Plan step 36. <x-group> renders data-md-group with its size, variant, shape, multiple and inline, a data-md-button-group row and data-md-group-segment labels over its radios or checkboxes. group.css draws the segments as M3's buttons with the toggle button's colours from :has(:checked), the disabled treatment from :has(:disabled), the focus ring from :has(:focus-visible) and the 48px target at xs and sm. The connected shapes move into button-group.css (the corner scale, square ends, the pressed and selected inner corners), which group.css imports; <x-button-group> adopts them in its own rewrite. The group's render tests move to GroupTest; AppBarTest (navigation group) follows the new legend and row hooks of theme-toggle's rows. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
102 lines
4.5 KiB
CSS
102 lines
4.5 KiB
CSS
/*
|
|
* <x-button-group>'s shapes: the corners a button takes from its place among its siblings. The
|
|
* connected form is also what `<x-group>` draws its segments with, which is why its stylesheet
|
|
* imports this one.
|
|
*
|
|
* Connected (`data-md-button-group="connected"`): 2px apart, the outer corners full, the inner
|
|
* corners small, smaller still while pressed, and a selected segment (`aria-pressed`, or a checked
|
|
* input inside it) fully round — ConnectedButtonGroupXSmall…XLargeTokens and the M3 Expressive
|
|
* connected button group spec: inner corners 4/8/8/16/20px, pressed 2/4/4/12/16px. At the two
|
|
* smallest sizes a segment is 32px or 40px tall, and M3 names both numbers it must not go below:
|
|
* "XS and S connected button groups have a 48dp target area and a 48dp minimum width".
|
|
*
|
|
* Shape (`data-md-shape="square"`, M3's "Default shape | Round, square" configuration):
|
|
* `--md-button-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 corner its inner edges take, which is the square table M3
|
|
* publishes for connected groups (4/8/8/16/20dp by size). Selection morphs the other way: M3 has a
|
|
* toggle inside a group "swap shape square/round on selection", so a selected segment in a square
|
|
* group turns round, which is why the selected rule keeps `--md-button-group-full`.
|
|
*
|
|
* "Full" is half the size's height (16/20/28/48/68px), never `--md-sys-shape-corner-full`'s
|
|
* 9999px. One element mixes full outer corners with small inner ones, and when a box's radii add
|
|
* up to more than its side, CSS scales every radius by the same factor: a 9999px corner beside an
|
|
* 8px one shrank the 8px one to a hundredth of a pixel, so the inner corners drew square.
|
|
*
|
|
* <x-button>'s own corner rules carry no specificity, so these reshape the buttons in a group
|
|
* whatever selector they use; a pressed or selected segment changes one custom property and the
|
|
* outer corners stay put.
|
|
*/
|
|
|
|
@layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility;
|
|
|
|
@layer material.components {
|
|
[data-md-button-group] {
|
|
--md-button-group-inner: var(--md-sys-shape-corner-sm);
|
|
--md-button-group-inner-pressed: var(--md-sys-shape-corner-xs);
|
|
--md-button-group-full: 20px;
|
|
--md-button-group-outer: var(--md-button-group-full);
|
|
}
|
|
|
|
[data-md-button-group][data-md-size='xs'] {
|
|
--md-button-group-inner: var(--md-sys-shape-corner-xs);
|
|
--md-button-group-inner-pressed: 2px;
|
|
--md-button-group-full: 16px;
|
|
}
|
|
|
|
[data-md-button-group][data-md-size='md'] {
|
|
--md-button-group-full: 28px;
|
|
}
|
|
|
|
[data-md-button-group][data-md-size='lg'] {
|
|
--md-button-group-inner: var(--md-sys-shape-corner-lg);
|
|
--md-button-group-inner-pressed: var(--md-sys-shape-corner-md);
|
|
--md-button-group-full: 48px;
|
|
}
|
|
|
|
[data-md-button-group][data-md-size='xl'] {
|
|
--md-button-group-inner: var(--md-sys-shape-corner-lg-increased);
|
|
--md-button-group-inner-pressed: var(--md-sys-shape-corner-lg);
|
|
--md-button-group-full: 68px;
|
|
}
|
|
|
|
/* A square group's ends take the corner its inner edges take. */
|
|
[data-md-button-group][data-md-shape='square'] {
|
|
--md-button-group-outer: var(--md-button-group-inner);
|
|
}
|
|
|
|
[data-md-button-group='connected'] {
|
|
gap: var(--md-sys-measurement-space25);
|
|
}
|
|
|
|
[data-md-button-group='connected']:is([data-md-size='xs'], [data-md-size='sm']) > * {
|
|
min-inline-size: var(--md-sys-measurement-space600);
|
|
}
|
|
|
|
[data-md-button-group='connected'] > * {
|
|
--md-button-group-corner: var(--md-button-group-inner);
|
|
|
|
border-start-start-radius: var(--md-button-group-corner);
|
|
border-end-start-radius: var(--md-button-group-corner);
|
|
border-start-end-radius: var(--md-button-group-corner);
|
|
border-end-end-radius: var(--md-button-group-corner);
|
|
}
|
|
|
|
[data-md-button-group='connected'] > :active {
|
|
--md-button-group-corner: var(--md-button-group-inner-pressed);
|
|
}
|
|
|
|
[data-md-button-group='connected'] > :is([aria-pressed='true'], :has(:checked)) {
|
|
--md-button-group-corner: var(--md-button-group-full);
|
|
}
|
|
|
|
[data-md-button-group='connected'] > :first-child {
|
|
border-start-start-radius: var(--md-button-group-outer);
|
|
border-end-start-radius: var(--md-button-group-outer);
|
|
}
|
|
|
|
[data-md-button-group='connected'] > :last-child {
|
|
border-start-end-radius: var(--md-button-group-outer);
|
|
border-end-end-radius: var(--md-button-group-outer);
|
|
}
|
|
}
|