PluginProbe
Elementor Website Builder – more than just a page builder / 3.28.0-dev2
Elementor Website Builder – more than just a page builder v3.28.0-dev2
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / modules / atomic-widgets / styles / styles-renderer.php

styles-renderer.php in Elementor Website Builder – more than just a page builder 3.28.0-dev2, at modules/atomic-widgets/styles/styles-renderer.php

168 lines 4.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Elementor\Modules\AtomicWidgets\Styles;
4
5 use Elementor\Core\Utils\Collection;
6 use Elementor\Modules\AtomicWidgets\PropsResolver\Props_Resolver;
7
8 class Styles_Renderer {
9 const DEFAULT_SELECTOR_PREFIX = '.elementor';
10
11 /**
12 * @var array<string, array{direction: 'min' | 'max', value: int, is_enabled: boolean}>
13 */
14 private array $breakpoints;
15
16 private $on_prop_transform;
17
18 private string $selector_prefix;
19
20 /**
21 * @param array<string, array{direction: 'min' | 'max', value: int, is_enabled: boolean}> $breakpoints
22 * @param string $selector_prefix
23 */
24 private function __construct( array $breakpoints, string $selector_prefix = self::DEFAULT_SELECTOR_PREFIX ) {
25 $this->breakpoints = $breakpoints;
26 $this->selector_prefix = $selector_prefix;
27 }
28
29 public static function make( array $breakpoints, string $selector_prefix = self::DEFAULT_SELECTOR_PREFIX ): self {
30 return new self( $breakpoints, $selector_prefix );
31 }
32
33 /**
34 * Render the styles to a CSS string.
35 *
36 * Styles format:
37 * array<int, array{
38 * id: string,
39 * type: string,
40 * variants: array<int, array{
41 * props: array<string, mixed>,
42 * meta: array<string, mixed>
43 * }>
44 * }>
45 *
46 * @param array $styles Array of style definitions.
47 *
48 * @return string Rendered CSS string.
49 */
50 public function render( array $styles ): string {
51 $css_style = [];
52
53 foreach ( $styles as $style_def ) {
54 $style = $this->style_definition_to_css_string( $style_def );
55 $css_style[] = $style;
56 }
57
58 return implode( '', $css_style );
59 }
60
61 public function on_prop_transform( callable $callback ): self {
62 $this->on_prop_transform = $callback;
63
64 return $this;
65 }
66
67 private function style_definition_to_css_string( array $style ): string {
68 $base_selector = $this->get_base_selector( $style );
69
70 if ( ! $base_selector ) {
71 return '';
72 }
73
74 $stylesheet = [];
75
76 foreach ( $style['variants'] as $variant ) {
77 $style_declaration = $this->variant_to_css_string( $base_selector, $variant );
78
79 if ( $style_declaration ) {
80 $stylesheet[] = $style_declaration;
81 }
82 }
83
84 return implode( '', $stylesheet );
85 }
86
87 private function get_base_selector( array $style_def ): ?string {
88 $map = [
89 'class' => '.',
90 ];
91
92 if (
93 isset( $style_def['type'] ) &&
94 isset( $style_def['id'] ) &&
95 isset( $map[ $style_def['type'] ] ) &&
96 $style_def['id']
97 ) {
98 $type = $map[ $style_def['type'] ];
99 $id = $style_def['id'];
100
101 $selector_parts = array_filter( [
102 $this->selector_prefix,
103 "{$type}{$id}",
104 ] );
105
106 return implode( ' ', $selector_parts );
107 }
108
109 return null;
110 }
111
112 private function variant_to_css_string( string $base_selector, array $variant ): string {
113 $css = $this->props_to_css_string( $variant['props'] );
114
115 if ( ! $css ) {
116 return '';
117 }
118
119 $state = isset( $variant['meta']['state'] ) ? ':' . $variant['meta']['state'] : '';
120 $selector = $base_selector . $state;
121
122 $style_declaration = $selector . '{' . $css . '}';
123
124 if ( isset( $variant['meta']['breakpoint'] ) ) {
125 $style_declaration = $this->wrap_with_media_query( $variant['meta']['breakpoint'], $style_declaration );
126 }
127
128 return $style_declaration;
129 }
130
131 private function props_to_css_string( array $props ): string {
132 $schema = Style_Schema::get();
133
134 return Collection::make( Props_Resolver::for_styles()->resolve( $schema, $props ) )
135 ->filter()
136 ->map( function ( $value, $prop ) {
137 if ( $this->on_prop_transform ) {
138 call_user_func( $this->on_prop_transform, $prop, $value );
139 }
140
141 return $prop . ':' . $value . ';';
142 } )
143 ->implode( '' );
144 }
145
146 private function wrap_with_media_query( string $breakpoint_id, string $css ): string {
147 if ( ! isset( $this->breakpoints[ $breakpoint_id ] ) ) {
148 return $css;
149 }
150
151 $breakpoint = $this->breakpoints[ $breakpoint_id ];
152 if ( isset( $breakpoint['is_enabled'] ) && ! $breakpoint['is_enabled'] ) {
153 return '';
154 }
155
156 $size = $this->get_breakpoint_size( $this->breakpoints[ $breakpoint_id ] );
157
158 return $size ? '@media(' . $size . '){' . $css . '}' : $css;
159 }
160
161 private function get_breakpoint_size( array $breakpoint ): ?string {
162 $bound = 'min' === $breakpoint['direction'] ? 'min-width' : 'max-width';
163 $width = $breakpoint['value'] . 'px';
164
165 return "{$bound}:{$width}";
166 }
167 }
168