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/dropdown-menu
dev 4b5bd9f35d
refactor(dropdown-menu): remove unused modal; Trigger→Button; canon vocab fixes
5 months ago
..
README.md feat(dropdown-menu): port from soma to eidos (Tier 1 sprint, 3/5) 5 months ago
dropdown-menu-arrow.svelte feat(dropdown-menu): port from soma to eidos (Tier 1 sprint, 3/5) 5 months ago
dropdown-menu-checkbox-group.svelte feat(dropdown-menu): port from soma to eidos (Tier 1 sprint, 3/5) 5 months ago
dropdown-menu-checkbox-item.svelte fix(dropdown-menu, context-menu): keep menu open on CheckboxItem / RadioItem activation 5 months ago
dropdown-menu-content.svelte feat(dropdown-menu): port from soma to eidos (Tier 1 sprint, 3/5) 5 months ago
dropdown-menu-group-heading.svelte feat(dropdown-menu): port from soma to eidos (Tier 1 sprint, 3/5) 5 months ago
dropdown-menu-group.svelte feat(dropdown-menu): port from soma to eidos (Tier 1 sprint, 3/5) 5 months ago
dropdown-menu-item.svelte feat(dropdown-menu): port from soma to eidos (Tier 1 sprint, 3/5) 5 months ago
dropdown-menu-radio-group.svelte feat(dropdown-menu): port from soma to eidos (Tier 1 sprint, 3/5) 5 months ago
dropdown-menu-radio-item.svelte fix(dropdown-menu, context-menu): keep menu open on CheckboxItem / RadioItem activation 5 months ago
dropdown-menu-separator.svelte feat(dropdown-menu): port from soma to eidos (Tier 1 sprint, 3/5) 5 months ago
dropdown-menu-sub-content.svelte feat(dropdown-menu): port from soma to eidos (Tier 1 sprint, 3/5) 5 months ago
dropdown-menu-sub-trigger.svelte feat(dropdown-menu): port from soma to eidos (Tier 1 sprint, 3/5) 5 months ago
dropdown-menu-sub.svelte feat(dropdown-menu): port from soma to eidos (Tier 1 sprint, 3/5) 5 months ago
dropdown-menu-trigger.svelte refactor(dropdown-menu): remove unused modal; Trigger→Button; canon vocab fixes 5 months ago
dropdown-menu.css refactor(dropdown-menu): remove unused modal; Trigger→Button; canon vocab fixes 5 months ago
dropdown-menu.svelte feat(dropdown-menu): port from soma to eidos (Tier 1 sprint, 3/5) 5 months ago
index.ts feat(dropdown-menu): port from soma to eidos (Tier 1 sprint, 3/5) 5 months ago
types.ts refactor(dropdown-menu): remove unused modal; Trigger→Button; canon vocab fixes 5 months ago

README.md

<DropdownMenu> — eidos

Anchored menu opened by a button trigger. Compound API mirrors Radix DropdownMenu / Bits UI / Ark UI — full surface: Items, Groups (with GroupHeading), Separators, optional CheckboxItem / RadioItem (with RadioGroup or CheckboxGroup binding), nested Sub-menus and an optional Arrow pointer.

Usage

<script lang="ts">
  import { DropdownMenu } from '$uix/eidos/components/dropdown-menu';
  let open = $state(false);
  let notifications = $state(true);
  let theme = $state<'light' | 'dark'>('light');
</script>

