Merge branch 'worktree-agent-a0d44b9ad5ca7814d'
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* The transitions an action runs between its states — buttons, connected segments, menu items,
|
||||
* the FAB menu's trigger.
|
||||
* 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
|
||||
@@ -84,3 +84,65 @@
|
||||
translate: 0 0.5rem;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* An extended FAB that collapses to a FAB while the page scrolls down (`<x-fab
|
||||
* collapse-on-scroll>`, resources/js/fab.js sets `data-collapsed`). M3's extended FAB page: it
|
||||
* "can collapse to a FAB on scroll-down and re-expand to extended on scroll-up — when switching
|
||||
* between FAB↔extended FAB, shape changes, the icon moves left, and the text label fades in/out".
|
||||
*
|
||||
* `width: auto` cannot transition, so the label sits in a one-column grid whose track closes to
|
||||
* zero; that track is what animates, and the button lays itself out around it every frame. The
|
||||
* gap and the minimum width go with it, all on the default spatial spring — the size of morph
|
||||
* `state-transition-default` is for — while the label fades on the effects spring. The collapsed
|
||||
* sizes are the FAB's own (FabBaseline/Medium/LargeTokens: 56/80/96px). The extended FAB's
|
||||
* padding already centres the glyph at `sm` (16px + 24px + 16px) and `md` (26 + 28 + 26); at
|
||||
* `lg` its 28px is 4px short of the 32px that centres a 32px glyph in 96px, so that one moves.
|
||||
* Corners do not change: each size's FAB and extended FAB share one.
|
||||
*
|
||||
* The transition list repeats the FAB's own shadow and colour transitions, which this rule
|
||||
* replaces. Under reduced motion tokens/motion.css takes every duration to zero, so it swaps.
|
||||
*/
|
||||
[data-fab-collapsible] {
|
||||
--fab-collapsed-size: 3.5rem;
|
||||
|
||||
transition-property: min-inline-size, padding-inline, gap, box-shadow, background-color, color;
|
||||
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-fast-duration), var(--md-sys-motion-effects-fast-duration), var(--md-sys-motion-effects-fast-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-fast), var(--md-sys-motion-effects-fast), var(--md-sys-motion-effects-fast);
|
||||
}
|
||||
|
||||
[data-fab-collapsible][data-fab-size='md'] { --fab-collapsed-size: 5rem; }
|
||||
[data-fab-collapsible][data-fab-size='lg'] { --fab-collapsed-size: 6rem; }
|
||||
|
||||
[data-fab-label] {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
transition-property: grid-template-columns, opacity;
|
||||
transition-duration: var(--md-sys-motion-spatial-default-duration), var(--md-sys-motion-effects-default-duration);
|
||||
transition-timing-function: var(--md-sys-motion-spatial-default), var(--md-sys-motion-effects-default);
|
||||
}
|
||||
|
||||
[data-fab-label] > span {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
[data-fab-collapsible][data-collapsed] {
|
||||
min-inline-size: var(--fab-collapsed-size);
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
[data-fab-collapsible][data-fab-size='lg'][data-collapsed] {
|
||||
padding-inline: 2rem;
|
||||
}
|
||||
|
||||
/* The label stays in the accessibility tree — clipped and transparent, never `display: none` — so
|
||||
the collapsed FAB keeps the name the extended one had. */
|
||||
[data-fab-collapsible][data-collapsed] [data-fab-label] {
|
||||
grid-template-columns: 0fr;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,16 @@
|
||||
* full, the inner corners small, smaller still while pressed, and a selected segment fully round
|
||||
* (ConnectedButtonGroupSmallTokens and the M3 Expressive connected button group spec).
|
||||
*
|
||||
* Shape (`shape="square"`, M3's "Default shape | Round, square" configuration): `--group-outer`
|
||||
* is what the two ends of a group round to — half the height for a round group, and for a square
|
||||
* one the same corner its inner edges take, which is the square table M3 publishes for connected
|
||||
* groups (4/8/8/16/20dp by size). A square *standard* group has no inner edges, so it hands its
|
||||
* buttons the square corner scale `<x-button shape="square">` draws (`--group-square`, and
|
||||
* `--group-square-pressed` under the finger) instead of asking the caller to write it on each
|
||||
* one. Selection morphs the other way in both: M3 has a toggle inside a group "swap shape
|
||||
* square/round on selection", so a selected button in a square group turns round, which is why
|
||||
* the selected rules keep `--group-full` rather than `--group-outer`.
|
||||
*
|
||||
* Split button (`<x-split-button>`): the same idea for two halves, on its own corner scale —
|
||||
* SplitButton*Tokens gives the inner corner 4/4/4/8/12px at rest and *grows* it to 8/12/12/20/20px
|
||||
* under the finger, the opposite of a connected group, so `--split-inner*` is separate from
|
||||
@@ -34,13 +44,32 @@
|
||||
--group-inner: var(--md-sys-shape-corner-sm);
|
||||
--group-inner-pressed: var(--md-sys-shape-corner-xs);
|
||||
--group-full: 1.25rem;
|
||||
--group-square: var(--md-sys-shape-corner-md);
|
||||
--group-square-pressed: var(--md-sys-shape-corner-sm);
|
||||
--group-outer: var(--group-full);
|
||||
}
|
||||
|
||||
[data-button-group][data-size='xs'] { --group-pad: 1rem; --group-grow: 4px; --group-inner: var(--md-sys-shape-corner-xs); --group-inner-pressed: 2px; --group-full: 1rem; }
|
||||
[data-button-group][data-size='sm'] { --group-pad: 1rem; --group-grow: 6px; --group-full: 1.25rem; }
|
||||
[data-button-group][data-size='md'] { --group-pad: 1.5rem; --group-grow: 8px; --group-full: 1.75rem; }
|
||||
[data-button-group][data-size='lg'] { --group-pad: 3rem; --group-grow: 16px; --group-inner: var(--md-sys-shape-corner-lg); --group-inner-pressed: var(--md-sys-shape-corner-md); --group-full: 3rem; }
|
||||
[data-button-group][data-size='xl'] { --group-pad: 4rem; --group-grow: 20px; --group-inner: var(--md-sys-shape-corner-lg-increased); --group-inner-pressed: var(--md-sys-shape-corner-lg); --group-full: 4.25rem; }
|
||||
[data-button-group][data-size='md'] { --group-pad: 1.5rem; --group-grow: 8px; --group-full: 1.75rem; --group-square: var(--md-sys-shape-corner-lg); --group-square-pressed: var(--md-sys-shape-corner-md); }
|
||||
[data-button-group][data-size='lg'] { --group-pad: 3rem; --group-grow: 16px; --group-inner: var(--md-sys-shape-corner-lg); --group-inner-pressed: var(--md-sys-shape-corner-md); --group-full: 3rem; --group-square: var(--md-sys-shape-corner-xl); --group-square-pressed: var(--md-sys-shape-corner-lg); }
|
||||
[data-button-group][data-size='xl'] { --group-pad: 4rem; --group-grow: 20px; --group-inner: var(--md-sys-shape-corner-lg-increased); --group-inner-pressed: var(--md-sys-shape-corner-lg); --group-full: 4.25rem; --group-square: var(--md-sys-shape-corner-xl); --group-square-pressed: var(--md-sys-shape-corner-lg); }
|
||||
|
||||
/* A square group's ends take the corner its inner edges take — M3's square table for connected
|
||||
groups — and a square standard group hands its buttons the button's own square scale. */
|
||||
[data-button-group][data-shape='square'] { --group-outer: var(--group-inner); }
|
||||
|
||||
[data-button-group='standard'][data-shape='square'] > * {
|
||||
border-radius: var(--group-square);
|
||||
}
|
||||
|
||||
[data-button-group='standard'][data-shape='square'] > :active:not(:disabled, [aria-disabled='true']) {
|
||||
border-radius: var(--group-square-pressed);
|
||||
}
|
||||
|
||||
[data-button-group='standard'][data-shape='square'] > [aria-pressed='true'] {
|
||||
border-radius: var(--group-full);
|
||||
}
|
||||
|
||||
[data-button-group='standard'] > :not([data-icon-button]):active:not(:disabled, [aria-disabled='true']) {
|
||||
padding-inline: calc(var(--group-pad) + var(--group-grow));
|
||||
@@ -107,14 +136,14 @@
|
||||
|
||||
[data-button-group='connected'] > :first-child,
|
||||
[data-split='leading'] {
|
||||
border-start-start-radius: var(--group-full);
|
||||
border-end-start-radius: var(--group-full);
|
||||
border-start-start-radius: var(--group-outer);
|
||||
border-end-start-radius: var(--group-outer);
|
||||
}
|
||||
|
||||
[data-button-group='connected'] > :last-child,
|
||||
[data-split='trailing'] {
|
||||
border-start-end-radius: var(--group-full);
|
||||
border-end-end-radius: var(--group-full);
|
||||
border-start-end-radius: var(--group-outer);
|
||||
border-end-end-radius: var(--group-outer);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* The exposed dropdown menu — the list a field drops open.
|
||||
* The menus: the exposed dropdown a field drops open, and what `<x-menu>` cannot say in utilities.
|
||||
*
|
||||
* Two lists wear it, so a form reads as one family:
|
||||
* Two lists wear the dropdown, so a form reads as one family:
|
||||
*
|
||||
* - `<x-select>`'s: the native <select>, opted into the browser's customizable select
|
||||
* (`appearance: base-select`). `::picker(select)` is the menu and each <option> a row, while the
|
||||
@@ -20,6 +20,76 @@
|
||||
* paints option colours into its native list would otherwise show a half-painted one.
|
||||
*/
|
||||
|
||||
/*
|
||||
* `<x-menu>` and the submenus inside it.
|
||||
*
|
||||
* A submenu is a popover of its own nested in the menu's, so it cannot take the container colour
|
||||
* from a class the item knows nothing about: the menu declares the pair as custom properties,
|
||||
* which a nested popover inherits down the DOM whatever the top layer does with its painting. The
|
||||
* fallbacks are the standard menu's, for a submenu in some other list (a FAB menu's).
|
||||
*/
|
||||
[data-menu] {
|
||||
--material-menu-surface: var(--md-sys-color-surface-container-low);
|
||||
--material-menu-ink: var(--md-sys-color-on-surface);
|
||||
}
|
||||
|
||||
[data-menu][data-vibrant] {
|
||||
--material-menu-surface: var(--md-sys-color-tertiary-container);
|
||||
--material-menu-ink: var(--md-sys-color-on-tertiary-container);
|
||||
}
|
||||
|
||||
[data-submenu] {
|
||||
background: var(--material-menu-surface, var(--md-sys-color-surface-container-low));
|
||||
color: var(--material-menu-ink, var(--md-sys-color-on-surface));
|
||||
}
|
||||
|
||||
/*
|
||||
* `<x-menu filter>`: M3's menu as a filtering surface. The field stays put while the list scrolls
|
||||
* under it and takes the menu's own container, so a vibrant menu's field is vibrant too. It is a
|
||||
* plain <input> with no field chrome — M3's menus embed a text field, not a text field component.
|
||||
*/
|
||||
[data-menu-filter] {
|
||||
position: sticky;
|
||||
inset-block-start: 0;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
min-block-size: 3rem;
|
||||
padding-inline: 1rem;
|
||||
border-block-end: 1px solid var(--md-sys-color-outline-variant);
|
||||
background: var(--material-menu-surface, var(--md-sys-color-surface-container-low));
|
||||
}
|
||||
|
||||
[data-menu-filter] input {
|
||||
flex: 1;
|
||||
min-inline-size: 0;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
color: inherit;
|
||||
font: var(--md-sys-typescale-body-lg);
|
||||
letter-spacing: var(--md-sys-typescale-body-lg-tracking);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
[data-menu-filter] input::placeholder {
|
||||
color: color-mix(in srgb, var(--material-menu-ink, var(--md-sys-color-on-surface)) 70%, transparent);
|
||||
}
|
||||
|
||||
/* The filter hides what the query leaves out with the `hidden` attribute; a row's own
|
||||
`display: flex` utility would otherwise beat the user agent's `[hidden] { display: none }`. */
|
||||
[data-menu] [hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* `data-active` is the row the arrow keys are on while the focus stays in the field — the state
|
||||
layer the roving focus would have drawn, without taking the focus off the field. A chosen or
|
||||
current row keeps its own colour. */
|
||||
[data-menu] [role^="menuitem"][data-active]:not([aria-checked="true"], [aria-current="page"]) {
|
||||
background: color-mix(in srgb, var(--material-menu-ink, var(--md-sys-color-on-surface)) 8%, transparent);
|
||||
}
|
||||
|
||||
.field-menu {
|
||||
max-block-size: 18rem;
|
||||
overflow-y: auto;
|
||||
|
||||
Reference in New Issue
Block a user