@octanejs/shadcn 0.0.1
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 +43 -0
- package/package.json +63 -0
- package/src/hooks/use-mobile.ts +23 -0
- package/src/index.ts +263 -0
- package/src/lib/types.ts +10 -0
- package/src/lib/utils.ts +8 -0
- package/src/styles/theme.css +104 -0
- package/src/ui/accordion.tsrx +72 -0
- package/src/ui/alert-dialog.tsrx +161 -0
- package/src/ui/alert.tsrx +69 -0
- package/src/ui/aspect-ratio.tsrx +10 -0
- package/src/ui/avatar.tsrx +79 -0
- package/src/ui/badge.tsrx +50 -0
- package/src/ui/breadcrumb.tsrx +89 -0
- package/src/ui/button.tsrx +71 -0
- package/src/ui/card.tsrx +75 -0
- package/src/ui/checkbox.tsrx +31 -0
- package/src/ui/collapsible.tsrx +21 -0
- package/src/ui/context-menu.tsrx +179 -0
- package/src/ui/dialog.tsrx +133 -0
- package/src/ui/dropdown-menu.tsrx +189 -0
- package/src/ui/empty.tsrx +86 -0
- package/src/ui/field.tsrx +188 -0
- package/src/ui/hover-card.tsrx +48 -0
- package/src/ui/input.tsrx +18 -0
- package/src/ui/item.tsrx +171 -0
- package/src/ui/kbd.tsrx +26 -0
- package/src/ui/label.tsrx +21 -0
- package/src/ui/menubar.tsrx +198 -0
- package/src/ui/native-select.tsrx +55 -0
- package/src/ui/navigation-menu.tsrx +116 -0
- package/src/ui/pagination.tsrx +113 -0
- package/src/ui/popover.tsrx +73 -0
- package/src/ui/progress.tsrx +27 -0
- package/src/ui/radio-group.tsrx +37 -0
- package/src/ui/scroll-area.tsrx +43 -0
- package/src/ui/select.tsrx +165 -0
- package/src/ui/separator.tsrx +30 -0
- package/src/ui/sheet.tsrx +114 -0
- package/src/ui/sidebar.tsrx +661 -0
- package/src/ui/skeleton.tsrx +14 -0
- package/src/ui/slider.tsrx +69 -0
- package/src/ui/sonner.tsrx +45 -0
- package/src/ui/spinner.tsrx +23 -0
- package/src/ui/switch.tsrx +30 -0
- package/src/ui/table.tsrx +80 -0
- package/src/ui/tabs.tsrx +69 -0
- package/src/ui/textarea.tsrx +20 -0
- package/src/ui/toggle-group.tsrx +100 -0
- package/src/ui/toggle.tsrx +47 -0
- package/src/ui/tooltip.tsrx +65 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// Default-Tailwind alert-dialog flavor (package canonical) — user-supplied
|
|
2
|
+
// styling, class strings verbatim. Octane adaptations: "use client" dropped,
|
|
3
|
+
// radix-ui → @octanejs/radix; Content composes Portal > Overlay + Content via
|
|
4
|
+
// createElement (Portal slots its child); Action/Cancel wrap the primitive in
|
|
5
|
+
// Button-asChild (descriptor child), consumer children via props.children.
|
|
6
|
+
import { createElement, type OctaneNode } from 'octane';
|
|
7
|
+
import { AlertDialog as AlertDialogPrimitive } from '@octanejs/radix';
|
|
8
|
+
|
|
9
|
+
import { cn } from '../lib/utils';
|
|
10
|
+
import { Button, type ButtonProps } from './button.tsrx';
|
|
11
|
+
|
|
12
|
+
type Props = { className?: string; children?: OctaneNode } & Record<string, unknown>;
|
|
13
|
+
|
|
14
|
+
export function AlertDialog(props: Record<string, unknown>) @{
|
|
15
|
+
<AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function AlertDialogTrigger(props: Record<string, unknown>) @{
|
|
19
|
+
<AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function AlertDialogPortal(props: Record<string, unknown>) @{
|
|
23
|
+
<AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function AlertDialogOverlay({ className, ...props }: Props) @{
|
|
27
|
+
<AlertDialogPrimitive.Overlay
|
|
28
|
+
data-slot="alert-dialog-overlay"
|
|
29
|
+
className={cn(
|
|
30
|
+
'fixed inset-0 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',
|
|
31
|
+
className,
|
|
32
|
+
)}
|
|
33
|
+
{...props}
|
|
34
|
+
/>
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface AlertDialogContentProps extends Props {
|
|
38
|
+
size?: 'default' | 'sm';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function AlertDialogContent({
|
|
42
|
+
className,
|
|
43
|
+
size = 'default',
|
|
44
|
+
children,
|
|
45
|
+
...props
|
|
46
|
+
}: AlertDialogContentProps) {
|
|
47
|
+
return createElement(
|
|
48
|
+
AlertDialogPrimitive.Portal,
|
|
49
|
+
{ 'data-slot': 'alert-dialog-portal' },
|
|
50
|
+
createElement(AlertDialogOverlay, { key: 'overlay' }),
|
|
51
|
+
createElement(AlertDialogPrimitive.Content, {
|
|
52
|
+
key: 'content',
|
|
53
|
+
'data-slot': 'alert-dialog-content',
|
|
54
|
+
'data-size': size,
|
|
55
|
+
className: cn(
|
|
56
|
+
'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',
|
|
57
|
+
className,
|
|
58
|
+
),
|
|
59
|
+
...props,
|
|
60
|
+
children,
|
|
61
|
+
}),
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function AlertDialogHeader({ className, ...props }: Props) @{
|
|
66
|
+
<div
|
|
67
|
+
data-slot="alert-dialog-header"
|
|
68
|
+
className={cn(
|
|
69
|
+
'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]',
|
|
70
|
+
className,
|
|
71
|
+
)}
|
|
72
|
+
{...props}
|
|
73
|
+
/>
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function AlertDialogFooter({ className, ...props }: Props) @{
|
|
77
|
+
<div
|
|
78
|
+
data-slot="alert-dialog-footer"
|
|
79
|
+
className={cn(
|
|
80
|
+
'-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',
|
|
81
|
+
className,
|
|
82
|
+
)}
|
|
83
|
+
{...props}
|
|
84
|
+
/>
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function AlertDialogMedia({ className, ...props }: Props) @{
|
|
88
|
+
<div
|
|
89
|
+
data-slot="alert-dialog-media"
|
|
90
|
+
className={cn(
|
|
91
|
+
'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',
|
|
92
|
+
className,
|
|
93
|
+
)}
|
|
94
|
+
{...props}
|
|
95
|
+
/>
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function AlertDialogTitle({ className, ...props }: Props) @{
|
|
99
|
+
<AlertDialogPrimitive.Title
|
|
100
|
+
data-slot="alert-dialog-title"
|
|
101
|
+
className={cn(
|
|
102
|
+
'cn-font-heading 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',
|
|
103
|
+
className,
|
|
104
|
+
)}
|
|
105
|
+
{...props}
|
|
106
|
+
/>
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function AlertDialogDescription({ className, ...props }: Props) @{
|
|
110
|
+
<AlertDialogPrimitive.Description
|
|
111
|
+
data-slot="alert-dialog-description"
|
|
112
|
+
className={cn(
|
|
113
|
+
'text-sm text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground',
|
|
114
|
+
className,
|
|
115
|
+
)}
|
|
116
|
+
{...props}
|
|
117
|
+
/>
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface AlertDialogActionProps extends Props {
|
|
121
|
+
variant?: ButtonProps['variant'];
|
|
122
|
+
size?: ButtonProps['size'];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function AlertDialogAction({
|
|
126
|
+
className,
|
|
127
|
+
variant = 'default',
|
|
128
|
+
size = 'default',
|
|
129
|
+
children,
|
|
130
|
+
...props
|
|
131
|
+
}: AlertDialogActionProps) {
|
|
132
|
+
return createElement(
|
|
133
|
+
Button,
|
|
134
|
+
{ variant, size, asChild: true },
|
|
135
|
+
createElement(AlertDialogPrimitive.Action, {
|
|
136
|
+
'data-slot': 'alert-dialog-action',
|
|
137
|
+
className: cn(className),
|
|
138
|
+
...props,
|
|
139
|
+
children,
|
|
140
|
+
}),
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function AlertDialogCancel({
|
|
145
|
+
className,
|
|
146
|
+
variant = 'outline',
|
|
147
|
+
size = 'default',
|
|
148
|
+
children,
|
|
149
|
+
...props
|
|
150
|
+
}: AlertDialogActionProps) {
|
|
151
|
+
return createElement(
|
|
152
|
+
Button,
|
|
153
|
+
{ variant, size, asChild: true },
|
|
154
|
+
createElement(AlertDialogPrimitive.Cancel, {
|
|
155
|
+
'data-slot': 'alert-dialog-cancel',
|
|
156
|
+
className: cn(className),
|
|
157
|
+
...props,
|
|
158
|
+
children,
|
|
159
|
+
}),
|
|
160
|
+
);
|
|
161
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Default-Tailwind alert flavor (package canonical) — user-supplied styling,
|
|
2
|
+
// cva strings verbatim. Pure template JSX (no consumer-children interleave).
|
|
3
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
4
|
+
|
|
5
|
+
import { cn } from '../lib/utils';
|
|
6
|
+
import type { DivProps } from '../lib/types';
|
|
7
|
+
|
|
8
|
+
export const alertVariants = cva(
|
|
9
|
+
'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',
|
|
10
|
+
{
|
|
11
|
+
variants: {
|
|
12
|
+
variant: {
|
|
13
|
+
default: 'bg-card text-card-foreground',
|
|
14
|
+
destructive: 'bg-card text-destructive *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
defaultVariants: {
|
|
18
|
+
variant: 'default',
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
export interface AlertProps extends DivProps {
|
|
24
|
+
variant?: VariantProps<typeof alertVariants>['variant'];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function Alert({ className, variant, ...props }: AlertProps) @{
|
|
28
|
+
<div
|
|
29
|
+
data-slot="alert"
|
|
30
|
+
role="alert"
|
|
31
|
+
className={cn(alertVariants({ variant }), className)}
|
|
32
|
+
{...props}
|
|
33
|
+
/>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function AlertTitle({ className, ...props }: { className?: string } & Record<
|
|
37
|
+
string,
|
|
38
|
+
unknown
|
|
39
|
+
>) @{
|
|
40
|
+
<div
|
|
41
|
+
data-slot="alert-title"
|
|
42
|
+
className={cn(
|
|
43
|
+
'font-medium group-has-[>svg]/alert:col-start-2 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground',
|
|
44
|
+
className,
|
|
45
|
+
)}
|
|
46
|
+
{...props}
|
|
47
|
+
/>
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function AlertDescription({ className, ...props }: { className?: string } & Record<
|
|
51
|
+
string,
|
|
52
|
+
unknown
|
|
53
|
+
>) @{
|
|
54
|
+
<div
|
|
55
|
+
data-slot="alert-description"
|
|
56
|
+
className={cn(
|
|
57
|
+
'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',
|
|
58
|
+
className,
|
|
59
|
+
)}
|
|
60
|
+
{...props}
|
|
61
|
+
/>
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function AlertAction({ className, ...props }: { className?: string } & Record<
|
|
65
|
+
string,
|
|
66
|
+
unknown
|
|
67
|
+
>) @{
|
|
68
|
+
<div data-slot="alert-action" className={cn('absolute top-2 right-2', className)} {...props} />
|
|
69
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Ported from shadcn-ui/ui@4baadbc6517070ae8f8feb2c97037adc2b305544
|
|
2
|
+
// apps/v4/registry/bases/radix/ui/aspect-ratio.tsx (the `"use client"`
|
|
3
|
+
// directive is dropped — octane has no RSC axis).
|
|
4
|
+
import { AspectRatio as AspectRatioPrimitive } from '@octanejs/radix';
|
|
5
|
+
|
|
6
|
+
type Props = Record<string, unknown>;
|
|
7
|
+
|
|
8
|
+
export function AspectRatio(props: Props) @{
|
|
9
|
+
<AspectRatioPrimitive.Root data-slot="aspect-ratio" {...props} />
|
|
10
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Default-Tailwind avatar flavor (package canonical) — user-supplied styling,
|
|
2
|
+
// class strings verbatim. Octane adaptations: "use client" dropped, radix-ui →
|
|
3
|
+
// @octanejs/radix; pure template JSX.
|
|
4
|
+
import { Avatar as AvatarPrimitive } from '@octanejs/radix';
|
|
5
|
+
|
|
6
|
+
import { cn } from '../lib/utils';
|
|
7
|
+
|
|
8
|
+
type Props = { className?: string } & Record<string, unknown>;
|
|
9
|
+
|
|
10
|
+
export interface AvatarProps extends Props {
|
|
11
|
+
size?: 'default' | 'sm' | 'lg';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function Avatar({ className, size = 'default', ...props }: AvatarProps) @{
|
|
15
|
+
<AvatarPrimitive.Root
|
|
16
|
+
data-slot="avatar"
|
|
17
|
+
data-size={size}
|
|
18
|
+
className={cn(
|
|
19
|
+
'group/avatar relative flex size-8 shrink-0 rounded-full select-none after:absolute after:inset-0 after:rounded-full after:border after:border-border after:mix-blend-darken data-[size=lg]:size-10 data-[size=sm]:size-6 dark:after:mix-blend-lighten',
|
|
20
|
+
className,
|
|
21
|
+
)}
|
|
22
|
+
{...props}
|
|
23
|
+
/>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function AvatarImage({ className, ...props }: Props) @{
|
|
27
|
+
<AvatarPrimitive.Image
|
|
28
|
+
data-slot="avatar-image"
|
|
29
|
+
className={cn('aspect-square size-full rounded-full object-cover', className)}
|
|
30
|
+
{...props}
|
|
31
|
+
/>
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function AvatarFallback({ className, ...props }: Props) @{
|
|
35
|
+
<AvatarPrimitive.Fallback
|
|
36
|
+
data-slot="avatar-fallback"
|
|
37
|
+
className={cn(
|
|
38
|
+
'flex size-full items-center justify-center rounded-full bg-muted text-sm text-muted-foreground group-data-[size=sm]/avatar:text-xs',
|
|
39
|
+
className,
|
|
40
|
+
)}
|
|
41
|
+
{...props}
|
|
42
|
+
/>
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function AvatarBadge({ className, ...props }: Props) @{
|
|
46
|
+
<span
|
|
47
|
+
data-slot="avatar-badge"
|
|
48
|
+
className={cn(
|
|
49
|
+
'absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground bg-blend-color ring-2 ring-background select-none',
|
|
50
|
+
'group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden',
|
|
51
|
+
'group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2',
|
|
52
|
+
'group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2',
|
|
53
|
+
className,
|
|
54
|
+
)}
|
|
55
|
+
{...props}
|
|
56
|
+
/>
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function AvatarGroup({ className, ...props }: Props) @{
|
|
60
|
+
<div
|
|
61
|
+
data-slot="avatar-group"
|
|
62
|
+
className={cn(
|
|
63
|
+
'group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background',
|
|
64
|
+
className,
|
|
65
|
+
)}
|
|
66
|
+
{...props}
|
|
67
|
+
/>
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function AvatarGroupCount({ className, ...props }: Props) @{
|
|
71
|
+
<div
|
|
72
|
+
data-slot="avatar-group-count"
|
|
73
|
+
className={cn(
|
|
74
|
+
'relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-muted-foreground ring-2 ring-background group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3',
|
|
75
|
+
className,
|
|
76
|
+
)}
|
|
77
|
+
{...props}
|
|
78
|
+
/>
|
|
79
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Default-Tailwind (package canonical) badge — user-supplied flavor, cva strings verbatim. Octane
|
|
2
|
+
// adaptations: radix-ui Slot → @octanejs/radix, asChild via the @if/Slot
|
|
3
|
+
// descriptor pattern.
|
|
4
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
5
|
+
import { Slot } from '@octanejs/radix';
|
|
6
|
+
|
|
7
|
+
import { cn } from '../lib/utils';
|
|
8
|
+
import type { HostProps } from '../lib/types';
|
|
9
|
+
|
|
10
|
+
export const badgeVariants = cva(
|
|
11
|
+
'group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!',
|
|
12
|
+
{
|
|
13
|
+
variants: {
|
|
14
|
+
variant: {
|
|
15
|
+
default: 'bg-primary text-primary-foreground [a]:hover:bg-primary/80',
|
|
16
|
+
secondary: 'bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80',
|
|
17
|
+
destructive: 'bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20',
|
|
18
|
+
outline: 'border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground',
|
|
19
|
+
ghost: 'hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50',
|
|
20
|
+
link: 'text-primary underline-offset-4 hover:underline',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
defaultVariants: {
|
|
24
|
+
variant: 'default',
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export interface BadgeProps extends HostProps<'span'> {
|
|
30
|
+
variant?: VariantProps<typeof badgeVariants>['variant'];
|
|
31
|
+
asChild?: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function Badge({ className, variant = 'default', asChild = false, ...props }: BadgeProps) @{
|
|
35
|
+
@if (asChild) {
|
|
36
|
+
<Slot
|
|
37
|
+
data-slot="badge"
|
|
38
|
+
data-variant={variant}
|
|
39
|
+
className={cn(badgeVariants({ variant }), className)}
|
|
40
|
+
{...props}
|
|
41
|
+
/>
|
|
42
|
+
} @else {
|
|
43
|
+
<span
|
|
44
|
+
data-slot="badge"
|
|
45
|
+
data-variant={variant}
|
|
46
|
+
className={cn(badgeVariants({ variant }), className)}
|
|
47
|
+
{...props}
|
|
48
|
+
/>
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// Default-Tailwind breadcrumb flavor (package canonical) — user-supplied
|
|
2
|
+
// styling, class strings verbatim. Octane adaptations: lucide-react →
|
|
3
|
+
// @octanejs/lucide, radix-ui Slot → @octanejs/radix (@if asChild);
|
|
4
|
+
// BreadcrumbSeparator's `children ?? icon` fallback composes with
|
|
5
|
+
// createElement (opaque children beside a descriptor default).
|
|
6
|
+
import { Slot } from '@octanejs/radix';
|
|
7
|
+
import { ChevronRightIcon, MoreHorizontalIcon } from '@octanejs/lucide';
|
|
8
|
+
import { createElement, type OctaneNode } from 'octane';
|
|
9
|
+
|
|
10
|
+
import { cn } from '../lib/utils';
|
|
11
|
+
|
|
12
|
+
type Props = { className?: string } & Record<string, unknown>;
|
|
13
|
+
|
|
14
|
+
export function Breadcrumb({ className, ...props }: Props) @{
|
|
15
|
+
<nav aria-label="breadcrumb" data-slot="breadcrumb" className={cn(className)} {...props} />
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function BreadcrumbList({ className, ...props }: Props) @{
|
|
19
|
+
<ol
|
|
20
|
+
data-slot="breadcrumb-list"
|
|
21
|
+
className={cn(
|
|
22
|
+
'flex flex-wrap items-center gap-1.5 text-sm wrap-break-word text-muted-foreground',
|
|
23
|
+
className,
|
|
24
|
+
)}
|
|
25
|
+
{...props}
|
|
26
|
+
/>
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function BreadcrumbItem({ className, ...props }: Props) @{
|
|
30
|
+
<li
|
|
31
|
+
data-slot="breadcrumb-item"
|
|
32
|
+
className={cn('inline-flex items-center gap-1', className)}
|
|
33
|
+
{...props}
|
|
34
|
+
/>
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function BreadcrumbLink({ asChild, className, ...props }: Props & { asChild?: boolean }) @{
|
|
38
|
+
@if (asChild) {
|
|
39
|
+
<Slot
|
|
40
|
+
data-slot="breadcrumb-link"
|
|
41
|
+
className={cn('transition-colors hover:text-foreground', className)}
|
|
42
|
+
{...props}
|
|
43
|
+
/>
|
|
44
|
+
} @else {
|
|
45
|
+
<a
|
|
46
|
+
data-slot="breadcrumb-link"
|
|
47
|
+
className={cn('transition-colors hover:text-foreground', className)}
|
|
48
|
+
{...props}
|
|
49
|
+
/>
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function BreadcrumbPage({ className, ...props }: Props) @{
|
|
54
|
+
<span
|
|
55
|
+
data-slot="breadcrumb-page"
|
|
56
|
+
role="link"
|
|
57
|
+
aria-disabled="true"
|
|
58
|
+
aria-current="page"
|
|
59
|
+
className={cn('font-normal text-foreground', className)}
|
|
60
|
+
{...props}
|
|
61
|
+
/>
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function BreadcrumbSeparator(props: Props & { children?: OctaneNode }) @{
|
|
65
|
+
const { className, children: _children, ...rest } = props;
|
|
66
|
+
|
|
67
|
+
<li
|
|
68
|
+
data-slot="breadcrumb-separator"
|
|
69
|
+
role="presentation"
|
|
70
|
+
aria-hidden="true"
|
|
71
|
+
className={cn('[&>svg]:size-3.5', className)}
|
|
72
|
+
{...rest}
|
|
73
|
+
>
|
|
74
|
+
{props.children ?? <ChevronRightIcon className="cn-rtl-flip" />}
|
|
75
|
+
</li>
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function BreadcrumbEllipsis({ className, ...props }: Props) @{
|
|
79
|
+
<span
|
|
80
|
+
data-slot="breadcrumb-ellipsis"
|
|
81
|
+
role="presentation"
|
|
82
|
+
aria-hidden="true"
|
|
83
|
+
className={cn('flex size-5 items-center justify-center [&>svg]:size-4', className)}
|
|
84
|
+
{...props}
|
|
85
|
+
>
|
|
86
|
+
<MoreHorizontalIcon />
|
|
87
|
+
<span className="sr-only">More</span>
|
|
88
|
+
</span>
|
|
89
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Default-Tailwind (package canonical) button — the Base UI shadcn flavor's styling, verbatim cva
|
|
2
|
+
// strings. ADAPTATION: upstream builds on @base-ui/react/button, which
|
|
3
|
+
// @octanejs/base-ui does not yet ship (binding gap, logged) — the host is a
|
|
4
|
+
// plain <button>, and Base UI's render-prop polymorphism maps to octane's
|
|
5
|
+
// asChild/Slot descriptor pattern. Upstream's base flavor sets no
|
|
6
|
+
// data-variant/data-size attributes; preserved as-is.
|
|
7
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
8
|
+
import { Slot } from '@octanejs/radix';
|
|
9
|
+
|
|
10
|
+
import { cn } from '../lib/utils';
|
|
11
|
+
import type { HostProps } from '../lib/types';
|
|
12
|
+
|
|
13
|
+
export const buttonVariants = cva(
|
|
14
|
+
'group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4',
|
|
15
|
+
{
|
|
16
|
+
variants: {
|
|
17
|
+
variant: {
|
|
18
|
+
default: 'bg-primary text-primary-foreground hover:bg-primary/80',
|
|
19
|
+
outline: 'border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50',
|
|
20
|
+
secondary: 'bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground',
|
|
21
|
+
ghost: 'hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50',
|
|
22
|
+
destructive: 'bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40',
|
|
23
|
+
link: 'text-primary underline-offset-4 hover:underline',
|
|
24
|
+
},
|
|
25
|
+
size: {
|
|
26
|
+
default: 'h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',
|
|
27
|
+
xs: 'h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*=\'size-\'])]:size-3',
|
|
28
|
+
sm: 'h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*=\'size-\'])]:size-3.5',
|
|
29
|
+
lg: 'h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',
|
|
30
|
+
icon: 'size-8',
|
|
31
|
+
'icon-xs': 'size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*=\'size-\'])]:size-3',
|
|
32
|
+
'icon-sm': 'size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg',
|
|
33
|
+
'icon-lg': 'size-9',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
defaultVariants: {
|
|
37
|
+
variant: 'default',
|
|
38
|
+
size: 'default',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
export interface ButtonProps extends HostProps<'button'> {
|
|
44
|
+
variant?: VariantProps<typeof buttonVariants>['variant'];
|
|
45
|
+
size?: VariantProps<typeof buttonVariants>['size'];
|
|
46
|
+
// OCTANE DIVERGENCE: asChild composes element descriptors (createElement),
|
|
47
|
+
// not opaque compiled .tsrx children — the documented radix Slot contract.
|
|
48
|
+
asChild?: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function Button({
|
|
52
|
+
className,
|
|
53
|
+
variant = 'default',
|
|
54
|
+
size = 'default',
|
|
55
|
+
asChild = false,
|
|
56
|
+
...props
|
|
57
|
+
}: ButtonProps) @{
|
|
58
|
+
@if (asChild) {
|
|
59
|
+
<Slot
|
|
60
|
+
data-slot="button"
|
|
61
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
62
|
+
{...props}
|
|
63
|
+
/>
|
|
64
|
+
} @else {
|
|
65
|
+
<button
|
|
66
|
+
data-slot="button"
|
|
67
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
68
|
+
{...props}
|
|
69
|
+
/>
|
|
70
|
+
}
|
|
71
|
+
}
|
package/src/ui/card.tsrx
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Default-Tailwind (package canonical) card — user-supplied flavor, class strings verbatim (uses the
|
|
2
|
+
// --card-spacing custom-property pattern and the nova cn-font-heading hook).
|
|
3
|
+
import { cn } from '../lib/utils';
|
|
4
|
+
import type { DivProps } from '../lib/types';
|
|
5
|
+
|
|
6
|
+
type Props = DivProps;
|
|
7
|
+
|
|
8
|
+
export interface CardProps extends Props {
|
|
9
|
+
size?: 'default' | 'sm';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function Card({ className, size = 'default', ...props }: CardProps) @{
|
|
13
|
+
<div
|
|
14
|
+
data-slot="card"
|
|
15
|
+
data-size={size}
|
|
16
|
+
className={cn(
|
|
17
|
+
'group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded-xl bg-card py-(--card-spacing) text-sm text-card-foreground ring-1 ring-foreground/10 [--card-spacing:--spacing(4)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl',
|
|
18
|
+
className,
|
|
19
|
+
)}
|
|
20
|
+
{...props}
|
|
21
|
+
/>
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function CardHeader({ className, ...props }: Props) @{
|
|
25
|
+
<div
|
|
26
|
+
data-slot="card-header"
|
|
27
|
+
className={cn(
|
|
28
|
+
'group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)',
|
|
29
|
+
className,
|
|
30
|
+
)}
|
|
31
|
+
{...props}
|
|
32
|
+
/>
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function CardTitle({ className, ...props }: Props) @{
|
|
36
|
+
<div
|
|
37
|
+
data-slot="card-title"
|
|
38
|
+
className={cn(
|
|
39
|
+
'cn-font-heading text-base leading-snug font-medium group-data-[size=sm]/card:text-sm',
|
|
40
|
+
className,
|
|
41
|
+
)}
|
|
42
|
+
{...props}
|
|
43
|
+
/>
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function CardDescription({ className, ...props }: Props) @{
|
|
47
|
+
<div
|
|
48
|
+
data-slot="card-description"
|
|
49
|
+
className={cn('text-sm text-muted-foreground', className)}
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function CardAction({ className, ...props }: Props) @{
|
|
55
|
+
<div
|
|
56
|
+
data-slot="card-action"
|
|
57
|
+
className={cn('col-start-2 row-span-2 row-start-1 self-start justify-self-end', className)}
|
|
58
|
+
{...props}
|
|
59
|
+
/>
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function CardContent({ className, ...props }: Props) @{
|
|
63
|
+
<div data-slot="card-content" className={cn('px-(--card-spacing)', className)} {...props} />
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function CardFooter({ className, ...props }: Props) @{
|
|
67
|
+
<div
|
|
68
|
+
data-slot="card-footer"
|
|
69
|
+
className={cn(
|
|
70
|
+
'flex items-center rounded-b-xl border-t bg-muted/50 p-(--card-spacing)',
|
|
71
|
+
className,
|
|
72
|
+
)}
|
|
73
|
+
{...props}
|
|
74
|
+
/>
|
|
75
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Default-Tailwind (utilities-inlined) checkbox flavor — the package's
|
|
2
|
+
// canonical styling direction. Octane adaptations from the shared React
|
|
3
|
+
// source: "use client" dropped, lucide-react → @octanejs/lucide, radix-ui →
|
|
4
|
+
// @octanejs/radix; structure (Root > Indicator > CheckIcon) is template JSX
|
|
5
|
+
// (no consumer children interleave).
|
|
6
|
+
import { Checkbox as CheckboxPrimitive } from '@octanejs/radix';
|
|
7
|
+
import { CheckIcon } from '@octanejs/lucide';
|
|
8
|
+
|
|
9
|
+
import { cn } from '../lib/utils';
|
|
10
|
+
|
|
11
|
+
export interface CheckboxProps extends Record<string, unknown> {
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function Checkbox({ className, ...props }: CheckboxProps) @{
|
|
16
|
+
<CheckboxPrimitive.Root
|
|
17
|
+
data-slot="checkbox"
|
|
18
|
+
className={cn(
|
|
19
|
+
'peer relative flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-input transition-colors outline-none group-has-disabled/field:opacity-50 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary',
|
|
20
|
+
className,
|
|
21
|
+
)}
|
|
22
|
+
{...props}
|
|
23
|
+
>
|
|
24
|
+
<CheckboxPrimitive.Indicator
|
|
25
|
+
data-slot="checkbox-indicator"
|
|
26
|
+
className="grid place-content-center text-current transition-none [&>svg]:size-3.5"
|
|
27
|
+
>
|
|
28
|
+
<CheckIcon />
|
|
29
|
+
</CheckboxPrimitive.Indicator>
|
|
30
|
+
</CheckboxPrimitive.Root>
|
|
31
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Ported from shadcn-ui/ui@4baadbc6517070ae8f8feb2c97037adc2b305544
|
|
2
|
+
// apps/v4/registry/bases/radix/ui/collapsible.tsx (the `"use client"`
|
|
3
|
+
// directive is dropped — octane has no RSC axis). Upstream references the
|
|
4
|
+
// `CollapsiblePrimitive.CollapsibleTrigger` / `CollapsibleContent` aliases;
|
|
5
|
+
// the @octanejs/radix binding exports the same components as `Trigger` /
|
|
6
|
+
// `Content`.
|
|
7
|
+
import { Collapsible as CollapsiblePrimitive } from '@octanejs/radix';
|
|
8
|
+
|
|
9
|
+
type Props = Record<string, unknown>;
|
|
10
|
+
|
|
11
|
+
export function Collapsible(props: Props) @{
|
|
12
|
+
<CollapsiblePrimitive.Root data-slot="collapsible" {...props} />
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function CollapsibleTrigger(props: Props) @{
|
|
16
|
+
<CollapsiblePrimitive.Trigger data-slot="collapsible-trigger" {...props} />
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function CollapsibleContent(props: Props) @{
|
|
20
|
+
<CollapsiblePrimitive.Content data-slot="collapsible-content" {...props} />
|
|
21
|
+
}
|