- dialog + drawer adopt data-depth="modal" (surface·border·base-shadow from the plane);
recipes pruned of orphan content-bg/border/shadow. The bundle's on-surface font fixes
the Times New Roman of portaled content (Decisión 8).
- Dialog.Close inherits the dialog size via context.ts, capped at md (sm→sm, md/lg/xl/full→md;
full is layout, not a bigger control — Radix/Mantine/MD3). THEMING §5 container→part norm.
- Dialog title → h3 typography role (--dialog-title-* points at --style-h3-*, override knob kept).
- Dialog trigger + close compose the framework <Button> via the asChild `child` snippet
(the trigger was a passthrough that rendered soma's native <button>); variant/color/size
defer to the canonical Button defaults (solid/primary) — no hardcoded ghost/neutral.
- demo layout (web/routes/uix/+layout@.svelte): "Display" control — density·scaling·border-width
applied to :root (reaches portaled overlays) to observe the interrelated theming axes live.
- update the depth-plane test (z is token-only; on-surface font) + the archetype audit hand-off.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dedicated password input component — matches the Ark UI / Chakra v3 /
Mantine / PrimeReact / Ant Design pattern of treating PasswordField as
its own first-class component (not a TextField variant). Includes one
feature that NO surveyed library ships: a CapsLock indicator driven by
KeyboardEvent.getModifierState('CapsLock').
Anatomy (5 parts, 4 events):
- Provider (root, value + visibility state)
- Input (the textbox; type flips between password / text)
- VisibilityTrigger (eye toggle button; aria-pressed + aria-controls)
- CapsLockIndicator (status live region; data-active toggles via soma
listening to keydown/keyup on Input)
- StrengthMeter (composable; consumer provides 0-4 score; UIX bundles
no zxcvbn-style algorithm — dependency-free by design)
Events:
- commit-input (every keystroke)
- commit-submit (Enter)
- shift-toggle-visibility (eye click)
- shift-caps-state (Caps Lock state flips while focused)
Key behaviors:
- `purpose: 'current' | 'new'` drives native autocomplete attribute
('current-password' for login / 'new-password' for registration).
- Field integration: disabled/readonly/required/invalid OR-merged.
- VisibilityTrigger gets tabindex=-1 so it doesn't break the form's
natural tab order — mouse / programmatic focus only, matching Ark UI.
- Caps Lock indicator is aria-live="polite" — announces on activation
while focused, silent when inactive.
- Letter-spacing increased on the input for legibility while masked.
Reference library survey performed (10 libraries) before implementation —
all consensus around dedicated component, all have built-in toggle,
ZERO have caps lock warning. Documented in the demo's API tab with a
feature comparison table.
Demo follows DEMO_AUTHORING_GUIDE canonical 6-tab depth: Live (controls
grouped by layer + code snippets at the bottom), API (props + reference
comparison), Morfo (field/value + Parts + Events tables), Sema (events
table with ▶ play), Recipe (selectors with morfo/eidos owner tags), A11y
(concern/contract table).
Also includes external work in words/ from a separate session
(unrelated to PasswordField) — not touching Words is the standing rule,
but the diff was already in the working tree.
svelte-check: 0 errors in PasswordField files (Words errors are tracked
by its own development branch).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous demos violated DEMO_AUTHORING_GUIDE in several places. Both
have been rewritten end-to-end against the aspect-ratio canary template
(canonical reference for 0-events eidos primitives).
Changes per demo:
- Stage always rendered between header and tablist (was inside Live tab).
- MutationObserver wired with stageRef + 6-entry trace strip (was absent —
required even for 0-event components per §6).
- Trace strip layout: 'no semantic events' badge + shape/variant + size +
color, matches aspect-ratio shape.
- Live tab adds the soma + eidos code snippets with full data-uix-code
wrappers and head badges (§7 + §8).
- somaSnippet now shows the equivalent semantic markup with a clear
"not real soma" note (since these are eidos-native).
- API tab uses data-uix-table with explicit "Skeleton-specific props" +
"Inherited from Box" + "Reference comparison" subsections (§4).
- Morfo tab matches §10: header field/value table + Parts table with
marker column + per-part data/aria subsection tables.
- Sema tab keeps the explicit 0-events explanation (was absent for one
of the demos).
- Recipe tab uses the Selectors table with morfo/eidos owner tags (§11)
instead of a single code snippet.
- A11y tab uses data-uix-table (concern/contract) instead of a bullet
list, matching aspect-ratio.
Reference template: web/routes/uix/components/aspect-ratio/+page.svelte.
Per §1, when in doubt, copy from the canary template and adapt.
svelte-check: 0 errors.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two pure-eidos loader components with morfos at scope `['eidos']`
(no soma backing, no semantic events).
Skeleton — content placeholder:
- 3 shapes: rect (default), circle, text (multi-line with staggered widths)
- 5 sizes (xs..xl), 8 color accents
- Optional shimmer animation via CSS `background-position` keyframes
- Single `<div role="status" aria-busy="true">` with translated aria-label
- Reduced-motion freezes animation, keeps visual
Spinner — indeterminate progress:
- 3 variants: ring (rotating arc), dots (bouncing), bars (stretching)
- 5 sizes, 8 colors
- Optional inline label via children snippet
- `role="status"` + `aria-live="polite"` for SR announcements
- Reduced-motion freezes animation, keeps visual
Files:
- morfo: skeleton.ts, spinner.ts (scope eidos, no events)
- eidos: full component + types + css + langs + index per component
- langs: skeleton/spinner under componentLangs barrel
- demos: canonical 6-tab depth + composition examples (avatar+text card)
- layout: sidebar additions under Status group
Note: also includes responsive shell additions to web/routes/uix/uix.css
that surfaced from an external session — same file, leaving them in.
Reference libraries reviewed (Mantine, Chakra v3, Radix Themes, MUI):
all expose the same shape/variant/size/color surface. shadcn Skeleton uses
the same pulse animation. No surprises in our API.
svelte-check: 0 errors in skeleton/spinner files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two visible inconsistencies in dark theme that the user flagged:
1. Scrollbars in code blocks (and any other scrollable inside the
demos) rendered with the user-agent default chrome — bright white
track + thumb on a dark surface. Only `[data-uix-rail]` (the left
navigation column) had a themed scrollbar.
Added a universal WebKit scrollbar theme scoped to
`[data-uix-docs]`: transparent track, `--uix-line` thumb with
2px padding-clipped border so it reads as a thin rounded handle
that hovers to `--uix-line-strong`. Both axes (10px width).
Firefox handled via `scrollbar-color` + `scrollbar-width: thin`
on the root.
2. `[data-uix-radio]` had zero CSS rules — the date-range-picker
demo's `mode` (inline / modal) selector fell back to native radio
inputs and an unstyled label, while its sibling controls used the
themed `[data-uix-switch]`. Two switches-as-controls + one set of
native radios in the same panel.
Mirrored the data-uix-switch chrome at radio size: 16x16 circle,
`--uix-line` border, `--uix-surface-sunken` background, inner
pill in `--uix-accent` when checked, focus ring matches the rest.
Label uses the same color + size as data-uix-switch-label.
Verified in browser on date-range-picker demo: the `mode` radios now
read as the same control family as the surrounding switches, and the
code-snippet scrollbar is dark-themed instead of bright white.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The `[data-uix-control] input[type='text|number']` rule only covered
two input types, so demos that used `<input type='date'>` (date- and
date-range pickers' min/max/start/end inputs, calendar bounds, etc.)
or `<input type='email|search|tel|url|password|time|month|week|
datetime-local'>` (form/field demos) fell back to the user-agent
chrome — different padding, borders, fonts, and the native
calendar/clock indicator with no theme alignment.
Replaced the type-specific selector with an exclusion list:
[data-uix-control] input:not([type='checkbox']):not([type='radio']):not([type='range'])
Every text-like input now picks up the demo's standard chrome
(6px / 32px / `--uix-line` border / `--uix-surface` bg / focus ring).
Checkbox + radio keep their bespoke toggle treatments; range keeps
its native track with the demo accent.
Added:
- Consistent `min-block-size: 32px` + `box-sizing: border-box` so
inputs line up vertically with the demo's button-style pill
controls.
- Disabled state: 0.55 opacity + `not-allowed` cursor.
- `::-webkit-calendar-picker-indicator` recolored for
date/datetime-local/month/time/week inputs — inverted 70% so the
calendar/clock icon reads on dark theme and matches the field
text tone, with full opacity on hover.
- `::-webkit-search-cancel-button` recolored.
Verified in browser: date-range-picker demo's start/end/minValue/
maxValue inputs now match minDays/maxDays (number) and label/name
(text) inputs. Form demo Field-rendered inputs and the controls
panel both read as one consistent surface. date-field controls
panel (locale select + name text + min/max date inputs) matches.
Closes#47 in the task list.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>