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