xiod-ui 1.0.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.
Files changed (224) hide show
  1. package/LICENSE +73 -0
  2. package/README.md +167 -0
  3. package/dist/components/accordion.d.ts +9 -0
  4. package/dist/components/accordion.js +46 -0
  5. package/dist/components/agent-steps.d.ts +47 -0
  6. package/dist/components/agent-steps.js +223 -0
  7. package/dist/components/alert-dialog.d.ts +21 -0
  8. package/dist/components/alert-dialog.js +74 -0
  9. package/dist/components/alert.d.ts +12 -0
  10. package/dist/components/alert.js +45 -0
  11. package/dist/components/aspect-ratio.d.ts +9 -0
  12. package/dist/components/aspect-ratio.js +22 -0
  13. package/dist/components/autocomplete.d.ts +35 -0
  14. package/dist/components/autocomplete.js +160 -0
  15. package/dist/components/avatar.d.ts +17 -0
  16. package/dist/components/avatar.js +65 -0
  17. package/dist/components/badge.d.ts +15 -0
  18. package/dist/components/badge.js +46 -0
  19. package/dist/components/breadcrumb.d.ts +12 -0
  20. package/dist/components/breadcrumb.js +75 -0
  21. package/dist/components/button-group.d.ts +14 -0
  22. package/dist/components/button-group.js +45 -0
  23. package/dist/components/button-split.d.ts +19 -0
  24. package/dist/components/button-split.js +73 -0
  25. package/dist/components/button.d.ts +15 -0
  26. package/dist/components/button.js +54 -0
  27. package/dist/components/calendar.d.ts +63 -0
  28. package/dist/components/calendar.js +425 -0
  29. package/dist/components/card.d.ts +17 -0
  30. package/dist/components/card.js +139 -0
  31. package/dist/components/carousel.d.ts +59 -0
  32. package/dist/components/carousel.js +503 -0
  33. package/dist/components/checkbox.d.ts +16 -0
  34. package/dist/components/checkbox.js +86 -0
  35. package/dist/components/circular-progress.d.ts +28 -0
  36. package/dist/components/circular-progress.js +127 -0
  37. package/dist/components/collapsible.d.ts +8 -0
  38. package/dist/components/collapsible.js +27 -0
  39. package/dist/components/color-picker.d.ts +159 -0
  40. package/dist/components/color-picker.js +1589 -0
  41. package/dist/components/combobox.d.ts +46 -0
  42. package/dist/components/combobox.js +237 -0
  43. package/dist/components/command.d.ts +22 -0
  44. package/dist/components/command.js +129 -0
  45. package/dist/components/context-menu.d.ts +38 -0
  46. package/dist/components/context-menu.js +164 -0
  47. package/dist/components/copy-to-clipboard.d.ts +32 -0
  48. package/dist/components/copy-to-clipboard.js +83 -0
  49. package/dist/components/corner-badge.d.ts +22 -0
  50. package/dist/components/corner-badge.js +84 -0
  51. package/dist/components/dashboard-grid.d.ts +83 -0
  52. package/dist/components/dashboard-grid.js +486 -0
  53. package/dist/components/date-picker.d.ts +29 -0
  54. package/dist/components/date-picker.js +261 -0
  55. package/dist/components/dialog.d.ts +26 -0
  56. package/dist/components/dialog.js +97 -0
  57. package/dist/components/dot-matrix.d.ts +32 -0
  58. package/dist/components/dot-matrix.js +707 -0
  59. package/dist/components/draggable.d.ts +42 -0
  60. package/dist/components/draggable.js +346 -0
  61. package/dist/components/drawer.d.ts +66 -0
  62. package/dist/components/drawer.js +304 -0
  63. package/dist/components/empty.d.ts +14 -0
  64. package/dist/components/empty.js +75 -0
  65. package/dist/components/field.d.ts +12 -0
  66. package/dist/components/field.js +44 -0
  67. package/dist/components/fieldset.d.ts +7 -0
  68. package/dist/components/fieldset.js +21 -0
  69. package/dist/components/file-upload.d.ts +61 -0
  70. package/dist/components/file-upload.js +482 -0
  71. package/dist/components/form.d.ts +6 -0
  72. package/dist/components/form.js +14 -0
  73. package/dist/components/frame.d.ts +10 -0
  74. package/dist/components/frame.js +47 -0
  75. package/dist/components/gauge.d.ts +27 -0
  76. package/dist/components/gauge.js +74 -0
  77. package/dist/components/grid.d.ts +26 -0
  78. package/dist/components/grid.js +204 -0
  79. package/dist/components/group.d.ts +19 -0
  80. package/dist/components/group.js +45 -0
  81. package/dist/components/input-group.d.ts +15 -0
  82. package/dist/components/input-group.js +61 -0
  83. package/dist/components/input-otp.d.ts +24 -0
  84. package/dist/components/input-otp.js +50 -0
  85. package/dist/components/input-payment.d.ts +131 -0
  86. package/dist/components/input-payment.js +1140 -0
  87. package/dist/components/input-phone.d.ts +70 -0
  88. package/dist/components/input-phone.js +657 -0
  89. package/dist/components/input-sensitive.d.ts +12 -0
  90. package/dist/components/input-sensitive.js +169 -0
  91. package/dist/components/input.d.ts +13 -0
  92. package/dist/components/input.js +26 -0
  93. package/dist/components/kbd.d.ts +6 -0
  94. package/dist/components/kbd.js +19 -0
  95. package/dist/components/kinetic-click.d.ts +48 -0
  96. package/dist/components/kinetic-click.js +1184 -0
  97. package/dist/components/label.d.ts +6 -0
  98. package/dist/components/label.js +18 -0
  99. package/dist/components/list-box.d.ts +20 -0
  100. package/dist/components/list-box.js +148 -0
  101. package/dist/components/loader.d.ts +13 -0
  102. package/dist/components/loader.js +430 -0
  103. package/dist/components/marker.d.ts +15 -0
  104. package/dist/components/marker.js +59 -0
  105. package/dist/components/menu.d.ts +42 -0
  106. package/dist/components/menu.js +186 -0
  107. package/dist/components/menubar.d.ts +40 -0
  108. package/dist/components/menubar.js +107 -0
  109. package/dist/components/message.d.ts +33 -0
  110. package/dist/components/message.js +112 -0
  111. package/dist/components/meter.d.ts +10 -0
  112. package/dist/components/meter.js +42 -0
  113. package/dist/components/morphic-toast.d.ts +61 -0
  114. package/dist/components/morphic-toast.js +916 -0
  115. package/dist/components/navigation-menu.d.ts +26 -0
  116. package/dist/components/navigation-menu.js +116 -0
  117. package/dist/components/number-field.d.ts +15 -0
  118. package/dist/components/number-field.js +86 -0
  119. package/dist/components/option-picker.d.ts +18 -0
  120. package/dist/components/option-picker.js +89 -0
  121. package/dist/components/orb.d.ts +38 -0
  122. package/dist/components/orb.js +1413 -0
  123. package/dist/components/pagination.d.ts +25 -0
  124. package/dist/components/pagination.js +147 -0
  125. package/dist/components/popover.d.ts +22 -0
  126. package/dist/components/popover.js +79 -0
  127. package/dist/components/preview-card.d.ts +16 -0
  128. package/dist/components/preview-card.js +60 -0
  129. package/dist/components/progress.d.ts +21 -0
  130. package/dist/components/progress.js +139 -0
  131. package/dist/components/radio.d.ts +16 -0
  132. package/dist/components/radio.js +68 -0
  133. package/dist/components/resizable.d.ts +58 -0
  134. package/dist/components/resizable.js +964 -0
  135. package/dist/components/ruler-picker.d.ts +27 -0
  136. package/dist/components/ruler-picker.js +253 -0
  137. package/dist/components/scroll-area.d.ts +13 -0
  138. package/dist/components/scroll-area.js +34 -0
  139. package/dist/components/scroll-bar.d.ts +13 -0
  140. package/dist/components/scroll-bar.js +47 -0
  141. package/dist/components/select.d.ts +29 -0
  142. package/dist/components/select.js +140 -0
  143. package/dist/components/separator.d.ts +6 -0
  144. package/dist/components/separator.js +15 -0
  145. package/dist/components/sidebar.d.ts +65 -0
  146. package/dist/components/sidebar.js +408 -0
  147. package/dist/components/skeleton.d.ts +5 -0
  148. package/dist/components/skeleton.js +12 -0
  149. package/dist/components/slider.d.ts +12 -0
  150. package/dist/components/slider.js +96 -0
  151. package/dist/components/sortable.d.ts +44 -0
  152. package/dist/components/sortable.js +327 -0
  153. package/dist/components/switch.d.ts +15 -0
  154. package/dist/components/switch.js +63 -0
  155. package/dist/components/table.d.ts +12 -0
  156. package/dist/components/table.js +65 -0
  157. package/dist/components/tabs.d.ts +12 -0
  158. package/dist/components/tabs.js +39 -0
  159. package/dist/components/text.d.ts +14 -0
  160. package/dist/components/text.js +69 -0
  161. package/dist/components/textarea.d.ts +9 -0
  162. package/dist/components/textarea.js +20 -0
  163. package/dist/components/theme-provider.d.ts +52 -0
  164. package/dist/components/theme-provider.js +148 -0
  165. package/dist/components/timeline.d.ts +34 -0
  166. package/dist/components/timeline.js +147 -0
  167. package/dist/components/toast.d.ts +17 -0
  168. package/dist/components/toast.js +161 -0
  169. package/dist/components/toggle-group.d.ts +14 -0
  170. package/dist/components/toggle-group.js +53 -0
  171. package/dist/components/toggle.d.ts +11 -0
  172. package/dist/components/toggle.js +36 -0
  173. package/dist/components/toolbar.d.ts +11 -0
  174. package/dist/components/toolbar.js +49 -0
  175. package/dist/components/tooltip.d.ts +17 -0
  176. package/dist/components/tooltip.js +56 -0
  177. package/dist/components/waveform.d.ts +61 -0
  178. package/dist/components/waveform.js +500 -0
  179. package/dist/components/wheel-picker.d.ts +44 -0
  180. package/dist/components/wheel-picker.js +771 -0
  181. package/dist/hooks/use-copy-to-clipboard.d.ts +9 -0
  182. package/dist/hooks/use-copy-to-clipboard.js +36 -0
  183. package/dist/hooks/use-media-query.d.ts +21 -0
  184. package/dist/hooks/use-media-query.js +58 -0
  185. package/dist/styles.css +202 -0
  186. package/dist/themes/afterglow.css +89 -0
  187. package/dist/themes/afterglow.scoped.css +90 -0
  188. package/dist/themes/blacklight.css +89 -0
  189. package/dist/themes/blacklight.scoped.css +90 -0
  190. package/dist/themes/cathode.css +89 -0
  191. package/dist/themes/cathode.scoped.css +90 -0
  192. package/dist/themes/cel.css +89 -0
  193. package/dist/themes/cel.scoped.css +90 -0
  194. package/dist/themes/cinder.css +89 -0
  195. package/dist/themes/cinder.scoped.css +90 -0
  196. package/dist/themes/clay.css +89 -0
  197. package/dist/themes/clay.scoped.css +90 -0
  198. package/dist/themes/cobalt.css +89 -0
  199. package/dist/themes/cobalt.scoped.css +90 -0
  200. package/dist/themes/crimson.css +89 -0
  201. package/dist/themes/crimson.scoped.css +90 -0
  202. package/dist/themes/ion.css +89 -0
  203. package/dist/themes/ion.scoped.css +90 -0
  204. package/dist/themes/iris.css +89 -0
  205. package/dist/themes/iris.scoped.css +90 -0
  206. package/dist/themes/lagoon.css +89 -0
  207. package/dist/themes/lagoon.scoped.css +90 -0
  208. package/dist/themes/mochi.css +89 -0
  209. package/dist/themes/mochi.scoped.css +90 -0
  210. package/dist/themes/riso.css +89 -0
  211. package/dist/themes/riso.scoped.css +90 -0
  212. package/dist/themes/roast.css +89 -0
  213. package/dist/themes/roast.scoped.css +90 -0
  214. package/dist/themes/sage.css +89 -0
  215. package/dist/themes/sage.scoped.css +90 -0
  216. package/dist/themes/sepia.css +89 -0
  217. package/dist/themes/sepia.scoped.css +90 -0
  218. package/dist/themes/sorbet.css +89 -0
  219. package/dist/themes/sorbet.scoped.css +90 -0
  220. package/dist/themes/taffy.css +89 -0
  221. package/dist/themes/taffy.scoped.css +90 -0
  222. package/dist/themes/toxin.css +89 -0
  223. package/dist/themes/toxin.scoped.css +90 -0
  224. package/package.json +140 -0
