@theruntime/components 0.0.0 → 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/package.json +113 -4
- package/src/accordion.tsx +62 -0
- package/src/alert-dialog.tsx +177 -0
- package/src/alert.tsx +60 -0
- package/src/aspect-ratio.tsx +7 -0
- package/src/attachment.tsx +192 -0
- package/src/avatar.tsx +94 -0
- package/src/badge.tsx +46 -0
- package/src/breadcrumb.tsx +102 -0
- package/src/bubble.tsx +125 -0
- package/src/button-group.tsx +82 -0
- package/src/button.tsx +62 -0
- package/src/calendar.tsx +178 -0
- package/src/card.tsx +75 -0
- package/src/carousel.tsx +228 -0
- package/src/chart/container.tsx +72 -0
- package/src/chart/context.tsx +39 -0
- package/src/chart/index.ts +4 -0
- package/src/chart/legend.tsx +63 -0
- package/src/chart/payload.ts +31 -0
- package/src/chart/tooltip.tsx +149 -0
- package/src/checkbox.tsx +27 -0
- package/src/cn.ts +36 -0
- package/src/collapsible.tsx +19 -0
- package/src/combobox/chips.tsx +71 -0
- package/src/combobox/content.tsx +123 -0
- package/src/combobox/index.ts +13 -0
- package/src/combobox/input.tsx +39 -0
- package/src/combobox/trigger.tsx +44 -0
- package/src/command.tsx +153 -0
- package/src/context-menu.tsx +222 -0
- package/src/dialog.tsx +142 -0
- package/src/direction.tsx +18 -0
- package/src/drawer.tsx +122 -0
- package/src/dropdown-menu.tsx +226 -0
- package/src/empty.tsx +94 -0
- package/src/field.tsx +232 -0
- package/src/form.tsx +153 -0
- package/src/hover-card.tsx +36 -0
- package/src/index.ts +90 -0
- package/src/input-group.tsx +156 -0
- package/src/input-otp.tsx +68 -0
- package/src/input.tsx +21 -0
- package/src/item.tsx +172 -0
- package/src/kbd.tsx +28 -0
- package/src/label.tsx +19 -0
- package/src/marker.tsx +66 -0
- package/src/menubar.tsx +250 -0
- package/src/message-scroller.tsx +128 -0
- package/src/message.tsx +85 -0
- package/src/native-select.tsx +56 -0
- package/src/navigation-menu.tsx +161 -0
- package/src/pagination.tsx +106 -0
- package/src/popover.tsx +72 -0
- package/src/progress.tsx +26 -0
- package/src/questionnaire/actions.tsx +118 -0
- package/src/questionnaire/choices.tsx +113 -0
- package/src/questionnaire/index.ts +21 -0
- package/src/questionnaire/root.tsx +75 -0
- package/src/radio-group.tsx +43 -0
- package/src/resizable.tsx +45 -0
- package/src/scroll-area.tsx +54 -0
- package/src/select.tsx +173 -0
- package/src/separator.tsx +26 -0
- package/src/sheet.tsx +132 -0
- package/src/shell/app-tab.tsx +67 -0
- package/src/shell/entry-row.tsx +137 -0
- package/src/shell/field.tsx +83 -0
- package/src/shell/group-head.tsx +19 -0
- package/src/shell/scope-chip.tsx +32 -0
- package/src/shell/suggest-panel.tsx +92 -0
- package/src/sidebar/context.tsx +128 -0
- package/src/sidebar/index.ts +23 -0
- package/src/sidebar/menu.tsx +239 -0
- package/src/sidebar/sections.tsx +118 -0
- package/src/sidebar/sidebar.tsx +183 -0
- package/src/skeleton.tsx +13 -0
- package/src/slider.tsx +56 -0
- package/src/sonner.tsx +41 -0
- package/src/spinner.tsx +16 -0
- package/src/styles.css +149 -0
- package/src/switch.tsx +33 -0
- package/src/table.tsx +90 -0
- package/src/tabs.tsx +79 -0
- package/src/textarea.tsx +18 -0
- package/src/toggle-group.tsx +81 -0
- package/src/toggle.tsx +44 -0
- package/src/tooltip.tsx +51 -0
- package/src/use-mobile.ts +21 -0
- package/README.md +0 -3
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { HoverCard as HoverCardPrimitive } from "radix-ui";
|
|
3
|
+
|
|
4
|
+
import { cn } from "./cn";
|
|
5
|
+
|
|
6
|
+
function HoverCard({ ...props }: React.ComponentProps<typeof HoverCardPrimitive.Root>) {
|
|
7
|
+
return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function HoverCardTrigger({ ...props }: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) {
|
|
11
|
+
return <HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function HoverCardContent({
|
|
15
|
+
className,
|
|
16
|
+
align = "center",
|
|
17
|
+
sideOffset = 4,
|
|
18
|
+
...props
|
|
19
|
+
}: React.ComponentProps<typeof HoverCardPrimitive.Content>) {
|
|
20
|
+
return (
|
|
21
|
+
<HoverCardPrimitive.Portal data-slot="hover-card-portal">
|
|
22
|
+
<HoverCardPrimitive.Content
|
|
23
|
+
data-slot="hover-card-content"
|
|
24
|
+
align={align}
|
|
25
|
+
sideOffset={sideOffset}
|
|
26
|
+
className={cn(
|
|
27
|
+
"z-50 w-64 origin-(--radix-hover-card-content-transform-origin) rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden 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-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
|
|
28
|
+
className,
|
|
29
|
+
)}
|
|
30
|
+
{...props}
|
|
31
|
+
/>
|
|
32
|
+
</HoverCardPrimitive.Portal>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export { HoverCard, HoverCardTrigger, HoverCardContent };
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// Vendored shadcn v4, retargeted onto this runtime's own theme tokens (bg-primary, border-input,
|
|
2
|
+
// bg-card, text-muted-foreground, ring-ring). The vocabulary matches the name map in styles.css
|
|
3
|
+
// and the values in tokens.css, so every component re-themes when the active theme class changes. shadcn v4 source is already token-driven, so
|
|
4
|
+
// nothing here is hardcoded.
|
|
5
|
+
//
|
|
6
|
+
// import { Button, Card, Accordion, Dialog, Sonner } from "@theruntime/components";
|
|
7
|
+
//
|
|
8
|
+
// Per-component subpath imports also work, e.g.
|
|
9
|
+
// `import { Button } from "@theruntime/components/button"`.
|
|
10
|
+
//
|
|
11
|
+
// Scope: every installable `registry:ui` item shadcn ships. `toast` is superseded by `sonner`,
|
|
12
|
+
// which is here. `questionnaire` is not in this style's registry, so it is vendored from
|
|
13
|
+
// `radix-nova`, the same Radix and `@shadcn/react` primitives, with its icon placeholder swapped
|
|
14
|
+
// for phosphor's CheckIcon.
|
|
15
|
+
//
|
|
16
|
+
// House adaptations are marked with a comment at the site: buttons are pills (button.tsx), and
|
|
17
|
+
// anything that closes a button's edge follows (button-group.tsx). Everything else is upstream
|
|
18
|
+
// verbatim apart from retargeted imports (`@/lib/utils` to `./cn`, `@/registry/new-york-v4/ui/x`
|
|
19
|
+
// to `./x`) and the dropped `"use client"` directive, which this runtime has no use for.
|
|
20
|
+
//
|
|
21
|
+
// To diverge, copy a component file into an app's own directory and import it locally. No tooling
|
|
22
|
+
// is involved. To extend, fetch a registry item from ui.shadcn.com/r and retarget its imports the
|
|
23
|
+
// same way; the barrel picks it up once it is added below.
|
|
24
|
+
//
|
|
25
|
+
// cn is re-exported from ./cn. Every component re-exports its own named parts.
|
|
26
|
+
|
|
27
|
+
export * from "./accordion";
|
|
28
|
+
export * from "./alert";
|
|
29
|
+
export * from "./alert-dialog";
|
|
30
|
+
export * from "./aspect-ratio";
|
|
31
|
+
export * from "./attachment";
|
|
32
|
+
export * from "./avatar";
|
|
33
|
+
export * from "./badge";
|
|
34
|
+
export * from "./breadcrumb";
|
|
35
|
+
export * from "./bubble";
|
|
36
|
+
export * from "./button";
|
|
37
|
+
export * from "./button-group";
|
|
38
|
+
export * from "./calendar";
|
|
39
|
+
export * from "./card";
|
|
40
|
+
export * from "./carousel";
|
|
41
|
+
export * from "./chart";
|
|
42
|
+
export * from "./checkbox";
|
|
43
|
+
export * from "./cn";
|
|
44
|
+
export * from "./collapsible";
|
|
45
|
+
export * from "./combobox";
|
|
46
|
+
export * from "./command";
|
|
47
|
+
export * from "./context-menu";
|
|
48
|
+
export * from "./dialog";
|
|
49
|
+
export * from "./direction";
|
|
50
|
+
export * from "./drawer";
|
|
51
|
+
export * from "./dropdown-menu";
|
|
52
|
+
export * from "./empty";
|
|
53
|
+
export * from "./field";
|
|
54
|
+
export * from "./form";
|
|
55
|
+
export * from "./hover-card";
|
|
56
|
+
export * from "./input";
|
|
57
|
+
export * from "./input-group";
|
|
58
|
+
export * from "./input-otp";
|
|
59
|
+
export * from "./item";
|
|
60
|
+
export * from "./kbd";
|
|
61
|
+
export * from "./label";
|
|
62
|
+
export * from "./marker";
|
|
63
|
+
export * from "./menubar";
|
|
64
|
+
export * from "./message";
|
|
65
|
+
export * from "./message-scroller";
|
|
66
|
+
export * from "./native-select";
|
|
67
|
+
export * from "./navigation-menu";
|
|
68
|
+
export * from "./pagination";
|
|
69
|
+
export * from "./popover";
|
|
70
|
+
export * from "./progress";
|
|
71
|
+
export * from "./questionnaire";
|
|
72
|
+
export * from "./radio-group";
|
|
73
|
+
export * from "./resizable";
|
|
74
|
+
export * from "./scroll-area";
|
|
75
|
+
export * from "./select";
|
|
76
|
+
export * from "./separator";
|
|
77
|
+
export * from "./sheet";
|
|
78
|
+
export * from "./sidebar";
|
|
79
|
+
export * from "./skeleton";
|
|
80
|
+
export * from "./slider";
|
|
81
|
+
export * from "./sonner";
|
|
82
|
+
export * from "./spinner";
|
|
83
|
+
export * from "./switch";
|
|
84
|
+
export * from "./table";
|
|
85
|
+
export * from "./tabs";
|
|
86
|
+
export * from "./textarea";
|
|
87
|
+
export * from "./toggle";
|
|
88
|
+
export * from "./toggle-group";
|
|
89
|
+
export * from "./tooltip";
|
|
90
|
+
export * from "./use-mobile";
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
|
+
|
|
4
|
+
import { cn } from "./cn";
|
|
5
|
+
import { Button } from "./button";
|
|
6
|
+
import { Input } from "./input";
|
|
7
|
+
import { Textarea } from "./textarea";
|
|
8
|
+
|
|
9
|
+
function InputGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
10
|
+
return (
|
|
11
|
+
<div
|
|
12
|
+
data-slot="input-group"
|
|
13
|
+
role="group"
|
|
14
|
+
className={cn(
|
|
15
|
+
"group/input-group relative flex w-full items-center rounded-md border border-input shadow-xs transition-[color,box-shadow] outline-none dark:bg-input/30",
|
|
16
|
+
"h-9 min-w-0 has-[>textarea]:h-auto",
|
|
17
|
+
|
|
18
|
+
// Variants based on alignment.
|
|
19
|
+
"has-[>[data-align=inline-start]]:[&>input]:pl-2",
|
|
20
|
+
"has-[>[data-align=inline-end]]:[&>input]:pr-2",
|
|
21
|
+
"has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3",
|
|
22
|
+
"has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3",
|
|
23
|
+
|
|
24
|
+
// Focus state.
|
|
25
|
+
"has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-[3px] has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50",
|
|
26
|
+
|
|
27
|
+
// Error state.
|
|
28
|
+
"has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-destructive/20 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40",
|
|
29
|
+
|
|
30
|
+
className,
|
|
31
|
+
)}
|
|
32
|
+
{...props}
|
|
33
|
+
/>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const inputGroupAddonVariants = cva(
|
|
38
|
+
"flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium text-muted-foreground select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",
|
|
39
|
+
{
|
|
40
|
+
variants: {
|
|
41
|
+
align: {
|
|
42
|
+
"inline-start": "order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]",
|
|
43
|
+
"inline-end": "order-last pr-3 has-[>button]:mr-[-0.45rem] has-[>kbd]:mr-[-0.35rem]",
|
|
44
|
+
"block-start":
|
|
45
|
+
"order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5 [.border-b]:pb-3",
|
|
46
|
+
"block-end":
|
|
47
|
+
"order-last w-full justify-start px-3 pb-3 group-has-[>input]/input-group:pb-2.5 [.border-t]:pt-3",
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
defaultVariants: {
|
|
51
|
+
align: "inline-start",
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
function InputGroupAddon({
|
|
57
|
+
className,
|
|
58
|
+
align = "inline-start",
|
|
59
|
+
...props
|
|
60
|
+
}: React.ComponentProps<"div"> & VariantProps<typeof inputGroupAddonVariants>) {
|
|
61
|
+
return (
|
|
62
|
+
<div
|
|
63
|
+
role="group"
|
|
64
|
+
data-slot="input-group-addon"
|
|
65
|
+
data-align={align}
|
|
66
|
+
className={cn(inputGroupAddonVariants({ align }), className)}
|
|
67
|
+
onClick={(e) => {
|
|
68
|
+
if (e.target instanceof Element && e.target.closest("button")) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
e.currentTarget.parentElement?.querySelector("input")?.focus();
|
|
72
|
+
}}
|
|
73
|
+
{...props}
|
|
74
|
+
/>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const inputGroupButtonVariants = cva("flex items-center gap-2 text-sm shadow-none", {
|
|
79
|
+
variants: {
|
|
80
|
+
size: {
|
|
81
|
+
xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-2 has-[>svg]:px-2 [&>svg:not([class*='size-'])]:size-3.5",
|
|
82
|
+
sm: "h-8 gap-1.5 rounded-md px-2.5 has-[>svg]:px-2.5",
|
|
83
|
+
"icon-xs": "size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0",
|
|
84
|
+
"icon-sm": "size-8 p-0 has-[>svg]:p-0",
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
defaultVariants: {
|
|
88
|
+
size: "xs",
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
function InputGroupButton({
|
|
93
|
+
className,
|
|
94
|
+
type = "button",
|
|
95
|
+
variant = "ghost",
|
|
96
|
+
size = "xs",
|
|
97
|
+
...props
|
|
98
|
+
}: Omit<React.ComponentProps<typeof Button>, "size"> &
|
|
99
|
+
VariantProps<typeof inputGroupButtonVariants>) {
|
|
100
|
+
return (
|
|
101
|
+
<Button
|
|
102
|
+
type={type}
|
|
103
|
+
data-size={size}
|
|
104
|
+
variant={variant}
|
|
105
|
+
className={cn(inputGroupButtonVariants({ size }), className)}
|
|
106
|
+
{...props}
|
|
107
|
+
/>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function InputGroupText({ className, ...props }: React.ComponentProps<"span">) {
|
|
112
|
+
return (
|
|
113
|
+
<span
|
|
114
|
+
className={cn(
|
|
115
|
+
"flex items-center gap-2 text-sm text-muted-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
|
|
116
|
+
className,
|
|
117
|
+
)}
|
|
118
|
+
{...props}
|
|
119
|
+
/>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function InputGroupInput({ className, ...props }: React.ComponentProps<"input">) {
|
|
124
|
+
return (
|
|
125
|
+
<Input
|
|
126
|
+
data-slot="input-group-control"
|
|
127
|
+
className={cn(
|
|
128
|
+
"flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent",
|
|
129
|
+
className,
|
|
130
|
+
)}
|
|
131
|
+
{...props}
|
|
132
|
+
/>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function InputGroupTextarea({ className, ...props }: React.ComponentProps<"textarea">) {
|
|
137
|
+
return (
|
|
138
|
+
<Textarea
|
|
139
|
+
data-slot="input-group-control"
|
|
140
|
+
className={cn(
|
|
141
|
+
"flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent",
|
|
142
|
+
className,
|
|
143
|
+
)}
|
|
144
|
+
{...props}
|
|
145
|
+
/>
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export {
|
|
150
|
+
InputGroup,
|
|
151
|
+
InputGroupAddon,
|
|
152
|
+
InputGroupButton,
|
|
153
|
+
InputGroupText,
|
|
154
|
+
InputGroupInput,
|
|
155
|
+
InputGroupTextarea,
|
|
156
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { OTPInput, OTPInputContext } from "input-otp";
|
|
3
|
+
import { MinusIcon } from "@phosphor-icons/react";
|
|
4
|
+
|
|
5
|
+
import { cn } from "./cn";
|
|
6
|
+
|
|
7
|
+
function InputOTP({
|
|
8
|
+
className,
|
|
9
|
+
containerClassName,
|
|
10
|
+
...props
|
|
11
|
+
}: React.ComponentProps<typeof OTPInput> & {
|
|
12
|
+
containerClassName?: string;
|
|
13
|
+
}) {
|
|
14
|
+
return (
|
|
15
|
+
<OTPInput
|
|
16
|
+
data-slot="input-otp"
|
|
17
|
+
containerClassName={cn("flex items-center gap-2 has-disabled:opacity-50", containerClassName)}
|
|
18
|
+
className={cn("disabled:cursor-not-allowed", className)}
|
|
19
|
+
{...props}
|
|
20
|
+
/>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function InputOTPGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
25
|
+
return (
|
|
26
|
+
<div data-slot="input-otp-group" className={cn("flex items-center", className)} {...props} />
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function InputOTPSlot({
|
|
31
|
+
index,
|
|
32
|
+
className,
|
|
33
|
+
...props
|
|
34
|
+
}: React.ComponentProps<"div"> & {
|
|
35
|
+
index: number;
|
|
36
|
+
}) {
|
|
37
|
+
const inputOTPContext = React.useContext(OTPInputContext);
|
|
38
|
+
const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {};
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<div
|
|
42
|
+
data-slot="input-otp-slot"
|
|
43
|
+
data-active={isActive}
|
|
44
|
+
className={cn(
|
|
45
|
+
"relative flex h-9 w-9 items-center justify-center border-y border-r border-input text-sm shadow-xs transition-all outline-none first:rounded-l-md first:border-l last:rounded-r-md aria-invalid:border-destructive data-[active=true]:z-10 data-[active=true]:border-ring data-[active=true]:ring-[3px] data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:border-destructive data-[active=true]:aria-invalid:ring-destructive/20 dark:bg-input/30 dark:data-[active=true]:aria-invalid:ring-destructive/40",
|
|
46
|
+
className,
|
|
47
|
+
)}
|
|
48
|
+
{...props}
|
|
49
|
+
>
|
|
50
|
+
{char}
|
|
51
|
+
{hasFakeCaret && (
|
|
52
|
+
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
|
|
53
|
+
<div className="h-4 w-px animate-caret-blink bg-foreground duration-1000" />
|
|
54
|
+
</div>
|
|
55
|
+
)}
|
|
56
|
+
</div>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function InputOTPSeparator({ ...props }: React.ComponentProps<"div">) {
|
|
61
|
+
return (
|
|
62
|
+
<div data-slot="input-otp-separator" role="separator" {...props}>
|
|
63
|
+
<MinusIcon />
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };
|
package/src/input.tsx
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import { cn } from "./cn";
|
|
4
|
+
|
|
5
|
+
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
|
|
6
|
+
return (
|
|
7
|
+
<input
|
|
8
|
+
type={type}
|
|
9
|
+
data-slot="input"
|
|
10
|
+
className={cn(
|
|
11
|
+
"h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30",
|
|
12
|
+
"focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
|
|
13
|
+
"aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
|
|
14
|
+
className,
|
|
15
|
+
)}
|
|
16
|
+
{...props}
|
|
17
|
+
/>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { Input };
|
package/src/item.tsx
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
|
+
import { Slot } from "radix-ui";
|
|
4
|
+
|
|
5
|
+
import { cn } from "./cn";
|
|
6
|
+
import { Separator } from "./separator";
|
|
7
|
+
|
|
8
|
+
function ItemGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
9
|
+
return (
|
|
10
|
+
<div
|
|
11
|
+
role="list"
|
|
12
|
+
data-slot="item-group"
|
|
13
|
+
className={cn("group/item-group flex flex-col", className)}
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function ItemSeparator({ className, ...props }: React.ComponentProps<typeof Separator>) {
|
|
20
|
+
return (
|
|
21
|
+
<Separator
|
|
22
|
+
data-slot="item-separator"
|
|
23
|
+
orientation="horizontal"
|
|
24
|
+
className={cn("my-0", className)}
|
|
25
|
+
{...props}
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const itemVariants = cva(
|
|
31
|
+
"group/item flex flex-wrap items-center rounded-md border border-transparent text-sm transition-colors duration-100 outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 [a]:transition-colors [a]:hover:bg-accent/50",
|
|
32
|
+
{
|
|
33
|
+
variants: {
|
|
34
|
+
variant: {
|
|
35
|
+
default: "bg-transparent",
|
|
36
|
+
outline: "border-border",
|
|
37
|
+
muted: "bg-muted/50",
|
|
38
|
+
},
|
|
39
|
+
size: {
|
|
40
|
+
default: "gap-4 p-4",
|
|
41
|
+
sm: "gap-2.5 px-4 py-3",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
defaultVariants: {
|
|
45
|
+
variant: "default",
|
|
46
|
+
size: "default",
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
function Item({
|
|
52
|
+
className,
|
|
53
|
+
variant = "default",
|
|
54
|
+
size = "default",
|
|
55
|
+
asChild = false,
|
|
56
|
+
...props
|
|
57
|
+
}: React.ComponentProps<"div"> & VariantProps<typeof itemVariants> & { asChild?: boolean }) {
|
|
58
|
+
const Comp = asChild ? Slot.Root : "div";
|
|
59
|
+
return (
|
|
60
|
+
<Comp
|
|
61
|
+
data-slot="item"
|
|
62
|
+
data-variant={variant}
|
|
63
|
+
data-size={size}
|
|
64
|
+
className={cn(itemVariants({ variant, size, className }))}
|
|
65
|
+
{...props}
|
|
66
|
+
/>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const itemMediaVariants = cva(
|
|
71
|
+
"flex shrink-0 items-center justify-center gap-2 group-has-[[data-slot=item-description]]/item:translate-y-0.5 group-has-[[data-slot=item-description]]/item:self-start [&_svg]:pointer-events-none",
|
|
72
|
+
{
|
|
73
|
+
variants: {
|
|
74
|
+
variant: {
|
|
75
|
+
default: "bg-transparent",
|
|
76
|
+
icon: "size-8 rounded-sm border bg-muted [&_svg:not([class*='size-'])]:size-4",
|
|
77
|
+
image: "size-10 overflow-hidden rounded-sm [&_img]:size-full [&_img]:object-cover",
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
defaultVariants: {
|
|
81
|
+
variant: "default",
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
function ItemMedia({
|
|
87
|
+
className,
|
|
88
|
+
variant = "default",
|
|
89
|
+
...props
|
|
90
|
+
}: React.ComponentProps<"div"> & VariantProps<typeof itemMediaVariants>) {
|
|
91
|
+
return (
|
|
92
|
+
<div
|
|
93
|
+
data-slot="item-media"
|
|
94
|
+
data-variant={variant}
|
|
95
|
+
className={cn(itemMediaVariants({ variant, className }))}
|
|
96
|
+
{...props}
|
|
97
|
+
/>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function ItemContent({ className, ...props }: React.ComponentProps<"div">) {
|
|
102
|
+
return (
|
|
103
|
+
<div
|
|
104
|
+
data-slot="item-content"
|
|
105
|
+
className={cn("flex flex-1 flex-col gap-1 [&+[data-slot=item-content]]:flex-none", className)}
|
|
106
|
+
{...props}
|
|
107
|
+
/>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function ItemTitle({ className, ...props }: React.ComponentProps<"div">) {
|
|
112
|
+
return (
|
|
113
|
+
<div
|
|
114
|
+
data-slot="item-title"
|
|
115
|
+
className={cn("flex w-fit items-center gap-2 text-sm leading-snug font-medium", className)}
|
|
116
|
+
{...props}
|
|
117
|
+
/>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function ItemDescription({ className, ...props }: React.ComponentProps<"p">) {
|
|
122
|
+
return (
|
|
123
|
+
<p
|
|
124
|
+
data-slot="item-description"
|
|
125
|
+
className={cn(
|
|
126
|
+
"line-clamp-2 text-sm leading-normal font-normal text-balance text-muted-foreground",
|
|
127
|
+
"[&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
|
|
128
|
+
className,
|
|
129
|
+
)}
|
|
130
|
+
{...props}
|
|
131
|
+
/>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function ItemActions({ className, ...props }: React.ComponentProps<"div">) {
|
|
136
|
+
return (
|
|
137
|
+
<div data-slot="item-actions" className={cn("flex items-center gap-2", className)} {...props} />
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function ItemHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
142
|
+
return (
|
|
143
|
+
<div
|
|
144
|
+
data-slot="item-header"
|
|
145
|
+
className={cn("flex basis-full items-center justify-between gap-2", className)}
|
|
146
|
+
{...props}
|
|
147
|
+
/>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function ItemFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|
152
|
+
return (
|
|
153
|
+
<div
|
|
154
|
+
data-slot="item-footer"
|
|
155
|
+
className={cn("flex basis-full items-center justify-between gap-2", className)}
|
|
156
|
+
{...props}
|
|
157
|
+
/>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export {
|
|
162
|
+
Item,
|
|
163
|
+
ItemMedia,
|
|
164
|
+
ItemContent,
|
|
165
|
+
ItemActions,
|
|
166
|
+
ItemGroup,
|
|
167
|
+
ItemSeparator,
|
|
168
|
+
ItemTitle,
|
|
169
|
+
ItemDescription,
|
|
170
|
+
ItemHeader,
|
|
171
|
+
ItemFooter,
|
|
172
|
+
};
|
package/src/kbd.tsx
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { cn } from "./cn";
|
|
2
|
+
|
|
3
|
+
function Kbd({ className, ...props }: React.ComponentProps<"kbd">) {
|
|
4
|
+
return (
|
|
5
|
+
<kbd
|
|
6
|
+
data-slot="kbd"
|
|
7
|
+
className={cn(
|
|
8
|
+
"pointer-events-none inline-flex h-5 w-fit min-w-5 items-center justify-center gap-1 rounded-sm bg-muted px-1 font-sans text-xs font-medium text-muted-foreground select-none",
|
|
9
|
+
"[&_svg:not([class*='size-'])]:size-3",
|
|
10
|
+
"[[data-slot=tooltip-content]_&]:bg-background/20 [[data-slot=tooltip-content]_&]:text-background dark:[[data-slot=tooltip-content]_&]:bg-background/10",
|
|
11
|
+
className,
|
|
12
|
+
)}
|
|
13
|
+
{...props}
|
|
14
|
+
/>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function KbdGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
19
|
+
return (
|
|
20
|
+
<kbd
|
|
21
|
+
data-slot="kbd-group"
|
|
22
|
+
className={cn("inline-flex items-center gap-1", className)}
|
|
23
|
+
{...props}
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { Kbd, KbdGroup };
|
package/src/label.tsx
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Label as LabelPrimitive } from "radix-ui";
|
|
3
|
+
|
|
4
|
+
import { cn } from "./cn";
|
|
5
|
+
|
|
6
|
+
function Label({ className, ...props }: React.ComponentProps<typeof LabelPrimitive.Root>) {
|
|
7
|
+
return (
|
|
8
|
+
<LabelPrimitive.Root
|
|
9
|
+
data-slot="label"
|
|
10
|
+
className={cn(
|
|
11
|
+
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
|
|
12
|
+
className,
|
|
13
|
+
)}
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export { Label };
|
package/src/marker.tsx
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
|
+
import { Slot } from "radix-ui";
|
|
4
|
+
|
|
5
|
+
import { cn } from "./cn";
|
|
6
|
+
|
|
7
|
+
const markerVariants = cva(
|
|
8
|
+
"group/marker relative flex min-h-4 w-full items-center gap-2 text-left text-sm text-muted-foreground [&_svg:not([class*='size-'])]:size-4 [a]:underline [a]:underline-offset-3 [a]:hover:text-foreground",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default: "",
|
|
13
|
+
separator:
|
|
14
|
+
"before:mr-1 before:h-px before:min-w-0 before:flex-1 before:bg-border after:ml-1 after:h-px after:min-w-0 after:flex-1 after:bg-border",
|
|
15
|
+
border: "border-b border-border pb-2",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
function Marker({
|
|
22
|
+
className,
|
|
23
|
+
variant = "default",
|
|
24
|
+
asChild = false,
|
|
25
|
+
...props
|
|
26
|
+
}: React.ComponentProps<"div"> &
|
|
27
|
+
VariantProps<typeof markerVariants> & {
|
|
28
|
+
asChild?: boolean;
|
|
29
|
+
}) {
|
|
30
|
+
const Comp = asChild ? Slot.Root : "div";
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<Comp
|
|
34
|
+
data-slot="marker"
|
|
35
|
+
data-variant={variant}
|
|
36
|
+
className={cn(markerVariants({ variant, className }))}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function MarkerIcon({ className, ...props }: React.ComponentProps<"span">) {
|
|
43
|
+
return (
|
|
44
|
+
<span
|
|
45
|
+
data-slot="marker-icon"
|
|
46
|
+
aria-hidden="true"
|
|
47
|
+
className={cn("size-4 shrink-0 [&_svg:not([class*='size-'])]:size-4", className)}
|
|
48
|
+
{...props}
|
|
49
|
+
/>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function MarkerContent({ className, ...props }: React.ComponentProps<"span">) {
|
|
54
|
+
return (
|
|
55
|
+
<span
|
|
56
|
+
data-slot="marker-content"
|
|
57
|
+
className={cn(
|
|
58
|
+
"min-w-0 wrap-break-word group-data-[variant=separator]/marker:flex-none group-data-[variant=separator]/marker:text-center *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
|
|
59
|
+
className,
|
|
60
|
+
)}
|
|
61
|
+
{...props}
|
|
62
|
+
/>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export { Marker, MarkerIcon, MarkerContent, markerVariants };
|