Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
# Wave 3 Component Reconciliation
**Date**: 2026-05-05
**Date locked into proposal**: 2026-05-05T06:54:49+01:00
**Source**: `npx shadcn@latest search @shadcn --limit 1000` (registry version `shadcn@4.6.0`, captured 2026-05-05)
**Live shadcn `registry:ui` count**: 56 components
## Summary
The live `@shadcn` registry exposes **56** `registry:ui` items. The proposal's provisional 8-batch table listed **63** components. Reconciling the two:
- **Direct match** (53 components): every item in batches 3a, 3b (minus `Field` which existed but as separate entry), 3c, 3d (minus `StatusBadge`/`Empty` which need separate notes), 3e, 3f, 3g (minus `ConfirmDeleteDialog`/`ErrorBoundary`/`ThemeToggle` — see notes), 3h (minus `MultiSelect`/`SearchableSelect`/`MoneyInput`/`LanguagePicker`).
- **Split / renamed in upstream**: `Combobox` is a separate item in shadcn (good — confirms cross-cutting design §3.4 hint was wrong; we keep `Combobox` as a discrete component, NOT folded into `Select`). `Field` ships as `field` — confirms the form-primitives split.
- **Suaveplan-only additions** (10 components): `StatusBadge`, `Empty` (now exists upstream as `empty`), `ConfirmDeleteDialog`, `ErrorBoundary`, `ThemeToggle`, `MultiSelect`, `SearchableSelect`, `MoneyInput`, `LanguagePicker`, `FieldGroup` (shadcn ships `field` + `field-group` separately — `field-group` exists, mapped to our `FieldGroup`).
- **Upstream additions we should consider for future batches** (5 components): `button-group`, `direction`, `kbd`, `native-select`, `spinner` (already in 3d), `form` (legacy alias — `react-forms` will provide; we do NOT ship a `Form` component in `react-ui`).
## Reconciled batch table
| Component | Proposal Batch | Live shadcn | Action | Notes |
|---|---|---|---|---|
| Button | 3a | exists (`button`) | implement | direct shadcn parity |
| Input | 3a | exists (`input`) | implement | direct shadcn parity |
| Label | 3a | exists (`label`) | implement | wraps `@radix-ui/react-label` |
| Separator | 3a | exists (`separator`) | implement | wraps `@radix-ui/react-separator` |
| Skeleton | 3a | exists (`skeleton`) | implement | direct shadcn parity |
| FieldGroup | 3b | exists (`field-group`) | implement in 3b | shadcn separates `field` + `field-group` |
| Field | 3b | exists (`field`) | implement in 3b | direct match |
| FieldSet | 3b | renamed → component split | implement in 3b | shadcn folds into `field` (`Field.Set`); we keep distinct primitive |
| InputGroup | 3b | exists (`input-group`) | implement in 3b | direct match |
| Textarea | 3b | exists (`textarea`) | implement in 3b | direct match |
| Checkbox | 3b | exists (`checkbox`) | implement in 3b | direct match |
| Switch | 3b | exists (`switch`) | implement in 3b | direct match |
| RadioGroup | 3b | exists (`radio-group`) | implement in 3b | direct match |
| Toggle | 3b | exists (`toggle`) | implement in 3b | direct match |
| ToggleGroup | 3b | exists (`toggle-group`) | implement in 3b | direct match |
| Dialog | 3c | exists (`dialog`) | implement in 3c | direct match |
| Sheet | 3c | exists (`sheet`) | implement in 3c | direct match |
| Drawer | 3c | exists (`drawer`) | implement in 3c | wraps `vaul` |
| AlertDialog | 3c | exists (`alert-dialog`) | implement in 3c | direct match |
| Popover | 3c | exists (`popover`) | implement in 3c | direct match |
| HoverCard | 3c | exists (`hover-card`) | implement in 3c | direct match |
| Tooltip | 3c | exists (`tooltip`) | implement in 3c | direct match |
| ContextMenu | 3c | exists (`context-menu`) | implement in 3c | direct match |
| Table | 3d | exists (`table`) | implement in 3d | direct match |
| DataTable | 3d | NOT in @shadcn (consumer-built) | implement in 3d | suaveplan addition; shadcn docs ship as recipe, not registry item |
| Card | 3d | exists (`card`) | implement in 3d | direct match |
| Badge | 3d | exists (`badge`) | implement in 3d | direct match |
| StatusBadge | 3d | NOT in @shadcn | implement in 3d | suaveplan addition; Zod-validated state surface |
| Avatar | 3d | exists (`avatar`) | implement in 3d | direct match |
| Alert | 3d | exists (`alert`) | implement in 3d | direct match |
| Empty | 3d | exists (`empty`) | implement in 3d | direct match — proposal listed this; confirmed live |
| Progress | 3d | exists (`progress`) | implement in 3d | direct match |
| Spinner | 3d | exists (`spinner`) | implement in 3d | direct match — proposal listed this; confirmed live |
| Sidebar | 3e | exists (`sidebar`) | implement in 3e | direct match; per AGENTS.md §3 needs sub-components to stay <300 lines |
| NavigationMenu | 3e | exists (`navigation-menu`) | implement in 3e | direct match |
| Breadcrumb | 3e | exists (`breadcrumb`) | implement in 3e | direct match |
| Tabs | 3e | exists (`tabs`) | implement in 3e | direct match |
| Pagination | 3e | exists (`pagination`) | implement in 3e | direct match; chevron-swap under `useDirection() === 'rtl'` |
| Menubar | 3e | exists (`menubar`) | implement in 3e | direct match |
| DropdownMenu | 3e | exists (`dropdown-menu`) | implement in 3e | direct match |
| Command | 3e | exists (`command`) | implement in 3e | direct match; emits `command.select` span |
| Accordion | 3f | exists (`accordion`) | implement in 3f | direct match |
| Collapsible | 3f | exists (`collapsible`) | implement in 3f | direct match |
| Resizable | 3f | exists (`resizable`) | implement in 3f | wraps `react-resizable-panels` |
| ScrollArea | 3f | exists (`scroll-area`) | implement in 3f | direct match |
| AspectRatio | 3f | exists (`aspect-ratio`) | implement in 3f | direct match |
| Carousel | 3f | exists (`carousel`) | implement in 3f | wraps `embla-carousel-react` |
| Sonner | 3g | exists (`sonner`) | implement in 3g | direct match; replaces legacy `Toast`/`Toaster` |
| ConfirmDeleteDialog | 3g | NOT in @shadcn | implement in 3g | suaveplan addition; specialised dialog |
| ErrorBoundary | 3g | NOT in @shadcn | implement in 3g | suaveplan addition; declarative React 19 boundary |
| ThemeToggle | 3g | NOT in @shadcn | implement in 3g | suaveplan addition; bound `<ThemeSwitcher>` |
| Calendar | 3h | exists (`calendar`) | implement in 3h | wraps `react-day-picker` |
| DatePicker | 3h | NOT in @shadcn (recipe only) | implement in 3h | shadcn docs as `Calendar + Popover`; we ship as a discrete component |
| Select | 3h | exists (`select`) | implement in 3h | direct match |
| MultiSelect | 3h | NOT in @shadcn | implement in 3h | suaveplan addition |
| Combobox | 3h | NOT in @shadcn registry as discrete UI item; ships as recipe (`command + popover`) | implement in 3h | suaveplan ships discrete component (cross-cutting design §3.4 hint REJECTED — we keep distinct from `Select`) |
| SearchableSelect | 3h | NOT in @shadcn | implement in 3h | suaveplan addition |
| Slider | 3h | exists (`slider`) | implement in 3h | direct match |
| InputOTP | 3h | exists (`input-otp`) | implement in 3h | wraps `input-otp` |
| Chart | 3h | exists (`chart`) | implement in 3h | wraps `recharts` |
| MoneyInput | 3h | NOT in @shadcn | implement in 3h | suaveplan addition; consumes `@suaveplan/i18n` formatters |
| LanguagePicker | 3h | NOT in @shadcn | implement in 3h | suaveplan addition; reads `@suaveplan/locale-data` |
| Item | 3h | exists (`item`) | implement in 3h | direct match |
## Findings to flag for later batches
1. **`Field`/`FieldGroup`/`FieldSet` split** (Wave 3b): shadcn ships `field` and `field-group` as discrete registry items. The `FieldSet` primitive in our proposal has no upstream peer — we ship it as a suaveplan addition. The Wave 3b implementer should mirror the shadcn `field` + `field-group` API where possible, then layer `FieldSet` as an additive primitive (`<fieldset>` semantics + label aggregation).
2. **`Combobox` is NOT folded into `Select`** (Wave 3h): the cross-cutting design §3.4 hinted at a possible fold; the live registry ships `Combobox` as a recipe (`command + popover`). We ship `Combobox` as a discrete component with the same props surface so consumers do not need to compose recipes themselves. `MultiSelect` and `SearchableSelect` are suaveplan-only additions atop the same recipe.
3. **`button-group` and `kbd` exist upstream but are NOT in the proposal's 8-batch table** (post-Wave 3): both are useful primitives. The proposal's count is locked at 63 for the v1 ship; `button-group` and `kbd` are deferred to a v1.1 follow-up change. No Wave 3 work needed.
4. **`direction` and `native-select` exist upstream but are out-of-scope** (post-Wave 3): `direction` is a Radix re-export (we already use `@radix-ui/react-direction` directly via the chassis `useDirection` hook); `native-select` is shadcn's bare-`<select>` wrapper which we deliberately replace with `Select` (Radix-backed) for a11y and styling consistency. Both deferred indefinitely.
5. **`form` ships in shadcn as the `react-hook-form`-bound wrapper**: per the proposal, this is **owned by `@suaveplan/react-forms`** (sibling change `enterprise-react-forms-v2`), NOT by `react-ui`. We deliberately do NOT add `form` to any react-ui batch; the form factory's `react-hook-form` + Zod-resolvers dep weight is incompatible with consumers wanting only a Button.
6. **`Empty` and `Spinner` already exist upstream** (Wave 3d): the proposal listed both as suaveplan additions in 3d — they have since landed in `@shadcn` as discrete items. Wave 3d implementer should mirror the upstream shape rather than invent; tag the implementation notes accordingly.
7. **`StatusBadge`, `DataTable`, `MoneyInput`, `LanguagePicker`, `MultiSelect`, `SearchableSelect`, `ConfirmDeleteDialog`, `ErrorBoundary`, `ThemeToggle`** are all suaveplan-only additions. Wave 3d/3g/3h implementers should NOT search for upstream peers; they should ship these as documented chassis-native components and emit registry items into `registry/r/` so external consumers can `npx shadcn@latest add @suaveplan/<name>` against `https://ui.suaveplan.com/r/`.
## Lock-in note
The §"Component count — resolved here" table in `proposal.md` is hereby **locked at 63 components** for the v1 ship. Changes to this list require a follow-up OpenSpec change (NOT an amendment to this proposal), per the proposal's §"Component count — resolved here" gate.
The Wave 3a implementation (this commit) ships the 5 Foundation components — Button, Input, Label, Separator, Skeleton — independent of the reconciliation findings above (they are stable across every shadcn version and live in `@shadcn` as direct matches).