JezK
Edit File: transition-property-converter.php
<?php namespace Elementor\Modules\AtomicWidgets\CssConverter\Converters; use Elementor\Modules\AtomicWidgets\CssConverter\Conversion_Context; use Elementor\Modules\AtomicWidgets\CssConverter\Property_Converter_Base; use Elementor\Modules\AtomicWidgets\CssConverter\ValueParsers\Css_Token_Splitter; use Elementor\Modules\AtomicWidgets\CssConverter\ValueParsers\Size_Value_Parser; use Elementor\Modules\AtomicWidgets\PropTypes\Key_Value_Prop_Type; use Elementor\Modules\AtomicWidgets\PropTypes\Primitives\String_Prop_Type; use Elementor\Modules\AtomicWidgets\PropTypes\Selection_Size_Prop_Type; use Elementor\Modules\AtomicWidgets\PropTypes\Size_Prop_Type; use Elementor\Modules\AtomicWidgets\PropTypes\Transition_Prop_Type; if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * Converter for the `transition` CSS property -> Transition_Prop_Type (array of Selection_Size). * * Parses comma-separated transition layers. Each layer is whitespace-split into tokens: * <property> <duration> [<easing>] [<delay>] * * Only the property name and the FIRST duration/delay time value are mapped — the schema has no * field for easing or delay, so they are intentionally dropped (silently). * * The `property` token must be in ALLOWED_PROPERTIES (sourced from the Elementor UI data). * Layers with an unrecognised property decline the entire declaration to customCss. * * Time values must be in `s` or `ms`; any other unit declines the layer. */ class Transition_Property_Converter extends Property_Converter_Base { const ALLOWED_PROPERTIES = [ 'all', 'background-color', 'background-position', 'border', 'border-color', 'border-radius', 'border-width', 'box-shadow', 'color', 'filter', 'flex', 'flex-basis', 'flex-grow', 'flex-shrink', 'font-size', 'font-variation-settings', 'height', 'inset-block-end', 'inset-block-start', 'inset-inline-end', 'inset-inline-start', 'letter-spacing', 'line-height', 'margin', 'margin-block-end', 'margin-block-start', 'margin-inline-end', 'margin-inline-start', 'max-height', 'max-width', 'min-height', 'min-width', 'opacity', 'padding', 'padding-block-end', 'padding-block-start', 'padding-inline-end', 'padding-inline-start', 'transform', 'width', 'word-spacing', '-webkit-text-stroke-color', 'z-index', ]; const TIME_UNITS = [ 's', 'ms' ]; protected function get_supported_properties(): array { return [ 'transition' ]; } protected function do_convert( Conversion_Context $context, array $rule ): bool { $layers = Css_Token_Splitter::split_by_comma( trim( $rule['value'] ) ); if ( empty( $layers ) ) { return false; } $items = []; foreach ( $layers as $layer ) { $item = $this->parse_layer( trim( $layer ) ); if ( null === $item ) { return false; } $items[] = $item; } $context->set_prop( 'transition', Transition_Prop_Type::generate( $items ) ); return true; } private function parse_layer( string $layer ): ?array { $tokens = Css_Token_Splitter::split_by_whitespace( $layer ); if ( empty( $tokens ) ) { return null; } $property = strtolower( $tokens[0] ); if ( ! in_array( $property, self::ALLOWED_PROPERTIES, true ) ) { return null; } $duration = $this->find_first_time( array_slice( $tokens, 1 ) ); if ( null === $duration ) { return null; } return Selection_Size_Prop_Type::generate( [ 'selection' => Key_Value_Prop_Type::generate( [ 'key' => String_Prop_Type::generate( $property ), 'value' => String_Prop_Type::generate( $property ), ] ), 'size' => Size_Prop_Type::generate( $duration ), ] ); } private function find_first_time( array $tokens ): ?array { foreach ( $tokens as $token ) { $parsed = Size_Value_Parser::parse( $token ); if ( null !== $parsed && in_array( $parsed['unit'], self::TIME_UNITS, true ) ) { return $parsed; } } return null; } }