@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,55 @@
|
|
|
1
|
+
// NativeSelect — maintainer-supplied default-Tailwind flavor, class strings
|
|
2
|
+
// verbatim. Octane adaptations: lucide-react → @octanejs/lucide.
|
|
3
|
+
//
|
|
4
|
+
// The consumer className lands on the WRAPPER div (upstream behavior); the
|
|
5
|
+
// <select> and the chevron keep their fixed classes.
|
|
6
|
+
import { ChevronDownIcon } from '@octanejs/lucide';
|
|
7
|
+
|
|
8
|
+
import { cn } from '../lib/utils';
|
|
9
|
+
|
|
10
|
+
export interface NativeSelectProps extends Record<string, unknown> {
|
|
11
|
+
className?: string;
|
|
12
|
+
size?: 'sm' | 'default';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function NativeSelect({ className, size = 'default', ...props }: NativeSelectProps) @{
|
|
16
|
+
<div
|
|
17
|
+
className={cn('group/native-select relative w-fit has-[select:disabled]:opacity-50', className)}
|
|
18
|
+
data-slot="native-select-wrapper"
|
|
19
|
+
data-size={size}
|
|
20
|
+
>
|
|
21
|
+
<select
|
|
22
|
+
data-slot="native-select"
|
|
23
|
+
data-size={size}
|
|
24
|
+
className="h-8 w-full min-w-0 appearance-none rounded-lg border border-input bg-transparent py-1 pr-8 pl-2.5 text-sm transition-colors outline-none select-none selection:bg-primary selection:text-primary-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] data-[size=sm]:py-0.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40"
|
|
25
|
+
{...props}
|
|
26
|
+
/>
|
|
27
|
+
<ChevronDownIcon
|
|
28
|
+
className="pointer-events-none absolute top-1/2 right-2.5 size-4 -translate-y-1/2 text-muted-foreground select-none"
|
|
29
|
+
aria-hidden="true"
|
|
30
|
+
data-slot="native-select-icon"
|
|
31
|
+
/>
|
|
32
|
+
</div>
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function NativeSelectOption({ className, ...props }: { className?: string } & Record<
|
|
36
|
+
string,
|
|
37
|
+
unknown
|
|
38
|
+
>) @{
|
|
39
|
+
<option
|
|
40
|
+
data-slot="native-select-option"
|
|
41
|
+
className={cn('bg-[Canvas] text-[CanvasText]', className)}
|
|
42
|
+
{...props}
|
|
43
|
+
/>
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function NativeSelectOptGroup({ className, ...props }: { className?: string } & Record<
|
|
47
|
+
string,
|
|
48
|
+
unknown
|
|
49
|
+
>) @{
|
|
50
|
+
<optgroup
|
|
51
|
+
data-slot="native-select-optgroup"
|
|
52
|
+
className={cn('bg-[Canvas] text-[CanvasText]', className)}
|
|
53
|
+
{...props}
|
|
54
|
+
/>
|
|
55
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// NavigationMenu — maintainer-supplied default-Tailwind flavor, class strings
|
|
2
|
+
// verbatim. Octane adaptations: lucide-react → @octanejs/lucide, radix-ui →
|
|
3
|
+
// @octanejs/radix. Root and Trigger interleave consumer children with sibling
|
|
4
|
+
// descriptors, so they use the {props.children} lowering in template JSX.
|
|
5
|
+
import type { OctaneNode } from 'octane';
|
|
6
|
+
import { cva } from 'class-variance-authority';
|
|
7
|
+
import { NavigationMenu as NavigationMenuPrimitive } from '@octanejs/radix';
|
|
8
|
+
import { ChevronDownIcon } from '@octanejs/lucide';
|
|
9
|
+
|
|
10
|
+
import { cn } from '../lib/utils';
|
|
11
|
+
|
|
12
|
+
type Props = { className?: string; children?: OctaneNode } & Record<string, unknown>;
|
|
13
|
+
|
|
14
|
+
export function NavigationMenu(props: Props & { viewport?: boolean }) @{
|
|
15
|
+
const { className, children: _children, viewport = true, ...rest } = props;
|
|
16
|
+
|
|
17
|
+
<NavigationMenuPrimitive.Root
|
|
18
|
+
data-slot="navigation-menu"
|
|
19
|
+
data-viewport={viewport}
|
|
20
|
+
className={cn(
|
|
21
|
+
'group/navigation-menu relative flex max-w-max flex-1 items-center justify-center',
|
|
22
|
+
className,
|
|
23
|
+
)}
|
|
24
|
+
{...rest}
|
|
25
|
+
>
|
|
26
|
+
{props.children}
|
|
27
|
+
@if (viewport) {
|
|
28
|
+
<NavigationMenuViewport />
|
|
29
|
+
}
|
|
30
|
+
</NavigationMenuPrimitive.Root>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function NavigationMenuList({ className, ...props }: Props) @{
|
|
34
|
+
<NavigationMenuPrimitive.List
|
|
35
|
+
data-slot="navigation-menu-list"
|
|
36
|
+
className={cn('group flex flex-1 list-none items-center justify-center gap-0', className)}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function NavigationMenuItem({ className, ...props }: Props) @{
|
|
42
|
+
<NavigationMenuPrimitive.Item
|
|
43
|
+
data-slot="navigation-menu-item"
|
|
44
|
+
className={cn('relative', className)}
|
|
45
|
+
{...props}
|
|
46
|
+
/>
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const navigationMenuTriggerStyle = cva(
|
|
50
|
+
'group/navigation-menu-trigger inline-flex h-9 w-max items-center justify-center rounded-lg px-2.5 py-1.5 text-sm font-medium transition-all outline-none hover:bg-muted focus:bg-muted focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-popup-open:bg-muted/50 data-popup-open:hover:bg-muted data-open:bg-muted/50 data-open:hover:bg-muted data-open:focus:bg-muted',
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
export function NavigationMenuTrigger(props: Props) @{
|
|
54
|
+
const { className, children: _children, ...rest } = props;
|
|
55
|
+
|
|
56
|
+
<NavigationMenuPrimitive.Trigger
|
|
57
|
+
data-slot="navigation-menu-trigger"
|
|
58
|
+
className={cn(navigationMenuTriggerStyle(), 'group', className)}
|
|
59
|
+
{...rest}
|
|
60
|
+
>
|
|
61
|
+
{props.children}
|
|
62
|
+
{' '}
|
|
63
|
+
<ChevronDownIcon
|
|
64
|
+
className="relative top-px ml-1 size-3 transition duration-300 group-data-popup-open/navigation-menu-trigger:rotate-180 group-data-open/navigation-menu-trigger:rotate-180"
|
|
65
|
+
aria-hidden="true"
|
|
66
|
+
/>
|
|
67
|
+
</NavigationMenuPrimitive.Trigger>
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function NavigationMenuContent({ className, ...props }: Props) @{
|
|
71
|
+
<NavigationMenuPrimitive.Content
|
|
72
|
+
data-slot="navigation-menu-content"
|
|
73
|
+
className={cn(
|
|
74
|
+
'top-0 left-0 w-full p-1 ease-[cubic-bezier(0.22,1,0.36,1)] group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded-lg group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:ring-1 group-data-[viewport=false]/navigation-menu:ring-foreground/10 group-data-[viewport=false]/navigation-menu:duration-300 data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 data-[motion^=from-]:animate-in data-[motion^=from-]:fade-in data-[motion^=to-]:animate-out data-[motion^=to-]:fade-out **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none md:absolute md:w-auto group-data-[viewport=false]/navigation-menu:data-open:animate-in group-data-[viewport=false]/navigation-menu:data-open:fade-in-0 group-data-[viewport=false]/navigation-menu:data-open:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-closed:animate-out group-data-[viewport=false]/navigation-menu:data-closed:fade-out-0 group-data-[viewport=false]/navigation-menu:data-closed:zoom-out-95',
|
|
75
|
+
className,
|
|
76
|
+
)}
|
|
77
|
+
{...props}
|
|
78
|
+
/>
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function NavigationMenuViewport({ className, ...props }: Props) @{
|
|
82
|
+
<div className={cn('absolute top-full left-0 isolate z-50 flex justify-center')}>
|
|
83
|
+
<NavigationMenuPrimitive.Viewport
|
|
84
|
+
data-slot="navigation-menu-viewport"
|
|
85
|
+
className={cn(
|
|
86
|
+
'origin-top-center relative mt-1.5 h-(--radix-navigation-menu-viewport-height) w-full overflow-hidden rounded-lg bg-popover text-popover-foreground shadow ring-1 ring-foreground/10 duration-100 md:w-(--radix-navigation-menu-viewport-width) data-open:animate-in data-open:zoom-in-90 data-closed:animate-out data-closed:zoom-out-90',
|
|
87
|
+
className,
|
|
88
|
+
)}
|
|
89
|
+
{...props}
|
|
90
|
+
/>
|
|
91
|
+
</div>
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function NavigationMenuLink({ className, ...props }: Props) @{
|
|
95
|
+
<NavigationMenuPrimitive.Link
|
|
96
|
+
data-slot="navigation-menu-link"
|
|
97
|
+
className={cn(
|
|
98
|
+
'flex items-center gap-2 rounded-lg p-2 text-sm transition-all outline-none hover:bg-muted focus:bg-muted focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-1 in-data-[slot=navigation-menu-content]:rounded-md data-active:bg-muted/50 data-active:hover:bg-muted data-active:focus:bg-muted [&_svg:not([class*=\'size-\'])]:size-4',
|
|
99
|
+
className,
|
|
100
|
+
)}
|
|
101
|
+
{...props}
|
|
102
|
+
/>
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function NavigationMenuIndicator({ className, ...props }: Props) @{
|
|
106
|
+
<NavigationMenuPrimitive.Indicator
|
|
107
|
+
data-slot="navigation-menu-indicator"
|
|
108
|
+
className={cn(
|
|
109
|
+
'top-full z-1 flex h-1.5 items-end justify-center overflow-hidden data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:animate-in data-[state=visible]:fade-in',
|
|
110
|
+
className,
|
|
111
|
+
)}
|
|
112
|
+
{...props}
|
|
113
|
+
>
|
|
114
|
+
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
|
|
115
|
+
</NavigationMenuPrimitive.Indicator>
|
|
116
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// Pagination — maintainer-supplied default-Tailwind flavor, class strings
|
|
2
|
+
// verbatim. Octane adaptations: lucide-react → @octanejs/lucide; PaginationLink
|
|
3
|
+
// is upstream's `<Button asChild><a …>` — Slot needs a real element descriptor
|
|
4
|
+
// as its child, so the Button/anchor pair composes with createElement and the
|
|
5
|
+
// link's children flow through the anchor's children prop.
|
|
6
|
+
import { createElement, type OctaneNode } from 'octane';
|
|
7
|
+
import { ChevronLeftIcon, ChevronRightIcon, MoreHorizontalIcon } from '@octanejs/lucide';
|
|
8
|
+
|
|
9
|
+
import { cn } from '../lib/utils';
|
|
10
|
+
import { Button, type ButtonProps } from './button.tsrx';
|
|
11
|
+
|
|
12
|
+
type Props = { className?: string } & Record<string, unknown>;
|
|
13
|
+
|
|
14
|
+
export function Pagination({ className, ...props }: Props) @{
|
|
15
|
+
<nav
|
|
16
|
+
role="navigation"
|
|
17
|
+
aria-label="pagination"
|
|
18
|
+
data-slot="pagination"
|
|
19
|
+
className={cn('mx-auto flex w-full justify-center', className)}
|
|
20
|
+
{...props}
|
|
21
|
+
/>
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function PaginationContent({ className, ...props }: Props) @{
|
|
25
|
+
<ul
|
|
26
|
+
data-slot="pagination-content"
|
|
27
|
+
className={cn('flex items-center gap-0.5', className)}
|
|
28
|
+
{...props}
|
|
29
|
+
/>
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function PaginationItem(props: Record<string, unknown>) @{
|
|
33
|
+
<li data-slot="pagination-item" {...props} />
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface PaginationLinkProps extends Record<string, unknown> {
|
|
37
|
+
className?: string;
|
|
38
|
+
isActive?: boolean;
|
|
39
|
+
size?: ButtonProps['size'];
|
|
40
|
+
children?: OctaneNode;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function PaginationLink({
|
|
44
|
+
className,
|
|
45
|
+
isActive,
|
|
46
|
+
size = 'icon',
|
|
47
|
+
children,
|
|
48
|
+
...props
|
|
49
|
+
}: PaginationLinkProps) {
|
|
50
|
+
return createElement(
|
|
51
|
+
Button,
|
|
52
|
+
{
|
|
53
|
+
asChild: true,
|
|
54
|
+
variant: isActive ? 'outline' : 'ghost',
|
|
55
|
+
size,
|
|
56
|
+
className: cn(className),
|
|
57
|
+
},
|
|
58
|
+
createElement('a', {
|
|
59
|
+
'aria-current': isActive ? 'page' : undefined,
|
|
60
|
+
'data-slot': 'pagination-link',
|
|
61
|
+
'data-active': isActive,
|
|
62
|
+
...props,
|
|
63
|
+
children,
|
|
64
|
+
}),
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function PaginationPrevious({
|
|
69
|
+
className,
|
|
70
|
+
text = 'Previous',
|
|
71
|
+
...props
|
|
72
|
+
}: PaginationLinkProps & {
|
|
73
|
+
text?: string;
|
|
74
|
+
}) @{
|
|
75
|
+
<PaginationLink
|
|
76
|
+
aria-label="Go to previous page"
|
|
77
|
+
size="default"
|
|
78
|
+
className={cn('pl-1.5!', className)}
|
|
79
|
+
{...props}
|
|
80
|
+
>
|
|
81
|
+
<ChevronLeftIcon data-icon="inline-start" className="cn-rtl-flip" />
|
|
82
|
+
<span className="hidden sm:block">{text as string}</span>
|
|
83
|
+
</PaginationLink>
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function PaginationNext({ className, text = 'Next', ...props }: PaginationLinkProps & {
|
|
87
|
+
text?: string;
|
|
88
|
+
}) @{
|
|
89
|
+
<PaginationLink
|
|
90
|
+
aria-label="Go to next page"
|
|
91
|
+
size="default"
|
|
92
|
+
className={cn('pr-1.5!', className)}
|
|
93
|
+
{...props}
|
|
94
|
+
>
|
|
95
|
+
<span className="hidden sm:block">{text as string}</span>
|
|
96
|
+
<ChevronRightIcon data-icon="inline-end" className="cn-rtl-flip" />
|
|
97
|
+
</PaginationLink>
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function PaginationEllipsis({ className, ...props }: Props) @{
|
|
101
|
+
<span
|
|
102
|
+
aria-hidden="true"
|
|
103
|
+
data-slot="pagination-ellipsis"
|
|
104
|
+
className={cn(
|
|
105
|
+
'flex size-8 items-center justify-center [&_svg:not([class*=\'size-\'])]:size-4',
|
|
106
|
+
className,
|
|
107
|
+
)}
|
|
108
|
+
{...props}
|
|
109
|
+
>
|
|
110
|
+
<MoreHorizontalIcon />
|
|
111
|
+
<span className="sr-only">More pages</span>
|
|
112
|
+
</span>
|
|
113
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// Popover — maintainer-supplied default-Tailwind flavor, class strings
|
|
2
|
+
// verbatim. Octane adaptations: "use client" dropped, radix-ui →
|
|
3
|
+
// @octanejs/radix.
|
|
4
|
+
//
|
|
5
|
+
// PopoverContent renders Portal > Content: the Portal's child must be a real
|
|
6
|
+
// element DESCRIPTOR (radix portals cannot enumerate opaque compiled .tsrx
|
|
7
|
+
// children), so the pair is composed with createElement; the consumer's
|
|
8
|
+
// children flow into the Content primitive through the ordinary props.children
|
|
9
|
+
// channel.
|
|
10
|
+
import { createElement } from 'octane';
|
|
11
|
+
import { Popover as PopoverPrimitive } from '@octanejs/radix';
|
|
12
|
+
|
|
13
|
+
import { cn } from '../lib/utils';
|
|
14
|
+
|
|
15
|
+
type Props = { className?: string } & Record<string, unknown>;
|
|
16
|
+
|
|
17
|
+
export function Popover(props: Record<string, unknown>) @{
|
|
18
|
+
<PopoverPrimitive.Root data-slot="popover" {...props} />
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function PopoverTrigger(props: Record<string, unknown>) @{
|
|
22
|
+
<PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface PopoverContentProps extends Record<string, unknown> {
|
|
26
|
+
className?: string;
|
|
27
|
+
align?: 'start' | 'center' | 'end';
|
|
28
|
+
sideOffset?: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function PopoverContent({
|
|
32
|
+
className,
|
|
33
|
+
align = 'center',
|
|
34
|
+
sideOffset = 4,
|
|
35
|
+
...props
|
|
36
|
+
}: PopoverContentProps) {
|
|
37
|
+
return createElement(PopoverPrimitive.Portal, {
|
|
38
|
+
children: createElement(PopoverPrimitive.Content, {
|
|
39
|
+
'data-slot': 'popover-content',
|
|
40
|
+
align,
|
|
41
|
+
sideOffset,
|
|
42
|
+
className: cn(
|
|
43
|
+
'z-50 flex w-72 origin-(--radix-popover-content-transform-origin) flex-col gap-2.5 rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 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',
|
|
44
|
+
className,
|
|
45
|
+
),
|
|
46
|
+
...props,
|
|
47
|
+
}),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function PopoverAnchor(props: Record<string, unknown>) @{
|
|
52
|
+
<PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function PopoverHeader({ className, ...props }: Props) @{
|
|
56
|
+
<div
|
|
57
|
+
data-slot="popover-header"
|
|
58
|
+
className={cn('flex flex-col gap-0.5 text-sm', className)}
|
|
59
|
+
{...props}
|
|
60
|
+
/>
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function PopoverTitle({ className, ...props }: Props) @{
|
|
64
|
+
<div data-slot="popover-title" className={cn('font-medium', className)} {...props} />
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function PopoverDescription({ className, ...props }: Props) @{
|
|
68
|
+
<p
|
|
69
|
+
data-slot="popover-description"
|
|
70
|
+
className={cn('text-muted-foreground', className)}
|
|
71
|
+
{...props}
|
|
72
|
+
/>
|
|
73
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Ported from shadcn-ui/ui@4baadbc6517070ae8f8feb2c97037adc2b305544
|
|
2
|
+
// apps/v4/registry/bases/radix/ui/progress.tsx (the `"use client"` directive
|
|
3
|
+
// is dropped — octane has no RSC axis). As upstream, `value` drives only the
|
|
4
|
+
// indicator transform — it is destructured off and NOT forwarded to the radix
|
|
5
|
+
// Root, whose role/aria-valuemax/data-state contract comes from its defaults.
|
|
6
|
+
import { Progress as ProgressPrimitive } from '@octanejs/radix';
|
|
7
|
+
|
|
8
|
+
import { cn } from '../lib/utils';
|
|
9
|
+
|
|
10
|
+
export interface ProgressProps extends Record<string, unknown> {
|
|
11
|
+
className?: string;
|
|
12
|
+
value?: number | null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function Progress({ className, value, ...props }: ProgressProps) @{
|
|
16
|
+
<ProgressPrimitive.Root
|
|
17
|
+
data-slot="progress"
|
|
18
|
+
className={cn('relative h-2 w-full overflow-hidden rounded-full bg-primary/20', className)}
|
|
19
|
+
{...props}
|
|
20
|
+
>
|
|
21
|
+
<ProgressPrimitive.Indicator
|
|
22
|
+
data-slot="progress-indicator"
|
|
23
|
+
className="h-full w-full flex-1 bg-primary transition-all"
|
|
24
|
+
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
|
|
25
|
+
/>
|
|
26
|
+
</ProgressPrimitive.Root>
|
|
27
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Default-Tailwind radio-group flavor (package canonical) — utilities-inlined
|
|
2
|
+
// upstream styling. Octane adaptations: "use client" dropped, lucide-react →
|
|
3
|
+
// @octanejs/lucide, radix-ui → @octanejs/radix; pure template JSX.
|
|
4
|
+
import { RadioGroup as RadioGroupPrimitive } from '@octanejs/radix';
|
|
5
|
+
import { CircleIcon } from '@octanejs/lucide';
|
|
6
|
+
|
|
7
|
+
import { cn } from '../lib/utils';
|
|
8
|
+
|
|
9
|
+
type Props = { className?: string } & Record<string, unknown>;
|
|
10
|
+
|
|
11
|
+
export function RadioGroup({ className, ...props }: Props) @{
|
|
12
|
+
<RadioGroupPrimitive.Root
|
|
13
|
+
data-slot="radio-group"
|
|
14
|
+
className={cn('grid gap-3', className)}
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function RadioGroupItem({ className, ...props }: Props) @{
|
|
20
|
+
<RadioGroupPrimitive.Item
|
|
21
|
+
data-slot="radio-group-item"
|
|
22
|
+
className={cn(
|
|
23
|
+
'aspect-square size-4 shrink-0 rounded-full border border-input text-primary shadow-xs transition-[color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:bg-input/30 dark:aria-invalid:ring-destructive/40',
|
|
24
|
+
className,
|
|
25
|
+
)}
|
|
26
|
+
{...props}
|
|
27
|
+
>
|
|
28
|
+
<RadioGroupPrimitive.Indicator
|
|
29
|
+
data-slot="radio-group-indicator"
|
|
30
|
+
className="relative flex items-center justify-center"
|
|
31
|
+
>
|
|
32
|
+
<CircleIcon
|
|
33
|
+
className="absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2 fill-primary"
|
|
34
|
+
/>
|
|
35
|
+
</RadioGroupPrimitive.Indicator>
|
|
36
|
+
</RadioGroupPrimitive.Item>
|
|
37
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// ScrollArea — maintainer-supplied default-Tailwind flavor, class strings
|
|
2
|
+
// verbatim. Octane adaptations: "use client" dropped, radix-ui →
|
|
3
|
+
// @octanejs/radix; ScrollArea interleaves consumer children with sibling
|
|
4
|
+
// descriptors (ScrollBar, Corner), so it uses the {props.children} lowering.
|
|
5
|
+
import type { OctaneNode } from 'octane';
|
|
6
|
+
import { ScrollArea as ScrollAreaPrimitive } from '@octanejs/radix';
|
|
7
|
+
|
|
8
|
+
import { cn } from '../lib/utils';
|
|
9
|
+
|
|
10
|
+
type Props = { className?: string; children?: OctaneNode } & Record<string, unknown>;
|
|
11
|
+
|
|
12
|
+
export function ScrollArea(props: Props) @{
|
|
13
|
+
const { className, children: _children, ...rest } = props;
|
|
14
|
+
|
|
15
|
+
<ScrollAreaPrimitive.Root data-slot="scroll-area" className={cn('relative', className)} {...rest}>
|
|
16
|
+
<ScrollAreaPrimitive.Viewport
|
|
17
|
+
data-slot="scroll-area-viewport"
|
|
18
|
+
className="size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1"
|
|
19
|
+
>{props.children}</ScrollAreaPrimitive.Viewport>
|
|
20
|
+
<ScrollBar />
|
|
21
|
+
<ScrollAreaPrimitive.Corner />
|
|
22
|
+
</ScrollAreaPrimitive.Root>
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function ScrollBar({ className, orientation = 'vertical', ...props }: Props & {
|
|
26
|
+
orientation?: 'vertical' | 'horizontal';
|
|
27
|
+
}) @{
|
|
28
|
+
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
|
29
|
+
data-slot="scroll-area-scrollbar"
|
|
30
|
+
data-orientation={orientation}
|
|
31
|
+
orientation={orientation}
|
|
32
|
+
className={cn(
|
|
33
|
+
'flex touch-none p-px transition-colors select-none data-horizontal:h-2.5 data-horizontal:flex-col data-horizontal:border-t data-horizontal:border-t-transparent data-vertical:h-full data-vertical:w-2.5 data-vertical:border-l data-vertical:border-l-transparent',
|
|
34
|
+
className,
|
|
35
|
+
)}
|
|
36
|
+
{...props}
|
|
37
|
+
>
|
|
38
|
+
<ScrollAreaPrimitive.ScrollAreaThumb
|
|
39
|
+
data-slot="scroll-area-thumb"
|
|
40
|
+
className="relative flex-1 rounded-full bg-border"
|
|
41
|
+
/>
|
|
42
|
+
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
|
43
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
// Select — maintainer-supplied default-Tailwind flavor, class strings verbatim.
|
|
2
|
+
// Octane adaptations: "use client" dropped, lucide-react → @octanejs/lucide,
|
|
3
|
+
// radix-ui → @octanejs/radix. Trigger/Content/Item compose with createElement
|
|
4
|
+
// where a Portal child or an `asChild` slot target must be a real element
|
|
5
|
+
// descriptor; consumer children flow through the props.children channel.
|
|
6
|
+
import { createElement, type OctaneNode } from 'octane';
|
|
7
|
+
import { Select as SelectPrimitive } from '@octanejs/radix';
|
|
8
|
+
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from '@octanejs/lucide';
|
|
9
|
+
|
|
10
|
+
import { cn } from '../lib/utils';
|
|
11
|
+
|
|
12
|
+
type Props = { className?: string; children?: OctaneNode } & Record<string, unknown>;
|
|
13
|
+
|
|
14
|
+
export function Select(props: Record<string, unknown>) @{
|
|
15
|
+
<SelectPrimitive.Root data-slot="select" {...props} />
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function SelectGroup({ className, ...props }: Props) @{
|
|
19
|
+
<SelectPrimitive.Group
|
|
20
|
+
data-slot="select-group"
|
|
21
|
+
className={cn('scroll-my-1 p-1', className)}
|
|
22
|
+
{...props}
|
|
23
|
+
/>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function SelectValue(props: Record<string, unknown>) @{
|
|
27
|
+
<SelectPrimitive.Value data-slot="select-value" {...props} />
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function SelectTrigger({ className, size = 'default', children, ...props }: Props & {
|
|
31
|
+
size?: 'sm' | 'default';
|
|
32
|
+
}) {
|
|
33
|
+
return createElement(
|
|
34
|
+
SelectPrimitive.Trigger,
|
|
35
|
+
{
|
|
36
|
+
'data-slot': 'select-trigger',
|
|
37
|
+
'data-size': size,
|
|
38
|
+
className: cn(
|
|
39
|
+
'flex w-fit items-center justify-between gap-1.5 rounded-lg border border-input bg-transparent py-2 pr-2 pl-2.5 text-sm whitespace-nowrap transition-colors outline-none select-none 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 data-placeholder:text-muted-foreground data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:bg-input/30 dark:hover:bg-input/50 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',
|
|
40
|
+
className,
|
|
41
|
+
),
|
|
42
|
+
...props,
|
|
43
|
+
},
|
|
44
|
+
children,
|
|
45
|
+
createElement(
|
|
46
|
+
SelectPrimitive.Icon,
|
|
47
|
+
{ key: 'icon', asChild: true },
|
|
48
|
+
createElement(ChevronDownIcon, {
|
|
49
|
+
className: 'pointer-events-none size-4 text-muted-foreground',
|
|
50
|
+
}),
|
|
51
|
+
),
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function SelectContent({
|
|
56
|
+
className,
|
|
57
|
+
children,
|
|
58
|
+
position = 'item-aligned',
|
|
59
|
+
align = 'center',
|
|
60
|
+
...props
|
|
61
|
+
}: Props & { position?: string; align?: string }) {
|
|
62
|
+
return createElement(
|
|
63
|
+
SelectPrimitive.Portal,
|
|
64
|
+
null,
|
|
65
|
+
createElement(
|
|
66
|
+
SelectPrimitive.Content,
|
|
67
|
+
{
|
|
68
|
+
'data-slot': 'select-content',
|
|
69
|
+
'data-align-trigger': position === 'item-aligned',
|
|
70
|
+
className: cn(
|
|
71
|
+
'relative z-50 max-h-(--radix-select-content-available-height) min-w-36 origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 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',
|
|
72
|
+
position === 'popper' &&
|
|
73
|
+
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
|
|
74
|
+
className,
|
|
75
|
+
),
|
|
76
|
+
position,
|
|
77
|
+
align,
|
|
78
|
+
...props,
|
|
79
|
+
},
|
|
80
|
+
createElement(SelectScrollUpButton, { key: 'up' }),
|
|
81
|
+
createElement(
|
|
82
|
+
SelectPrimitive.Viewport,
|
|
83
|
+
{
|
|
84
|
+
key: 'viewport',
|
|
85
|
+
'data-position': position,
|
|
86
|
+
className: cn(
|
|
87
|
+
'data-[position=popper]:h-(--radix-select-trigger-height) data-[position=popper]:w-full data-[position=popper]:min-w-(--radix-select-trigger-width)',
|
|
88
|
+
position === 'popper' && '',
|
|
89
|
+
),
|
|
90
|
+
},
|
|
91
|
+
children,
|
|
92
|
+
),
|
|
93
|
+
createElement(SelectScrollDownButton, { key: 'down' }),
|
|
94
|
+
),
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function SelectLabel({ className, ...props }: Props) @{
|
|
99
|
+
<SelectPrimitive.Label
|
|
100
|
+
data-slot="select-label"
|
|
101
|
+
className={cn('px-1.5 py-1 text-xs text-muted-foreground', className)}
|
|
102
|
+
{...props}
|
|
103
|
+
/>
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function SelectItem({ className, children, ...props }: Props) {
|
|
107
|
+
return createElement(
|
|
108
|
+
SelectPrimitive.Item,
|
|
109
|
+
{
|
|
110
|
+
'data-slot': 'select-item',
|
|
111
|
+
className: cn(
|
|
112
|
+
'relative flex w-full cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2',
|
|
113
|
+
className,
|
|
114
|
+
),
|
|
115
|
+
...props,
|
|
116
|
+
},
|
|
117
|
+
createElement(
|
|
118
|
+
'span',
|
|
119
|
+
{
|
|
120
|
+
key: 'indicator',
|
|
121
|
+
className: 'pointer-events-none absolute right-2 flex size-4 items-center justify-center',
|
|
122
|
+
},
|
|
123
|
+
createElement(
|
|
124
|
+
SelectPrimitive.ItemIndicator,
|
|
125
|
+
null,
|
|
126
|
+
createElement(CheckIcon, { className: 'pointer-events-none' }),
|
|
127
|
+
),
|
|
128
|
+
),
|
|
129
|
+
createElement(SelectPrimitive.ItemText, { key: 'text' }, children),
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function SelectSeparator({ className, ...props }: Props) @{
|
|
134
|
+
<SelectPrimitive.Separator
|
|
135
|
+
data-slot="select-separator"
|
|
136
|
+
className={cn('pointer-events-none -mx-1 my-1 h-px bg-border', className)}
|
|
137
|
+
{...props}
|
|
138
|
+
/>
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function SelectScrollUpButton({ className, ...props }: Props) @{
|
|
142
|
+
<SelectPrimitive.ScrollUpButton
|
|
143
|
+
data-slot="select-scroll-up-button"
|
|
144
|
+
className={cn(
|
|
145
|
+
'z-10 flex cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*=\'size-\'])]:size-4',
|
|
146
|
+
className,
|
|
147
|
+
)}
|
|
148
|
+
{...props}
|
|
149
|
+
>
|
|
150
|
+
<ChevronUpIcon />
|
|
151
|
+
</SelectPrimitive.ScrollUpButton>
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function SelectScrollDownButton({ className, ...props }: Props) @{
|
|
155
|
+
<SelectPrimitive.ScrollDownButton
|
|
156
|
+
data-slot="select-scroll-down-button"
|
|
157
|
+
className={cn(
|
|
158
|
+
'z-10 flex cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*=\'size-\'])]:size-4',
|
|
159
|
+
className,
|
|
160
|
+
)}
|
|
161
|
+
{...props}
|
|
162
|
+
>
|
|
163
|
+
<ChevronDownIcon />
|
|
164
|
+
</SelectPrimitive.ScrollDownButton>
|
|
165
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Ported from shadcn-ui/ui@4baadbc6517070ae8f8feb2c97037adc2b305544
|
|
2
|
+
// apps/v4/registry/bases/radix/ui/separator.tsx (the `"use client"` directive
|
|
3
|
+
// is dropped — octane has no RSC axis).
|
|
4
|
+
import { Separator as SeparatorPrimitive } from '@octanejs/radix';
|
|
5
|
+
|
|
6
|
+
import { cn } from '../lib/utils';
|
|
7
|
+
|
|
8
|
+
export interface SeparatorProps extends Record<string, unknown> {
|
|
9
|
+
className?: string;
|
|
10
|
+
orientation?: 'horizontal' | 'vertical';
|
|
11
|
+
decorative?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function Separator({
|
|
15
|
+
className,
|
|
16
|
+
orientation = 'horizontal',
|
|
17
|
+
decorative = true,
|
|
18
|
+
...props
|
|
19
|
+
}: SeparatorProps) @{
|
|
20
|
+
<SeparatorPrimitive.Root
|
|
21
|
+
data-slot="separator"
|
|
22
|
+
decorative={decorative}
|
|
23
|
+
orientation={orientation}
|
|
24
|
+
className={cn(
|
|
25
|
+
'shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px',
|
|
26
|
+
className,
|
|
27
|
+
)}
|
|
28
|
+
{...props}
|
|
29
|
+
/>
|
|
30
|
+
}
|