@hexclave/ui 1.0.3 → 1.0.6

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 (84) hide show
  1. package/dist/components/copy-button.d.ts +1 -1
  2. package/dist/components/simple-tooltip.js +2 -2
  3. package/dist/components/simple-tooltip.js.map +1 -1
  4. package/dist/components/ui/button.d.ts +2 -2
  5. package/dist/components/ui/form.d.ts +1 -1
  6. package/dist/components/ui/form.d.ts.map +1 -1
  7. package/dist/components/ui/resizable.d.ts +1 -1
  8. package/dist/components/ui/resizable.d.ts.map +1 -1
  9. package/dist/components/ui/typography.d.ts +1 -1
  10. package/dist/esm/components/copy-button.d.ts +1 -1
  11. package/dist/esm/components/simple-tooltip.js +3 -3
  12. package/dist/esm/components/simple-tooltip.js.map +1 -1
  13. package/dist/esm/components/ui/button.d.ts +2 -2
  14. package/dist/esm/components/ui/form.d.ts +1 -1
  15. package/dist/esm/components/ui/form.d.ts.map +1 -1
  16. package/dist/esm/components/ui/resizable.d.ts +1 -1
  17. package/dist/esm/components/ui/resizable.d.ts.map +1 -1
  18. package/dist/esm/components/ui/typography.d.ts +1 -1
  19. package/package.json +3 -2
  20. package/src/components/action-dialog.tsx +135 -0
  21. package/src/components/brand-icons.tsx +276 -0
  22. package/src/components/browser-frame/LICENSE +3 -0
  23. package/src/components/browser-frame/index.tsx +51 -0
  24. package/src/components/copy-button.tsx +36 -0
  25. package/src/components/copy-field.tsx +52 -0
  26. package/src/components/data-table/cells.tsx +133 -0
  27. package/src/components/data-table/column-header.tsx +52 -0
  28. package/src/components/data-table/data-table.tsx +318 -0
  29. package/src/components/data-table/faceted-filter.tsx +138 -0
  30. package/src/components/data-table/index.tsx +9 -0
  31. package/src/components/data-table/pagination.tsx +76 -0
  32. package/src/components/data-table/toolbar-items.tsx +13 -0
  33. package/src/components/data-table/toolbar.tsx +100 -0
  34. package/src/components/data-table/utils.tsx +7 -0
  35. package/src/components/data-table/view-options.tsx +64 -0
  36. package/src/components/simple-tooltip.tsx +48 -0
  37. package/src/components/ui/accordion.tsx +58 -0
  38. package/src/components/ui/alert.tsx +60 -0
  39. package/src/components/ui/aspect-ratio.tsx +7 -0
  40. package/src/components/ui/avatar.tsx +51 -0
  41. package/src/components/ui/badge.tsx +36 -0
  42. package/src/components/ui/breadcrumb.tsx +116 -0
  43. package/src/components/ui/button.tsx +95 -0
  44. package/src/components/ui/calendar.tsx +77 -0
  45. package/src/components/ui/card.tsx +88 -0
  46. package/src/components/ui/checkbox.tsx +31 -0
  47. package/src/components/ui/collapsible.tsx +11 -0
  48. package/src/components/ui/command.tsx +159 -0
  49. package/src/components/ui/context-menu.tsx +205 -0
  50. package/src/components/ui/dialog.tsx +135 -0
  51. package/src/components/ui/dropdown-menu.tsx +245 -0
  52. package/src/components/ui/form.tsx +173 -0
  53. package/src/components/ui/hover-card.tsx +30 -0
  54. package/src/components/ui/inline-code.tsx +40 -0
  55. package/src/components/ui/input-otp.tsx +73 -0
  56. package/src/components/ui/input.tsx +68 -0
  57. package/src/components/ui/label.tsx +40 -0
  58. package/src/components/ui/menubar.tsx +241 -0
  59. package/src/components/ui/navigation-menu.tsx +131 -0
  60. package/src/components/ui/password-input.tsx +50 -0
  61. package/src/components/ui/popover.tsx +34 -0
  62. package/src/components/ui/progress.tsx +29 -0
  63. package/src/components/ui/radio-group.tsx +45 -0
  64. package/src/components/ui/resizable.tsx +45 -0
  65. package/src/components/ui/scroll-area.tsx +49 -0
  66. package/src/components/ui/select.tsx +162 -0
  67. package/src/components/ui/separator.tsx +32 -0
  68. package/src/components/ui/sheet.tsx +139 -0
  69. package/src/components/ui/skeleton.tsx +23 -0
  70. package/src/components/ui/slider.tsx +29 -0
  71. package/src/components/ui/spinner.tsx +18 -0
  72. package/src/components/ui/switch.tsx +75 -0
  73. package/src/components/ui/table.tsx +117 -0
  74. package/src/components/ui/tabs.tsx +56 -0
  75. package/src/components/ui/textarea.tsx +24 -0
  76. package/src/components/ui/toast.tsx +135 -0
  77. package/src/components/ui/toaster.tsx +35 -0
  78. package/src/components/ui/toggle-group.tsx +62 -0
  79. package/src/components/ui/toggle.tsx +46 -0
  80. package/src/components/ui/tooltip.tsx +40 -0
  81. package/src/components/ui/typography.tsx +47 -0
  82. package/src/components/ui/use-toast.tsx +195 -0
  83. package/src/index.ts +54 -0
  84. package/src/lib/utils.tsx +6 -0
