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 / expanders / border-shorthand-expander.php

border-shorthand-expander.php in Elementor Website Builder – more than just a page builder 4.3.1, at modules/atomic-widgets/css-converter/expanders/border-shorthand-expander.php

150 lines 4.5 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\Expanders;
4
5 use Elementor\Modules\AtomicWidgets\CssConverter\Css_Var_Token_Resolver;
6 use Elementor\Modules\AtomicWidgets\CssConverter\Shorthand_Expander_Base;
7 use Elementor\Modules\AtomicWidgets\CssConverter\ValueParsers\Css_Token_Splitter;
8 use Elementor\Modules\AtomicWidgets\CssConverter\ValueParsers\Size_Value_Parser;
9 use Elementor\Modules\Variables\Services\Variables_Service;
10
11 if ( ! defined( 'ABSPATH' ) ) {
12 exit; // Exit if accessed directly.
13 }
14
15 /**
16 * Expands a `border` / `border-{side}` shorthand into its width / style / color longhands. There is no
17 * aggregate Border prop type; these are independent longhands, so this is a split, not a merge. The
18 * concrete longhand property names are injected, so the same logic serves the all-sides `border`
19 * (border-width/style/color) and each per-side shorthand (e.g. border-top-width/style/color).
20 *
21 * Each token is classified once: a border-style keyword (enum from the live schema) -> style; a length
22 * the Size parser accepts, or a width keyword (thin/medium/thick) -> width; anything else -> color (the
23 * catch-all, mirroring the raw-passthrough color converter). Only the parts present are emitted (omitted
24 * parts are not reset to CSS initials). A second token for an already filled role is ambiguous, so the
25 * whole expansion declines and the original shorthand is kept for custom_css. A produced longhand can
26 * still individually decline downstream (e.g. `border-{side}-style`, which has no converter), degrading
27 * to custom_css for that part only.
28 */
29 class Border_Shorthand_Expander extends Shorthand_Expander_Base {
30 const WIDTH_KEYWORDS = [ 'thin', 'medium', 'thick' ];
31 const ROLE_WIDTH = 'width';
32 const ROLE_STYLE = 'style';
33 const ROLE_COLOR = 'color';
34
35 private string $property;
36
37 /**
38 * @var array<string, string> Role (width|style|color) -> emitted longhand property name.
39 */
40 private array $longhands;
41
42 /**
43 * @var string[]
44 */
45 private array $style_keywords;
46
47 private ?Variables_Service $variables_service;
48
49 /**
50 * @param string $property The shorthand this expander owns (border, border-top, ...).
51 * @param array<string, string> $longhands Role -> longhand property name to emit.
52 * @param string[] $style_keywords The border-style enum, sourced from the live schema.
53 */
54 public function __construct(
55 string $property,
56 array $longhands,
57 array $style_keywords,
58 ?Variables_Service $variables_service = null
59 ) {
60 $this->property = $property;
61 $this->longhands = $longhands;
62 $this->style_keywords = $style_keywords;
63 $this->variables_service = $variables_service;
64 }
65
66 protected function get_supported_properties(): array {
67 return [ $this->property ];
68 }
69
70 protected function expand_null( array $rule ): array {
71 return array_map( fn( $p ) => $this->null_rule( $p ), array_values( $this->longhands ) );
72 }
73
74 protected function do_expand( array $rule ): array {
75 $value = $rule['value'];
76
77 $tokens = Css_Token_Splitter::split_by_whitespace( trim( $value ) );
78
79 if ( empty( $tokens ) ) {
80 return [];
81 }
82
83 $slots = [
84 self::ROLE_WIDTH => null,
85 self::ROLE_STYLE => null,
86 self::ROLE_COLOR => null,
87 ];
88
89 foreach ( $tokens as $token ) {
90 $role = $this->classify_token( $token );
91
92 if ( null === $role || null !== $slots[ $role ] ) {
93 return [];
94 }
95
96 $slots[ $role ] = $token;
97 }
98
99 $rules = [];
100
101 foreach ( $slots as $role => $slot_value ) {
102 if ( null === $slot_value ) {
103 continue;
104 }
105
106 $property = $this->longhands[ $role ];
107
108 $rules[] = [
109 'property' => $property,
110 'value' => $slot_value,
111 'declaration' => $property . ': ' . $slot_value,
112 ];
113 }
114
115 return $rules;
116 }
117
118 private function classify_token( string $token ): ?string {
119 if ( Css_Var_Token_Resolver::is_var_only_token( $token ) ) {
120 $resolved_type = Css_Var_Token_Resolver::resolve_var_only_token_type( $this->variables_service, $token );
121
122 if ( 'color' === $resolved_type ) {
123 return self::ROLE_COLOR;
124 }
125
126 if ( 'size' === $resolved_type ) {
127 return self::ROLE_WIDTH;
128 }
129
130 return null;
131 }
132
133 return $this->classify_literal_token( $token );
134 }
135
136 private function classify_literal_token( string $token ): string {
137 $lower = strtolower( $token );
138
139 if ( in_array( $lower, $this->style_keywords, true ) ) {
140 return self::ROLE_STYLE;
141 }
142
143 if ( in_array( $lower, self::WIDTH_KEYWORDS, true ) || null !== Size_Value_Parser::parse( $token ) ) {
144 return self::ROLE_WIDTH;
145 }
146
147 return self::ROLE_COLOR;
148 }
149 }
150