feat(dropdown-menu): port from soma to eidos (Tier 1 sprint, 3/5)
Full 15-part compound — pass-through wrappers over soma with the
canonical visual recipe.
Parts: Provider · Trigger · Content · Arrow · Item · Group ·
GroupHeading · Separator · CheckboxItem · CheckboxGroup · RadioGroup
· RadioItem · Sub · SubTrigger · SubContent.
API parity with Bits UI (richest reference): CheckboxGroup +
RadioGroup binding arrays / scalars, nested Sub-menus, Arrow pointer.
Radix Primitives + Ark UI lack CheckboxGroup; Chakra v3 + Radix
Themes lack Arrow.
Recipe (dropdown-menu.css):
- Uniform chrome across Content + SubContent (panel shadow,
border, padding, max-height)
- Items share one set of tokens (hover/focus highlight, disabled
opacity, indicator slot via `::before` for Checkbox/Radio
data-state='checked')
- SubTrigger gets a chevron via `::after`
- GroupHeading: muted uppercase, micro-tracked
- Separator: 1px subtle divider
- Enter animation on `data-state='open'`
No `variant` / `color` / `size` knobs at the eidos layer — menus are
themselves the visual variant of "list of actions" within an app.
Per-item destructive coloring deferred to next pass (cascade via
item's `data-color` attr).
Morfo scope: ['soma'] → ['soma', 'sema', 'eidos']. Sound comes from
the family bases (`emerge` for open/close, `commit` for select) — no
per-component cascade needed.
Demo: 6-tab template, items hooked to `lastSelected` tracker, all
three groupings demoed (Items / CheckboxGroup / RadioGroup / Sub).
Checks: svelte-check 0 errors, component:audit 91/91 PASS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
<script lang="ts">
|
|
|
|
|
/**
|
|
|
|
|
* Eidos `<DropdownMenu.CheckboxItem>`. Defaults
|
|
|
|
|
* `closeOnSelect={false}` because a checkbox is a state toggle, not
|
|
|
|
|
* a one-shot action — the user typically wants to toggle multiple
|
|
|
|
|
* options without having to re-open the menu each time. Pass
|
|
|
|
|
* `closeOnSelect` explicitly to override (Radix Primitives leaves
|
|
|
|
|
* the close behaviour to the consumer; we pick the saner default).
|
|
|
|
|
*/
|
feat(dropdown-menu): port from soma to eidos (Tier 1 sprint, 3/5)
Full 15-part compound — pass-through wrappers over soma with the
canonical visual recipe.
Parts: Provider · Trigger · Content · Arrow · Item · Group ·
GroupHeading · Separator · CheckboxItem · CheckboxGroup · RadioGroup
· RadioItem · Sub · SubTrigger · SubContent.
API parity with Bits UI (richest reference): CheckboxGroup +
RadioGroup binding arrays / scalars, nested Sub-menus, Arrow pointer.
Radix Primitives + Ark UI lack CheckboxGroup; Chakra v3 + Radix
Themes lack Arrow.
Recipe (dropdown-menu.css):
- Uniform chrome across Content + SubContent (panel shadow,
border, padding, max-height)
- Items share one set of tokens (hover/focus highlight, disabled
opacity, indicator slot via `::before` for Checkbox/Radio
data-state='checked')
- SubTrigger gets a chevron via `::after`
- GroupHeading: muted uppercase, micro-tracked
- Separator: 1px subtle divider
- Enter animation on `data-state='open'`
No `variant` / `color` / `size` knobs at the eidos layer — menus are
themselves the visual variant of "list of actions" within an app.
Per-item destructive coloring deferred to next pass (cascade via
item's `data-color` attr).
Morfo scope: ['soma'] → ['soma', 'sema', 'eidos']. Sound comes from
the family bases (`emerge` for open/close, `commit` for select) — no
per-component cascade needed.
Demo: 6-tab template, items hooked to `lastSelected` tracker, all
three groupings demoed (Items / CheckboxGroup / RadioGroup / Sub).
Checks: svelte-check 0 errors, component:audit 91/91 PASS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
import * as DropdownMenu from '$soma/components/dropdown-menu';
|
|
|
|
|
import type { DropdownMenuCheckboxItemProps } from './types';
|
|
|
|
|
|
|
|
|
|
let {
|
|
|
|
|
checked = $bindable(false),
|
|
|
|
|
closeOnSelect = false,
|
feat(dropdown-menu): port from soma to eidos (Tier 1 sprint, 3/5)
Full 15-part compound — pass-through wrappers over soma with the
canonical visual recipe.
Parts: Provider · Trigger · Content · Arrow · Item · Group ·
GroupHeading · Separator · CheckboxItem · CheckboxGroup · RadioGroup
· RadioItem · Sub · SubTrigger · SubContent.
API parity with Bits UI (richest reference): CheckboxGroup +
RadioGroup binding arrays / scalars, nested Sub-menus, Arrow pointer.
Radix Primitives + Ark UI lack CheckboxGroup; Chakra v3 + Radix
Themes lack Arrow.
Recipe (dropdown-menu.css):
- Uniform chrome across Content + SubContent (panel shadow,
border, padding, max-height)
- Items share one set of tokens (hover/focus highlight, disabled
opacity, indicator slot via `::before` for Checkbox/Radio
data-state='checked')
- SubTrigger gets a chevron via `::after`
- GroupHeading: muted uppercase, micro-tracked
- Separator: 1px subtle divider
- Enter animation on `data-state='open'`
No `variant` / `color` / `size` knobs at the eidos layer — menus are
themselves the visual variant of "list of actions" within an app.
Per-item destructive coloring deferred to next pass (cascade via
item's `data-color` attr).
Morfo scope: ['soma'] → ['soma', 'sema', 'eidos']. Sound comes from
the family bases (`emerge` for open/close, `commit` for select) — no
per-component cascade needed.
Demo: 6-tab template, items hooked to `lastSelected` tracker, all
three groupings demoed (Items / CheckboxGroup / RadioGroup / Sub).
Checks: svelte-check 0 errors, component:audit 91/91 PASS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
children: bodyContent,
|
|
|
|
|
...rest
|
|
|
|
|
}: DropdownMenuCheckboxItemProps = $props();
|
|
|
|
|
</script>
|
|
|
|
|
|
feat(motion): event-driven item cascade — first real consumer (DropdownMenu)
Productizes the event-driven cascade on a real component (not the explicit
`<Cascade>` orchestrator). When a DropdownMenu opens, its items fade in
staggered by structural order — the appearance flows from the `open` (emerge)
event, nothing in the app wires it.
Architecture: a +1 GENERIC selector branch in the motion generator, NOT a
per-item `data-state`. A `menuitem` isn't open/closed — the menu is — and eidos
writing a state attr is a smell. The new container-driven form
`[data-stagger][data-state='open'] > [data-animation-style='X']` fires each
child's ENTER off the container's `data-state` (which soma already writes via
the morfo `commits`); items carry only `data-animation-style`. ENTER only: the
coordinated EXIT cascade (retain the container until children finish) is the
deferred soma PresenceGroup work, so a closing container can't drive a child
exit that would be cut off on unmount.
- render-css.ts: `renderCssPresetRules` adds the container-driven enter branch
(same declarations, shared comma selector) — reuses the existing presets +
the foundation `:nth-child` stagger index; zero new system.
- DropdownMenu: Content marks itself `[data-stagger]` +
`--motion-stagger-each: var(--motion-stagger)` (20ms, themeable, no magic
number); item/checkbox-item/radio-item carry `data-animation-style="fade"`
(overridable). `fade` so item opacity doesn't fight the panel's own scale.
- regen generated/base.css (8 css presets gain the container-driven enter).
Verified in browser (frozen frame): index from `:nth-child`, `delay = idx ×
each`, opacity gradient in flight (Ruler 0.98 → Grid 0.89 → Guides 0.69, Log
out 0.00). Honest limit (documented): only DIRECT-child items cascade — items in
a <Group>/<RadioGroup> DOM wrapper aren't `:nth-child` of the panel, so they
appear instantly (the "transparent intermediate").
Docs: dropdown README §Motion, cascade README §2 (concrete consumer), RFC §D.11.4.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4 months ago
|
|
|
<DropdownMenu.CheckboxItem data-animation-style="fade" {...rest} {closeOnSelect} bind:checked>
|
feat(dropdown-menu): port from soma to eidos (Tier 1 sprint, 3/5)
Full 15-part compound — pass-through wrappers over soma with the
canonical visual recipe.
Parts: Provider · Trigger · Content · Arrow · Item · Group ·
GroupHeading · Separator · CheckboxItem · CheckboxGroup · RadioGroup
· RadioItem · Sub · SubTrigger · SubContent.
API parity with Bits UI (richest reference): CheckboxGroup +
RadioGroup binding arrays / scalars, nested Sub-menus, Arrow pointer.
Radix Primitives + Ark UI lack CheckboxGroup; Chakra v3 + Radix
Themes lack Arrow.
Recipe (dropdown-menu.css):
- Uniform chrome across Content + SubContent (panel shadow,
border, padding, max-height)
- Items share one set of tokens (hover/focus highlight, disabled
opacity, indicator slot via `::before` for Checkbox/Radio
data-state='checked')
- SubTrigger gets a chevron via `::after`
- GroupHeading: muted uppercase, micro-tracked
- Separator: 1px subtle divider
- Enter animation on `data-state='open'`
No `variant` / `color` / `size` knobs at the eidos layer — menus are
themselves the visual variant of "list of actions" within an app.
Per-item destructive coloring deferred to next pass (cascade via
item's `data-color` attr).
Morfo scope: ['soma'] → ['soma', 'sema', 'eidos']. Sound comes from
the family bases (`emerge` for open/close, `commit` for select) — no
per-component cascade needed.
Demo: 6-tab template, items hooked to `lastSelected` tracker, all
three groupings demoed (Items / CheckboxGroup / RadioGroup / Sub).
Checks: svelte-check 0 errors, component:audit 91/91 PASS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
|
|
|
{#snippet children(snippetProps)}
|
|
|
|
|
{@render bodyContent?.(snippetProps)}
|
|
|
|
|
{/snippet}
|
|
|
|
|
</DropdownMenu.CheckboxItem>
|