@@ -0,0 +1,245 @@
1
+ "use client";
2
+
3
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
4
+ import { CheckIcon, ChevronRightIcon, DotFilledIcon } from "@radix-ui/react-icons";
5
+ import { forwardRefIfNeeded } from "@hexclave/shared/dist/utils/react";
6
+ import React from "react";
7
+
8
+ import { useAsyncCallback } from "@hexclave/shared/dist/hooks/use-async-callback";
9
+ import { throwErr } from "@hexclave/shared/dist/utils/errors";
10
+ import { runAsynchronouslyWithAlert } from "@hexclave/shared/dist/utils/promises";
11
+ import { cn } from "../../lib/utils";
12
+ import { Spinner } from "./spinner";
13
+
14
+ const DropdownMenuContext = React.createContext<{
15
+ open: boolean,
16
+ setOpen: (open: boolean) => void,
17
+ } | undefined>(undefined);
18
+
19
+ const DropdownMenu = forwardRefIfNeeded<
20
+ never,
21
+ DropdownMenuPrimitive.DropdownMenuProps
22
+ >(({ ...props }, ref) => {
23
+ const [open, setOpen] = React.useState(!!props.open);
24
+
25
+ return (
26
+ <DropdownMenuContext.Provider value={{
27
+ open,
28
+ setOpen: (o) => {
29
+ props.onOpenChange?.(o);
30
+ setOpen(o);
31
+ }
32
+ }}>
33
+ <DropdownMenuPrimitive.Root
34
+ {...props}
35
+ open={props.open ?? open}
36
+ onOpenChange={o => {
37
+ props.onOpenChange?.(o);
38
+ setOpen(o);
39
+ }}
40
+ />
41
+ </DropdownMenuContext.Provider>
42
+ );
43
+ });
44
+ DropdownMenu.displayName = DropdownMenuPrimitive.Root.displayName;
45
+
46
+ const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
47
+
48
+ const DropdownMenuGroup = DropdownMenuPrimitive.Group;
49
+
50
+ const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
51
+
52
+ const DropdownMenuSub = DropdownMenuPrimitive.Sub;
53
+
54
+ const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
55
+
56
+ const DropdownMenuSubTrigger = forwardRefIfNeeded<
57
+ React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
58
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
59
+ inset?: boolean,
60
+ }
61
+ >(({ className, inset, children, ...props }, ref) => (
62
+ <DropdownMenuPrimitive.SubTrigger
63
+ ref={ref}
64
+ className={cn(
65
+ "stack-scope flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",
66
+ inset && "pl-8",
67
+ className
68
+ )}
69
+ {...props}
70
+ >
71
+ {children}
72
+ <ChevronRightIcon className="ml-auto h-4 w-4" />
73
+ </DropdownMenuPrimitive.SubTrigger>
74
+ ));
75
+ DropdownMenuSubTrigger.displayName =
76
+ DropdownMenuPrimitive.SubTrigger.displayName;
77
+
78
+ const DropdownMenuSubContent = forwardRefIfNeeded<
79
+ React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
80
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
81
+ >(({ className, ...props }, ref) => (
82
+ <DropdownMenuPrimitive.SubContent
83
+ ref={ref}
84
+ className={cn(
85
+ "stack-scope z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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",
86
+ className
87
+ )}
88
+ {...props}
89
+ />
90
+ ));
91
+ DropdownMenuSubContent.displayName =
92
+ DropdownMenuPrimitive.SubContent.displayName;
93
+
94
+ const DropdownMenuContent = forwardRefIfNeeded<
95
+ React.ElementRef<typeof DropdownMenuPrimitive.Content>,
96
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
97
+ >(({ className, sideOffset = 4, ...props }, ref) => (
98
+ <DropdownMenuPrimitive.Portal>
99
+ <DropdownMenuPrimitive.Content
100
+ ref={ref}
101
+ sideOffset={sideOffset}
102
+ className={cn(
103
+ "stack-scope z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
104
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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",
105
+ className
106
+ )}
107
+ {...props}
108
+ />
109
+ </DropdownMenuPrimitive.Portal>
110
+ ));
111
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
112
+
113
+ const DropdownMenuItem = forwardRefIfNeeded<
114
+ React.ElementRef<typeof DropdownMenuPrimitive.Item>,
115
+ Omit<React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item>, "onClick"> & {
116
+ inset?: boolean,
117
+ onClick?: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void | Promise<void>,
118
+ }
119
+ >(({ className, inset, ...props }, ref) => {
120
+ const { setOpen } = React.useContext(DropdownMenuContext) ?? throwErr("No DropdownMenuContext found");
121
+ const [handleClick, isLoading] = useAsyncCallback(async (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
122
+ await props.onClick?.(e);
123
+ setOpen(false);
124
+ }, [props.onClick]);
125
+
126
+ return <DropdownMenuPrimitive.Item
127
+ ref={ref}
128
+ className={cn(
129
+ "stack-scope relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
130
+ inset && "pl-8",
131
+ className
132
+ )}
133
+ {...props}
134
+ disabled={isLoading || props.disabled}
135
+ onClick={props.onClick ? (e) => {
136
+ e.preventDefault();
137
+ e.stopPropagation();
138
+ runAsynchronouslyWithAlert(handleClick(e));
139
+ } : undefined}
140
+ >
141
+ <div style={{ visibility: isLoading ? "visible" : "hidden", position: "absolute", inset: 0, display: "flex", justifyContent: "center", alignItems: "center" }}>
142
+ <Spinner />
143
+ </div>
144
+ <div style={{ visibility: isLoading ? "hidden" : "visible" }}>
145
+ {props.children}
146
+ </div>
147
+ </DropdownMenuPrimitive.Item>;
148
+ });
149
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
150
+
151
+ const DropdownMenuCheckboxItem = forwardRefIfNeeded<
152
+ React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
153
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
154
+ >(({ className, children, checked, ...props }, ref) => (
155
+ <DropdownMenuPrimitive.CheckboxItem
156
+ ref={ref}
157
+ className={cn(
158
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
159
+ className
160
+ )}
161
+ checked={checked}
162
+ {...props}
163
+ >
164
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
165
+ <DropdownMenuPrimitive.ItemIndicator>
166
+ <CheckIcon className="h-4 w-4" />
167
+ </DropdownMenuPrimitive.ItemIndicator>
168
+ </span>
169
+ {children}
170
+ </DropdownMenuPrimitive.CheckboxItem>
171
+ ));
172
+ DropdownMenuCheckboxItem.displayName =
173
+ DropdownMenuPrimitive.CheckboxItem.displayName;
174
+
175
+ const DropdownMenuRadioItem = forwardRefIfNeeded<
176
+ React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
177
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
178
+ >(({ className, children, ...props }, ref) => (
179
+ <DropdownMenuPrimitive.RadioItem
180
+ ref={ref}
181
+ className={cn(
182
+ "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
183
+ className
184
+ )}
185
+ {...props}
186
+ >
187
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
188
+ <DropdownMenuPrimitive.ItemIndicator>
189
+ <DotFilledIcon className="h-4 w-4 fill-current" />
190
+ </DropdownMenuPrimitive.ItemIndicator>
191
+ </span>
192
+ {children}
193
+ </DropdownMenuPrimitive.RadioItem>
194
+ ));
195
+ DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
196
+
197
+ const DropdownMenuLabel = forwardRefIfNeeded<
198
+ React.ElementRef<typeof DropdownMenuPrimitive.Label>,
199
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
200
+ inset?: boolean,
201
+ }
202
+ >(({ className, inset, ...props }, ref) => (
203
+ <DropdownMenuPrimitive.Label
204
+ ref={ref}
205
+ className={cn(
206
+ "px-2 py-1.5 text-sm font-semibold",
207
+ inset && "pl-8",
208
+ className
209
+ )}
210
+ {...props}
211
+ />
212
+ ));
213
+ DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
214
+
215
+ const DropdownMenuSeparator = forwardRefIfNeeded<
216
+ React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
217
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
218
+ >(({ className, ...props }, ref) => (
219
+ <DropdownMenuPrimitive.Separator
220
+ ref={ref}
221
+ className={cn("-mx-1 my-1 h-px bg-muted", className)}
222
+ {...props}
223
+ />
224
+ ));
225
+ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
226
+
227
+ const DropdownMenuShortcut = ({
228
+ className,
229
+ ...props
230
+ }: React.HTMLAttributes<HTMLSpanElement>) => {
231
+ return (
232
+ <span
233
+ className={cn("stack-scope ml-auto text-xs tracking-widest opacity-60", className)}
234
+ {...props}
235
+ />
236
+ );
237
+ };
238
+ DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
239
+
240
+ export {
241
+ DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator,
242
+ DropdownMenuShortcut, DropdownMenuSub,
243
+ DropdownMenuSubContent,
244
+ DropdownMenuSubTrigger, DropdownMenuTrigger
245
+ };
@@ -0,0 +1,173 @@
1
+ 'use client';
2
+
3
+ import * as LabelPrimitive from "@radix-ui/react-label";
4
+ import { Slot } from "@radix-ui/react-slot";
5
+ import React from "react";
6
+ import { forwardRefIfNeeded } from "@hexclave/shared/dist/utils/react";
7
+ import {
8
+ Controller,
9
+ ControllerProps,
10
+ FieldPath,
11
+ FieldValues,
12
+ FormProvider,
13
+ useFormContext,
14
+ } from "react-hook-form";
15
+
16
+ import { HexclaveAssertionError } from "@hexclave/shared/dist/utils/errors";
17
+ import { cn } from "../../lib/utils";
18
+ import { SpanLabel } from "./label";
19
+
20
+ const Form = FormProvider;
21
+
22
+ type FormFieldContextValue<
23
+ TFieldValues extends FieldValues = FieldValues,
24
+ TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
25
+ > = {
26
+ name: TName,
27
+ }
28
+
29
+ const FormFieldContext = React.createContext<FormFieldContextValue | null>(null);
30
+
31
+ const FormField = <
32
+ TFieldValues extends FieldValues = FieldValues,
33
+ TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
34
+ >({
35
+ ...props
36
+ }: ControllerProps<TFieldValues, TName>) => {
37
+ return (
38
+ <FormFieldContext.Provider value={{ name: props.name }}>
39
+ <Controller {...props} />
40
+ </FormFieldContext.Provider>
41
+ );
42
+ };
43
+
44
+ const useFormField = () => {
45
+ const fieldContext = React.useContext(FormFieldContext);
46
+ const itemContext = React.useContext(FormItemContext);
47
+ const { getFieldState, formState } = useFormContext();
48
+
49
+ if (!fieldContext) {
50
+ throw new HexclaveAssertionError("useFormField should be used within <FormField>");
51
+ }
52
+
53
+ const fieldState = getFieldState(fieldContext.name, formState);
54
+
55
+ const { id } = itemContext;
56
+ const formItemId = React.useId();
57
+
58
+ return {
59
+ id,
60
+ name: fieldContext.name,
61
+ formItemId: `${formItemId}-form-item`,
62
+ formDescriptionId: `${id}-form-item-description`,
63
+ formMessageId: `${id}-form-item-message`,
64
+ ...fieldState,
65
+ };
66
+ };
67
+
68
+ type FormItemContextValue = {
69
+ id: string,
70
+ }
71
+
72
+ const FormItemContext = React.createContext<FormItemContextValue>(
73
+ {} as FormItemContextValue
74
+ );
75
+
76
+ const FormItem = forwardRefIfNeeded<
77
+ HTMLDivElement,
78
+ React.HTMLAttributes<HTMLDivElement>
79
+ >(({ className, ...props }, ref) => {
80
+ const id = React.useId();
81
+
82
+ return (
83
+ <FormItemContext.Provider value={{ id }}>
84
+ <div ref={ref} className={cn("space-y-2", className)} {...props} />
85
+ </FormItemContext.Provider>
86
+ );
87
+ });
88
+ FormItem.displayName = "FormItem";
89
+
90
+ const FormLabel = forwardRefIfNeeded<
91
+ React.ElementRef<typeof LabelPrimitive.Root>,
92
+ React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
93
+ >(({ className, ...props }, ref) => {
94
+ const { error } = useFormField();
95
+
96
+ return (
97
+ <SpanLabel
98
+ ref={ref}
99
+ className={cn(error && "text-destructive", className)}
100
+ {...props}
101
+ />
102
+ );
103
+ });
104
+ FormLabel.displayName = "FormLabel";
105
+
106
+ const FormControl = forwardRefIfNeeded<
107
+ React.ElementRef<typeof Slot>,
108
+ React.ComponentPropsWithoutRef<typeof Slot>
109
+ >(({ ...props }, ref) => {
110
+ const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
111
+
112
+ return (
113
+ <Slot
114
+ ref={ref}
115
+ id={formItemId}
116
+ aria-describedby={
117
+ !error
118
+ ? `${formDescriptionId}`
119
+ : `${formDescriptionId} ${formMessageId}`
120
+ }
121
+ aria-invalid={!!error}
122
+ {...props}
123
+ />
124
+ );
125
+ });
126
+ FormControl.displayName = "FormControl";
127
+
128
+ const FormDescription = forwardRefIfNeeded<
129
+ HTMLParagraphElement,
130
+ React.HTMLAttributes<HTMLParagraphElement>
131
+ >(({ className, ...props }, ref) => {
132
+ const { formDescriptionId } = useFormField();
133
+
134
+ return (
135
+ <p
136
+ ref={ref}
137
+ id={formDescriptionId}
138
+ className={cn("text-[0.8rem] text-muted-foreground", className)}
139
+ {...props}
140
+ />
141
+ );
142
+ });
143
+ FormDescription.displayName = "FormDescription";
144
+
145
+ const FormMessage = forwardRefIfNeeded<
146
+ HTMLParagraphElement,
147
+ React.HTMLAttributes<HTMLParagraphElement>
148
+ >(({ className, children, ...props }, ref) => {
149
+ const { error, formMessageId } = useFormField();
150
+ const body = error ? String(error.message) : children;
151
+
152
+ if (!body) {
153
+ return null;
154
+ }
155
+
156
+ return (
157
+ <p
158
+ ref={ref}
159
+ id={formMessageId}
160
+ className={cn("text-[0.8rem] font-medium text-destructive", className)}
161
+ {...props}
162
+ >
163
+ {body}
164
+ </p>
165
+ );
166
+ });
167
+ FormMessage.displayName = "FormMessage";
168
+
169
+ export {
170
+ Form, FormControl,
171
+ FormDescription, FormField, FormItem,
172
+ FormLabel, FormMessage, useFormField
173
+ };
@@ -0,0 +1,30 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import { forwardRefIfNeeded } from "@hexclave/shared/dist/utils/react";
5
+ import * as HoverCardPrimitive from "@radix-ui/react-hover-card";
6
+
7
+ import { cn } from "../../lib/utils";
8
+
9
+ const HoverCard = HoverCardPrimitive.Root;
10
+
11
+ const HoverCardTrigger = HoverCardPrimitive.Trigger;
12
+
13
+ const HoverCardContent = forwardRefIfNeeded<
14
+ React.ElementRef<typeof HoverCardPrimitive.Content>,
15
+ React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>
16
+ >(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
17
+ <HoverCardPrimitive.Content
18
+ ref={ref}
19
+ align={align}
20
+ sideOffset={sideOffset}
21
+ className={cn(
22
+ "stack-scope z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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",
23
+ className
24
+ )}
25
+ {...props}
26
+ />
27
+ ));
28
+ HoverCardContent.displayName = HoverCardPrimitive.Content.displayName;
29
+
30
+ export { HoverCard, HoverCardTrigger, HoverCardContent };
@@ -0,0 +1,40 @@
1
+ "use client";
2
+
3
+ import { cn } from "../../lib/utils";
4
+ import React from "react";
5
+ import { forwardRefIfNeeded } from "@hexclave/shared/dist/utils/react";
6
+ import { hasClickableParent } from "@hexclave/shared/dist/utils/dom";
7
+ import { getNodeText } from "@hexclave/shared/dist/utils/react";
8
+ import { runAsynchronously } from "@hexclave/shared/dist/utils/promises";
9
+ import { useToast } from "./use-toast";
10
+
11
+ const InlineCode = forwardRefIfNeeded<
12
+ React.ElementRef<"code">,
13
+ React.ComponentPropsWithoutRef<"code">
14
+ >((props, ref) => {
15
+ const { toast } = useToast();
16
+
17
+ return <code
18
+ ref={ref}
19
+ {...props}
20
+ className={cn("stack-scope bg-zinc-200 text-zinc-700 dark:bg-zinc-800 dark:text-zinc-300 rounded-sm px-1 cursor-pointer", props.className)}
21
+ onClick={(e: React.MouseEvent<HTMLElement>) => {
22
+ props.onClick?.(e);
23
+ if (!hasClickableParent(e.currentTarget)) {
24
+ e.stopPropagation();
25
+ e.preventDefault();
26
+ runAsynchronously(async () => {
27
+ try {
28
+ await navigator.clipboard.writeText(getNodeText(props.children));
29
+ toast({ description: 'Copied to clipboard!', variant: 'success' });
30
+ } catch (e) {
31
+ toast({ description: 'Failed to copy to clipboard', variant: 'destructive' });
32
+ }
33
+ });
34
+ }
35
+ }}
36
+ />;
37
+ });
38
+ InlineCode.displayName = "Code";
39
+
40
+ export { InlineCode };
@@ -0,0 +1,73 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import { forwardRefIfNeeded } from "@hexclave/shared/dist/utils/react";
5
+ import { DashIcon } from "@radix-ui/react-icons";
6
+ import { OTPInput, OTPInputContext } from "input-otp";
7
+
8
+ import { cn } from "../../lib/utils";
9
+
10
+ const InputOTP: React.FC<React.ComponentPropsWithoutRef<typeof OTPInput>> = forwardRefIfNeeded<
11
+ React.ElementRef<typeof OTPInput>,
12
+ React.ComponentPropsWithoutRef<typeof OTPInput>
13
+ >(({ className, containerClassName, ...props }, ref) => (
14
+ <OTPInput
15
+ ref={ref}
16
+ containerClassName={cn(
17
+ "stack-scope flex items-center gap-2 has-[:disabled]:opacity-50",
18
+ containerClassName
19
+ )}
20
+ className={cn("disabled:cursor-not-allowed", className)}
21
+ {...props}
22
+ />
23
+ ));
24
+ InputOTP.displayName = "InputOTP";
25
+
26
+ const InputOTPGroup = forwardRefIfNeeded<
27
+ React.ElementRef<"div">,
28
+ React.ComponentPropsWithoutRef<"div">
29
+ >(({ className, ...props }, ref) => (
30
+ <div ref={ref} className={cn("flex items-center gap-1", className)} {...props} />
31
+ ));
32
+ InputOTPGroup.displayName = "InputOTPGroup";
33
+
34
+ const InputOTPSlot = forwardRefIfNeeded<
35
+ React.ElementRef<"div">,
36
+ React.ComponentPropsWithoutRef<"div"> & { index: number, size?: 'default' | 'lg' }
37
+ >(({ index, className, size = 'default', ...props }, ref) => {
38
+ const inputOTPContext = React.useContext(OTPInputContext);
39
+ const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index];
40
+
41
+ return (
42
+ <div
43
+ ref={ref}
44
+ className={cn(
45
+ "relative flex h-9 w-9 items-center justify-center border border-input text-sm rounded-md",
46
+ size === 'lg' ? 'h-10 w-10 text-lg font-medium' : '',
47
+ isActive && "z-10 ring-1 ring-ring",
48
+ className
49
+ )}
50
+ {...props}
51
+ >
52
+ {char}
53
+ {hasFakeCaret && (
54
+ <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
55
+ <div className="h-4 w-px animate-caret-blink bg-foreground duration-1000" />
56
+ </div>
57
+ )}
58
+ </div>
59
+ );
60
+ });
61
+ InputOTPSlot.displayName = "InputOTPSlot";
62
+
63
+ const InputOTPSeparator = forwardRefIfNeeded<
64
+ React.ElementRef<"div">,
65
+ React.ComponentPropsWithoutRef<"div">
66
+ >(({ ...props }, ref) => (
67
+ <div ref={ref} role="separator" {...props}>
68
+ <DashIcon />
69
+ </div>
70
+ ));
71
+ InputOTPSeparator.displayName = "InputOTPSeparator";
72
+
73
+ export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };
@@ -0,0 +1,68 @@
1
+ import { forwardRefIfNeeded } from "@hexclave/shared/dist/utils/react";
2
+ import React from "react";
3
+
4
+ import { cn } from "../../lib/utils";
5
+
6
+ export type InputProps = {
7
+ prefixItem?: React.ReactNode,
8
+ } & React.InputHTMLAttributes<HTMLInputElement>
9
+
10
+ export const Input = forwardRefIfNeeded<HTMLInputElement, InputProps>(
11
+ ({ className, type, prefixItem, ...props }, ref) => {
12
+ const baseClasses = "stack-scope flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50";
13
+
14
+ if (prefixItem) {
15
+ return (
16
+ <div className="flex flex-row items-center backdrop-blur-md bg-white/20 dark:bg-black/20 flex-1">
17
+ <div className={'flex self-stretch justify-center items-center text-muted-foreground pl-3 select-none bg-muted/70 pr-3 border-r border-input rounded-l-md'}>
18
+ {prefixItem}
19
+ </div>
20
+ <input
21
+ type={type}
22
+ className={cn(baseClasses, 'rounded-l-none', className)}
23
+ ref={ref}
24
+ {...props}
25
+ />
26
+ </div>
27
+ );
28
+ } else {
29
+ return (
30
+ <div className="flex flex-row items-center backdrop-blur-md bg-white/20 dark:bg-black/20 flex-1">
31
+ <input
32
+ type={type}
33
+ className={cn(baseClasses, className)}
34
+ ref={ref}
35
+ {...props}
36
+ />
37
+ </div>
38
+ );
39
+ }
40
+ }
41
+ );
42
+ Input.displayName = "Input";
43
+
44
+
45
+ export type DelayedInputProps = {
46
+ delay?: number,
47
+ } & InputProps
48
+
49
+ export const DelayedInput = forwardRefIfNeeded<HTMLInputElement, DelayedInputProps>(
50
+ ({ delay = 500, defaultValue, ...props }, ref) => {
51
+ const [value, setValue] = React.useState(defaultValue ?? "");
52
+
53
+ const timeout = React.useRef<ReturnType<typeof setTimeout> | null>(null);
54
+
55
+ const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
56
+ setValue(e.target.value);
57
+ if (timeout.current) {
58
+ clearTimeout(timeout.current);
59
+ }
60
+ timeout.current = setTimeout(() => {
61
+ props.onChange?.(e);
62
+ }, delay);
63
+ };
64
+
65
+ return <Input ref={ref} {...props} value={value} onChange={onChange} />;
66
+ }
67
+ );
68
+ DelayedInput.displayName = "DelayedInput";
@@ -0,0 +1,40 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import { forwardRefIfNeeded } from "@hexclave/shared/dist/utils/react";
5
+ import * as LabelPrimitive from "@radix-ui/react-label";
6
+ import { cva, type VariantProps } from "class-variance-authority";
7
+
8
+ import { cn } from "../../lib/utils";
9
+
10
+ const labelVariants = cva(
11
+ "stack-scope text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 text-gray-600 dark:text-gray-400",
12
+ );
13
+
14
+ const Label = forwardRefIfNeeded<
15
+ React.ElementRef<typeof LabelPrimitive.Root>,
16
+ React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
17
+ VariantProps<typeof labelVariants>
18
+ >(({ className, ...props }, ref) => (
19
+ <label
20
+ ref={ref}
21
+ className={cn(labelVariants(), className)}
22
+ {...props}
23
+ />
24
+ ));
25
+ Label.displayName = LabelPrimitive.Root.displayName;
26
+
27
+ const SpanLabel = forwardRefIfNeeded<
28
+ React.ElementRef<typeof LabelPrimitive.Root>,
29
+ React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
30
+ VariantProps<typeof labelVariants>
31
+ >(({ className, ...props }, ref) => (
32
+ <span
33
+ ref={ref}
34
+ className={cn(labelVariants(), className)}
35
+ {...props}
36
+ />
37
+ ));
38
+ SpanLabel.displayName = LabelPrimitive.Root.displayName;
39
+
40
+ export { Label, SpanLabel };