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 }
14 Commits (217d6969e4db72e0eafe15af4ce1d14724c93758)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
217d6969e4 |
active-uix: uix.runtime(morfo, sources) auto-injects dom + semantic
Adds a single convenience method on `ActiveUix` so soma providers stop
duplicating the `dom: this.soma.dom, semantic: this.soma.semantic`
boilerplate at every `createMorfoRuntime` callsite.
Before (8 providers, identical lines):
this.runtime = createMorfoRuntime(dialogMorfo, {
dom: this.soma.dom, // ← duplicated everywhere
semantic: this.soma.semantic, // ← duplicated everywhere
states: { … },
props: { … },
events: { … }
})
After:
this.runtime = this.soma.uix.runtime(dialogMorfo, {
states: { … },
props: { … },
events: { … }
})
The implementation is a thin convenience — internally `uix.runtime()`
calls `createMorfoRuntime(morfo, { dom: this.dom, semantic: this.semantic,
…sources })`. No registry, no scope ids, no per-instance lifecycle to
track. Per-provider runtime ownership unchanged. The user explicitly
chose this minimal fix over a "single shared runtime + scope handles"
design after weighing the tradeoffs.
Migrated callsites: avatar, collapsible, dialog, drawer, popover,
switch, toast, toggle (8 providers, ~10 callsites including toast's
two — root + item). The `createMorfoRuntime` named import dropped from
each (only `MorfoRuntime` type kept where the field is annotated).
3 new tests on `active-uix.svelte.test.ts`:
- returns a MorfoRuntime with auto-injected services
- caller does not pass dom or semantic
- attach mode uses the external app's dom + semantic
Verified: vitest 17/17 active-uix (was 14), 211/211 UIX, smoke 68/68,
morfo-check 66/66.
|
5 months ago |
|
|
4bf6dea420 |
remove backward-compat re-export shims
Per architectural feedback: when relocating code to its correct layer,
do the migration completely — update every consumer directly and
delete the original. No re-export barrels at the old paths.
Removed shims:
- `src/uix/soma/attrs/` — was re-exporting `createAttrs` /
`registerContract` / `assertContract` / `getContract` from
`$uix/morfo` and the bool/data-attr formatters from `$libs/dom`.
All 66 importing files updated to import from the canonical
locations directly.
- `src/uix/soma/reactive/` — `reactive.svelte.ts` was a thin
re-export of `$libs/reactive`. The 79 consumers (every soma
provider + layers + types) now import primitives directly from
`$libs/reactive`. The `opts.ts` Props↔Opts bridge moved to
`src/uix/soma/provider/opts.ts` (its natural home — provider
plumbing, not reactive primitives).
- `attachRef` / `RefAttachment` re-export from
`src/uix/soma/provider/provider.svelte.ts` and from
`src/uix/soma/index.ts`. Both removed. Consumers
(`floating.svelte.ts`, `date-field-provider.svelte.ts`) now
import directly from `$libs/reactive`.
Also:
- Moved `ActiveProps<T>` / `StateProps<T>` types to
`src/libs/reactive/types.ts` — they're trivial generic helpers
over `Active<T>` / `State<T>` and shouldn't have lived in soma.
- Stripped soma's root barrel (`src/uix/soma/index.ts`) of every
re-export of libs/morfo concerns. It now only re-exports
actually-soma surfaces (Provider base, mergeProps, css helpers,
id, types, Soma class).
Result:
- `grep -r '\$soma' src/uix/morfo` → 0 matches
- `grep -r '\$uix' src/libs` → 0 matches
- `src/uix/soma/attrs/` and `src/uix/soma/reactive/` no longer exist
- Every import statement now reflects the real architectural layer
Verified: vitest 19/20 files / 214 tests (1 pre-existing air dead-
branch fail using `bun:test`), smoke 68/68, morfo-check 66/66.
|
5 months ago |
|
|
9b07cead6b |
uix: consolidate DOM + relocate morfo runtime to its layer
Three architectural cleanups in one cut:
1. **morfo runtime relocates to its own layer.** The MorfoRuntime + the
pure morfo→attrs resolver (and their tests) move from
`src/uix/soma/morfo/` → `src/uix/morfo/`. They were never
soma-specific — they interpret a morfo declaration on behalf of any
consumer. Soma was just the only consumer at the time. The new
barrel at `$uix/morfo` re-exports `createMorfoRuntime`,
`MorfoRuntime`, `MorfoRuntimeSources`, `RegisterPartOpts`,
`SourceMap`, `SemanticEmitter`, `TriggerOptions`, plus the resolver
helpers (`findMorfoPart`, `resolvePartAttrs`, `shouldEmitMorfoEntry`,
etc.).
2. **`src/uix/adom/` is gone.** The runtime pieces (`createActiveDom`,
`BodyScrollLock`, `DOMContext`, `RovingFocusGroup`, viewport) all
live at `$adom` (`src/arts/adom/`) which is the canonical
ecosystem-level ActiveDom. The `apply.ts` types and helpers
(`DomAttrValue`, `applyChange`, `removeAttrs`, `StructuralChange`)
live in `$libs/dom` and are re-exported from `$adom`. The 4 last
`$uix/adom` import sites updated to `$adom`.
3. **`src/uix/soma/dom/` is gone.** The 14 utilities (`isBrowser`,
`getDocument`, `isHTMLElement`, focus + tabbable helpers, etc.) all
exist as a superset in `$libs/dom`. The 12 soma consumers updated
their imports from `'../dom'` / `'$soma/dom'` → `'$libs/dom'`. No
functional change — purely import-path consolidation.
`src/uix/active-uix/` is preserved as an empty placeholder for the
future cross-layer composition class that will set up morfo + soma +
sema + eidos together.
The relocated runtime now imports cleanly:
- `ActiveDom`, `DomAttrValue` ← `$adom`
- `EngineSemantic`, sema helpers ← `$uix/sema`
- `Active`, `State` ← `$libs/reactive` (was `$soma/reactive`)
- `createAttrs` ← `$soma/attrs` (cross-layer; createAttrs is morfo
logic that lives in soma for now — slated for relocation in a
follow-up)
- `attachRef`, `RefAttachment` ← `$soma/provider/...` (idem)
Verified: vitest 14 files / 197 tests, smoke 68/68, morfo-check 66/66.
|
5 months ago |
|
|
930d4c8c16 |
soma: emit perceptual signal on open in dialog/drawer/popover
Diagnosis: clicking "open" on dialog/drawer/popover produced no sound
(or any semantic feedback). Cause: every overlay trigger was bypassing
`runtime.trigger(...)` with a direct `handleOpen()` because the morfo's
declared target part (overlay content) doesn't yet exist in the DOM
when the trigger fires — and `runtime.trigger` was throwing when the
target part had no registered ref.
Fix:
- `MorfoRuntime.trigger(name, opts?)` now accepts `{ fallbackTarget?:
HTMLElement }`. When the declared target part is unmounted, the
fallback is used as the visual signal target so the perceptual
signal still fires. Sound / vibra channels don't care about the
target; the visual channel writes its `data-event*` to the trigger
briefly, which is the natural locus of the user's action anyway.
- Dialog / Drawer / Popover triggers now go through `runtime.trigger`
with the trigger element as `fallbackTarget`. Each provider's
`events` map gains an `open` (or `present`) entry that runs
`handleOpen()` as the runtime's handler step — preserving the
prewrite → emit → handler order.
- Popover's toggle uses `close-dismiss` for the close direction so
both directions emit a perceptual signal, not just open.
Soma class: `soma.dom` and `soma.semantic` are now non-optional again
(matching pre-migration semantics — every layout declares both
services). `soma.format.*` slices stay optional.
Verified end-to-end with a Playwright probe that spies AudioContext
construction:
Open dialog → 2 oscillators (was 0)
Press Escape → +2 (was 2)
Click overlay → +2 (was 0)
Gates: vitest 7 files / 78 tests, smoke 68/68, morfo-check 66/66.
|
5 months ago |
|
|
b096237d3e |
soma/dialog: dismissWith(action) public API + tinted demo section
Expose a programmatic dismiss method on DialogProvider that fires the
matching close-* event through the runtime, and use it from the eidos
Dialog demo to make the exit-tinting visible.
Soma:
- DialogProvider.dismissWith('save'|'cancel'|'fail'|'dismiss'|
'dismiss-outside') maps to the corresponding morfo event
(close-save, close-cancel, close-after-fail, close-dismiss,
close-dismiss-outside) and fires runtime.trigger().
- DialogProvider class re-exported from $soma/components/dialog so
consumers can call DialogProvider.get() inside a child component.
Demo (test/eidos/dialog):
- New "Exit tinting by causa" section with three buttons that close
the same dialog via three different events:
Save → close-save → border-top tinted success (240ms hold)
Cancel → close-cancel → border-top tinted neutral (240ms hold)
Fail → close-after-fail → border-top tinted danger (600ms hold)
The 600ms fail hold is sema's family='alert' default — the dialog
stays open longer for the user to register the failure before close.
- Uses a small _dismiss-button.svelte child component that captures
DialogProvider.get() at component init time. The inline onclick
pattern (Dialog.DialogProvider.get()?.dismissWith(...)) doesn't
work from the parent route's scope because Svelte's getContext is
init-time-only — the route is the parent of Dialog.Provider, not
a child. The _dismiss-button is rendered inside Dialog.Content so
its init-time context lookup resolves correctly.
Verification (playwright probe):
save t=144ms lastAction=saved hold=240ms
cancel t=116ms lastAction=cancelled hold=240ms
fail t=117ms lastAction=failed hold=600ms (full alert family)
Smoke 68/68.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
bb8c8657e1 |
soma/dialog: soft-migrate close-* events through MorfoRuntime
Inject a MorfoRuntime side-channel in DialogProvider that fires the
prewrite → semantic.emit → handler cadence for the close-* events
declared in the dialog morfo. The legacy provider machinery
(assertProps + resolveMorfoProps + Provider class hierarchy) stays —
runtime is alongside, not replacing.
Wiring:
- DialogProvider creates the runtime in its constructor with
`events.{close-save, close-cancel, close-dismiss,
close-dismiss-outside, close-after-fail}` all delegating to
handleClose(). The runtime gets dom + semantic from soma + state
sources for `open` + prop sources for `disabled`/`modal`.
- DialogContentProvider registers the content part with the runtime
when its constructor runs, so trigger() can resolve
`event.target = partRef('content')` to a real DOM node.
- DialogTriggerProvider.onclick keeps direct handleOpen() — the
'open' event in the morfo targets content, but content isn't
in the DOM until AFTER open flips. Chicken-and-egg.
- DialogCloseProvider.onclick → trigger('close-cancel').
- DialogContentProvider's dismissal callbacks:
onEscapeKeydown → trigger('close-dismiss')
onInteractOutside → trigger('close-dismiss-outside')
What this unlocks:
Each close path now writes `data-last-action` (saved/cancelled/
dismissed/dismissed-outside/failed) BEFORE flipping data-state,
visible during the exit animation. The dialog recipe's tint rules
in eidos finally fire in vivo.
Verification (playwright check-eidos-recipes):
@8ms post-click lastAction=cancelled state=open (prewrite)
@241ms lastAction=cancelled state=open (signal hold)
@378ms lastAction=cancelled state=closed (exit)
@493ms opacity=0.017 (exiting)
The 240ms wait between click and exit is sema's family='emerge' hold.
The user can override per-event via `morfo.events[].hold` if 240ms feels
too long for a dialog cancel. Smoke 68/68, morfo-check 66/66.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
5 months ago |
|
|
a0a1485b9f |
Refactor sema and add shared dom runtime
|
6 months ago |
|
|
91257e8526 |
soma/morfo: rename root part → provider + fix toolbar effect loop
Naming coherence across the part layer: the root part's `kebab` field now
matches its `name: 'Provider'`. The `createAttrs` special case still emits
`data-{component}` (no suffix) for the provider part — the DOM contract is
unchanged, only the authoring name changes.
Affected:
- createAttrs special-case: 'root' → 'provider'
- 66 morfos: kebab 'root' → 'provider'
- 77 soma provider files: `attrs.root` → `attrs.provider`, constructor
part arg 'root' → 'provider'
- Docs: A2 rule rewritten, morfo/README, soma/README example updates
- Test / schema / morfo-check: updated for new kebab
Toolbar fix: remove `itemsVersion` counter and per-item `$effect` blocks
that called `notifyItemsChanged()`. The pattern was an A30 violation —
each item's $effect read `ref.current`/`disabled` and wrote back to the
provider, which cascaded through `firstTabStop` → per-item `props`
$derived → DOM reattach → effect re-run, triggering
`effect_update_depth_exceeded` on page load. `isTabStop` now uses
`untrack` around the DOM walk so per-item `props` derivations only
depend on `lastFocusedElement`.
Verification: 7/7 morfo tests, 65/65 smoke, 66/66 morfo-check, no effect
loops detected across any demo page.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
6 months ago |
|
|
8c16ffac81 |
morfo: cross-layer contract + 14 new WAI-ARIA components + Dialog wired
Morfo (src/uix/morfo/): machine-readable contract of a component's public DOM surface, shared between soma/sema/eidos. Shape v5 consolidated across three independent AI reviews (Gemini, Grok, ChatGPT) plus Sema alignment. Types, sium-based validator with cross-field invariants, dialog.ts as the first canonical morfo with data-last-action for Sema-causal exits, 7 passing unit tests. createAttrs(morfo) and registerContract(morfo) now consume a Morfo — legacy inline signature removed. Dialog provider refactored to derive parts + data contract from dialogMorfo. The other 65 soma components need porting (svelte-check lists them) — tracked work. Tooling: scripts/smoke-check.mjs — Playwright smoke over 65 soma demo routes scripts/morfo-check.ts — validates emitted DOM vs morfo scripts/morfo-vocabulary-check.ts — canonical vocabulary consistency npm run smoke / morfo:check / morfo:vocabulary WAI-ARIA APG components added (100% APG coverage now): Announce, Avatar, Clipboard, DragDrop, Feed, GridList, Meter, Progress, SearchField, TagGroup, TreeGrid + Table.RowDetail/Trigger (detail panel pattern; hierarchical Table rows deprecated — use TreeGrid instead). air: Link, Banner. Sema prep: src/uix/sema/sema_pre.md documents the semantic layer's DOM requirements. Morfo already provides everything Sema needs (data-last-action patterns, transition markers, enumerable state values, cross-component consistency). Sema implementation deferred. COMPONENT_GUIDE updated: items 37-39 (translation namespace grep, DOM topology vs .require() audit, npm run smoke is part of done) + A34 rule with incident log. WAI-ARIA pattern listed as soma membership criterion. Pagination translation bug fixed (soma.pagination.page -> idlangref PAGINATION_LANGS.PAGE). Table demo namespace fix (soma.table.* -> components.table.*). Avatar demo now offline-safe (SVG data URL). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
6 months ago |
|
|
015d5e258d |
soma: gesture layer, drawer component, full audit fixes across 26 components
Gesture Layer:
- Gesture.base(), Gesture.drag(), Gesture.resize() — shared pointer tracking
- VelocityTracker with ring buffer, staleness check, projection
- 52 tests (velocity + gesture integration)
- setPointerCapture deferred until moveBuffer exceeded (prevents click stealing)
Drawer Component:
- 8 parts: Provider, Trigger, Content, Overlay, Handle, Title, Description, Close
- Gesture.drag() integration for swipe dismiss
- Snap points (fractional + px), fadeFromIndex, handle tap-to-cycle
- Modal/non-modal/non-dismissible modes
- Logical directions (start/end) RTL-aware via soma presentation
- CSS custom properties (--drawer-progress, --drawer-offset-x/y)
Architecture:
- T1: 219 files migrated from $soma/ alias to relative paths
- T2: 35 wrappers — noop replaced with () => {} inline
- Translation system: componentLangs + common.buttons.* + idlangref constants
- COMPONENT_GUIDE.md + README.md fully updated to reflect current patterns
- contracts.ts: case-normalized registerContract/assertContract
Audit Fixes (P0 critical):
- DI1/PO1/TO1: 'provider' → 'root' in parts/contract/super
- TB1: data-table attr on wrapper
- CH1/SW1/NF4: hidden input rendering fixes
- SP2: panel cleanup on unmount
- RG1: roving tabindex fallback to first item
- CO1: aria-labelledby on collapsible content
Audit Fixes (P1 high):
- SafePolygon integrated in dropdown-menu SubProvider + tooltip
- 9 langs.ts files with idlangref constants
- Dialog: aria-label removed (WCAG 2.5.3), handleOpen/Close guards
- Stepper: count decrement + private, aria-label on List
- ToggleGroup: roving tabindex in multiple mode
- Select: pure aria-activedescendant (no mixed focus), label registry
- NumberField: startValue respects min, scrubber commit on pointerup only
- Toolbar: element-based focus tracking (not index)
Audit Fixes (P2 medium):
- A6: timer/listener cleanup in 6 components
- A12: getDirectionalKeys in 4 components
- A10: DOM queries scoped to root in 3 components
- Dropdown-menu: typeahead + Home/End in SubContent, activate() pattern
- Checkbox: PrimitiveLabelAttributes, getAriaChecked helper, stale value cleanup
- Pagination: reactive page clamping, Set-based computePageRange
- Scroll-area: thumbSize zero-guard, mount flash prevention
- Splitter: collapse/expand respects adjacent constraints, immediate pointer capture
5 issues remain (design decisions): stepper registry, table sub-row IDs,
tags-input ARIA model, tags-input paste, toast exit animation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
6 months ago |
|
|
a1d0bee655 |
refactor: App layer with reactive lang, soma migration, 26 component audits, RTL fixes
- Add App service compositor (langs, nums, money, dates, units, presentation) - Add createSvelteLang() with reactivity for locale and schema changes - Migrate 25 soma providers from getSoma()/translator.svelte to Soma.getOr()/langs.t() - Add reactive dir resolution in all component wrappers - Add dir HTML attribute to 12 root providers (accordion, tabs, slider, etc.) - Fix slider RTL: range, thumb, tick use right/left based on dir - Add table structural parts: Header, Body, Footer wrappers - Implement ColumnPinning, ColumnSizing, Expanded in table-core - Remove soma core formatters, translator.svelte, prop-resolvers (moved to App) - Remove duplicate convenience getters (locale, dir, translate) from App/Soma - Audit all 26 soma components, create audit docs with 84 issues found - Update test page with pinning, sizing, expandable rows demos |
6 months ago |
|
|
8a88ad577a |
soma: audit fixes — 84 issues across 25 components, Table complete
Table component: - Complete state manager: sorting, filtering, pagination, selection, column pinning (sticky), column sizing, expandable rows (sub-rows + detail panels), column visibility - Provider renders <table> with translated aria-label - Sorting opt-in per column, consumer places sort buttons - filteredRowCount/totalRowCount for correct pagination count - Sub-row IDs hierarchical (parentId.subIndex), no collisions - Production-grade test page (Swiss Industrial design) - Full README with all features documented Critical fixes (10): - Toast: memory leaks (timer + hotkey listener cleanup via $effect) - Toast: restartTimer() method for promise-based toasts - ScrollArea: type='always' now works (check order fix) - ScrollArea: thumb click no longer triggers track jump - Tooltip: no crash without <Tooltip.Group> (ctx.getOr) - Combobox: click-outside-to-close fixed (isValidEvent) - Popover: stray 'n' character removed from popover.svelte - TreeView: ARIA ownership fixed (role=treeitem on Branch, not Control) - Splitter: documented required array spread for reactivity High fixes (14): - Checkbox: group disabled/name propagation + checked sync via $effect - Select: aria-labelledby on content, aria-disabled on items - Stepper: aria-controls + aria-labelledby cross-linking - TagsInput: highlightPrev returns to input, role on Control/Item - Editable: Preview role=button + aria-label - Pagination: translated aria-label on items - RadioGroup: removed unused Soma import Medium fixes (60): - registerContract() added to all 25 components - Dead config=getSoma() removed from 7 providers - Dead imports removed (Tooltip, Popover, Slider, Combobox) - Dialog: aria-modal conditional on modal prop - Slider: pointer capture release + onpointercancel - Popover: hover timeout cleanup, aria-modal support - Tabs: inactive content hidden + aria-hidden + tabindex=-1 - ToggleGroup: aria-orientation + roving tabindex fallback - Toolbar: data-disabled on Button - Stepper: Content tabindex - TreeView: RTL keyboard support (expand/collapse key swap) - NumberField: Enter key commit, clampOnBlur, allowMouseWheel, scrubber a11y - Toast: data-state on root, aria-live on viewport - ScrollArea: scrollbar aria-label + tabindex - Collapsible: part root (not provider), aria-controls, role=region - Tooltip: removed dead provider part from attrs Architecture: - COMPONENT_GUIDE.md: 14 audit-derived rules (A1-A14) - Checklist expanded from 15 to 23 steps - 8 new HTML primitive types (Table, THead, TBody, TFoot, TR, TH, TD, Caption) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
6 months ago |
|
|
1fd0b46b2e |
soma: refactor providers to follow terra patterns, fix translations, add table/number-field
- Rename root→provider in all 25 component providers (terra convention) - Fix translations: use translatePath (ling.t) instead of translate (ling.ts) for dot-path resolution with soma. prefix - Move onChange callbacks from provider Opts to writableActive setters in svelte wrappers (terra pattern, reduces prop duplication) - Add shared test layout with ling translator for all soma test pages - Add Table component with sorting, selection, pagination, filtering, column visibility, ARIA grid pattern - Add NumberField component with glob numr integration - Fix table headers reactivity (missing getter) - Fix table column filters (was passing row instead of cellValue) - Add AUDIT.md with F1-F15 findings (11 fixed, 4 pending) - Revert accidental terra modifications Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
6 months ago |
|
|
94c499db96 |
soma: 12 components, architecture docs, naming fixes, form tier complete
Components (12):
- Accordion (keyboard nav, single/multiple, collapsible, loop)
- Checkbox (indeterminate, group, readonly)
- Collapsible
- Combobox (input + floating listbox, consumer-side filtering)
- Dialog (variant dialog/alertdialog, modal, nested, animations, forceMount)
- DropdownMenu (15 parts, submenus, typeahead, checkbox/radio items)
- Popover (floating, openOnHover, modal, custom anchor)
- RadioGroup (roving tabindex, orientation, readonly)
- Select (single/multiple, typeahead, scroll-into-view, hidden select)
- Slider (drag, keyboard, single/range, ticks, vertical)
- Switch (hidden input, data-checked)
- Tooltip (skip-delay group, 3-state, hover/focus)
Architecture:
- State class files renamed: {name}.svelte.ts → {name}-provider.svelte.ts
(avoids Vite module resolution ambiguity with .svelte wrappers)
- Export name standardized: always Provider, never Root
- COMPONENT_GUIDE.md: step-by-step implementation guide with checklist
- SOMA_ARCHITECTURE.md: updated structure, anti-patterns, improvements table
- README.md: updated naming, file structure, inventory
- context.ts: error message uses Provider not Root
- Demo index page at /test/soma/
Bug fixes:
- DropdownMenu trigger missing onclick/onkeydown in props
- DropdownMenu interactOutsideBehavior always 'close' (not modal-dependent)
- Checkbox getContext in event handler → captured in constructor
- Select context not found → was Vite cache issue (not naming)
- ScrollLock unlock path
- Floating wrapper z-index: auto override
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
6 months ago |