feat(dropdown-menu): adopt the `overlay` elevation plane (B2)

Content / SubContent now carry `data-depth="overlay"` and take their
surface · border · shadow · halo from the overlay plane instead of the
recipe. Prune the now-redundant recipe tokens (content-border-width /
border-color / bg / shadow) — the plane is the single source, no
double-paint — and point the arrow fill at `--depth-overlay-surface` so
it always matches the panel. Radius / font / color stay the panel's own.

Verified in-browser: open menu paints bg oklch(0.285) + 1px border +
shadow/halo from the plane; orphan-token contract test passes; check 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
active-uix
dev 4 months ago
parent 1431970371
commit f80f222596

@ -140,11 +140,17 @@ chips" without per-item state bookkeeping.
## Decisiones
- **No `variant` / `color` / `size` at the menu level.** Menus are
the visual variant of "list of actions" within an app; introducing
multiple visual flavors creates noise. If a consumer wants a colored
destructive item they pass `data-color` on the `<DropdownMenu.Item>`
directly (the morfo accepts it).
- **No `variant` / `color` at the menu level.** Menus are the visual
variant of "list of actions" within an app; introducing multiple visual
flavors creates noise. If a consumer wants a colored destructive item they
pass `data-color` on the `<DropdownMenu.Item>` directly (the morfo accepts it).
- **`size` IS a menu axis (1:1 with the controls).** A menu is *content*, so
it scales like a Field input — `size N → --font-size-N` + `--control-height-N`,
not one step below. `<DropdownMenu.Content size>` (default `md`) stamps
`data-size`; the recipe retints the panel's own per-size tokens, and the size
flows to every fly-out submenu via a context (submenus portal out, so CSS
inheritance can't carry it). This is what composed menus (e.g. `SplitButton`)
forward their size into — the scale lives here, once, not per consumer.
- **Pass-through wrappers** for every part. Visual treatment is in the
CSS recipe via `[data-dropdown-menu-*]` selectors — keeping wrappers
thin makes context-menu and menubar trivial to derive (just

@ -34,7 +34,7 @@
setListSurfaceSizeContext({ getSize: () => resolvedSize });
</script>
<DropdownMenu.Content data-stagger="" data-list-surface="" {...rest} data-size={resolvedSize}>
<DropdownMenu.Content data-stagger="" data-list-surface="" data-depth="overlay" {...rest} data-size={resolvedSize}>
{#snippet children(snippetProps)}
{@render bodyContent?.(snippetProps)}
{/snippet}

@ -21,7 +21,7 @@
const resolvedSize = $derived(eidos.resolve(size ?? sizeCtx?.getSize(), 'md'));
</script>
<DropdownMenu.SubContent data-stagger="" data-list-surface="" {...rest} data-size={resolvedSize}>
<DropdownMenu.SubContent data-stagger="" data-list-surface="" data-depth="overlay" {...rest} data-size={resolvedSize}>
{#snippet children(snippetProps)}
{@render bodyContent?.(snippetProps)}
{/snippet}

@ -36,11 +36,9 @@
max-block-size: var(--dropdown-menu-content-max-height, min(60vh, 22rem));
overflow-y: auto;
padding: var(--dropdown-menu-content-padding, var(--space-1));
border: var(--dropdown-menu-content-border-width, 1px) solid
var(--dropdown-menu-content-border-color, var(--color-border-default));
/* Elevation — surface · border · shadow — from the `overlay` plane via
`data-depth` (A1, Decisión 8). Radius / font / color stay the panel's own. */
border-radius: var(--dropdown-menu-content-radius, var(--radius-md));
background: var(--dropdown-menu-content-bg, var(--color-surface-overlay));
box-shadow: var(--dropdown-menu-content-shadow, var(--shadow-overlay));
font-family: var(--style-label-font-family, var(--font-ui));
font-size: var(--dropdown-menu-content-font-size, var(--font-size-sm));
color: var(--color-content-primary);
@ -182,7 +180,9 @@
/* ── Arrow ────────────────────────────────────────────────────────── */
[data-dropdown-menu-arrow] {
fill: var(--dropdown-menu-content-bg, var(--color-surface-overlay));
/* The arrow is part of the elevation surface — consume the `overlay` plane so
it always matches the panel (A1, like popover), not a parallel token. */
fill: var(--depth-overlay-surface);
}
/* ── State transitions ────────────────────────────────────────────── */

@ -3357,11 +3357,7 @@
--dropdown-menu-content-min-width: 12rem;
--dropdown-menu-content-max-height: min(60vh, 22rem);
--dropdown-menu-content-padding: var(--space-1);
--dropdown-menu-content-border-width: var(--border-width);
--dropdown-menu-content-border-color: var(--color-border-default);
--dropdown-menu-content-radius: var(--radius-md);
--dropdown-menu-content-bg: var(--color-surface-overlay);
--dropdown-menu-content-shadow: var(--depth-overlay-shadow), var(--depth-overlay-halo);
--dropdown-menu-content-font-size: var(--font-size-sm);
--dropdown-menu-item-gap: var(--space-2);
--dropdown-menu-item-height: 2rem;

@ -4196,11 +4196,7 @@ export const THEME_BASE_RECIPE_TOKENS = {
'content-min-width': '12rem',
'content-max-height': 'min(60vh, 22rem)',
'content-padding': 'var(--space-1)',
'content-border-width': 'var(--border-width)',
'content-border-color': 'var(--color-border-default)',
'content-radius': 'var(--radius-md)',
'content-bg': 'var(--color-surface-overlay)',
'content-shadow': 'var(--depth-overlay-shadow), var(--depth-overlay-halo)',
'content-font-size': 'var(--font-size-sm)',
'item-gap': 'var(--space-2)',
'item-height': '2rem',

Loading…
Cancel
Save

Powered by TurnKey Linux.