M3 says to avoid an icon in a snackbar and gives the supporting text no fourth colour, so the state glyph and the 80% description are gone: a type now only picks the announcement role. The 40px action and close buttons take the shared touch-target, Escape dismisses a snackbar that holds the focus, and the host publishes --material-snackbar-height on <html> so a `fab` button sits above the snackbar instead of under it. Plan step 18, actions.md ACT-17, ACT-18, ACT-20, ACT-34, ACT-35. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
87 lines
4.4 KiB
CSS
87 lines
4.4 KiB
CSS
/*
|
|
* The transitions an action runs between its states — buttons, connected segments, menu items,
|
|
* the FAB menu's trigger.
|
|
*
|
|
* 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;
|
|
}
|