@@ -0,0 +1,482 @@
1
+ "use client";
2
+ import { Button } from "./button.js";
3
+ import { cn } from "cn";
4
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ import { cva } from "class-variance-authority";
6
+ import * as React$1 from "react";
7
+ import { mergeProps } from "@base-ui/react/merge-props";
8
+ import { useRender } from "@base-ui/react/use-render";
9
+ import { AlertCircle } from "xiod-icons/icons/AlertCircle";
10
+ import { CheckmarkCircle } from "xiod-icons/icons/CheckmarkCircle";
11
+ import { Delete } from "xiod-icons/icons/Delete";
12
+ import { File } from "xiod-icons/icons/File";
13
+ import { FileArchive } from "xiod-icons/icons/FileArchive";
14
+ import { FileAudio } from "xiod-icons/icons/FileAudio";
15
+ import { FileCode } from "xiod-icons/icons/FileCode";
16
+ import { FileEmpty } from "xiod-icons/icons/FileEmpty";
17
+ import { FileImage } from "xiod-icons/icons/FileImage";
18
+ import { FileVideo } from "xiod-icons/icons/FileVideo";
19
+ //#region src/components/file-upload.tsx
20
+ const FileUploadContext = React$1.createContext(null);
21
+ function useFileUploadContext() {
22
+ const context = React$1.useContext(FileUploadContext);
23
+ if (!context) throw new Error("FileUpload subcomponents must be rendered within a <FileUpload> provider component.");
24
+ return context;
25
+ }
26
+ function isAccepted(file, acceptString) {
27
+ if (!acceptString) return true;
28
+ const acceptTypes = acceptString.split(",").map((t) => t.trim().toLowerCase());
29
+ const fileType = file.type.toLowerCase();
30
+ const fileName = file.name.toLowerCase();
31
+ return acceptTypes.some((type) => {
32
+ if (type.startsWith(".")) return fileName.endsWith(type);
33
+ if (type.endsWith("/*")) {
34
+ const baseType = type.slice(0, -2);
35
+ return fileType.startsWith(baseType);
36
+ }
37
+ return fileType === type;
38
+ });
39
+ }
40
+ function formatFileSize(bytes) {
41
+ if (bytes === 0) return "0 Bytes";
42
+ const k = 1024;
43
+ const sizes = [
44
+ "Bytes",
45
+ "KB",
46
+ "MB",
47
+ "GB"
48
+ ];
49
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
50
+ return `${parseFloat((bytes / k ** i).toFixed(2))} ${sizes[i]}`;
51
+ }
52
+ function FileUpload({ files: filesProp, onFilesChange, onFilesAdded, onFileRemove, maxFiles = 5, maxSizeMB = 10, accept, disabled = false, children, ...props }) {
53
+ const [internalFiles, setInternalFiles] = React$1.useState([]);
54
+ const [isDragging, setIsDragging] = React$1.useState(false);
55
+ const fileInputRef = React$1.useRef(null);
56
+ const files = filesProp ?? internalFiles;
57
+ const setFiles = React$1.useCallback((update) => {
58
+ if (filesProp === void 0) setInternalFiles(update);
59
+ if (onFilesChange) onFilesChange(typeof update === "function" ? update(files) : update);
60
+ }, [
61
+ filesProp,
62
+ onFilesChange,
63
+ files
64
+ ]);
65
+ const removeFile = React$1.useCallback((id) => {
66
+ if (disabled) return;
67
+ const updatedFiles = files.filter((f) => f.id !== id);
68
+ setFiles(updatedFiles);
69
+ if (onFileRemove) onFileRemove(id);
70
+ }, [
71
+ files,
72
+ disabled,
73
+ onFileRemove,
74
+ setFiles
75
+ ]);
76
+ const addFiles = React$1.useCallback((newFiles) => {
77
+ if (disabled) return;
78
+ const validatedItems = [];
79
+ const currentFileCount = files.length;
80
+ let addedCount = 0;
81
+ for (const file of newFiles) {
82
+ if (maxFiles && currentFileCount + addedCount >= maxFiles) break;
83
+ let errorMessage;
84
+ let status = "idle";
85
+ if (maxSizeMB && file.size > maxSizeMB * 1024 * 1024) {
86
+ errorMessage = `File exceeds max size of ${maxSizeMB}MB`;
87
+ status = "error";
88
+ } else if (accept && !isAccepted(file, accept)) {
89
+ errorMessage = "Invalid file type";
90
+ status = "error";
91
+ }
92
+ validatedItems.push({
93
+ id: Math.random().toString(36).substring(2, 9),
94
+ file,
95
+ progress: 0,
96
+ status,
97
+ errorMessage
98
+ });
99
+ addedCount++;
100
+ }
101
+ if (validatedItems.length > 0) {
102
+ const updatedFiles = [...files, ...validatedItems];
103
+ setFiles(updatedFiles);
104
+ if (onFilesAdded) onFilesAdded(validatedItems.map((item) => item.file));
105
+ }
106
+ }, [
107
+ files,
108
+ maxFiles,
109
+ maxSizeMB,
110
+ accept,
111
+ disabled,
112
+ onFilesAdded,
113
+ setFiles
114
+ ]);
115
+ const contextValue = React$1.useMemo(() => ({
116
+ files,
117
+ isDragging,
118
+ setIsDragging,
119
+ maxFiles,
120
+ maxSizeMB,
121
+ accept,
122
+ disabled,
123
+ removeFile,
124
+ addFiles,
125
+ fileInputRef
126
+ }), [
127
+ files,
128
+ isDragging,
129
+ maxFiles,
130
+ maxSizeMB,
131
+ accept,
132
+ disabled,
133
+ removeFile,
134
+ addFiles
135
+ ]);
136
+ return /* @__PURE__ */ jsx(FileUploadContext.Provider, {
137
+ value: contextValue,
138
+ children: /* @__PURE__ */ jsx("div", {
139
+ className: "contents",
140
+ "data-slot": "file-upload",
141
+ ...props,
142
+ children
143
+ })
144
+ });
145
+ }
146
+ function FileUploadTrigger({ className, render, ...props }) {
147
+ const { fileInputRef, isDragging, setIsDragging, disabled, addFiles } = useFileUploadContext();
148
+ const handleDragOver = (e) => {
149
+ if (disabled) return;
150
+ e.preventDefault();
151
+ e.stopPropagation();
152
+ setIsDragging(true);
153
+ };
154
+ const handleDragLeave = (e) => {
155
+ if (disabled) return;
156
+ e.preventDefault();
157
+ e.stopPropagation();
158
+ setIsDragging(false);
159
+ };
160
+ const handleDrop = (e) => {
161
+ if (disabled) return;
162
+ e.preventDefault();
163
+ e.stopPropagation();
164
+ setIsDragging(false);
165
+ if (e.dataTransfer.files && e.dataTransfer.files.length > 0) addFiles(Array.from(e.dataTransfer.files));
166
+ };
167
+ const handleClick = () => {
168
+ if (disabled) return;
169
+ fileInputRef.current?.click();
170
+ };
171
+ const handleKeyDown = (e) => {
172
+ if (disabled) return;
173
+ if (e.key === "Enter" || e.key === " ") {
174
+ e.preventDefault();
175
+ fileInputRef.current?.click();
176
+ }
177
+ };
178
+ const defaultProps = {
179
+ role: "button",
180
+ tabIndex: disabled ? -1 : 0,
181
+ className: cn("relative flex flex-col items-center justify-center rounded-2xl border border-dashed border-input bg-muted/20 hover:bg-muted/40 p-[calc(--spacing(8)-1px)] text-center transition-[color,background-color,border-color,transform,box-shadow,opacity] duration-200 outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 cursor-pointer select-none", "before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-2xl)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] dark:before:shadow-[0_-1px_--theme(--color-white/6%)]", isDragging && "scale-[1.01] border-primary bg-primary/4 dark:bg-primary/8 border-solid", disabled && "cursor-not-allowed opacity-64", className),
182
+ "data-dragging": isDragging ? "true" : void 0,
183
+ "data-disabled": disabled ? "true" : void 0,
184
+ "data-slot": "file-upload-trigger",
185
+ onDragOver: handleDragOver,
186
+ onDragLeave: handleDragLeave,
187
+ onDrop: handleDrop,
188
+ onClick: handleClick,
189
+ onKeyDown: handleKeyDown
190
+ };
191
+ return useRender({
192
+ defaultTagName: "div",
193
+ props: mergeProps(defaultProps, props),
194
+ render
195
+ });
196
+ }
197
+ function FileUploadInput({ className, ...props }) {
198
+ const { fileInputRef, maxFiles, accept, disabled, addFiles } = useFileUploadContext();
199
+ const handleChange = (e) => {
200
+ if (e.target.files && e.target.files.length > 0) addFiles(Array.from(e.target.files));
201
+ e.target.value = "";
202
+ };
203
+ return /* @__PURE__ */ jsx("input", {
204
+ type: "file",
205
+ ref: fileInputRef,
206
+ className: cn("hidden", className),
207
+ multiple: maxFiles > 1,
208
+ accept,
209
+ disabled,
210
+ onChange: handleChange,
211
+ "data-slot": "file-upload-input",
212
+ ...props
213
+ });
214
+ }
215
+ function FileUploadList({ className, render, ...props }) {
216
+ const defaultProps = {
217
+ className: cn("grid gap-3 w-full mt-4", className),
218
+ "data-slot": "file-upload-list"
219
+ };
220
+ return useRender({
221
+ defaultTagName: "div",
222
+ props: mergeProps(defaultProps, props),
223
+ render
224
+ });
225
+ }
226
+ const FileItemContext = React$1.createContext(null);
227
+ function useFileItemContext() {
228
+ const context = React$1.useContext(FileItemContext);
229
+ if (!context) throw new Error("FileUploadItem subcomponents must be rendered within a <FileUploadItem> parent component.");
230
+ return context;
231
+ }
232
+ function FileUploadItem({ className, render, fileItem, ...props }) {
233
+ const defaultProps = {
234
+ className: cn("group relative flex items-center gap-4 overflow-hidden rounded-xl border border-border/80 bg-background/50 p-[calc(--spacing(3)-1px)] shadow-xs/5 not-dark:bg-clip-padding before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-xl)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] dark:before:shadow-[0_-1px_--theme(--color-white/6%)] transition-[color,background-color,border-color,box-shadow,opacity]", fileItem.status === "uploading" && "pb-4.5", className),
235
+ "data-status": fileItem.status,
236
+ "data-slot": "file-upload-item"
237
+ };
238
+ return /* @__PURE__ */ jsx(FileItemContext.Provider, {
239
+ value: fileItem,
240
+ children: useRender({
241
+ defaultTagName: "div",
242
+ props: mergeProps(defaultProps, props),
243
+ render
244
+ })
245
+ });
246
+ }
247
+ function FileUploadItemIcon({ className, render, ...props }) {
248
+ const { file } = useFileItemContext();
249
+ const defaultProps = {
250
+ className: cn("flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-muted text-muted-foreground", className),
251
+ "data-slot": "file-upload-item-icon"
252
+ };
253
+ const getIcon = () => {
254
+ const type = file.type.toLowerCase();
255
+ const name = file.name.toLowerCase();
256
+ if (type.startsWith("image/")) return /* @__PURE__ */ jsx(FileImage, { className: "size-5 text-primary" });
257
+ if (type.startsWith("video/")) return /* @__PURE__ */ jsx(FileVideo, { className: "size-5 text-primary" });
258
+ if (type.startsWith("audio/")) return /* @__PURE__ */ jsx(FileAudio, { className: "size-5 text-warning" });
259
+ if (type.includes("pdf") || name.endsWith(".pdf")) return /* @__PURE__ */ jsx(File, { className: "size-5 text-destructive" });
260
+ if (type.includes("zip") || type.includes("tar") || type.includes("gzip") || type.includes("rar") || name.endsWith(".zip") || name.endsWith(".rar") || name.endsWith(".gz")) return /* @__PURE__ */ jsx(FileArchive, { className: "size-5 text-success" });
261
+ if (type.includes("json") || type.includes("javascript") || type.includes("typescript") || type.includes("html") || type.includes("css") || name.endsWith(".json") || name.endsWith(".js") || name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".html") || name.endsWith(".css")) return /* @__PURE__ */ jsx(FileCode, { className: "size-5 text-info" });
262
+ return /* @__PURE__ */ jsx(FileEmpty, { className: "size-5 text-muted-foreground" });
263
+ };
264
+ const defaultContent = getIcon();
265
+ const mergedProps = mergeProps(defaultProps, props);
266
+ if (mergedProps.children === void 0) mergedProps.children = defaultContent;
267
+ return useRender({
268
+ defaultTagName: "div",
269
+ props: mergedProps,
270
+ render
271
+ });
272
+ }
273
+ function FileUploadItemName({ className, render, ...props }) {
274
+ const { file } = useFileItemContext();
275
+ const defaultProps = {
276
+ className: cn("truncate text-sm font-medium text-foreground pr-2", className),
277
+ "data-slot": "file-upload-item-name"
278
+ };
279
+ const mergedProps = mergeProps(defaultProps, props);
280
+ if (mergedProps.children === void 0) mergedProps.children = file.name;
281
+ return useRender({
282
+ defaultTagName: "p",
283
+ props: mergedProps,
284
+ render
285
+ });
286
+ }
287
+ function FileUploadItemSize({ className, render, ...props }) {
288
+ const { file } = useFileItemContext();
289
+ const defaultProps = {
290
+ className: cn("text-xs text-muted-foreground", className),
291
+ "data-slot": "file-upload-item-size"
292
+ };
293
+ const mergedProps = mergeProps(defaultProps, props);
294
+ if (mergedProps.children === void 0) mergedProps.children = formatFileSize(file.size);
295
+ return useRender({
296
+ defaultTagName: "span",
297
+ props: mergedProps,
298
+ render
299
+ });
300
+ }
301
+ function FileUploadItemProgress({ className, render, ...props }) {
302
+ const { progress, status } = useFileItemContext();
303
+ const defaultProps = {
304
+ className: cn("absolute bottom-0 left-0 h-1 w-full bg-muted/60", className),
305
+ "data-slot": "file-upload-item-progress"
306
+ };
307
+ const mergedProps = mergeProps(defaultProps, props);
308
+ if (mergedProps.children === void 0) mergedProps.children = /* @__PURE__ */ jsx("div", {
309
+ className: "h-full bg-primary transition-[width] duration-300 ease-in-out",
310
+ style: { width: `${progress}%` },
311
+ role: "progressbar",
312
+ "aria-valuenow": progress,
313
+ "aria-valuemin": 0,
314
+ "aria-valuemax": 100
315
+ });
316
+ const renderResult = useRender({
317
+ defaultTagName: "div",
318
+ props: mergedProps,
319
+ render
320
+ });
321
+ if (status !== "uploading") return null;
322
+ return renderResult;
323
+ }
324
+ function FileUploadItemStatus({ className, render, ...props }) {
325
+ const { status, progress, errorMessage } = useFileItemContext();
326
+ const defaultProps = {
327
+ className: cn("flex items-center gap-1.5 shrink-0", className),
328
+ "data-slot": "file-upload-item-status"
329
+ };
330
+ const getStatusContent = () => {
331
+ if (status === "success") return /* @__PURE__ */ jsxs("span", {
332
+ className: "inline-flex items-center gap-1 rounded-full bg-success/10 px-2 py-0.5 text-xs font-medium text-success dark:bg-success/20",
333
+ children: [/* @__PURE__ */ jsx(CheckmarkCircle, { className: "size-3" }), " Done"]
334
+ });
335
+ if (status === "error") return /* @__PURE__ */ jsxs("span", {
336
+ className: "inline-flex items-center gap-1 rounded-full bg-destructive/10 px-2 py-0.5 text-xs font-medium text-destructive dark:bg-destructive/20",
337
+ title: errorMessage,
338
+ children: [/* @__PURE__ */ jsx(AlertCircle, { className: "size-3" }), " Failed"]
339
+ });
340
+ if (status === "uploading") return /* @__PURE__ */ jsxs("span", {
341
+ className: "text-xs font-medium text-muted-foreground",
342
+ children: [Math.round(progress), "%"]
343
+ });
344
+ return null;
345
+ };
346
+ const defaultContent = getStatusContent();
347
+ const mergedProps = mergeProps(defaultProps, props);
348
+ if (mergedProps.children === void 0) mergedProps.children = defaultContent;
349
+ const renderResult = useRender({
350
+ defaultTagName: "div",
351
+ props: mergedProps,
352
+ render
353
+ });
354
+ if (!defaultContent) return null;
355
+ return renderResult;
356
+ }
357
+ function FileUploadItemRemove({ className, render, ...props }) {
358
+ const { id } = useFileItemContext();
359
+ const { removeFile, disabled } = useFileUploadContext();
360
+ const defaultProps = {
361
+ type: "button",
362
+ disabled,
363
+ onClick: (e) => {
364
+ e.stopPropagation();
365
+ removeFile(id);
366
+ },
367
+ className: cn("relative flex items-center justify-center rounded-lg text-muted-foreground hover:bg-destructive/10 hover:text-destructive transition-colors shrink-0 outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-64 size-8 pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11", className),
368
+ "data-slot": "file-upload-item-remove"
369
+ };
370
+ const mergedProps = mergeProps(defaultProps, props);
371
+ if (mergedProps.children === void 0) mergedProps.children = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Delete, { className: "size-4" }), /* @__PURE__ */ jsx("span", {
372
+ className: "sr-only",
373
+ children: "Remove file"
374
+ })] });
375
+ return useRender({
376
+ defaultTagName: "button",
377
+ props: mergedProps,
378
+ render
379
+ });
380
+ }
381
+ const attachmentVariants = cva("group/attachment relative flex w-fit max-w-full min-w-0 shrink-0 flex-wrap rounded-2xl border bg-card text-card-foreground focus-within:ring-1 focus-within:ring-ring/30 not-dark:bg-clip-padding transition-[color,background-color,border-color,box-shadow,opacity] duration-200 outline-none", {
382
+ variants: {
383
+ size: {
384
+ default: "gap-2 text-sm has-data-[slot=attachment-content]:px-2.5 has-data-[slot=attachment-content]:py-2 has-data-[slot=attachment-media]:p-2",
385
+ sm: "gap-2.5 text-xs has-data-[slot=attachment-content]:px-2 has-data-[slot=attachment-content]:py-1.5 has-data-[slot=attachment-media]:p-1.5",
386
+ xs: "gap-1.5 rounded-xl text-xs has-data-[slot=attachment-content]:px-1.5 has-data-[slot=attachment-content]:py-1 has-data-[slot=attachment-media]:p-1"
387
+ },
388
+ orientation: {
389
+ horizontal: "min-w-40 items-center",
390
+ vertical: "w-24 flex-col has-data-[slot=attachment-content]:w-30"
391
+ }
392
+ },
393
+ defaultVariants: {
394
+ size: "default",
395
+ orientation: "horizontal"
396
+ }
397
+ });
398
+ function Attachment({ className, state = "done", size = "default", orientation = "horizontal", ...props }) {
399
+ return /* @__PURE__ */ jsx("div", {
400
+ "data-slot": "attachment",
401
+ "data-state": state,
402
+ "data-size": size,
403
+ "data-orientation": orientation,
404
+ className: cn(attachmentVariants({
405
+ size,
406
+ orientation
407
+ }), state === "error" ? "border-destructive/30 bg-destructive/4" : "border-border/80 bg-background/50", state === "idle" && "border-dashed", "before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-2xl)-1px)] group-data-[size=xs]/attachment:before:rounded-[calc(var(--radius-xl)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] dark:before:shadow-[0_-1px_--theme(--color-white/6%)]", className),
408
+ ...props
409
+ });
410
+ }
411
+ const attachmentMediaVariants = cva("relative flex aspect-square w-10 shrink-0 items-center justify-center overflow-hidden rounded-lg bg-muted text-foreground group-data-[orientation=vertical]/attachment:w-full group-data-[size=sm]/attachment:w-8 group-data-[size=xs]/attachment:w-7 group-data-[size=xs]/attachment:rounded-md group-data-[state=error]/attachment:bg-destructive/10 group-data-[state=error]/attachment:text-destructive group-data-[orientation=vertical]/attachment:*:data-[slot=spinner]:size-6! [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 group-data-[orientation=vertical]/attachment:[&_svg:not([class*='size-'])]:size-6 group-data-[size=xs]/attachment:[&_svg:not([class*='size-'])]:size-3.5", {
412
+ variants: { variant: {
413
+ icon: "",
414
+ image: "opacity-60 group-data-[state=done]/attachment:opacity-100 group-data-[state=idle]/attachment:opacity-100 *:[img]:aspect-square *:[img]:w-full *:[img]:object-cover"
415
+ } },
416
+ defaultVariants: { variant: "icon" }
417
+ });
418
+ function AttachmentMedia({ className, variant = "icon", ...props }) {
419
+ return /* @__PURE__ */ jsx("div", {
420
+ "data-slot": "attachment-media",
421
+ "data-variant": variant,
422
+ className: cn(attachmentMediaVariants({ variant }), className),
423
+ ...props
424
+ });
425
+ }
426
+ function AttachmentContent({ className, ...props }) {
427
+ return /* @__PURE__ */ jsx("div", {
428
+ "data-slot": "attachment-content",
429
+ className: cn("max-w-full min-w-0 flex-1 leading-tight group-data-[orientation=vertical]/attachment:px-1", className),
430
+ ...props
431
+ });
432
+ }
433
+ function AttachmentTitle({ className, ...props }) {
434
+ return /* @__PURE__ */ jsx("span", {
435
+ "data-slot": "attachment-title",
436
+ className: cn("block max-w-full min-w-0 truncate font-medium text-foreground group-data-[state=processing]/attachment:animate-pulse group-data-[state=uploading]/attachment:animate-pulse", className),
437
+ ...props
438
+ });
439
+ }
440
+ function AttachmentDescription({ className, ...props }) {
441
+ return /* @__PURE__ */ jsx("span", {
442
+ "data-slot": "attachment-description",
443
+ className: cn("mt-0.5 block min-w-0 truncate text-xs text-muted-foreground group-data-[state=error]/attachment:text-destructive/80 max-w-full", className),
444
+ ...props
445
+ });
446
+ }
447
+ function AttachmentActions({ className, ...props }) {
448
+ return /* @__PURE__ */ jsx("div", {
449
+ "data-slot": "attachment-actions",
450
+ className: cn("relative z-20 flex shrink-0 items-center group-data-[orientation=vertical]/attachment:absolute group-data-[orientation=vertical]/attachment:top-3 group-data-[orientation=vertical]/attachment:right-3 group-data-[orientation=vertical]/attachment:gap-1", className),
451
+ ...props
452
+ });
453
+ }
454
+ function AttachmentAction({ className, variant, size = "icon-xs", ...props }) {
455
+ return /* @__PURE__ */ jsx(Button, {
456
+ "data-slot": "attachment-action",
457
+ variant: variant ?? "ghost",
458
+ size,
459
+ className: cn("pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11", className),
460
+ ...props
461
+ });
462
+ }
463
+ function AttachmentTrigger({ className, render, type, ...props }) {
464
+ return useRender({
465
+ defaultTagName: "button",
466
+ props: mergeProps({
467
+ type: render ? type : type ?? "button",
468
+ className: cn("absolute inset-0 z-10 outline-none cursor-pointer", className)
469
+ }, props),
470
+ render,
471
+ state: { slot: "attachment-trigger" }
472
+ });
473
+ }
474
+ function AttachmentGroup({ className, ...props }) {
475
+ return /* @__PURE__ */ jsx("div", {
476
+ "data-slot": "attachment-group",
477
+ className: cn("flex min-w-0 snap-x snap-mandatory scrollbar-none gap-3 overflow-x-auto overscroll-x-contain py-1 *:data-[slot=attachment]:flex-none *:data-[slot=attachment]:snap-start", className),
478
+ ...props
479
+ });
480
+ }
481
+ //#endregion
482
+ export { Attachment, AttachmentAction, AttachmentActions, AttachmentContent, AttachmentDescription, AttachmentGroup, AttachmentMedia, AttachmentTitle, AttachmentTrigger, FileUpload, FileUploadInput, FileUploadItem, FileUploadItemIcon, FileUploadItemName, FileUploadItemProgress, FileUploadItemRemove, FileUploadItemSize, FileUploadItemStatus, FileUploadList, FileUploadTrigger, attachmentMediaVariants, attachmentVariants, formatFileSize };
@@ -0,0 +1,6 @@
1
+ import * as React$1 from "react";
2
+ import { Form as Form$1 } from "@base-ui/react/form";
3
+ //#region src/components/form.d.ts
4
+ declare function Form({ className, ...props }: Form$1.Props): React$1.JSX.Element;
5
+ //#endregion
6
+ export { Form };
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ import { cn } from "cn";
3
+ import { jsx } from "react/jsx-runtime";
4
+ import { Form as Form$1 } from "@base-ui/react/form";
5
+ //#region src/components/form.tsx
6
+ function Form({ className, ...props }) {
7
+ return /* @__PURE__ */ jsx(Form$1, {
8
+ className: cn("flex w-full flex-col gap-4", className),
9
+ "data-slot": "form",
10
+ ...props
11
+ });
12
+ }
13
+ //#endregion
14
+ export { Form };
@@ -0,0 +1,10 @@
1
+ import * as React$1 from "react";
2
+ //#region src/components/frame.d.ts
3
+ declare function Frame({ className, ...props }: React$1.ComponentProps<"div">): React$1.JSX.Element;
4
+ declare function FramePanel({ className, ...props }: React$1.ComponentProps<"div">): React$1.JSX.Element;
5
+ declare function FrameHeader({ className, ...props }: React$1.ComponentProps<"header">): React$1.JSX.Element;
6
+ declare function FrameTitle({ className, ...props }: React$1.ComponentProps<"div">): React$1.JSX.Element;
7
+ declare function FrameDescription({ className, ...props }: React$1.ComponentProps<"div">): React$1.JSX.Element;
8
+ declare function FrameFooter({ className, ...props }: React$1.ComponentProps<"footer">): React$1.JSX.Element;
9
+ //#endregion
10
+ export { Frame, FrameDescription, FrameFooter, FrameHeader, FramePanel, FrameTitle };
@@ -0,0 +1,47 @@
1
+ import { cn } from "cn";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region src/components/frame.tsx
4
+ function Frame({ className, ...props }) {
5
+ return /* @__PURE__ */ jsx("div", {
6
+ className: cn("relative flex flex-col rounded-2xl bg-muted/72 p-1", "*:[[data-slot=frame-panel]+[data-slot=frame-panel]]:mt-1", className),
7
+ "data-slot": "frame",
8
+ ...props
9
+ });
10
+ }
11
+ function FramePanel({ className, ...props }) {
12
+ return /* @__PURE__ */ jsx("div", {
13
+ className: cn("relative rounded-xl border bg-background bg-clip-padding p-[calc(--spacing(5)-1px)] shadow-xs/5 before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-xl)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] dark:before:shadow-[0_-1px_--theme(--color-white/6%)]", className),
14
+ "data-slot": "frame-panel",
15
+ ...props
16
+ });
17
+ }
18
+ function FrameHeader({ className, ...props }) {
19
+ return /* @__PURE__ */ jsx("header", {
20
+ className: cn("flex flex-col px-5 py-4", className),
21
+ "data-slot": "frame-panel-header",
22
+ ...props
23
+ });
24
+ }
25
+ function FrameTitle({ className, ...props }) {
26
+ return /* @__PURE__ */ jsx("div", {
27
+ className: cn("font-semibold text-sm", className),
28
+ "data-slot": "frame-panel-title",
29
+ ...props
30
+ });
31
+ }
32
+ function FrameDescription({ className, ...props }) {
33
+ return /* @__PURE__ */ jsx("div", {
34
+ className: cn("text-muted-foreground text-sm", className),
35
+ "data-slot": "frame-panel-description",
36
+ ...props
37
+ });
38
+ }
39
+ function FrameFooter({ className, ...props }) {
40
+ return /* @__PURE__ */ jsx("footer", {
41
+ className: cn("px-5 py-4", className),
42
+ "data-slot": "frame-panel-footer",
43
+ ...props
44
+ });
45
+ }
46
+ //#endregion
47
+ export { Frame, FrameDescription, FrameFooter, FrameHeader, FramePanel, FrameTitle };
@@ -0,0 +1,27 @@
1
+ import * as React$1 from "react";
2
+ import { useRender } from "@base-ui/react/use-render";
3
+ //#region src/components/gauge.d.ts
4
+ export interface GaugeProps extends useRender.ComponentProps<"div"> {
5
+ /**
6
+ * The progress value (0 to max).
7
+ */
8
+ value?: number;
9
+ /**
10
+ * The maximum progress value. Defaults to 100.
11
+ */
12
+ max?: number;
13
+ /**
14
+ * The size of the gauge (diameter) in pixels. Defaults to 120.
15
+ */
16
+ size?: number;
17
+ /**
18
+ * The stroke width of the SVG circle. Defaults to 12.
19
+ */
20
+ strokeWidth?: number;
21
+ /**
22
+ * Whether to display the value text in the center. Defaults to true.
23
+ */
24
+ showValue?: boolean;
25
+ }
26
+ export declare function Gauge({ render, value, max, size, strokeWidth, showValue, className, children, ...props }: GaugeProps): React$1.ReactElement;
27
+ //#endregion
@@ -0,0 +1,74 @@
1
+ "use client";
2
+ import { cn } from "cn";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ import { mergeProps } from "@base-ui/react/merge-props";
5
+ import { useRender } from "@base-ui/react/use-render";
6
+ //#region src/components/gauge.tsx
7
+ function Gauge({ render, value = 0, max = 100, size = 120, strokeWidth = 12, showValue = true, className, children, ...props }) {
8
+ const safeMax = Number.isFinite(max) && max > 0 ? max : 100;
9
+ const safeValue = Math.min(Math.max(Number.isFinite(value) ? value : 0, 0), safeMax);
10
+ const safeSize = Number.isFinite(size) && size > 0 ? size : 120;
11
+ const safeStrokeWidth = Number.isFinite(strokeWidth) && strokeWidth > 0 ? Math.min(strokeWidth, safeSize) : Math.min(12, safeSize);
12
+ const percentage = safeValue / safeMax * 100;
13
+ const center = safeSize / 2;
14
+ const radius = Math.max(0, center - safeStrokeWidth / 2);
15
+ const circumference = 2 * Math.PI * radius;
16
+ const semiCircumference = circumference / 2;
17
+ const trackDashoffset = semiCircumference;
18
+ const indicatorDashoffset = circumference - semiCircumference * (percentage / 100);
19
+ const defaultProps = {
20
+ className: cn("relative inline-flex flex-col items-center justify-end shrink-0", className),
21
+ role: "meter",
22
+ "aria-valuemin": 0,
23
+ "aria-valuemax": safeMax,
24
+ "aria-valuenow": safeValue,
25
+ "data-state": percentage === 100 ? "complete" : "loading",
26
+ "data-slot": "gauge",
27
+ style: {
28
+ width: safeSize,
29
+ height: safeSize / 2 + safeStrokeWidth / 2
30
+ },
31
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("svg", {
32
+ className: "absolute top-0 left-0 overflow-visible pointer-events-none",
33
+ style: {
34
+ width: safeSize,
35
+ height: safeSize
36
+ },
37
+ viewBox: `0 0 ${safeSize} ${safeSize}`,
38
+ children: [/* @__PURE__ */ jsx("circle", {
39
+ className: "stroke-muted fill-transparent",
40
+ cx: center,
41
+ cy: center,
42
+ r: radius,
43
+ strokeWidth: safeStrokeWidth,
44
+ strokeDasharray: circumference,
45
+ strokeDashoffset: trackDashoffset,
46
+ strokeLinecap: "round",
47
+ transform: `rotate(180 ${center} ${center})`
48
+ }), /* @__PURE__ */ jsx("circle", {
49
+ className: "stroke-primary fill-transparent transition-[stroke-dashoffset] duration-500 ease-in-out",
50
+ cx: center,
51
+ cy: center,
52
+ r: radius,
53
+ strokeWidth: safeStrokeWidth,
54
+ strokeDasharray: circumference,
55
+ strokeDashoffset: indicatorDashoffset,
56
+ strokeLinecap: "round",
57
+ transform: `rotate(180 ${center} ${center})`
58
+ })]
59
+ }), /* @__PURE__ */ jsx("div", {
60
+ className: "flex flex-col items-center justify-end z-10 w-full h-full pb-1",
61
+ children: children ? children : showValue ? /* @__PURE__ */ jsx("span", {
62
+ className: "text-2xl font-bold tracking-tighter text-foreground leading-none",
63
+ children: safeValue
64
+ }) : null
65
+ })] })
66
+ };
67
+ return useRender({
68
+ defaultTagName: "div",
69
+ render,
70
+ props: mergeProps(defaultProps, props)
71
+ });
72
+ }
73
+ //#endregion
74
+ export { Gauge };