@octanejs/shadcn 0.0.37 → 0.0.38
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 +14 -15
- package/package.json +8 -8
- package/src/bases/base-ui/ui/context-menu.tsrx +21 -16
- package/src/bases/base-ui/ui/dialog.tsrx +30 -39
- package/src/bases/base-ui/ui/dropdown-menu.tsrx +21 -16
- package/src/bases/base-ui/ui/hover-card.tsrx +17 -15
- package/src/bases/base-ui/ui/menubar.tsrx +21 -16
- package/src/bases/base-ui/ui/popover.tsrx +17 -15
- package/src/bases/base-ui/ui/slider.tsrx +40 -51
- package/src/bases/base-ui/ui/tabs.tsrx +7 -16
- package/src/bases/base-ui/ui/toggle-group.tsrx +21 -31
- package/src/bases/base-ui/ui/tooltip.tsrx +17 -15
package/README.md
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
# @octanejs/shadcn
|
|
2
2
|
|
|
3
|
-
shadcn/ui for the [octane](https://github.com/octanejs/octane) renderer
|
|
4
|
-
|
|
5
|
-
octane's hooks and native events, built on
|
|
6
|
-
[`@octanejs/radix`](../radix).
|
|
3
|
+
shadcn/ui for the [octane](https://github.com/octanejs/octane) renderer, with
|
|
4
|
+
Base UI, Radix, and React Aria bases adapted to octane's hooks and native events.
|
|
7
5
|
|
|
8
6
|
## Installation
|
|
9
7
|
|
|
@@ -16,7 +14,7 @@ Upstream pin: `shadcn-ui/ui@4baadbc6` + CLI `shadcn@4.14.1`.
|
|
|
16
14
|
|
|
17
15
|
## What ships
|
|
18
16
|
|
|
19
|
-
- **
|
|
17
|
+
- **44 component families across three bases**: the full Tier-1 static set, all 24
|
|
20
18
|
radix-backed Tier-2 components, and the first Tier-3 composites (Sidebar with
|
|
21
19
|
`useSidebar`/`useIsMobile`, Field), plus `cn()` and the default neutral theme
|
|
22
20
|
tokens (`@octanejs/shadcn/theme.css`).
|
|
@@ -34,10 +32,14 @@ Upstream pin: `shadcn-ui/ui@4baadbc6` + CLI `shadcn@4.14.1`.
|
|
|
34
32
|
|
|
35
33
|
## Component coverage
|
|
36
34
|
|
|
37
|
-
|
|
35
|
+
The coverage table tracks the families ported for each primitive base.
|
|
38
36
|
Switching `style` changes which primitive a component is built on — the `data-slot` contract and
|
|
39
37
|
component names stay identical.
|
|
40
38
|
|
|
39
|
+
The Base UI wrappers target `@octanejs/base-ui`'s Base UI 1.8.0 API. Select,
|
|
40
|
+
Combobox, Navigation Menu, and Scroll Area primitives are available from
|
|
41
|
+
`@octanejs/base-ui`; their shadcn Base UI wrappers have not been ported yet.
|
|
42
|
+
|
|
41
43
|
<!-- BEGIN COVERAGE -->
|
|
42
44
|
|
|
43
45
|
**44 families** — Radix 44/44 · React Aria 33/44 · Base UI 40/44
|
|
@@ -69,13 +71,13 @@ component names stay identical.
|
|
|
69
71
|
| `label` | ✅ | ✅ | ✅ |
|
|
70
72
|
| `menubar` | ✅ | ⛔ | ✅ |
|
|
71
73
|
| `native-select` | ✅ | ✅ | ✅ |
|
|
72
|
-
| `navigation-menu` | ✅ | ⛔ |
|
|
74
|
+
| `navigation-menu` | ✅ | ⛔ | — |
|
|
73
75
|
| `pagination` | ✅ | ✅ | ✅ |
|
|
74
76
|
| `popover` | ✅ | ✅ | ✅ |
|
|
75
77
|
| `progress` | ✅ | ⛔ | ✅ |
|
|
76
78
|
| `radio-group` | ✅ | ✅ | ✅ |
|
|
77
|
-
| `scroll-area` | ✅ | ✅ |
|
|
78
|
-
| `select` | ✅ | ⛔ |
|
|
79
|
+
| `scroll-area` | ✅ | ✅ | — |
|
|
80
|
+
| `select` | ✅ | ⛔ | — |
|
|
79
81
|
| `separator` | ✅ | ✅ | ✅ |
|
|
80
82
|
| `sheet` | ✅ | ✅ | ✅ |
|
|
81
83
|
| `sidebar` | ✅ | ⛔ | ✅ |
|
|
@@ -95,9 +97,6 @@ component names stay identical.
|
|
|
95
97
|
|
|
96
98
|
| Base | Family | Reason |
|
|
97
99
|
| --- | --- | --- |
|
|
98
|
-
| Base UI | `navigation-menu` | @octanejs/base-ui has no navigation-menu primitive |
|
|
99
|
-
| Base UI | `scroll-area` | @octanejs/base-ui has no scroll-area primitive |
|
|
100
|
-
| Base UI | `select` | @octanejs/base-ui has no select primitive |
|
|
101
100
|
| Base UI | `sonner` | needs next-themes, which has no octane binding |
|
|
102
101
|
| React Aria | `context-menu` | no counterpart in upstream’s aria base |
|
|
103
102
|
| React Aria | `dropdown-menu` | no counterpart in upstream’s aria base |
|
|
@@ -143,12 +142,12 @@ same mechanism shadcn uses upstream, where its own registry is
|
|
|
143
142
|
|
|
144
143
|
| `style` | Primitives | Families |
|
|
145
144
|
| --- | --- | --- |
|
|
146
|
-
| `base-nova` *(default)* | `@octanejs/base-ui` |
|
|
145
|
+
| `base-nova` *(default)* | `@octanejs/base-ui` | 40 |
|
|
147
146
|
| `radix-nova` | `@octanejs/radix` | 44 |
|
|
148
147
|
| `aria-nova` | `@octanejs/aria` | 33 |
|
|
149
148
|
|
|
150
|
-
The bases
|
|
151
|
-
|
|
149
|
+
The bases currently ship different family counts; see the coverage table for remaining ports.
|
|
150
|
+
Switching `style` changes which primitive a component
|
|
152
151
|
is built on; the `data-slot` contract and component names stay identical, so your markup and
|
|
153
152
|
styling do not change.
|
|
154
153
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octanejs/shadcn",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.38",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -154,23 +154,23 @@
|
|
|
154
154
|
"clsx": "^2.1.1",
|
|
155
155
|
"tailwind-merge": "3.6.0",
|
|
156
156
|
"@octanejs/aria": "0.0.46",
|
|
157
|
-
"@octanejs/base-ui": "0.1.
|
|
157
|
+
"@octanejs/base-ui": "0.1.51",
|
|
158
158
|
"@octanejs/lucide": "0.1.47",
|
|
159
|
-
"@octanejs/radix": "0.1.
|
|
159
|
+
"@octanejs/radix": "0.1.52",
|
|
160
160
|
"@octanejs/sonner": "0.1.47"
|
|
161
161
|
},
|
|
162
162
|
"peerDependencies": {
|
|
163
|
-
"octane": "^0.
|
|
163
|
+
"octane": "^0.2.5"
|
|
164
164
|
},
|
|
165
165
|
"devDependencies": {
|
|
166
|
-
"@tsrx/react": "^0.2.
|
|
166
|
+
"@tsrx/react": "^0.2.67",
|
|
167
167
|
"esbuild": "^0.28.1",
|
|
168
168
|
"lucide-react": "1.24.0",
|
|
169
169
|
"radix-ui": "^1.6.4",
|
|
170
|
-
"react": "
|
|
171
|
-
"react-dom": "
|
|
170
|
+
"react": "19.2.7",
|
|
171
|
+
"react-dom": "19.2.7",
|
|
172
172
|
"vitest": "^4.1.10",
|
|
173
|
-
"octane": "0.2.
|
|
173
|
+
"octane": "0.2.5"
|
|
174
174
|
},
|
|
175
175
|
"scripts": {
|
|
176
176
|
"test": "vitest run",
|
|
@@ -30,21 +30,23 @@ import { cn } from '../../../lib/utils';
|
|
|
30
30
|
|
|
31
31
|
type Props = { className?: string; children?: OctaneNode } & Record<string, unknown>;
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
33
|
+
/** Props routed to the Positioner rather than the popup. */
|
|
34
|
+
export type BaseUiPositioningProps =
|
|
35
|
+
Pick<
|
|
36
|
+
ContextMenuPrimitive.Positioner.Props,
|
|
37
|
+
| 'side'
|
|
38
|
+
| 'sideOffset'
|
|
39
|
+
| 'align'
|
|
40
|
+
| 'alignOffset'
|
|
41
|
+
| 'anchor'
|
|
42
|
+
| 'positionMethod'
|
|
43
|
+
| 'collisionBoundary'
|
|
44
|
+
| 'collisionPadding'
|
|
45
|
+
| 'collisionAvoidance'
|
|
46
|
+
| 'arrowPadding'
|
|
47
|
+
| 'sticky'
|
|
48
|
+
| 'disableAnchorTracking'
|
|
49
|
+
>;
|
|
48
50
|
|
|
49
51
|
export function ContextMenu(props: Record<string, unknown>) @{
|
|
50
52
|
<ContextMenuPrimitive.Root data-slot="context-menu" {...props} />
|
|
@@ -221,7 +223,10 @@ export function ContextMenuCheckboxItem(props: Props & {
|
|
|
221
223
|
</ContextMenuPrimitive.CheckboxItem>
|
|
222
224
|
}
|
|
223
225
|
|
|
224
|
-
export function ContextMenuRadioItem(props:
|
|
226
|
+
export function ContextMenuRadioItem(props: Omit<
|
|
227
|
+
ContextMenuPrimitive.RadioItem.Props,
|
|
228
|
+
'className'
|
|
229
|
+
> & { className?: string; inset?: boolean }) @{
|
|
225
230
|
const { className, children: _children, inset, ...rest } = props;
|
|
226
231
|
|
|
227
232
|
<ContextMenuPrimitive.RadioItem
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
//
|
|
11
11
|
// UNVERIFIED PROVENANCE: class strings come from this package's radix base rather than
|
|
12
12
|
// transcribed from upstream's Base UI source.
|
|
13
|
-
import {
|
|
13
|
+
import { type OctaneNode } from 'octane';
|
|
14
14
|
import { Dialog as DialogPrimitive } from '@octanejs/base-ui/dialog';
|
|
15
15
|
import { XIcon } from '@octanejs/lucide';
|
|
16
16
|
|
|
@@ -46,7 +46,8 @@ export function DialogOverlay({ className, ...props }: Props) @{
|
|
|
46
46
|
/>
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
export interface DialogContentProps extends Props {
|
|
49
|
+
export interface DialogContentProps extends Omit<DialogPrimitive.Popup.Props, 'className'> {
|
|
50
|
+
className?: string;
|
|
50
51
|
showCloseButton?: boolean;
|
|
51
52
|
}
|
|
52
53
|
|
|
@@ -55,38 +56,30 @@ export function DialogContent({
|
|
|
55
56
|
children,
|
|
56
57
|
showCloseButton = true,
|
|
57
58
|
...props
|
|
58
|
-
}: DialogContentProps) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
{ variant: 'ghost', size: 'icon-sm' },
|
|
83
|
-
createElement(XIcon, { key: 'icon' }),
|
|
84
|
-
createElement('span', { key: 'sr', className: 'sr-only' }, 'Close'),
|
|
85
|
-
),
|
|
86
|
-
})
|
|
87
|
-
: null,
|
|
88
|
-
),
|
|
89
|
-
);
|
|
59
|
+
}: DialogContentProps) @{
|
|
60
|
+
<DialogPrimitive.Portal data-slot="dialog-portal">
|
|
61
|
+
<DialogOverlay />
|
|
62
|
+
<DialogPrimitive.Popup
|
|
63
|
+
data-slot="dialog-content"
|
|
64
|
+
className={cn(
|
|
65
|
+
'fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-sm text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none 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',
|
|
66
|
+
className,
|
|
67
|
+
)}
|
|
68
|
+
{...props}
|
|
69
|
+
>
|
|
70
|
+
{children}
|
|
71
|
+
@if (showCloseButton) {
|
|
72
|
+
<DialogPrimitive.Close
|
|
73
|
+
data-slot="dialog-close"
|
|
74
|
+
className="absolute top-2 right-2"
|
|
75
|
+
render={<Button variant="ghost" size="icon-sm">
|
|
76
|
+
<XIcon />
|
|
77
|
+
<span className="sr-only">Close</span>
|
|
78
|
+
</Button>}
|
|
79
|
+
/>
|
|
80
|
+
}
|
|
81
|
+
</DialogPrimitive.Popup>
|
|
82
|
+
</DialogPrimitive.Portal>
|
|
90
83
|
}
|
|
91
84
|
|
|
92
85
|
export function DialogHeader({ className, ...props }: Props) @{
|
|
@@ -109,11 +102,9 @@ export function DialogFooter(props: DialogFooterProps) @{
|
|
|
109
102
|
{...rest}
|
|
110
103
|
>
|
|
111
104
|
{props.children}
|
|
112
|
-
{
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
})
|
|
116
|
-
: null}
|
|
105
|
+
@if (showCloseButton) {
|
|
106
|
+
<DialogPrimitive.Close render={<Button variant="outline">Close</Button>} />
|
|
107
|
+
}
|
|
117
108
|
</div>
|
|
118
109
|
}
|
|
119
110
|
|
|
@@ -57,21 +57,23 @@ export function DropdownMenuTrigger(props: Record<string, unknown>) @{
|
|
|
57
57
|
<MenuPrimitive.Trigger data-slot="dropdown-menu-trigger" {...props} />
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
60
|
+
/** Props routed to the Positioner rather than the popup. */
|
|
61
|
+
export type BaseUiPositioningProps =
|
|
62
|
+
Pick<
|
|
63
|
+
MenuPrimitive.Positioner.Props,
|
|
64
|
+
| 'side'
|
|
65
|
+
| 'sideOffset'
|
|
66
|
+
| 'align'
|
|
67
|
+
| 'alignOffset'
|
|
68
|
+
| 'anchor'
|
|
69
|
+
| 'positionMethod'
|
|
70
|
+
| 'collisionBoundary'
|
|
71
|
+
| 'collisionPadding'
|
|
72
|
+
| 'collisionAvoidance'
|
|
73
|
+
| 'arrowPadding'
|
|
74
|
+
| 'sticky'
|
|
75
|
+
| 'disableAnchorTracking'
|
|
76
|
+
>;
|
|
75
77
|
|
|
76
78
|
export interface DropdownMenuContentProps extends Props, BaseUiPositioningProps {}
|
|
77
79
|
|
|
@@ -170,7 +172,10 @@ export function DropdownMenuRadioGroup(props: Record<string, unknown>) @{
|
|
|
170
172
|
<MenuPrimitive.RadioGroup data-slot="dropdown-menu-radio-group" {...props} />
|
|
171
173
|
}
|
|
172
174
|
|
|
173
|
-
export function DropdownMenuRadioItem(props: Props & {
|
|
175
|
+
export function DropdownMenuRadioItem(props: Omit<MenuPrimitive.RadioItem.Props, 'className'> & {
|
|
176
|
+
className?: string;
|
|
177
|
+
inset?: boolean;
|
|
178
|
+
}) @{
|
|
174
179
|
const { className, children: _children, inset, ...rest } = props;
|
|
175
180
|
|
|
176
181
|
<MenuPrimitive.RadioItem
|
|
@@ -28,21 +28,23 @@ import { PreviewCard as PreviewCardPrimitive } from '@octanejs/base-ui/preview-c
|
|
|
28
28
|
|
|
29
29
|
import { cn } from '../../../lib/utils';
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
31
|
+
/** Props routed to the Positioner rather than the popup. */
|
|
32
|
+
export type BaseUiPositioningProps =
|
|
33
|
+
Pick<
|
|
34
|
+
PreviewCardPrimitive.Positioner.Props,
|
|
35
|
+
| 'side'
|
|
36
|
+
| 'sideOffset'
|
|
37
|
+
| 'align'
|
|
38
|
+
| 'alignOffset'
|
|
39
|
+
| 'anchor'
|
|
40
|
+
| 'positionMethod'
|
|
41
|
+
| 'collisionBoundary'
|
|
42
|
+
| 'collisionPadding'
|
|
43
|
+
| 'collisionAvoidance'
|
|
44
|
+
| 'arrowPadding'
|
|
45
|
+
| 'sticky'
|
|
46
|
+
| 'disableAnchorTracking'
|
|
47
|
+
>;
|
|
46
48
|
|
|
47
49
|
export function HoverCard(props: Record<string, unknown>) @{
|
|
48
50
|
<PreviewCardPrimitive.Root data-slot="hover-card" {...props} />
|
|
@@ -33,21 +33,23 @@ import { cn } from '../../../lib/utils';
|
|
|
33
33
|
|
|
34
34
|
type Props = { className?: string; children?: OctaneNode } & Record<string, unknown>;
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
36
|
+
/** Props routed to the Positioner rather than the popup. */
|
|
37
|
+
export type BaseUiPositioningProps =
|
|
38
|
+
Pick<
|
|
39
|
+
MenuPrimitive.Positioner.Props,
|
|
40
|
+
| 'side'
|
|
41
|
+
| 'sideOffset'
|
|
42
|
+
| 'align'
|
|
43
|
+
| 'alignOffset'
|
|
44
|
+
| 'anchor'
|
|
45
|
+
| 'positionMethod'
|
|
46
|
+
| 'collisionBoundary'
|
|
47
|
+
| 'collisionPadding'
|
|
48
|
+
| 'collisionAvoidance'
|
|
49
|
+
| 'arrowPadding'
|
|
50
|
+
| 'sticky'
|
|
51
|
+
| 'disableAnchorTracking'
|
|
52
|
+
>;
|
|
51
53
|
|
|
52
54
|
export function Menubar({ className, ...props }: Props) @{
|
|
53
55
|
<MenubarPrimitive
|
|
@@ -170,7 +172,10 @@ export function MenubarCheckboxItem(props: Props & {
|
|
|
170
172
|
</MenuPrimitive.CheckboxItem>
|
|
171
173
|
}
|
|
172
174
|
|
|
173
|
-
export function MenubarRadioItem(props: Props & {
|
|
175
|
+
export function MenubarRadioItem(props: Omit<MenuPrimitive.RadioItem.Props, 'className'> & {
|
|
176
|
+
className?: string;
|
|
177
|
+
inset?: boolean;
|
|
178
|
+
}) @{
|
|
174
179
|
const { className, children: _children, inset, ...rest } = props;
|
|
175
180
|
|
|
176
181
|
<MenuPrimitive.RadioItem
|
|
@@ -41,21 +41,23 @@ export function PopoverTrigger(props: Record<string, unknown>) @{
|
|
|
41
41
|
<PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
44
|
+
/** Props routed to the Positioner rather than the popup. */
|
|
45
|
+
export type BaseUiPositioningProps =
|
|
46
|
+
Pick<
|
|
47
|
+
PopoverPrimitive.Positioner.Props,
|
|
48
|
+
| 'side'
|
|
49
|
+
| 'sideOffset'
|
|
50
|
+
| 'align'
|
|
51
|
+
| 'alignOffset'
|
|
52
|
+
| 'anchor'
|
|
53
|
+
| 'positionMethod'
|
|
54
|
+
| 'collisionBoundary'
|
|
55
|
+
| 'collisionPadding'
|
|
56
|
+
| 'collisionAvoidance'
|
|
57
|
+
| 'arrowPadding'
|
|
58
|
+
| 'sticky'
|
|
59
|
+
| 'disableAnchorTracking'
|
|
60
|
+
>;
|
|
59
61
|
|
|
60
62
|
export interface PopoverContentProps extends Record<string, unknown>, BaseUiPositioningProps {
|
|
61
63
|
className?: string;
|
|
@@ -23,29 +23,26 @@
|
|
|
23
23
|
// `thumbAlignment="edge"` is forwarded as upstream does: it insets the thumb so the two extremes
|
|
24
24
|
// sit flush with the ends of the track instead of overhanging them.
|
|
25
25
|
//
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
import { createElement, useMemo } from 'octane';
|
|
26
|
+
// One keyed thumb is rendered for each value.
|
|
27
|
+
import { useMemo } from 'octane';
|
|
29
28
|
import { Slider as SliderPrimitive } from '@octanejs/base-ui/slider';
|
|
30
29
|
|
|
31
30
|
import { cn } from '../../../lib/utils';
|
|
32
31
|
|
|
33
|
-
export interface SliderProps
|
|
32
|
+
export interface SliderProps<
|
|
33
|
+
Value extends number | readonly number[] = number | readonly number[],
|
|
34
|
+
> extends Omit<SliderPrimitive.Root.Props<Value>, 'className'> {
|
|
34
35
|
className?: string;
|
|
35
|
-
defaultValue?: number | number[];
|
|
36
|
-
value?: number | number[];
|
|
37
|
-
min?: number;
|
|
38
|
-
max?: number;
|
|
39
36
|
}
|
|
40
37
|
|
|
41
|
-
export function Slider({
|
|
38
|
+
export function Slider<Value extends number | readonly number[]>({
|
|
42
39
|
className,
|
|
43
40
|
defaultValue,
|
|
44
41
|
value,
|
|
45
42
|
min = 0,
|
|
46
43
|
max = 100,
|
|
47
44
|
...props
|
|
48
|
-
}: SliderProps) {
|
|
45
|
+
}: SliderProps<Value>) @{
|
|
49
46
|
// This drives HOW MANY THUMBS get rendered, so a value shape it fails to recognise is a visible
|
|
50
47
|
// bug rather than a type nicety.
|
|
51
48
|
//
|
|
@@ -67,45 +64,37 @@ export function Slider({
|
|
|
67
64
|
return [min, max];
|
|
68
65
|
}, [value, defaultValue, min, max]);
|
|
69
66
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
className
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
SliderPrimitive.
|
|
87
|
-
|
|
88
|
-
className
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
className
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
(_, index) => createElement(SliderPrimitive.Thumb, {
|
|
104
|
-
'data-slot': 'slider-thumb',
|
|
105
|
-
key: index,
|
|
106
|
-
className: 'relative block size-3 shrink-0 rounded-full border border-ring bg-white ring-ring/50 transition-[color,box-shadow] select-none after:absolute after:-inset-2 hover:ring-3 focus-visible:ring-3 focus-visible:outline-hidden active:ring-3 disabled:pointer-events-none disabled:opacity-50',
|
|
107
|
-
}),
|
|
108
|
-
),
|
|
109
|
-
),
|
|
110
|
-
);
|
|
67
|
+
<SliderPrimitive.Root
|
|
68
|
+
className={cn(
|
|
69
|
+
'data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full',
|
|
70
|
+
className,
|
|
71
|
+
)}
|
|
72
|
+
data-slot="slider"
|
|
73
|
+
defaultValue={defaultValue}
|
|
74
|
+
value={value}
|
|
75
|
+
min={min}
|
|
76
|
+
max={max}
|
|
77
|
+
thumbAlignment="edge"
|
|
78
|
+
{...props}
|
|
79
|
+
>
|
|
80
|
+
<SliderPrimitive.Control
|
|
81
|
+
className="relative flex w-full touch-none items-center select-none data-disabled:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-40 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col"
|
|
82
|
+
>
|
|
83
|
+
<SliderPrimitive.Track
|
|
84
|
+
data-slot="slider-track"
|
|
85
|
+
className="relative grow overflow-hidden rounded-full bg-muted select-none data-[orientation=horizontal]:h-1 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1"
|
|
86
|
+
>
|
|
87
|
+
<SliderPrimitive.Indicator
|
|
88
|
+
data-slot="slider-range"
|
|
89
|
+
className="bg-primary select-none data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full"
|
|
90
|
+
/>
|
|
91
|
+
</SliderPrimitive.Track>
|
|
92
|
+
@for (const index of _values.keys(); key index) {
|
|
93
|
+
<SliderPrimitive.Thumb
|
|
94
|
+
data-slot="slider-thumb"
|
|
95
|
+
className="relative block size-3 shrink-0 rounded-full border border-ring bg-white ring-ring/50 transition-[color,box-shadow] select-none after:absolute after:-inset-2 hover:ring-3 focus-visible:ring-3 focus-visible:outline-hidden active:ring-3 disabled:pointer-events-none disabled:opacity-50"
|
|
96
|
+
/>
|
|
97
|
+
}
|
|
98
|
+
</SliderPrimitive.Control>
|
|
99
|
+
</SliderPrimitive.Root>
|
|
111
100
|
}
|
|
@@ -2,17 +2,8 @@
|
|
|
2
2
|
// class strings verbatim. Runs on @octanejs/base-ui's `Tabs`, which was ported for this family:
|
|
3
3
|
// Root / List / Tab / Panel.
|
|
4
4
|
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// converts the orientation state to `data-orientation="horizontal" | "vertical"` instead, so those
|
|
8
|
-
// utilities would match nothing: the root would never switch to a column, and every
|
|
9
|
-
// `group-data-horizontal/tabs:` and `group-data-vertical/tabs:` selector on the trigger would be
|
|
10
|
-
// dead. They are written as `data-[orientation=…]:` here.
|
|
11
|
-
//
|
|
12
|
-
// This is the SAME skew the slider hit, and it is not a porting mistake in either layer — shadcn's
|
|
13
|
-
// Base UI sources target a newer Base UI than the pin this package binds. The primitive stays
|
|
14
|
-
// faithful to its pin; the adaptation belongs here. When the binding moves to a release that emits
|
|
15
|
-
// the bare attributes, these revert to upstream's spelling.
|
|
5
|
+
// Base UI 1.8 emits `data-orientation="horizontal" | "vertical"`, so orientation
|
|
6
|
+
// selectors target the attribute value on the root, list, trigger, and panel.
|
|
16
7
|
//
|
|
17
8
|
// `data-active` on the trigger needs no such treatment: the pin emits it exactly as upstream's
|
|
18
9
|
// classes expect (verified by rendering).
|
|
@@ -23,9 +14,9 @@ import { Tabs as TabsPrimitive } from '@octanejs/base-ui/tabs';
|
|
|
23
14
|
|
|
24
15
|
import { cn } from '../../../lib/utils';
|
|
25
16
|
|
|
26
|
-
type
|
|
17
|
+
type StyledProps<P> = Omit<P, 'className'> & { className?: string };
|
|
27
18
|
|
|
28
|
-
export interface TabsProps extends Props {
|
|
19
|
+
export interface TabsProps extends StyledProps<TabsPrimitive.Root.Props> {
|
|
29
20
|
orientation?: 'horizontal' | 'vertical';
|
|
30
21
|
}
|
|
31
22
|
|
|
@@ -54,7 +45,7 @@ export const tabsListVariants = cva(
|
|
|
54
45
|
},
|
|
55
46
|
);
|
|
56
47
|
|
|
57
|
-
export interface TabsListProps extends Props {
|
|
48
|
+
export interface TabsListProps extends StyledProps<TabsPrimitive.List.Props> {
|
|
58
49
|
variant?: VariantProps<typeof tabsListVariants>['variant'];
|
|
59
50
|
}
|
|
60
51
|
|
|
@@ -67,7 +58,7 @@ export function TabsList({ className, variant = 'default', ...props }: TabsListP
|
|
|
67
58
|
/>
|
|
68
59
|
}
|
|
69
60
|
|
|
70
|
-
export function TabsTrigger({ className, ...props }: Props) @{
|
|
61
|
+
export function TabsTrigger({ className, ...props }: StyledProps<TabsPrimitive.Tab.Props>) @{
|
|
71
62
|
<TabsPrimitive.Tab
|
|
72
63
|
data-slot="tabs-trigger"
|
|
73
64
|
className={cn(
|
|
@@ -81,7 +72,7 @@ export function TabsTrigger({ className, ...props }: Props) @{
|
|
|
81
72
|
/>
|
|
82
73
|
}
|
|
83
74
|
|
|
84
|
-
export function TabsContent({ className, ...props }: Props) @{
|
|
75
|
+
export function TabsContent({ className, ...props }: StyledProps<TabsPrimitive.Panel.Props>) @{
|
|
85
76
|
<TabsPrimitive.Panel
|
|
86
77
|
data-slot="tabs-content"
|
|
87
78
|
className={cn('flex-1 text-sm outline-none', className)}
|
|
@@ -20,13 +20,9 @@
|
|
|
20
20
|
// The pressed dialect is `data-pressed`, not radix's `data-[state=on]` — see toggle.tsrx, whose
|
|
21
21
|
// `toggleVariants` this file reuses, so the two bases cannot drift apart.
|
|
22
22
|
//
|
|
23
|
-
// ToggleGroup is composed with createElement: the consumer's children must sit INSIDE the context
|
|
24
|
-
// Provider, and opaque compiled .tsrx children can only flow through the props.children channel
|
|
25
|
-
// (see breadcrumb.tsrx's comment).
|
|
26
|
-
//
|
|
27
23
|
// UNVERIFIED PROVENANCE: class strings come from this package's radix base rather than
|
|
28
24
|
// transcribed from upstream's Base UI source.
|
|
29
|
-
import { createContext,
|
|
25
|
+
import { createContext, useContext, type CSSProperties, type OctaneNode } from 'octane';
|
|
30
26
|
import { type VariantProps } from 'class-variance-authority';
|
|
31
27
|
import { ToggleGroup as ToggleGroupPrimitive } from '@octanejs/base-ui/toggle-group';
|
|
32
28
|
import { Toggle as TogglePrimitive } from '@octanejs/base-ui/toggle';
|
|
@@ -65,32 +61,26 @@ export function ToggleGroup({
|
|
|
65
61
|
type,
|
|
66
62
|
children,
|
|
67
63
|
...props
|
|
68
|
-
}: ToggleGroupProps) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
createElement(
|
|
89
|
-
ToggleGroupContext.Provider,
|
|
90
|
-
{ value: { variant, size, spacing, orientation } },
|
|
91
|
-
children,
|
|
92
|
-
),
|
|
93
|
-
);
|
|
64
|
+
}: ToggleGroupProps) @{
|
|
65
|
+
const style: CSSProperties & { '--gap': number } = { '--gap': spacing };
|
|
66
|
+
<ToggleGroupPrimitive
|
|
67
|
+
data-slot="toggle-group"
|
|
68
|
+
data-variant={variant}
|
|
69
|
+
data-size={size}
|
|
70
|
+
data-spacing={spacing}
|
|
71
|
+
orientation={orientation}
|
|
72
|
+
multiple={type === 'multiple'}
|
|
73
|
+
style={style}
|
|
74
|
+
className={cn(
|
|
75
|
+
'group/toggle-group flex w-fit items-center gap-[--spacing(var(--gap))] rounded-md data-[spacing=default]:data-[variant=outline]:shadow-xs',
|
|
76
|
+
className,
|
|
77
|
+
)}
|
|
78
|
+
{...props}
|
|
79
|
+
>
|
|
80
|
+
<ToggleGroupContext.Provider
|
|
81
|
+
value={{ variant, size, spacing, orientation }}
|
|
82
|
+
>{children}</ToggleGroupContext.Provider>
|
|
83
|
+
</ToggleGroupPrimitive>
|
|
94
84
|
}
|
|
95
85
|
|
|
96
86
|
export interface ToggleGroupItemProps extends Record<string, unknown> {
|
|
@@ -39,21 +39,23 @@ export interface TooltipContentProps extends Record<string, unknown> {
|
|
|
39
39
|
children?: OctaneNode;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
42
|
+
/** Props routed to the Positioner rather than the popup. */
|
|
43
|
+
export type BaseUiPositioningProps =
|
|
44
|
+
Pick<
|
|
45
|
+
TooltipPrimitive.Positioner.Props,
|
|
46
|
+
| 'side'
|
|
47
|
+
| 'sideOffset'
|
|
48
|
+
| 'align'
|
|
49
|
+
| 'alignOffset'
|
|
50
|
+
| 'anchor'
|
|
51
|
+
| 'positionMethod'
|
|
52
|
+
| 'collisionBoundary'
|
|
53
|
+
| 'collisionPadding'
|
|
54
|
+
| 'collisionAvoidance'
|
|
55
|
+
| 'arrowPadding'
|
|
56
|
+
| 'sticky'
|
|
57
|
+
| 'disableAnchorTracking'
|
|
58
|
+
>;
|
|
57
59
|
|
|
58
60
|
export function TooltipContent({
|
|
59
61
|
className,
|