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" >
import { DropdownMenu } from '$uix/eidos/components/dropdown-menu';
import { compileMorfo } from '$uix/morfo';
import { dropdownMenuMorfo } from '@/uix/morfo/components/dropdown-menu';
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
import { getActiveUix } from '$active-uix';
const uix = getActiveUix();
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
type Tab = 'live' | 'api' | 'morfo' | 'sema' | 'recipe' | 'a11y';
let tab = $state< Tab > ('live');
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
// ── Live state ────────────────────────────────────────────────────────
// Soma · Provider
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
let open = $state(false);
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
let dir = $state< 'ltr' | 'rtl'>('ltr');
let accessibleWhenDisabled = $state(true);
// Soma · Content
let side = $state< 'top' | 'right' | 'bottom' | 'left'>('bottom');
let sideOffset = $state(4);
let align = $state< 'start' | 'center' | 'end'>('start');
let alignOffset = $state(0);
let avoidCollisions = $state(true);
let loop = $state(false);
let trapFocus = $state(true);
let preventScroll = $state(true);
// Item-level
let disableLogout = $state(false);
let closeOnSelect = $state(true);
// Bound state (mirrors)
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
let notifications = $state(true);
let theme = $state< 'light' | 'dark' | 'system'>('system');
let viewLayers = $state< string [ ] > (['ruler']);
let lastSelected = $state< string | null > (null);
refactor(dropdown-menu): remove unused modal; Trigger→Button; canon vocab fixes
Three related fixes touching the menu surface:
1. **Remove `modal` from DropdownMenu** (#127). The prop was declared in
soma but never wired to anything — no overlay, no pointer-events
blocker, no scrim. ark-ui / Headless-UI / Chakra all treat menu as
non-modal by convention; Dialog/Drawer/AlertDialog cover blocking
semantics. Drop it from soma (types, provider opts, component, test
fixture), the eidos doc comment, the menubar consumer, and the
dropdown-menu demo (state, control, snippet, API table, parity table).
2. **DropdownMenu.Trigger now renders `<Button>` internally** (#120
first consumer). Default variant='surface', size='md', intent='neutral'.
`variant` is narrowed to ControlVariant (`'surface' | 'outline' | 'ghost'`)
per DEMO_AUTHORING_GUIDE §12.7 so the trigger stays consistent with
the form-control surface (Field/Select/Combobox) instead of inheriting
Button's wider 6-variant set. The eidos demo exposes variant/size/intent
chips that match the canonical narrowed vocab (Intent: neutral · affirm
· fulfill · risk · threat · loss). Trigger's per-recipe CSS dropped —
chrome comes from button.css.
3. **Menu-item unchecked indicators** (follow-up to #118). CheckboxItem
and RadioItem now paint an empty outlined box / circle even when
unchecked, so the user can tell at a glance which rows are checkable.
Checked state fills with the accent color via the same `::before`. The
reserved padding slot (26px) keeps row text from shifting when state
flips.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
// Eidos · Trigger visual props (forwarded to < Button > under the hood).
// `variant` narrows ButtonVariant → ControlVariant (3) to stay
// consistent with the rest of the form-control surface.
let triggerVariant = $state< 'surface' | 'outline' | 'ghost'>('surface');
let triggerSize = $state< 'xs' | 'sm' | 'md' | 'lg' | 'xl'>('md');
let triggerIntent = $state< 'neutral' | 'affirm' | 'fulfill' | 'risk' | 'threat' | 'loss'>(
'neutral'
);
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
// Composition
let showGroupHeading = $state(true);
let showSeparators = $state(true);
let showCheckboxItem = $state(true);
let showCheckboxGroup = $state(true);
let showRadioGroup = $state(true);
let showSub = $state(true);
let showArrow = $state(false);
// Demo content
let triggerLabel = $state('Open menu');
let subTriggerLabel = $state('More options');
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
function pickItem(label: string) {
return () => {
lastSelected = label;
};
}
type TraceEntry = { event : string ; family : string ; intent? : string ; at : number } ;
let trace = $state< TraceEntry [ ] > ([]);
let stageRef = $state< HTMLElement | null > (null);
$effect(() => {
const el = stageRef;
if (!el) return;
const obs = new MutationObserver((mutations) => {
for (const m of mutations) {
if (m.attributeName !== 'data-event') continue;
const target = m.target as Element;
const ev = target.getAttribute('data-event');
if (!ev) continue;
trace = [
{
event: ev,
family: target.getAttribute('data-event-family') ?? '—',
intent: target.getAttribute('data-event-intent') ?? undefined,
at: Date.now()
},
...trace
].slice(0, 6);
}
});
obs.observe(el, { attributes : true , subtree : true , attributeFilter : [ 'data-event' ] } );
return () => obs.disconnect();
});
const compiled = compileMorfo(dropdownMenuMorfo);
const partsList = $derived([...compiled.parts.byKebab.values()]);
const events = $derived([...compiled.actions.byName.values()]);
function fmtTime(at: number): string {
const d = new Date(at);
return `${ String ( d . getSeconds ()). padStart ( 2 , '0' )} .${ String ( d . getMilliseconds ()). padStart ( 3 , '0' )} `;
}
const somaSnippet = $derived(
[
"< script lang = 'ts' > " ,
" import * as DropdownMenu from '$soma/components/dropdown-menu';",
' let open = $state(false);',
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
' let notifications = $state(true);',
' let theme = $state("system");',
' let viewLayers = $state(["ruler"]);',
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>',
'',
'< DropdownMenu.Provider ' ,
' bind:open',
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
dir !== 'ltr' && ` dir="${ dir } "`,
!accessibleWhenDisabled && ' accessibleWhenDisabled={ 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
'>',
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
` < DropdownMenu.Trigger > ${ triggerLabel } </ DropdownMenu.Trigger > `,
' < DropdownMenu.Content ' ,
side !== 'bottom' && ` side="${ side } "`,
sideOffset !== 0 && ` sideOffset={ $ { sideOffset }} `,
align !== 'start' && ` align="${ align } "`,
alignOffset !== 0 && ` alignOffset={ $ { alignOffset }} `,
!avoidCollisions && ' avoidCollisions={ false } ',
loop & & ' loop',
!trapFocus && ' trapFocus={ false } ',
!preventScroll && ' preventScroll={ false } ',
' >',
showGroupHeading & & ' < DropdownMenu.Group > ',
showGroupHeading & & ' < DropdownMenu.GroupHeading > Account< / DropdownMenu.GroupHeading > ',
showGroupHeading && ' < DropdownMenu.Item onSelect = { … } > Profile</DropdownMenu.Item > ',
showGroupHeading && ' < DropdownMenu.Item onSelect = { … } > Settings</DropdownMenu.Item > ',
showGroupHeading & & ' < / DropdownMenu.Group > ',
!showGroupHeading && ' < DropdownMenu.Item onSelect = { … } > Profile</DropdownMenu.Item > ',
!showGroupHeading && ' < DropdownMenu.Item onSelect = { … } > Settings</DropdownMenu.Item > ',
showSeparators & & ' < DropdownMenu.Separator / > ',
showCheckboxItem && ' < DropdownMenu.CheckboxItem bind:checked = { notifications } > Notifications</DropdownMenu.CheckboxItem > ',
showSeparators & & showCheckboxItem & & ' < DropdownMenu.Separator / > ',
showCheckboxGroup && ' < DropdownMenu.CheckboxGroup bind:value = { viewLayers } > ',
showCheckboxGroup & & showGroupHeading & & ' < DropdownMenu.GroupHeading > View< / DropdownMenu.GroupHeading > ',
showCheckboxGroup & & ' < DropdownMenu.CheckboxItem value = "ruler" > Ruler< / DropdownMenu.CheckboxItem > ',
showCheckboxGroup & & ' < DropdownMenu.CheckboxItem value = "grid" > Grid< / DropdownMenu.CheckboxItem > ',
showCheckboxGroup & & ' < DropdownMenu.CheckboxItem value = "guides" > Guides< / DropdownMenu.CheckboxItem > ',
showCheckboxGroup & & ' < / DropdownMenu.CheckboxGroup > ',
showSeparators & & showCheckboxGroup & & ' < DropdownMenu.Separator / > ',
showRadioGroup && ' < DropdownMenu.RadioGroup bind:value = { theme } > ',
showRadioGroup & & showGroupHeading & & ' < DropdownMenu.GroupHeading > Theme< / DropdownMenu.GroupHeading > ',
showRadioGroup & & ' < DropdownMenu.RadioItem value = "light" > Light< / DropdownMenu.RadioItem > ',
showRadioGroup & & ' < DropdownMenu.RadioItem value = "dark" > Dark< / DropdownMenu.RadioItem > ',
showRadioGroup & & ' < DropdownMenu.RadioItem value = "system" > System< / DropdownMenu.RadioItem > ',
showRadioGroup & & ' < / DropdownMenu.RadioGroup > ',
showSeparators & & showRadioGroup & & ' < DropdownMenu.Separator / > ',
showSub & & ' < DropdownMenu.Sub > ',
showSub && ` < DropdownMenu.SubTrigger > ${ subTriggerLabel } </ DropdownMenu.SubTrigger > `,
showSub & & ' < DropdownMenu.SubContent > ',
showSub && ' < DropdownMenu.Item onSelect = { … } > Export…</DropdownMenu.Item > ',
showSub && ' < DropdownMenu.Item onSelect = { … } > Import…</DropdownMenu.Item > ',
showSub & & ' < DropdownMenu.Item disabled > Sync (offline)< / DropdownMenu.Item > ',
showSub & & ' < / DropdownMenu.SubContent > ',
showSub & & ' < / DropdownMenu.Sub > ',
showSeparators & & ' < DropdownMenu.Separator / > ',
` < DropdownMenu.Item $ { disableLogout ? ' disabled' : '' } $ { ! closeOnSelect ? ' closeOnSelect = { false } ' : ' ' } onSelect = { … } > Log out </ DropdownMenu . Item > `,
showArrow & & ' < DropdownMenu.Arrow / > ',
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
' < / DropdownMenu.Content > ',
'< / DropdownMenu.Provider > '
]
.filter(Boolean)
.join('\n')
);
const eidosSnippet = $derived(
[
"< script lang = 'ts' > " ,
" import { DropdownMenu } from '$uix/eidos/components/dropdown-menu';",
' let open = $state(false);',
'< /' + 'script>',
'',
'< DropdownMenu ' ,
' bind:open',
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
dir !== 'ltr' && ` dir="${ dir } "`,
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
'>',
refactor(dropdown-menu): remove unused modal; Trigger→Button; canon vocab fixes
Three related fixes touching the menu surface:
1. **Remove `modal` from DropdownMenu** (#127). The prop was declared in
soma but never wired to anything — no overlay, no pointer-events
blocker, no scrim. ark-ui / Headless-UI / Chakra all treat menu as
non-modal by convention; Dialog/Drawer/AlertDialog cover blocking
semantics. Drop it from soma (types, provider opts, component, test
fixture), the eidos doc comment, the menubar consumer, and the
dropdown-menu demo (state, control, snippet, API table, parity table).
2. **DropdownMenu.Trigger now renders `<Button>` internally** (#120
first consumer). Default variant='surface', size='md', intent='neutral'.
`variant` is narrowed to ControlVariant (`'surface' | 'outline' | 'ghost'`)
per DEMO_AUTHORING_GUIDE §12.7 so the trigger stays consistent with
the form-control surface (Field/Select/Combobox) instead of inheriting
Button's wider 6-variant set. The eidos demo exposes variant/size/intent
chips that match the canonical narrowed vocab (Intent: neutral · affirm
· fulfill · risk · threat · loss). Trigger's per-recipe CSS dropped —
chrome comes from button.css.
3. **Menu-item unchecked indicators** (follow-up to #118). CheckboxItem
and RadioItem now paint an empty outlined box / circle even when
unchecked, so the user can tell at a glance which rows are checkable.
Checked state fills with the accent color via the same `::before`. The
reserved padding slot (26px) keeps row text from shifting when state
flips.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
` < DropdownMenu.Trigger $ { triggerVariant !== 'surface' ? ` variant="$ { triggerVariant } "` : ''}${triggerSize !== 'md' ? ` size=" $ { triggerSize } "` : ''}${triggerIntent !== 'neutral' ? ` intent=" $ { triggerIntent } " ` : '' } > ${ triggerLabel } </ DropdownMenu.Trigger > `,
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
` < DropdownMenu.Content $ { side !== 'bottom' ? ` side="$ { side } "` : ''}${align !== 'start' ? ` align=" $ { align } " ` : '' } > `,
showGroupHeading & & ' < DropdownMenu.Group > ',
showGroupHeading & & ' < DropdownMenu.GroupHeading > Account< / DropdownMenu.GroupHeading > ',
showGroupHeading && ' < DropdownMenu.Item onSelect = { … } > Profile</DropdownMenu.Item > ',
showGroupHeading && ' < DropdownMenu.Item onSelect = { … } > Settings</DropdownMenu.Item > ',
showGroupHeading & & ' < / DropdownMenu.Group > ',
!showGroupHeading && ' < DropdownMenu.Item onSelect = { … } > Profile</DropdownMenu.Item > ',
showSeparators & & ' < DropdownMenu.Separator / > ',
showCheckboxItem && ' < DropdownMenu.CheckboxItem bind:checked = { notifications } > Notifications</DropdownMenu.CheckboxItem > ',
showCheckboxGroup && ' < DropdownMenu.CheckboxGroup bind:value = { viewLayers } > ',
showCheckboxGroup & & ' < DropdownMenu.CheckboxItem value = "ruler" > Ruler< / DropdownMenu.CheckboxItem > ',
showCheckboxGroup & & ' < DropdownMenu.CheckboxItem value = "grid" > Grid< / DropdownMenu.CheckboxItem > ',
showCheckboxGroup & & ' < / DropdownMenu.CheckboxGroup > ',
showRadioGroup && ' < DropdownMenu.RadioGroup bind:value = { theme } > ',
showRadioGroup & & ' < DropdownMenu.RadioItem value = "light" > Light< / DropdownMenu.RadioItem > ',
showRadioGroup & & ' < DropdownMenu.RadioItem value = "dark" > Dark< / DropdownMenu.RadioItem > ',
showRadioGroup & & ' < / DropdownMenu.RadioGroup > ',
showSub & & ' < DropdownMenu.Sub > ',
showSub && ` < DropdownMenu.SubTrigger > ${ subTriggerLabel } </ DropdownMenu.SubTrigger > `,
showSub & & ' < DropdownMenu.SubContent > ',
showSub & & ' < DropdownMenu.Item > Export…< / DropdownMenu.Item > ',
showSub & & ' < / DropdownMenu.SubContent > ',
showSub & & ' < / DropdownMenu.Sub > ',
showSeparators & & ' < DropdownMenu.Separator / > ',
` < DropdownMenu.Item $ { disableLogout ? ' disabled' : '' } onSelect = { … } > Log out </ DropdownMenu . Item > `,
showArrow & & ' < DropdownMenu.Arrow / > ',
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
' < / DropdownMenu.Content > ',
'< / DropdownMenu > '
]
.filter(Boolean)
.join('\n')
);
< / script >
< div data-uix-canvas-inner >
< header >
< div data-uix-eyebrow > Overlay · DropdownMenu< / div >
< h1 data-uix-page-title > DropdownMenu< / h1 >
< p data-uix-page-lede >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
Button-anchored menu — compound API parity with Radix DropdownMenu and
bits-ui. 14 morfo parts + an eidos-only < code > CheckboxGroup< / code >
wrapper for Bits-UI-style array binding (15 importable components).
Includes Items, standalone or grouped Checkbox items, RadioGroup /
RadioItem, Group / GroupHeading, Separator, nested Sub / SubTrigger /
SubContent, and an optional Arrow. 3 semantic events.
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
< span data-uix-layer-badge = "soma" > soma< / span > owns positioning,
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
keyboard navigation, focus trap and dismissal;
< span data-uix-layer-badge = "eidos" > eidos< / span > paints uniform panel
chrome across levels.
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
< / p >
< div data-uix-page-meta >
< span data-uix-meta-pill >
< span data-uix-meta-key > parts</ span > { compiled . parts . order . length }
< / span >
< span data-uix-meta-pill >
< span data-uix-meta-key > events</ span > { events . length }
< / span >
< span data-uix-meta-pill >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< span data-uix-meta-key > apg< / span >
< a href = { dropdownMenuMorfo . apg } target="_blank" rel = "noreferrer" > menu-button ↗</ a >
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
< / span >
{ #if lastSelected }
< span data-uix-meta-pill >
< span data-uix-meta-key > last</ span > { lastSelected }
< / span >
{ /if }
< / div >
< / header >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
<!-- Live preview always rendered -->
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
< div data-uix-stage >
< div data-uix-stage-area bind:this = { stageRef } >
refactor(dropdown-menu): remove unused modal; Trigger→Button; canon vocab fixes
Three related fixes touching the menu surface:
1. **Remove `modal` from DropdownMenu** (#127). The prop was declared in
soma but never wired to anything — no overlay, no pointer-events
blocker, no scrim. ark-ui / Headless-UI / Chakra all treat menu as
non-modal by convention; Dialog/Drawer/AlertDialog cover blocking
semantics. Drop it from soma (types, provider opts, component, test
fixture), the eidos doc comment, the menubar consumer, and the
dropdown-menu demo (state, control, snippet, API table, parity table).
2. **DropdownMenu.Trigger now renders `<Button>` internally** (#120
first consumer). Default variant='surface', size='md', intent='neutral'.
`variant` is narrowed to ControlVariant (`'surface' | 'outline' | 'ghost'`)
per DEMO_AUTHORING_GUIDE §12.7 so the trigger stays consistent with
the form-control surface (Field/Select/Combobox) instead of inheriting
Button's wider 6-variant set. The eidos demo exposes variant/size/intent
chips that match the canonical narrowed vocab (Intent: neutral · affirm
· fulfill · risk · threat · loss). Trigger's per-recipe CSS dropped —
chrome comes from button.css.
3. **Menu-item unchecked indicators** (follow-up to #118). CheckboxItem
and RadioItem now paint an empty outlined box / circle even when
unchecked, so the user can tell at a glance which rows are checkable.
Checked state fills with the accent color via the same `::before`. The
reserved padding slot (26px) keeps row text from shifting when state
flips.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< DropdownMenu bind:open { dir } { accessibleWhenDisabled } >
< DropdownMenu.Trigger
variant={ triggerVariant }
size={ triggerSize }
intent={ triggerIntent }
>
{ triggerLabel }
< / DropdownMenu.Trigger >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< DropdownMenu.Content
{ side }
{ sideOffset }
{ align }
{ alignOffset }
{ avoidCollisions }
{ loop }
{ trapFocus }
{ preventScroll }
>
{ #if showGroupHeading }
< DropdownMenu.Group >
< DropdownMenu.GroupHeading > Account< / DropdownMenu.GroupHeading >
< DropdownMenu.Item onSelect = { pickItem ( 'Profile' )} > Profile</DropdownMenu.Item >
< DropdownMenu.Item onSelect = { pickItem ( 'Settings' )} > Settings</DropdownMenu.Item >
< / DropdownMenu.Group >
{ : else }
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
< DropdownMenu.Item onSelect = { pickItem ( 'Profile' )} > Profile</DropdownMenu.Item >
< DropdownMenu.Item onSelect = { pickItem ( 'Settings' )} > Settings</DropdownMenu.Item >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
{ /if }
{ #if showSeparators } < DropdownMenu.Separator /> { /if }
{ #if showCheckboxItem }
< DropdownMenu.CheckboxItem bind:checked = { notifications } >
Show notifications
< / DropdownMenu.CheckboxItem >
{ /if }
{ #if showCheckboxGroup }
< DropdownMenu.CheckboxGroup bind:value = { viewLayers } >
{ #if showGroupHeading } < DropdownMenu.GroupHeading > View</ DropdownMenu.GroupHeading > { /if }
< DropdownMenu.CheckboxItem value = "ruler" > Ruler< / DropdownMenu.CheckboxItem >
< DropdownMenu.CheckboxItem value = "grid" > Grid< / DropdownMenu.CheckboxItem >
< DropdownMenu.CheckboxItem value = "guides" > Guides< / DropdownMenu.CheckboxItem >
< / DropdownMenu.CheckboxGroup >
{ /if }
{ #if showSeparators } < DropdownMenu.Separator /> { /if }
{ #if showRadioGroup }
< DropdownMenu.RadioGroup bind:value = { theme } >
{ #if showGroupHeading } < DropdownMenu.GroupHeading > Theme</ DropdownMenu.GroupHeading > { /if }
< DropdownMenu.RadioItem value = "light" > Light< / DropdownMenu.RadioItem >
< DropdownMenu.RadioItem value = "dark" > Dark< / DropdownMenu.RadioItem >
< DropdownMenu.RadioItem value = "system" > System< / DropdownMenu.RadioItem >
< / DropdownMenu.RadioGroup >
{ /if }
{ #if showSeparators } < DropdownMenu.Separator /> { /if }
{ #if showSub }
< DropdownMenu.Sub >
< DropdownMenu.SubTrigger > { subTriggerLabel } </ DropdownMenu.SubTrigger >
< DropdownMenu.SubContent >
< DropdownMenu.Item onSelect = { pickItem ( 'Export…' )} > Export…</DropdownMenu.Item >
< DropdownMenu.Item onSelect = { pickItem ( 'Import…' )} > Import…</DropdownMenu.Item >
< DropdownMenu.Item disabled > Sync (offline)< / DropdownMenu.Item >
< / DropdownMenu.SubContent >
< / DropdownMenu.Sub >
{ /if }
{ #if showSeparators } < DropdownMenu.Separator /> { /if }
< DropdownMenu.Item
disabled={ disableLogout }
{ closeOnSelect }
onSelect={ pickItem ( 'Log out' )}
>
Log out
< / DropdownMenu.Item >
{ #if showArrow } < DropdownMenu.Arrow /> { /if }
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
< / DropdownMenu.Content >
< / DropdownMenu >
< / div >
< div data-uix-stage-trace >
< span data-uix-stage-trace-key > trace< / span >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
{ #if trace . length === 0 }
< span > click the trigger to summon the menu< / span >
{ : else }
fix(demos): eliminate each_key_duplicate crash in 22 component demos
The event-trace inspector in each demo keyed its `{#each}` by a
`Date.now()` timestamp (`entry.at` / `h.at`). A single interaction can
stamp `data-event` on several elements within the same millisecond, so
two trace entries share the key and Svelte throws `each_key_duplicate`
(reported on dropdown-menu).
The trace is an ephemeral, 3-item, text-only log with no transitions or
stateful children, so positional reconciliation is correct: drop the
timestamp key (the each becomes unkeyed). The `fmtTime(...at)` display is
left intact.
Swept all 22 demos carrying the pattern (21 keyed by `entry.at` + announce
by `h.at`): dropdown-menu, context-menu, menubar, navigation-menu, listbox,
grid-list, table, tree-view, tree-grid, feed, command, carousel, drag-drop,
clipboard, announce, alert-dialog, button, color-field, link-preview,
range-calendar, time-field, time-range-field.
Verified: `as \w+ (\w+.at)` -> 0 occurrences site-wide; `npm run check`
0 errors; browser repro on dropdown-menu + table (burst of events, no
each_key_duplicate, console clean).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4 months ago
{ #each trace . slice ( 0 , 3 ) as entry }
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< span >< span data-uix-stage-trace-event > { entry . event } </ span > · { entry . family }{ entry . intent ? ' · ' + entry . intent : '' } </ span >
< span style = "color: var(--uix-text-faint)" > { fmtTime ( entry . at )} </ span >
{ /each }
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
{ /if }
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< span style = "margin-inline-start: auto;" >
< span data-uix-stage-trace-key > open</ span > { String ( open )}
{ #if lastSelected }
< span data-uix-stage-trace-key style = "margin-inline-start: 0.5rem;" > last</ span > { lastSelected }
{ /if }
< / span >
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
< / div >
< / div >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
<!-- Tabs -->
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
< div data-uix-tabs role = "tablist" >
< button data-uix-tab data-active = { tab === 'live' } onclick= {() => ( tab = 'live' )} > Live</ button >
< button data-uix-tab data-active = { tab === 'api' } onclick= {() => ( tab = 'api' )} >
API < span data-uix-tab-count > 15< / span >
< / button >
< button data-uix-tab data-active = { tab === 'morfo' } onclick= {() => ( tab = 'morfo' )} >
< span data-uix-layer-badge = "morfo" > morfo< / span >
< span data-uix-tab-count > { partsList . length } p · { events . length } e</ span >
< / button >
< button data-uix-tab data-active = { tab === 'sema' } onclick= {() => ( tab = 'sema' )} >
< span data-uix-layer-badge = "sema" > sema< / span >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< span data-uix-tab-count > { events . length } </ span >
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
< / button >
< button data-uix-tab data-active = { tab === 'recipe' } onclick= {() => ( tab = 'recipe' )} > Recipe</ button >
< button data-uix-tab data-active = { tab === 'a11y' } onclick= {() => ( tab = 'a11y' )} > A11y</ button >
< / div >
{ #if tab === 'live' }
< section data-uix-section >
< h2 data-uix-section-title > Controls< / h2 >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< p data-uix-section-desc >
DropdownMenu is a pure pass-through over < span data-uix-layer-badge = "soma" > soma< / span > ;
the eidos layer adds no evaluative props. Knobs are grouped by the
layer that owns the prop, with a < em > composition< / em > group for
parts toggled in / out of the markup (per the
composition-over-visibility norm). Semantic events live in the < a href = "#sema" onclick = {( e ) => { e . preventDefault (); tab = 'sema' ; }} > Sema</a > tab.
< / p >
<!-- ── Soma · Provider ─────────────────────────────────────────── -->
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
< div data-uix-subsection-head >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< span data-uix-layer-badge = "soma" > soma< / span > Provider props
< / div >
< div data-uix-controls >
< label data-uix-control >
< span data-uix-control-label > open < span data-uix-control-hint > bindable< / span > < / span >
< span data-uix-switch >
< input type = "checkbox" bind:checked = { open } / >
< span data-uix-switch-label > { open ? 'open' : 'closed' } </ span >
< / span >
< / label >
< label data-uix-control >
< span data-uix-control-label > accessibleWhenDisabled< / span >
< span data-uix-switch >
< input type = "checkbox" bind:checked = { accessibleWhenDisabled } / >
< span data-uix-switch-label > { accessibleWhenDisabled ? 'on' : 'off' } </ span >
< / span >
< / label >
< label data-uix-control >
< span data-uix-control-label > dir< / span >
< span data-uix-chips role = "radiogroup" >
{ #each [ 'ltr' , 'rtl' ] as d ( d )}
< button data-uix-chip data-active = { dir === d } onclick= {() => ( dir = d as 'ltr' | 'rtl' )} > { d } </ button >
{ /each }
< / span >
< / label >
< / div >
<!-- ── Soma · Content (floating layer) ─────────────────────────── -->
< div data-uix-subsection-head >
< span data-uix-layer-badge = "soma" > soma< / span > Content props
< span style = "font-weight: normal; color: var(--uix-text-muted);" >
· floating layer · positioning + focus mgmt
< / span >
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
< / div >
< div data-uix-controls >
< label data-uix-control >
< span data-uix-control-label > side< / span >
< span data-uix-chips role = "radiogroup" >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
{ #each [ 'top' , 'right' , 'bottom' , 'left' ] as s ( s )}
< button data-uix-chip data-active = { side === s } onclick= {() => ( side = s as typeof side )} > { s } </ button >
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
{ /each }
< / span >
< / label >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< label data-uix-control >
< span data-uix-control-label > sideOffset < span data-uix-control-hint > { sideOffset } px</ span ></ span >
< input type = "range" min = "0" max = "24" step = "1" bind:value = { sideOffset } / >
< / label >
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
< label data-uix-control >
< span data-uix-control-label > align< / span >
< span data-uix-chips role = "radiogroup" >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
{ #each [ 'start' , 'center' , 'end' ] as a ( a )}
< button data-uix-chip data-active = { align === a } onclick= {() => ( align = a as typeof align )} > { a } </ button >
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
{ /each }
< / span >
< / label >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< label data-uix-control >
< span data-uix-control-label > alignOffset < span data-uix-control-hint > { alignOffset } px</ span ></ span >
< input type = "range" min = "-24" max = "24" step = "1" bind:value = { alignOffset } / >
< / label >
< label data-uix-control >
< span data-uix-control-label > avoidCollisions< / span >
< span data-uix-switch >
< input type = "checkbox" bind:checked = { avoidCollisions } / >
< span data-uix-switch-label > { avoidCollisions ? 'on' : 'off' } </ span >
< / span >
< / label >
< label data-uix-control >
< span data-uix-control-label > loop< / span >
< span data-uix-switch >
< input type = "checkbox" bind:checked = { loop } / >
< span data-uix-switch-label > { loop ? 'on' : 'off' } </ span >
< / span >
< / label >
< label data-uix-control >
< span data-uix-control-label > trapFocus< / span >
< span data-uix-switch >
< input type = "checkbox" bind:checked = { trapFocus } / >
< span data-uix-switch-label > { trapFocus ? 'on' : 'off' } </ span >
< / span >
< / label >
< label data-uix-control >
< span data-uix-control-label > preventScroll< / span >
< span data-uix-switch >
< input type = "checkbox" bind:checked = { preventScroll } / >
< span data-uix-switch-label > { preventScroll ? 'on' : 'off' } </ span >
< / span >
< / label >
< / div >
<!-- ── Soma · Item - level ───────────────────────────────────────── -->
< div data-uix-subsection-head >
< span data-uix-layer-badge = "soma" > soma< / span > Item props
< span style = "font-weight: normal; color: var(--uix-text-muted);" >
· applied to the Log out item below
< / span >
< / div >
< div data-uix-controls >
< label data-uix-control >
< span data-uix-control-label > disabled< / span >
< span data-uix-switch >
< input type = "checkbox" bind:checked = { disableLogout } / >
< span data-uix-switch-label > { disableLogout ? 'on' : 'off' } </ span >
< / span >
< / label >
< label data-uix-control >
< span data-uix-control-label > closeOnSelect< / span >
< span data-uix-switch >
< input type = "checkbox" bind:checked = { closeOnSelect } / >
< span data-uix-switch-label > { closeOnSelect ? 'on' : 'off' } </ span >
< / span >
< / label >
< / div >
<!-- ── Composition ─────────────────────────────────────────────── -->
< div data-uix-subsection-head >
Composition
< span style = "font-weight: normal; color: var(--uix-text-muted);" >
· toggle parts in / out of the markup
< / span >
< / div >
< div data-uix-controls >
< label data-uix-control >
< span data-uix-control-label > Group + GroupHeading< / span >
< span data-uix-switch >
< input type = "checkbox" bind:checked = { showGroupHeading } / >
< span data-uix-switch-label > { showGroupHeading ? 'on' : 'off' } </ span >
< / span >
< / label >
< label data-uix-control >
< span data-uix-control-label > Separators< / span >
< span data-uix-switch >
< input type = "checkbox" bind:checked = { showSeparators } / >
< span data-uix-switch-label > { showSeparators ? 'on' : 'off' } </ span >
< / span >
< / label >
< label data-uix-control >
< span data-uix-control-label > CheckboxItem < span data-uix-control-hint > standalone bind:checked< / span > < / span >
< span data-uix-switch >
< input type = "checkbox" bind:checked = { showCheckboxItem } / >
< span data-uix-switch-label > { showCheckboxItem ? 'on' : 'off' } </ span >
< / span >
< / label >
< label data-uix-control >
< span data-uix-control-label > CheckboxGroup < span data-uix-control-hint > array binding< / span > < / span >
< span data-uix-switch >
< input type = "checkbox" bind:checked = { showCheckboxGroup } / >
< span data-uix-switch-label > { showCheckboxGroup ? 'on' : 'off' } </ span >
< / span >
< / label >
< label data-uix-control >
< span data-uix-control-label > RadioGroup< / span >
< span data-uix-switch >
< input type = "checkbox" bind:checked = { showRadioGroup } / >
< span data-uix-switch-label > { showRadioGroup ? 'on' : 'off' } </ span >
< / span >
< / label >
< label data-uix-control >
< span data-uix-control-label > Sub menu< / span >
< span data-uix-switch >
< input type = "checkbox" bind:checked = { showSub } / >
< span data-uix-switch-label > { showSub ? 'on' : 'off' } </ span >
< / span >
< / label >
< label data-uix-control >
< span data-uix-control-label > Arrow< / span >
< span data-uix-switch >
< input type = "checkbox" bind:checked = { showArrow } / >
< span data-uix-switch-label > { showArrow ? 'on' : 'off' } </ span >
< / span >
< / label >
< / div >
refactor(dropdown-menu): remove unused modal; Trigger→Button; canon vocab fixes
Three related fixes touching the menu surface:
1. **Remove `modal` from DropdownMenu** (#127). The prop was declared in
soma but never wired to anything — no overlay, no pointer-events
blocker, no scrim. ark-ui / Headless-UI / Chakra all treat menu as
non-modal by convention; Dialog/Drawer/AlertDialog cover blocking
semantics. Drop it from soma (types, provider opts, component, test
fixture), the eidos doc comment, the menubar consumer, and the
dropdown-menu demo (state, control, snippet, API table, parity table).
2. **DropdownMenu.Trigger now renders `<Button>` internally** (#120
first consumer). Default variant='surface', size='md', intent='neutral'.
`variant` is narrowed to ControlVariant (`'surface' | 'outline' | 'ghost'`)
per DEMO_AUTHORING_GUIDE §12.7 so the trigger stays consistent with
the form-control surface (Field/Select/Combobox) instead of inheriting
Button's wider 6-variant set. The eidos demo exposes variant/size/intent
chips that match the canonical narrowed vocab (Intent: neutral · affirm
· fulfill · risk · threat · loss). Trigger's per-recipe CSS dropped —
chrome comes from button.css.
3. **Menu-item unchecked indicators** (follow-up to #118). CheckboxItem
and RadioItem now paint an empty outlined box / circle even when
unchecked, so the user can tell at a glance which rows are checkable.
Checked state fills with the accent color via the same `::before`. The
reserved padding slot (26px) keeps row text from shifting when state
flips.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
<!-- ── Eidos · Trigger (visual chrome forwarded to <Button>) ─── -->
< div data-uix-subsection-head >
< span data-uix-layer-badge = "eidos" > eidos< / span > Trigger
< span style = "font-weight: normal; color: var(--uix-text-muted);" >
· visual props forwarded to the underlying < Button>
< / span >
< / div >
< div data-uix-controls >
< label data-uix-control >
< span data-uix-control-label > variant< / span >
< span data-uix-chips role = "radiogroup" >
{ #each [ 'surface' , 'outline' , 'ghost' ] as v ( v )}
< button
data-uix-chip
data-active={ triggerVariant === v }
onclick={() => ( triggerVariant = v as typeof triggerVariant )}
>
{ v }
< / button >
{ /each }
< / span >
< / label >
< label data-uix-control >
< span data-uix-control-label > size< / span >
< span data-uix-chips role = "radiogroup" >
{ #each [ 'xs' , 'sm' , 'md' , 'lg' , 'xl' ] as s ( s )}
< button
data-uix-chip
data-active={ triggerSize === s }
onclick={() => ( triggerSize = s as typeof triggerSize )}
>
{ s }
< / button >
{ /each }
< / span >
< / label >
< label data-uix-control >
< span data-uix-control-label > intent< / span >
< span data-uix-chips role = "radiogroup" >
{ #each [ 'neutral' , 'affirm' , 'fulfill' , 'risk' , 'threat' , 'loss' ] as i ( i )}
< button
data-uix-chip
data-active={ triggerIntent === i }
onclick={() => ( triggerIntent = i as typeof triggerIntent )}
>
{ i }
< / button >
{ /each }
< / span >
< / label >
< / div >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
<!-- ── Bound state (mirrors) ───────────────────────────────────── -->
< div data-uix-subsection-head >
Bound state
< span style = "font-weight: normal; color: var(--uix-text-muted);" >
· `bind:checked` / `bind:value` mirrors from the live menu items
< / span >
< / div >
< div data-uix-controls >
< label data-uix-control >
< span data-uix-control-label > notifications < span data-uix-control-hint > CheckboxItem< / span > < / span >
< span data-uix-switch >
< input type = "checkbox" bind:checked = { notifications } / >
< span data-uix-switch-label > { notifications ? 'on' : 'off' } </ span >
< / span >
< / label >
< label data-uix-control >
< span data-uix-control-label > viewLayers < span data-uix-control-hint > CheckboxGroup array< / span > < / span >
< input type = "text" value = { viewLayers . join ( ', ' ) || '(empty)' } readonly />
< / label >
< label data-uix-control >
< span data-uix-control-label > theme < span data-uix-control-hint > RadioGroup< / span > < / span >
< span data-uix-chips role = "radiogroup" >
{ #each [ 'light' , 'dark' , 'system' ] as t ( t )}
< button data-uix-chip data-active = { theme === t } onclick= {() => ( theme = t as typeof theme )} > { t } </ button >
{ /each }
< / span >
< / label >
< / div >
<!-- ── Demo content (literal text) ─────────────────────────────── -->
< div data-uix-subsection-head >
Demo content
< span style = "font-weight: normal; color: var(--uix-text-muted);" >
· literal labels rendered into the menu
< / span >
< / div >
< div data-uix-controls >
< label data-uix-control >
< span data-uix-control-label > Trigger label< / span >
< input type = "text" bind:value = { triggerLabel } / >
< / label >
< label data-uix-control >
< span data-uix-control-label > SubTrigger label< / span >
< input type = "text" bind:value = { subTriggerLabel } disabled= { ! showSub } />
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
< / label >
< / div >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
<!-- ── Code snippets per layer ─────────────────────────────────── -->
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
< div data-uix-code >
< div data-uix-code-head >
< span data-uix-layer-badge = "soma" > soma< / span >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< span > headless · positioning + keyboard + dismissal< / span >
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
< span data-uix-code-lang > svelte< / span >
< / div >
< pre >< code > { somaSnippet } </ code ></ pre >
< / div >
< div data-uix-code style = "margin-top: var(--uix-space-3);" >
< div data-uix-code-head >
< span data-uix-layer-badge = "eidos" > eidos< / span >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< span > visual · namespaced compound (pure pass-through; no extra props)< / span >
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
< span data-uix-code-lang > svelte< / span >
< / div >
< pre >< code > { eidosSnippet } </ code ></ pre >
< / div >
< / section >
{ /if }
{ #if tab === 'api' }
< section data-uix-section >
< h2 data-uix-section-title > API reference< / h2 >
< p data-uix-section-desc >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
15 parts forwarded from soma. Item-family parts share
< code > id< / code > , < code > disabled< / code > , < code > textValue< / code > ,
< code > closeOnSelect< / code > . CheckboxGroup adds a Bits-UI-style
array binding (item is checked when its < code > value< / code > is in
the group's array).
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
< / p >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< div data-uix-subsection-head > DropdownMenu (Provider)< / div >
< div data-uix-table-wrap >
< table data-uix-table >
< thead > < tr > < th > Prop< / th > < th > Type< / th > < th > Default< / th > < th > Description< / th > < / tr > < / thead >
< tbody >
< tr > < td class = "name" > id< / td > < td class = "type" > string< / td > < td class = "default empty" > auto< / td > < td > Stable identifier.< / td > < / tr >
< tr > < td class = "name" > open < span data-uix-tag data-kind = "bindable" > bindable< / span > < / td > < td class = "type" > boolean< / td > < td class = "default" > false< / td > < td > Whether the menu is open.< / td > < / tr >
< tr > < td class = "name" > onOpenChange / onOpenChangeComplete< / td > < td class = "type" > (open: boolean) => void< / td > < td class = "default empty" > —< / td > < td > Fire on every open/close and after the animation settles.< / td > < / tr >
< tr > < td class = "name" > dir< / td > < td class = "type" > 'ltr' | 'rtl'< / td > < td class = "default" > 'ltr'< / td > < td > Direction used for keyboard navigation inside sub-menus.< / td > < / tr >
< tr > < td class = "name" > accessibleWhenDisabled< / td > < td class = "type" > boolean< / td > < td class = "default" > true< / td > < td > Disabled items remain focusable per WAI-ARIA APG; set false to skip them entirely.< / td > < / tr >
< / tbody >
< / table >
< / div >
< div data-uix-subsection-head > Trigger< / div >
< div data-uix-table-wrap >
< table data-uix-table >
< thead > < tr > < th > Prop< / th > < th > Type< / th > < th > Default< / th > < th > Description< / th > < / tr > < / thead >
< tbody >
< tr > < td class = "name" > id< / td > < td class = "type" > string< / td > < td class = "default empty" > auto< / td > < td > —< / td > < / tr >
refactor(dropdown-menu): remove unused modal; Trigger→Button; canon vocab fixes
Three related fixes touching the menu surface:
1. **Remove `modal` from DropdownMenu** (#127). The prop was declared in
soma but never wired to anything — no overlay, no pointer-events
blocker, no scrim. ark-ui / Headless-UI / Chakra all treat menu as
non-modal by convention; Dialog/Drawer/AlertDialog cover blocking
semantics. Drop it from soma (types, provider opts, component, test
fixture), the eidos doc comment, the menubar consumer, and the
dropdown-menu demo (state, control, snippet, API table, parity table).
2. **DropdownMenu.Trigger now renders `<Button>` internally** (#120
first consumer). Default variant='surface', size='md', intent='neutral'.
`variant` is narrowed to ControlVariant (`'surface' | 'outline' | 'ghost'`)
per DEMO_AUTHORING_GUIDE §12.7 so the trigger stays consistent with
the form-control surface (Field/Select/Combobox) instead of inheriting
Button's wider 6-variant set. The eidos demo exposes variant/size/intent
chips that match the canonical narrowed vocab (Intent: neutral · affirm
· fulfill · risk · threat · loss). Trigger's per-recipe CSS dropped —
chrome comes from button.css.
3. **Menu-item unchecked indicators** (follow-up to #118). CheckboxItem
and RadioItem now paint an empty outlined box / circle even when
unchecked, so the user can tell at a glance which rows are checkable.
Checked state fills with the accent color via the same `::before`. The
reserved padding slot (26px) keeps row text from shifting when state
flips.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< tr > < td class = "name" > variant < span data-uix-tag data-kind = "eidos" > eidos< / span > < / td > < td class = "type" > ControlVariant: 'surface' | 'outline' | 'ghost'< / td > < td class = "default" > 'surface'< / td > < td > Forwarded to the inner < code > < Button> < / code > . Narrowed from ButtonVariant (per DEMO_AUTHORING_GUIDE §12.7) to stay consistent with form-control surface.< / td > < / tr >
< tr > < td class = "name" > size < span data-uix-tag data-kind = "eidos" > eidos< / span > < / td > < td class = "type" > 'xs' | 'sm' | 'md' | 'lg' | 'xl'< / td > < td class = "default" > 'md'< / td > < td > Button size scale.< / td > < / tr >
< tr > < td class = "name" > intent < span data-uix-tag data-kind = "eidos" > eidos< / span > < / td > < td class = "type" > 'neutral' | 'affirm' | 'fulfill' | 'risk' | 'threat' | 'loss'< / td > < td class = "default" > 'neutral'< / td > < td > Evaluative intent forwarded to Button — full canonical Intent set.< / td > < / tr >
< tr > < td class = "name" > color < span data-uix-tag data-kind = "eidos" > eidos< / span > < / td > < td class = "type" > ColorRole — see eidos/lib/types.ts< / td > < td class = "default empty" > —< / td > < td > Hierarchical color override (only applies under < code > intent='neutral'< / code > ).< / td > < / tr >
< tr > < td class = "name" > iconOnly · icon · endIcon · rounded < span data-uix-tag data-kind = "eidos" > eidos< / span > < / td > < td class = "type" > Button props< / td > < td class = "default empty" > —< / td > < td > Standard Button visual knobs forwarded through.< / td > < / tr >
< tr >< td class = "name" > child</ td >< td class = "type" > { `Snippet<[{ props }]>` } </ td >< td class = "default empty" > —</ td >< td > Opt out of < code > < Button> </ code > entirely and render your own element.</ td ></ tr >
< tr > < td class = "name" > …native button attrs< / td > < td class = "type" > PrimitiveButtonAttributes< / td > < td class = "default empty" > —< / td > < td > All HTML button attrs flow through to the underlying button.< / td > < / tr >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< / tbody >
< / table >
< / div >
< div data-uix-subsection-head > Content< / div >
< div data-uix-table-wrap >
< table data-uix-table >
< thead > < tr > < th > Prop< / th > < th > Type< / th > < th > Default< / th > < th > Description< / th > < / tr > < / thead >
< tbody >
< tr > < td class = "name" > forceMount< / td > < td class = "type" > boolean< / td > < td class = "default" > false< / td > < td > Keep in DOM when closed.< / td > < / tr >
< tr > < td class = "name" > side< / td > < td class = "type" > 'top' | 'right' | 'bottom' | 'left'< / td > < td class = "default" > 'bottom'< / td > < td > Preferred side relative to the Trigger.< / td > < / tr >
< tr > < td class = "name" > sideOffset< / td > < td class = "type" > number< / td > < td class = "default" > 0< / td > < td > Main-axis gap (pixels).< / td > < / tr >
< tr > < td class = "name" > align< / td > < td class = "type" > 'start' | 'center' | 'end'< / td > < td class = "default" > 'start'< / td > < td > Cross-axis alignment.< / td > < / tr >
< tr > < td class = "name" > alignOffset< / td > < td class = "type" > number< / td > < td class = "default" > 0< / td > < td > Cross-axis gap.< / td > < / tr >
< tr > < td class = "name" > arrowPadding< / td > < td class = "type" > number< / td > < td class = "default" > 0< / td > < td > Margin between Arrow and panel corner.< / td > < / tr >
< tr > < td class = "name" > avoidCollisions< / td > < td class = "type" > boolean< / td > < td class = "default" > true< / td > < td > Flip / shift when clipped.< / td > < / tr >
< tr > < td class = "name" > collisionBoundary< / td > < td class = "type" > Element | Element[]< / td > < td class = "default empty" > viewport< / td > < td > Boundary the floating math respects.< / td > < / tr >
< tr > < td class = "name" > collisionPadding< / td > < td class = "type" > number | Partial< Record< Side, number> > < / td > < td class = "default" > 0< / td > < td > Inset from boundary edges.< / td > < / tr >
< tr > < td class = "name" > sticky< / td > < td class = "type" > 'partial' | 'always'< / td > < td class = "default" > 'partial'< / td > < td > Stickiness during anchor scroll.< / td > < / tr >
< tr > < td class = "name" > hideWhenDetached< / td > < td class = "type" > boolean< / td > < td class = "default" > true< / td > < td > Hide if anchor scrolls fully out of view.< / td > < / tr >
< tr > < td class = "name" > updatePositionStrategy< / td > < td class = "type" > 'optimized' | 'always'< / td > < td class = "default" > 'optimized'< / td > < td > Floating math cadence.< / td > < / tr >
< tr > < td class = "name" > strategy< / td > < td class = "type" > 'fixed' | 'absolute'< / td > < td class = "default" > 'fixed'< / td > < td > CSS positioning strategy.< / td > < / tr >
< tr > < td class = "name" > loop< / td > < td class = "type" > boolean< / td > < td class = "default" > false< / td > < td > Arrow keys wrap at boundaries.< / td > < / tr >
< tr > < td class = "name" > trapFocus< / td > < td class = "type" > boolean< / td > < td class = "default" > true< / td > < td > Tab cycles inside Content.< / td > < / tr >
< tr > < td class = "name" > preventScroll< / td > < td class = "type" > boolean< / td > < td class = "default" > true< / td > < td > Body scroll lock while open.< / td > < / tr >
< tr > < td class = "name" > escapeKeydownBehavior / interactOutsideBehavior< / td > < td class = "type" > DismissalBehavior< / td > < td class = "default" > 'close'< / td > < td > How Escape / outside-click interact with the dismissal layer.< / td > < / tr >
< tr > < td class = "name" > onOpenAutoFocus / onCloseAutoFocus< / td > < td class = "type" > (e: Event) => void< / td > < td class = "default empty" > —< / td > < td > Cancellable focus hooks.< / td > < / tr >
< tr > < td class = "name" > onEscapeKeydown / onInteractOutside / onFocusOutside< / td > < td class = "type" > handlers< / td > < td class = "default empty" > —< / td > < td > Cancellable dismissal events.< / td > < / tr >
< tr > < td class = "name" > dir< / td > < td class = "type" > 'ltr' | 'rtl'< / td > < td class = "default empty" > inherits< / td > < td > —< / td > < / tr >
< / tbody >
< / table >
< / div >
< div data-uix-subsection-head > Item · CheckboxItem · RadioItem · SubTrigger< / div >
< div data-uix-table-wrap >
< table data-uix-table >
< thead > < tr > < th > Prop< / th > < th > Type< / th > < th > Default< / th > < th > Applies to< / th > < th > Description< / th > < / tr > < / thead >
< tbody >
< tr > < td class = "name" > disabled< / td > < td class = "type" > boolean< / td > < td class = "default" > false< / td > < td > all< / td > < td > Skipped or just unactivatable per < code > accessibleWhenDisabled< / code > .< / td > < / tr >
< tr > < td class = "name" > textValue< / td > < td class = "type" > string< / td > < td class = "default empty" > —< / td > < td > all< / td > < td > Override for typeahead.< / td > < / tr >
< tr > < td class = "name" > onSelect< / td > < td class = "type" > () => void< / td > < td class = "default empty" > —< / td > < td > Item, CheckboxItem, RadioItem< / td > < td > Activation handler.< / td > < / tr >
< tr > < td class = "name" > closeOnSelect< / td > < td class = "type" > boolean< / td > < td class = "default" > true< / td > < td > Item, CheckboxItem, RadioItem< / td > < td > Close the menu after activation.< / td > < / tr >
< tr > < td class = "name" > checked < span data-uix-tag data-kind = "bindable" > bindable< / span > < / td > < td class = "type" > boolean< / td > < td class = "default" > false< / td > < td > CheckboxItem (standalone)< / td > < td > Whether the checkbox is checked.< / td > < / tr >
< tr > < td class = "name" > value< / td > < td class = "type" > string< / td > < td class = "default empty" > —< / td > < td > CheckboxItem (in CheckboxGroup)< / td > < td > Group identifier; item is checked when present in the group array.< / td > < / tr >
< tr > < td class = "name" > onCheckedChange< / td > < td class = "type" > (checked: boolean) => void< / td > < td class = "default empty" > —< / td > < td > CheckboxItem< / td > < td > —< / td > < / tr >
< tr > < td class = "name" > value (required)< / td > < td class = "type" > string< / td > < td class = "default empty" > —< / td > < td > RadioItem< / td > < td > Identifier inside the parent RadioGroup.< / td > < / tr >
< / tbody >
< / table >
< / div >
< div data-uix-subsection-head > CheckboxGroup · RadioGroup< / div >
< div data-uix-table-wrap >
< table data-uix-table >
< thead > < tr > < th > Prop< / th > < th > Type< / th > < th > Default< / th > < th > Applies to< / th > < th > Description< / th > < / tr > < / thead >
< tbody >
< tr > < td class = "name" > value < span data-uix-tag data-kind = "bindable" > bindable< / span > < / td > < td class = "type" > string[]< / td > < td class = "default" > []< / td > < td > CheckboxGroup< / td > < td > Array of selected values (Bits UI pattern).< / td > < / tr >
< tr > < td class = "name" > onValueChange< / td > < td class = "type" > (v: string[]) => void< / td > < td class = "default empty" > —< / td > < td > CheckboxGroup< / td > < td > —< / td > < / tr >
< tr > < td class = "name" > value < span data-uix-tag data-kind = "bindable" > bindable< / span > < / td > < td class = "type" > string< / td > < td class = "default empty" > —< / td > < td > RadioGroup< / td > < td > Currently-selected RadioItem value.< / td > < / tr >
< tr > < td class = "name" > onValueChange< / td > < td class = "type" > (v: string) => void< / td > < td class = "default empty" > —< / td > < td > RadioGroup< / td > < td > —< / td > < / tr >
< / tbody >
< / table >
< / div >
< div data-uix-subsection-head > Sub · SubTrigger · SubContent< / div >
< div data-uix-table-wrap >
< table data-uix-table >
< thead > < tr > < th > Prop< / th > < th > Type< / th > < th > Default< / th > < th > Applies to< / th > < th > Description< / th > < / tr > < / thead >
< tbody >
< tr > < td class = "name" > open < span data-uix-tag data-kind = "bindable" > bindable< / span > < / td > < td class = "type" > boolean< / td > < td class = "default" > false< / td > < td > Sub< / td > < td > Independent sub-menu open state.< / td > < / tr >
< tr > < td class = "name" > side< / td > < td class = "type" > Side< / td > < td class = "default" > 'right'< / td > < td > SubContent< / td > < td > Default fly-out direction.< / td > < / tr >
< tr > < td class = "name" > align / alignOffset / sideOffset< / td > < td class = "type" > like Content< / td > < td class = "default" > —< / td > < td > SubContent< / td > < td > —< / td > < / tr >
< tr > < td class = "name" > avoidCollisions / collisionBoundary / collisionPadding< / td > < td class = "type" > like Content< / td > < td class = "default" > —< / td > < td > SubContent< / td > < td > —< / td > < / tr >
< tr > < td class = "name" > loop< / td > < td class = "type" > boolean< / td > < td class = "default" > false< / td > < td > SubContent< / td > < td > Wrap nav inside the fly-out.< / td > < / tr >
< / tbody >
< / table >
< / div >
< div data-uix-subsection-head > Group · GroupHeading · Separator · Arrow< / div >
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
< div data-uix-table-wrap >
< table data-uix-table >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< thead > < tr > < th > Part< / th > < th > Props< / th > < th > Notes< / th > < / tr > < / thead >
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
< tbody >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< tr > < td class = "name" > Group< / td > < td class = "type" > id< / td > < td > Wraps a block of items; < code > aria-labelledby< / code > wires to GroupHeading.< / td > < / tr >
< tr > < td class = "name" > GroupHeading< / td > < td class = "type" > id< / td > < td > Non-interactive caption (uppercase, muted).< / td > < / tr >
< tr > < td class = "name" > Separator< / td > < td class = "type" > id< / td > < td > < code > role='separator'< / code > , 1px divider.< / td > < / tr >
< tr > < td class = "name" > Arrow< / td > < td class = "type" > width, height< / td > < td > Optional SVG pointer.< / td > < / tr >
< / tbody >
< / table >
< / div >
< div data-uix-subsection-head > Reference parity< / div >
< div data-uix-table-wrap >
< table data-uix-table >
< thead > < tr > < th > Feature< / th > < th > Radix< / th > < th > bits-ui< / th > < th > ark-ui< / th > < th > Eidos (this)< / th > < / tr > < / thead >
< tbody >
< tr > < td > Button trigger< / td > < td > ✓< / td > < td > ✓< / td > < td > ✓< / td > < td > ✓< / td > < / tr >
< tr > < td > CheckboxItem (single)< / td > < td > ✓< / td > < td > ✓< / td > < td > ✓< / td > < td > ✓< / td > < / tr >
< tr > < td > CheckboxGroup (array bind)< / td > < td > —< / td > < td > ✓< / td > < td > —< / td > < td > ✓< / td > < / tr >
< tr > < td > RadioGroup / RadioItem< / td > < td > ✓< / td > < td > ✓< / td > < td > ✓< / td > < td > ✓< / td > < / tr >
< tr > < td > Nested Sub menus< / td > < td > ✓< / td > < td > ✓< / td > < td > ✓< / td > < td > ✓< / td > < / tr >
< tr > < td > Group / GroupHeading< / td > < td > ✓< / td > < td > ✓< / td > < td > ✓< / td > < td > ✓< / td > < / tr >
< tr > < td > Arrow part< / td > < td > ✓< / td > < td > ✓< / td > < td > —< / td > < td > ✓< / td > < / tr >
< tr > < td > closeOnSelect per item< / td > < td > ✓< / td > < td > ✓< / td > < td > —< / td > < td > ✓< / td > < / tr >
< tr > < td > accessibleWhenDisabled (APG)< / td > < td > —< / td > < td > —< / td > < td > —< / td > < td > ✓< / td > < / tr >
< tr > < td > commit-select semantic event< / td > < td > —< / td > < td > —< / td > < td > —< / td > < td > ✓< / td > < / tr >
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
< / tbody >
< / table >
< / div >
< / section >
{ /if }
{ #if tab === 'morfo' }
< section data-uix-section >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< h2 data-uix-section-title >
< span data-uix-layer-badge = "morfo" > morfo< / span >
· declarative contract
< / h2 >
< p data-uix-section-desc >
14 parts declared in the morfo + 1 eidos-only part
(CheckboxGroup wraps and binds an array — pure composition, no
new data-attrs vs Item siblings). 3 events. Source:
< code > src/uix/morfo/components/dropdown-menu.ts< / code > .
< / p >
<!-- ── Component header ───────────────────────────────────────── -->
< div data-uix-table-wrap >
< table data-uix-table >
< thead > < tr > < th > Field< / th > < th > Value< / th > < / tr > < / thead >
< tbody >
< tr >< td class = "name" > name</ td >< td class = "type" > "{ dropdownMenuMorfo . name } "</ td ></ tr >
< tr >< td class = "name" > kebab</ td >< td class = "type" > "{ dropdownMenuMorfo . kebab } "</ td ></ tr >
< tr >< td class = "name" > scope</ td >< td class = "type" > [{ dropdownMenuMorfo . scope . map (( s ) => `"$ { s } " `).join(', ') } ]</ td ></ tr >
< tr >< td class = "name" > apg</ td >< td >< a href = { dropdownMenuMorfo . apg } target="_blank" rel = "noreferrer" > { dropdownMenuMorfo . apg } </ a ></ td ></ tr >
< tr >< td class = "name" > parts.length</ td >< td class = "default" > { dropdownMenuMorfo . parts . length } </ td ></ tr >
< tr >< td class = "name" > events.length</ td >< td class = "default" > { dropdownMenuMorfo . events ? . length ?? 0 } </ td ></ tr >
< / tbody >
< / table >
< / div >
< div data-uix-subsection-head > Parts< / div >
< div data-uix-table-wrap >
< table data-uix-table >
< thead > < tr > < th > Part< / th > < th > Marker< / th > < th > Element< / th > < th > Role< / th > < th > Archetype< / th > < th > States< / th > < th > Optional< / th > < / tr > < / thead >
< tbody >
{ #each partsList as part ( part . kebab )}
< tr >
< td class = "name" > { part . kebab } </ td >
< td >< code data-uix-part-marker > [{ part . marker } ]</ code ></ td >
< td class = "type" > < { part . defaultElement } > </ td >
< td class = "type" > { part . role ?? '—' } </ td >
< td class = "default" > { part . archetype ?? '—' } </ td >
< td class = "default" > { part . states . length ? part . states . join ( ' | ' ) : '—' } </ td >
< td class = "default" > { part . optional ? 'yes' : 'no' } </ td >
< / tr >
{ /each }
< / tbody >
< / table >
< / div >
{ #each dropdownMenuMorfo . parts as rawPart ( rawPart . kebab )}
{ @const partAny = rawPart as unknown as { kebab : string ; aria? : ReadonlyArray < { attr : string ; value : { kind : string }; condition ?: { when : string ; prop? : string ; part? : string }; severity? : string } > ; keyboard? : ReadonlyArray < { key : string ; action : string } > }}
{ @const dataAttrs = compiled . contracts . dataAttrsByPart . get ( partAny . kebab ) ?? []}
{ @const ariaAttrs = partAny . aria ?? []}
{ @const keyboard = partAny . keyboard ?? []}
{ #if dataAttrs . length || ariaAttrs . length || keyboard . length }
< div data-uix-subsection-head > { partAny . kebab } </ div >
{ #if dataAttrs . length }
< div data-uix-table-wrap >
< table data-uix-table >
< thead > < tr > < th > data-attr< / th > < th > Values< / th > < th > Source kind< / th > < / tr > < / thead >
< tbody >
{ #each dataAttrs as attr ( attr . attr )}
< tr >
< td class = "name" > { attr . attr } </ td >
< td class = "type" > { attr . values ? attr . values . join ( ' | ' ) : '—' } </ td >
< td class = "default" > { 'value' in attr && attr . value ? ( attr as { value : { kind : string } }). value . kind : '—' } </ td >
< / tr >
{ /each }
< / tbody >
< / table >
< / div >
{ /if }
{ #if ariaAttrs . length }
< div data-uix-table-wrap style = "margin-top: var(--uix-space-2);" >
< table data-uix-table >
< thead > < tr > < th > aria-attr< / th > < th > Source kind< / th > < th > Condition< / th > < th > Severity< / th > < / tr > < / thead >
< tbody >
{ #each ariaAttrs as a ( a . attr )}
< tr >
< td class = "name" > { a . attr } </ td >
< td class = "type" > { a . value . kind } </ td >
< td class = "default" > { a . condition ? `when $ { a . condition . when } $ { a . condition . prop ? ` ($ { a . condition . prop }) ` : '' } $ { a . condition . part ? ` ($ { a . condition . part }) ` : '' } ` : 'always' } </ td >
< td class = "default" > { a . severity ?? 'required' } </ td >
< / tr >
{ /each }
< / tbody >
< / table >
< / div >
{ /if }
{ #if keyboard . length }
< div data-uix-table-wrap style = "margin-top: var(--uix-space-2);" >
< table data-uix-table >
< thead > < tr > < th > key< / th > < th > action< / th > < / tr > < / thead >
< tbody >
{ #each keyboard as kb ( kb . key )}
< tr >
< td >< span data-uix-kbd > { kb . key === ' ' ? 'Space' : kb . key } </ span ></ td >
< td class = "default" > { kb . action } </ td >
< / tr >
{ /each }
< / tbody >
< / table >
< / div >
{ /if }
{ /if }
{ /each }
< div data-uix-subsection-head > Events declaration< / div >
< p data-uix-section-desc style = "margin-top: 0.25rem;" >
< code > open< / code > / < code > close< / code > fire < em > pre< / em > the state
flip; < code > commit-select< / code > fires < em > post< / em > with static
< code > intent='affirm'</ code > . Play any signal from the < a href = "#sema" onclick = {( e ) => { e . preventDefault (); tab = 'sema' ; }} > Sema</a > tab.
< / p >
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
< div data-uix-table-wrap >
< table data-uix-table >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< thead > < tr > < th > name< / th > < th > family< / th > < th > verb< / th > < th > sequence< / th > < th > intent< / th > < th > target< / th > < th > prewrite< / th > < th > commit< / th > < / tr > < / thead >
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
< tbody >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
{ #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 ?? '?' } ` : '—' }
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
< tr >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< td class = "name" > { action . name } </ td >
< td class = "type" > { sem . family } </ td >
< td > { sem . verb ?? '—' } </ td >
< td > { sem . sequence ?? 'pre' } </ td >
< td class = "default" > { intentStr } </ td >
< td > { action . target } </ td >
< td class = "default" > { action . prewrite . length ? action . prewrite . map (( p ) => `$ { p . attr } = $ { p . value } `).join(', ') : '—' } </ td >
< td class = "default" > { action . commit ? `$ { action . commit . attr } = $ { action . commit . value } ` : '—' } </ td >
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
< / tr >
{ /each }
< / tbody >
< / table >
< / div >
< / section >
{ /if }
{ #if tab === 'sema' }
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< section data-uix-section id = "sema" >
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
< h2 data-uix-section-title >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< span data-uix-layer-badge = "sema" > sema< / span >
· events + perceptual signature
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
< / h2 >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< p data-uix-section-desc >
Three events. < code > emerge·open< / code > / < code > emerge·close< / code >
share the floating-overlay signature with ContextMenu, Popover and
Tooltip; < code > commit·select< / code > with < code > intent='affirm'< / code >
takes the affirmative-commit signature. Open the menu first so the
Content / Item targets exist before pressing < strong > play< / strong > .
< / p >
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
< div data-uix-table-wrap >
< table data-uix-table >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< thead > < tr > < th > Name< / th > < th > Family< / th > < th > Verb< / th > < th > Sequence< / th > < th > Intent< / th > < th > Target part< / th > < th > Play< / th > < / tr > < / thead >
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
< tbody >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
{ #each events as action ( action . name )}
{ @const intentDecl = 'intent' in action . semantic ? action.semantic.intent : undefined }
{ @const effectiveIntent = typeof intentDecl === 'string' ? intentDecl : undefined }
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
< tr >
< td class = "name" > { action . name } </ td >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< td class = "type" > { action . semantic . family } </ td >
< td > { action . semantic . verb ?? '—' } </ td >
< td > { action . semantic . sequence ?? 'pre' } </ td >
< td class = "default" > { effectiveIntent ?? '—' } </ td >
< td class = "default" > { action . target } </ td >
< td >
< button
data-uix-play
onclick={() => {
const targetSel =
action.target === 'item'
? '[data-dropdown-menu-item]'
: action.target === 'content'
? '[data-dropdown-menu-content]'
: '[data-dropdown-menu-trigger]';
const target = (
stageRef?.querySelector(targetSel) ??
stageRef?.querySelector('[data-dropdown-menu-trigger]') ??
stageRef
) as HTMLElement | null;
if (!target) return;
void uix.events?.emit({
name: action.name,
family: action.semantic.family,
target,
...(effectiveIntent ? { intent : effectiveIntent } : {} )
});
}}
>▶ play< / button >
< / td >
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
< / tr >
{ /each }
< / tbody >
< / table >
< / div >
< / section >
{ /if }
{ #if tab === 'recipe' }
< section data-uix-section >
< h2 data-uix-section-title > Eidos recipe< / h2 >
< p data-uix-section-desc >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
Source: < code > src/uix/eidos/components/dropdown-menu/dropdown-menu.css< / code > .
Uniform chrome across < code > Content< / code > and < code > SubContent< / code > ;
items share one set of tokens so a fly-out reads identically to
the root. All selectors target morfo-emitted markers — no
eidos-private data-attrs.
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
< / p >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< div data-uix-table-wrap >
< table data-uix-table >
< thead > < tr > < th > Selector< / th > < th > Source< / th > < th > Concern< / th > < / tr > < / thead >
< tbody >
< tr > < td class = "name" > [data-dropdown-menu-trigger]< / td > < td > < span data-uix-tag data-kind = "soma" > morfo< / span > < / td > < td > Button reset + focus ring; ARIA-driven open-state hint.< / td > < / tr >
< tr > < td class = "name" > [data-dropdown-menu-content], [data-dropdown-menu-sub-content]< / td > < td > < span data-uix-tag data-kind = "soma" > morfo< / span > < / td > < td > Panel chrome (border, radius, surface, shadow).< / td > < / tr >
< tr > < td class = "name" > [data-dropdown-menu-content][data-state='open' | 'closed']< / td > < td > < span data-uix-tag data-kind = "soma" > morfo< / span > < / td > < td > Enter / exit transitions.< / td > < / tr >
< tr > < td class = "name" > [data-dropdown-menu-item], [data-dropdown-menu-checkbox-item], [data-dropdown-menu-radio-item], [data-dropdown-menu-sub-trigger]< / td > < td > < span data-uix-tag data-kind = "soma" > morfo< / span > < / td > < td > Row layout, padding, gap, hover background.< / td > < / tr >
< tr > < td class = "name" > [data-dropdown-menu-item][data-disabled]< / td > < td > < span data-uix-tag data-kind = "soma" > morfo< / span > < / td > < td > Disabled opacity + cursor.< / td > < / tr >
< tr > < td class = "name" > [data-dropdown-menu-checkbox-item][data-state='checked']::before< / td > < td > < span data-uix-tag data-kind = "soma" > morfo< / span > < / td > < td > Check indicator (rounded square).< / td > < / tr >
< tr > < td class = "name" > [data-dropdown-menu-radio-item][data-state='checked']::before< / td > < td > < span data-uix-tag data-kind = "soma" > morfo< / span > < / td > < td > Radio indicator (circle).< / td > < / tr >
< tr > < td class = "name" > [data-dropdown-menu-sub-trigger]::after< / td > < td > < span data-uix-tag data-kind = "eidos" > eidos< / span > < / td > < td > Right-arrow chevron pure CSS.< / td > < / tr >
< tr > < td class = "name" > [data-dropdown-menu-group-heading]< / td > < td > < span data-uix-tag data-kind = "soma" > morfo< / span > < / td > < td > Uppercase muted micro-caption.< / td > < / tr >
< tr > < td class = "name" > [data-dropdown-menu-separator]< / td > < td > < span data-uix-tag data-kind = "soma" > morfo< / span > < / td > < td > 1px divider line.< / td > < / tr >
< tr > < td class = "name" > [data-dropdown-menu-arrow]< / td > < td > < span data-uix-tag data-kind = "soma" > morfo< / span > < / td > < td > SVG fill matched to panel surface.< / td > < / tr >
< / tbody >
< / table >
< / div >
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
< / section >
{ /if }
{ #if tab === 'a11y' }
< section data-uix-section >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< h2 data-uix-section-title > Accessibility< / h2 >
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
< p data-uix-section-desc >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
Follows the APG < a href = { dropdownMenuMorfo . apg } target="_blank" rel = "noreferrer" > menu-button pattern</ a > .
Trigger is a native < code > < button> < / code > exposing
< code > aria-haspopup='menu'< / code > + < code > aria-expanded< / code > ;
Content gets < code > role='menu'< / code > .
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
< / p >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< div data-uix-subsection-head > Keyboard< / div >
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
< div data-uix-table-wrap >
< table data-uix-table >
< thead > < tr > < th > Key< / th > < th > Effect< / th > < / tr > < / thead >
< tbody >
feat(eidos): Button + 9 demo rebuilds + picker recipe polish
Build:
- New <Button> compound (morfo + soma + sema + eidos): 6 variants
(solid/soft/surface/outline/ghost/plain), 8 colors, 5 sizes, optional
icon/endIcon snippets, loading state with built-in Spinner, asChild
Slot pattern, intent-driven sema (commit-action with fromProp:intent).
Demo rebuilds (canonical depth per DEMO_AUTHORING_GUIDE):
- context-menu, dropdown-menu, pin-input, alert-dialog, toggle-group:
full per-part Morfo contracts, reference-parity tables, ARIA contract
tables, keyboard tables, composition controls.
- color-field, time-field, time-picker, time-range-picker, color-picker,
month-grid, year-grid: same canonical treatment; per-part data/aria/
keyboard iteration of raw morfo, reference parity vs react-aria/
ark-ui/Chakra/bits-ui/Mantine.
Picker recipe polish:
- PickerShell.Clear/Cancel/Close refactored to use <Button size="xs">
(affects 5 pickers — date / date-range / time / time-range / color).
- TimePicker + TimeRangePicker: popover condensed (min-width 18rem -> 14
/ 32 -> 28), per-channel accent (hour=primary, minute=secondary,
second=neutral; end variant muted), ruler off by default, hour ruler
cleaned to 0/6/12/18/23.
- ColorPicker: typography token --_color-picker-trigger-font-size that
scales with data-size (10/12/14px); autoFormat default true; Area
recipe override for [data-x-channel='hue'] with rainbow gradient +
saturation/brightness Y overlays.
- ValueText eidos wrapper: fix children snippet bug that suppressed
soma's displayValue fallback.
- date-field.css: segment editing affordance (cursor + hover + active
ring) via new --_date-field-accent-element token across 8 color
cascades.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
< tr > < td > < span data-uix-kbd > Enter< / span > / < span data-uix-kbd > Space< / span > on Trigger< / td > < td > Open the menu, focus first item.< / td > < / tr >
< tr > < td > < span data-uix-kbd > ArrowDown< / span > on Trigger< / td > < td > Open the menu, focus first item.< / td > < / tr >
< tr > < td > < span data-uix-kbd > ArrowUp< / span > / < span data-uix-kbd > ArrowDown< / span > < / td > < td > Move focus to previous / next item.< / td > < / tr >
< tr > < td > < span data-uix-kbd > Home< / span > / < span data-uix-kbd > End< / span > < / td > < td > First / last item.< / td > < / tr >
< tr > < td > Typeahead< / td > < td > Letters jump to the first item starting with that prefix (uses < code > textValue< / code > when set).< / td > < / tr >
< tr > < td > < span data-uix-kbd > Enter< / span > / < span data-uix-kbd > Space< / span > < / td > < td > Activate the focused item; close menu by default.< / td > < / tr >
< tr > < td > < span data-uix-kbd > Escape< / span > < / td > < td > Close the menu, return focus to Trigger.< / td > < / tr >
< tr > < td > < span data-uix-kbd > ArrowRight< / span > on SubTrigger< / td > < td > Open sub-menu (or < span data-uix-kbd > ArrowLeft< / span > in RTL).< / td > < / tr >
< tr > < td > < span data-uix-kbd > ArrowLeft< / span > inside SubContent< / td > < td > Close sub-menu, return to parent.< / td > < / tr >
< tr > < td > < span data-uix-kbd > Tab< / span > < / td > < td > Trapped inside Content while open.< / td > < / tr >
< / tbody >
< / table >
< / div >
< div data-uix-subsection-head > ARIA contract< / div >
< div data-uix-table-wrap >
< table data-uix-table >
< thead > < tr > < th > Part< / th > < th > Attribute< / th > < th > Value< / th > < / tr > < / thead >
< tbody >
< tr > < td class = "name" > trigger< / td > < td > aria-haspopup< / td > < td class = "type" > "menu"< / td > < / tr >
< tr >< td class = "name" > trigger</ td >< td > aria-expanded</ td >< td class = "type" > { `{open}` } </ td ></ tr >
< tr >< td class = "name" > trigger</ td >< td > aria-controls</ td >< td class = "type" > { `<content id>` } </ td ></ tr >
< tr > < td class = "name" > content< / td > < td > role< / td > < td class = "type" > "menu"< / td > < / tr >
< tr > < td class = "name" > content< / td > < td > aria-orientation< / td > < td class = "type" > "vertical"< / td > < / tr >
< tr >< td class = "name" > content</ td >< td > aria-labelledby</ td >< td class = "type" > { `<trigger id>` } </ td ></ tr >
< tr > < td class = "name" > item< / td > < td > role< / td > < td class = "type" > "menuitem"< / td > < / tr >
< tr >< td class = "name" > checkbox-item</ td >< td > role / aria-checked</ td >< td class = "type" > "menuitemcheckbox" / { `{checked}` } </ td ></ tr >
< tr >< td class = "name" > radio-item</ td >< td > role / aria-checked</ td >< td class = "type" > "menuitemradio" / { `{checked}` } </ td ></ tr >
< tr >< td class = "name" > sub-trigger</ td >< td > aria-haspopup / aria-expanded / aria-controls</ td >< td class = "type" > "menu" / { `{open}` } / { `<sub-content id>` } </ td ></ tr >
< tr >< td class = "name" > sub-content</ td >< td > role / aria-labelledby</ td >< td class = "type" > "menu" / { `<sub-trigger id>` } </ td ></ tr >
< tr > < td class = "name" > separator< / td > < td > role / aria-orientation< / td > < td class = "type" > "separator" / "horizontal"< / td > < / tr >
< tr >< td class = "name" > group</ td >< td > role / aria-labelledby</ td >< td class = "type" > "group" / { `<group-heading id>` } </ td ></ tr >
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
< / tbody >
< / table >
< / div >
< / section >
{ /if }
< / div >