Non-modal menus:
- DropdownMenu + ContextMenu default to trapFocus=false + preventScroll=false
(were modal — hard focus-trap + body scroll-lock that made them feel stuck).
Menus stay navigable while open (Chakra-style); the props remain for an opt-in
modal menu. morfo focus.trap=false + the demo control defaults aligned.
list-surface — ONE shared size source for list surfaces:
- new lib/list-surface.css (--list-* keyed on [data-list-surface][data-size], 1:1
with the control sizes) + lib/list-surface-context.ts (shared size context for
portaled sub-panels). DropdownMenu/ContextMenu/Menubar/Listbox bridge their
--{c}-* size tokens to --list-*; ContextMenu gained the size axis it lacked.
Row-height doctrine — unified to CONTROL-HEIGHT:
- archetypes.css [data-archetype=item/option] gains a fallback-guarded control-
height FLOOR (min-block-size: var(--list-item-height, auto) + padding-block:
var(--list-item-py, var(--space-1-5))) — ZERO regression off a list-surface
(the ~45 non-list archetype consumers are untouched). Select/Combobox/Command
stamp data-list-surface so their option rows inherit the floor, matching menu
items. Verified: select option md 36px / lg 44px = menu items; bare archetype
item unchanged (0 floor, --space-1-5 padding).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Completes the menu-family event-driven cascade: a SubContent fly-out now cascades
its items in on open, same as the root panel. The SubContent has its own
`data-state`, so the existing container-driven preset rule applies unchanged — it
only needed the `[data-stagger]` marker on the panel + `--motion-stagger-each` on
the sub-content recipe selector. Its items are the same `DropdownMenu.Item`
(already `data-animation-style="fade"`). Menubar inherits via the shared
DropdownMenu.SubContent.
Verified at runtime: SubContent panel carries `data-stagger` + `data-state=open`,
`--motion-stagger-each: 20ms`, items `name:fade-in` with consecutive `:nth-child`
index 0/1/2 (a flat submenu cascades cleanly). `check` clean for the touched
components.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extends the just-landed DropdownMenu event-driven item cascade to its siblings
so the framework is coherent — every menu in the family fades its items in
staggered on open, same mechanism, zero new generator code (rides the
container-driven preset branch shipped with DropdownMenu).
- ContextMenu (own recipe): Content marks the panel `[data-stagger]` +
`--motion-stagger-each: var(--motion-stagger)`; item / checkbox-item /
radio-item carry `data-animation-style="fade"`.
- Menubar (ONE line): soma `Menubar.Content` delegates to `DropdownMenuContent`,
so its panel already carries `data-dropdown-menu-content` (→ the dropdown
recipe rhythm applies) and re-uses `DropdownMenu.Item` (→ already
`data-animation-style="fade"`). It only adds the `[data-stagger]` marker.
Verified at runtime: ContextMenu (scrubbed opacity gradient 0.96/0.84/0.00),
Menubar (panel carries `data-stagger` + `data-dropdown-menu-content`, items
`name:fade-in`, structural index from `:nth-child` 0/1/2/6/7). `check` clean for
the touched components. (Preview tab runs backgrounded → rAF paused; verified by
scrubbing `animation.currentTime` via WAAPI rather than waiting for playback.)
Deliberately NOT rolled out: select / combobox / command — live-filtered or
long-scroll lists where an open cascade is questionable UX.
Docs: ContextMenu README (Motion parity note), Menubar index doc, DropdownMenu
README (family cross-reference), RFC §D.11.4 (rollout).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>