| @@ -71,15 +71,114 @@ | ||
| 71 | 71 | ]; |
| 72 | 72 | } |
| 73 | 73 | |
| 74 | 74 | /** |
| 75 | - * Choose displayed step image URL (same rules as step-marker / filled-bar TS). | |
| 75 | + * Read step image URL from step array (new key with legacy fallback). | |
| 76 | 76 | * |
| 77 | - * @param bool $is_step_active Whether step is active or completed. | |
| 78 | - * @param string $active_url Active image URL. | |
| 79 | - * @param string $inactive_url Inactive image URL. | |
| 77 | + * @param array<string, mixed> $step Step data. | |
| 80 | 78 | * @return string |
| 81 | 79 | */ |
| 80 | + public static function get_step_image_url( $step ) { | |
| 81 | + if ( ! is_array( $step ) ) { | |
| 82 | + return ''; | |
| 83 | + } | |
| 84 | + $image_url = isset( $step['image_url'] ) ? trim( (string) $step['image_url'] ) : ''; | |
| 85 | + if ( '' !== $image_url ) { | |
| 86 | + return $image_url; | |
| 87 | + } | |
| 88 | + $active = isset( $step['image_active_url'] ) ? trim( (string) $step['image_active_url'] ) : ''; | |
| 89 | + if ( '' !== $active ) { | |
| 90 | + return $active; | |
| 91 | + } | |
| 92 | + return isset( $step['image_inactive_url'] ) ? trim( (string) $step['image_inactive_url'] ) : ''; | |
| 93 | + } | |
| 94 | + | |
| 95 | + /** | |
| 96 | + * Element-level active/inactive label color (per-step legacy overrides on read). | |
| 97 | + * | |
| 98 | + * @param array<string, mixed> $step Step data. | |
| 99 | + * @param bool $is_step_active Whether the step is active or completed. | |
| 100 | + * @param string $label_active_color Element label color (active). | |
| 101 | + * @param string $label_inactive_color Element label color (inactive). | |
| 102 | + * @return string | |
| 103 | + */ | |
| 104 | + public static function get_step_label_color( | |
| 105 | + $step, | |
| 106 | + $is_step_active, | |
| 107 | + $label_active_color = '#111827', | |
| 108 | + $label_inactive_color = '#9CA3AF' | |
| 109 | + ) { | |
| 110 | + if ( is_array( $step ) ) { | |
| 111 | + $label_color = isset( $step['label_color'] ) ? trim( (string) $step['label_color'] ) : ''; | |
| 112 | + if ( '' !== $label_color ) { | |
| 113 | + return $label_color; | |
| 114 | + } | |
| 115 | + if ( $is_step_active ) { | |
| 116 | + $legacy_active = isset( $step['label_active_color'] ) ? trim( (string) $step['label_active_color'] ) : ''; | |
| 117 | + if ( '' !== $legacy_active ) { | |
| 118 | + return $legacy_active; | |
| 119 | + } | |
| 120 | + } else { | |
| 121 | + $legacy_inactive = isset( $step['label_inactive_color'] ) ? trim( (string) $step['label_inactive_color'] ) : ''; | |
| 122 | + if ( '' !== $legacy_inactive ) { | |
| 123 | + return $legacy_inactive; | |
| 124 | + } | |
| 125 | + } | |
| 126 | + } | |
| 127 | + | |
| 128 | + $active_color = trim( (string) $label_active_color ); | |
| 129 | + $inactive_color = trim( (string) $label_inactive_color ); | |
| 130 | + | |
| 131 | + if ( $is_step_active ) { | |
| 132 | + return '' !== $active_color ? $active_color : '#111827'; | |
| 133 | + } | |
| 134 | + | |
| 135 | + return '' !== $inactive_color ? $inactive_color : '#9CA3AF'; | |
| 136 | + } | |
| 137 | + | |
| 138 | + /** | |
| 139 | + * Filled-bar icon border from step (new keys with legacy fallback). | |
| 140 | + * | |
| 141 | + * @param array<string, mixed> $step Step data. | |
| 142 | + * @return array{color: string, style: string, width_px: int} | |
| 143 | + */ | |
| 144 | + public static function get_step_icon_border( $step ) { | |
| 145 | + $fallback_color = '#c9a8ff'; | |
| 146 | + if ( ! is_array( $step ) ) { | |
| 147 | + return [ | |
| 148 | + 'color' => $fallback_color, | |
| 149 | + 'style' => 'solid', | |
| 150 | + 'width_px' => 2, | |
| 151 | + ]; | |
| 152 | + } | |
| 153 | + $color = isset( $step['icon_border_color'] ) ? trim( (string) $step['icon_border_color'] ) : ''; | |
| 154 | + if ( '' === $color && isset( $step['filled_bar_icon_border_color_active'] ) ) { | |
| 155 | + $color = trim( (string) $step['filled_bar_icon_border_color_active'] ); | |
| 156 | + } | |
| 157 | + if ( '' === $color && isset( $step['filled_bar_icon_border_color_inactive'] ) ) { | |
| 158 | + $color = trim( (string) $step['filled_bar_icon_border_color_inactive'] ); | |
| 159 | + } | |
| 160 | + if ( '' === $color ) { | |
| 161 | + $color = $fallback_color; | |
| 162 | + } | |
| 163 | + $style = isset( $step['icon_border_style'] ) ? strtolower( trim( (string) $step['icon_border_style'] ) ) : 'solid'; | |
| 164 | + if ( ! in_array( $style, [ 'solid', 'dashed', 'dotted' ], true ) ) { | |
| 165 | + $style = 'solid'; | |
| 166 | + } | |
| 167 | + $width_px = 2; | |
| 168 | + if ( isset( $step['icon_border_width'] ) ) { | |
| 169 | + $width_px = max( 0, min( 10, (int) round( (float) $step['icon_border_width'] ) ) ); | |
| 170 | + } | |
| 171 | + return [ | |
| 172 | + 'color' => $color, | |
| 173 | + 'style' => $style, | |
| 174 | + 'width_px' => $width_px, | |
| 175 | + ]; | |
| 176 | + } | |
| 177 | + | |
| 178 | + /** | |
| 179 | + * @deprecated Use get_step_image_url() on step array. | |
| 180 | + */ | |
| 82 | 181 | public static function resolve_step_image_url( $is_step_active, $active_url, $inactive_url ) { |
| 83 | 182 | $active_url = (string) $active_url; |
| 84 | 183 | $inactive_url = (string) $inactive_url; |
| 85 | 184 | $chosen = $is_step_active ? $active_url : $inactive_url; |
| @@ -89,71 +188,75 @@ | ||
| 89 | 188 | return '' !== $active_url ? $active_url : $inactive_url; |
| 90 | 189 | } |
| 91 | 190 | |
| 92 | 191 | /** |
| 93 | - * Filled-bar icon pill background: inactive steps always use #E2E6EE. | |
| 192 | + * Filled-bar label text color (per-step label_color with legacy fallbacks). | |
| 94 | 193 | * |
| 95 | - * @param bool $is_step_active Whether step is active or completed. | |
| 96 | - * @param string $raw_image_bg_color Per-step image background (may be empty). | |
| 97 | - * @param string $connector_active_color Fallback when active and no per-step color. | |
| 194 | + * @param array<string, mixed> $step Step data. | |
| 195 | + * @param string $legacy_label_color Legacy single label color on step. | |
| 196 | + * @param string $global_label_active_color Element default (legacy). | |
| 197 | + * @param string $global_label_inactive_color Element default (legacy). | |
| 98 | 198 | * @return string |
| 99 | 199 | */ |
| 100 | - public static function resolve_filled_bar_icon_background( $is_step_active, $raw_image_bg_color, $connector_active_color ) { | |
| 101 | - $raw_image_bg_color = (string) $raw_image_bg_color; | |
| 102 | - if ( ! $is_step_active ) { | |
| 103 | - return '#E2E6EE'; | |
| 104 | - } | |
| 105 | - return '' !== $raw_image_bg_color ? $raw_image_bg_color : $connector_active_color; | |
| 200 | + public static function resolve_filled_bar_label_color( | |
| 201 | + $step, | |
| 202 | + $is_step_active, | |
| 203 | + $label_active_color = '#111827', | |
| 204 | + $label_inactive_color = '#9CA3AF' | |
| 205 | + ) { | |
| 206 | + return self::get_step_label_color( | |
| 207 | + $step, | |
| 208 | + $is_step_active, | |
| 209 | + $label_active_color, | |
| 210 | + $label_inactive_color | |
| 211 | + ); | |
| 106 | 212 | } |
| 107 | 213 | |
| 108 | 214 | /** |
| 109 | - * Filled-bar label text color (legacy label_color overrides per-step / global). | |
| 215 | + * Filled-bar icon wrapper border color (single per-step color). | |
| 110 | 216 | * |
| 111 | - * @param string $legacy_label_color Legacy single label color override. | |
| 112 | - * @param bool $is_step_active Whether label is for active step. | |
| 113 | - * @param string $step_label_active_color Per-step active color. | |
| 114 | - * @param string $step_label_inactive_color Per-step inactive color. | |
| 115 | - * @param string $global_label_active_color Element default active label color. | |
| 116 | - * @param string $global_label_inactive_color Element default inactive label color. | |
| 217 | + * @param array<string, mixed> $step Step data. | |
| 117 | 218 | * @return string |
| 118 | 219 | */ |
| 119 | - public static function resolve_filled_bar_label_color( | |
| 120 | - $legacy_label_color, | |
| 121 | - $is_step_active, | |
| 122 | - $step_label_active_color, | |
| 123 | - $step_label_inactive_color, | |
| 124 | - $global_label_active_color, | |
| 125 | - $global_label_inactive_color | |
| 126 | - ) { | |
| 127 | - $legacy_label_color = (string) $legacy_label_color; | |
| 128 | - if ( '' !== $legacy_label_color ) { | |
| 129 | - return $legacy_label_color; | |
| 220 | + public static function resolve_filled_bar_icon_border_color( $step ) { | |
| 221 | + $border = self::get_step_icon_border( $step ); | |
| 222 | + return $border['color']; | |
| 223 | + } | |
| 224 | + | |
| 225 | + /** | |
| 226 | + * Step-marker current-step accent: per-step image_bg_color when set, else connector active. | |
| 227 | + * | |
| 228 | + * @param array<string, mixed> $step Step data. | |
| 229 | + * @param string $connector_active_color Element connector active color. | |
| 230 | + * @return string | |
| 231 | + */ | |
| 232 | + public static function resolve_step_marker_accent_color( $step, $connector_active_color ) { | |
| 233 | + if ( is_array( $step ) ) { | |
| 234 | + $bg = trim( (string) ( $step['image_bg_color'] ?? '' ) ); | |
| 235 | + if ( '' !== $bg ) { | |
| 236 | + return $bg; | |
| 237 | + } | |
| 130 | 238 | } |
| 131 | - $step_label_active_color = (string) $step_label_active_color; | |
| 132 | - $step_label_inactive_color = (string) $step_label_inactive_color; | |
| 133 | - if ( $is_step_active ) { | |
| 134 | - return '' !== $step_label_active_color ? $step_label_active_color : $global_label_active_color; | |
| 135 | - } | |
| 136 | - return '' !== $step_label_inactive_color ? $step_label_inactive_color : $global_label_inactive_color; | |
| 239 | + return (string) $connector_active_color; | |
| 137 | 240 | } |
| 138 | 241 | |
| 139 | 242 | /** |
| 140 | - * Filled-bar icon wrapper border-color by step state. | |
| 243 | + * Blend a hex color toward white (step-marker ring border). | |
| 141 | 244 | * |
| 142 | - * @param bool $is_step_active Whether step is active or completed. | |
| 143 | - * @param string $raw_active Per-step border color when active. | |
| 144 | - * @param string $raw_inactive Per-step border color when inactive. | |
| 245 | + * @param string $hex Color such as #2563eb. | |
| 246 | + * @param float $amount Blend amount 0–1. | |
| 145 | 247 | * @return string |
| 146 | 248 | */ |
| 147 | - public static function resolve_filled_bar_icon_border_color( $is_step_active, $raw_active, $raw_inactive ) { | |
| 148 | - $fallback_active = '#c9a8ff'; | |
| 149 | - $fallback_inactive = '#e2e6ee'; | |
| 150 | - $raw_active = trim( (string) $raw_active ); | |
| 151 | - $raw_inactive = trim( (string) $raw_inactive ); | |
| 152 | - | |
| 153 | - if ( $is_step_active ) { | |
| 154 | - return '' !== $raw_active ? $raw_active : $fallback_active; | |
| 249 | + public static function blend_hex_with_white( $hex, $amount = 0.55 ) { | |
| 250 | + $raw = ltrim( (string) $hex, '#' ); | |
| 251 | + if ( 6 !== strlen( $raw ) || ! ctype_xdigit( $raw ) ) { | |
| 252 | + return '#C4B0E8'; | |
| 155 | 253 | } |
| 156 | - | |
| 157 | - return '' !== $raw_inactive ? $raw_inactive : $fallback_inactive; | |
| 254 | + $r0 = hexdec( substr( $raw, 0, 2 ) ); | |
| 255 | + $g0 = hexdec( substr( $raw, 2, 2 ) ); | |
| 256 | + $b0 = hexdec( substr( $raw, 4, 2 ) ); | |
| 257 | + $mix = static function ( $c ) use ( $amount ) { | |
| 258 | + return (int) round( $c + ( 255 - $c ) * $amount ); | |
| 259 | + }; | |
| 260 | + return sprintf( '#%02x%02x%02x', $mix( $r0 ), $mix( $g0 ), $mix( $b0 ) ); | |
| 158 | 261 | } |
| 159 | 262 | } |