| @@ -99,14 +99,14 @@ | ||
| 99 | 99 | // values. Controls that hardcode only Tablet/Mobile defaults emit |
| 100 | 100 | // "phantom" declarations (e.g. border-width:0) for any unknown suffix; |
| 101 | 101 | // subtracting the phantom leaves only genuinely-overridden custom values, |
| 102 | 102 | // with no per-control changes. |
| 103 | - $phantom = (array) call_user_func( $builder, '__ablocksphantom__' ); | |
| 103 | + $phantom = \ABlocks\Helper::call_device_builder( $builder, '__ablocksphantom__' ); | |
| 104 | 104 | foreach ( $custom_devices as $d ) { |
| 105 | 105 | if ( $d['width'] <= 0 || 'Tablet' === $d['id'] || 'Mobile' === $d['id'] ) { |
| 106 | 106 | continue; |
| 107 | 107 | } |
| 108 | - $actual = (array) call_user_func( $builder, $d['suffix'] ); | |
| 108 | + $actual = \ABlocks\Helper::call_device_builder( $builder, $d['suffix'] ); | |
| 109 | 109 | $real = []; |
| 110 | 110 | foreach ( $actual as $prop => $val ) { |
| 111 | 111 | if ( ! array_key_exists( $prop, $phantom ) || $phantom[ $prop ] !== $val ) { |
| 112 | 112 | $real[ $prop ] = $val; |
| @@ -167,9 +167,9 @@ | ||
| 167 | 167 | } |
| 168 | 168 | } else { |
| 169 | 169 | // Custom breakpoints present: emit every breakpoint in |
| 170 | 170 | // width-descending order (narrowest last so it wins the cascade), |
| 171 | - // each deduped against desktop. | |
| 171 | + // each deduped against what it inherits. | |
| 172 | 172 | $bp_defaults = \ABlocks\Helper::get_breakpoints(); |
| 173 | 173 | $bp_list = [ |
| 174 | 174 | [ 'width' => $bp_defaults['tablet'], 'min' => 0, 'max' => $bp_defaults['tablet'], 'styles' => $class_style['tablet_styles'] ], |
| 175 | 175 | [ 'width' => $bp_defaults['mobile'], 'min' => 0, 'max' => $bp_defaults['mobile'], 'styles' => $class_style['mobile_styles'] ], |
| @@ -185,12 +185,24 @@ | ||
| 185 | 185 | usort( $bp_list, function ( $a, $b ) { |
| 186 | 186 | return (int) $b['width'] - (int) $a['width']; |
| 187 | 187 | } ); |
| 188 | 188 | |
| 189 | - foreach ( $bp_list as $bp ) { | |
| 190 | - $bp_styles = $this->filter_responsive_styles( $desktop_styles, $bp['styles'] ); | |
| 191 | - $bp_raw = $this->generate_css_for_media_query( 'bp', $bp_styles ); | |
| 192 | - if ( $bp_raw === $desktop_raw || '' === trim( $bp_raw ) ) { | |
| 189 | + $emitted = []; | |
| 190 | + foreach ( $bp_list as $i => $bp ) { | |
| 191 | + // Dedupe against what this breakpoint inherits — desktop plus every | |
| 192 | + // wider breakpoint whose range contains it — not desktop alone, so an | |
| 193 | + // explicit value that equals desktop's still overrides a wider | |
| 194 | + // custom breakpoint's. | |
| 195 | + $parent = $desktop_styles; | |
| 196 | + for ( $j = 0; $j < $i; $j++ ) { | |
| 197 | + if ( \ABlocks\Helper::breakpoint_contains( $bp_list[ $j ], $bp ) ) { | |
| 198 | + $parent = array_merge( $parent, $emitted[ $j ] ); | |
| 199 | + } | |
| 200 | + } | |
| 201 | + $bp_styles = $this->filter_responsive_styles( $parent, $bp['styles'] ); | |
| 202 | + $emitted[ $i ] = $bp_styles; | |
| 203 | + $bp_raw = $this->generate_css_for_media_query( 'bp', $bp_styles ); | |
| 204 | + if ( '' === trim( $bp_raw ) ) { | |
| 193 | 205 | continue; |
| 194 | 206 | } |
| 195 | 207 | $bp_css = AssetsGenerator::minify_css( $bp_raw ); |
| 196 | 208 | $media = \ABlocks\Helper::breakpoint_media_condition( $bp['min'], $bp['max'] ); |