PluginProbe ʕ •ᴥ•ʔ
Kubio AI Page Builder / trunk
Kubio AI Page Builder vtrunk
2.8.2 2.8.1 trunk 1.0.0 1.0.1 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.7.0 1.7.1 1.7.2 1.7.3 1.8.0 1.8.1 1.8.2 1.9.0 2.0.0 2.1.1 2.1.2 2.1.3 2.2.0 2.2.3 2.2.4 2.2.5 2.3.0 2.3.1 2.3.3 2.3.4 2.4.0 2.4.1 2.4.2 2.4.3 2.4.5 2.5.0 2.5.1 2.5.2 2.5.3 2.6.0 2.6.1 2.6.2 2.6.3 2.6.5 2.6.6 2.6.7 2.7.0 2.7.1 2.7.2 2.7.3 2.8.0
kubio / lib / src / Core / StyleManager / StyleRender.php
kubio / lib / src / Core / StyleManager Last commit date
Generics 1 year ago Props 1 month ago BlockStyleRender.php 1 year ago DynamicStyles.php 1 year ago GlobalStyleRender.php 1 year ago MainAttribute.php 4 years ago ParserUtils.php 1 year ago StyleManager.php 2 years ago StyleParser.php 1 year ago StyleRender.php 1 year ago Utils.php 1 year ago
StyleRender.php
848 lines
1 <?php
2
3 namespace Kubio\Core\StyleManager;
4
5 use Kubio\Config;
6 use Kubio\Core\LodashBasic;
7 use Kubio\Core\Utils as CoreUtils;
8 use Kubio\Flags;
9
10 use function _\concat;
11 use function _\uniq;
12 use function array_merge;
13 use function count;
14 use function is_array;
15 use function is_string;
16 use function str_contains;
17 use function str_replace;
18 #[\AllowDynamicProperties]
19 class ElementStyleStateRender {
20
21 private $name;
22 private $style;
23
24 public function __construct( $name, $style ) {
25 $this->name = $name;
26 $this->style = $style;
27 }
28
29 public function toCss( $options = null ) {
30 $context = array_merge( $options, array( 'state' => $this->name ) );
31 return StyleParser::getInstance()->transform(
32 LodashBasic::omit( (array) $this->style, 'ancestor' ),
33 $context
34 );
35 }
36 }
37 #[\AllowDynamicProperties]
38 class ElementStyleMediaRender {
39
40 const DEFAULT_STATE = 'normal';
41 private $name;
42 private $style;
43 private $byState = array();
44 private $desktopMediaRender = null;
45
46 public function __construct( $mediaName, $mediaStyle, $desktopMediaRender = null ) {
47 $this->name = $mediaName;
48 $this->style = $mediaStyle;
49 $this->desktopMediaRender = $desktopMediaRender;
50
51 if ( $desktopMediaRender ) {
52 $mediaStyle = LodashBasic::mergeSkipSeqArray( array(), $desktopMediaRender->style, $mediaStyle );
53 }
54
55 $defaultStyle = LodashBasic::get(
56 $mediaStyle,
57 array( self::DEFAULT_STATE ),
58 array()
59 );
60
61 if ( $mediaStyle ) {
62 foreach ( $mediaStyle as $stateName => $stateStyle ) {
63 $mergedStyle =
64 $stateName === self::DEFAULT_STATE
65 ? $stateStyle
66 : LodashBasic::merge( array(), $defaultStyle, $stateStyle );
67 if ( is_array( $mergedStyle ) && count( $mergedStyle ) ) {
68 $this->byState[ $stateName ] = new ElementStyleStateRender(
69 $stateName,
70 $mergedStyle
71 );
72 }
73 }
74 }
75 }
76
77 public function toCss( $options = null ) {
78 $result = array();
79
80 $result[ self::DEFAULT_STATE ] = isset(
81 $this->byState[ self::DEFAULT_STATE ]
82 )
83 ? $this->byState[ self::DEFAULT_STATE ]->toCss( $options )
84 : array();
85
86 foreach ( $this->byState as $stateName => $stateStyle ) {
87 if ( $stateName !== self::DEFAULT_STATE ) {
88 $stateCss = $stateStyle->toCss( $options );
89 if ( $stateCss ) {
90 $result[ $stateName ] = LodashBasic::diff(
91 $stateCss,
92 $result[ self::DEFAULT_STATE ]
93 );
94 }
95 }
96 }
97 return $result;
98 }
99 }
100 #[\AllowDynamicProperties]
101 class ElementStyleRender {
102
103 private $byMedias = array();
104 private $name;
105
106 private function getOrderedKeys( $byMedias ) {
107 return uniq( concat( array( 'desktop' ), array_keys( $byMedias ) ) );
108 }
109
110 public function __construct( $name, $style ) {
111 $this->name = $name;
112 $byOrderedMedias = $this->getOrderedKeys( $style );
113 $desktopMediaRender = null;
114 foreach ( $byOrderedMedias as $mediaName ) {
115 $mediaStyle = $style[ $mediaName ];
116
117 $this->byMedias[ $mediaName ] = new ElementStyleMediaRender(
118 $mediaName,
119 $mediaStyle,
120 $desktopMediaRender
121 );
122
123 if ( $mediaName == 'desktop' ) {
124 $desktopMediaRender = $this->byMedias[ $mediaName ];
125 }
126 }
127 }
128
129 public function toCss( $options = null ) {
130 $result = array();
131 $byOrderedMedias = $this->getOrderedKeys( $this->byMedias );
132 foreach ( $byOrderedMedias as $mediaName ) {
133 $mediaStyle = $this->byMedias[ $mediaName ];
134 $result[ $mediaName ] = $mediaStyle->toCss( $options );
135
136 if ( $mediaName !== 'desktop' ) {
137 $result[ $mediaName ] = LodashBasic::diff( $result[ $mediaName ], $result['desktop'] );
138 }
139 }
140 return $result;
141 }
142 }
143 #[\AllowDynamicProperties]
144 class AncestorStyleRender {
145
146 private $name;
147 private $elementsByName = array();
148
149 public function __construct( $name, $style ) {
150 $this->name = $name;
151 foreach ( $style as $elementName => $elementStyle ) {
152 $this->elementsByName[ $elementName ] = new ElementStyleRender(
153 $elementName,
154 $elementStyle
155 );
156 }
157 }
158
159 public function toCss( $options ) {
160 $result = array();
161 $allowedElements = $options['allowedElements'];
162 foreach ( $allowedElements as $elementName ) {
163 $elementStyle = LodashBasic::get(
164 $this->elementsByName,
165 $elementName,
166 false
167 );
168 if ( $elementStyle ) {
169 $result[ $elementName ] = $elementStyle->toCss(
170 LodashBasic::merge(
171 $options,
172 array(
173 'styledElement' => $elementName,
174 )
175 )
176 );
177 }
178 }
179 return $result;
180 }
181 }
182 #[\AllowDynamicProperties]
183 class AncestorsStyleContext {
184
185 public $allowedElements = array();
186 public $model = array();
187 public $htmlSupport = true;
188
189 public function __construct( $model, $allowedElements, $htmlSupport = true ) {
190 $this->model = $model;
191 $this->allowedElements = $allowedElements;
192 $this->htmlSupport = $htmlSupport;
193 }
194 }
195 #[\AllowDynamicProperties]
196 class AncestorsStyleRender {
197
198 private $ancestorsByName = array();
199 private $context = array();
200
201 private function getOrderedAncestors( $ancestors ) {
202 return uniq( concat( array( 'default' ), array_keys( $ancestors ) ) );
203 }
204
205 public function __construct( $style, $context = array() ) {
206 $this->context = $context;
207 $ancestor = LodashBasic::get( $style, 'ancestor', array() );
208 $ancestors = LodashBasic::merge(
209 array( 'default' => LodashBasic::omit( $style, 'ancestor' ) ),
210 $ancestor
211 );
212 $ordered_ancestors = $this->getOrderedAncestors( $ancestors );
213
214 $defaultNormalizedStyle = array();
215 foreach ( $ordered_ancestors as $ancestorName ) {
216 $ancestorStyle = $ancestors[ $ancestorName ];
217 $normalized = Utils::normalizeStyle(
218 $ancestorStyle,
219 array(
220 'allowedElements' => $context->allowedElements,
221 )
222 );
223
224 if ( $ancestorName !== 'default' ) {
225 $normalized = LodashBasic::mergeSkipSeqArray( array(), $defaultNormalizedStyle, $normalized );
226 } else {
227 $defaultNormalizedStyle = $normalized;
228 }
229
230 $this->ancestorsByName[ $ancestorName ] = new AncestorStyleRender(
231 $ancestorName,
232 $normalized
233 );
234 }
235 }
236
237 public function toCss( $composeSelector = null, $styleType = 'shared' ) {
238 $result = array();
239
240 $ordered_ancestors = $this->getOrderedAncestors( $this->ancestorsByName );
241
242 foreach ( $ordered_ancestors as $ancestorName ) {
243 $ancestorStyle = $this->ancestorsByName[ $ancestorName ];
244 $result[ $ancestorName ] = $ancestorStyle->toCss(
245 LodashBasic::merge( (array) $this->context, array( 'styleType' => $styleType ) )
246 );
247 if ( $ancestorName !== 'default' ) {
248 $result[ $ancestorName ] = LodashBasic::diff( $result[ $ancestorName ], $result['default'] );
249 }
250 }
251
252 $mapped = array();
253 foreach ( $result as $ancestorName => $ancestorStyle ) {
254 foreach ( $ancestorStyle as $elementName => $elementStyleByMedia ) {
255 foreach ( $elementStyleByMedia as $media => $elementMediaStyle ) {
256 foreach (
257 $elementMediaStyle
258 as $elementStateName => $elementStateStyle
259 ) {
260
261 if ( $elementStateName === 'visited' ) {
262 continue;
263 }
264
265 $selectors = $composeSelector(
266 $ancestorName,
267 $elementName,
268 $elementStateName
269 );
270 $value = array();
271 LodashBasic::set(
272 $value,
273 LodashBasic::concat( array( $media ), $selectors ),
274 $elementStateStyle
275 );
276 $mapped = LodashBasic::merge( $mapped, $value );
277 }
278 }
279 }
280 }
281 return $mapped;
282 }
283 }
284 #[\AllowDynamicProperties]
285 class BasicPropsConfig {
286
287 public function __construct( $props ) {
288 foreach ( $props as $name => $value ) {
289 $this->$name = $value;
290 }
291 }
292 }
293 #[\AllowDynamicProperties]
294 class StateConfig extends BasicPropsConfig {
295
296 public $selector = false;
297 public $stateRedirectElement = false;
298 }
299 #[\AllowDynamicProperties]
300 class ElementConfig extends BasicPropsConfig {
301
302 const STATE_KEY = '{{state}}';
303 public $usePrefix = true;
304 public $useParentPrefix = false;
305 public $useWrapperPrefix = false;
306 public $ancestor = false;
307 public $selector = false;
308 public $statesConfig = array();
309 public $statesById = array();
310 public $selectorPrepend = false;
311 public $prefixWithTag = false;
312
313 public function getSelector( $state = null ) {
314 if ( $this->isSelectorPerState() ) {
315 $defaultSelector = LodashBasic::get( $this->selector, 'default' );
316 $elementSelector = LodashBasic::get(
317 $this->selector,
318 $state,
319 $defaultSelector
320 );
321 if ( $elementSelector === null ) {
322 $elementSelector = '';
323 }
324 $elementSelector = str_replace(
325 self::STATE_KEY,
326 $this->getStateConfig( $state )->selector,
327 $elementSelector
328 );
329 } else {
330 $elementSelector = $this->selector;
331 }
332 return $elementSelector;
333 }
334
335 public function isSelectorPerState() {
336 return is_array( $this->selector );
337 }
338
339 public function getStateConfig( $state ) {
340 $props = LodashBasic::merge(
341 $this->statesById[ $state ],
342 LodashBasic::get( $this->statesConfig, 'default', array() ),
343 LodashBasic::get( $this->statesConfig, $state, array() )
344 );
345 return new StateConfig( $props );
346 }
347 public function shouldPrependAncestor( $ancestor ) {
348 return $this->ancestor !== $ancestor;
349 }
350
351 public function shouldAppendStateSelector() {
352 if ( $this->isSelectorPerState() ) {
353 return false;
354 }
355 if (
356 is_string( $this->selector ) &&
357 str_contains( $this->selector, self::STATE_KEY )
358 ) {
359 return false;
360 }
361 return true;
362 }
363 }
364 #[\AllowDynamicProperties]
365 class StyleRender {
366
367 public static $prefixSelectorsByType = array(
368 'shared' => '#kubio',
369 'local' => '#kubio',
370 'dynamic' => 'body',
371 'global' => '',
372 );
373
374 public $prefixParents;
375 protected $parser;
376 protected $model = array();
377 protected $styledElementsByName = array();
378 protected $styledElementsEnum = array();
379
380 protected $statesByElement;
381 protected $statesById;
382
383 protected $allowedElements;
384 protected $htmlSupport;
385 protected $baseClass;
386
387 protected $wrapperElement;
388
389 public $useParentPrefix = false;
390
391 public $skipSharedStyleRender = false;
392
393 public function __construct( $options ) {
394 $this->parser = StyleParser::getInstance();
395 $this->statesById = Config::statesById();
396 $this->prefixParents = array();
397 $this->useParentPrefix = false;
398 $this->htmlSupport = true;
399 $this->baseClass = '';
400
401 $this->loadOptions( $options );
402
403 $this->allowedElements = LodashBasic::concat(
404 array( 'default' ),
405 array_keys( $this->styledElementsByName ),
406 array_values( $this->styledElementsEnum )
407 );
408 $this->statesByElement = $this->getStatesByElement();
409 }
410
411 public function loadOptions( $options ) {
412 foreach ( $options as $name => $value ) {
413 if ( property_exists( $this, $name ) ) {
414 $this->{$name} = $value;
415 }
416 }
417 }
418
419 public function getStatesByElement() {
420 $statesByElement = array();
421 foreach ( $this->styledElementsByName as $name => $item ) {
422 $statesByElement[ $name ] = LodashBasic::get(
423 $item,
424 array( 'supports', Config::$statesKey ),
425 array( 'normal', 'hover' )
426 );
427 }
428 return $statesByElement;
429 }
430
431 public static function normalizeData(
432 $mainAttr,
433 $styledElementsByName,
434 $styledElementsEnum
435 ) {
436 $model = array(
437 'style' => array(
438 'local' => LodashBasic::get( $mainAttr, '_style', array() ),
439 'shared' => LodashBasic::get( $mainAttr, 'style', array() ),
440 ),
441 'props' => array(
442 'local' => LodashBasic::get( $mainAttr, '_props', array() ),
443 'shared' => LodashBasic::get( $mainAttr, 'props', array() ),
444 ),
445 'id' => LodashBasic::get( $mainAttr, 'id' ),
446 'styleRef' => LodashBasic::get( $mainAttr, 'styleRef' ),
447 );
448
449 foreach ( $styledElementsEnum as $elementName ) {
450 if ( ! isset( $styledElementsByName[ $elementName ] ) ) {
451 $styledElementsByName[ $elementName ] = array();
452 }
453 }
454 return array(
455 'model' => $model,
456 'styledElementsByName' => $styledElementsByName,
457 'styledElementsEnum' => $styledElementsEnum,
458 );
459 }
460
461 public function export( $dynamicStyle = null ) {
462 $style = $this->model->style;
463 $css = array();
464
465 foreach ( $style as $styleType => $styleValue ) {
466 if (
467 $styleValue &&
468 ! ( $this->skipSharedStyleRender && $styleType == 'shared' )
469 ) {
470 $css[ $styleType ] = $this->convertStyleToCss(
471 $styleValue,
472 array(
473 'styledElementsByName' => $this->styledElementsByName,
474 'styleType' => $styleType,
475 )
476 );
477 }
478 }
479
480 if ( $dynamicStyle ) {
481 $css['dynamic'] = $this->convertStyleToCss(
482 self::normalizeDynamicStyle( $dynamicStyle ),
483 array(
484 'styledElementsByName' => $this->styledElementsByName,
485 'styleType' => 'dynamic',
486 )
487 );
488 }
489
490 return $css;
491 }
492
493 public function convertStyleToCss( $style, $settings ) {
494 $styleType = LodashBasic::get( $settings, 'styleType', 'shared' );
495 $rootPrefix = LodashBasic::get(
496 $settings,
497 'prefix',
498 self::$prefixSelectorsByType[ $styleType ]
499 );
500
501 $allowedElements = $this->getStyledElementsNames();
502
503 $ancestorsStyle = new AncestorsStyleRender(
504 $style,
505 new AncestorsStyleContext(
506 $this->model,
507 $allowedElements,
508 $this->htmlSupport
509 )
510 );
511
512 $composeSelectorWithPrefix = function (
513 $ancestor,
514 $element,
515 $state
516 ) use (
517 $rootPrefix,
518 $styleType
519 ) {
520 return $this->composeSelector(
521 $rootPrefix,
522 $styleType,
523 $ancestor,
524 $element,
525 $state
526 );
527 };
528
529 $jssByMedia = $ancestorsStyle->toCss( $composeSelectorWithPrefix, $styleType );
530
531 $cssByMedia = array();
532 foreach ( $jssByMedia as $media => $jssOnMedia ) {
533 LodashBasic::set(
534 $cssByMedia,
535 array( $media ),
536 array( self::renderJssToCss( $jssOnMedia ) )
537 );
538 }
539 return $cssByMedia;
540 }
541
542 public function getStyledElementsNames() {
543 return LodashBasic::concat( array(), array_keys( $this->styledElementsByName ) );
544 }
545
546 public function composeSelector(
547 $rootPrefix,
548 $styleType,
549 $ancestor,
550 $element,
551 $state
552 ) {
553 $elementConfig = $this->getElementData( $element );
554 $selectors = array();
555
556 if ( $elementConfig->usePrefix ) {
557 $selectors[] = $rootPrefix;
558 }
559
560 if ( $this->useParentPrefix || $elementConfig->useParentPrefix ) {
561 $selectors = array_merge( $selectors, $this->prefixParents );
562 }
563
564 $ancestorSelector =
565 $ancestor === 'default' ? '' : $this->ancestorToSelector( $ancestor );
566 $shouldPrependAncestor = $elementConfig->shouldPrependAncestor(
567 $ancestor
568 );
569 if ( $ancestorSelector && $shouldPrependAncestor ) {
570 $selectors[] = $ancestorSelector;
571 }
572
573 $isWrapperElement = $this->wrapperElement === $element;
574
575 $shouldPrefixWithWrapperSelector =
576 $this->wrapperElement &&
577 ( $elementConfig->selector || $elementConfig->useWrapperPrefix ) &&
578 $elementConfig->usePrefix &&
579 ! $isWrapperElement;
580
581 if ( $shouldPrefixWithWrapperSelector ) {
582 $selectors[] = $this->composeElementSelector(
583 $styleType,
584 $ancestor,
585 $this->wrapperElement
586 );
587 }
588
589 $stateConfig = $elementConfig->getStateConfig( $state );
590
591 if ( $stateConfig->stateRedirectElement ) {
592 $stateElementSelector = $this->composeElementSelector(
593 $styleType,
594 $ancestor,
595 $stateConfig->stateRedirectElement,
596 $state
597 );
598 $selectors[] = $stateElementSelector;
599
600 if ( $elementConfig->shouldAppendStateSelector() ) {
601 $selectors[] = '&' . $stateConfig->selector;
602 }
603 }
604
605 $mainSelector = $this->composeElementSelector(
606 $styleType,
607 $ancestor,
608 $element,
609 $state
610 );
611
612 if ( $ancestorSelector && ! $shouldPrependAncestor ) {
613 $mainSelector = $ancestorSelector . $mainSelector;
614 }
615
616 $selectors[] = $mainSelector;
617 if (
618 $elementConfig->shouldAppendStateSelector() &&
619 ! $stateConfig->stateRedirectElement &&
620 $stateConfig->selector
621 ) {
622 $selectors[] = '&' . $stateConfig->selector;
623 }
624
625 return $selectors;
626 }
627
628 public function getElementData( $elementName ) {
629 $elementConfig = isset( $this->styledElementsByName[ $elementName ] )
630 ? $this->styledElementsByName[ $elementName ]
631 : array();
632 return new ElementConfig(
633 array_merge( array( 'statesById' => $this->statesById ), $elementConfig )
634 );
635 }
636
637 /**
638 * @param $styleType
639 * @param $ancestor
640 * @param $element
641 *
642 * @return bool|string
643 */
644 public function composeElementSelector(
645 $styleType,
646 $ancestor,
647 $element,
648 $state = null
649 ) {
650 $elementConfig = $this->getElementData( $element );
651 $elementSelector = $elementConfig->getSelector( $state );
652 $isWrapperElement =
653 $this->wrapperElement && $this->wrapperElement === $element;
654
655 if (
656 $elementSelector === false ||
657 ( $isWrapperElement && $elementSelector )
658 ) {
659 $prefixWithTag =
660 $elementConfig->prefixWithTag === true
661 ? $elementConfig->props['tag']
662 : $elementConfig->prefixWithTag;
663
664 if ( isset( $elementConfig->props['htmlTag'] ) && $elementConfig->prefixWithTag === true ) {
665 $prefixWithTag = $elementConfig->props['htmlTag'];
666 }
667
668 $composedSelector = $this->componentInstanceClass(
669 $element,
670 $styleType,
671 true,
672 $elementConfig->prefixWithTag ? $prefixWithTag : false
673 );
674
675 if ( $elementSelector ) {
676 if ( $elementConfig->selectorPrepend ) {
677 $composedSelector = self::composeSelectors(
678 $elementSelector,
679 '&' . $composedSelector
680 );
681 } else {
682 $composedSelector = self::composeSelectors(
683 $composedSelector,
684 $elementSelector
685 );
686 }
687 }
688
689 $elementSelector = $composedSelector;
690 }
691
692 return $elementSelector;
693 }
694
695 public function componentInstanceClass(
696 $name,
697 $type,
698 $asSelector = false,
699 $tag = false
700 ) {
701 $id = $this->model->styleRef;
702 switch ( $type ) {
703 case 'local':
704 $id = $this->componentLocalInstanceId( $type );
705 break;
706 }
707
708 $style_prefix = apply_filters(
709 'kubio/element-style-class-prefix',
710 'style-'
711 );
712
713 $tagPrefix = $tag ? $tag : '';
714 $className = $style_prefix . $id . ( $name ? '-' . $name : '' );
715 return $asSelector ? $tagPrefix . '.' . $className : $className;
716 }
717
718 public function componentLocalInstanceId( $type ) {
719 return $type . '-' . $this->model->id;
720 }
721
722 public static function renderJssToCss( $jss, $inherited_selector = '' ) {
723 $result = '';
724 $nested = array();
725 $properties = array();
726
727 $style_join = array(
728 'new_line' => '',
729 'tab' => '',
730 );
731
732 if ( CoreUtils::isDebug() ) {
733 $style_join = array(
734 'new_line' => "\n",
735 'tab' => "\t",
736 );
737 }
738
739 foreach ( $jss as $key => $value ) {
740 if ( ! is_array( $value ) ) {
741 $properties[] = join(
742 ':',
743 array(
744 LodashBasic::kebabCase( $key ),
745 $value,
746 )
747 );
748 } else {
749 $nested[ $key ] = $value;
750 }
751 }
752
753 if ( count( $properties ) ) {
754 $result .=
755 $inherited_selector .
756 "{{$style_join['new_line']}" .
757 join( ';', $properties ) . ';' .
758 "{$style_join['new_line']}}{$style_join['new_line']}";
759 }
760
761 foreach ( $nested as $nested_selector => $value ) {
762 $new_selector = self::composeSelectors(
763 $inherited_selector,
764 $nested_selector
765 );
766 $result .= self::renderJssToCss( $value, $new_selector );
767 }
768
769 return $result;
770 }
771
772 public static function composeSelectors(
773 $inherited_selector_str,
774 $nested_selector
775 ) {
776 $selector_parts = array();
777 $selectors = explode( ',', $nested_selector );
778 $inherited_selectors = explode( ',', $inherited_selector_str );
779
780 foreach ( $inherited_selectors as $inherited_selector ) {
781 $inherited_selector = \_\trim( $inherited_selector );
782
783 foreach ( $selectors as $selector ) {
784 $selector = \_\trim( $selector );
785 $is_compounded = strpos( $selector, '&' ) !== false;
786
787 if ( $is_compounded ) {
788 $compounded_selector = str_replace( '&', trim( $inherited_selector ), $selector );
789 array_push(
790 $selector_parts,
791 $compounded_selector
792 );
793 } else {
794 array_push(
795 $selector_parts,
796 join(
797 ' ',
798 LodashBasic::compact( array( $inherited_selector, trim( $selector ) ) )
799 )
800 );
801 }
802 }
803 }
804 $selector_parts = array_map(function($part) {
805 $bodySelector = '@body';
806 if(!str_contains($part, $bodySelector)) {
807 return $part;
808 }
809 $newRootSelector = 'body:not(.extra-1)';
810 $part = str_replace($bodySelector, "", $part);
811
812 //only apply the body changes to the new users to not have issues with backward compatability
813 if(Flags::getSetting( 'enableTypographyBodySelector')) {
814 $part = str_replace("#kubio", $newRootSelector, $part);
815 }
816
817 return $part;
818 }, $selector_parts);
819
820 return join( ',', LodashBasic::uniq( $selector_parts ) );
821 }
822
823 public static function normalizeDynamicStyle( $dynamicStyleByElements ) {
824 $converted = array();
825 foreach ( $dynamicStyleByElements as $elementName => $styleByMedia ) {
826 $newStyle = array( 'media' => array() );
827 if ( isset( $styleByMedia['desktop'] ) ) {
828 $newStyle = $styleByMedia['desktop'];
829 }
830 foreach ( $styleByMedia as $media => $style ) {
831 if ( $media !== 'desktop' ) {
832 LodashBasic::set( $newStyle, array( 'media', $media ), $style );
833 }
834 }
835 LodashBasic::set(
836 $converted,
837 array( 'descendants', $elementName ),
838 $newStyle
839 );
840 }
841 return $converted;
842 }
843 public function ancestorToSelector( $name ) {
844 $selector = Config::value( array( 'ancestors', $name, 'selector' ) );
845 return $selector;
846 }
847 }
848