block_name ); // Icon Style $css_generator->add_class_styles( '{{WRAPPER}} .ablocks-icon-wrap', Icon::get_wrapper_css( $attributes ), Icon::get_wrapper_css( $attributes, 'Tablet' ), Icon::get_wrapper_css( $attributes, 'Mobile' ), $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return Icon::get_wrapper_css( $attributes, $device ); } ) ); $css_generator->add_class_styles( '{{WRAPPER}} .ablocks-icon-wrap:hover', Icon::get_wrapper_hover_css( $attributes ), Icon::get_wrapper_hover_css( $attributes, 'Tablet' ), Icon::get_wrapper_hover_css( $attributes, 'Mobile' ), $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return Icon::get_wrapper_hover_css( $attributes, $device ); } ) ); $css_generator->add_class_styles( '{{WRAPPER}} .ablocks-icon-wrap img.ablocks-image-icon', Icon::get_element_image_css( $attributes ), Icon::get_element_image_css( $attributes, 'Tablet' ), Icon::get_element_image_css( $attributes, 'Mobile' ), $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return Icon::get_element_image_css( $attributes, $device ); } ) ); $css_generator->add_class_styles( '{{WRAPPER}} .ablocks-icon-wrap img.ablocks-image-icon:hover', Icon::get_element_image_hover_css( $attributes ), Icon::get_element_image_hover_css( $attributes, 'Tablet' ), Icon::get_element_image_hover_css( $attributes, 'Mobile' ), $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return Icon::get_element_image_hover_css( $attributes, $device ); } ) ); $css_generator->add_class_styles( '{{WRAPPER}} .ablocks-icon-wrap svg.ablocks-svg-icon', Icon::get_element_css( $attributes ), Icon::get_element_css( $attributes, 'Tablet' ), Icon::get_element_css( $attributes, 'Mobile' ), $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return Icon::get_element_css( $attributes, $device ); } ) ); $css_generator->add_class_styles( '{{WRAPPER}} .ablocks-icon-wrap svg.ablocks-svg-icon:hover', Icon::get_element_image_hover_css( $attributes ), Icon::get_element_image_hover_css( $attributes, 'Tablet' ), Icon::get_element_image_hover_css( $attributes, 'Mobile' ), $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return Icon::get_element_image_hover_css( $attributes, $device ); } ) ); // TitleText CSS $css_generator->add_class_styles( '{{WRAPPER}} .ablocks-price-menu-item-details-title', $this->get_title_text_css( $attributes, '' ), $this->get_title_text_css( $attributes, 'Tablet' ), $this->get_title_text_css( $attributes, 'Mobile' ), $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return $this->get_title_text_css( $attributes, $device ); } ) ); // DescriptionText CSS $css_generator->add_class_styles( '{{WRAPPER}} .ablocks-price-menu-item-details-des', $this->get_description_text_css( $attributes, '' ), $this->get_description_text_css( $attributes, 'Tablet' ), $this->get_description_text_css( $attributes, 'Mobile' ), $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return $this->get_description_text_css( $attributes, $device ); } ) ); // SeparatorText CSS $css_generator->add_class_styles( '{{WRAPPER}} .ablocks-price-menu-divider__pattern-' . ( $attributes['dividerType'] === 'mask-style' ? 'mask' : 'css' ), $this->get_divider_css( $attributes, '' ), $this->get_divider_css( $attributes, 'Tablet' ), $this->get_divider_css( $attributes, 'Mobile' ), $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return $this->get_divider_css( $attributes, $device ); } ) ); // PriceText CSS $css_generator->add_class_styles( '{{WRAPPER}} .ablocks-price-menu-item-price', $this->get_price_text_css( $attributes, '' ), $this->get_price_text_css( $attributes, 'Tablet' ), $this->get_price_text_css( $attributes, 'Mobile' ), $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return $this->get_price_text_css( $attributes, $device ); } ) ); // Divider width (item override of the parent's width) $css_generator->add_class_styles( '{{WRAPPER}} .ablocks-divider', self::get_divider_width_css( $attributes, '' ), self::get_divider_width_css( $attributes, 'Tablet' ), self::get_divider_width_css( $attributes, 'Mobile' ), $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return self::get_divider_width_css( $attributes, $device ); } ) ); $css_generator->add_class_styles( '{{WRAPPER}} .ablocks-price-menu-item', self::get_item_width_css( $attributes, '' ), self::get_item_width_css( $attributes, 'Tablet' ), self::get_item_width_css( $attributes, 'Mobile' ), $css_generator->custom_device_map( function ( $device ) use ( $attributes ) { return self::get_item_width_css( $attributes, $device ); } ) ); $css_generator->add_class_styles( '{{WRAPPER}} .ablocks-price-menu-item-details-brief > .ablocks-price-menu-item-price', self::get_price_row_css( $attributes ) ); // Responsive placements: hide the slots not used on each device. foreach ( [ 'divider' => isset( $attributes['placeDivider'] ) ? $attributes['placeDivider'] : '', 'price' => isset( $attributes['placePrice'] ) ? $attributes['placePrice'] : '', ] as $kind => $placement ) { foreach ( self::get_used_placements( $placement ) as $slot ) { $css_generator->add_class_styles( '{{WRAPPER}} .' . self::get_slot_class_name( $kind, $slot ), self::get_slot_css( $placement, $slot, '' ), self::get_slot_css( $placement, $slot, 'Tablet' ), self::get_slot_css( $placement, $slot, 'Mobile' ), $css_generator->custom_device_map( function ( $device ) use ( $placement, $slot ) { return self::get_slot_css( $placement, $slot, $device ); } ) ); } } return $css_generator->generate_css(); } /** * Divider width as a custom property; mirrors get_divider_width_css() in * src/blocks/price-menu-item/styling.js. The parent passes its own property * and default. A width without a stored unit keeps the legacy unit: % with a * description, px without. */ public static function get_divider_width_css( $attributes, $device = '', $property = '--ablocks-pm-item-divider-width', $default_value = null ) { return Range::get_css([ 'attributeValue' => isset( $attributes['width'] ) ? $attributes['width'] : [], 'attributeObjectKey' => 'value', 'isResponsive' => true, 'defaultValue' => $default_value, 'hasUnit' => true, 'unitDefaultValue' => ! empty( $attributes['allowDescription'] ) ? '%' : 'px', 'property' => $property, 'device' => $device, ]); } // A responsive member for the device, inherited from wider devices; '' when unset. private static function resolve_member( $value, $key, $device ) { $target = 'Desktop' === $device ? '' : (string) $device; foreach ( array_merge( [ $target ], Helper::get_responsive_ancestors( $target ) ) as $suffix ) { $member = is_array( $value ) && isset( $value[ $key . $suffix ] ) && ! is_array( $value[ $key . $suffix ] ) ? (string) $value[ $key . $suffix ] : ''; if ( Helper::has_responsive_value( $member ) ) { return $member; } } return ''; } // A % Title & price gap in effect on this device (unit default px). public static function is_percent_title_price_gap( $attributes, $device = '' ) { $gap = isset( $attributes['titlePriceGap'] ) ? $attributes['titlePriceGap'] : []; return '' !== self::resolve_member( $gap, 'value', $device ) && '%' === Range::get_unit( [ 'attributeValue' => $gap, 'attributeObjectKey' => 'value', 'unitDefaultValue' => 'px', 'device' => $device, ] ); } // A % on the title row; mirrors isPercentTitleRow() in styling.js. The legacy // implicit % (Allow description, no stored unit) is left alone. public static function is_percent_title_row( $attributes, $device = '' ) { return self::is_percent_title_price_gap( $attributes, $device ) || ( ! empty( $attributes['allowDivider'] ) && 'near title' === self::get_placement( isset( $attributes['placeDivider'] ) ? $attributes['placeDivider'] : '', $device ) && '%' === self::resolve_member( isset( $attributes['width'] ) ? $attributes['width'] : [], 'valueUnit', $device ) ); } private static function has_percent_unit( $value ) { if ( ! is_array( $value ) ) { return false; } foreach ( $value as $key => $member ) { if ( 0 === strpos( $key, 'valueUnit' ) && '%' === $member ) { return true; } } return false; } public static function has_percent_title_price_gap( $attributes ) { return self::has_percent_unit( isset( $attributes['titlePriceGap'] ) ? $attributes['titlePriceGap'] : [] ); } // Whether any device can use the % title row, so narrower devices that do // not must reset the item width they would otherwise inherit. public static function has_percent_title_row( $attributes ) { return self::has_percent_title_price_gap( $attributes ) || ( ! empty( $attributes['allowDivider'] ) && in_array( 'near title', self::get_used_placements( isset( $attributes['placeDivider'] ) ? $attributes['placeDivider'] : '' ), true ) && self::has_percent_unit( isset( $attributes['width'] ) ? $attributes['width'] : [] ) ); } // Once Price alignment is chosen the item spans its row and the price fills // the space after the title/divider so text-align can position it. A % on // the title row needs the same; mirrors get_item_width_css() in styling.js. public static function get_item_width_css( $attributes, $device = '' ) { if ( ! empty( $attributes['priceAlignmentCustom'] ) ) { return $device ? [] : [ 'width' => '100%' ]; } if ( self::is_percent_title_row( $attributes, $device ) ) { return [ 'width' => '100%' ]; } return $device && self::has_percent_title_row( $attributes ) ? [ 'width' => 'fit-content' ] : []; } public static function get_price_row_css( $attributes ) { return ! empty( $attributes['priceAlignmentCustom'] ) ? [ 'flex-grow' => '1' ] : []; } /** * placeDivider / placePrice: a legacy string or a responsive array * ( value, valueTablet, valueMobile, … ). Mirrors placement.js. */ public static function get_placement( $placement, $device = '' ) { $placement = is_array( $placement ) ? $placement : [ 'value' => (string) $placement ]; $target = 'Desktop' === $device ? '' : (string) $device; foreach ( array_merge( [ $target ], Helper::get_responsive_ancestors( $target ) ) as $suffix ) { $value = isset( $placement[ 'value' . $suffix ] ) ? $placement[ 'value' . $suffix ] : ''; if ( Helper::has_responsive_value( $value ) ) { return $value; } } return ''; } public static function get_used_placements( $placement ) { if ( ! is_array( $placement ) ) { return Helper::has_responsive_value( $placement ) ? [ $placement ] : []; } $used = []; foreach ( $placement as $key => $value ) { if ( 0 === strpos( $key, 'value' ) && is_string( $value ) && Helper::has_responsive_value( $value ) ) { $used[] = $value; } } return array_values( array_unique( $used ) ); } // The placement is a block attribute and this name lands in a selector of // an inline