Draw the split button without Tailwind
Plan step 36. <x-split-button> renders data-md-split-button and data-md-size on the pair and data-md-split on its halves. split-button.css draws SplitButton*Tokens' shape — full outer corners, inner corners that grow under the finger, the trailing half round while its menu is open — the narrower leading padding and 48px trailing half at xs and sm, and the chevron's own size, nudge and turn on the standard scheme. groups.css is empty and leaves tailwind.css. The actions browser test follows data-md-split and data-md-button-group, and gains the owed tests for a connected segment's 48px edge and a button group's single-required and multi selection. 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
8dd0a7ef9d
commit
2a4dcead3d
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* <x-split-button>: an action and a menu of its alternatives, as two `<x-button>`s 2px apart.
|
||||
*
|
||||
* The halves share one shape (SplitButtonXSmall…XLargeTokens, androidx Compose Material 3,
|
||||
* Apache-2.0): outer corners full — half the height, 16/20/28/48/68px, never 9999px, which would
|
||||
* scale the small inner corners away — and inner corners of 4/4/4/8/12px that *grow* under the
|
||||
* finger to 8/12/12/20/20px, the opposite of a connected button group. The trailing half turns
|
||||
* fully round while its menu is open (`aria-expanded`). `<x-button>`'s own corner rules carry no
|
||||
* specificity, so these win.
|
||||
*
|
||||
* At the two smallest sizes the leading half keeps less room on its inner side (10px at `xs`,
|
||||
* 12px at `sm`) and the trailing half is 48px wide. The trailing chevron has its own size,
|
||||
* 22/22/26/38/50px, which the icon-button table does not know about, and sits
|
||||
* `--md-split-button-nudge` (1/1/2/3/6px) towards the leading half so the pair reads as one
|
||||
* control: equal and opposite inline margins move it by exactly that much inside a centred flex
|
||||
* row, in whichever direction the writing mode runs. It turns over while the menu is open, on M3's
|
||||
* standard scheme rather than the expressive springs (the site: "the trailing button uses the
|
||||
* standard motion scheme, not expressive, when rotating").
|
||||
*/
|
||||
|
||||
@layer material.reset, material.tokens, material.base, material.layout, material.components, material.text, material.visibility;
|
||||
|
||||
@import './button.css';
|
||||
|
||||
@layer material.components {
|
||||
[data-md-split-button] {
|
||||
--md-split-button-inner: var(--md-sys-shape-corner-xs);
|
||||
--md-split-button-inner-pressed: var(--md-sys-shape-corner-md);
|
||||
--md-split-button-full: 20px;
|
||||
--md-split-button-icon: 22px;
|
||||
--md-split-button-nudge: 1px;
|
||||
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--md-sys-measurement-space25);
|
||||
}
|
||||
|
||||
[data-md-split-button][data-md-size='xs'] {
|
||||
--md-split-button-inner-pressed: var(--md-sys-shape-corner-sm);
|
||||
--md-split-button-full: 16px;
|
||||
}
|
||||
|
||||
[data-md-split-button][data-md-size='md'] {
|
||||
--md-split-button-full: 28px;
|
||||
--md-split-button-icon: 26px;
|
||||
--md-split-button-nudge: 2px;
|
||||
}
|
||||
|
||||
[data-md-split-button][data-md-size='lg'] {
|
||||
--md-split-button-inner: var(--md-sys-shape-corner-sm);
|
||||
--md-split-button-inner-pressed: var(--md-sys-shape-corner-lg-increased);
|
||||
--md-split-button-full: 48px;
|
||||
--md-split-button-icon: 38px;
|
||||
--md-split-button-nudge: 3px;
|
||||
}
|
||||
|
||||
[data-md-split-button][data-md-size='xl'] {
|
||||
--md-split-button-inner: var(--md-sys-shape-corner-md);
|
||||
--md-split-button-inner-pressed: var(--md-sys-shape-corner-lg-increased);
|
||||
--md-split-button-full: 68px;
|
||||
--md-split-button-icon: 50px;
|
||||
--md-split-button-nudge: 6px;
|
||||
}
|
||||
|
||||
[data-md-split-button] [data-md-split] {
|
||||
--md-split-button-corner: var(--md-split-button-inner);
|
||||
|
||||
border-start-start-radius: var(--md-split-button-corner);
|
||||
border-end-start-radius: var(--md-split-button-corner);
|
||||
border-start-end-radius: var(--md-split-button-corner);
|
||||
border-end-end-radius: var(--md-split-button-corner);
|
||||
}
|
||||
|
||||
[data-md-split-button] [data-md-split]:active {
|
||||
--md-split-button-corner: var(--md-split-button-inner-pressed);
|
||||
}
|
||||
|
||||
[data-md-split-button] [data-md-split='trailing'][aria-expanded='true'] {
|
||||
--md-split-button-corner: var(--md-split-button-full);
|
||||
}
|
||||
|
||||
[data-md-split-button] [data-md-split='leading'] {
|
||||
border-start-start-radius: var(--md-split-button-full);
|
||||
border-end-start-radius: var(--md-split-button-full);
|
||||
}
|
||||
|
||||
[data-md-split-button] [data-md-split='trailing'] {
|
||||
border-start-end-radius: var(--md-split-button-full);
|
||||
border-end-end-radius: var(--md-split-button-full);
|
||||
}
|
||||
|
||||
[data-md-split-button][data-md-size='xs'] [data-md-split='leading'] {
|
||||
padding-inline-end: var(--md-sys-measurement-space125);
|
||||
}
|
||||
|
||||
[data-md-split-button][data-md-size='sm'] [data-md-split='leading'] {
|
||||
padding-inline-end: 12px;
|
||||
}
|
||||
|
||||
[data-md-split-button]:is([data-md-size='xs'], [data-md-size='sm']) [data-md-split='trailing'] {
|
||||
inline-size: var(--md-sys-measurement-space600);
|
||||
}
|
||||
|
||||
[data-md-split-button] [data-md-split='trailing'] [data-md-icon] {
|
||||
inline-size: var(--md-split-button-icon);
|
||||
block-size: var(--md-split-button-icon);
|
||||
margin-inline-start: calc(-1 * var(--md-split-button-nudge));
|
||||
margin-inline-end: var(--md-split-button-nudge);
|
||||
transition: rotate var(--md-sys-motion-duration-short) var(--md-sys-motion-easing-standard);
|
||||
}
|
||||
|
||||
[data-md-split-button] [data-md-split='trailing'][aria-expanded='true'] [data-md-icon] {
|
||||
rotate: 180deg;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user