@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.
Files changed (52) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +43 -0
  3. package/package.json +63 -0
  4. package/src/hooks/use-mobile.ts +23 -0
  5. package/src/index.ts +263 -0
  6. package/src/lib/types.ts +10 -0
  7. package/src/lib/utils.ts +8 -0
  8. package/src/styles/theme.css +104 -0
  9. package/src/ui/accordion.tsrx +72 -0
  10. package/src/ui/alert-dialog.tsrx +161 -0
  11. package/src/ui/alert.tsrx +69 -0
  12. package/src/ui/aspect-ratio.tsrx +10 -0
  13. package/src/ui/avatar.tsrx +79 -0
  14. package/src/ui/badge.tsrx +50 -0
  15. package/src/ui/breadcrumb.tsrx +89 -0
  16. package/src/ui/button.tsrx +71 -0
  17. package/src/ui/card.tsrx +75 -0
  18. package/src/ui/checkbox.tsrx +31 -0
  19. package/src/ui/collapsible.tsrx +21 -0
  20. package/src/ui/context-menu.tsrx +179 -0
  21. package/src/ui/dialog.tsrx +133 -0
  22. package/src/ui/dropdown-menu.tsrx +189 -0
  23. package/src/ui/empty.tsrx +86 -0
  24. package/src/ui/field.tsrx +188 -0
  25. package/src/ui/hover-card.tsrx +48 -0
  26. package/src/ui/input.tsrx +18 -0
  27. package/src/ui/item.tsrx +171 -0
  28. package/src/ui/kbd.tsrx +26 -0
  29. package/src/ui/label.tsrx +21 -0
  30. package/src/ui/menubar.tsrx +198 -0
  31. package/src/ui/native-select.tsrx +55 -0
  32. package/src/ui/navigation-menu.tsrx +116 -0
  33. package/src/ui/pagination.tsrx +113 -0
  34. package/src/ui/popover.tsrx +73 -0
  35. package/src/ui/progress.tsrx +27 -0
  36. package/src/ui/radio-group.tsrx +37 -0
  37. package/src/ui/scroll-area.tsrx +43 -0
  38. package/src/ui/select.tsrx +165 -0
  39. package/src/ui/separator.tsrx +30 -0
  40. package/src/ui/sheet.tsrx +114 -0
  41. package/src/ui/sidebar.tsrx +661 -0
  42. package/src/ui/skeleton.tsrx +14 -0
  43. package/src/ui/slider.tsrx +69 -0
  44. package/src/ui/sonner.tsrx +45 -0
  45. package/src/ui/spinner.tsrx +23 -0
  46. package/src/ui/switch.tsrx +30 -0
  47. package/src/ui/table.tsrx +80 -0
  48. package/src/ui/tabs.tsrx +69 -0
  49. package/src/ui/textarea.tsrx +20 -0
  50. package/src/ui/toggle-group.tsrx +100 -0
  51. package/src/ui/toggle.tsrx +47 -0
  52. package/src/ui/tooltip.tsrx +65 -0
