@apostel/bedrock 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +216 -0
- package/dist/accessible-icon/parts.d.ts +16 -0
- package/dist/accessible-icon/parts.d.ts.map +1 -0
- package/dist/accessible-icon/parts.js +24 -0
- package/dist/accessible-icon/parts.js.map +1 -0
- package/dist/accordion/controlled-root.d.ts +19 -0
- package/dist/accordion/controlled-root.d.ts.map +1 -0
- package/dist/accordion/controlled-root.js +53 -0
- package/dist/accordion/controlled-root.js.map +1 -0
- package/dist/accordion/parts.d.ts +35 -0
- package/dist/accordion/parts.d.ts.map +1 -0
- package/dist/accordion/parts.js +52 -0
- package/dist/accordion/parts.js.map +1 -0
- package/dist/accordion/root.d.ts +24 -0
- package/dist/accordion/root.d.ts.map +1 -0
- package/dist/accordion/root.js +45 -0
- package/dist/accordion/root.js.map +1 -0
- package/dist/accordion/shared.d.ts +23 -0
- package/dist/accordion/shared.d.ts.map +1 -0
- package/dist/accordion/shared.js +16 -0
- package/dist/accordion/shared.js.map +1 -0
- package/dist/alert-dialog/parts.d.ts +16 -0
- package/dist/alert-dialog/parts.d.ts.map +1 -0
- package/dist/alert-dialog/parts.js +20 -0
- package/dist/alert-dialog/parts.js.map +1 -0
- package/dist/anchor.d.ts +27 -0
- package/dist/anchor.d.ts.map +1 -0
- package/dist/anchor.js +70 -0
- package/dist/anchor.js.map +1 -0
- package/dist/aspect-ratio/parts.d.ts +16 -0
- package/dist/aspect-ratio/parts.d.ts.map +1 -0
- package/dist/aspect-ratio/parts.js +15 -0
- package/dist/aspect-ratio/parts.js.map +1 -0
- package/dist/avatar/parts.d.ts +23 -0
- package/dist/avatar/parts.d.ts.map +1 -0
- package/dist/avatar/parts.js +51 -0
- package/dist/avatar/parts.js.map +1 -0
- package/dist/bedrock.css +64 -0
- package/dist/capabilities.d.ts +25 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +40 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/checkbox/controlled-root.d.ts +18 -0
- package/dist/checkbox/controlled-root.d.ts.map +1 -0
- package/dist/checkbox/controlled-root.js +28 -0
- package/dist/checkbox/controlled-root.js.map +1 -0
- package/dist/checkbox/parts.d.ts +29 -0
- package/dist/checkbox/parts.d.ts.map +1 -0
- package/dist/checkbox/parts.js +42 -0
- package/dist/checkbox/parts.js.map +1 -0
- package/dist/client-render.d.ts +10 -0
- package/dist/client-render.d.ts.map +1 -0
- package/dist/client-render.js +14 -0
- package/dist/client-render.js.map +1 -0
- package/dist/collapsible/controlled-root.d.ts +17 -0
- package/dist/collapsible/controlled-root.d.ts.map +1 -0
- package/dist/collapsible/controlled-root.js +21 -0
- package/dist/collapsible/controlled-root.js.map +1 -0
- package/dist/collapsible/parts.d.ts +14 -0
- package/dist/collapsible/parts.d.ts.map +1 -0
- package/dist/collapsible/parts.js +24 -0
- package/dist/collapsible/parts.js.map +1 -0
- package/dist/collapsible/root.d.ts +16 -0
- package/dist/collapsible/root.d.ts.map +1 -0
- package/dist/collapsible/root.js +28 -0
- package/dist/collapsible/root.js.map +1 -0
- package/dist/collapsible/shared.d.ts +11 -0
- package/dist/collapsible/shared.d.ts.map +1 -0
- package/dist/collapsible/shared.js +26 -0
- package/dist/collapsible/shared.js.map +1 -0
- package/dist/compose-refs.d.ts +29 -0
- package/dist/compose-refs.d.ts.map +1 -0
- package/dist/compose-refs.js +67 -0
- package/dist/compose-refs.js.map +1 -0
- package/dist/context-menu/root.d.ts +17 -0
- package/dist/context-menu/root.d.ts.map +1 -0
- package/dist/context-menu/root.js +50 -0
- package/dist/context-menu/root.js.map +1 -0
- package/dist/controlled.d.ts +120 -0
- package/dist/controlled.d.ts.map +1 -0
- package/dist/controlled.js +91 -0
- package/dist/controlled.js.map +1 -0
- package/dist/create-controlled-root.d.ts +29 -0
- package/dist/create-controlled-root.d.ts.map +1 -0
- package/dist/create-controlled-root.js +92 -0
- package/dist/create-controlled-root.js.map +1 -0
- package/dist/dialog/controlled-root.d.ts +15 -0
- package/dist/dialog/controlled-root.d.ts.map +1 -0
- package/dist/dialog/controlled-root.js +21 -0
- package/dist/dialog/controlled-root.js.map +1 -0
- package/dist/dialog/parts.d.ts +18 -0
- package/dist/dialog/parts.d.ts.map +1 -0
- package/dist/dialog/parts.js +80 -0
- package/dist/dialog/parts.js.map +1 -0
- package/dist/dialog/root.d.ts +22 -0
- package/dist/dialog/root.d.ts.map +1 -0
- package/dist/dialog/root.js +39 -0
- package/dist/dialog/root.js.map +1 -0
- package/dist/dialog/shared.d.ts +32 -0
- package/dist/dialog/shared.d.ts.map +1 -0
- package/dist/dialog/shared.js +53 -0
- package/dist/dialog/shared.js.map +1 -0
- package/dist/dropdown-menu/controlled-root.d.ts +7 -0
- package/dist/dropdown-menu/controlled-root.d.ts.map +1 -0
- package/dist/dropdown-menu/controlled-root.js +13 -0
- package/dist/dropdown-menu/controlled-root.js.map +1 -0
- package/dist/dropdown-menu/root.d.ts +13 -0
- package/dist/dropdown-menu/root.d.ts.map +1 -0
- package/dist/dropdown-menu/root.js +22 -0
- package/dist/dropdown-menu/root.js.map +1 -0
- package/dist/hover-card/controlled-root.d.ts +9 -0
- package/dist/hover-card/controlled-root.d.ts.map +1 -0
- package/dist/hover-card/controlled-root.js +15 -0
- package/dist/hover-card/controlled-root.js.map +1 -0
- package/dist/hover-card/root.d.ts +13 -0
- package/dist/hover-card/root.d.ts.map +1 -0
- package/dist/hover-card/root.js +19 -0
- package/dist/hover-card/root.js.map +1 -0
- package/dist/index.d.ts +274 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +211 -0
- package/dist/index.js.map +1 -0
- package/dist/interest.d.ts +30 -0
- package/dist/interest.d.ts.map +1 -0
- package/dist/interest.js +94 -0
- package/dist/interest.js.map +1 -0
- package/dist/label/parts.d.ts +14 -0
- package/dist/label/parts.d.ts.map +1 -0
- package/dist/label/parts.js +21 -0
- package/dist/label/parts.js.map +1 -0
- package/dist/menu/parts.d.ts +64 -0
- package/dist/menu/parts.d.ts.map +1 -0
- package/dist/menu/parts.js +131 -0
- package/dist/menu/parts.js.map +1 -0
- package/dist/menu/shared.d.ts +7 -0
- package/dist/menu/shared.d.ts.map +1 -0
- package/dist/menu/shared.js +9 -0
- package/dist/menu/shared.js.map +1 -0
- package/dist/menubar/parts.d.ts +20 -0
- package/dist/menubar/parts.d.ts.map +1 -0
- package/dist/menubar/parts.js +34 -0
- package/dist/menubar/parts.js.map +1 -0
- package/dist/navigation-menu/parts.d.ts +28 -0
- package/dist/navigation-menu/parts.d.ts.map +1 -0
- package/dist/navigation-menu/parts.js +46 -0
- package/dist/navigation-menu/parts.js.map +1 -0
- package/dist/open-state.d.ts +23 -0
- package/dist/open-state.d.ts.map +1 -0
- package/dist/open-state.js +106 -0
- package/dist/open-state.js.map +1 -0
- package/dist/popover/controlled-root.d.ts +14 -0
- package/dist/popover/controlled-root.d.ts.map +1 -0
- package/dist/popover/controlled-root.js +17 -0
- package/dist/popover/controlled-root.js.map +1 -0
- package/dist/popover/parts.d.ts +27 -0
- package/dist/popover/parts.d.ts.map +1 -0
- package/dist/popover/parts.js +39 -0
- package/dist/popover/parts.js.map +1 -0
- package/dist/popover/root.d.ts +24 -0
- package/dist/popover/root.d.ts.map +1 -0
- package/dist/popover/root.js +24 -0
- package/dist/popover/root.js.map +1 -0
- package/dist/popover/shared.d.ts +22 -0
- package/dist/popover/shared.d.ts.map +1 -0
- package/dist/popover/shared.js +25 -0
- package/dist/popover/shared.js.map +1 -0
- package/dist/progress/parts.d.ts +25 -0
- package/dist/progress/parts.d.ts.map +1 -0
- package/dist/progress/parts.js +32 -0
- package/dist/progress/parts.js.map +1 -0
- package/dist/radio-group/controlled-root.d.ts +19 -0
- package/dist/radio-group/controlled-root.d.ts.map +1 -0
- package/dist/radio-group/controlled-root.js +29 -0
- package/dist/radio-group/controlled-root.js.map +1 -0
- package/dist/radio-group/parts.d.ts +36 -0
- package/dist/radio-group/parts.d.ts.map +1 -0
- package/dist/radio-group/parts.js +62 -0
- package/dist/radio-group/parts.js.map +1 -0
- package/dist/roving.d.ts +26 -0
- package/dist/roving.d.ts.map +1 -0
- package/dist/roving.js +124 -0
- package/dist/roving.js.map +1 -0
- package/dist/scroll-area/parts.d.ts +29 -0
- package/dist/scroll-area/parts.d.ts.map +1 -0
- package/dist/scroll-area/parts.js +44 -0
- package/dist/scroll-area/parts.js.map +1 -0
- package/dist/select/parts.d.ts +57 -0
- package/dist/select/parts.d.ts.map +1 -0
- package/dist/select/parts.js +76 -0
- package/dist/select/parts.js.map +1 -0
- package/dist/separator/parts.d.ts +14 -0
- package/dist/separator/parts.d.ts.map +1 -0
- package/dist/separator/parts.js +15 -0
- package/dist/separator/parts.js.map +1 -0
- package/dist/slider/parts.d.ts +32 -0
- package/dist/slider/parts.d.ts.map +1 -0
- package/dist/slider/parts.js +52 -0
- package/dist/slider/parts.js.map +1 -0
- package/dist/slot.d.ts +3 -0
- package/dist/slot.d.ts.map +1 -0
- package/dist/slot.js +49 -0
- package/dist/slot.js.map +1 -0
- package/dist/switch/parts.d.ts +21 -0
- package/dist/switch/parts.d.ts.map +1 -0
- package/dist/switch/parts.js +31 -0
- package/dist/switch/parts.js.map +1 -0
- package/dist/tabs/controlled-root.d.ts +11 -0
- package/dist/tabs/controlled-root.d.ts.map +1 -0
- package/dist/tabs/controlled-root.js +15 -0
- package/dist/tabs/controlled-root.js.map +1 -0
- package/dist/tabs/parts.d.ts +20 -0
- package/dist/tabs/parts.d.ts.map +1 -0
- package/dist/tabs/parts.js +42 -0
- package/dist/tabs/parts.js.map +1 -0
- package/dist/tabs/root.d.ts +15 -0
- package/dist/tabs/root.d.ts.map +1 -0
- package/dist/tabs/root.js +26 -0
- package/dist/tabs/root.js.map +1 -0
- package/dist/tabs/shared.d.ts +12 -0
- package/dist/tabs/shared.d.ts.map +1 -0
- package/dist/tabs/shared.js +11 -0
- package/dist/tabs/shared.js.map +1 -0
- package/dist/toast/parts.d.ts +40 -0
- package/dist/toast/parts.d.ts.map +1 -0
- package/dist/toast/parts.js +102 -0
- package/dist/toast/parts.js.map +1 -0
- package/dist/toggle/controlled-root.d.ts +9 -0
- package/dist/toggle/controlled-root.d.ts.map +1 -0
- package/dist/toggle/controlled-root.js +14 -0
- package/dist/toggle/controlled-root.js.map +1 -0
- package/dist/toggle/parts.d.ts +20 -0
- package/dist/toggle/parts.d.ts.map +1 -0
- package/dist/toggle/parts.js +29 -0
- package/dist/toggle/parts.js.map +1 -0
- package/dist/toggle-group/parts.d.ts +28 -0
- package/dist/toggle-group/parts.d.ts.map +1 -0
- package/dist/toggle-group/parts.js +57 -0
- package/dist/toggle-group/parts.js.map +1 -0
- package/dist/toolbar/parts.d.ts +22 -0
- package/dist/toolbar/parts.d.ts.map +1 -0
- package/dist/toolbar/parts.js +27 -0
- package/dist/toolbar/parts.js.map +1 -0
- package/dist/tooltip/controlled-root.d.ts +9 -0
- package/dist/tooltip/controlled-root.d.ts.map +1 -0
- package/dist/tooltip/controlled-root.js +15 -0
- package/dist/tooltip/controlled-root.js.map +1 -0
- package/dist/tooltip/parts.d.ts +23 -0
- package/dist/tooltip/parts.d.ts.map +1 -0
- package/dist/tooltip/parts.js +28 -0
- package/dist/tooltip/parts.js.map +1 -0
- package/dist/tooltip/root.d.ts +13 -0
- package/dist/tooltip/root.d.ts.map +1 -0
- package/dist/tooltip/root.js +17 -0
- package/dist/tooltip/root.js.map +1 -0
- package/dist/tooltip/shared.d.ts +13 -0
- package/dist/tooltip/shared.d.ts.map +1 -0
- package/dist/tooltip/shared.js +9 -0
- package/dist/tooltip/shared.js.map +1 -0
- package/dist/tooltip/use-controlled-interest-root.d.ts +19 -0
- package/dist/tooltip/use-controlled-interest-root.d.ts.map +1 -0
- package/dist/tooltip/use-controlled-interest-root.js +31 -0
- package/dist/tooltip/use-controlled-interest-root.js.map +1 -0
- package/dist/tooltip/use-interest-root.d.ts +16 -0
- package/dist/tooltip/use-interest-root.d.ts.map +1 -0
- package/dist/tooltip/use-interest-root.js +39 -0
- package/dist/tooltip/use-interest-root.js.map +1 -0
- package/dist/types.d.ts +55 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/validate-element.d.ts +12 -0
- package/dist/validate-element.d.ts.map +1 -0
- package/dist/validate-element.js +21 -0
- package/dist/validate-element.js.map +1 -0
- package/dist/validate-trigger.d.ts +14 -0
- package/dist/validate-trigger.d.ts.map +1 -0
- package/dist/validate-trigger.js +59 -0
- package/dist/validate-trigger.js.map +1 -0
- package/dist/visually-hidden/parts.d.ts +12 -0
- package/dist/visually-hidden/parts.d.ts.map +1 -0
- package/dist/visually-hidden/parts.js +25 -0
- package/dist/visually-hidden/parts.js.map +1 -0
- package/package.json +81 -0
- package/skills/migrate-to-bedrock/SKILL.md +188 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: migrate-to-bedrock
|
|
3
|
+
description: Migrate a React codebase from Radix UI primitives to @apostel/bedrock. Use when the user asks to migrate off Radix, replace @radix-ui/react-* imports, adopt bedrock, or move a shadcn/ui project onto native platform primitives. Also use when asked why a bedrock trigger throws, why a dialog no longer closes on backdrop click, or why data-state selectors stopped matching.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Migrating from Radix to bedrock
|
|
7
|
+
|
|
8
|
+
bedrock is Radix-**shaped**: same compound components, same part names, same
|
|
9
|
+
`asChild`. It is built on the top layer, invoker commands, anchor positioning
|
|
10
|
+
and native form controls instead of on JavaScript that reimplements them.
|
|
11
|
+
|
|
12
|
+
That means most of a migration is mechanical, and the parts that are not are
|
|
13
|
+
concentrated in four places. Do the mechanical work first; the four judgement
|
|
14
|
+
calls are what the user needs to actually decide.
|
|
15
|
+
|
|
16
|
+
**Before touching anything, read `docs/gaps.md` in the bedrock repo or at
|
|
17
|
+
<https://bedrock.sams.land/gaps.html> and tell the user what applies to them.**
|
|
18
|
+
Three of the items there stop migrations dead, and finding that out after a
|
|
19
|
+
half-finished refactor is worse than finding out first.
|
|
20
|
+
|
|
21
|
+
## Step 0 — establish whether this is viable
|
|
22
|
+
|
|
23
|
+
Check these before writing any code. Report what you find; do not decide alone.
|
|
24
|
+
|
|
25
|
+
| check | how | if yes |
|
|
26
|
+
| --- | --- | --- |
|
|
27
|
+
| jsdom component tests that click a trigger | `rg -l 'render\(' --glob '*.test.*'` and look for dialog/menu interaction | **This is the big one.** jsdom has no invoker commands, so those clicks do nothing. Every such test needs rewriting against a real browser. Say so before anything else. |
|
|
28
|
+
| triggers that are not `<button>` | `rg -B2 'Trigger asChild' -A3` | Each one is a build error at mount, not a warning. Router `<Link>` inside a `Dialog.Trigger` is the most common. |
|
|
29
|
+
| `data-state` in CSS, Tailwind config, or shared utilities | `rg 'data-state' --glob '!node_modules'` | Repo-wide selector change. `:open` cannot select an ancestor. |
|
|
30
|
+
| overlays with content in them | `rg -A5 'Dialog.Overlay\|AlertDialog.Overlay'` | `::backdrop` is a pseudo-element. A spinner or close button inside the overlay is a redesign. |
|
|
31
|
+
|
|
32
|
+
If the project has hundreds of jsdom component tests and no Playwright setup,
|
|
33
|
+
that cost dwarfs everything else. Say that plainly rather than starting.
|
|
34
|
+
|
|
35
|
+
## Step 1 — mechanical changes
|
|
36
|
+
|
|
37
|
+
Safe to apply across the repo.
|
|
38
|
+
|
|
39
|
+
```diff
|
|
40
|
+
-import * as Dialog from '@radix-ui/react-dialog'
|
|
41
|
+
+import { Dialog } from '@apostel/bedrock'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Then, inside the tree:
|
|
45
|
+
|
|
46
|
+
| Radix | bedrock | why |
|
|
47
|
+
| --- | --- | --- |
|
|
48
|
+
| `<X.Portal>` | delete the wrapper, keep its children | The top layer means there is nothing to portal past. |
|
|
49
|
+
| `<X.Overlay className="…" />` | delete it; move the classes to `backdrop:` on Content | The overlay is `::backdrop`. |
|
|
50
|
+
| `[data-state="open"]` | `:open` | Native state, no JS mirror. |
|
|
51
|
+
| `[data-state="closed"]` | `:not(:open)` | |
|
|
52
|
+
| `[data-state="checked"]` | `:checked` | |
|
|
53
|
+
| `[data-state="on"]` | `[aria-pressed="true"]` | Toggle and ToggleGroup. |
|
|
54
|
+
| `forceMount` | delete it | Content unmounts when closed and there is no opt-out. Check what depended on it. |
|
|
55
|
+
| `data-[state=open]:animate-in` | `open:` + `starting:` + `transition-discrete` | Tailwind 4 has all three built in. |
|
|
56
|
+
|
|
57
|
+
For animation, the shape is always the same:
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
className="
|
|
61
|
+
scale-95 opacity-0 transition-all transition-discrete duration-150
|
|
62
|
+
open:scale-100 open:opacity-100
|
|
63
|
+
starting:open:scale-95 starting:open:opacity-0
|
|
64
|
+
"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`transition-discrete` is what keeps the element displayed while it fades out;
|
|
68
|
+
without it the exit is skipped. On a top-layer element also transition
|
|
69
|
+
`overlay`, or the exit plays *underneath* whatever was above it.
|
|
70
|
+
|
|
71
|
+
## Step 2 — the four judgement calls
|
|
72
|
+
|
|
73
|
+
Do not resolve these silently. Each one changes behaviour a user will notice.
|
|
74
|
+
|
|
75
|
+
### Triggers must be buttons
|
|
76
|
+
|
|
77
|
+
Radix attaches a click handler to whatever you give it. bedrock does not, and
|
|
78
|
+
throws at mount in development.
|
|
79
|
+
|
|
80
|
+
```diff
|
|
81
|
+
-<Dialog.Trigger asChild><Link href="/upgrade">Upgrade</Link></Dialog.Trigger>
|
|
82
|
+
+<Dialog.Trigger asChild><button type="button" onClick={…}>Upgrade</button></Dialog.Trigger>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The second most common failure is subtler: a `<button>` inside a `<form>`
|
|
86
|
+
defaults to `type="submit"`, and the browser ignores `commandfor` on a submit
|
|
87
|
+
button. Add `type="button"`.
|
|
88
|
+
|
|
89
|
+
If the element genuinely cannot change — a third-party component that renders a
|
|
90
|
+
`div` — `useDialogTrigger()` hands over the props and the accessibility
|
|
91
|
+
responsibility. Use it as a last resort and say so in a comment.
|
|
92
|
+
|
|
93
|
+
### Light dismiss is gone
|
|
94
|
+
|
|
95
|
+
A modal `<dialog>` does not close on a backdrop click. Users report this as "the
|
|
96
|
+
dialog is stuck". Restore it per dialog if the product wants it:
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
<Dialog.Content {...{ closedby: 'any' }} />
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Ask before applying it globally — for a destructive confirmation, *not*
|
|
103
|
+
dismissing on an outside click is usually the better behaviour.
|
|
104
|
+
|
|
105
|
+
### `onOpenChange` on the default root cannot refuse
|
|
106
|
+
|
|
107
|
+
It is a `toggle` listener: it reports, it cannot decline.
|
|
108
|
+
|
|
109
|
+
Grep for handlers that conditionally avoid calling `setOpen` — an
|
|
110
|
+
unsaved-changes guard, a "are you sure" interstitial. Those roots, and only
|
|
111
|
+
those, move to the controlled import:
|
|
112
|
+
|
|
113
|
+
```diff
|
|
114
|
+
-import { Dialog } from '@apostel/bedrock'
|
|
115
|
+
+import { Dialog } from '@apostel/bedrock/controlled'
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Everything else keeps the smaller bundle. A handler that just resets a form or
|
|
119
|
+
fires analytics is served by the default root.
|
|
120
|
+
|
|
121
|
+
### Closed content is unmounted
|
|
122
|
+
|
|
123
|
+
This is usually a *win* — a form inside a dialog resets itself, and any
|
|
124
|
+
`onOpenChange` handler that existed only to reset state can be deleted. Look for
|
|
125
|
+
those and remove them; that is the cleanup the migration pays for.
|
|
126
|
+
|
|
127
|
+
It bites in two places: content that was measured while closed, and an
|
|
128
|
+
animation library driving presence. Both need the state hoisting above the
|
|
129
|
+
dialog.
|
|
130
|
+
|
|
131
|
+
## Step 3 — per-primitive notes
|
|
132
|
+
|
|
133
|
+
Only what actually differs. Everything not listed is a straight swap.
|
|
134
|
+
|
|
135
|
+
- **Accordion** — `type="single"` is `<details name>`, so an open item can
|
|
136
|
+
always be closed; Radix's `collapsible={false}` has no equivalent. `Header`
|
|
137
|
+
renders the `<summary>` and `Trigger` sits inside it.
|
|
138
|
+
- **Checkbox, Switch, RadioGroup, Slider, Progress** — real elements, so
|
|
139
|
+
`Indicator`, `Thumb`, `Track` and `Range` render nothing. Their styles move to
|
|
140
|
+
`::before`, `::-webkit-slider-thumb`, `::-webkit-progress-value`. Watch for
|
|
141
|
+
icon *components* inside those parts: an `<input>` has no children, so a
|
|
142
|
+
`<CheckIcon />` inside a checkbox has nowhere to go and becomes CSS.
|
|
143
|
+
- **Slider** — one thumb. A two-thumb range has no native equivalent; flag it.
|
|
144
|
+
- **Select** — a real `<select>`. `Select.Value` is `<selectedcontent>`, so
|
|
145
|
+
there is no `placeholder` render prop. On phones this gets the OS picker,
|
|
146
|
+
which is usually desirable and occasionally a design regression.
|
|
147
|
+
- **Tabs** — the unselected panel is unmounted rather than hidden.
|
|
148
|
+
- **Tooltip / HoverCard** — no `Provider`; the delay is a prop on the root. The
|
|
149
|
+
trigger may be an `<a>`.
|
|
150
|
+
- **Menus** — submenus need no configuration, and Escape closes only the topmost
|
|
151
|
+
layer. If the code has layer-ordering workarounds, delete them.
|
|
152
|
+
- **NavigationMenu** — `Viewport` renders nothing.
|
|
153
|
+
|
|
154
|
+
## Step 4 — verify
|
|
155
|
+
|
|
156
|
+
1. `npx tsc --noEmit` — the prop-level differences surface here.
|
|
157
|
+
2. Run the app and open every migrated overlay **in a browser**. The dev throw
|
|
158
|
+
for a bad trigger only fires when the component actually mounts, so a trigger
|
|
159
|
+
behind a rare branch will not appear until it renders.
|
|
160
|
+
3. Check the console for bedrock warnings: they name the pseudo-element to
|
|
161
|
+
style instead of the part that now renders nothing.
|
|
162
|
+
4. If the project has jsdom tests for these components, they are now testing
|
|
163
|
+
nothing. Either port them to Playwright or delete them — leaving them green
|
|
164
|
+
and meaningless is the worst outcome.
|
|
165
|
+
|
|
166
|
+
## shadcn/ui projects
|
|
167
|
+
|
|
168
|
+
There is a registry, so most components are one command rather than a rewrite:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
npx shadcn@latest add https://bedrock.sams.land/r/dialog.json
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
24 items cover everything that was Radix-backed except `menubar`,
|
|
175
|
+
`navigation-menu`, `toast`, `sheet` and `drawer`. Commit before running it — the
|
|
176
|
+
CLI overwrites `components/ui/*.tsx`, and the diff is the thing worth reading.
|
|
177
|
+
|
|
178
|
+
Note that `dialog` from the registry is the **uncontrolled** build and has no
|
|
179
|
+
`open` prop; it throws in development telling you to install
|
|
180
|
+
`dialog-controlled` instead. Install whichever the app actually uses.
|
|
181
|
+
|
|
182
|
+
## What to tell the user at the end
|
|
183
|
+
|
|
184
|
+
- which files changed, and which of the four judgement calls you applied
|
|
185
|
+
- any trigger you could not fix without changing an element they own
|
|
186
|
+
- whether their tests still test anything
|
|
187
|
+
- the measured bundle difference, if they care: it is in the bedrock README per
|
|
188
|
+
primitive, and it is not uniform — menus save far less than dialogs do
|