feat(react)!: headless hooks and a shadcn registry for the flow (#113)
`@domainkit/react` becomes headless and the styled flow moves to the
DomainKit
shadcn registry, so a host application's own buttons, dialogs, tables,
and
badges render the domain setup DomainKit drives.
Integrating the painted components into a real dashboard went badly: the
provider logo was double-wrapped, the connection header was a grey panel
beside
the records card, the ready state collapsed to one line, the table cells
did not
line up, and a host could restyle a part but never hand the library its
own
Button. The fix is a split rather than five patches.
## What changes
- **Headless package.** Every component, the `data-domainkit-part`
vocabulary,
`styles.css`, the theme tokens, the icon set, and `Provider.Mark` are
gone.
What ships is hooks: `Domain.useFlow`, the four controllers, `useZones`,
`useAccounts`, `useDomainField`, `Records.statusOf`, the zone-file
helpers,
`useCopy`, `Messages`, `Outcome.describe`, and `Testing`. The package no
longer depends on `@base-ui/react` and exports no CSS.
- **Read-only is a fact.** `FlowState.readOnly` rides on the flow, so a
surface
says "An administrator can connect Cloudflare" instead of rendering
nothing.
- **The registry is the styled path.** `provider-row`, `connect-dialog`,
`records-table`, `plan-action`, `outcome`, `domain-field`, and
`disconnect-dialog` land as registry components, and a `domain-flow`
block
composes them on `Domain.useFlow`, on the Base UI variant both the docs
preview kit and the target host already use.
- **The shape the screenshots asked for.** The provider row heads the
records
card with the one action on the right and Disconnect behind the row's
menu.
Ready keeps the row and the full table with no toggle. Table cells align
middle. The mark is the host's node with no tile around it.
## What it looks like
Sixteen states of the `domain-flow` block, captured against
`Testing.transport` at `86053e2`, on
the docs preview kit: **[the
gallery](https://claude.ai/code/artifact/2f20b368-eb8a-4038-bb74-fef9abc4695c)**.
The host side of the same overhaul is
[Samva's
gallery](https://claude.ai/code/artifact/6c27f79d-07d5-4d4b-aa74-4acadc162681).
The flow, in the order a customer meets it:
1. **Host detected** — discovery names the provider serving the zone,
and the row offers Connect.
2. **Plan** — connecting builds the plan, the rows say "Will add", and
one press adds all three.
3. **A record in the way** — a conflict is not a write, so the action
offers the rest and the row
underneath says what is in the way and what to do about it.
4. **Applying** — approve and apply are one press, so there is one thing
to watch.
5. **After the apply** — "3 added", counted off the receipt that proves
what was written.
6. **Ready** — the row and the full table, every record Found. Nothing
collapses behind a toggle.
7. **Read-only** — "An administrator can connect Meridian DNS" where a
trigger would be.
The two decisions:
8. **Connect dialog** — narrowed to the provider that serves the zone,
its interactive method first.
9. **Token form** — one input per declared field, one control away from
the offer, with a way back.
10. **Refused token** — the provider answered the secret, so the answer
sits beside that field and
the typed value survives it.
11. **Disconnect dialog** — releasing the provider and removing what
DomainKit added as one
decision, with the exact records on screen while the customer decides.
Adding a domain:
12. **Zones** — every zone the workspace's accounts reach.
13. **Filtering** — typing narrows the list.
14. **Completed** — Tab kept the subdomain in front of the zone, and the
line names the account.
15. **Outside every zone** — a plain text field, because those records
are added by hand.
16. **Nothing connected** — the field offers the provider instead of an
empty list.
Against the 0.11 screenshots this replaces: the mark is one squircle
rather than a circle inside a
tile, the connection is a row heading the records card rather than a
grey panel beside it, ready
keeps its table, the DKIM value truncates instead of running eleven
lines, and the status column
lines up with the type and the name.
## Validation
`bun run typecheck && bun run test && bun run lint && bun run
format:check`,
`bun run typecheck:examples`, the docs app's test, build, and audit, and
`bun run release:check && bun run tegami preview`.
https://claude.ai/code/session_017P54ng7iisz1dsk18u1w1x S
Saatvik Arya committed
df50033361e76a0fda3515801f050778db18e70f
Parent: 5ded294
Committed by GitHub <noreply@github.com>
on 9/5/2026, 9:41:35 AM