@camox/ui 0.6.1 → 0.7.0
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/package.json +5 -47
- package/src/components/alert-dialog.tsx +62 -35
- package/src/components/alert.tsx +18 -5
- package/src/components/avatar.tsx +8 -11
- package/src/components/badge.tsx +26 -16
- package/src/components/breadcrumb.tsx +26 -25
- package/src/components/button-group.tsx +23 -23
- package/src/components/button.tsx +26 -26
- package/src/components/command.tsx +53 -48
- package/src/components/dialog.tsx +40 -32
- package/src/components/dropdown-menu.tsx +137 -107
- package/src/components/input-group.tsx +146 -0
- package/src/components/input.tsx +4 -5
- package/src/components/kbd.tsx +1 -3
- package/src/components/label.tsx +2 -5
- package/src/components/panel.tsx +56 -25
- package/src/components/popover.tsx +55 -15
- package/src/components/select.tsx +86 -67
- package/src/components/separator.tsx +4 -11
- package/src/components/sheet.tsx +32 -37
- package/src/components/skeleton.tsx +1 -1
- package/src/components/switch.tsx +11 -7
- package/src/components/tabs.tsx +37 -16
- package/src/components/textarea.tsx +2 -4
- package/src/components/toggle.tsx +12 -14
- package/src/components/tooltip.tsx +29 -32
- package/src/styles/globals.css +1 -1
- package/src/components/accordion.tsx +0 -58
- package/src/components/checkbox.tsx +0 -27
- package/src/components/control-group.tsx +0 -58
- package/src/components/frame.tsx +0 -146
- package/src/components/input-base.tsx +0 -189
- package/src/components/resizable.tsx +0 -46
- package/src/hooks/use-mobile.ts +0 -19
|
@@ -1,23 +1,27 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as React from "react";
|
|
1
|
+
import { Switch as SwitchPrimitive } from "@base-ui/react/switch";
|
|
3
2
|
|
|
4
3
|
import { cn } from "../lib/utils";
|
|
5
4
|
|
|
6
|
-
function Switch({
|
|
5
|
+
function Switch({
|
|
6
|
+
className,
|
|
7
|
+
size = "default",
|
|
8
|
+
...props
|
|
9
|
+
}: SwitchPrimitive.Root.Props & {
|
|
10
|
+
size?: "sm" | "default";
|
|
11
|
+
}) {
|
|
7
12
|
return (
|
|
8
13
|
<SwitchPrimitive.Root
|
|
9
14
|
data-slot="switch"
|
|
15
|
+
data-size={size}
|
|
10
16
|
className={cn(
|
|
11
|
-
"peer
|
|
17
|
+
"peer group/switch relative inline-flex shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-[size=default]:h-[18.4px] data-[size=default]:w-[32px] data-[size=sm]:h-[14px] data-[size=sm]:w-[24px] dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:bg-primary data-unchecked:bg-input dark:data-unchecked:bg-input/80 data-disabled:cursor-not-allowed data-disabled:opacity-50",
|
|
12
18
|
className,
|
|
13
19
|
)}
|
|
14
20
|
{...props}
|
|
15
21
|
>
|
|
16
22
|
<SwitchPrimitive.Thumb
|
|
17
23
|
data-slot="switch-thumb"
|
|
18
|
-
className=
|
|
19
|
-
"bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0",
|
|
20
|
-
)}
|
|
24
|
+
className="bg-background dark:data-checked:bg-primary-foreground dark:data-unchecked:bg-foreground pointer-events-none block rounded-full ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=default]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=default]/switch:data-unchecked:translate-x-0 group-data-[size=sm]/switch:data-unchecked:translate-x-0"
|
|
21
25
|
/>
|
|
22
26
|
</SwitchPrimitive.Root>
|
|
23
27
|
);
|
package/src/components/tabs.tsx
CHANGED
|
@@ -1,37 +1,58 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { Tabs as TabsPrimitive } from "@base-ui/react/tabs";
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
3
|
|
|
4
4
|
import { cn } from "../lib/utils";
|
|
5
5
|
|
|
6
|
-
function Tabs({ className, ...props }:
|
|
6
|
+
function Tabs({ className, orientation = "horizontal", ...props }: TabsPrimitive.Root.Props) {
|
|
7
7
|
return (
|
|
8
8
|
<TabsPrimitive.Root
|
|
9
9
|
data-slot="tabs"
|
|
10
|
-
|
|
10
|
+
data-orientation={orientation}
|
|
11
|
+
className={cn("group/tabs flex gap-2 data-horizontal:flex-col", className)}
|
|
11
12
|
{...props}
|
|
12
13
|
/>
|
|
13
14
|
);
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
const tabsListVariants = cva(
|
|
18
|
+
"group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-9 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none",
|
|
19
|
+
{
|
|
20
|
+
variants: {
|
|
21
|
+
variant: {
|
|
22
|
+
default: "bg-muted",
|
|
23
|
+
line: "gap-1 bg-transparent",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
defaultVariants: {
|
|
27
|
+
variant: "default",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
function TabsList({
|
|
33
|
+
className,
|
|
34
|
+
variant = "default",
|
|
35
|
+
...props
|
|
36
|
+
}: TabsPrimitive.List.Props & VariantProps<typeof tabsListVariants>) {
|
|
17
37
|
return (
|
|
18
38
|
<TabsPrimitive.List
|
|
19
39
|
data-slot="tabs-list"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
className,
|
|
23
|
-
)}
|
|
40
|
+
data-variant={variant}
|
|
41
|
+
className={cn(tabsListVariants({ variant }), className)}
|
|
24
42
|
{...props}
|
|
25
43
|
/>
|
|
26
44
|
);
|
|
27
45
|
}
|
|
28
46
|
|
|
29
|
-
function TabsTrigger({ className, ...props }:
|
|
47
|
+
function TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {
|
|
30
48
|
return (
|
|
31
|
-
<TabsPrimitive.
|
|
49
|
+
<TabsPrimitive.Tab
|
|
32
50
|
data-slot="tabs-trigger"
|
|
33
51
|
className={cn(
|
|
34
|
-
"
|
|
52
|
+
"relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 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.5 has-data-[icon=inline-start]:pl-1.5 aria-disabled:pointer-events-none aria-disabled:opacity-50 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",
|
|
53
|
+
"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",
|
|
54
|
+
"data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground",
|
|
55
|
+
"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",
|
|
35
56
|
className,
|
|
36
57
|
)}
|
|
37
58
|
{...props}
|
|
@@ -39,14 +60,14 @@ function TabsTrigger({ className, ...props }: React.ComponentProps<typeof TabsPr
|
|
|
39
60
|
);
|
|
40
61
|
}
|
|
41
62
|
|
|
42
|
-
function TabsContent({ className, ...props }:
|
|
63
|
+
function TabsContent({ className, ...props }: TabsPrimitive.Panel.Props) {
|
|
43
64
|
return (
|
|
44
|
-
<TabsPrimitive.
|
|
65
|
+
<TabsPrimitive.Panel
|
|
45
66
|
data-slot="tabs-content"
|
|
46
|
-
className={cn("flex-1 outline-none", className)}
|
|
67
|
+
className={cn("flex-1 text-sm outline-none", className)}
|
|
47
68
|
{...props}
|
|
48
69
|
/>
|
|
49
70
|
);
|
|
50
71
|
}
|
|
51
72
|
|
|
52
|
-
export { Tabs, TabsList, TabsTrigger, TabsContent };
|
|
73
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants };
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { cn } from "../lib/utils";
|
|
4
4
|
|
|
5
5
|
function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
|
|
6
6
|
return (
|
|
7
7
|
<textarea
|
|
8
8
|
data-slot="textarea"
|
|
9
9
|
className={cn(
|
|
10
|
-
|
|
11
|
-
INPUT_FOCUS_STYLES,
|
|
12
|
-
"dark:bg-input/30 flex field-sizing-content min-h-16 w-full px-3 py-2",
|
|
10
|
+
"flex field-sizing-content min-h-16 w-full rounded-md border border-input bg-transparent px-2.5 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none placeholder:text-muted-foreground 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 md:text-sm dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
|
|
13
11
|
className,
|
|
14
12
|
)}
|
|
15
13
|
{...props}
|
|
@@ -1,23 +1,21 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type
|
|
3
|
-
import { cva } from "class-variance-authority";
|
|
4
|
-
import * as React from "react";
|
|
1
|
+
import { Toggle as TogglePrimitive } from "@base-ui/react/toggle";
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
5
3
|
|
|
6
4
|
import { cn } from "../lib/utils";
|
|
7
5
|
|
|
8
6
|
const toggleVariants = cva(
|
|
9
|
-
"inline-flex items-center justify-center gap-
|
|
7
|
+
"group/toggle inline-flex items-center justify-center gap-1 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-muted hover:text-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 aria-pressed:bg-muted dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
10
8
|
{
|
|
11
9
|
variants: {
|
|
12
10
|
variant: {
|
|
13
11
|
default: "bg-transparent",
|
|
14
|
-
outline:
|
|
15
|
-
"border border-input bg-transparent shadow-xs hover:bg-accent/50 hover:text-accent-foreground",
|
|
12
|
+
outline: "border border-input bg-transparent shadow-xs hover:bg-muted",
|
|
16
13
|
},
|
|
17
14
|
size: {
|
|
18
|
-
default:
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
default:
|
|
16
|
+
"h-9 min-w-9 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
|
|
17
|
+
sm: "h-8 min-w-8 px-2.5 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5",
|
|
18
|
+
lg: "h-10 min-w-10 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
|
|
21
19
|
},
|
|
22
20
|
},
|
|
23
21
|
defaultVariants: {
|
|
@@ -29,12 +27,12 @@ const toggleVariants = cva(
|
|
|
29
27
|
|
|
30
28
|
function Toggle({
|
|
31
29
|
className,
|
|
32
|
-
variant,
|
|
33
|
-
size,
|
|
30
|
+
variant = "default",
|
|
31
|
+
size = "default",
|
|
34
32
|
...props
|
|
35
|
-
}:
|
|
33
|
+
}: TogglePrimitive.Props & VariantProps<typeof toggleVariants>) {
|
|
36
34
|
return (
|
|
37
|
-
<TogglePrimitive
|
|
35
|
+
<TogglePrimitive
|
|
38
36
|
data-slot="toggle"
|
|
39
37
|
className={cn(toggleVariants({ variant, size, className }))}
|
|
40
38
|
{...props}
|
|
@@ -1,53 +1,50 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as React from "react";
|
|
1
|
+
import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip";
|
|
3
2
|
|
|
4
3
|
import { cn } from "../lib/utils";
|
|
5
4
|
|
|
6
|
-
function TooltipProvider({
|
|
7
|
-
|
|
8
|
-
...props
|
|
9
|
-
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
|
|
10
|
-
return (
|
|
11
|
-
<TooltipPrimitive.Provider
|
|
12
|
-
data-slot="tooltip-provider"
|
|
13
|
-
delayDuration={delayDuration}
|
|
14
|
-
{...props}
|
|
15
|
-
/>
|
|
16
|
-
);
|
|
5
|
+
function TooltipProvider({ delay = 0, ...props }: TooltipPrimitive.Provider.Props) {
|
|
6
|
+
return <TooltipPrimitive.Provider data-slot="tooltip-provider" delay={delay} {...props} />;
|
|
17
7
|
}
|
|
18
8
|
|
|
19
|
-
function Tooltip({ ...props }:
|
|
20
|
-
return
|
|
21
|
-
<TooltipProvider>
|
|
22
|
-
<TooltipPrimitive.Root data-slot="tooltip" {...props} />
|
|
23
|
-
</TooltipProvider>
|
|
24
|
-
);
|
|
9
|
+
function Tooltip({ ...props }: TooltipPrimitive.Root.Props) {
|
|
10
|
+
return <TooltipPrimitive.Root data-slot="tooltip" {...props} />;
|
|
25
11
|
}
|
|
26
12
|
|
|
27
|
-
function TooltipTrigger({ ...props }:
|
|
13
|
+
function TooltipTrigger({ ...props }: TooltipPrimitive.Trigger.Props) {
|
|
28
14
|
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
|
|
29
15
|
}
|
|
30
16
|
|
|
31
17
|
function TooltipContent({
|
|
32
18
|
className,
|
|
33
|
-
|
|
19
|
+
side = "top",
|
|
20
|
+
sideOffset = 4,
|
|
21
|
+
align = "center",
|
|
22
|
+
alignOffset = 0,
|
|
34
23
|
children,
|
|
35
24
|
...props
|
|
36
|
-
}:
|
|
25
|
+
}: TooltipPrimitive.Popup.Props &
|
|
26
|
+
Pick<TooltipPrimitive.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset">) {
|
|
37
27
|
return (
|
|
38
28
|
<TooltipPrimitive.Portal>
|
|
39
|
-
<TooltipPrimitive.
|
|
40
|
-
|
|
29
|
+
<TooltipPrimitive.Positioner
|
|
30
|
+
align={align}
|
|
31
|
+
alignOffset={alignOffset}
|
|
32
|
+
side={side}
|
|
41
33
|
sideOffset={sideOffset}
|
|
42
|
-
className=
|
|
43
|
-
"bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 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 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
|
44
|
-
className,
|
|
45
|
-
)}
|
|
46
|
-
{...props}
|
|
34
|
+
className="isolate z-50"
|
|
47
35
|
>
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
36
|
+
<TooltipPrimitive.Popup
|
|
37
|
+
data-slot="tooltip-content"
|
|
38
|
+
className={cn(
|
|
39
|
+
"z-50 inline-flex w-fit max-w-xs origin-(--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=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-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",
|
|
40
|
+
className,
|
|
41
|
+
)}
|
|
42
|
+
{...props}
|
|
43
|
+
>
|
|
44
|
+
{children}
|
|
45
|
+
<TooltipPrimitive.Arrow className="bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] data-[side=bottom]:top-1 data-[side=inline-end]:top-1/2! data-[side=inline-end]:-left-1 data-[side=inline-end]:-translate-y-1/2 data-[side=inline-start]:top-1/2! data-[side=inline-start]:-right-1 data-[side=inline-start]:-translate-y-1/2 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5" />
|
|
46
|
+
</TooltipPrimitive.Popup>
|
|
47
|
+
</TooltipPrimitive.Positioner>
|
|
51
48
|
</TooltipPrimitive.Portal>
|
|
52
49
|
);
|
|
53
50
|
}
|
package/src/styles/globals.css
CHANGED
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
--foreground: theme(--color-zinc-50);
|
|
43
43
|
--card: theme(--color-zinc-900);
|
|
44
44
|
--card-foreground: theme(--color-zinc-50);
|
|
45
|
-
--popover:
|
|
45
|
+
--popover: oklch(17.5% 0.0055 285.85);
|
|
46
46
|
--popover-foreground: theme(--color-zinc-50);
|
|
47
47
|
--primary: theme(--color-emerald-600);
|
|
48
48
|
--primary-foreground: theme(--color-emerald-50);
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import * as AccordionPrimitive from "@radix-ui/react-accordion";
|
|
2
|
-
import * as React from "react";
|
|
3
|
-
|
|
4
|
-
import { cn } from "../lib/utils";
|
|
5
|
-
|
|
6
|
-
function Accordion({ ...props }: React.ComponentProps<typeof AccordionPrimitive.Root>) {
|
|
7
|
-
return <AccordionPrimitive.Root data-slot="accordion" {...props} />;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function AccordionItem({
|
|
11
|
-
className,
|
|
12
|
-
...props
|
|
13
|
-
}: React.ComponentProps<typeof AccordionPrimitive.Item>) {
|
|
14
|
-
return (
|
|
15
|
-
<AccordionPrimitive.Item
|
|
16
|
-
data-slot="accordion-item"
|
|
17
|
-
className={cn("border-b last:border-b-0", className)}
|
|
18
|
-
{...props}
|
|
19
|
-
/>
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
interface AccordionTriggerProps extends React.ComponentProps<typeof AccordionPrimitive.Trigger> {}
|
|
24
|
-
|
|
25
|
-
function AccordionTrigger({ className, children, ...props }: AccordionTriggerProps) {
|
|
26
|
-
return (
|
|
27
|
-
<AccordionPrimitive.Header className="flex">
|
|
28
|
-
<AccordionPrimitive.Trigger
|
|
29
|
-
data-slot="accordion-trigger"
|
|
30
|
-
className={cn(
|
|
31
|
-
"focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180",
|
|
32
|
-
className,
|
|
33
|
-
)}
|
|
34
|
-
{...props}
|
|
35
|
-
>
|
|
36
|
-
{children}
|
|
37
|
-
</AccordionPrimitive.Trigger>
|
|
38
|
-
</AccordionPrimitive.Header>
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function AccordionContent({
|
|
43
|
-
className,
|
|
44
|
-
children,
|
|
45
|
-
...props
|
|
46
|
-
}: React.ComponentProps<typeof AccordionPrimitive.Content>) {
|
|
47
|
-
return (
|
|
48
|
-
<AccordionPrimitive.Content
|
|
49
|
-
data-slot="accordion-content"
|
|
50
|
-
className="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm"
|
|
51
|
-
{...props}
|
|
52
|
-
>
|
|
53
|
-
<div className={cn("pt-0 pb-4", className)}>{children}</div>
|
|
54
|
-
</AccordionPrimitive.Content>
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
|
|
2
|
-
import { CheckIcon } from "lucide-react";
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
|
|
5
|
-
import { cn } from "../lib/utils";
|
|
6
|
-
|
|
7
|
-
function Checkbox({ className, ...props }: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
|
|
8
|
-
return (
|
|
9
|
-
<CheckboxPrimitive.Root
|
|
10
|
-
data-slot="checkbox"
|
|
11
|
-
className={cn(
|
|
12
|
-
"peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
|
13
|
-
className,
|
|
14
|
-
)}
|
|
15
|
-
{...props}
|
|
16
|
-
>
|
|
17
|
-
<CheckboxPrimitive.Indicator
|
|
18
|
-
data-slot="checkbox-indicator"
|
|
19
|
-
className="flex items-center justify-center text-current transition-none"
|
|
20
|
-
>
|
|
21
|
-
<CheckIcon className="size-3.5" />
|
|
22
|
-
</CheckboxPrimitive.Indicator>
|
|
23
|
-
</CheckboxPrimitive.Root>
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export { Checkbox };
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { Primitive } from "@radix-ui/react-primitive";
|
|
4
|
-
import { Slot } from "@radix-ui/react-slot";
|
|
5
|
-
import * as React from "react";
|
|
6
|
-
|
|
7
|
-
import { cn } from "../lib/utils";
|
|
8
|
-
|
|
9
|
-
const ControlGroupContext = React.createContext<Pick<ControlGroupProps, "orientation">>({
|
|
10
|
-
orientation: "horizontal",
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
function useControlGroup() {
|
|
14
|
-
const context = React.useContext(ControlGroupContext);
|
|
15
|
-
if (!context) {
|
|
16
|
-
throw new Error("useControlGroup must be used within a <ControlGroup />.");
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return context;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface ControlGroupProps extends React.ComponentProps<typeof Primitive.div> {
|
|
23
|
-
orientation?: "horizontal" | "vertical";
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function ControlGroup({ className, orientation = "horizontal", ...props }: ControlGroupProps) {
|
|
27
|
-
return (
|
|
28
|
-
<ControlGroupContext.Provider value={{ orientation }}>
|
|
29
|
-
<Primitive.div
|
|
30
|
-
data-slot="control-group"
|
|
31
|
-
data-orientation={orientation}
|
|
32
|
-
className={cn("flex", orientation === "vertical" && "flex-col", className)}
|
|
33
|
-
{...props}
|
|
34
|
-
/>
|
|
35
|
-
</ControlGroupContext.Provider>
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function ControlGroupItem({ className, ...props }: React.ComponentProps<typeof Slot>) {
|
|
40
|
-
const { orientation } = useControlGroup();
|
|
41
|
-
|
|
42
|
-
return (
|
|
43
|
-
<Slot
|
|
44
|
-
data-slot="control-group-item"
|
|
45
|
-
className={cn(
|
|
46
|
-
"rounded-none focus-within:z-10",
|
|
47
|
-
orientation === "horizontal" &&
|
|
48
|
-
"-me-px h-auto first:rounded-s-md last:-me-0 last:rounded-e-md",
|
|
49
|
-
orientation === "vertical" &&
|
|
50
|
-
"w-auto [margin-block-end:-1px] first:rounded-ss-md first:rounded-se-md last:rounded-ee-md last:rounded-es-md last:[margin-block-end:0]",
|
|
51
|
-
className,
|
|
52
|
-
)}
|
|
53
|
-
{...props}
|
|
54
|
-
/>
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export { ControlGroup, ControlGroupItem };
|
package/src/components/frame.tsx
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { createPortal } from "react-dom";
|
|
3
|
-
|
|
4
|
-
import { cn } from "../lib/utils";
|
|
5
|
-
|
|
6
|
-
interface FrameContextValue {
|
|
7
|
-
window: Window | null;
|
|
8
|
-
iframeElement: HTMLIFrameElement | null;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const FrameContext = React.createContext<FrameContextValue>({
|
|
12
|
-
window: null,
|
|
13
|
-
iframeElement: null,
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
export function useFrame() {
|
|
17
|
-
const context = React.use(FrameContext);
|
|
18
|
-
if (!context) {
|
|
19
|
-
throw new Error("useFrame must be used within a Frame");
|
|
20
|
-
}
|
|
21
|
-
return context;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
interface FrameProps {
|
|
25
|
-
children: React.ReactNode;
|
|
26
|
-
/** Optional className for the iframe element */
|
|
27
|
-
className?: string;
|
|
28
|
-
/** Optional inline styles for the iframe element */
|
|
29
|
-
style?: React.CSSProperties;
|
|
30
|
-
/** Whether to copy parent document styles into the iframe (default: true) */
|
|
31
|
-
copyStyles?: boolean;
|
|
32
|
-
/** Callback when iframe is ready, receives the iframe element */
|
|
33
|
-
onIframeReady?: (iframe: HTMLIFrameElement) => void;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export const Frame = ({
|
|
37
|
-
children,
|
|
38
|
-
className,
|
|
39
|
-
style,
|
|
40
|
-
copyStyles = true,
|
|
41
|
-
onIframeReady,
|
|
42
|
-
}: FrameProps) => {
|
|
43
|
-
const iframeRef = React.useRef<HTMLIFrameElement>(null);
|
|
44
|
-
const [iframeWindow, setIframeWindow] = React.useState<Window | null>(null);
|
|
45
|
-
const [iframeElement, setIframeElement] = React.useState<HTMLIFrameElement | null>(null);
|
|
46
|
-
const [mountNode, setMountNode] = React.useState<HTMLElement | null>(null);
|
|
47
|
-
const [hasRadixPopper, setHasRadixPopper] = React.useState(false);
|
|
48
|
-
|
|
49
|
-
React.useEffect(() => {
|
|
50
|
-
const iframe = iframeRef.current;
|
|
51
|
-
if (!iframe) return;
|
|
52
|
-
|
|
53
|
-
const handleLoad = () => {
|
|
54
|
-
const iframeDoc = iframe.contentDocument;
|
|
55
|
-
const iframeWin = iframe.contentWindow;
|
|
56
|
-
|
|
57
|
-
if (!iframeDoc || !iframeWin) return;
|
|
58
|
-
|
|
59
|
-
// Set up basic document structure
|
|
60
|
-
iframeDoc.open();
|
|
61
|
-
iframeDoc.write(
|
|
62
|
-
"<!DOCTYPE html><html><head></head><body style='background: transparent;'></body></html>",
|
|
63
|
-
);
|
|
64
|
-
iframeDoc.close();
|
|
65
|
-
|
|
66
|
-
// Navigate the top-level window when a native <a> is clicked inside the
|
|
67
|
-
// iframe. Links managed by a client-side router (e.g. TanStack Router's
|
|
68
|
-
// <Link>) call e.preventDefault() themselves, so we skip those.
|
|
69
|
-
// We listen on `iframeWin` (not `iframeDoc`) so that this handler fires
|
|
70
|
-
// AFTER React's event delegation (which is on the document/body), giving
|
|
71
|
-
// React a chance to call preventDefault() first.
|
|
72
|
-
iframeWin.addEventListener("click", (e) => {
|
|
73
|
-
if (e.defaultPrevented) return;
|
|
74
|
-
const anchor = (e.target as Element).closest("a");
|
|
75
|
-
if (!anchor?.href) return;
|
|
76
|
-
if (anchor.target === "_blank") return;
|
|
77
|
-
e.preventDefault();
|
|
78
|
-
window.top?.location.assign(anchor.href);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
// Copy styles from parent document if requested
|
|
82
|
-
if (copyStyles) {
|
|
83
|
-
const headStyles = Array.from(
|
|
84
|
-
document.head.querySelectorAll('style, link[rel="stylesheet"]'),
|
|
85
|
-
);
|
|
86
|
-
headStyles.forEach((style) => {
|
|
87
|
-
const clonedStyle = style.cloneNode(true);
|
|
88
|
-
iframeDoc.head.appendChild(clonedStyle);
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Set the mount node to the iframe's body
|
|
93
|
-
setMountNode(iframeDoc.body);
|
|
94
|
-
setIframeWindow(iframeWin);
|
|
95
|
-
setIframeElement(iframe);
|
|
96
|
-
onIframeReady?.(iframe);
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
// Add load event listener
|
|
100
|
-
iframe.addEventListener("load", handleLoad);
|
|
101
|
-
|
|
102
|
-
// Trigger load if iframe is already loaded
|
|
103
|
-
if (iframe.contentDocument?.readyState === "complete") {
|
|
104
|
-
handleLoad();
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return () => {
|
|
108
|
-
iframe.removeEventListener("load", handleLoad);
|
|
109
|
-
};
|
|
110
|
-
}, [copyStyles, onIframeReady]);
|
|
111
|
-
|
|
112
|
-
// Monitor for Radix popper content wrapper in body
|
|
113
|
-
React.useEffect(() => {
|
|
114
|
-
const checkForRadixPopper = () => {
|
|
115
|
-
const hasPopper =
|
|
116
|
-
document.body.querySelector(":scope > [data-radix-popper-content-wrapper]") !== null;
|
|
117
|
-
setHasRadixPopper(hasPopper);
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
// Initial check
|
|
121
|
-
checkForRadixPopper();
|
|
122
|
-
|
|
123
|
-
// Set up MutationObserver to watch for changes
|
|
124
|
-
const observer = new MutationObserver(checkForRadixPopper);
|
|
125
|
-
observer.observe(document.body, {
|
|
126
|
-
childList: true,
|
|
127
|
-
subtree: false, // Only watch direct children of body
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
return () => {
|
|
131
|
-
observer.disconnect();
|
|
132
|
-
};
|
|
133
|
-
}, []);
|
|
134
|
-
|
|
135
|
-
return (
|
|
136
|
-
<div className={cn("relative w-full h-full", className)} style={style}>
|
|
137
|
-
{/* Display an overlay to properly close close Radix portals (modals, popovers...) */}
|
|
138
|
-
{/* because otherwise Radix wouldn't detect pointer events that would happen on the iframe */}
|
|
139
|
-
{hasRadixPopper && <div className="absolute top-0 left-0 h-full w-full" />}
|
|
140
|
-
<FrameContext.Provider value={{ window: iframeWindow, iframeElement }}>
|
|
141
|
-
<iframe ref={iframeRef} className={cn("w-full h-full")} />
|
|
142
|
-
{mountNode && createPortal(children, mountNode)}
|
|
143
|
-
</FrameContext.Provider>
|
|
144
|
-
</div>
|
|
145
|
-
);
|
|
146
|
-
};
|