Coherence audit (ARCHETYPE_COHERENCE_AUDIT_2026-06-19): 8 archetypes + 8 closed
decisions, the §13 construction contract, per-component deviation matrix (88/117
deviate). Master guides (soma/COMPONENT_GUIDE, eidos/components/README) point to it.
A1 — elevation bundle via `data-depth`: the plane paints surface·border·shadow·halo
(added `border` to the depth bundle). z-index is NOT painted — stacking is a
positioning concern owned by the floating-wrapper. Popover migrated to the overlay
plane (panel + arrow consume it); recipe orphans pruned.
Popover fixes: arrow un-clipped via an inner [data-popover-viewport] (Radix-style;
the absolute arrow escapes the scroll clip), sized via density tokens (not soma's
hardcoded 10×5), border-seam overlap keyed on data-side, hover-bounce guard in
scheduleHoverOpen (ignore hover-open when already open). Dialog.Close composes
IconButton/Button (neutral) — closes the Lote ② debt.
Option lists: density-driven padding/radius via --space-* + concentric radius,
ScrollArea adoption, emerge open/close events (combobox/select/command), and the
canonical option-highlight in archetypes.css.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reference-library parity (Radix Themes, Chakra v3):
- size: 'xs' | 'sm' | 'md' | 'lg' (Chakra t-shirt scale) → thickness
via --scroll-area-scrollbar-size.
- radius: 'none' | 'sm' | 'md' | 'lg' | 'full' (Radix Themes) → thumb
curvature via --scroll-area-thumb-radius.
- scrollbars: 'vertical' | 'horizontal' | 'both' (Radix Themes) →
recipe-level sugar that auto-mounts Scrollbar / Thumb / Corner from
the root. Explicit composition still supported (omit the prop).
Bug fix — type='scroll' + horizontal sometimes stuck hidden:
- `mounted` on ScrollAreaScrollbarProvider is now $state. Previously
a plain field, so the `shouldShow` derived didn't invalidate when
the requestFrame mount-flag flipped during the first frame.
- The reveal-on-scroll $effect now skips its first run via a
`firstRun` flag. That first run was the subscription pass with
scrollTop/scrollLeft still 0 — it was eagerly calling show() and
setting `visible=true` before `mounted` flipped. Subsequent real
scrolls then assigned visible=true again (no-op), so shouldShow
didn't re-run and the bar stayed hidden until the hide timer
expired. Now the bar only reveals on genuine scroll deltas.
Demo: chip controls for size + radius, switched to scrollbars prop
on the root (drops the explicit Scrollbar/Thumb children), eidos
snippet shows the recipe-sugar form, soma snippet still shows the
explicit Radix-style composition.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- scroll-area soma: defer the mount-frame request to `$effect` so SSR
doesn't hit `dom::window_required` during constructor evaluation.
- scroll-area recipe: scrollbars now `position: absolute` (overlay
style) so the horizontal track lands at the viewport's block-end
instead of flowing below it. `:has` rules reserve corresponding edges
when both axes mount; corner switched to absolute as well.
- drawer demo: drop the ↑↓←→ glyph pop-outs and `overflow: visible`
during dragging. The handle's own pill grip is the affordance — the
same shape the splitter uses, no extra chrome.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 new layout primitives close the air port set (15 / 15 done).
`npm run component:audit`: 91 / 91 PASS, all 3 new PASS with 0 errors.
**scroll-area** — eidos compound wrapper over the existing soma:
`<ScrollArea><ScrollArea.Viewport>{content}</ScrollArea.Viewport>
<ScrollArea.Scrollbar orientation="vertical"><ScrollArea.Thumb />
</ScrollArea.Scrollbar><ScrollArea.Corner /></ScrollArea>`. Mirrors
Radix Primitives / Bits UI shape. Demo 667 lines.
**separator** — visual primitive (`scope: ['eidos']`) with conditional
ARIA: `role="separator"` + `aria-orientation` when not decorative,
`aria-hidden="true"` when decorative. New morfo
`src/uix/morfo/components/separator.ts`. Demo 645 lines.
**splitter** — eidos compound over existing soma:
`<Splitter orientation="horizontal"><Splitter.Panel>{a}</Splitter.Panel>
<Splitter.ResizeTrigger /><Splitter.Panel>{b}</Splitter.Panel>
</Splitter>`. Demo 824 lines.
**Splitter sema rewire — match Slider's handle/drag/commit shape:**
The morfo previously declared only `commit-resize`. Direct-manipulation
primitives (Slider, Splitter) should share the same event vocabulary so
audio/haptic projections feel coherent across the family. Renamed +
expanded to mirror Slider:
- `handle-pick` (family: handle, verb: pick, sequence: coincident,
target: resize-trigger) — fires on pointerdown when user grabs the
trigger.
- `handle-drag` (family: handle, verb: drag, sequence: coincident,
target: resize-trigger) — fires on each pointermove frame.
- `commit-set` (family: commit, verb: set, intent: neutral,
sequence: post, target: provider) — fires on pointerup. The runtime
`commit-set` handler is wired to call the consumer's `onResizeEnd`
callback, so sema and JS callback land at the same moment (parity
with Slider's `onValueCommit`).
Soma provider triggers these via `this.runtime.trigger(name)` in
`onpointerdown` / `onpointermove` / `notifyResizeEnd` (the latter
unchanged externally — internally now routes through the runtime
trigger).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>