diff --git a/src/uix/eidos/components/navigation-menu/index.ts b/src/uix/eidos/components/navigation-menu/index.ts new file mode 100644 index 000000000..04072531d --- /dev/null +++ b/src/uix/eidos/components/navigation-menu/index.ts @@ -0,0 +1,71 @@ +// NavigationMenu — eidos compound API. +// +// import { NavigationMenu } from '$uix/eidos/components/navigation-menu'; +// +// +// +// +// Products +// +//

Mega-menu content for Products

+//
+//
+// +// Pricing +// +//
+// +//
+// +// Soma owns active-item state, hover delays (`openDelay` / +// `skipDelayDuration` / `closeDelay`), `hoverEnabled`, loop nav, +// `data-motion` directional swap, indicator rect CSS vars. Eidos paints +// the bar + trigger chrome + Content panel + slide animations. +// +// Naming: matches soma's part names exactly. Both `Trigger` (button) +// and `Link` (anchor) stay native — NOT routed through ` + + + + + + + + {#if tab === 'live'} +
+

Controls

+ +
+ soma Provider props +
+
+ + + + + + + +
+ +
+ eidos visual size +
+
+ +
+ +
+
+ eidos + visual · bar + trigger chrome + Content panel + directional motion + svelte +
+
{eidosSnippet}
+
+
+ {/if} + + {#if tab === 'api'} +
+

API reference

+

7 parts: Provider, List, Item, Trigger, Content, Link, Indicator.

+ +
Provider
+
+ + + + + + + + + + + + +
PropTypeDefaultDescription
value bindablestring | nullnullCurrently open item value.
orientation'horizontal' | 'vertical''horizontal'Bar layout axis.
openDelaynumber200Hover-to-open delay (ms).
skipDelayDurationnumber100Hover-swap delay between sibling triggers (ms).
closeDelaynumber300Close delay after pointer exit (ms).
hoverEnabledbooleantrueDisable to require click-only opening.
loopbooleantrueWrap arrow nav between triggers.
size eidos'sm' | 'md' | 'lg''md'Visual size — trigger padding + font.
+
+ +
Item · Trigger · Content · Link · Indicator
+

+ Item is the wrapper around each trigger / content pair (gets value for routing in the bar's value binding). Trigger renders a native <button> with chevron affordance; Link renders <a> with aria-current support — both styled by the recipe with the same flat in-bar chrome, NOT routed through <Button>. Indicator is a 2px underline that slides between active triggers via CSS vars ({`--navigation-menu-indicator-{x,y,w,h}`}) written by soma. +

+
+ {/if} + + {#if tab === 'morfo'} +
+

+ morfo + · declarative contract +

+

Source: src/uix/morfo/components/navigation-menu.ts.

+ +
+ + + + + + + + +
FieldValue
name"{navigationMenuMorfo.name}"
kebab"{navigationMenuMorfo.kebab}"
parts.length{navigationMenuMorfo.parts.length}
events.length{events.length}
+
+ +
Parts
+
+ + + + {#each partsList as part (part.kebab)} + + + + + + + + + + {/each} + +
PartMarkerElementRoleArchetypeStatesOptional
{part.kebab}[{part.marker}]<{part.defaultElement}>{part.role ?? '—'}{part.archetype ?? '—'}{part.states.length ? part.states.join(' | ') : '—'}{part.optional ? 'yes' : 'no'}
+
+ +
Events declaration
+
+ + + + {#each events as action (action.name)} + {@const sem = action.semantic} + {@const intentDecl = 'intent' in sem ? sem.intent : undefined} + {@const intentStr = typeof intentDecl === 'string' ? intentDecl : intentDecl ? `fromProp:${(intentDecl as { fromProp?: string }).fromProp ?? '?'}` : '—'} + + + + + + + + + {/each} + +
namefamilyverbsequenceintenttarget
{action.name}{sem.family}{sem.verb ?? '—'}{sem.sequence ?? 'pre'}{intentStr}{action.target}
+
+
+ {/if} + + {#if tab === 'sema'} +
+

+ sema + · events +

+ +
+ + + + {#each events as action (action.name)} + {@const intentDecl = 'intent' in action.semantic ? action.semantic.intent : undefined} + {@const effectiveIntent = typeof intentDecl === 'string' ? intentDecl : undefined} + + + + + + + + + {/each} + +
NameFamilyVerbSequenceIntentPlay
{action.name}{action.semantic.family}{action.semantic.verb ?? '—'}{action.semantic.sequence ?? 'pre'}{effectiveIntent ?? '—'} + +
+
+
+ {/if} + + {#if tab === 'recipe'} +
+

Eidos recipe

+

Selectors at src/uix/eidos/components/navigation-menu/navigation-menu.css.

+
+ + + + + + + + + + + + + +
SelectorSourceWhat it paints
[data-navigation-menu]eidosRoot bar — inline-flex container with relative positioning.
[data-navigation-menu][data-size]eidosSize scale — trigger padding + font + list gap.
[data-navigation-menu-list]morfoHorizontal/vertical flex list of items.
[data-navigation-menu-trigger], [data-navigation-menu-link]morfoFlat in-bar chrome — transparent bg, hover tint, focus ring.
[data-navigation-menu-trigger][data-state='open']morfoOpen-state tint + chevron rotation.
[data-navigation-menu-link][aria-current='page']morfoActive-page accent.
[data-navigation-menu-content]morfoMega-menu panel chrome + entrance animation.
[data-navigation-menu-content][data-motion]morfoDirectional slide on trigger swap (from-start/end + to-start/end).
[data-navigation-menu-indicator]morfo2px underline that slides via CSS vars ({`--navigation-menu-indicator-{x,y,w,h}`}).
+
+
+ {/if} + + {#if tab === 'a11y'} +
+

Accessibility

+

+ Root renders <nav> with translated aria-label + ("Main"). Each Trigger has aria-haspopup="menu", + aria-expanded and aria-controls; Content + is the labelled mega-menu region. Links use aria-current="page" + when the route matches. +

+ +
Keyboard
+
+ + + + + + + + + + +
KeyAction
ArrowRight / ArrowLeft on TriggerMove focus to next/previous Trigger (horizontal orientation; RTL inverts).
ArrowDown / ArrowUp on TriggerOpen the menu and move focus into the Content (vertical orientation: prev/next instead).
Enter / Space on TriggerToggle the menu open/close.
EscapeClose the menu, focus stays on Trigger.
Home / EndFirst / last Trigger.
TabMove focus into the Content if open; otherwise advance past the bar.
+
+ +
ARIA contract
+
+ + + + + + + + + + + + +
PartAttributeValue
navigation-menuaria-label"Main" (translated)
listrole"list"
triggeraria-haspopup"menu"
triggeraria-expanded"true" | "false"
triggerdata-state"open" | "closed"
contentrole"menu"
contentdata-motion"from-start" | "from-end" | "to-start" | "to-end"
linkaria-current"page" (active route only)
+
+
+ {/if} +