astra
alpha-0.1-background
alpha-0.1-dir-prefs
alpha-0.1-sec-dom
menubar-v4-safe
active-uix
morfo-runtime
morfo-driven-soma
semantuix
glm-5
main
sium-v1.0
${ noResults }
26 Commits (b943fa7386c4308bc325de3392bff6df18630f0d)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
d767d88c03 |
fix(codex-audit): close P0 + tokenize drift introduced by Words sprint
Three categories of audit drift introduced during the recent Words
sprints (drawer redesign, image float bar, color marks, insert
panel, gutter rail), all caught by the existing contract tests now
that the work has landed:
1. **Undeclared morfo attr** (P0 contracts test):
`data-words-block-selected` is stamped by the engine's render on
the atomic-selected block (today only image) but wasn't in the
morfo's data-attr list. Adds it as optional on the same parts
array that already declares `data-words-image-*`.
2. **Missing i18n key** (translations:check):
The drawer part references `components.words.drawer` for its
aria-label, but the langs catalog was never updated when
DRAWER-CANON landed. Add `drawer` to
`src/uix/langs/components/words.ts` (es + en).
3. **Recipe CSS contract drift** (eidos recipe-css-contract test):
- 3 undeclared CSS vars used in the drawer-Editable styles:
`--words-toolbar-color` → `--words-command-color`
`--words-command-hover-bg` → `--words-command-bg-hover`
`--words-command-active-color` → `--words-command-color-hover`
(Right names per `lib/recipes/base.ts > words`.)
- 15 raw font-size literals (0.65rem / 0.7rem / 0.75rem / 0.8rem
/ 0.9rem) replaced with the existing words font-size tokens:
0.65/0.7rem → `var(--words-status-font-size)`
0.75/0.8rem → `var(--words-font-size-sm)`
0.9rem → `var(--words-font-size-md)`
Result:
- `contracts.test.ts`: 31→32 pass (the data-attr violation is gone).
- `translations:check`: 219 refs / 76 catalogs / 0 errors / 0 warnings.
- `recipe-css-contract.test.ts`: 17→19 pass.
- Full `vitest run src/uix`: **867/867** pass (was 865/2-fail before).
- `npm run check` clean (only 6 pre-existing errors unrelated).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
4 months ago |
|
|
58c2c0babf |
fix(words): close audit P0 + quiet focus event (FASE 1)
Cierre de los hallazgos P0/P1 del audit Codex sobre Words + fix del
evento contact-focus molesto reportado por el usuario.
F1.1 — Fix evento foco (UX):
El handler onfocus disparaba `runtime.trigger('contact-focus')` cada vez
que el editor recibía foco, generando sound + haptic + visual stamp en
cada re-focus desde popovers internos (bubble menu / link editor / find
panel / slash menu / toolbar dropdowns). En sesión normal de edición el
foco entra/sale del content docenas de veces, lo que producía fatiga
perceptual.
Cambios en words-provider.svelte.ts:
- onfocus: emit solo en transición real (was-not-focused → focused).
Re-focus desde popover interno NO emite.
- onblur: si el related target es interno al Words tool tree
(isInsideWordsTool), mantener focused=true (Words se trata como un
solo scope de foco). Skip commit('blur') también para evitar
commits espurios entre popover hops.
F1.2 — Declarar 8 data-* hardcoded en morfo (audit P0-1):
Añadidos al Content part:
- data-words-find-match, data-words-find-active (mark highlights)
- data-words-indent (list items con indent > 0)
- data-language (alias parsing-only para interop con HTML externo
emitido por Prism/highlight.js)
Nuevas 6 parts compound (Eidos wrappers):
- HeadingPicker + HeadingPickerPanel (data-words-heading-picker /
-panel)
- CodeLanguagePicker + CodeLanguagePanel
- ToolbarFamilyMenu + ToolbarFamilyPanel
F1.3 — Rename i18n keys a kebab-case (audit P0-1):
4 keys camelCase eran ilegales según contracts.test.ts. Renamed:
- components.words.bubbleMenu → bubble-menu
- components.words.slashMenu → slash-menu
- components.words.linkEditor → link-editor
- components.words.findReplace → find-replace
Propagado a: morfo declarations (8 refs), provider tslangs calls
(4 refs), catalog langs/components/words.ts (4 keys).
F1.4 — Canonizar 9 event names a forma {family}-{verb}[-{variant}]
(audit P2-1):
Renombrados para parsear con el morfo:vocabulary script. El verb
declarado en cada semantic ahora aparece explícito en el name:
- commit-content → commit-save-content (verb: save)
- commit-format → commit-set-format (verb: set)
- commit-link → commit-set-link
- commit-unlink → commit-reset-link (verb: reset)
- commit-slash-command → commit-set-slash
- commit-check → commit-set-check
- commit-history → commit-restore-history (verb: restore)
- commit-clear → commit-reset-content (verb: reset)
- signal-invalid-input → signal-warn-invalid (verb: warn)
Propagado a: sema cascade selectors, soma provider trigger calls,
provider + content tests, demo route. 0 conflictos con event names
de otros componentes (file-upload/tag-group/etc. usan namespaces
propios sin colisión con words).
Tests: 161/161 pass en src/uix/{contracts,soma/components/words}.
Suite full eidos+morfo+soma+sema pendiente de verificar tras commit.
contracts.test.ts ahora verde — cierra P0 audit Codex.
morfo:vocabulary 0 event-name warnings (los 107 data-attr enum
warnings son pre-existentes, separate scope).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
4 months ago |
|
|
9c6375c96e |
feat(eidos): TSC v2.2 (parts + composition) + universal theming coverage
Token Scope Contract universal — no más excepciones arquitectónicas.
Los 3 componentes que vivían fuera de TSC v2.1 (select, avatar,
toggle-group) ahora están dentro del contrato via dos extensiones nuevas.
TSC v2.2 extensiones (lib/config-types.ts + render-css.ts + config.ts):
- `parts: readonly string[]` en RecipeTokenMultiDeclaration — emite
selectores comma-separados (`[data-{c}-x], [data-{c}-y]`) para
componentes con data-color cascadeado per-part. Consumer: select.
- `composition: { foreignRecipe: { targetSelector, tokens } }` sibling
key — overrides cross-recipe scoped a la cascade del host. Consumer:
toggle-group modifica `--toggle-palette-*` en sus items.
Migraciones:
- select: 3 private `_accent-{track,border,text}` con parts: ['trigger',
'content'] + 7 cascades color:X each. Removed orphan `_accent-solid`
(CSS no consumía).
- avatar: 6 tokens via composite scopes `['variant:X', 'color:Y']` con
matrix helper inline. Badge usa parts: ['badge']. Reemplaza 24 bloques
CSS × 2 partes.
- toggle-group: composition block con 8 palette tokens × 4 colors.
Reemplaza 4 bloques CSS per-color.
Bug toggle-group post-composition (encontrado y arreglado):
Tras la composition migration, el cascade del toggle-group seguía roto
porque los tokens derivados (`--toggle-solid-on-bg`, `--toggle-outline-fg`,
etc.) viven en scope `[data-toggle]`. El `[data-toggle-group-item]` es
sibling (no descendant), así que `var(--toggle-solid-on-bg)` resolvía
undefined. Fix: inlined derivation expressions directamente en
`[data-toggle-group-item]` y sus variant cascades (solid/outline/ghost),
referenciando palette tokens en su propio scope local.
Validador + emisor + contract:
- `validateRecipeComposition` valida el shape `{ targetSelector, tokens }`
y rechaza composition entries con scope='root'.
- `stripCompositionKey` + `emitComposition` separan el pipeline.
- `appendRecipeContractTokens` skip-list para `composition` (no aparece
como fake `--{c}-composition` knob).
- `tokenKeys`/`tokenEntries` helpers en recipe-css-contract.test.ts
filtran composition en todos los iteradores.
Documentación:
- THEMING.md §18 reescrito como "Cobertura universal de TSC". §7
extendido con subsecciones "Multi-part scope" y "Cross-recipe
composition" + ejemplos completos. TOC actualizado.
- eidos/README.md tabla de referencia ampliada con TSC v2.2 + §18.
- CLAUDE.md gana hand-off "2026-05-27 #5" (TSC v2.2 + cobertura universal).
- CONTINUE.md reescrito al estado actual de la sesión.
Working tree también incluye sprint Words en paralelo (multiple authors):
slash menu, find/replace regex, code language picker, table audit,
toolbar family menu, code highlight engine.
Tests: 786/786 pass en src/uix/{eidos,morfo,soma,sema}. `npm run check`:
6 errores pre-existentes (lib/_demo, soma/components/internal,
web/routes/active) no relacionados.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
c34fd1fd31 |
feat(uix-components): apply persistence + a11ySemantic + live-region messages to 6 morfos
Per the canonical book §6.2 + §9.2 mapping, six morfos with `signal.warn`,
`signal.alert` or `signal.notify` events get explicit `persistence` +
`a11ySemantic` annotations, and their providers wire up `clearTarget` +
caller-message integration with the shared live region.
**Morfo annotations**:
| Morfo / event | persistence | a11ySemantic |
|--------------------------------------------|----------------|---------------------------------------------------------|
| announce.signal-alert | untilAction | requiresPersistentTrace + requiresLiveRegion |
| form.signal-warn-invalid | untilFix | requiresPersistentTrace + requiresFocusMove + reducedMotionFallback='text' |
| file-upload.signal-warn-reject | untilFix | requiresPersistentTrace + reducedMotionFallback='text' |
| password-field.signal-notify-caps-state | stateBound | requiresLiveRegion + reducedMotionFallback='text' |
| tags-input.signal-warn-reject | untilFix | requiresPersistentTrace + reducedMotionFallback='text' |
| textarea.signal-warn-count-overflow | untilFix | requiresPersistentTrace + reducedMotionFallback='text' |
**Provider wiring**:
- form-provider: clearTarget on submit, message="{N} form errors..." via
FORM_LANGS.ERROR_SUMMARY_*.
- file-upload-provider: clearTarget before each accept/reject cycle, message
via new FILE_UPLOAD_LANGS.REJECT_SUMMARY_{SINGLE,MULTI}.
- password-field-provider: clearTarget on caps-off transition, message
via existing PASSWORD_FIELD_LANGS.CAPS_WARNING.
- tags-input-provider: helper `emitWarnReject` (clear + emit + message
via new TAGS_INPUT_LANGS.REJECT_WARNING), called from addTagValue,
addFromInput, handlePaste. Successful add also clears (the add is the fix).
- textarea-provider: emits only on transition INTO overflow, clears in
transition OUT (untilFix projection persists). Message via new
TEXTAREA_LANGS.OVERFLOW_WARNING with {{max}}.
Three new lang catalog entries (reject/overflow warnings) merged into
the existing components.{name}.* namespaces.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
ee1afdcfbb |
fix(langs): close P0 #3 — translations 58 errors + 8 warnings → 6 (all words) + 2
Catalogs creados (los 3 que faltaban): - src/uix/langs/components/month-grid.ts (label) - src/uix/langs/components/year-grid.ts (label) - src/uix/langs/components/textarea.ts (label + count) Catalogs con claves anadidas: - field.ts: required-indicator (*), optional-indicator ((opcional)) - time-picker.ts: clock + hour + minute + second + day-period + am + pm + clear + cancel + close - time-range-picker.ts: clock + day-period + clear + cancel + close Common keys anadidas (compartidas entre grid components y picker views): - common.month-grid.prev-year, next-year - common.year-grid.prev-page, next-page Barrel index.ts actualizado con los 3 nuevos catalogs: month-grid, textarea, year-grid. Cleanup de huerfanas que ningun morfo referenciaba (date-picker y date-range-picker tenian clear/cancel/close en el catalog pero el morfo los habia migrado a Button consumer via PickerShell): - date-picker.ts: drop clear, cancel, close - date-range-picker.ts: drop clear, cancel, close Errores restantes (6 + 2 warn) son TODOS de words — out of scope (en desarrollo aparte, no se toca esta sesion). Pre: 58 errors + 8 warnings (translations:check) Post: 6 errors (words) + 2 warnings (words) Net: 0 errores y 0 warnings de no-words. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
89f52c5e88 |
feat(eidos): Card, Avatar ext, Image, SText, Badge, service components + dates engine fixes
Sprint completo: - Card (eidos + sema): elevation/intent/interactive, eventos select+activate. - Avatar: ring, AvatarBadge, AvatarGroup separados; demo Avatar standalone. - Image: status surface (idle/loading/loaded/error) consumiendo soma ImageProvider. - SText + STextVirtualList: canvas-text engine portado de morfo-driven-soma como componentes separados para optimizar bundle (no se importa canvas si no se usa). - Badge: primitivo eidos puro. - Trans, FormatNumber, FormatDate, RelativeTime: 4 service components greppables alrededor de uix.langs y uix.format. Nav group "Utilities". Bugs fix arts/format/dates (engine-dates.ts): 1. Preset / per-axis conflict: Intl.DateTimeFormat rechaza dateStyle/timeStyle con cualquier per-axis (weekday/era/year/month/day/dayPeriod/hour/minute/ second/fractionalSecondDigits) o con timeZoneName. Engine drop-ea ambos presets por defecto cuando detecta conflict (regla estricta — un solo per-axis hace ilegales los dos presets). 2. Per-call locale override: formatDate/Time/DateTime aceptan tercer arg locale?: string. No muta engine state. Cache (getCachedDateFormat) keyea por (locale x options). resolveCallHourCycle: cuando hay locale override y pref auto, el ciclo horario se resuelve desde el locale OVERRIDE. 3. withHourCycle precedence: caller hourCycle/hour12 ahora gana sobre preferencia del engine. Antes spread mal ordenado sobrescribia 'h12' del caller con 'h23' del engine cuando locale resolvia a 24h. FormatDate component vuelve a rutear siempre por uix.format.dates (cache + hourCycle + locale reactivo), pasando locale como tercer arg. Demos service components autonomos del toolbar global: cada uno owns su demoLocale state con 7 chips (es-ES/en-US/en-GB/de-DE/fr-FR/ja-JP/ar-EG). FormatDate stage filtra dateStyle/timeStyle por mode + chip hourCycle anadido. Tests: 14/14 passing en engine-dates.test.ts (+6 nuevos: conflict handling, locale override, hourCycle precedence). Docs: arts/format/README.md (handoff 2026-05-25 con las 3 reglas), README.md por service component, project_service_components_sprint_2026-05-25.md, feedback_service_demos_own_locale.md (pattern reusable). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
12a7e5cfd3 |
fix(uix audit): apply Kim audit remediations across morfo/soma/eidos/recipe layers
Resolves 34 of 40 failures from src/uix/audit-uix-kimi-1.md. The remaining
6 are all Words component (excluded per project owner — actively developed
on a separate track) or unrelated infra (cookie-adapter-client jsdom timeout).
Key changes:
- soma/provider/context.ts: swallow Svelte's `lifecycle_outside_component`
in `context.set()` so unit tests can instantiate providers without a
component tree (unblocked 18 picker tests in one line).
- soma/textarea: route inline style writes through `dom.apply({attrs})`
instead of direct `el.style.X = Y` (contract regex compliance).
- soma/picker-shell: add minimal Provider component + morfo so the shared
handle utility passes the morfo/component contract.
- eidos/_layout: lift `shared.ts` to `eidos/lib/layout-helpers.ts` (the
`_layout` directory wasn't a real component) and update 8 layout
primitive imports.
- eidos/command: replace `onMount` with `$effect` (visual layer can't use
Svelte 4 lifecycle hooks per component-api contract); restructure
`Item.Icon`/`Item.Shortcut` namespace so contract regex matches.
- eidos/color-picker: extract hue spectrum hsl literals to sidecar
`color-picker-spectrum.css`; keep main recipe color-literal-free.
- eidos/lib/recipes/base.ts: declare 196 layout-primitive + chrome CSS
vars (box, flex, grid, float, group, banner, container, section,
separator, toggle-group, pin-input, scroll-area, splitter,
navigation-menu, dropdown-menu, context-menu, date-range-field,
time-range-field, plus per-component additions to date-field,
color-picker, button, select). 197 missing → 0 non-Words.
- morfo: add `data-dir` to carousel, `data-kind` to date-picker, add
StrengthMeterLabel sub-part to password-field, register picker-shell.
- 5 pickers (date/color/date-range/time/time-range): add `internals.ts`
indirection so `exports.ts` doesn't re-export `*provider.svelte.ts`
directly (contract D); rewrite virtual root types to plain object
literals (no `WithChild`/`PrimitiveDivAttributes`).
- 4 new READMEs (button, textarea, password-field, picker-shell)
following the search-field canonical template.
Test result: 2391/2397 passing (99.75%). Remaining 6 failures are all
Words-scope or jsdom infra timeout — explicitly out of scope.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
da3e5026bb |
feat: build PasswordField (full stack)
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>
|
5 months ago |
|
|
616d8535f7 |
feat(eidos): add Skeleton and Spinner loader primitives
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> |
5 months ago |
|
|
940e94bb64 |
Build TextArea component + fix locale propagation bug across soma providers
Major work in this session:
1. NumberField demo refactored to expose Intl.NumberFormatOptions live
- 9 canonical presets (currency/unit/percent/compact/plain)
- Locale/currency/unit lists derived from $libs/langs, $libs/currency,
$format/units (no more hardcoded arrays)
- Default locale from uix.format.numbers.getLocale()
2. Bug fix: locale prop ignored when soma.format service is active
- soma/NumberField: 5 bypass points via new `hasOwnLocale` getter
(decimalSeparator, groupSeparator, formatValue, formatEditValue, parseValue)
- soma/Calendar: dateOrder respects locale prop (matches DateField precedence)
- soma/RangeCalendar: same dateOrder fix
- When the consumer passes `locale` prop, soma.nums/dates is bypassed
and Intl is used directly with the prop locale
3. TextArea — new component, full 4-layer stack
- morfo: 3 parts (provider/input/count), 3 events
(commit-input/commit-submit/shift-count-overflow), APG textbox
- soma: TextAreaProvider with autosize (scrollHeight measurement),
submitOn modes (false|enter|shift+enter|mod+enter), maxLength soft clamp,
Field integration (OR-merge), counter overflow tracking
- eidos: 5 sizes × 3 variants × 8 colors, autosize suppresses CSS resize
- sema: commit-submit + shift-count-overflow perceptual cues
- demo: canonical 6-tab depth, all props exposed as live controls
- PrimitiveTextareaAttributes added to soma/types/html.ts
4. Also includes accumulated unreleased work from prior sessions:
- Eidos ports: announce, clipboard, drag-drop, feed, table,
tree-grid, tree-view, virtual-grid, virtual-list, words
- Their canonical demos under web/routes/uix/components/
- Semantic events defined for utility morfos
(announce/clipboard/virtual-list/virtual-grid)
- Tree indent guides fixed (TreeView ::before, TreeGrid stacked gradients)
- Sidebar reorganized with Data + Utilities groups
- Eidos words content layer and primitives
Reference library survey performed before TextArea API design (Mantine,
Radix Themes, Chakra v3, React Aria, Ark UI, Bits UI, shadcn, MUI, Prime).
Decision documented: no separate CurrencyField/UnitField — single
NumberField with formatOptions is the canon (matches all surveyed
headless libs except PrimeReact's mode enum, which still uses 1 component).
svelte-check: 0 errors in modified/created files.
See CONTINUE.md for full session notes and next steps.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
a804c39208 |
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 |
|
|
30e9517a9a |
feat(combobox): SelectedTags inline chips for multi mode
New parts `<Combobox.SelectedTags>`, `<Combobox.SelectedTag>` and `<Combobox.SelectedTagRemove>` render the current selection as removable chips inside `<Combobox.Control>` when `type='multiple'` (Material UI Autocomplete pattern): - Morfo: 3 new public parts with kebab names + texts entries. - Langs: es/en entries `selected-tags` / `selected-tag-remove`. - Soma: `ComboboxSelectedTagsProvider` exposes `items` derived from the provider's label registry; `ComboboxSelectedTagProvider` surfaces `data-value` / `data-label`; `ComboboxSelectedTagRemoveProvider` resolves its parent tag via context and calls `provider.removeValue` on click. Provider gains `getSelectedItems()` and `removeValue()` helpers; `selectedTagsEmpty` runtime prop drives `[data-empty]`. - Soma item registry: stop unregistering labels on Item cleanup so chips keep proper labels after the listbox closes/lazy-unmounts. - Eidos: default snippet loops items and renders a chip + X icon per entry; consumer can override the snippet for custom rendering. - CSS: chip styling, wrap-friendly Control with breathing padding when chips are present, ClearButton pinned right via auto margin, input flex basis reduced to 4rem so it shares a row with chips. - Demo: renders `<Combobox.SelectedTags />` inside Control when `mode === 'multiple'`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
df948aa35a |
fix(combobox): input mirrors selected label in single mode; multi preserves filter
Two related bugs reported in the demo: 1. After selecting an item in single mode, the input stayed at the previously typed query (or empty), so the user couldn't tell which value was committed unless they peeked at the Trigger area. 2. In multi mode, selecting an item used to clear the input, which destroyed any active filter. cmdk-style usage (filter → pick → filter → pick) was impossible — the user had to retype the query for every selection. Provider behaviour now: - `selectItem()` in SINGLE mode sets `inputValue` to the selected label (resolved via the existing `labelRegistry`). - `selectItem()` in MULTI mode leaves `inputValue` untouched, so the filter survives the click and the user can keep picking matches. - A new $effect keeps `inputValue` in sync with `value` in SINGLE mode for initial mount and external `bind:value` updates. - A second $effect clears `inputValue` whenever the picker switches between 'single' and 'multiple' — the two modes use the input for different purposes, and stale text from one would silently filter the other. Also: - Added `components.combobox.clear` to the langs dictionary so the ClearButton stops emitting `[langs] Translation key not found` warnings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
394aeaa476 |
pickers: promote Footer/Clear/Cancel/Close to canonical Eidos parts
The footer affordances (Clear / Cancel / Close) lived inline in each
demo as picker-actions.svelte. Promoted to canonical Eidos surface so
the API is consistent and the contract is auditable.
morfo:
- date-picker + date-range-picker: added Footer (archetype 'footer'),
Clear/Cancel/Close (archetype 'trigger', kind 'public', optional).
Each part declares aria-label via idlangref and data-action="…".
- types.ts: added 'footer' to ARCHETYPE_VOCABULARY array + the
MorfoArchetype union (the type had it, the runtime list did not).
- lang catalogs: added clear / cancel / close idlangref entries to
date-picker.ts and date-range-picker.ts.
eidos:
- Created date-picker-footer/clear/cancel/close.svelte and the range
mirrors. Each part:
- Pulls the provider from context via DatePickerProvider.require()
(analogous DateRangePickerProvider.require() for the range).
- Renders nothing when the corresponding *Button opt is false; the
Close part stays visible whenever mode === 'modal' (modal pickers
need a way out — outside-click and Escape are blocked).
- Emits data-{component}-{part} + data-action so the recipe selector
matches the morfo declaration.
- aria-label resolves via uix.langs.ts('#?components.X.{action}|…').
- onclick calls provider.clear() / cancel() / commit() then forwards
any consumer-supplied onclick.
- index.ts barrels: registered Footer/Clear/Cancel + replaced
Close (was popover-close.svelte) with the new picker-aware Close.
Soma popover-close still drives the old aria; date-picker's Close
adds the modal-conditional visibility + commit semantics.
- *.css: folded the inline picker-actions styles into the recipes —
data-{name}-footer flex row + data-{name}-{clear,cancel,close}
buttons (clear/cancel margin-inline-end: auto so close sits flush
right). prefers-reduced-motion already covered.
soma:
- date-picker exports.ts: surfaces DatePickerProvider + DatePickerMode
+ datePickerAttrs so the Eidos parts can consume them (mirrors what
date-range-picker already exposed). No new behavior — just plumbing.
demo:
- date-picker + date-range-picker demos: replaced
<PickerActions /> with <DatePicker.Footer>
<DatePicker.Clear /><DatePicker.Cancel /><DatePicker.Close />
</DatePicker.Footer>. The two picker-actions.svelte files are
deleted.
Verification: 0 type errors, morfo:check PASS (Footer parts not
required in DOM; conditional visibility honored), component:audit
67/67 PASS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
fd9fb633e0 |
search-field demo: clear button text follows the locale
The demo hardcoded the visible Clear button label inline:
<SearchField.ClearTrigger>Clear</SearchField.ClearTrigger>
So the toolbar's locale toggle (ES/EN) only swapped the aria-label
via the morfo's translationRef, not the visible text. With locale=ES
the panel showed a Spanish UI everywhere except the literal "Clear".
Replace with `uix.langs.ts('#?components.search-field.clear|Clear')`
so the visible button picks up the active catalog entry. Catalog
strings shortened to just `Borrar` / `Clear` (one-word action label
that fits the inline-button affordance — the previous "Borrar
búsqueda" was too long for the visible chrome and wrapped in two
lines). The full phrase still reads naturally for aria-label.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
b11097fcf2 |
batch: texts.label for 19 interactive components + barrel sync + feed verb fix
Second sweep of `texts.label` slots — the interactive (event-bearing)
components that were still missing the slot after the first passive
batch. Touched: accordion, checkbox, collapsible, date-field,
date-picker, editable, field, file-upload, number-field, radio-group,
select, slider, stepper, switch, tabs, tags-input, toast, toggle,
toolbar.
Each got:
- A `label: '#?components.{kebab}.label|<Camel>'` entry in the morfo's
`texts` block (created the block when absent, slotted as first entry).
- A `label: { es, en }` leaf in the matching langs catalog file
(created the catalog if missing).
Barrel `src/uix/langs/components/index.ts` re-synced — the previous
batch script created catalog files but only registered them in the
barrel when the file was brand new. After two passes some files
weren't being merged. Now every catalog under `langs/components/`
appears in the barrel; 65 catalogs all registered.
feed: fixed A-3.4b — `commit-load-more` was using verb `add` which is
not in `SEMA_VERBS.commit`. Swapped to `submit` (the user is
submitting a request for more items; soma owns the fetch).
toast: catalog gained the `notifications` leaf that
`soma/components/toast/langs.ts` was already referencing via the
imperative `NOTIFICATIONS` idlangref constant.
Audit: PASS 33 → 34. translations:check clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
98fc40bf62 |
batch A-3.1: add semantic events to 12 interactive morfos
A pass over every component flagged "interactive with 0 events" (audit A-3.1) plus the texts.label slot they all shared. The events follow the canonical sema families and reuse the focus-move filtering installed earlier so the audit no longer treats keyboard navigation as missing coverage. Per-component event additions: - listbox: commit-select, commit-unselect (affirm/neutral, target=item) - toggle-group: commit-toggle (intent fromProp, target=item) - grid-list: commit-select, commit-unselect (target=item) - context-menu: open, close, commit-select - dropdown-menu: open, close, commit-select - menubar: commit-select - navigation-menu: commit-select - tree-view: commit-select + shift-expand + shift-collapse - tree-grid: commit-select + shift-expand + shift-collapse - table: shift-sort + commit-select + shift-expand-row - carousel: shift-slide - feed: commit-load-more + shift-focus-item - command: commit-invoke (palette item invocation, intent fulfill) - splitter: commit-resize (handle settle, not continuous drag) - drag-drop: commit-drag-start + commit-drop + commit-cancel - color-field: commit-set - time-field: commit-set Each got a `texts.label` slot + matching catalog entry. New catalog files for context-menu / dropdown-menu / menubar / toggle-group; existing files extended for the rest. Audit: PASS 25 → 33 in one batch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
6161b0f4cd |
batch: add texts.label to 12 passive components
Most passive components missing the A-1.3 audit point (texts.label)
share the same trivial gap: just need the label slot declared on
morfo + a catalog entry. One-off migration script
`scripts/add-texts-label-batch.ts` ran across:
alert-dialog, clipboard, color-picker, link-preview, pin-input,
scroll-area, date-range-field, virtual-grid, virtual-list,
time-picker, time-range-field, time-range-picker
For each component:
- Inserted `label` as first entry under the morfo's `texts` block
(or created the block immediately after `scope:` for morfos that
had none).
- Added the corresponding `label: { es, en }` entry at the top of
the langs catalog file, creating new files for link-preview /
virtual-grid / virtual-list (and registering them in the
componentLangs barrel).
- Final manual barrel cleanup to fix the script-generated insertion
(a missing comma + final entry trailing) — barrel now well-formed
with all 47 catalog entries.
Audit: PASS 11 → 23. Sweep doubled the PASS count in one pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
2fc8a30b22 |
drawer: PASS audit + texts.label + Baseline/Gaps
Full walk of drawer (modal slide-in, parallel to dialog): - Morfo: validated. 6 events (present/save/cancel/dismiss/dismiss- outside/after-fail). Focus policy with trap/return/restore. 9 parts (Provider/Trigger/Content/Overlay/Handle + Header/Footer/Title/ Description/Close). - `texts.label` added with catalog entry. Drawer was already wired in the langs barrel. - README `## Baseline` section added (drawer DOES have an air baseline at `glm-5:src/uix/air/components/drawer`, plus the soma additions for drag/snap points). `## Gaps` with dispositions: shouldScaleBackground (descartar — shell-level concern), free-resize without snap points (diferir), Handle ARIA slider role (implementar — accessibility gap for snap points), pulse-to-peek (diferir), nested visual stacking (implementar — same gap as dialog), AlertDrawer variant (descartar — compose AlertDialog inside). Audit: PASS 10 → 11. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
f8c9734c00 |
dialog: PASS audit + texts.label + Baseline/Gaps sections
Full walk of dialog (core modal pattern): - Morfo: validated. 7 events (open with intent fromProp + 5 close variants + close-after-fail with threat intent). Focus policy: trap/return-to-trigger/restore. 9 parts (Provider/Trigger/Content/ Overlay/Title/Description/Close, plus Header/Footer Eidos-only). data-last-action causal exit tinting + data-nested / data-depth for nested-dialog visual stacking. - `texts.label` added with catalog entry. - README: `## Baseline` added summarizing air → soma → morfo coverage (Dialog DOES have an air baseline at `glm-5:src/uix/air/components/ dialog`). `## Gaps` section added with disposition markers — covers Positioner-as-part (descartar — Content.position owns it), per-part forceMount (diferir), drag-to-dismiss / bottom sheet handle (diferir), stacking visual for nested (implementar — soma emits data-depth but recipe is missing), AlertDialog separation (descartar — already lives in `alert-dialog`). Audit: PASS 9 → 10. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
42755cae23 |
popover: PASS audit + accept bare canonical verbs in A-3.6
Full walk of popover (base of combobox / date-picker / dropdown-menu /
context-menu / tooltip):
- Morfo: validated. 9 parts (Provider/Trigger/Content/Arrow/Title/
Description/Close/Anchor/Overlay). 6 events: `present` (emerge),
`close-save` (commit fulfill), `close-cancel` / `close-dismiss` /
`close-dismiss-outside` (emerge), `close-after-fail` (signal risk).
Focus trap + return-to-trigger + restore. Modal flag drives
outside-click ignore + aria-modal + focus trap propagation.
- `texts.label` added with catalog entry. New `popover` entry in the
componentLangs barrel.
- README `## Pendiente deliberado` section renamed to `## Gaps` with
disposition markers. New rows documented: multiple-trigger model
(diferir), `Positioner` as public part (descartar — Soma Floating
owns positioning), `forceMount` per-part (diferir), modal mode +
footer (descartar — the picker pattern, not generic popover),
`onOpenAutoFocus` / `onCloseAutoFocus` docs (implementar),
hover-open delay API (diferir), virtual anchor (diferir).
Audit script refinement (A-3.6):
- Bare canonical verbs are now accepted as valid event names. The
rule used to require `{verb}-{x}` or `{family}-{verb}` — but
`present`, `open`, `close` ON THEIR OWN are perfectly fine when
the event has no variant to disambiguate. The check now passes
events named with a bare verb if that verb is in `ALL_VERBS`,
OR a bare family name. Popover's `present` event no longer
generates a warn.
Audit: PASS 8 → 9. Popover flips to PASS clean. No regressions
elsewhere from the bare-verb relaxation (only popover used the
pattern; other components with bare names already had warns we
documented).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
6181dba46d |
form: PASS audit + refine R-1.2 to require morfo declaration
Full walk of Form (largest finding set in the project):
- Morfo: validated. 14 parts — Provider/Submit/Reset/ErrorSummary +
9 AutoFields parts for the reflective renderer. Provider declares
data-pending/dirty/touched/invalid/submitted on the contract. Sema
events `commit-submit` (fulfill), `signal-invalid` (risk),
`commit-reset` (neutral) are correct.
- `texts.label` added with catalog entry (`label = 'Formulario' / 'Form'`).
- Recipe CSS: `[data-form][data-invalid]` rule added. Low-emphasis
affordance — the ErrorSummary picks up the risk border but field
cells keep their own `[data-invalid]` styling via the Field recipe.
- README rewritten with canonical sections:
- `## Baseline` summarizing air / soma / morfo coverage
- `## Comparativa` (was `## Reference Comparison`) — extended to
include shadcn-svelte plus AutoFields differentiators
(discriminated unions, array fields, first-error focus,
validation timing modes)
- `## Decisiones` documenting the small-wrapper rule, AutoFields
exception, validation timing ownership, the no-noise-on-load
default, sema event placement, and the low-emphasis invalid
treatment
- `## Gaps` (new) with disposition markers — apg is `descartar`
(no APG for "Form" — APG covers individual widgets), AutoFields
i18n is `implementar`, multi-step / submission feedback / etc.
are `diferir`, auto-save / optimistic UI are `descartar`
Audit script refinement:
- R-1.2 (data-disabled styles) now only fires when the morfo
*declares* `data-disabled` on any part. Form's Provider doesn't
emit a disabled state at the root (individual fields handle it
themselves), so demanding defensive CSS for a state the contract
never emits was a false-positive. The rule still fires correctly
for components that DO declare `data-disabled` in their morfo.
Audit: PASS 7 → 8. Form flips to PASS with only one remaining
warn (`A-1.4` no apg URL — `descartar` documented as a gap).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
714df0e5c9 |
combobox: PASS audit + extend focus-move list for listbox/menu nav
Full walk of combobox (popover + editable input + listbox): - Morfo: validated. 10 parts (Provider/Input/Trigger/Content/Viewport/ Item/Group/GroupHeading/Separator/Arrow). Single + multiple via `data-type` on Provider, `aria-multiselectable` conditional on `prop:multiple`. Item declares `data-state` checked/unchecked, `data-value`, `data-highlighted`, `data-disabled`. Keyboard: 6 keys but only 2 mutate state (Enter→select, Escape→close-delegated). - Decision documented: combobox does NOT emit emerge events for open/close/typing/filtering/highlighting — these are navigation mechanics, not commits. Escape close is delegated to the popover layer's `close-dismiss` event. The 2 `commit-*` events cover the actual user intent (choosing an item). - `texts.label` added with catalog entry. The toggle key already existed. Audit script refinements: - Extended focus-move action list to cover listbox/menu/tablist navigation (`next-item`, `prev-item`, `first-item`, `last-item`, `next-tab`, `prev-tab`, `first-tab`, `last-tab`) plus the popover/ dialog actions that are delegated to the containing overlay layer (`open`, `close`, `dismiss`, `toggle`). A combobox / select / menu that hosts Escape→close is not under-declared if the overlay layer owns the sema event. README rewritten with canonical sections: - `## Baseline` summarizing air + soma + morfo coverage. - `## Comparativa` (was `## Comparison`) — table preserved. - `## Decisiones` documenting the no-emerge-events policy, focus-only keys, Control composition rationale, multi-select aria propagation. - `## Gaps` (was `## Out of scope`) rewritten with disposition tokens (implementar / diferir / descartar) per row. ClearTrigger and Validation state get `implementar`; Modal+footer gets `descartar` (combobox is inline by design, not a confirm-style picker). Audit: PASS 6 → 7. No regressions; the relaxed focus-move list benefits other listbox/menu components too (will surface on their audits). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
2fcade063b |
tooltip: expand morfo + recipe states → PASS audit
Closes the second BROKEN component from the audit (after date-range-picker). Five errors collapse to zero: - Morfo declares the three `emerge` events the recipe animations were already keying off (`open`, `close`, `close-dismiss`) plus a `texts.label` slot. `data-disabled` is now declared on `Trigger` (with optional severity) so the recipe rule has a real contract to land on. `aria-disabled` and `texts.label` round out the surface; the new `tooltip.label` catalog entry ships under `src/uix/langs/components/tooltip.ts`. - Recipe CSS: explicit `[data-tooltip-trigger][data-disabled]` and `[data-tooltip-trigger]:focus-visible` rules. The disabled rule suppresses pointer events; the focus rule provides a defensive outline so a focusable trigger shell is at least keyboard-visible. - README: convert the old `## Pendiente deliberado` section into a proper `## Gaps` table with explicit dispositions (implementar/diferir/descartar), and update `## Eventos Sema` to reflect that tooltip now declares its three emerge events instead of claiming zero. Comparativa was already complete; the regex fix from the previous commit picked it up. Audit: tooltip BROKEN → PASS. Project-wide goes from 1/64/2 to 3/64/0 (PASS / NEEDS-WORK / BROKEN). No more BROKEN components. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
c61ba78d35 |
date-range-picker: expand morfo + README → PASS audit
Closes incidencia 2026-05-20 #7 plus the remaining audit gaps: - Morfo now declares the full event surface for the picker layer: `open` (emerge, with intent fromProp), `close-range-commit` (commit fulfill), `close-cancel` / `close-dismiss` / `close-dismiss-outside` (emerge), and `commit-clear` (commit reset). Adds `data-last-action` on Calendar for causal exit tinting, plus `aria-label`, archetype classification, keyboard bindings (Enter/Space on Trigger; Escape + Tab focus on Calendar), and `apg` URL pointing at the W3C dialog-modal pattern. - `texts.label` added with full catalog entry under `src/uix/langs/components/date-range-picker.ts` so A-1.3 passes. - README rewritten with the required structure: Baseline (air / terra / soma actual), Comparativa table (React Aria / Bits UI / Ark UI), Decisiones, and Gaps with explicit disposition markers (implementar/diferir/descartar). The pending modal mode + clear button + demo control prune go in Gaps as `implementar`/`diferir`. - Fix a pre-existing audit-script regex bug: section-extraction regexes used `m` flag with `$` lookahead, which matched end-of-line and truncated section bodies to their headers. Switched to `\n## ` as the explicit section boundary. Audit: date-range-picker BROKEN → PASS. Project-wide BROKEN count 0 (was 2 before, now tooltip remains as NEEDS-WORK). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
5 months ago |
|
|
2b3f3e093e |
uix: rename morfo.translations → morfo.texts (idlangref discipline)
Morfo now declares text slots as absolute idlangrefs in `texts: Record<string, LangRef>`,
not literal multilingual records. Multilingual content moves out of morfo entirely
into per-component catalogs under `src/uix/langs/components/{kebab}.ts`, merged
globally by `ActiveUix` via the new `componentLangs` barrel. Morfo stays a pure
abstract surface; localization lives in its own layer.
- Type: `translations?: LangNode` → `texts?: Record<string, LangRef>` in
`src/uix/morfo/types.ts`. Doc and test fixtures updated.
- Catalog: new `src/uix/langs/` directory with `common.ts` (was `langs.ts`),
`components/` (one file per migrated morfo, plus a barrel), and an aggregate
`uixLangs`. `ActiveUix` registers both namespaces at boot.
- Registry: `registerMorfo` no longer carries a translations fingerprint and
no longer extends `ActiveLangs` dynamically. `connectMorfoTranslations` and
`MorfoTranslationTarget` deleted from the public morfo barrel.
- Validation: schema.ts drops the relative-translationRef-in-morfo.translations
check; catalog presence is enforced by the new `scripts/translations-check.ts`
(wired as `npm run translations:check`).
- Audit: `scripts/component-audit.ts` rule A-1.3 now validates `texts.label`
idlangref shape (`#?components.{kebab}.label|Fallback`) and explicitly errors
on any surviving legacy `translations:` field.
- Migration: `scripts/migrate-translations-to-texts.ts` is the one-off Node
script that produced the 42 morfo rewrites and 42 catalog files.
- Tests: `morfo/registry.test.ts` rewritten around the simpler contract;
`active-uix.svelte.test.ts` reflects boot-time catalog availability instead
of lazy per-morfo extension.
Verification: `npm run check` (0 errors), `npm run translations:check`
(0/0), `npm run morfo:check` (36/36 routed). The 4 pre-existing failures
in `test` are unrelated (date-picker types, css regen, range-calendar
clear, color contract).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |