first commit
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\AtomicWidgets\Styles;
|
||||
|
||||
use Elementor\Core\Files\CSS\Post as Post_CSS;
|
||||
use Elementor\Core\Utils\Collection;
|
||||
use Elementor\Modules\AtomicWidgets\Utils;
|
||||
use Elementor\Plugin;
|
||||
|
||||
class Atomic_Widget_Base_Styles {
|
||||
public function register_hooks() {
|
||||
add_action( 'elementor/css-file/post/parse', fn( Post_CSS $post ) => $this->inject_elements_base_styles( $post ), 10 );
|
||||
}
|
||||
|
||||
private function inject_elements_base_styles( Post_CSS $post ) {
|
||||
if ( ! Plugin::$instance->kits_manager->is_kit( $post->get_post_id() ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$elements = Plugin::$instance->elements_manager->get_element_types();
|
||||
$widgets = Plugin::$instance->widgets_manager->get_widget_types();
|
||||
|
||||
$base_styles = Collection::make( $elements )
|
||||
->merge( $widgets )
|
||||
->filter( fn( $element ) => Utils::is_atomic( $element ) )
|
||||
->map( fn( $element ) => $element->get_base_styles() )
|
||||
->flatten()
|
||||
->all();
|
||||
|
||||
$css = Styles_Renderer::make(
|
||||
Plugin::$instance->breakpoints->get_breakpoints_config()
|
||||
)->on_prop_transform( function( $key, $value ) use ( &$post ) {
|
||||
if ( 'font-family' !== $key ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$post->add_font( $value );
|
||||
} )->render( $base_styles );
|
||||
|
||||
$post->get_stylesheet()->add_raw_css( $css );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\AtomicWidgets\Styles;
|
||||
|
||||
use Elementor\Core\Files\CSS\Post as Post_CSS;
|
||||
use Elementor\Element_Base;
|
||||
use Elementor\Modules\AtomicWidgets\Utils;
|
||||
use Elementor\Plugin;
|
||||
|
||||
class Atomic_Widget_Styles {
|
||||
public function register_hooks() {
|
||||
add_action( 'elementor/element/parse_css', fn( Post_CSS $post, Element_Base $element ) => $this->parse_element_style( $post, $element ), 10, 2 );
|
||||
}
|
||||
|
||||
private function parse_element_style( Post_CSS $post, Element_Base $element ) {
|
||||
if ( ! Utils::is_atomic( $element ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$styles = $element->get_raw_data()['styles'];
|
||||
|
||||
if ( empty( $styles ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$css = Styles_Renderer::make(
|
||||
Plugin::$instance->breakpoints->get_breakpoints_config()
|
||||
)->on_prop_transform( function( $key, $value ) use ( &$post ) {
|
||||
if ( 'font-family' !== $key ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$post->add_font( $value );
|
||||
} )->render( $styles );
|
||||
|
||||
$post->get_stylesheet()->add_raw_css( $css );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\AtomicWidgets\Styles;
|
||||
|
||||
class Style_Definition {
|
||||
private string $type = 'class';
|
||||
private string $label = '';
|
||||
|
||||
/** @var Style_Variant[] */
|
||||
private array $variants = [];
|
||||
|
||||
public static function make(): self {
|
||||
return new self();
|
||||
}
|
||||
|
||||
public function set_type( string $type ): self {
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function set_label( string $label ): self {
|
||||
$this->label = $label;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function add_variant( Style_Variant $variant ): self {
|
||||
$this->variants[] = $variant->build();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function build( string $id ): array {
|
||||
return [
|
||||
'id' => $id,
|
||||
'type' => $this->type,
|
||||
'label' => $this->label,
|
||||
'variants' => $this->variants,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\AtomicWidgets\Styles;
|
||||
|
||||
use Elementor\Modules\AtomicWidgets\PropTypes\Background_Prop_Type;
|
||||
use Elementor\Modules\AtomicWidgets\PropTypes\Box_Shadow_Prop_Type;
|
||||
use Elementor\Modules\AtomicWidgets\PropTypes\Border_Radius_Prop_Type;
|
||||
use Elementor\Modules\AtomicWidgets\PropTypes\Border_Width_Prop_Type;
|
||||
use Elementor\Modules\AtomicWidgets\PropTypes\Color_Prop_Type;
|
||||
use Elementor\Modules\AtomicWidgets\PropTypes\Dimensions_Prop_Type;
|
||||
use Elementor\Modules\AtomicWidgets\PropTypes\Layout_Direction_Prop_Type;
|
||||
use Elementor\Modules\AtomicWidgets\PropTypes\Primitives\Number_Prop_Type;
|
||||
use Elementor\Modules\AtomicWidgets\PropTypes\Size_Prop_Type;
|
||||
use Elementor\Modules\AtomicWidgets\PropTypes\Primitives\String_Prop_Type;
|
||||
use Elementor\Modules\AtomicWidgets\PropTypes\Stroke_Prop_Type;
|
||||
use Elementor\Modules\AtomicWidgets\PropTypes\Union_Prop_Type;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
class Style_Schema {
|
||||
public static function get() {
|
||||
return apply_filters( 'elementor/atomic-widgets/styles/schema', static::get_style_schema() );
|
||||
}
|
||||
|
||||
public static function get_style_schema(): array {
|
||||
return array_merge(
|
||||
self::get_size_props(),
|
||||
self::get_position_props(),
|
||||
self::get_typography_props(),
|
||||
self::get_spacing_props(),
|
||||
self::get_border_props(),
|
||||
self::get_background_props(),
|
||||
self::get_effects_props(),
|
||||
self::get_layout_props(),
|
||||
self::get_alignment_props(),
|
||||
);
|
||||
}
|
||||
|
||||
private static function get_size_props() {
|
||||
return [
|
||||
'width' => Size_Prop_Type::make(),
|
||||
'height' => Size_Prop_Type::make(),
|
||||
'min-width' => Size_Prop_Type::make(),
|
||||
'min-height' => Size_Prop_Type::make(),
|
||||
'max-width' => Size_Prop_Type::make(),
|
||||
'max-height' => Size_Prop_Type::make(),
|
||||
'overflow' => String_Prop_Type::make()->enum( [
|
||||
'visible',
|
||||
'hidden',
|
||||
'auto',
|
||||
] ),
|
||||
'aspect-ratio' => String_Prop_Type::make(),
|
||||
'object-fit' => String_Prop_Type::make()->enum( [
|
||||
'fill',
|
||||
'cover',
|
||||
'contain',
|
||||
'none',
|
||||
'scale-down',
|
||||
] ),
|
||||
'object-position' => String_Prop_Type::make()->enum( [
|
||||
'center center',
|
||||
'center left',
|
||||
'center right',
|
||||
'top center',
|
||||
'top left',
|
||||
'top right',
|
||||
'bottom center',
|
||||
'bottom left',
|
||||
'bottom right',
|
||||
] ),
|
||||
];
|
||||
}
|
||||
|
||||
private static function get_position_props() {
|
||||
return [
|
||||
'position' => String_Prop_Type::make()->enum( [
|
||||
'static',
|
||||
'relative',
|
||||
'absolute',
|
||||
'fixed',
|
||||
'sticky',
|
||||
] ),
|
||||
'inset-block-start' => Size_Prop_Type::make(),
|
||||
'inset-inline-end' => Size_Prop_Type::make(),
|
||||
'inset-block-end' => Size_Prop_Type::make(),
|
||||
'inset-inline-start' => Size_Prop_Type::make(),
|
||||
'z-index' => Number_Prop_Type::make(),
|
||||
'scroll-margin-top' => Size_Prop_Type::make(),
|
||||
];
|
||||
}
|
||||
|
||||
private static function get_typography_props() {
|
||||
return [
|
||||
'font-family' => String_Prop_Type::make(),
|
||||
'font-weight' => String_Prop_Type::make()->enum( [
|
||||
'100',
|
||||
'200',
|
||||
'300',
|
||||
'400',
|
||||
'500',
|
||||
'600',
|
||||
'700',
|
||||
'800',
|
||||
'900',
|
||||
'normal',
|
||||
'bold',
|
||||
'bolder',
|
||||
'lighter',
|
||||
] ),
|
||||
'font-size' => Size_Prop_Type::make(),
|
||||
'color' => Color_Prop_Type::make(),
|
||||
'letter-spacing' => Size_Prop_Type::make(),
|
||||
'word-spacing' => Size_Prop_Type::make(),
|
||||
'column-count' => Number_Prop_Type::make(),
|
||||
'column-gap' => Size_Prop_Type::make(),
|
||||
'line-height' => Size_Prop_Type::make(),
|
||||
'text-align' => String_Prop_Type::make()->enum( [
|
||||
'start',
|
||||
'center',
|
||||
'end',
|
||||
'justify',
|
||||
] ),
|
||||
'font-style' => String_Prop_Type::make()->enum( [
|
||||
'normal',
|
||||
'italic',
|
||||
'oblique',
|
||||
] ),
|
||||
// TODO: validate text-decoration in more specific way [EDS-524]
|
||||
'text-decoration' => String_Prop_Type::make(),
|
||||
'text-transform' => String_Prop_Type::make()->enum( [
|
||||
'none',
|
||||
'capitalize',
|
||||
'uppercase',
|
||||
'lowercase',
|
||||
] ),
|
||||
'direction' => String_Prop_Type::make()->enum( [
|
||||
'ltr',
|
||||
'rtl',
|
||||
] ),
|
||||
'stroke' => Stroke_Prop_Type::make(),
|
||||
'all' => String_Prop_Type::make()->enum( [
|
||||
'initial',
|
||||
'inherit',
|
||||
'unset',
|
||||
'revert',
|
||||
'revert-layer',
|
||||
] ),
|
||||
'cursor' => String_Prop_Type::make()->enum( [
|
||||
'pointer',
|
||||
] ),
|
||||
];
|
||||
}
|
||||
|
||||
private static function get_spacing_props() {
|
||||
return [
|
||||
'padding' => Union_Prop_Type::make()
|
||||
->add_prop_type( Dimensions_Prop_Type::make() )
|
||||
->add_prop_type( Size_Prop_Type::make() ),
|
||||
'margin' => Union_Prop_Type::make()
|
||||
->add_prop_type( Dimensions_Prop_Type::make() )
|
||||
->add_prop_type( Size_Prop_Type::make() ),
|
||||
];
|
||||
}
|
||||
|
||||
private static function get_border_props() {
|
||||
return [
|
||||
'border-radius' => Union_Prop_Type::make()
|
||||
->add_prop_type( Size_Prop_Type::make() )
|
||||
->add_prop_type( Border_Radius_Prop_Type::make() ),
|
||||
'border-width' => Union_Prop_Type::make()
|
||||
->add_prop_type( Size_Prop_Type::make() )
|
||||
->add_prop_type( Border_Width_Prop_Type::make() ),
|
||||
'border-color' => Color_Prop_Type::make(),
|
||||
'border-style' => String_Prop_Type::make()->enum( [
|
||||
'none',
|
||||
'hidden',
|
||||
'dotted',
|
||||
'dashed',
|
||||
'solid',
|
||||
'double',
|
||||
'groove',
|
||||
'ridge',
|
||||
'inset',
|
||||
'outset',
|
||||
] ),
|
||||
];
|
||||
}
|
||||
|
||||
private static function get_background_props() {
|
||||
return [
|
||||
'background' => Background_Prop_Type::make(),
|
||||
];
|
||||
}
|
||||
|
||||
private static function get_effects_props() {
|
||||
return [
|
||||
'box-shadow' => Box_Shadow_Prop_Type::make(),
|
||||
];
|
||||
}
|
||||
|
||||
private static function get_layout_props() {
|
||||
return [
|
||||
'display' => String_Prop_Type::make()->enum( [
|
||||
'block',
|
||||
'inline',
|
||||
'inline-block',
|
||||
'flex',
|
||||
'inline-flex',
|
||||
'grid',
|
||||
'inline-grid',
|
||||
'flow-root',
|
||||
'none',
|
||||
'contents',
|
||||
] ),
|
||||
'flex-direction' => String_Prop_Type::make()->enum( [
|
||||
'row',
|
||||
'row-reverse',
|
||||
'column',
|
||||
'column-reverse',
|
||||
] ),
|
||||
'gap' => Union_Prop_Type::make()
|
||||
->add_prop_type( Layout_Direction_Prop_Type::make() )
|
||||
->add_prop_type( Size_Prop_Type::make() ),
|
||||
'flex-wrap' => String_Prop_Type::make()->enum( [
|
||||
'wrap',
|
||||
'nowrap',
|
||||
'wrap-reverse',
|
||||
] ),
|
||||
'flex-grow' => Number_Prop_Type::make(),
|
||||
'flex-shrink' => Number_Prop_Type::make(),
|
||||
'flex-basis' => Size_Prop_Type::make(),
|
||||
];
|
||||
}
|
||||
|
||||
private static function get_alignment_props() {
|
||||
return [
|
||||
'justify-content' => String_Prop_Type::make()->enum( [
|
||||
'center',
|
||||
'start',
|
||||
'end',
|
||||
'flex-start',
|
||||
'flex-end',
|
||||
'left',
|
||||
'right',
|
||||
'normal',
|
||||
'space-between',
|
||||
'space-around',
|
||||
'space-evenly',
|
||||
'stretch',
|
||||
] ),
|
||||
'align-content' => String_Prop_Type::make()->enum( [
|
||||
'center',
|
||||
'start',
|
||||
'end',
|
||||
'space-between',
|
||||
'space-around',
|
||||
'space-evenly',
|
||||
] ),
|
||||
'align-items' => String_Prop_Type::make()->enum( [
|
||||
'normal',
|
||||
'stretch',
|
||||
'center',
|
||||
'start',
|
||||
'end',
|
||||
'flex-start',
|
||||
'flex-end',
|
||||
'self-start',
|
||||
'self-end',
|
||||
'anchor-center',
|
||||
] ),
|
||||
'align-self' => String_Prop_Type::make()->enum( [
|
||||
'auto',
|
||||
'normal',
|
||||
'center',
|
||||
'start',
|
||||
'end',
|
||||
'self-start',
|
||||
'self-end',
|
||||
'flex-start',
|
||||
'flex-end',
|
||||
'anchor-center',
|
||||
'baseline',
|
||||
'first baseline',
|
||||
'last baseline',
|
||||
'stretch',
|
||||
] ),
|
||||
'order' => Number_Prop_Type::make(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\AtomicWidgets\Styles;
|
||||
|
||||
class Style_Variant {
|
||||
private ?string $breakpoint = null;
|
||||
private ?string $state = null;
|
||||
|
||||
/** @var array<string, array> */
|
||||
private array $props = [];
|
||||
|
||||
public static function make(): self {
|
||||
return new self();
|
||||
}
|
||||
|
||||
public function set_breakpoint( string $breakpoint ): self {
|
||||
$this->breakpoint = $breakpoint;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function set_state( string $state ): self {
|
||||
$this->state = $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function add_prop( string $key, $value ): self {
|
||||
$this->props[ $key ] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function build(): array {
|
||||
return [
|
||||
'meta' => [
|
||||
'breakpoint' => $this->breakpoint,
|
||||
'state' => $this->state,
|
||||
],
|
||||
'props' => $this->props,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\AtomicWidgets\Styles;
|
||||
|
||||
use Elementor\Core\Utils\Collection;
|
||||
use Elementor\Modules\AtomicWidgets\PropsResolver\Render_Props_Resolver;
|
||||
|
||||
class Styles_Renderer {
|
||||
const DEFAULT_SELECTOR_PREFIX = '.elementor';
|
||||
|
||||
/**
|
||||
* @var array<string, array{direction: 'min' | 'max', value: int, is_enabled: boolean}>
|
||||
*/
|
||||
private array $breakpoints;
|
||||
|
||||
private $on_prop_transform;
|
||||
|
||||
private string $selector_prefix;
|
||||
|
||||
/**
|
||||
* @param array<string, array{direction: 'min' | 'max', value: int, is_enabled: boolean}> $breakpoints
|
||||
* @param string $selector_prefix
|
||||
*/
|
||||
private function __construct( array $breakpoints, string $selector_prefix = self::DEFAULT_SELECTOR_PREFIX ) {
|
||||
$this->breakpoints = $breakpoints;
|
||||
$this->selector_prefix = $selector_prefix;
|
||||
}
|
||||
|
||||
public static function make( array $breakpoints, string $selector_prefix = self::DEFAULT_SELECTOR_PREFIX ): self {
|
||||
return new self( $breakpoints, $selector_prefix );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the styles to a CSS string.
|
||||
*
|
||||
* Styles format:
|
||||
* array<int, array{
|
||||
* id: string,
|
||||
* type: string,
|
||||
* cssName: string | null,
|
||||
* variants: array<int, array{
|
||||
* props: array<string, mixed>,
|
||||
* meta: array<string, mixed>
|
||||
* }>
|
||||
* }>
|
||||
*
|
||||
* @param array $styles Array of style definitions.
|
||||
*
|
||||
* @return string Rendered CSS string.
|
||||
*/
|
||||
public function render( array $styles ): string {
|
||||
$css_style = [];
|
||||
|
||||
foreach ( $styles as $style_def ) {
|
||||
$style = $this->style_definition_to_css_string( $style_def );
|
||||
$css_style[] = $style;
|
||||
}
|
||||
|
||||
return implode( '', $css_style );
|
||||
}
|
||||
|
||||
public function on_prop_transform( callable $callback ): self {
|
||||
$this->on_prop_transform = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function style_definition_to_css_string( array $style ): string {
|
||||
$base_selector = $this->get_base_selector( $style );
|
||||
|
||||
if ( ! $base_selector ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$stylesheet = [];
|
||||
|
||||
foreach ( $style['variants'] as $variant ) {
|
||||
$style_declaration = $this->variant_to_css_string( $base_selector, $variant );
|
||||
|
||||
if ( $style_declaration ) {
|
||||
$stylesheet[] = $style_declaration;
|
||||
}
|
||||
}
|
||||
|
||||
return implode( '', $stylesheet );
|
||||
}
|
||||
|
||||
private function get_base_selector( array $style_def ): ?string {
|
||||
$map = [
|
||||
'class' => '.',
|
||||
];
|
||||
|
||||
if (
|
||||
isset( $style_def['type'] ) &&
|
||||
isset( $style_def['id'] ) &&
|
||||
isset( $map[ $style_def['type'] ] ) &&
|
||||
$style_def['id']
|
||||
) {
|
||||
$type = $map[ $style_def['type'] ];
|
||||
$name = $style_def['cssName'] ?? $style_def['id'];
|
||||
|
||||
$selector_parts = array_filter( [
|
||||
$this->selector_prefix,
|
||||
"{$type}{$name}",
|
||||
] );
|
||||
|
||||
return implode( ' ', $selector_parts );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function variant_to_css_string( string $base_selector, array $variant ): string {
|
||||
$css = $this->props_to_css_string( $variant['props'] );
|
||||
|
||||
if ( ! $css ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$state = isset( $variant['meta']['state'] ) ? ':' . $variant['meta']['state'] : '';
|
||||
$selector = $base_selector . $state;
|
||||
|
||||
$style_declaration = $selector . '{' . $css . '}';
|
||||
|
||||
if ( isset( $variant['meta']['breakpoint'] ) ) {
|
||||
$style_declaration = $this->wrap_with_media_query( $variant['meta']['breakpoint'], $style_declaration );
|
||||
}
|
||||
|
||||
return $style_declaration;
|
||||
}
|
||||
|
||||
private function props_to_css_string( array $props ): string {
|
||||
$schema = Style_Schema::get();
|
||||
|
||||
return Collection::make( Render_Props_Resolver::for_styles()->resolve( $schema, $props ) )
|
||||
->filter()
|
||||
->map( function ( $value, $prop ) {
|
||||
if ( $this->on_prop_transform ) {
|
||||
call_user_func( $this->on_prop_transform, $prop, $value );
|
||||
}
|
||||
|
||||
return $prop . ':' . $value . ';';
|
||||
} )
|
||||
->implode( '' );
|
||||
}
|
||||
|
||||
private function wrap_with_media_query( string $breakpoint_id, string $css ): string {
|
||||
if ( ! isset( $this->breakpoints[ $breakpoint_id ] ) ) {
|
||||
return $css;
|
||||
}
|
||||
|
||||
$breakpoint = $this->breakpoints[ $breakpoint_id ];
|
||||
if ( isset( $breakpoint['is_enabled'] ) && ! $breakpoint['is_enabled'] ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$size = $this->get_breakpoint_size( $this->breakpoints[ $breakpoint_id ] );
|
||||
|
||||
return $size ? '@media(' . $size . '){' . $css . '}' : $css;
|
||||
}
|
||||
|
||||
private function get_breakpoint_size( array $breakpoint ): ?string {
|
||||
$bound = 'min' === $breakpoint['direction'] ? 'min-width' : 'max-width';
|
||||
$width = $breakpoint['value'] . 'px';
|
||||
|
||||
return "{$bound}:{$width}";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user