Unify the four pseudo-element indicator recipes — context-menu and
dropdown-menu × {checkbox-item, radio-item} — into a single partial at
`lib/menu-indicator.css`. The four selectors paint identical geometry
(0.875rem rounded square or circle at the leading inset) so a single
source keeps them in lockstep.
Tokens are exposed as private vars (`--_menu-indicator-{size,radius,
color,inset,mask}`) so a consumer can override per-component without
re-implementing the recipe.
Import order matters: the partial must load AFTER the menu recipes so
its `padding-inline-start: calc(...)` wins over the row rule's
`padding-inline` shorthand at equal specificity. Verified in browser
on both /uix/components/dropdown-menu and /uix/components/context-menu:
checked checkbox-items render 14×14 purple rounded squares, radio-items
render circles, and all rows reserve the same 26px slot so toggling
state doesn't shift text.
Out of scope: Checkbox / RadioGroup / Select.ItemIndicator — those use
`[data-*-indicator]` DOM parts with SVG markers and xs/sm/md/lg/xl size
scales, an architecturally different pattern.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
active-uix
parent
dc03773ca5
commit
0e9628b8f0
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Shared menu-item indicator recipe.
|
||||
*
|
||||
* Targets the four pseudo-element indicators that signal `data-state='checked'`
|
||||
* on menu items inside a `role="menu"` container:
|
||||
*
|
||||
* [data-context-menu-checkbox-item]
|
||||
* [data-context-menu-radio-item]
|
||||
* [data-dropdown-menu-checkbox-item]
|
||||
* [data-dropdown-menu-radio-item]
|
||||
*
|
||||
* These four selectors share the exact same geometry — a 0.875rem ✕ 0.875rem
|
||||
* filled element painted at the leading inset of the item row. The check
|
||||
* variant is a rounded square, the radio variant is a circle.
|
||||
*
|
||||
* The four items are SEPARATE morfo parts (different ARIA roles —
|
||||
* `menuitemcheckbox` vs `menuitemradio`) but their visual treatment is
|
||||
* coherent: both represent a "selected" affordance inside the menu chrome.
|
||||
* Unifying the recipe avoids drift between the two menus (context-menu vs
|
||||
* dropdown-menu) without merging the contracts.
|
||||
*
|
||||
* Tokens (consumer-overridable via the same private vars):
|
||||
* --_menu-indicator-size @default 0.875rem
|
||||
* --_menu-indicator-radius @default 0.2rem (rounded square)
|
||||
* --_menu-indicator-color @default var(--color-primary-solid)
|
||||
* --_menu-indicator-inset @default var(--space-2)
|
||||
* --_menu-indicator-mask @default none (optional CSS mask-image for
|
||||
* a custom check glyph)
|
||||
*
|
||||
* NOT INCLUDED: Checkbox / RadioGroup / Select.ItemIndicator. Those use DOM
|
||||
* parts (`[data-checkbox-indicator]`, etc.) with their own SVG markers and
|
||||
* size scales (xs/sm/md/lg/xl), a different architectural pattern.
|
||||
*/
|
||||
|
||||
/* Reserve the indicator slot on every menu-item type that may carry one,
|
||||
even when unchecked, so the row text doesn't shift when state flips. */
|
||||
[data-context-menu-checkbox-item],
|
||||
[data-context-menu-radio-item],
|
||||
[data-dropdown-menu-checkbox-item],
|
||||
[data-dropdown-menu-radio-item] {
|
||||
--_menu-indicator-size: 0.875rem;
|
||||
--_menu-indicator-radius: 0.2rem;
|
||||
--_menu-indicator-color: var(--color-primary-solid);
|
||||
--_menu-indicator-inset: var(--space-2);
|
||||
|
||||
position: relative;
|
||||
padding-inline-start: calc(
|
||||
var(--_menu-indicator-inset) + var(--_menu-indicator-size) + var(--space-1)
|
||||
);
|
||||
}
|
||||
|
||||
/* The indicator itself — only painted when state is checked. */
|
||||
[data-context-menu-checkbox-item][data-state='checked']::before,
|
||||
[data-context-menu-radio-item][data-state='checked']::before,
|
||||
[data-dropdown-menu-checkbox-item][data-state='checked']::before,
|
||||
[data-dropdown-menu-radio-item][data-state='checked']::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset-inline-start: var(--_menu-indicator-inset);
|
||||
inline-size: var(--_menu-indicator-size);
|
||||
block-size: var(--_menu-indicator-size);
|
||||
border-radius: var(--_menu-indicator-radius);
|
||||
background: var(--_menu-indicator-color);
|
||||
mask-image: var(--_menu-indicator-mask, none);
|
||||
-webkit-mask-image: var(--_menu-indicator-mask, none);
|
||||
}
|
||||
|
||||
/* Radio variant — circular indicator. */
|
||||
[data-context-menu-radio-item][data-state='checked']::before,
|
||||
[data-dropdown-menu-radio-item][data-state='checked']::before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
Loading…
Reference in new issue