You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/src/uix/eidos/components/context-menu/context-menu.css

207 lines
8.2 KiB

/*
* ContextMenu recipe.
*
* Functionally identical to DropdownMenu — same panel chrome, same
* item row treatment. Only differences:
*
* - Trigger is a `<span>` wrapper (NOT a button) that intercepts
* `contextmenu`. The recipe gives it no chrome by default; the
* wrapper is meant to feel inert until invoked.
* - Anchoring is to the cursor position rather than the trigger's
* bounding box — soma's floating layer handles this. The visual
* panel reads identical to DropdownMenu's.
*
* To avoid recipe duplication we lean on attribute selectors that
* cover both `data-dropdown-menu-*` and `data-context-menu-*` for the
* shared parts (Content, Item, Group, Separator, etc.). The Trigger
* gets its own rule since its semantics differ.
*/
/* ── Panel (Content / SubContent) ──────────────────────────────────── */
[data-context-menu-content],
[data-context-menu-sub-content] {
min-inline-size: var(--context-menu-content-min-width, 12rem);
max-block-size: var(--context-menu-content-max-height, min(60vh, 22rem));
overflow-y: auto;
padding: var(--context-menu-content-padding, var(--space-1));
/* 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(--context-menu-content-radius, var(--radius-md));
font-family: var(--style-label-font-family, var(--font-ui));
font-size: var(--context-menu-content-font-size, var(--font-size-sm));
color: var(--color-content-primary);
}
[data-context-menu-content]:focus-visible,
[data-context-menu-sub-content]:focus-visible {
outline: none;
}
/* ── Size scale → shared list-surface ───────────────────────────────────
*
* The size rhythm (font / item-height / padding / gap / content-padding /
* radius, 1:1 with the control sizes) lives in `lib/list-surface.css` — the
* ONE source shared by every menu + selection popup. The panel carries
* `data-list-surface` + `data-size` (stamped by the eidos Content/SubContent),
* so that block sets `--list-*`; here we just BRIDGE the panel's own public
* tokens to it, keeping them as the per-component override knobs. Mirrors the
* DropdownMenu bridge — both menus read identically.
*/
[data-context-menu-content],
[data-context-menu-sub-content] {
--context-menu-content-font-size: var(--list-font-size);
--context-menu-item-height: var(--list-item-height);
--context-menu-item-py: var(--list-item-py);
--context-menu-item-px: var(--list-item-px);
--context-menu-item-gap: var(--list-item-gap);
--context-menu-content-padding: var(--list-content-padding);
--context-menu-content-radius: var(--list-content-radius);
}
feat(motion): event-driven cascade rollout to the menu family (ContextMenu + Menubar) 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>
4 months ago
/* Event-driven item cascade rhythm — the Content wrapper marks itself
`[data-stagger]`; each direct-child item carries `data-animation-style` and
gets its structural index from `:nth-child`. `var(--motion-stagger)` is the
canonical 20ms (0 = parallel). Same mechanism as DropdownMenu; the appearance
flows from the `open` (emerge) event — no JS writes the index. Applies to the
root panel AND fly-out SubContent (both mark themselves `[data-stagger]`). */
[data-context-menu-content],
[data-context-menu-sub-content] {
feat(motion): event-driven cascade rollout to the menu family (ContextMenu + Menubar) 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>
4 months ago
--motion-stagger-each: var(--motion-stagger);
}
/* ── Item rows ─────────────────────────────────────────────────────── */
[data-context-menu-item],
[data-context-menu-checkbox-item],
[data-context-menu-radio-item],
[data-context-menu-sub-trigger] {
display: flex;
align-items: center;
gap: var(--context-menu-item-gap, var(--space-2));
min-block-size: var(--context-menu-item-height, 2rem);
padding-block: var(--context-menu-item-py, var(--space-1));
padding-inline: var(--context-menu-item-px, var(--space-2));
border-radius: var(--context-menu-item-radius, var(--radius-sm));
color: var(--color-content-primary);
line-height: var(--leading-ui);
cursor: pointer;
user-select: none;
transition:
background var(--duration-fast) var(--ease-default),
color var(--duration-fast) var(--ease-default);
}
[data-context-menu-item]:hover:not([data-disabled]),
[data-context-menu-checkbox-item]:hover:not([data-disabled]),
[data-context-menu-radio-item]:hover:not([data-disabled]),
[data-context-menu-sub-trigger]:hover:not([data-disabled]),
[data-context-menu-item]:focus-visible,
[data-context-menu-checkbox-item]:focus-visible,
[data-context-menu-radio-item]:focus-visible,
[data-context-menu-sub-trigger]:focus-visible,
[data-context-menu-sub-trigger][data-state='open'] {
outline: none;
background: var(--context-menu-item-bg-hover, var(--color-primary-element));
color: var(--context-menu-item-fg-hover, var(--color-content-primary));
}
[data-context-menu-item][data-disabled],
[data-context-menu-checkbox-item][data-disabled],
[data-context-menu-radio-item][data-disabled],
[data-context-menu-sub-trigger][data-disabled] {
cursor: default;
opacity: var(--context-menu-item-disabled-opacity, 0.55);
}
/* Indicator slot + ::before painting for checkbox-item / radio-item shared
with dropdown-menu via `lib/menu-indicator.css` (imported by eidos
entrypoint before this recipe). Override the private vars below if a
per-component tweak is needed. */
[data-context-menu-sub-trigger]::after {
content: '';
margin-inline-start: auto;
inline-size: 0.625rem;
block-size: 0.625rem;
border-inline-end: var(--border-width-medium) solid currentColor;
border-block-start: var(--border-width-medium) solid currentColor;
transform: rotate(45deg);
opacity: var(--opacity-muted);
}
/* ── Group / GroupHeading / Separator ─────────────────────────────── */
[data-context-menu-group] {
display: contents;
}
[data-context-menu-group-heading] {
padding-block: var(--context-menu-heading-py, var(--space-1));
padding-inline: var(--context-menu-heading-px, var(--space-2));
color: var(--color-content-muted);
font-size: var(--context-menu-heading-font-size, var(--font-size-xs));
font-weight: var(--style-label-font-weight, 500);
text-transform: uppercase;
letter-spacing: var(--tracking-caps);
}
[data-context-menu-separator] {
margin-block: var(--context-menu-separator-my, var(--space-1));
block-size: 1px;
background: var(--context-menu-separator-bg, var(--color-border-subtle));
}
/* ── Trigger ──────────────────────────────────────────────────────── */
/*
* Default: no visual treatment. The Trigger is meant to feel inert
* until invoked. Consumers wrap whatever content they want
* right-clickable; the recipe stays out of the way.
*
* `data-state='open'` (set by soma when the menu is open) gets a
* subtle outline as a courtesy affordance — the user often forgets
* which area summoned the menu.
*/
[data-context-menu-trigger] {
display: inline-block;
}
[data-context-menu-trigger][data-state='open'] {
outline: 1px dashed var(--color-border-default);
outline-offset: 2px;
border-radius: var(--radius-sm);
}
/* ── Arrow ────────────────────────────────────────────────────────── */
[data-context-menu-arrow] {
/* 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 ────────────────────────────────────────────── */
[data-context-menu-content][data-state='closed'],
[data-context-menu-sub-content][data-state='closed'] {
opacity: 0;
pointer-events: none;
}
[data-context-menu-content][data-state='open'],
[data-context-menu-sub-content][data-state='open'] {
animation: context-menu-enter var(--duration-fast) var(--ease-out);
}
@keyframes context-menu-enter {
from {
opacity: 0;
transform: scale(0.96);
}
to {
opacity: 1;
transform: none;
}
}

Powered by TurnKey Linux.