@@ -0,0 +1,69 @@
1
+ // Ported from shadcn-ui/ui@4baadbc6517070ae8f8feb2c97037adc2b305544
2
+ // apps/v4/registry/bases/radix/ui/slider.tsx (the `"use client"` directive is
3
+ // dropped — octane has no RSC axis).
4
+ //
5
+ // The Track/Range/Thumb tree is composed with createElement: upstream renders
6
+ // one Thumb per entry of `_values` via an array map, and mapped/prop-position
7
+ // descriptors are the octane channel for computed children (see
8
+ // breadcrumb.tsrx's comment on opaque compiled children).
9
+ import { createElement, useMemo } from 'octane';
10
+ import { Slider as SliderPrimitive } from '@octanejs/radix';
11
+
12
+ import { cn } from '../lib/utils';
13
+
14
+ export interface SliderProps extends Record<string, unknown> {
15
+ className?: string;
16
+ defaultValue?: number[];
17
+ value?: number[];
18
+ min?: number;
19
+ max?: number;
20
+ }
21
+
22
+ export function Slider({
23
+ className,
24
+ defaultValue,
25
+ value,
26
+ min = 0,
27
+ max = 100,
28
+ ...props
29
+ }: SliderProps) {
30
+ const _values = useMemo(
31
+ () => Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min, max],
32
+ [value, defaultValue, min, max],
33
+ );
34
+
35
+ return createElement(
36
+ SliderPrimitive.Root,
37
+ {
38
+ 'data-slot': 'slider',
39
+ defaultValue,
40
+ value,
41
+ min,
42
+ max,
43
+ className: cn(
44
+ 'relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col',
45
+ className,
46
+ ),
47
+ ...props,
48
+ },
49
+ createElement(
50
+ SliderPrimitive.Track,
51
+ {
52
+ 'data-slot': 'slider-track',
53
+ className: 'relative grow overflow-hidden rounded-full bg-muted data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5',
54
+ },
55
+ createElement(SliderPrimitive.Range, {
56
+ 'data-slot': 'slider-range',
57
+ className: 'absolute bg-primary data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full',
58
+ }),
59
+ ),
60
+ ...Array.from(
61
+ { length: _values.length },
62
+ (_, index) => createElement(SliderPrimitive.Thumb, {
63
+ 'data-slot': 'slider-thumb',
64
+ key: index,
65
+ className: 'block size-4 shrink-0 rounded-full border border-primary bg-white shadow-sm ring-ring/50 transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50',
66
+ }),
67
+ ),
68
+ );
69
+ }
@@ -0,0 +1,45 @@
1
+ // Ported from shadcn-ui/ui@4baadbc6517070ae8f8feb2c97037adc2b305544
2
+ // apps/v4/registry/bases/radix/ui/sonner.tsx (the `"use client"` directive is
3
+ // dropped — octane has no RSC axis). IconPlaceholder resolves to lucide (see
4
+ // spinner.tsrx).
5
+ //
6
+ // OCTANE DIVERGENCE: upstream reads the theme from next-themes' useTheme()
7
+ // (Next.js-specific); here `theme` is an ordinary prop with upstream's
8
+ // 'system' default — pass your app's theme source explicitly. The icon
9
+ // descriptors are composed with createElement (they travel through a props
10
+ // object, the documented channel for element descriptors).
11
+ import { createElement } from 'octane';
12
+ import { Toaster as Sonner, type ToasterProps } from '@octanejs/sonner';
13
+ import {
14
+ CircleCheckIcon,
15
+ InfoIcon,
16
+ Loader2Icon,
17
+ OctagonXIcon,
18
+ TriangleAlertIcon,
19
+ } from '@octanejs/lucide';
20
+
21
+ export function Toaster({ theme = 'system', ...props }: ToasterProps) {
22
+ return createElement(Sonner, {
23
+ theme: theme as ToasterProps['theme'],
24
+ className: 'toaster group',
25
+ icons: {
26
+ success: createElement(CircleCheckIcon, { className: 'size-4' }),
27
+ info: createElement(InfoIcon, { className: 'size-4' }),
28
+ warning: createElement(TriangleAlertIcon, { className: 'size-4' }),
29
+ error: createElement(OctagonXIcon, { className: 'size-4' }),
30
+ loading: createElement(Loader2Icon, { className: 'size-4 animate-spin' }),
31
+ },
32
+ style: {
33
+ '--normal-bg': 'var(--popover)',
34
+ '--normal-text': 'var(--popover-foreground)',
35
+ '--normal-border': 'var(--border)',
36
+ '--border-radius': 'var(--radius)',
37
+ },
38
+ toastOptions: {
39
+ classNames: {
40
+ toast: 'cn-toast',
41
+ },
42
+ },
43
+ ...props,
44
+ });
45
+ }
@@ -0,0 +1,23 @@
1
+ // Ported from shadcn-ui/ui@4baadbc6517070ae8f8feb2c97037adc2b305544
2
+ // apps/v4/registry/bases/radix/ui/spinner.tsx.
3
+ //
4
+ // OCTANE DIVERGENCE: upstream's IconPlaceholder (the CLI-resolved iconLibrary
5
+ // axis) is resolved at port time to the default library, lucide, via
6
+ // @octanejs/lucide. Other icon libraries are a registry-emit concern.
7
+ import { Loader2Icon } from '@octanejs/lucide';
8
+
9
+ import { cn } from '../lib/utils';
10
+
11
+ export interface SpinnerProps extends Record<string, unknown> {
12
+ className?: string;
13
+ }
14
+
15
+ export function Spinner({ className, ...props }: SpinnerProps) @{
16
+ <Loader2Icon
17
+ data-slot="spinner"
18
+ role="status"
19
+ aria-label="Loading"
20
+ className={cn('size-4 animate-spin', className)}
21
+ {...props}
22
+ />
23
+ }
@@ -0,0 +1,30 @@
1
+ // Default-Tailwind switch flavor (package canonical) — utilities-inlined
2
+ // upstream styling. Octane adaptations: "use client" dropped, radix-ui →
3
+ // @octanejs/radix; pure template JSX.
4
+ import { Switch as SwitchPrimitive } from '@octanejs/radix';
5
+
6
+ import { cn } from '../lib/utils';
7
+
8
+ export interface SwitchProps extends Record<string, unknown> {
9
+ className?: string;
10
+ size?: 'sm' | 'default';
11
+ }
12
+
13
+ export function Switch({ className, size = 'default', ...props }: SwitchProps) @{
14
+ <SwitchPrimitive.Root
15
+ data-slot="switch"
16
+ data-size={size}
17
+ className={cn(
18
+ 'peer group/switch inline-flex shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-[1.15rem] data-[size=default]:w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input dark:data-[state=unchecked]:bg-input/80',
19
+ className,
20
+ )}
21
+ {...props}
22
+ >
23
+ <SwitchPrimitive.Thumb
24
+ data-slot="switch-thumb"
25
+ className={cn(
26
+ 'pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0 dark:data-[state=checked]:bg-primary-foreground dark:data-[state=unchecked]:bg-foreground',
27
+ )}
28
+ />
29
+ </SwitchPrimitive.Root>
30
+ }
@@ -0,0 +1,80 @@
1
+ // Ported from shadcn-ui/ui@4baadbc6517070ae8f8feb2c97037adc2b305544
2
+ // apps/v4/registry/bases/radix/ui/table.tsx (the `"use client"` directive is
3
+ // dropped — octane has no RSC axis). Table renders inside the upstream
4
+ // table-container wrapper div.
5
+ import { cn } from '../lib/utils';
6
+
7
+ // Multi-host family (div/table/thead/tbody/tr/th/td/caption): no single host
8
+ // prop table applies, so the shared alias stays structural.
9
+ type Props = { className?: string } & Record<string, unknown>;
10
+
11
+ export function Table({ className, ...props }: Props) @{
12
+ <div data-slot="table-container" className="relative w-full overflow-x-auto">
13
+ <table
14
+ data-slot="table"
15
+ className={cn('w-full caption-bottom text-sm', className)}
16
+ {...props}
17
+ />
18
+ </div>
19
+ }
20
+
21
+ export function TableHeader({ className, ...props }: Props) @{
22
+ <thead data-slot="table-header" className={cn('[&_tr]:border-b', className)} {...props} />
23
+ }
24
+
25
+ export function TableBody({ className, ...props }: Props) @{
26
+ <tbody
27
+ data-slot="table-body"
28
+ className={cn('[&_tr:last-child]:border-0', className)}
29
+ {...props}
30
+ />
31
+ }
32
+
33
+ export function TableFooter({ className, ...props }: Props) @{
34
+ <tfoot
35
+ data-slot="table-footer"
36
+ className={cn('bg-muted/50 border-t font-medium [&>tr]:last:border-b-0', className)}
37
+ {...props}
38
+ />
39
+ }
40
+
41
+ export function TableRow({ className, ...props }: Props) @{
42
+ <tr
43
+ data-slot="table-row"
44
+ className={cn(
45
+ 'border-b transition-colors hover:bg-muted/50 has-aria-expanded:bg-muted/50 data-[state=selected]:bg-muted',
46
+ className,
47
+ )}
48
+ {...props}
49
+ />
50
+ }
51
+
52
+ export function TableHead({ className, ...props }: Props) @{
53
+ <th
54
+ data-slot="table-head"
55
+ className={cn(
56
+ 'text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',
57
+ className,
58
+ )}
59
+ {...props}
60
+ />
61
+ }
62
+
63
+ export function TableCell({ className, ...props }: Props) @{
64
+ <td
65
+ data-slot="table-cell"
66
+ className={cn(
67
+ 'p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',
68
+ className,
69
+ )}
70
+ {...props}
71
+ />
72
+ }
73
+
74
+ export function TableCaption({ className, ...props }: Props) @{
75
+ <caption
76
+ data-slot="table-caption"
77
+ className={cn('text-muted-foreground mt-4 text-sm', className)}
78
+ {...props}
79
+ />
80
+ }
@@ -0,0 +1,69 @@
1
+ // Tabs — maintainer-supplied default-Tailwind flavor, class strings verbatim.
2
+ // Octane adaptations: "use client" dropped, radix-ui → @octanejs/radix, cva →
3
+ // class-variance-authority (unchanged).
4
+ import { cva, type VariantProps } from 'class-variance-authority';
5
+ import { Tabs as TabsPrimitive } from '@octanejs/radix';
6
+
7
+ import { cn } from '../lib/utils';
8
+
9
+ type Props = { className?: string } & Record<string, unknown>;
10
+
11
+ export function Tabs({ className, orientation = 'horizontal', ...props }: Props & {
12
+ orientation?: 'horizontal' | 'vertical';
13
+ }) @{
14
+ <TabsPrimitive.Root
15
+ data-slot="tabs"
16
+ data-orientation={orientation}
17
+ orientation={orientation}
18
+ className={cn('group/tabs flex gap-2 data-horizontal:flex-col', className)}
19
+ {...props}
20
+ />
21
+ }
22
+
23
+ export const tabsListVariants = cva(
24
+ 'group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none',
25
+ {
26
+ variants: {
27
+ variant: {
28
+ default: 'bg-muted',
29
+ line: 'gap-1 bg-transparent',
30
+ },
31
+ },
32
+ defaultVariants: {
33
+ variant: 'default',
34
+ },
35
+ },
36
+ );
37
+
38
+ export function TabsList({ className, variant = 'default', ...props }: Props & VariantProps<
39
+ typeof tabsListVariants
40
+ >) @{
41
+ <TabsPrimitive.List
42
+ data-slot="tabs-list"
43
+ data-variant={variant}
44
+ className={cn(tabsListVariants({ variant }), className)}
45
+ {...props}
46
+ />
47
+ }
48
+
49
+ export function TabsTrigger({ className, ...props }: Props) @{
50
+ <TabsPrimitive.Trigger
51
+ data-slot="tabs-trigger"
52
+ className={cn(
53
+ 'relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4',
54
+ 'group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent',
55
+ 'data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground',
56
+ 'after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100',
57
+ className,
58
+ )}
59
+ {...props}
60
+ />
61
+ }
62
+
63
+ export function TabsContent({ className, ...props }: Props) @{
64
+ <TabsPrimitive.Content
65
+ data-slot="tabs-content"
66
+ className={cn('flex-1 text-sm outline-none', className)}
67
+ {...props}
68
+ />
69
+ }
@@ -0,0 +1,20 @@
1
+ // Ported from shadcn-ui/ui@4baadbc6517070ae8f8feb2c97037adc2b305544
2
+ // apps/v4/registry/bases/radix/ui/textarea.tsx.
3
+ //
4
+ // OCTANE DIVERGENCE: per-keystroke handling is the native `onInput` event, not
5
+ // a synthetic `onChange`; native `change` keeps its commit-on-blur meaning.
6
+ import { cn } from '../lib/utils';
7
+ import type { HostProps } from '../lib/types';
8
+
9
+ export interface TextareaProps extends HostProps<'textarea'> {}
10
+
11
+ export function Textarea({ className, ...props }: TextareaProps) @{
12
+ <textarea
13
+ data-slot="textarea"
14
+ className={cn(
15
+ 'flex field-sizing-content min-h-16 w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none placeholder:text-muted-foreground 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 md:text-sm dark:bg-input/30 dark:aria-invalid:ring-destructive/40',
16
+ className,
17
+ )}
18
+ {...props}
19
+ />
20
+ }
@@ -0,0 +1,100 @@
1
+ // Ported from shadcn-ui/ui@4baadbc6517070ae8f8feb2c97037adc2b305544
2
+ // apps/v4/registry/bases/radix/ui/toggle-group.tsx (the `"use client"` directive
3
+ // is dropped — octane has no RSC axis). React.createContext/useContext map onto
4
+ // octane's createContext/useContext.
5
+ //
6
+ // ToggleGroup is composed with createElement: the consumer's children must sit
7
+ // INSIDE the context Provider, and opaque compiled .tsrx children can only flow
8
+ // through the props.children channel (see breadcrumb.tsrx's comment).
9
+ import { createContext, createElement, useContext, type OctaneNode } from 'octane';
10
+ import { type VariantProps } from 'class-variance-authority';
11
+ import { ToggleGroup as ToggleGroupPrimitive } from '@octanejs/radix';
12
+
13
+ import { cn } from '../lib/utils';
14
+ import { toggleVariants } from './toggle.tsrx';
15
+
16
+ const ToggleGroupContext = createContext<
17
+ VariantProps<typeof toggleVariants> & {
18
+ spacing?: number;
19
+ orientation?: 'horizontal' | 'vertical';
20
+ }
21
+ >({
22
+ size: 'default',
23
+ variant: 'default',
24
+ spacing: 2,
25
+ orientation: 'horizontal',
26
+ });
27
+
28
+ export interface ToggleGroupProps extends Record<string, unknown> {
29
+ className?: string;
30
+ variant?: VariantProps<typeof toggleVariants>['variant'];
31
+ size?: VariantProps<typeof toggleVariants>['size'];
32
+ spacing?: number;
33
+ orientation?: 'horizontal' | 'vertical';
34
+ children?: OctaneNode;
35
+ }
36
+
37
+ export function ToggleGroup({
38
+ className,
39
+ variant,
40
+ size,
41
+ spacing = 2,
42
+ orientation = 'horizontal',
43
+ children,
44
+ ...props
45
+ }: ToggleGroupProps) {
46
+ return createElement(
47
+ ToggleGroupPrimitive.Root,
48
+ {
49
+ 'data-slot': 'toggle-group',
50
+ 'data-variant': variant,
51
+ 'data-size': size,
52
+ 'data-spacing': spacing,
53
+ 'data-orientation': orientation,
54
+ // Forwarded to the primitive: it drives RovingFocusGroup's arrow-key
55
+ // axis (a vertical group must ignore left/right and use up/down).
56
+ orientation,
57
+ style: { '--gap': spacing },
58
+ className: cn(
59
+ 'group/toggle-group flex w-fit items-center gap-[--spacing(var(--gap))] rounded-md data-[spacing=default]:data-[variant=outline]:shadow-xs',
60
+ className,
61
+ ),
62
+ ...props,
63
+ },
64
+ createElement(
65
+ ToggleGroupContext.Provider,
66
+ { value: { variant, size, spacing, orientation } },
67
+ children,
68
+ ),
69
+ );
70
+ }
71
+
72
+ export interface ToggleGroupItemProps extends Record<string, unknown> {
73
+ className?: string;
74
+ variant?: VariantProps<typeof toggleVariants>['variant'];
75
+ size?: VariantProps<typeof toggleVariants>['size'];
76
+ }
77
+
78
+ export function ToggleGroupItem({
79
+ className,
80
+ variant = 'default',
81
+ size = 'default',
82
+ ...props
83
+ }: ToggleGroupItemProps) @{
84
+ const context = useContext(ToggleGroupContext);
85
+ <ToggleGroupPrimitive.Item
86
+ data-slot="toggle-group-item"
87
+ data-variant={context.variant || variant}
88
+ data-size={context.size || size}
89
+ data-spacing={context.spacing}
90
+ className={cn(
91
+ 'min-w-0 flex-1 shrink-0 rounded-none shadow-none first:rounded-l-md last:rounded-r-md focus:z-10 focus-visible:z-10 data-[spacing=0]:data-[variant=outline]:border-l-0 data-[spacing=0]:data-[variant=outline]:first:border-l',
92
+ toggleVariants({
93
+ variant: context.variant || variant,
94
+ size: context.size || size,
95
+ }),
96
+ className,
97
+ )}
98
+ {...props}
99
+ />
100
+ }
@@ -0,0 +1,47 @@
1
+ // Ported from shadcn-ui/ui@4baadbc6517070ae8f8feb2c97037adc2b305544
2
+ // apps/v4/registry/bases/radix/ui/toggle.tsx (the `"use client"` directive is
3
+ // dropped — octane has no RSC axis).
4
+ import { cva, type VariantProps } from 'class-variance-authority';
5
+ import { Toggle as TogglePrimitive } from '@octanejs/radix';
6
+
7
+ import { cn } from '../lib/utils';
8
+
9
+ export const toggleVariants = cva(
10
+ 'inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-muted hover:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4',
11
+ {
12
+ variants: {
13
+ variant: {
14
+ default: 'bg-transparent',
15
+ outline: 'border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground',
16
+ },
17
+ size: {
18
+ default: 'h-9 min-w-9 px-2',
19
+ sm: 'h-8 min-w-8 px-1.5',
20
+ lg: 'h-10 min-w-10 px-2.5',
21
+ },
22
+ },
23
+ defaultVariants: {
24
+ variant: 'default',
25
+ size: 'default',
26
+ },
27
+ },
28
+ );
29
+
30
+ export interface ToggleProps extends Record<string, unknown> {
31
+ className?: string;
32
+ variant?: VariantProps<typeof toggleVariants>['variant'];
33
+ size?: VariantProps<typeof toggleVariants>['size'];
34
+ }
35
+
36
+ export function Toggle({
37
+ className,
38
+ variant = 'default',
39
+ size = 'default',
40
+ ...props
41
+ }: ToggleProps) @{
42
+ <TogglePrimitive.Root
43
+ data-slot="toggle"
44
+ className={cn(toggleVariants({ variant, size, className }))}
45
+ {...props}
46
+ />
47
+ }
@@ -0,0 +1,65 @@
1
+ // Ported from shadcn-ui/ui@4baadbc6517070ae8f8feb2c97037adc2b305544
2
+ // apps/v4/registry/bases/radix/ui/tooltip.tsx (the `"use client"` directive is
3
+ // dropped — octane has no RSC axis).
4
+ //
5
+ // TooltipContent renders Portal > Content + Arrow: the Portal's child must be
6
+ // a real element DESCRIPTOR (radix portals cannot enumerate opaque compiled
7
+ // .tsrx 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, type OctaneNode } from 'octane';
11
+ import { Tooltip as TooltipPrimitive } from '@octanejs/radix';
12
+
13
+ import { cn } from '../lib/utils';
14
+
15
+ export interface TooltipProviderProps extends Record<string, unknown> {
16
+ delayDuration?: number;
17
+ }
18
+
19
+ export function TooltipProvider({ delayDuration = 0, ...props }: TooltipProviderProps) @{
20
+ <TooltipPrimitive.Provider
21
+ data-slot="tooltip-provider"
22
+ delayDuration={delayDuration}
23
+ {...props}
24
+ />
25
+ }
26
+
27
+ export function Tooltip(props: Record<string, unknown>) @{
28
+ <TooltipPrimitive.Root data-slot="tooltip" {...props} />
29
+ }
30
+
31
+ export function TooltipTrigger(props: Record<string, unknown>) @{
32
+ <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
33
+ }
34
+
35
+ export interface TooltipContentProps extends Record<string, unknown> {
36
+ className?: string;
37
+ sideOffset?: number;
38
+ children?: OctaneNode;
39
+ }
40
+
41
+ export function TooltipContent({
42
+ className,
43
+ sideOffset = 0,
44
+ children,
45
+ ...props
46
+ }: TooltipContentProps) {
47
+ return createElement(TooltipPrimitive.Portal, {
48
+ children: createElement(TooltipPrimitive.Content, {
49
+ 'data-slot': 'tooltip-content',
50
+ sideOffset,
51
+ className: cn(
52
+ 'z-50 inline-flex w-fit max-w-xs origin-(--radix-tooltip-content-transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 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-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 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',
53
+ className,
54
+ ),
55
+ ...props,
56
+ children: [
57
+ children,
58
+ createElement(TooltipPrimitive.Arrow, {
59
+ key: 'arrow',
60
+ className: 'z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground',
61
+ }),
62
+ ],
63
+ }),
64
+ });
65
+ }