Draw the alert's dismiss button from the interaction classes
Plan step 36 ("Interaction is the shared classes", the user, 2026-09-14).
The dismiss button hand-rolled md-state-layer, md-focus-ring and
md-touch-target, and alert.css's own header said so; it now renders the
classes and keeps only its own size, offset and colour.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
co-authored by
Claude Opus 5
parent
480387a64e
commit
7ff6928d4a
@@ -7,11 +7,9 @@
|
|||||||
*
|
*
|
||||||
* `data-md-color`: info (the default), success, warning, error, primary, secondary, tertiary or
|
* `data-md-color`: info (the default), success, warning, error, primary, secondary, tertiary or
|
||||||
* neutral (surface-container-high, on-surface — it has no state colour of its own). The dismiss
|
* neutral (surface-container-high, on-surface — it has no state colour of its own). The dismiss
|
||||||
* button is drawn at 40px, pulled 8px out into the alert's padding, and reaches M3's 48px target
|
* button is drawn at 40px, pulled 8px out into the alert's padding, and renders the foundation's
|
||||||
* (ACT-18) through an `::after`. Its state layer, focus ring and target are the declarations of
|
* `md-state-layer`, `md-focus-ring` and `md-touch-target` (foundation/interaction.css) to reach
|
||||||
* the foundation's `md-state-layer`, `md-focus-ring` and `md-touch-target`
|
* M3's 48px target (ACT-18); nothing here copies their rules.
|
||||||
* (foundation/interaction.css), keyed on the button itself as button.css does, because the view
|
|
||||||
* writes no class list.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility;
|
@layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility;
|
||||||
@@ -95,8 +93,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
[data-md-alert-dismiss] {
|
[data-md-alert-dismiss] {
|
||||||
position: relative;
|
|
||||||
isolation: isolate;
|
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -106,49 +102,5 @@
|
|||||||
margin: -8px;
|
margin: -8px;
|
||||||
border-radius: var(--md-sys-shape-corner-full);
|
border-radius: var(--md-sys-shape-corner-full);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
outline: none;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
z-index: -1;
|
|
||||||
border-radius: inherit;
|
|
||||||
background-color: currentColor;
|
|
||||||
opacity: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
transition: opacity var(--md-sys-motion-effects-fast-duration) var(--md-sys-motion-effects-fast);
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
min-width: var(--md-sys-measurement-space600);
|
|
||||||
min-height: var(--md-sys-measurement-space600);
|
|
||||||
translate: -50% -50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (hover: hover) {
|
|
||||||
&:hover::before {
|
|
||||||
opacity: var(--md-sys-state-hover-state-layer-opacity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus-visible {
|
|
||||||
outline: 3px solid var(--md-sys-color-secondary);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus-visible::before {
|
|
||||||
opacity: var(--md-sys-state-focus-state-layer-opacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active::before {
|
|
||||||
opacity: var(--md-sys-state-pressed-state-layer-opacity);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,8 @@
|
|||||||
something the person just did (ACT-36). M3 publishes no banner; the nearest thing it does
|
something the person just did (ACT-36). M3 publishes no banner; the nearest thing it does
|
||||||
publish, the snackbar, says polite and never assertive.
|
publish, the snackbar, says polite and never assertive.
|
||||||
|
|
||||||
Drawn by resources/css/components/alert.css from `data-md-alert` and `data-md-color`; no
|
Drawn by resources/css/components/alert.css from `data-md-alert` and `data-md-color`; the
|
||||||
class list. --}}
|
dismiss button carries only the foundation's interaction classes. --}}
|
||||||
|
|
||||||
@props([
|
@props([
|
||||||
'title' => null,
|
'title' => null,
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if ($dismissible)
|
@if ($dismissible)
|
||||||
<button type="button" data-md-alert-dismiss aria-label="{{ __('Dismiss') }}" x-on:click="shown = false">
|
<button type="button" class="md-state-layer md-focus-ring md-touch-target" data-md-alert-dismiss aria-label="{{ __('Dismiss') }}" x-on:click="shown = false">
|
||||||
<x-livewire-material::icon name="close" size="20" />
|
<x-livewire-material::icon name="close" size="20" />
|
||||||
</button>
|
</button>
|
||||||
@endif
|
@endif
|
||||||
|
|||||||
@@ -47,17 +47,17 @@ it('takes actions, drops its icon on request, and can be dismissed', function ()
|
|||||||
->and(substr_count($html, '<svg'))->toBe(1);
|
->and(substr_count($html, '<svg'))->toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('reaches 48px from its 40px dismiss button', function () {
|
it('reaches 48px from its 40px dismiss button, from the foundation\'s class, not a copy', function () {
|
||||||
$css = ComponentStylesheet::read('alert');
|
$css = ComponentStylesheet::read('alert');
|
||||||
|
|
||||||
expect($css->declarations('[data-md-alert-dismiss]'))->toMatchArray([
|
expect($css->declarations('[data-md-alert-dismiss]'))->toMatchArray([
|
||||||
'width' => 'var(--md-sys-measurement-space500)',
|
'width' => 'var(--md-sys-measurement-space500)',
|
||||||
'height' => 'var(--md-sys-measurement-space500)',
|
'height' => 'var(--md-sys-measurement-space500)',
|
||||||
])
|
])
|
||||||
->and($css->declarations('[data-md-alert-dismiss]::after'))->toMatchArray([
|
->and($css->has('[data-md-alert-dismiss]::after'))->toBeFalse()
|
||||||
'min-width' => 'var(--md-sys-measurement-space600)',
|
->and($css->has('[data-md-alert-dismiss]::before'))->toBeFalse()
|
||||||
'min-height' => 'var(--md-sys-measurement-space600)',
|
->and((string) $this->blade('<x-alert description="Draft." dismissible />'))
|
||||||
]);
|
->toMatch('/class="md-state-layer md-focus-ring md-touch-target" data-md-alert-dismiss/');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('draws neutral in surface-container-high, on-surface', function () {
|
it('draws neutral in surface-container-high, on-surface', function () {
|
||||||
|
|||||||
Reference in New Issue
Block a user