feat(motion): cascade fly-out submenus too (DropdownMenu + ContextMenu)

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>
active-uix
dev 4 months ago
parent 19ecbf44e4
commit 2a378360e6

@ -1,11 +1,15 @@
<script lang="ts">
/**
* `data-stagger`: a fly-out submenu cascades its items in on open, same as the
* root Content. See the DropdownMenu README -> Motion.
*/
import * as ContextMenu from '$soma/components/context-menu';
import type { ContextMenuSubContentProps } from './types';
let { children: bodyContent, ...rest }: ContextMenuSubContentProps = $props();
</script>
<ContextMenu.SubContent {...rest}>
<ContextMenu.SubContent data-stagger="" {...rest}>
{#snippet children(snippetProps)}
{@render bodyContent?.(snippetProps)}
{/snippet}

@ -44,8 +44,10 @@
`[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. */
[data-context-menu-content] {
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] {
--motion-stagger-each: var(--motion-stagger);
}

@ -113,6 +113,10 @@ Two honest limits (both documented framework-wide):
lifecycle), still deferred — so a closing container does **not** drive a child
exit that would be cut off on unmount.
Fly-out **submenus** (`SubContent`) cascade too — the SubContent panel has its
own `data-state`, so the same marker + items work; a flat submenu cascades its
items consecutively (`:nth-child` 0/1/2…).
`<ContextMenu>` and `<Menubar>` share this verbatim (same soma menu machinery):
ContextMenu has its own recipe; Menubar's per-menu panel already carries
`data-dropdown-menu-content` and re-uses `DropdownMenu.Item`, so it inherits the

@ -1,11 +1,16 @@
<script lang="ts">
/**
* `data-stagger`: a fly-out submenu cascades its items in on open, same as the
* root Content (its items also carry `data-animation-style="fade"`). See the
* DropdownMenu README -> Motion.
*/
import * as DropdownMenu from '$soma/components/dropdown-menu';
import type { DropdownMenuSubContentProps } from './types';
let { children: bodyContent, ...rest }: DropdownMenuSubContentProps = $props();
</script>
<DropdownMenu.SubContent {...rest}>
<DropdownMenu.SubContent data-stagger="" {...rest}>
{#snippet children(snippetProps)}
{@render bodyContent?.(snippetProps)}
{/snippet}

@ -55,8 +55,10 @@
and gets its structural index from `:nth-child`. This is the per-item
delay step — `var(--motion-stagger)` (canonical 20ms); 0 = parallel,
larger = a more deliberate ripple. The cascade flows from the `open`
(emerge) event — no JS writes the index, no consumer wiring. */
[data-dropdown-menu-content] {
(emerge) event — no JS writes the index, no consumer wiring. Applies to the
root panel AND fly-out SubContent (both mark themselves `[data-stagger]`). */
[data-dropdown-menu-content],
[data-dropdown-menu-sub-content] {
--motion-stagger-each: var(--motion-stagger);
}

Loading…
Cancel
Save

Powered by TurnKey Linux.