PluginProbe
Elementor Website Builder – more than just a page builder / 3.25.3
Elementor Website Builder – more than just a page builder v3.25.3
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.25.3, at modules/atomic-widgets/styles/styles-renderer.php

203 lines 4.7 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\Modules\AtomicWidgets\Base\Style_Transformer_Base;
6
7 class Styles_Renderer {
8
9 /**
10 * @var array<string, Style_Transformer_Base> $transformers
11 */
12 private array $transformers;
13
14 /**
15 * @var array<string, array{direction: 'min' | 'max', value: int, is_enabled: boolean}> $breakpoints
16 */
17 private array $breakpoints;
18
19 /**
20 * Styles_Renderer constructor.
21 *
22 * @param array{
23 * transformers: array<string, Style_Transformer_Base>,
24 * breakpoints: array<string, array{direction: 'min' | 'max', value: int, is_enabled: boolean}>
25 * } $config
26 */
27 public function __construct( array $config ) {
28 $this->transformers = $config['transformers'];
29 $this->breakpoints = $config['breakpoints'];
30 }
31
32 /**
33 * Render the styles to a CSS string.
34 *
35 * @param array<int, array{
36 * id: string,
37 * type: string,
38 * variants: array<int, array{
39 * props: array<string, mixed>,
40 * meta: array<string, mixed>
41 * }>
42 * }> $styles Array of style definitions.
43 *
44 * @return string Rendered CSS string.
45 */
46 public function render( array $styles ): string {
47 $css_style = [];
48
49 foreach ( $styles as $style_def ) {
50 $style = $this->style_definition_to_css_string( $style_def );
51 $css_style[] = $style;
52 }
53
54 return implode( '', $css_style );
55 }
56
57 private function style_definition_to_css_string( array $style ): string {
58 $base_selector = $this->get_base_selector( $style );
59
60 if ( ! $base_selector ) {
61 return '';
62 }
63
64 $stylesheet = [];
65
66 foreach ( $style['variants'] as $variant ) {
67 $style_declaration = $this->variant_to_css_string( $base_selector, $variant );
68
69 if ( $style_declaration ) {
70 $stylesheet[] = $style_declaration;
71 }
72 }
73
74 return implode( '', $stylesheet );
75 }
76
77 private function get_base_selector( array $style_def ): ?string {
78 $map = [
79 'class' => '.',
80 ];
81
82 if (
83 isset( $style_def['type'] ) &&
84 isset( $style_def['id'] ) &&
85 isset( $map[ $style_def['type'] ] ) &&
86 $style_def['id']
87 ) {
88 return $map[ $style_def['type'] ] . $style_def['id'];
89 }
90
91 return null;
92 }
93
94 private function variant_to_css_string( string $base_selector, array $variant ): string {
95 $css = $this->props_to_css_string( $variant['props'] );
96
97 if ( ! $css ) {
98 return '';
99 }
100
101 $state = isset( $variant['meta']['state'] ) ? ':' . $variant['meta']['state'] : '';
102 $selector = $base_selector . $state;
103
104 $style_declaration = $selector . '{' . $css . '}';
105
106 if ( isset( $variant['meta']['breakpoint'] ) ) {
107 $style_declaration = $this->wrap_with_media_query( $variant['meta']['breakpoint'], $style_declaration );
108 }
109
110 return $style_declaration;
111 }
112
113 private function props_to_css_string( array $props ): string {
114 $css = [];
115
116 foreach ( $props as $prop => $raw_value ) {
117 $prop = $this->camel_case_to_dash( $prop );
118 $value = $this->transform_value( $raw_value );
119
120 if ( $prop && $value ) {
121 $css[] = $prop . ':' . $value;
122 }
123 }
124
125 return implode( ';', $css );
126 }
127
128 private function camel_case_to_dash( string $str ): string {
129 return strtolower( preg_replace( '/([a-zA-Z])(?=[A-Z])/', '$1-', $str ) );
130 }
131
132 private function wrap_with_media_query( string $breakpoint_id, string $css ): string {
133 if ( ! isset( $this->breakpoints[ $breakpoint_id ] ) ) {
134 return $css;
135 }
136
137 $breakpoint = $this->breakpoints[ $breakpoint_id ];
138 if ( isset( $breakpoint['is_enabled'] ) && ! $breakpoint['is_enabled'] ) {
139 return '';
140 }
141
142 $size = $this->get_breakpoint_size( $this->breakpoints[ $breakpoint_id ] );
143
144 return $size ? '@media(' . $size . '){' . $css . '}' : $css;
145 }
146
147 private function get_breakpoint_size( array $breakpoint ): ?string {
148 $bound = 'min' === $breakpoint['direction'] ? 'min-width' : 'max-width';
149 $width = $breakpoint['value'] . 'px';
150
151 return "{$bound}:{$width}";
152 }
153
154 private function transform_value( $value ): ?string {
155 if ( is_string( $value ) ) {
156 return $value;
157 }
158
159 if ( ! $this->is_transformable( $value ) ) {
160 return 'unset';
161 }
162
163 $transformer = $this->get_transformer( $value['$$type'] );
164
165 if ( ! $transformer ) {
166 return 'unset';
167 }
168
169 try {
170 $transformed = $transformer->transform(
171 $value['value'],
172 fn( $value ) => $this->transform_value( $value )
173 );
174
175 return $this->transform_value( $transformed );
176
177 } catch ( \Exception $e ) {
178 return 'unset';
179 }
180 }
181
182 private function is_transformable( $value ): bool {
183 return (
184 isset( $value['$$type'], $value['value'] ) &&
185 is_string( $value['$$type'] )
186 );
187 }
188
189 private function get_transformer( $type ): ?Style_Transformer_Base {
190 if ( ! isset( $this->transformers[ $type ] ) ) {
191 return null;
192 }
193
194 $transformer = $this->transformers[ $type ];
195
196 if ( ! $transformer instanceof Style_Transformer_Base ) {
197 return null;
198 }
199
200 return $transformer;
201 }
202 }
203