| 1 |
<?php |
| 2 |
namespace ABlocks\Blocks\AtomicSvg; |
| 3 |
|
| 4 |
if ( ! defined( 'ABSPATH' ) ) { |
| 5 |
exit; |
| 6 |
} |
| 7 |
|
| 8 |
use ABlocks\Classes\AtomicBlockBase; |
| 9 |
use ABlocks\Classes\AtomicStyles; |
| 10 |
|
| 11 |
/** |
| 12 |
* atomic-svg — inline SVG with the atomic style system (fill / stroke / size). |
| 13 |
* Static markup; only the scoped CSS is rendered here. |
| 14 |
*/ |
| 15 |
class Block extends AtomicBlockBase { |
| 16 |
protected $block_name = 'atomic-svg'; |
| 17 |
|
| 18 |
/** |
| 19 |
* The graphic fills its wrapper by default — that is what makes the Size |
| 20 |
* panel's width resize the icon, since the wrapper shrink-wraps it. |
| 21 |
* |
| 22 |
* `justify-content` asks for the opposite: it positions content inside the |
| 23 |
* box, which needs the graphic to be SMALLER than the box. While the |
| 24 |
* graphic was filling, there was never any free space to distribute, so |
| 25 |
* the control silently did nothing — measured, a 300px-wide block with |
| 26 |
* `justify-content: center` painted a 300px graphic flush to the left edge. |
| 27 |
* |
| 28 |
* So when the author has set it, the graphic takes its own intrinsic size |
| 29 |
* and the wrapper positions it. Emitted per bucket, so it follows the |
| 30 |
* breakpoint and state the author set it in. |
| 31 |
* |
| 32 |
* Skipped for a bucket that ALSO sets Width there: Custom Width is the more |
| 33 |
* specific, more deliberate choice — it is what makes the Size panel resize |
| 34 |
* the icon at all — and must keep winning even once justify-content is set, |
| 35 |
* or reducing it silently stopped doing anything the moment the author also |
| 36 |
* centred the icon: the graphic reverted to its intrinsic size instead of |
| 37 |
* shrinking, and with it the space it occupies inside the wrapper (what |
| 38 |
* Align items / Justify content actually position), so both kept reading |
| 39 |
* the icon's PREVIOUS, unshrunk size. |
| 40 |
*/ |
| 41 |
protected function extra_css( $base, $attributes ) { |
| 42 |
$styles = isset( $attributes['styles'] ) && is_array( $attributes['styles'] ) |
| 43 |
? $attributes['styles'] |
| 44 |
: []; |
| 45 |
|
| 46 |
return AtomicStyles::conditional_rules( |
| 47 |
$styles, |
| 48 |
$base, |
| 49 |
'justify-content', |
| 50 |
' svg', |
| 51 |
'width:auto;max-width:100%;', |
| 52 |
'width' |
| 53 |
) |
| 54 |
. $this->cancel_flex_item_centering( $styles, $base ); |
| 55 |
} |
| 56 |
|
| 57 |
/** |
| 58 |
* Cancel the shared width guard's `margin-left:auto;margin-right:auto` |
| 59 |
* (see StylesSchema::state_declarations()) wherever it actually fired. |
| 60 |
* |
| 61 |
* That guard exists to centre a narrower TOP-LEVEL block — a plain block |
| 62 |
* box, the only shape it was written for. This wrapper is `display: |
| 63 |
* inline-flex`, so in that normal-flow case the auto margins do nothing at |
| 64 |
* all: inline-level boxes never centre on their own horizontal margins. |
| 65 |
* They start doing something only once the wrapper becomes a Flex/Grid |
| 66 |
* ITEM of an Atomic Div/Flex/Grid parent — every value for a flex item's |
| 67 |
* own `display` computes to a block-level "outer display" regardless of |
| 68 |
* what was authored, which is exactly the size at which auto margins |
| 69 |
* start responding. And what they do there is take over the item's |
| 70 |
* position on the main axis outright — a flex item's own auto margins are |
| 71 |
* consulted before `justify-content` ever runs, so the parent's |
| 72 |
* Left/Center/Right stopped choosing anything: measured, `justify-content: |
| 73 |
* flex-start` and `flex-end` on the SAME 50px-wide icon with a Custom |
| 74 |
* Width rendered at the IDENTICAL centred position (277px from the left in |
| 75 |
* a 604px row either way) the moment the icon carried a width of its own. |
| 76 |
* |
| 77 |
* So the guard is worth exactly nothing for this block in the case it was |
| 78 |
* built for, and actively wrong in the one case it can ever reach. Rather |
| 79 |
* than touch the shared compiler both other guards on this block already |
| 80 |
* come from — and risk every OTHER atomic block that relies on it staying |
| 81 |
* centred inside a normal, non-flex parent — this walks the SAME compiled |
| 82 |
* buckets and, only where the guard actually wrote `auto` (never where an |
| 83 |
* author's OWN margin is what is there instead — `has_horizontal_margin()` |
| 84 |
* is what stopped the guard writing anything in that case, and this must |
| 85 |
* agree with it or an author's margin would be overwritten right back to |
| 86 |
* zero), resets it to `0` on the very same selector. Same specificity, |
| 87 |
* later in this block's own <style> tag, so it is this declaration that |
| 88 |
* wins — the shared rule is untouched, and the outcome is identical to it |
| 89 |
* never having fired here at all. |
| 90 |
* |
| 91 |
* @param array $styles The block's styles object. |
| 92 |
* @param string $base The block's own selector. |
| 93 |
* @return string CSS, or ''. |
| 94 |
*/ |
| 95 |
private function cancel_flex_item_centering( $styles, $base ) { |
| 96 |
$css = ''; |
| 97 |
foreach ( AtomicStyles::compile_rules( $styles ) as $rule ) { |
| 98 |
list( $media, $state, $pairs ) = $rule; |
| 99 |
$centred = false; |
| 100 |
foreach ( $pairs as $pair ) { |
| 101 |
if ( 'margin-left' === $pair[0] && 'auto' === $pair[1] ) { |
| 102 |
$centred = true; |
| 103 |
break; |
| 104 |
} |
| 105 |
} |
| 106 |
if ( ! $centred ) { |
| 107 |
continue; |
| 108 |
} |
| 109 |
$body = $base . $state . '{margin-left:0;margin-right:0;}'; |
| 110 |
$css .= ( '' !== $media ) ? $media . '{' . $body . '}' : $body; |
| 111 |
} |
| 112 |
return $css; |
| 113 |
} |
| 114 |
} |
| 115 |
|