Words: lift heading level cap 1-3 -> 1-6 (engine type, WORDS_HEADING_LEVELS,
render tag union, validate message, parse-html no longer clamps h4-h6, provider
unions). Palabras panel: Nivel toggle H1...H6 wired to the theme's --style-h{n}
scale; level is a required selection.
ToggleGroup: new `deselectable` prop (default true). In single mode,
`deselectable={false}` requires a selection - re-pressing the active item is a
no-op (radio-like, like Ark/Bits). Soma provider + types + docs; eidos forwards;
palabras uses it for the heading Nivel toggle. Provider test added.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Los 11 packs sema shipped en commit 2d562f37 quedaban dormantes
porque soma no llamaba runtime.trigger en ningún sitio de estos 7
componentes. Esta es la cabling que los activa.
Patrón: emisión en el state-mutator central (no en handlers
individuales) cuando es posible, pasando fallbackTarget al elemento
DOM apropiado para que el cascade selector matchee la instancia
correcta (no la "más reciente registrada").
- toggle-group: `commit-toggle` desde Item.onclick con item button
como fallbackTarget.
- menubar: `commit-select` desde Provider.open(value), usando
triggerRegistry para resolver value→element. Cubre click, keyboard,
hover-follow y arrow-nav en una sola emisión.
- navigation-menu: `commit-select` desde Provider.openNow(value),
usando triggerRefs existente. Closest() del trigger sube al
item ancestro.
- dropdown-menu: `open` y `close` desde handleOpen/handleClose
(sequence: 'pre' — antes de la mutación de state); `commit-select`
desde MenuItemProvider.onclick + onkeydown.
- context-menu: `open` desde openAt(), `close` desde handleClose,
`commit-select` desde ContextMenuItemProvider.onclick + onkeydown.
- tree-view: `emerge-expand`/`emerge-collapse` desde toggleExpand
(lookup branch via querySelector). `commit-select` desde select()
con parámetro fromEl pasado por BranchControl/ItemProvider.
- tree-grid: análogos via lookup de row por data-value.
Pack tree-view actualizado: añade cascade rule para commit-select
sobre `branch` (mismo tuning que item) — branches y leaves comparten
firma perceptual.
Fix colateral: tag-group test esperaba intent='neutral' para
commit-unselect, pero el canon (f3641347) lo declara como 'affirm'.
Test actualizado.
Verificación:
- npm run morfo:vocabulary → EXIT 0
- npx vitest run src/uix/sema src/uix/morfo → 195/195 pass
- npx vitest run src/uix/soma → 419/419 pass (74 files)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
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>
All 65 soma components now consume their morfo as the cross-layer contract.
createAttrs(morfo) and registerContract(morfo) overloads removed — the
Morfo form is now mandatory. Each component provider has a 3-line morfo
import + wire-up block instead of 20+ lines of inline declarations.
Additions:
sium/core/lazy.ts — lazy() combinator for recursive schemas (unblocks
morfo's eventual lazy part-tree validation; tests included).
sium/examples/ — booking, color, login, settings, signup, survey, tree
form demos.
Route demos at src/routes/test/sium/{booking,color,login,settings,
signup,survey,tree}.
Tooling:
morfo-check.ts — now tolerates sibling parts sharing a physical element
(Link variant of Item, etc.). Queries via allPartAttrs cross-scope.
morfo-vocabulary-check.ts — 28 WARN (legitimate per-component
vocabularies or subsets like switch missing "indeterminate"). All
reviewed, none are bugs.
Fixes caught by morfo-check:
table: data-sorted / data-pinned marked severity:'optional' (only
emitted when sorting/pinning active, not always).
tree-grid: data-expanded on Row severity:'optional' (branches only).
menubar: data-menubar-value declared on Trigger.
splitter: data-splitter-panel-id declared on Panel.
Verify:
npm run check — 0 morfo errors (4 pre-existing in sium/examples,
unrelated).
npx vitest run src/uix/morfo — 7/7 tests pass.
npm run smoke — 65/65 routes pass.
npm run morfo:check — 66/66 morfos validate against real DOM.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- 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