Take colour off the overshooting spatial spring
Four components animated background-color and color on ease-spatial-fast, whose fast variant peaks at 1.094 — the one thing tokens/motion.css says a colour must never do. Tailwind cannot emit two springs on one element, so a small unlayered file gives shape and size the spatial spring and colour and elevation the effects one in a single property list. Plan step 18, actions.md ACT-19. 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
d560e7449c
commit
597656c88a
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 and size on the fast spatial spring, 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.
|
||||
*
|
||||
* Unlayered, as the rest of the package's component CSS, so a `transition-*` utility on the call
|
||||
* site cannot half-undo one.
|
||||
*/
|
||||
|
||||
@utility state-transition-fast {
|
||||
transition-property: border-radius, padding, margin, 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-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-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);
|
||||
}
|
||||
@@ -20,6 +20,7 @@
|
||||
@import './tokens/font.css';
|
||||
@import './tokens/theme.css';
|
||||
@import './tokens/state.css';
|
||||
@import './components/actions.css';
|
||||
@import './components/groups.css';
|
||||
@import './components/list.css';
|
||||
@import './components/field.css';
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
`size` is Expressive's scale — `xs` 32px, `sm` 40px (the default), `md` 56px, `lg` 96px,
|
||||
`xl` 136px — each with its own padding, type style and icon size. `shape` is `round` (the
|
||||
default) or `square`; either one squares off towards a smaller corner while pressed, on the
|
||||
fast spatial spring.
|
||||
fast spatial spring, while the colours cross on the fast effects spring beside it
|
||||
(`state-transition-fast`, resources/css/components/actions.css: a colour must never
|
||||
overshoot).
|
||||
|
||||
With an `icon` and no label it is an icon button: `width` is `narrow`, `default` or `wide`,
|
||||
`variant="text"` is M3's standard icon button, and the tooltip or label names it for screen
|
||||
@@ -164,7 +166,7 @@
|
||||
|
||||
$classes = [
|
||||
'group/button state-layer focus-ring inline-flex shrink-0 cursor-pointer select-none items-center justify-center whitespace-nowrap',
|
||||
'transition-[border-radius,background-color,color,box-shadow,padding,margin] duration-(--md-sys-motion-spatial-fast-duration) ease-spatial-fast',
|
||||
'state-transition-fast',
|
||||
$dimensions,
|
||||
// A composite component (a split button's halves) passes the corners its place needs.
|
||||
$corners ?? $corner.' '.$pressed[$size],
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
Livewire, so it stays open through a render of the component around it.
|
||||
|
||||
FabMenuBaselineTokens (androidx Compose Material 3, Apache-2.0): 56px items, 4px apart, 8px
|
||||
above the close button. --}}
|
||||
above the close button. The FAB's corner and colours morph on the two default springs at once
|
||||
(`state-transition-default`, resources/css/components/actions.css). --}}
|
||||
|
||||
@props([
|
||||
'icon' => 'add',
|
||||
@@ -46,7 +47,7 @@
|
||||
@if ($label) aria-label="{{ $label }}" @endif
|
||||
@class([
|
||||
'group/fab state-layer focus-ring inline-flex size-14 shrink-0 cursor-pointer items-center justify-center rounded-corner-lg shadow-elevation-3 hover:shadow-elevation-4',
|
||||
'transition-[border-radius,background-color,color,box-shadow] duration-(--md-sys-motion-spatial-default-duration) ease-spatial-default aria-expanded:rounded-corner-full',
|
||||
'state-transition-default aria-expanded:rounded-corner-full',
|
||||
$colours,
|
||||
])
|
||||
>
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
default), `filled` or `outlined`, as for toggle buttons. The segments share the row unless
|
||||
`inline`. An option with `'disabled' => true` greys its own segment. At `xs` and `sm` a
|
||||
segment carries `touch-target` and a 48px minimum width, which M3 asks for by name and tells
|
||||
you never to reduce.
|
||||
you never to reduce. Corners move on the spatial spring and colours on the effects one
|
||||
(`state-transition-fast`).
|
||||
|
||||
ReStride's props, kept: `label`, `hint`, `hint-class`, `name` (needed with `x-model`, which
|
||||
names no property), `options`, `option-value`, `option-label`; plus `option-icon`, `size`,
|
||||
@@ -79,7 +80,7 @@
|
||||
@foreach ($options as $option)
|
||||
<label @class([
|
||||
'state-layer relative flex cursor-pointer select-none items-center justify-center whitespace-nowrap',
|
||||
'transition-[border-radius,background-color,color] duration-(--md-sys-motion-spatial-fast-duration) ease-spatial-fast',
|
||||
'state-transition-fast',
|
||||
'flex-1' => ! $inline,
|
||||
$small ? 'touch-target min-w-12' : 'min-w-0',
|
||||
$segment,
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
disabled.
|
||||
|
||||
44px tall (SegmentedMenuTokens.Item), body-large label, 20px icons, 4px corners that open to
|
||||
12px at the ends of the list. --}}
|
||||
12px at the ends of the list, the corner on the spatial spring and the colour on the effects
|
||||
one (`state-transition-fast`). --}}
|
||||
|
||||
@props([
|
||||
'label' => null,
|
||||
@@ -45,7 +46,7 @@
|
||||
->class([
|
||||
'group/item state-layer flex w-full min-h-11 cursor-pointer items-center gap-3 px-3 text-start outline-none',
|
||||
'rounded-corner-xs first:rounded-t-corner-md last:rounded-b-corner-md',
|
||||
'transition-[border-radius,background-color] duration-(--md-sys-motion-spatial-fast-duration) ease-spatial-fast',
|
||||
'state-transition-fast',
|
||||
'focus-visible:outline-3 focus-visible:-outline-offset-3 focus-visible:outline-secondary',
|
||||
'py-2' => filled($description),
|
||||
'rounded-corner-md bg-tertiary-container text-on-tertiary-container' => $selected === true,
|
||||
|
||||
Reference in New Issue
Block a user