Per the doctrine update in GUIA §13: eidos for multi-part components
exposes BOTH a flat default that auto-composes Provider/Trigger/Content
AND the compound parts for advanced cases. Soma + morfo remain the
universal composable foundation underneath.
Why: with the previous "compound only" rule for multi-part, eidos
collapsible was a pure pass-through that added nothing operational —
the consumer wrote the same import + same shape as soma. The flat
default makes eidos earn its layer by collapsing the 90% case to a
single call:
// 90% case — flat ergonomic
<Collapsible bind:open>
{#snippet trigger()}Show details{/snippet}
<p>Body content.</p>
</Collapsible>
// Advanced — compound (parts in different subtrees, multi-trigger,
// conditional content)
<header><Collapsible.Provider bind:open>
<Collapsible.Trigger>Show</Collapsible.Trigger>
</Collapsible.Provider></header>
<aside>
<Collapsible.Content>...</Collapsible.Content>
</aside>
The architectural virtue: if the flat doesn't fit, a developer drops
to soma + morfo and composes freely. No vendor lock-in in the visual
layer; eidos is the design system convention, soma is the universal
primitive.
Files:
- src/uix/eidos/components/collapsible/collapsible.svelte (NEW): flat
default that auto-composes Provider + Trigger + Content via a
`trigger` snippet for the toggle label and `children` for the body.
- src/uix/eidos/components/collapsible/types.ts: adds
`CollapsibleFlatProps = SomaCollapsibleProps & { trigger?: Snippet }`.
- src/uix/eidos/components/collapsible/index.ts: exports `default`
(flat) plus named `Provider`/`Trigger`/`Content` (compound).
- src/uix/eidos/components/collapsible/{trigger,content,provider}.svelte:
fixed children destructuring so snippets propagate cleanly to soma
(was previously spreading $props() blindly which can lose snippet
bindings in Svelte 5).
- src/docs/GUIA_IMPLEMENTACION_SEMAUIX.md: NEW §13 "Doctrina del API:
soma compound, eidos opinionado" formalises the two-shape rule and
the architectural virtue (soma+morfo as universal foundation).
Renumbered §13/§14 → §14/§15.
- web/routes/collapsible/+page.svelte: live preview now uses the flat
form; eidos snippet shows the flat shape; soma snippet keeps the
compound shape; Notes tab updated.
- src/uix/eidos/components/collapsible/README.md: rewrote API section
with both shapes + the "if neither fits, use soma+morfo" escape.
Tests 218/218 green. npm run check baseline 39.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The collapsible demo only rendered the eidos snippet, which made the
"compound shape is the same" doctrinal point invisible: a reader
couldn't see that soma and eidos expose the same multi-part API,
differing only in import path and what each layer guarantees.
Now both code blocks stack in the Live tab:
- soma: includes the `<script>` boilerplate (`let open = $state(false)`)
to make the headless/structural-only nature explicit
- eidos: same shape, different import, no setup boilerplate (consumer
binds open directly with `onOpenChange={handleChange}` for the demo
trace)
Per doctrine §10, only single-part components (toggle/switch) get a
flat default export — multi-part keeps compound on both layers, so the
two snippets share shape. That's correct. The DIFFERENCE is the import
path, the visible boilerplate, and what each layer adds (soma:
structural contract; eidos: same surface + recipe CSS).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>