<DropdownMenu bind:open>
  <DropdownMenu.Trigger>Open menu</DropdownMenu.Trigger>
  <DropdownMenu.Content side="bottom" align="start">
    <DropdownMenu.Group>
      <DropdownMenu.GroupHeading>Account</DropdownMenu.GroupHeading>
      <DropdownMenu.Item onSelect={() => goto('/profile')}>Profile</DropdownMenu.Item>
      <DropdownMenu.Item onSelect={() => goto('/settings')}>Settings</DropdownMenu.Item>
    </DropdownMenu.Group>
    <DropdownMenu.Separator />
    <DropdownMenu.CheckboxItem bind:checked={notifications}>
      Show notifications
    </DropdownMenu.CheckboxItem>
    <DropdownMenu.Separator />
    <DropdownMenu.RadioGroup bind:value={theme}>
      <DropdownMenu.RadioItem value="light">Light</DropdownMenu.RadioItem>
      <DropdownMenu.RadioItem value="dark">Dark</DropdownMenu.RadioItem>
    </DropdownMenu.RadioGroup>
    <DropdownMenu.Separator />
    <DropdownMenu.Sub>
      <DropdownMenu.SubTrigger>More options</DropdownMenu.SubTrigger>
      <DropdownMenu.SubContent>
        <DropdownMenu.Item>Nested item</DropdownMenu.Item>
      </DropdownMenu.SubContent>
    </DropdownMenu.Sub>
  </DropdownMenu.Content>
</DropdownMenu>

Parts

15 in total. All pass-through wrappers over soma — eidos adds no evaluative props at this level; visual treatment is uniform across items because the menu is itself the "variant" within an app's UI.

Part Notes
DropdownMenu (root) Provider; bind:open
Trigger Toggle button — bring your own visual via children
Content Floating panel — soma owns positioning (side / align / collisions)
Arrow Optional anchor pointer
Item role=menuitem; fires commit-select on activation
Group / GroupHeading Semantic grouping with aria-labelledby
Separator role=separator, horizontal 1px divider
CheckboxItem role=menuitemcheckbox; bind:checked
CheckboxGroup Binds an array; child CheckboxItems use value to participate
RadioGroup / RadioItem role=menuitemradio inside role=group
Sub / SubTrigger / SubContent Nested fly-out menu

Baseline

WAI-ARIA APG Menu Button: https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/

Soma owns:

  • Floating positioning (side, align, sideOffset, avoidCollisions)
  • Keyboard navigation (arrows, typeahead, Home/End, Enter/Space, Escape)
  • Focus trap inside the open Content, return-on-close to Trigger
  • Modal / dismissal behaviour (overlay click, outside interact)
  • Sub-menu cross-axis navigation (ArrowRight opens, ArrowLeft closes)

Comparativa

Lib Sub-menus CheckboxItem / RadioItem CheckboxGroup Arrow Modal toggle
Radix Primitives ✓ ✓ — ✓ ✓
Bits UI ✓ ✓ ✓ ✓ ✓
Ark UI ✓ ✓ — — ✓
Chakra v3 ✓ ✓ — — —
Radix Themes ✓ ✓ — — —
shadcn/ui inherits Radix ✓ — inherits ✓
Eidos (this) ✓ ✓ ✓ (Bits pattern) ✓ ✓

Full parity with the strongest reference (Bits UI). CheckboxGroup is Bits' addition that Radix lacks — useful for "menu of toggleable 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).
  • 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 different triggers).
  • SubContent reads identical to Content. Same panel chrome, same item rows. The contrast between root and sub is visual hierarchy (positioning, chevron affordance), not different styling.
  • Indicator via ::before pseudo. Checkbox/Radio items reserve a leading affordance slot; soma's CheckboxItem doesn't ship an indicator child by default (unlike Bits') because the visual cue via data-state="checked" + pseudo is more compact.

Gaps

Gap Disposición Detalle
Per-item data-color cascade (destructive item visual) implementar próximo turno Add a cascade [data-dropdown-menu-item][data-color='risk'] for the canonical destructive item pattern.
Right-aligned Shortcut slot (⌘K text) diferir Add an ItemShortcut part if the user requests; common pattern from shadcn.
RadioGroupHeading separate from GroupHeading diferir Not in soma morfo; only one heading semantics today.
Animation on data-state='closed' exit diferir Right now closed instantly sets opacity 0. Add a fade-out keyframe when Presence is wired.

Reference

Powered by TurnKey Linux.