| 1 |
<?php |
| 2 |
|
| 3 |
namespace Elementor\Modules\AtomicWidgets\CssConverter\Expanders; |
| 4 |
|
| 5 |
use Elementor\Modules\AtomicWidgets\CssConverter\Shorthand_Expander_Base; |
| 6 |
use Elementor\Modules\AtomicWidgets\CssConverter\ValueParsers\Css_Token_Splitter; |
| 7 |
use Elementor\Modules\AtomicWidgets\CssConverter\ValueParsers\Size_Value_Parser; |
| 8 |
|
| 9 |
if ( ! defined( 'ABSPATH' ) ) { |
| 10 |
exit; // Exit if accessed directly. |
| 11 |
} |
| 12 |
|
| 13 |
/** |
| 14 |
* Expands the `outline` shorthand into its supported longhands (outline-width, outline-style, |
| 15 |
* outline-color). Token classification mirrors the border expander: a style keyword -> style; a |
| 16 |
* length or width keyword -> width; anything else -> color. Duplicate roles or unclassifiable |
| 17 |
* tokens cause the whole expansion to decline (-> custom_css). |
| 18 |
* |
| 19 |
* On null reset, outline-offset is also included because it is a supported prop type even though |
| 20 |
* it is not part of the outline shorthand syntax. |
| 21 |
*/ |
| 22 |
class Outline_Shorthand_Expander extends Shorthand_Expander_Base { |
| 23 |
const STYLE_KEYWORDS = [ |
| 24 |
'none', |
| 25 |
'auto', |
| 26 |
'dotted', |
| 27 |
'dashed', |
| 28 |
'solid', |
| 29 |
'double', |
| 30 |
'groove', |
| 31 |
'ridge', |
| 32 |
'inset', |
| 33 |
'outset', |
| 34 |
]; |
| 35 |
|
| 36 |
const WIDTH_KEYWORDS = [ 'thin', 'medium', 'thick' ]; |
| 37 |
|
| 38 |
const SHORTHAND_LONGHANDS = [ |
| 39 |
'width' => 'outline-width', |
| 40 |
'style' => 'outline-style', |
| 41 |
'color' => 'outline-color', |
| 42 |
]; |
| 43 |
|
| 44 |
const ALL_LONGHANDS = [ 'outline-width', 'outline-style', 'outline-color', 'outline-offset' ]; |
| 45 |
|
| 46 |
protected function get_supported_properties(): array { |
| 47 |
return [ 'outline' ]; |
| 48 |
} |
| 49 |
|
| 50 |
protected function expand_null( array $rule ): array { |
| 51 |
return array_map( fn( $p ) => $this->null_rule( $p ), self::ALL_LONGHANDS ); |
| 52 |
} |
| 53 |
|
| 54 |
protected function do_expand( array $rule ): array { |
| 55 |
$tokens = Css_Token_Splitter::split_by_whitespace( trim( $rule['value'] ) ); |
| 56 |
|
| 57 |
if ( empty( $tokens ) ) { |
| 58 |
return []; |
| 59 |
} |
| 60 |
|
| 61 |
$slots = [ |
| 62 |
'width' => null, |
| 63 |
'style' => null, |
| 64 |
'color' => null, |
| 65 |
]; |
| 66 |
|
| 67 |
foreach ( $tokens as $token ) { |
| 68 |
$role = $this->classify_token( $token ); |
| 69 |
|
| 70 |
if ( null === $role || null !== $slots[ $role ] ) { |
| 71 |
return []; |
| 72 |
} |
| 73 |
|
| 74 |
$slots[ $role ] = $token; |
| 75 |
} |
| 76 |
|
| 77 |
$rules = []; |
| 78 |
|
| 79 |
foreach ( $slots as $role => $value ) { |
| 80 |
if ( null === $value ) { |
| 81 |
continue; |
| 82 |
} |
| 83 |
|
| 84 |
$property = self::SHORTHAND_LONGHANDS[ $role ]; |
| 85 |
|
| 86 |
$rules[] = [ |
| 87 |
'property' => $property, |
| 88 |
'value' => $value, |
| 89 |
'declaration' => $property . ': ' . $value, |
| 90 |
]; |
| 91 |
} |
| 92 |
|
| 93 |
return $rules; |
| 94 |
} |
| 95 |
|
| 96 |
private function classify_token( string $token ): ?string { |
| 97 |
$lower = strtolower( $token ); |
| 98 |
|
| 99 |
if ( in_array( $lower, self::STYLE_KEYWORDS, true ) ) { |
| 100 |
return 'style'; |
| 101 |
} |
| 102 |
|
| 103 |
if ( in_array( $lower, self::WIDTH_KEYWORDS, true ) || null !== Size_Value_Parser::parse( $token ) ) { |
| 104 |
return 'width'; |
| 105 |
} |
| 106 |
|
| 107 |
return 'color'; |
| 108 |
} |
| 109 |
} |
| 110 |
|