PluginProbe
Elementor Website Builder – more than just a page builder / 4.3.1
Elementor Website Builder – more than just a page builder v4.3.1
4.3.2 4.3.1 4.3.0 4.3.0-beta3 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 All 455 releases
elementor / modules / atomic-widgets / css-converter / converters / object-side-merge-converter.php

object-side-merge-converter.php in Elementor Website Builder – more than just a page builder 4.3.1, at modules/atomic-widgets/css-converter/converters/object-side-merge-converter.php

132 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\CssConverter\Converters;
4
5 use Elementor\Modules\AtomicWidgets\CssConverter\Conversion_Context;
6 use Elementor\Modules\AtomicWidgets\CssConverter\Property_Converter_Base;
7 use Elementor\Modules\AtomicWidgets\CssConverter\Css_Var_Token_Resolver;
8
9 use Elementor\Modules\AtomicWidgets\CssConverter\ValueParsers\Size_Value_Parser;
10 use Elementor\Modules\AtomicWidgets\PropTypes\Size_Prop_Type;
11 use Elementor\Modules\Variables\Services\Variables_Service;
12
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit; // Exit if accessed directly.
15 }
16
17 /**
18 * Converter for a single side/corner longhand that contributes a fragment to a multi-side object prop:
19 * border-{side}-width -> a side of `border-width` (Border_Width), border-{corner}-radius -> a corner of
20 * `border-radius` (Border_Radius). One instance per input property.
21 *
22 * The target object is accumulated in the shared context across sibling declarations: each instance
23 * reads the current target prop and re-populates it. If the target is already this object it merges the
24 * one side in; if it is the single Size member (e.g. a prior `border-width: 1px`) all sides are seeded
25 * from that single before the override, so the CSS cascade stays faithful; otherwise a fresh object is
26 * created. A value the Size parser rejects declines the declaration (-> custom_css) and leaves the
27 * accumulated object untouched.
28 */
29 class Object_Side_Merge_Converter extends Property_Converter_Base {
30 const SIZE_TYPE = 'size';
31
32 private string $property;
33 private string $target_property;
34 private string $type_key;
35 private string $side_key;
36
37 /**
38 * @var string[]
39 */
40 private array $all_side_keys;
41
42 /**
43 * @var class-string
44 */
45 private string $object_prop_type;
46
47 private ?Variables_Service $variables_service;
48
49 /**
50 * @param string $property The input longhand this converter owns (e.g. border-top-width).
51 * @param string $target_property The aggregate prop it contributes to (e.g. border-width).
52 * @param string $type_key The aggregate object's $$type (e.g. border-width).
53 * @param string $side_key The object key this longhand fills (e.g. block-start).
54 * @param string[] $all_side_keys Every key of the object, used to seed from a single Size.
55 * @param string $object_prop_type Object_Prop_Type class used to wrap the merged sides.
56 * @param Variables_Service|null $variables_service When provided, a var-only value that resolves to a
57 * known size variable is emitted as a variable PropValue
58 * instead of a raw Size leaf.
59 */
60 public function __construct(
61 string $property,
62 string $target_property,
63 string $type_key,
64 string $side_key,
65 array $all_side_keys,
66 string $object_prop_type,
67 ?Variables_Service $variables_service = null
68 ) {
69 $this->property = $property;
70 $this->target_property = $target_property;
71 $this->type_key = $type_key;
72 $this->side_key = $side_key;
73 $this->all_side_keys = $all_side_keys;
74 $this->object_prop_type = $object_prop_type;
75 $this->variables_service = $variables_service;
76 }
77
78 protected function get_supported_properties(): array {
79 return [ $this->property ];
80 }
81
82 protected function convert_null( Conversion_Context $context, array $rule ): bool {
83 $sides = $this->current_sides( $context->get_prop( $this->target_property ) );
84 $sides[ $this->side_key ] = null;
85
86 $context->set_prop( $this->target_property, ( $this->object_prop_type )::generate( $sides ) );
87
88 return true;
89 }
90
91 protected function do_convert( Conversion_Context $context, array $rule ): bool {
92 $value = trim( $rule['value'] );
93 $leaf = Size_Value_Parser::parse( $value );
94
95 if ( null === $leaf ) {
96 return false;
97 }
98
99 $side_value = Css_Var_Token_Resolver::resolve_size_var_prop_value( $this->variables_service, $value )
100 ?? Size_Prop_Type::generate( $leaf );
101
102 $sides = $this->current_sides( $context->get_prop( $this->target_property ) );
103 $sides[ $this->side_key ] = $side_value;
104
105 $context->set_prop( $this->target_property, ( $this->object_prop_type )::generate( $sides ) );
106
107 return true;
108 }
109
110 /**
111 * @param mixed $existing The current target prop value, if any.
112 * @return array<string, array> Side key -> Size PropValue.
113 */
114 private function current_sides( $existing ): array {
115 if ( ! is_array( $existing ) ) {
116 return [];
117 }
118
119 $type = $existing['$$type'] ?? null;
120
121 if ( $this->type_key === $type && is_array( $existing['value'] ?? null ) ) {
122 return $existing['value'];
123 }
124
125 if ( self::SIZE_TYPE === $type ) {
126 return array_fill_keys( $this->all_side_keys, $existing );
127 }
128
129 return [];
130 }
131 }
132