| @@ -99,14 +99,14 @@ | ||
| 99 | 99 | |
| 100 | 100 | // Subtract a "phantom" baseline (builder run against a value-less suffix) |
| 101 | 101 | // so controls that only default Tablet/Mobile don't leak phantom |
| 102 | 102 | // declarations into custom breakpoints. Leaves only real overrides. |
| 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; |
| @@ -161,9 +161,9 @@ | ||
| 161 | 161 | $addToCssBlocks( 'mobile', $this->get_breakpoint( 'mobile' ), $mobile_css ); |
| 162 | 162 | } |
| 163 | 163 | } else { |
| 164 | 164 | // Custom breakpoints present: emit every breakpoint width-descending |
| 165 | - // (narrowest last so it wins), each deduped against desktop. | |
| 165 | + // (narrowest last so it wins), each deduped against what it inherits. | |
| 166 | 166 | $bp_defaults = \ABlocks\Helper::get_breakpoints(); |
| 167 | 167 | $bp_list = [ |
| 168 | 168 | [ 'width' => $bp_defaults['tablet'], 'min' => 0, 'max' => $bp_defaults['tablet'], 'styles' => $class_style['tablet_styles'] ], |
| 169 | 169 | [ 'width' => $bp_defaults['mobile'], 'min' => 0, 'max' => $bp_defaults['mobile'], 'styles' => $class_style['mobile_styles'] ], |
| @@ -178,12 +178,24 @@ | ||
| 178 | 178 | } |
| 179 | 179 | usort( $bp_list, function ( $a, $b ) { |
| 180 | 180 | return (int) $b['width'] - (int) $a['width']; |
| 181 | 181 | } ); |
| 182 | - foreach ( $bp_list as $bp ) { | |
| 183 | - $bp_styles = $this->filter_responsive_styles( $desktop_styles, $bp['styles'] ); | |
| 184 | - $bp_raw = $this->generate_css_for_media_query( 'bp', $bp_styles ); | |
| 185 | - if ( $bp_raw === $desktop_raw || '' === trim( $bp_raw ) ) { | |
| 182 | + $emitted = []; | |
| 183 | + foreach ( $bp_list as $i => $bp ) { | |
| 184 | + // Dedupe against what this breakpoint inherits — desktop plus every | |
| 185 | + // wider breakpoint whose range contains it — not desktop alone, so an | |
| 186 | + // explicit value that equals desktop's still overrides a wider | |
| 187 | + // custom breakpoint's. | |
| 188 | + $parent = $desktop_styles; | |
| 189 | + for ( $j = 0; $j < $i; $j++ ) { | |
| 190 | + if ( \ABlocks\Helper::breakpoint_contains( $bp_list[ $j ], $bp ) ) { | |
| 191 | + $parent = array_merge( $parent, $emitted[ $j ] ); | |
| 192 | + } | |
| 193 | + } | |
| 194 | + $bp_styles = $this->filter_responsive_styles( $parent, $bp['styles'] ); | |
| 195 | + $emitted[ $i ] = $bp_styles; | |
| 196 | + $bp_raw = $this->generate_css_for_media_query( 'bp', $bp_styles ); | |
| 197 | + if ( '' === trim( $bp_raw ) ) { | |
| 186 | 198 | continue; |
| 187 | 199 | } |
| 188 | 200 | $bp_css = AssetsGenerator::minify_css( $bp_raw ); |
| 189 | 201 | $media = \ABlocks\Helper::breakpoint_media_condition( $bp['min'], $bp['max'] ); |