Files
livewire-material/resources/css/components/actions.css
T
Andreas Reinhold / reiniandClaude Opus 5 1cf4f16c95 Draw the FAB without Tailwind
Plan step 36. <x-fab> renders data-md-fab with data-md-size,
data-md-color, data-md-variant, data-md-extended and, collapsing on
scroll, data-md-collapse-on-scroll with a bound data-md-collapsed; it
passes its glyph's size to <x-icon>. fab.css draws FabBaseline/Medium/
LargeTokens and ExtendedFab*Tokens per size, the container and filled
colours, elevation 3 and 4 on hover, the state layer and focus ring,
and the collapse morph that leaves actions.css.

data-fab becomes data-md-fab, also in navigation.css (the rail flattens
a nested FAB) and toolbar.css (a docked toolbar's FAB), with their tests.
The actions browser test gains the owed collapse-on-scroll test.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
2026-09-14 15:06:45 +02:00

87 lines
4.5 KiB
CSS

/*
* The transitions an action runs between its states — buttons, connected segments, menu items,
* the FAB menu's trigger, and an extended FAB collapsing to a FAB on scroll.
*
* M3 has two spring styles and they are not interchangeable: spatial moves things (position,
* size, rotation, rounded corners) and overshoots by 9% on the way, effects changes how things
* look (colour, opacity, elevation) and is critically damped, because a colour must never
* overshoot — tokens/motion.css says so in the library's own words. An element whose corners and
* colours both change on a press therefore needs two springs at once, which Tailwind cannot write
* (`duration-*` and `ease-*` each emit one value); CSS can, by giving `transition-property` a
* list and matching it position for position.
*
* `state-transition-fast` is the press/hover/select transition of a control the finger lands on:
* shape, size and the place it sits on the fast spatial spring (a `fab` button nudges up when a
* snackbar arrives under it), colour and elevation on the fast effects spring.
* `state-transition-default` is the same pair one step slower, for the bigger morph of a FAB
* turning into a close button.
*
* `popover-transition` is the enter and exit of a menu: M3 asks for a transition that ties the
* list to its trigger, so it scales up from its `transform-origin` on the spatial spring while it
* fades in on the effects one, and `allow-discrete` keeps `display` and `overlay` alive long
* enough for the exit to be seen.
*
* These are `@utility` declarations, so they compile into Tailwind's utilities layer like any
* other class: a `transition-*` utility written beside one on the call site will fight it, and
* whichever Tailwind emits last wins. Pass neither.
*/
@utility state-transition-fast {
transition-property: border-radius, padding, margin, bottom, background-color, color, box-shadow;
transition-duration:
var(--md-sys-motion-spatial-fast-duration), var(--md-sys-motion-spatial-fast-duration),
var(--md-sys-motion-spatial-fast-duration), var(--md-sys-motion-spatial-fast-duration),
var(--md-sys-motion-effects-fast-duration), var(--md-sys-motion-effects-fast-duration), var(--md-sys-motion-effects-fast-duration);
transition-timing-function:
var(--md-sys-motion-spatial-fast), var(--md-sys-motion-spatial-fast),
var(--md-sys-motion-spatial-fast), var(--md-sys-motion-spatial-fast),
var(--md-sys-motion-effects-fast), var(--md-sys-motion-effects-fast), var(--md-sys-motion-effects-fast);
}
@utility state-transition-default {
transition-property: border-radius, padding, margin, background-color, color, box-shadow;
transition-duration:
var(--md-sys-motion-spatial-default-duration), var(--md-sys-motion-spatial-default-duration), var(--md-sys-motion-spatial-default-duration),
var(--md-sys-motion-effects-default-duration), var(--md-sys-motion-effects-default-duration), var(--md-sys-motion-effects-default-duration);
transition-timing-function:
var(--md-sys-motion-spatial-default), var(--md-sys-motion-spatial-default), var(--md-sys-motion-spatial-default),
var(--md-sys-motion-effects-default), var(--md-sys-motion-effects-default), var(--md-sys-motion-effects-default);
}
@utility popover-transition {
opacity: 0;
scale: 0.95;
transition-property: opacity, scale, display, overlay;
transition-duration:
var(--md-sys-motion-effects-fast-duration), var(--md-sys-motion-spatial-fast-duration),
var(--md-sys-motion-spatial-fast-duration), var(--md-sys-motion-spatial-fast-duration);
transition-timing-function:
var(--md-sys-motion-effects-fast), var(--md-sys-motion-spatial-fast), linear, linear;
transition-behavior: allow-discrete;
&:popover-open {
opacity: 1;
scale: 1;
}
@starting-style {
&:popover-open {
opacity: 0;
scale: 0.95;
}
}
}
/*
* A FAB menu's items rise into place as the list opens and sink back as it closes. The entry is
* `@starting-style` on the item itself; the exit needs the state to be readable while the popover
* is on its way out, which is what `:not(:popover-open)` is — the popover keeps `display: flex`
* for the length of its own discrete transition, so the items have somewhere to animate to.
*
* Unlayered (a plain rule, not an `@utility`), so it beats the item's own utilities.
*/
[data-fab-menu]:not(:popover-open) > * {
translate: 0 0.5rem;
opacity: 0;
}