@octanejs/shadcn 0.0.7 → 0.0.9
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/README.md +170 -3
- package/package.json +46 -7
- package/src/bases/base-ui/ui/accordion.tsrx +71 -0
- package/src/bases/base-ui/ui/alert-dialog.tsrx +149 -0
- package/src/bases/base-ui/ui/alert.tsrx +68 -0
- package/src/bases/base-ui/ui/aspect-ratio.tsrx +24 -0
- package/src/bases/base-ui/ui/avatar.tsrx +89 -0
- package/src/bases/base-ui/ui/badge.tsrx +56 -0
- package/src/bases/base-ui/ui/breadcrumb.tsrx +109 -0
- package/src/bases/base-ui/ui/button.tsrx +69 -0
- package/src/bases/base-ui/ui/card.tsrx +76 -0
- package/src/bases/base-ui/ui/checkbox.tsrx +43 -0
- package/src/bases/base-ui/ui/collapsible.tsrx +25 -0
- package/src/bases/base-ui/ui/dialog.tsrx +137 -0
- package/src/bases/base-ui/ui/dropdown-menu.tsrx +292 -0
- package/src/bases/base-ui/ui/empty.tsrx +88 -0
- package/src/bases/base-ui/ui/field.tsrx +201 -0
- package/src/bases/base-ui/ui/input.tsrx +28 -0
- package/src/bases/base-ui/ui/item.tsrx +163 -0
- package/src/bases/base-ui/ui/kbd.tsrx +27 -0
- package/src/bases/base-ui/ui/label.tsrx +31 -0
- package/src/bases/base-ui/ui/native-select.tsrx +54 -0
- package/src/bases/base-ui/ui/pagination.tsrx +125 -0
- package/src/bases/base-ui/ui/popover.tsrx +124 -0
- package/src/bases/base-ui/ui/progress.tsrx +46 -0
- package/src/bases/base-ui/ui/radio-group.tsrx +62 -0
- package/src/bases/base-ui/ui/separator.tsrx +34 -0
- package/src/bases/base-ui/ui/sheet.tsrx +121 -0
- package/src/bases/base-ui/ui/skeleton.tsrx +17 -0
- package/src/bases/base-ui/ui/slider.tsrx +111 -0
- package/src/bases/base-ui/ui/spinner.tsrx +30 -0
- package/src/bases/base-ui/ui/switch.tsrx +43 -0
- package/src/bases/base-ui/ui/table.tsrx +85 -0
- package/src/bases/base-ui/ui/textarea.tsrx +22 -0
- package/src/bases/base-ui/ui/toggle-group.tsrx +124 -0
- package/src/bases/base-ui/ui/toggle.tsrx +57 -0
- package/src/bases/base-ui/ui/tooltip.tsrx +111 -0
package/README.md
CHANGED
|
@@ -13,20 +13,187 @@ Upstream pin: `shadcn-ui/ui@4baadbc6` + CLI `shadcn@4.14.1`.
|
|
|
13
13
|
radix-backed Tier-2 components, and the first Tier-3 composites (Sidebar with
|
|
14
14
|
`useSidebar`/`useIsMobile`, Field), plus `cn()` and the default neutral theme
|
|
15
15
|
tokens (`@octanejs/shadcn/theme.css`).
|
|
16
|
-
- **Two consumption modes**: import from the package
|
|
16
|
+
- **Two consumption modes**: import from the package subpaths, or install
|
|
17
17
|
components AS SOURCE with the upstream shadcn CLI against the generated
|
|
18
|
-
registry (`registry
|
|
18
|
+
registry (`registry/` — `pnpm registry:build` / `registry:check`).
|
|
19
|
+
- **Three primitive bases in one registry**, selected the way shadcn selects its
|
|
20
|
+
own: `components.json`'s `style` field, substituted into the registry URL. See
|
|
21
|
+
[Installing with the shadcn CLI](#installing-with-the-shadcn-cli).
|
|
19
22
|
- **Styling flavors**: components are migrating to the default-Tailwind
|
|
20
23
|
(utilities-inlined) flavor — class strings work against any Tailwind v4 build
|
|
21
24
|
with the shadcn theme tokens. The not-yet-migrated families still carry the
|
|
22
25
|
upstream `cn-*` semantic hooks and need a shadcn style sheet (e.g.
|
|
23
26
|
`style-nova`). `status.json` lists exactly which families are which.
|
|
24
27
|
|
|
28
|
+
## Component coverage
|
|
29
|
+
|
|
30
|
+
Each primitive base ships the families its primitives support, exactly as upstream's do.
|
|
31
|
+
Switching `style` changes which primitive a component is built on — the `data-slot` contract and
|
|
32
|
+
component names stay identical.
|
|
33
|
+
|
|
34
|
+
<!-- BEGIN COVERAGE -->
|
|
35
|
+
|
|
36
|
+
**44 families** — Radix 44/44 · React Aria 33/44 · Base UI 35/44
|
|
37
|
+
|
|
38
|
+
✅ ported · — not ported yet (fair game) · ⛔ blocked, see notes below
|
|
39
|
+
|
|
40
|
+
| Family | Radix | React Aria | Base UI |
|
|
41
|
+
| --- | :---: | :---: | :---: |
|
|
42
|
+
| `accordion` | ✅ | ✅ | ✅ |
|
|
43
|
+
| `alert` | ✅ | ✅ | ✅ |
|
|
44
|
+
| `alert-dialog` | ✅ | ✅ | ✅ |
|
|
45
|
+
| `aspect-ratio` | ✅ | ✅ | ✅ |
|
|
46
|
+
| `avatar` | ✅ | ✅ | ✅ |
|
|
47
|
+
| `badge` | ✅ | ✅ | ✅ |
|
|
48
|
+
| `breadcrumb` | ✅ | ✅ | ✅ |
|
|
49
|
+
| `button` | ✅ | ✅ | ✅ |
|
|
50
|
+
| `card` | ✅ | ✅ | ✅ |
|
|
51
|
+
| `checkbox` | ✅ | ✅ | ✅ |
|
|
52
|
+
| `collapsible` | ✅ | ✅ | ✅ |
|
|
53
|
+
| `context-menu` | ✅ | ⛔ | — |
|
|
54
|
+
| `dialog` | ✅ | ✅ | ✅ |
|
|
55
|
+
| `dropdown-menu` | ✅ | ⛔ | ✅ |
|
|
56
|
+
| `empty` | ✅ | ✅ | ✅ |
|
|
57
|
+
| `field` | ✅ | ✅ | ✅ |
|
|
58
|
+
| `hover-card` | ✅ | ⛔ | — |
|
|
59
|
+
| `input` | ✅ | ✅ | ✅ |
|
|
60
|
+
| `item` | ✅ | ✅ | ✅ |
|
|
61
|
+
| `kbd` | ✅ | ✅ | ✅ |
|
|
62
|
+
| `label` | ✅ | ✅ | ✅ |
|
|
63
|
+
| `menubar` | ✅ | ⛔ | — |
|
|
64
|
+
| `native-select` | ✅ | ✅ | ✅ |
|
|
65
|
+
| `navigation-menu` | ✅ | ⛔ | ⛔ |
|
|
66
|
+
| `pagination` | ✅ | ✅ | ✅ |
|
|
67
|
+
| `popover` | ✅ | ✅ | ✅ |
|
|
68
|
+
| `progress` | ✅ | ⛔ | ✅ |
|
|
69
|
+
| `radio-group` | ✅ | ✅ | ✅ |
|
|
70
|
+
| `scroll-area` | ✅ | ✅ | ⛔ |
|
|
71
|
+
| `select` | ✅ | ⛔ | ⛔ |
|
|
72
|
+
| `separator` | ✅ | ✅ | ✅ |
|
|
73
|
+
| `sheet` | ✅ | ✅ | ✅ |
|
|
74
|
+
| `sidebar` | ✅ | ⛔ | — |
|
|
75
|
+
| `skeleton` | ✅ | ✅ | ✅ |
|
|
76
|
+
| `slider` | ✅ | ✅ | ✅ |
|
|
77
|
+
| `sonner` | ✅ | ⛔ | ⛔ |
|
|
78
|
+
| `spinner` | ✅ | ✅ | ✅ |
|
|
79
|
+
| `switch` | ✅ | ✅ | ✅ |
|
|
80
|
+
| `table` | ✅ | ✅ | ✅ |
|
|
81
|
+
| `tabs` | ✅ | ✅ | ⛔ |
|
|
82
|
+
| `textarea` | ✅ | ✅ | ✅ |
|
|
83
|
+
| `toggle` | ✅ | ✅ | ✅ |
|
|
84
|
+
| `toggle-group` | ✅ | ⛔ | ✅ |
|
|
85
|
+
| `tooltip` | ✅ | ⛔ | ✅ |
|
|
86
|
+
|
|
87
|
+
**Blocked**
|
|
88
|
+
|
|
89
|
+
| Base | Family | Reason |
|
|
90
|
+
| --- | --- | --- |
|
|
91
|
+
| Base UI | `navigation-menu` | @octanejs/base-ui has no navigation-menu primitive |
|
|
92
|
+
| Base UI | `scroll-area` | @octanejs/base-ui has no scroll-area primitive |
|
|
93
|
+
| Base UI | `select` | @octanejs/base-ui has no select primitive |
|
|
94
|
+
| Base UI | `sonner` | needs next-themes, which has no octane binding |
|
|
95
|
+
| Base UI | `tabs` | @octanejs/base-ui has no tabs primitive |
|
|
96
|
+
| React Aria | `context-menu` | no counterpart in upstream’s aria base |
|
|
97
|
+
| React Aria | `dropdown-menu` | no counterpart in upstream’s aria base |
|
|
98
|
+
| React Aria | `hover-card` | no counterpart in upstream’s aria base |
|
|
99
|
+
| React Aria | `menubar` | no counterpart in upstream’s aria base |
|
|
100
|
+
| React Aria | `navigation-menu` | no counterpart in upstream’s aria base |
|
|
101
|
+
| React Aria | `progress` | no counterpart in upstream’s aria base |
|
|
102
|
+
| React Aria | `select` | needs input-group |
|
|
103
|
+
| React Aria | `sidebar` | no counterpart in upstream’s aria base |
|
|
104
|
+
| React Aria | `sonner` | needs next-themes, which has no octane binding |
|
|
105
|
+
| React Aria | `toggle-group` | no counterpart in upstream’s aria base |
|
|
106
|
+
| React Aria | `tooltip` | no counterpart in upstream’s aria base |
|
|
107
|
+
|
|
108
|
+
<!-- END COVERAGE -->
|
|
109
|
+
|
|
110
|
+
The table is generated from the sources by `pnpm coverage:build` and gated by `coverage:check`,
|
|
111
|
+
so it cannot drift as families land.
|
|
112
|
+
|
|
113
|
+
## Installing with the shadcn CLI
|
|
114
|
+
|
|
115
|
+
The registry is consumed by the **upstream** `shadcn` CLI — nothing octane-specific is
|
|
116
|
+
required on the consumer side.
|
|
117
|
+
|
|
118
|
+
Add the registry to your `components.json` and pick a base with `style`:
|
|
119
|
+
|
|
120
|
+
```jsonc
|
|
121
|
+
{
|
|
122
|
+
"style": "base-nova", // base-nova | radix-nova | aria-nova
|
|
123
|
+
"registries": {
|
|
124
|
+
"@octane": "https://octanejs.dev/r/styles/{style}/{name}.json"
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
npx shadcn add @octane/button
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
`{style}` and `{name}` are the only placeholders the CLI substitutes, and it never parses the
|
|
134
|
+
style string — so the base is chosen entirely by which tree the registry serves. This is the
|
|
135
|
+
same mechanism shadcn uses upstream, where its own registry is
|
|
136
|
+
`<host>/styles/{style}/{name}.json`.
|
|
137
|
+
|
|
138
|
+
| `style` | Primitives | Families |
|
|
139
|
+
| --- | --- | --- |
|
|
140
|
+
| `base-nova` *(default)* | `@octanejs/base-ui` | 21 |
|
|
141
|
+
| `radix-nova` | `@octanejs/radix` | 44 |
|
|
142
|
+
| `aria-nova` | `@octanejs/aria` | 33 |
|
|
143
|
+
|
|
144
|
+
The bases deliberately ship different family counts, exactly as upstream's do — a base only
|
|
145
|
+
has the families its primitives support. Switching `style` changes which primitive a component
|
|
146
|
+
is built on; the `data-slot` contract and component names stay identical, so your markup and
|
|
147
|
+
styling do not change.
|
|
148
|
+
|
|
149
|
+
A registry URL without the `{style}` segment resolves to the default style, so
|
|
150
|
+
`https://octanejs.dev/r/{name}.json` serves the Base UI variant.
|
|
151
|
+
|
|
152
|
+
### Serving it locally
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
pnpm --dir packages/shadcn registry:build # regenerate from src/
|
|
156
|
+
pnpm --dir packages/shadcn registry:serve # http://localhost:4517
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Then point `components.json` at `http://localhost:4517/styles/{style}/{name}.json`, which is
|
|
160
|
+
what `playground/octane` does.
|
|
161
|
+
|
|
162
|
+
## Importing from the package
|
|
163
|
+
|
|
164
|
+
There is no barrel entry. Every family has its own subpath, so an app pulls in only what it
|
|
165
|
+
uses — the Radix base at the bare name, the others under their base:
|
|
166
|
+
|
|
25
167
|
```tsx
|
|
26
|
-
|
|
168
|
+
// Radix base (the bare subpaths)
|
|
169
|
+
import { Button } from '@octanejs/shadcn/Button';
|
|
170
|
+
import { Dialog, DialogContent, DialogTitle } from '@octanejs/shadcn/Dialog';
|
|
171
|
+
|
|
172
|
+
// React Aria base
|
|
173
|
+
import { Button } from '@octanejs/shadcn/react-aria/Button';
|
|
174
|
+
|
|
175
|
+
// Base UI base
|
|
176
|
+
import {
|
|
177
|
+
AlertDialog,
|
|
178
|
+
AlertDialogAction,
|
|
179
|
+
AlertDialogCancel,
|
|
180
|
+
AlertDialogContent,
|
|
181
|
+
AlertDialogDescription,
|
|
182
|
+
AlertDialogFooter,
|
|
183
|
+
AlertDialogHeader,
|
|
184
|
+
AlertDialogMedia,
|
|
185
|
+
AlertDialogTitle,
|
|
186
|
+
AlertDialogTrigger,
|
|
187
|
+
} from '@octanejs/shadcn/base-ui/AlertDialog';
|
|
188
|
+
|
|
27
189
|
import '@octanejs/shadcn/theme.css';
|
|
28
190
|
```
|
|
29
191
|
|
|
192
|
+
Subpaths are `PascalCase` and map to the family, not the export: `AlertDialogTrigger` and its
|
|
193
|
+
siblings all come from `.../AlertDialog`. `cn` lives at `@octanejs/shadcn/cn`, shared types at
|
|
194
|
+
`@octanejs/shadcn/types`, and `useIsMobile` at `@octanejs/shadcn/hooks/use-mobile`.
|
|
195
|
+
|
|
196
|
+
|
|
30
197
|
Octane adaptations are uniform and documented per file: no `"use client"`,
|
|
31
198
|
refs as props, native events (`onInput` per keystroke), `asChild` and Portal
|
|
32
199
|
children composed as element descriptors, and children forwarding through the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octanejs/shadcn",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -104,6 +104,41 @@
|
|
|
104
104
|
"./react-aria/Tabs": "./src/bases/react-aria/ui/tabs.tsrx",
|
|
105
105
|
"./react-aria/Textarea": "./src/bases/react-aria/ui/textarea.tsrx",
|
|
106
106
|
"./react-aria/Toggle": "./src/bases/react-aria/ui/toggle.tsrx",
|
|
107
|
+
"./base-ui/Accordion": "./src/bases/base-ui/ui/accordion.tsrx",
|
|
108
|
+
"./base-ui/Alert": "./src/bases/base-ui/ui/alert.tsrx",
|
|
109
|
+
"./base-ui/AlertDialog": "./src/bases/base-ui/ui/alert-dialog.tsrx",
|
|
110
|
+
"./base-ui/AspectRatio": "./src/bases/base-ui/ui/aspect-ratio.tsrx",
|
|
111
|
+
"./base-ui/Avatar": "./src/bases/base-ui/ui/avatar.tsrx",
|
|
112
|
+
"./base-ui/Badge": "./src/bases/base-ui/ui/badge.tsrx",
|
|
113
|
+
"./base-ui/Breadcrumb": "./src/bases/base-ui/ui/breadcrumb.tsrx",
|
|
114
|
+
"./base-ui/Button": "./src/bases/base-ui/ui/button.tsrx",
|
|
115
|
+
"./base-ui/Card": "./src/bases/base-ui/ui/card.tsrx",
|
|
116
|
+
"./base-ui/Checkbox": "./src/bases/base-ui/ui/checkbox.tsrx",
|
|
117
|
+
"./base-ui/Collapsible": "./src/bases/base-ui/ui/collapsible.tsrx",
|
|
118
|
+
"./base-ui/Dialog": "./src/bases/base-ui/ui/dialog.tsrx",
|
|
119
|
+
"./base-ui/DropdownMenu": "./src/bases/base-ui/ui/dropdown-menu.tsrx",
|
|
120
|
+
"./base-ui/Empty": "./src/bases/base-ui/ui/empty.tsrx",
|
|
121
|
+
"./base-ui/Field": "./src/bases/base-ui/ui/field.tsrx",
|
|
122
|
+
"./base-ui/Input": "./src/bases/base-ui/ui/input.tsrx",
|
|
123
|
+
"./base-ui/Item": "./src/bases/base-ui/ui/item.tsrx",
|
|
124
|
+
"./base-ui/Kbd": "./src/bases/base-ui/ui/kbd.tsrx",
|
|
125
|
+
"./base-ui/Label": "./src/bases/base-ui/ui/label.tsrx",
|
|
126
|
+
"./base-ui/NativeSelect": "./src/bases/base-ui/ui/native-select.tsrx",
|
|
127
|
+
"./base-ui/Pagination": "./src/bases/base-ui/ui/pagination.tsrx",
|
|
128
|
+
"./base-ui/Popover": "./src/bases/base-ui/ui/popover.tsrx",
|
|
129
|
+
"./base-ui/Progress": "./src/bases/base-ui/ui/progress.tsrx",
|
|
130
|
+
"./base-ui/RadioGroup": "./src/bases/base-ui/ui/radio-group.tsrx",
|
|
131
|
+
"./base-ui/Separator": "./src/bases/base-ui/ui/separator.tsrx",
|
|
132
|
+
"./base-ui/Sheet": "./src/bases/base-ui/ui/sheet.tsrx",
|
|
133
|
+
"./base-ui/Skeleton": "./src/bases/base-ui/ui/skeleton.tsrx",
|
|
134
|
+
"./base-ui/Slider": "./src/bases/base-ui/ui/slider.tsrx",
|
|
135
|
+
"./base-ui/Spinner": "./src/bases/base-ui/ui/spinner.tsrx",
|
|
136
|
+
"./base-ui/Switch": "./src/bases/base-ui/ui/switch.tsrx",
|
|
137
|
+
"./base-ui/Table": "./src/bases/base-ui/ui/table.tsrx",
|
|
138
|
+
"./base-ui/Textarea": "./src/bases/base-ui/ui/textarea.tsrx",
|
|
139
|
+
"./base-ui/Toggle": "./src/bases/base-ui/ui/toggle.tsrx",
|
|
140
|
+
"./base-ui/ToggleGroup": "./src/bases/base-ui/ui/toggle-group.tsrx",
|
|
141
|
+
"./base-ui/Tooltip": "./src/bases/base-ui/ui/tooltip.tsrx",
|
|
107
142
|
"./cn": "./src/lib/utils.ts",
|
|
108
143
|
"./types": "./src/lib/types.ts",
|
|
109
144
|
"./hooks/use-mobile": "./src/hooks/use-mobile.ts",
|
|
@@ -113,13 +148,14 @@
|
|
|
113
148
|
"class-variance-authority": "0.7.1",
|
|
114
149
|
"clsx": "^2.1.1",
|
|
115
150
|
"tailwind-merge": "3.6.0",
|
|
116
|
-
"@octanejs/aria": "0.0.
|
|
117
|
-
"@octanejs/
|
|
118
|
-
"@octanejs/
|
|
119
|
-
"@octanejs/
|
|
151
|
+
"@octanejs/aria": "0.0.18",
|
|
152
|
+
"@octanejs/base-ui": "0.1.22",
|
|
153
|
+
"@octanejs/lucide": "0.1.19",
|
|
154
|
+
"@octanejs/radix": "0.1.23",
|
|
155
|
+
"@octanejs/sonner": "0.1.19"
|
|
120
156
|
},
|
|
121
157
|
"peerDependencies": {
|
|
122
|
-
"octane": "0.1.
|
|
158
|
+
"octane": "0.1.24"
|
|
123
159
|
},
|
|
124
160
|
"devDependencies": {
|
|
125
161
|
"@tsrx/react": "^0.2.56",
|
|
@@ -129,12 +165,15 @@
|
|
|
129
165
|
"react": "^19.2.7",
|
|
130
166
|
"react-dom": "^19.2.7",
|
|
131
167
|
"vitest": "^4.1.10",
|
|
132
|
-
"octane": "0.1.
|
|
168
|
+
"octane": "0.1.24"
|
|
133
169
|
},
|
|
134
170
|
"scripts": {
|
|
135
171
|
"test": "vitest run",
|
|
136
172
|
"registry:build": "node scripts/build-registry.mjs",
|
|
137
173
|
"registry:check": "node scripts/build-registry.mjs --check",
|
|
174
|
+
"registry:serve": "node scripts/serve-registry.mjs",
|
|
175
|
+
"coverage:build": "node scripts/build-coverage-table.mjs",
|
|
176
|
+
"coverage:check": "node scripts/build-coverage-table.mjs --check",
|
|
138
177
|
"typecheck": "node scripts/typecheck.mjs"
|
|
139
178
|
}
|
|
140
179
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Base UI base accordion — transcribed from upstream's `bases/base-ui/ui/accordion.tsx`
|
|
2
|
+
// (maintainer-supplied), class strings and data-slot names verbatim. Runs on
|
|
3
|
+
// @octanejs/base-ui/accordion.
|
|
4
|
+
//
|
|
5
|
+
// Note the part mapping: upstream shadcn names the content part `AccordionContent` while the
|
|
6
|
+
// underlying Base UI part is `Accordion.Panel`, and `AccordionTrigger` renders the
|
|
7
|
+
// `Accordion.Header` wrapper itself rather than exposing it. Both are upstream's shape, kept
|
|
8
|
+
// as-is so consumers following the shadcn docs get the components they expect.
|
|
9
|
+
//
|
|
10
|
+
// Octane adaptations: no `"use client"` (octane has no Server Components); upstream's
|
|
11
|
+
// IconPlaceholder resolves at port time to lucide via @octanejs/lucide.
|
|
12
|
+
import { Accordion as AccordionPrimitive } from '@octanejs/base-ui/accordion';
|
|
13
|
+
import { ChevronDownIcon, ChevronUpIcon } from '@octanejs/lucide';
|
|
14
|
+
|
|
15
|
+
import { cn } from '../../../lib/utils';
|
|
16
|
+
|
|
17
|
+
export function Accordion({ className, ...props }: Record<string, any>) @{
|
|
18
|
+
<AccordionPrimitive.Root
|
|
19
|
+
data-slot="accordion"
|
|
20
|
+
className={cn('flex w-full flex-col', className)}
|
|
21
|
+
{...props}
|
|
22
|
+
/>
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function AccordionItem({ className, ...props }: Record<string, any>) @{
|
|
26
|
+
<AccordionPrimitive.Item
|
|
27
|
+
data-slot="accordion-item"
|
|
28
|
+
className={cn('not-last:border-b', className)}
|
|
29
|
+
{...props}
|
|
30
|
+
/>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function AccordionTrigger({ className, children, ...props }: Record<string, any>) @{
|
|
34
|
+
<AccordionPrimitive.Header className="flex">
|
|
35
|
+
<AccordionPrimitive.Trigger
|
|
36
|
+
data-slot="accordion-trigger"
|
|
37
|
+
className={cn(
|
|
38
|
+
'group/accordion-trigger relative flex flex-1 items-start justify-between rounded-lg border border-transparent py-2.5 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:after:border-ring aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground',
|
|
39
|
+
className,
|
|
40
|
+
)}
|
|
41
|
+
{...props}
|
|
42
|
+
>
|
|
43
|
+
{children}
|
|
44
|
+
<ChevronDownIcon
|
|
45
|
+
data-slot="accordion-trigger-icon"
|
|
46
|
+
className="pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden"
|
|
47
|
+
/>
|
|
48
|
+
<ChevronUpIcon
|
|
49
|
+
data-slot="accordion-trigger-icon"
|
|
50
|
+
className="pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline"
|
|
51
|
+
/>
|
|
52
|
+
</AccordionPrimitive.Trigger>
|
|
53
|
+
</AccordionPrimitive.Header>
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// `className` styles the INNER div, not the panel — upstream keeps the panel's own class string
|
|
57
|
+
// fixed so the open/close animation hooks cannot be overridden away by a consumer class.
|
|
58
|
+
export function AccordionContent({ className, children, ...props }: Record<string, any>) @{
|
|
59
|
+
<AccordionPrimitive.Panel
|
|
60
|
+
data-slot="accordion-content"
|
|
61
|
+
className="overflow-hidden text-sm data-open:animate-accordion-down data-closed:animate-accordion-up"
|
|
62
|
+
{...props}
|
|
63
|
+
>
|
|
64
|
+
<div
|
|
65
|
+
className={cn(
|
|
66
|
+
'h-(--accordion-panel-height) pt-0 pb-2.5 data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4',
|
|
67
|
+
className,
|
|
68
|
+
)}
|
|
69
|
+
>{children}</div>
|
|
70
|
+
</AccordionPrimitive.Panel>
|
|
71
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// Base UI base alert-dialog — transcribed from upstream's `bases/base-ui/ui/alert-dialog.tsx`
|
|
2
|
+
// (maintainer-supplied), running on @octanejs/base-ui's AlertDialog. Upstream part mapping:
|
|
3
|
+
// Overlay -> Backdrop, Content -> Popup, Cancel -> Close. This port also composes Action via Close.
|
|
4
|
+
//
|
|
5
|
+
// TWO DELIBERATE DEPARTURES FROM THE SOURCE:
|
|
6
|
+
// - Upstream's AlertDialogTitle carries `cn-font-heading`, a semantic hook from the pinned cn-*
|
|
7
|
+
// system. This package ships the default-Tailwind utilities-inlined flavor instead, the
|
|
8
|
+
// react-aria base already drops this exact class for that reason, and nothing in the playground
|
|
9
|
+
// defines it (0 occurrences in the built CSS), so keeping it would ship a class that resolves
|
|
10
|
+
// to nothing. Every other class string is verbatim.
|
|
11
|
+
// - Upstream renders AlertDialogAction as a plain Button, so it does not dismiss the dialog.
|
|
12
|
+
// Composing it through Close preserves the public Button-like API and supplies the expected
|
|
13
|
+
// confirm-and-dismiss behavior shown by Base UI's own alert-dialog examples.
|
|
14
|
+
//
|
|
15
|
+
// Octane adaptations: no `"use client"`; refs are props. AlertDialogContent composes its
|
|
16
|
+
// Portal/Overlay/Popup tree internally, so consumer children still flow through the ordinary
|
|
17
|
+
// props.children channel.
|
|
18
|
+
import { AlertDialog as AlertDialogPrimitive } from '@octanejs/base-ui/alert-dialog';
|
|
19
|
+
|
|
20
|
+
import { cn } from '../../../lib/utils';
|
|
21
|
+
import type { DivProps } from '../../../lib/types';
|
|
22
|
+
import { Button } from './button.tsrx';
|
|
23
|
+
|
|
24
|
+
export function AlertDialog({ ...props }: Record<string, any>) @{
|
|
25
|
+
<AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function AlertDialogTrigger({ ...props }: Record<string, any>) @{
|
|
29
|
+
<AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function AlertDialogPortal({ ...props }: Record<string, any>) @{
|
|
33
|
+
<AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function AlertDialogOverlay({ className, ...props }: Record<string, any>) @{
|
|
37
|
+
<AlertDialogPrimitive.Backdrop
|
|
38
|
+
data-slot="alert-dialog-overlay"
|
|
39
|
+
className={cn(
|
|
40
|
+
'fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0',
|
|
41
|
+
className,
|
|
42
|
+
)}
|
|
43
|
+
{...props}
|
|
44
|
+
/>
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function AlertDialogContent({ className, size = 'default', ...props }: Record<
|
|
48
|
+
string,
|
|
49
|
+
any
|
|
50
|
+
>) @{
|
|
51
|
+
<AlertDialogPortal>
|
|
52
|
+
<AlertDialogOverlay key="overlay" />
|
|
53
|
+
<AlertDialogPrimitive.Popup
|
|
54
|
+
key="content"
|
|
55
|
+
data-slot="alert-dialog-content"
|
|
56
|
+
data-size={size}
|
|
57
|
+
className={cn(
|
|
58
|
+
'group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95',
|
|
59
|
+
className,
|
|
60
|
+
)}
|
|
61
|
+
{...props}
|
|
62
|
+
/>
|
|
63
|
+
</AlertDialogPortal>
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function AlertDialogHeader({ className, ...props }: DivProps) @{
|
|
67
|
+
<div
|
|
68
|
+
data-slot="alert-dialog-header"
|
|
69
|
+
className={cn(
|
|
70
|
+
'grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]',
|
|
71
|
+
className,
|
|
72
|
+
)}
|
|
73
|
+
{...props}
|
|
74
|
+
/>
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function AlertDialogFooter({ className, ...props }: DivProps) @{
|
|
78
|
+
<div
|
|
79
|
+
data-slot="alert-dialog-footer"
|
|
80
|
+
className={cn(
|
|
81
|
+
'-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end',
|
|
82
|
+
className,
|
|
83
|
+
)}
|
|
84
|
+
{...props}
|
|
85
|
+
/>
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function AlertDialogMedia({ className, ...props }: DivProps) @{
|
|
89
|
+
<div
|
|
90
|
+
data-slot="alert-dialog-media"
|
|
91
|
+
className={cn(
|
|
92
|
+
'mb-2 inline-flex size-10 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*=\'size-\'])]:size-6',
|
|
93
|
+
className,
|
|
94
|
+
)}
|
|
95
|
+
{...props}
|
|
96
|
+
/>
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function AlertDialogTitle({ className, ...props }: Record<string, any>) @{
|
|
100
|
+
<AlertDialogPrimitive.Title
|
|
101
|
+
data-slot="alert-dialog-title"
|
|
102
|
+
className={cn(
|
|
103
|
+
'text-base font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2',
|
|
104
|
+
className,
|
|
105
|
+
)}
|
|
106
|
+
{...props}
|
|
107
|
+
/>
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function AlertDialogDescription({ className, ...props }: Record<string, any>) @{
|
|
111
|
+
<AlertDialogPrimitive.Description
|
|
112
|
+
data-slot="alert-dialog-description"
|
|
113
|
+
className={cn(
|
|
114
|
+
'text-sm text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground',
|
|
115
|
+
className,
|
|
116
|
+
)}
|
|
117
|
+
{...props}
|
|
118
|
+
/>
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function AlertDialogAction({
|
|
122
|
+
className,
|
|
123
|
+
variant = 'default',
|
|
124
|
+
size = 'default',
|
|
125
|
+
...props
|
|
126
|
+
}: Record<string, any>) @{
|
|
127
|
+
<AlertDialogPrimitive.Close
|
|
128
|
+
data-slot="alert-dialog-action"
|
|
129
|
+
className={cn(className)}
|
|
130
|
+
render={<Button variant={variant} size={size} />}
|
|
131
|
+
{...props}
|
|
132
|
+
/>
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// `render` takes an ELEMENT here, not a function — that is Base UI's render-prop contract, and
|
|
136
|
+
// it is what lets each action keep Close's dismiss behavior while looking like a Button.
|
|
137
|
+
export function AlertDialogCancel({
|
|
138
|
+
className,
|
|
139
|
+
variant = 'outline',
|
|
140
|
+
size = 'default',
|
|
141
|
+
...props
|
|
142
|
+
}: Record<string, any>) @{
|
|
143
|
+
<AlertDialogPrimitive.Close
|
|
144
|
+
data-slot="alert-dialog-cancel"
|
|
145
|
+
className={cn(className)}
|
|
146
|
+
render={<Button variant={variant} size={size} />}
|
|
147
|
+
{...props}
|
|
148
|
+
/>
|
|
149
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Base UI base alert — structure and cva strings from upstream `bases/base-ui/ui/alert.tsx`.
|
|
2
|
+
//
|
|
3
|
+
// Alert uses no headless primitive in any base, and this file's nine string literals were
|
|
4
|
+
// verified byte-identical to the React Aria base's `alert.tsrx`. That is a finding, not an
|
|
5
|
+
// assumption: the two bases DO diverge elsewhere (the Radix base's Skeleton is `bg-accent`
|
|
6
|
+
// where aria's is `bg-muted`), so identity is checked per component rather than inherited.
|
|
7
|
+
//
|
|
8
|
+
// Octane adaptations: `React.ComponentProps<'div'>` → the package's `DivProps`; no
|
|
9
|
+
// `"use client"` (octane has no Server Components). Pure template JSX, no consumer-children
|
|
10
|
+
// interleave, so every part uses the `@{ … }` shorthand.
|
|
11
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
12
|
+
|
|
13
|
+
import { cn } from '../../../lib/utils';
|
|
14
|
+
import type { DivProps } from '../../../lib/types';
|
|
15
|
+
|
|
16
|
+
export const alertVariants = cva(
|
|
17
|
+
'group/alert relative grid w-full gap-0.5 rounded-lg border px-2.5 py-2 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*=\'size-\'])]:size-4',
|
|
18
|
+
{
|
|
19
|
+
variants: {
|
|
20
|
+
variant: {
|
|
21
|
+
default: 'bg-card text-card-foreground',
|
|
22
|
+
destructive: 'bg-card text-destructive *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
defaultVariants: {
|
|
26
|
+
variant: 'default',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
export interface AlertProps extends DivProps {
|
|
32
|
+
variant?: VariantProps<typeof alertVariants>['variant'];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function Alert({ className, variant, ...props }: AlertProps) @{
|
|
36
|
+
<div
|
|
37
|
+
data-slot="alert"
|
|
38
|
+
role="alert"
|
|
39
|
+
className={cn(alertVariants({ variant }), className)}
|
|
40
|
+
{...props}
|
|
41
|
+
/>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function AlertTitle({ className, ...props }: DivProps) @{
|
|
45
|
+
<div
|
|
46
|
+
data-slot="alert-title"
|
|
47
|
+
className={cn(
|
|
48
|
+
'font-medium group-has-[>svg]/alert:col-start-2 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground',
|
|
49
|
+
className,
|
|
50
|
+
)}
|
|
51
|
+
{...props}
|
|
52
|
+
/>
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function AlertDescription({ className, ...props }: DivProps) @{
|
|
56
|
+
<div
|
|
57
|
+
data-slot="alert-description"
|
|
58
|
+
className={cn(
|
|
59
|
+
'text-sm text-balance text-muted-foreground md:text-pretty [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4',
|
|
60
|
+
className,
|
|
61
|
+
)}
|
|
62
|
+
{...props}
|
|
63
|
+
/>
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function AlertAction({ className, ...props }: DivProps) @{
|
|
67
|
+
<div data-slot="alert-action" className={cn('absolute top-2 right-2', className)} {...props} />
|
|
68
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Base UI base aspect-ratio — presentational, no headless primitive in any base.
|
|
2
|
+
//
|
|
3
|
+
// UNVERIFIED PROVENANCE: derived from this package's React Aria base rather than transcribed
|
|
4
|
+
// from upstream's `bases/base-ui/ui/aspect-ratio.tsx`, which was not available at port time.
|
|
5
|
+
// `alert` was confirmed byte-identical between the two bases, which is why this is plausible —
|
|
6
|
+
// but it is not proof, and the bases DO diverge elsewhere. Diff the class strings against the
|
|
7
|
+
// upstream source before treating this as ported.
|
|
8
|
+
import { cn } from '../../../lib/utils';
|
|
9
|
+
import type { DivProps } from '../../../lib/types';
|
|
10
|
+
|
|
11
|
+
export interface AspectRatioProps extends DivProps {
|
|
12
|
+
ratio: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function AspectRatio({ ratio, className, ...props }: AspectRatioProps) @{
|
|
16
|
+
<div
|
|
17
|
+
data-slot="aspect-ratio"
|
|
18
|
+
style={{
|
|
19
|
+
'--ratio': ratio,
|
|
20
|
+
} as Record<string, string | number>}
|
|
21
|
+
className={cn('relative aspect-(--ratio)', className)}
|
|
22
|
+
{...props}
|
|
23
|
+
/>
|
|
24
|
+
}
|