@gentleduck/registry-ui 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/index.css +3 -0
  3. package/package.json +59 -0
  4. package/src/_old/_table/index.ts +5 -0
  5. package/src/_old/_table/table-advanced.constants.tsx +24 -0
  6. package/src/_old/_table/table-advanced.tsx +311 -0
  7. package/src/_old/_table/table-advanced.types.ts +272 -0
  8. package/src/_old/_table/table.constants.ts +2 -0
  9. package/src/_old/_table/table.hook.tsx +115 -0
  10. package/src/_old/_table/table.lib.ts +85 -0
  11. package/src/_old/_table/table.tsx +916 -0
  12. package/src/_old/_table/table.types.ts +118 -0
  13. package/src/_old/_table/todo.md +11 -0
  14. package/src/_old/_upload/index.ts +9 -0
  15. package/src/_old/_upload/todo.md +38 -0
  16. package/src/_old/_upload/upload-advanced-chunks.tsx +1624 -0
  17. package/src/_old/_upload/upload-advanced.tsx +507 -0
  18. package/src/_old/_upload/upload-sonner.tsx +58 -0
  19. package/src/_old/_upload/upload.assets.tsx +239 -0
  20. package/src/_old/_upload/upload.constants.tsx +75 -0
  21. package/src/_old/_upload/upload.dto.ts +19 -0
  22. package/src/_old/_upload/upload.lib.tsx +630 -0
  23. package/src/_old/_upload/upload.tsx +491 -0
  24. package/src/_old/_upload/upload.types.ts +436 -0
  25. package/src/accordion/accordion.tsx +247 -0
  26. package/src/accordion/index.ts +1 -0
  27. package/src/alert/alert.constants.ts +17 -0
  28. package/src/alert/alert.tsx +52 -0
  29. package/src/alert/index.ts +2 -0
  30. package/src/alert-dialog/alert-dialog.tsx +107 -0
  31. package/src/alert-dialog/index.ts +1 -0
  32. package/src/aspect-ratio/aspect-ratio.tsx +33 -0
  33. package/src/aspect-ratio/index.ts +1 -0
  34. package/src/audio/audio-record.tsx +776 -0
  35. package/src/audio/audio-visualizer.tsx +377 -0
  36. package/src/audio/audio.libs.ts +5 -0
  37. package/src/audio/audio.types.ts +50 -0
  38. package/src/audio/index.ts +2 -0
  39. package/src/avatar/avatar.tsx +78 -0
  40. package/src/avatar/index.ts +1 -0
  41. package/src/badge/badge.constants.ts +38 -0
  42. package/src/badge/badge.tsx +19 -0
  43. package/src/badge/index.ts +2 -0
  44. package/src/breadcrumb/breadcrumb.tsx +119 -0
  45. package/src/breadcrumb/index.ts +1 -0
  46. package/src/button/button.constants.ts +44 -0
  47. package/src/button/button.tsx +79 -0
  48. package/src/button/button.types.ts +38 -0
  49. package/src/button/index.ts +3 -0
  50. package/src/button-group/button-group.constants.ts +26 -0
  51. package/src/button-group/button-group.tsx +65 -0
  52. package/src/button-group/index.ts +2 -0
  53. package/src/calendar/calendar.tsx +191 -0
  54. package/src/calendar/index.ts +1 -0
  55. package/src/card/card.tsx +81 -0
  56. package/src/card/index.ts +1 -0
  57. package/src/carousel/carousel.tsx +211 -0
  58. package/src/carousel/carousel.types.ts +23 -0
  59. package/src/carousel/index.ts +2 -0
  60. package/src/chart/chart.libs.ts +27 -0
  61. package/src/chart/chart.tsx +260 -0
  62. package/src/chart/chart.types.ts +38 -0
  63. package/src/chart/index.ts +3 -0
  64. package/src/checkbox/checkbox.tsx +144 -0
  65. package/src/checkbox/checkbox.types.ts +24 -0
  66. package/src/checkbox/index.ts +2 -0
  67. package/src/collapsible/collapsible.tsx +151 -0
  68. package/src/collapsible/index.ts +1 -0
  69. package/src/combobox/combobox.tsx +132 -0
  70. package/src/combobox/index.ts +1 -0
  71. package/src/command/command.tsx +192 -0
  72. package/src/command/command.types.ts +11 -0
  73. package/src/command/index.ts +2 -0
  74. package/src/context-menu/context-menu.tsx +178 -0
  75. package/src/context-menu/index.ts +1 -0
  76. package/src/dialog/dialog-responsive.tsx +137 -0
  77. package/src/dialog/dialog.tsx +97 -0
  78. package/src/dialog/index.ts +2 -0
  79. package/src/direction/direction.tsx +13 -0
  80. package/src/direction/index.ts +1 -0
  81. package/src/drawer/drawer.tsx +185 -0
  82. package/src/drawer/index.ts +1 -0
  83. package/src/dropdown-menu/dropdown-menu.tsx +181 -0
  84. package/src/dropdown-menu/index.ts +1 -0
  85. package/src/empty/empty.constants.ts +15 -0
  86. package/src/empty/empty.tsx +73 -0
  87. package/src/empty/index.ts +2 -0
  88. package/src/field/field.constants.ts +22 -0
  89. package/src/field/field.tsx +203 -0
  90. package/src/field/index.ts +2 -0
  91. package/src/hover-card/hover-card.tsx +79 -0
  92. package/src/hover-card/index.ts +1 -0
  93. package/src/input/index.ts +1 -0
  94. package/src/input/input.tsx +45 -0
  95. package/src/input-group/index.ts +1 -0
  96. package/src/input-group/input-group.tsx +170 -0
  97. package/src/input-otp/index.ts +1 -0
  98. package/src/input-otp/input-otp.tsx +66 -0
  99. package/src/item/index.ts +2 -0
  100. package/src/item/item.constants.ts +22 -0
  101. package/src/item/item.tsx +185 -0
  102. package/src/json-editor/index.ts +4 -0
  103. package/src/json-editor/json-editor.hooks.ts +21 -0
  104. package/src/json-editor/json-editor.libs.ts +34 -0
  105. package/src/json-editor/json-editor.tsx +425 -0
  106. package/src/json-editor/json-editor.types.ts +80 -0
  107. package/src/json-editor/json-editor.view.tsx +110 -0
  108. package/src/json-editor/json-text-area.tsx +7 -0
  109. package/src/kbd/index.ts +1 -0
  110. package/src/kbd/kbd.tsx +39 -0
  111. package/src/label/index.ts +1 -0
  112. package/src/label/label.tsx +28 -0
  113. package/src/menubar/index.ts +1 -0
  114. package/src/menubar/menubar.tsx +213 -0
  115. package/src/navigation-menu/index.ts +1 -0
  116. package/src/navigation-menu/navigation-menu.tsx +152 -0
  117. package/src/pagination/index.ts +2 -0
  118. package/src/pagination/pagination.tsx +191 -0
  119. package/src/pagination/pagination.types.ts +17 -0
  120. package/src/popover/index.ts +1 -0
  121. package/src/popover/popover.tsx +35 -0
  122. package/src/preview-panel/index.ts +3 -0
  123. package/src/preview-panel/preview-panel-dialog.tsx +99 -0
  124. package/src/preview-panel/preview-panel.tsx +389 -0
  125. package/src/preview-panel/preview-panel.types.ts +49 -0
  126. package/src/progress/index.ts +1 -0
  127. package/src/progress/progress.tsx +32 -0
  128. package/src/radio-group/index.ts +1 -0
  129. package/src/radio-group/radio-group.tsx +92 -0
  130. package/src/resizable/index.ts +1 -0
  131. package/src/resizable/resizable.tsx +52 -0
  132. package/src/scroll-area/index.ts +1 -0
  133. package/src/scroll-area/scroll-area.tsx +30 -0
  134. package/src/select/index.ts +1 -0
  135. package/src/select/select.tsx +138 -0
  136. package/src/separator/index.ts +1 -0
  137. package/src/separator/separator.tsx +28 -0
  138. package/src/sheet/index.ts +2 -0
  139. package/src/sheet/sheet.constants.tsx +20 -0
  140. package/src/sheet/sheet.tsx +92 -0
  141. package/src/sidebar/index.ts +4 -0
  142. package/src/sidebar/sidebar.constants.ts +30 -0
  143. package/src/sidebar/sidebar.hooks.ts +13 -0
  144. package/src/sidebar/sidebar.tsx +676 -0
  145. package/src/sidebar/sidebar.types.ts +28 -0
  146. package/src/skeleton/index.ts +1 -0
  147. package/src/skeleton/skeleton.tsx +22 -0
  148. package/src/slider/index.ts +1 -0
  149. package/src/slider/slider.tsx +57 -0
  150. package/src/sonner/index.ts +4 -0
  151. package/src/sonner/sonner.chunks.tsx +80 -0
  152. package/src/sonner/sonner.libs.ts +13 -0
  153. package/src/sonner/sonner.tsx +31 -0
  154. package/src/sonner/sonner.types.ts +9 -0
  155. package/src/switch/index.ts +1 -0
  156. package/src/switch/switch.tsx +63 -0
  157. package/src/table/index.ts +1 -0
  158. package/src/table/table.tsx +95 -0
  159. package/src/tabs/index.ts +1 -0
  160. package/src/tabs/tabs.tsx +151 -0
  161. package/src/textarea/index.ts +1 -0
  162. package/src/textarea/textarea.tsx +24 -0
  163. package/src/toggle/index.ts +2 -0
  164. package/src/toggle/toggle.constants.ts +22 -0
  165. package/src/toggle/toggle.tsx +24 -0
  166. package/src/toggle-group/index.ts +1 -0
  167. package/src/toggle-group/toggle-group.tsx +69 -0
  168. package/src/tooltip/index.ts +1 -0
  169. package/src/tooltip/tooltip.tsx +32 -0
  170. package/src/upload/index.ts +1 -0
  171. package/src/upload/upload.constants.tsx +19 -0
  172. package/src/upload/upload.libs.ts +97 -0
  173. package/src/upload/upload.tsx +340 -0
  174. package/src/upload/upload.types.ts +44 -0
  175. package/tsconfig.json +25 -0
@@ -0,0 +1,436 @@
1
+ // //@ts-nocheck
2
+ // import { ScrollArea } from '@/registry/default/ui'
3
+ // import { Button } from '../button'
4
+ // import {
5
+ // BucketFilesType,
6
+ // BucketFoldersType,
7
+ // TRPC_RESPONSE,
8
+ // } from '../../../../upload-api/src/globals'
9
+ // import { FileTypeEnum } from './upload.constants'
10
+ //
11
+ // // NOTE: UPLOAD TYPES
12
+ //
13
+ // export interface StateWithExtraFeatures<T extends Record<string, any>> {
14
+ // data: T | null
15
+ // state: 'pending' | 'success' | 'error'
16
+ // }
17
+ //
18
+ // /**
19
+ // * Context type for managing uploads.
20
+ // * @template T - The type of attachments.
21
+ // */
22
+ // export interface UploadContextType<T extends Record<string, any>> {
23
+ // attachments: StateWithExtraFeatures<T[]> // List of attachments
24
+ // setAttachments: React.Dispatch<
25
+ // React.SetStateAction<StateWithExtraFeatures<T[]>>
26
+ // > // Function to update attachments
27
+ // attachmentsState: T[] // State of attachments
28
+ // setAttachmentsState: React.Dispatch<React.SetStateAction<T[]>> // Function to update attachments state
29
+ // }
30
+ //
31
+ // /**
32
+ // * Props for the Upload component.
33
+ // * @extends {React.HTMLProps<HTMLDivElement>}
34
+ // */
35
+ // export interface UploadProps
36
+ // extends Omit<React.HTMLProps<HTMLDivElement>, 'content'> {
37
+ // trigger: React.ReactNode // Trigger element for the upload action
38
+ // content: React.ReactNode // Content to display in the upload area
39
+ // }
40
+ //
41
+ // /**
42
+ // * Props for the UploadTrigger component.
43
+ // * @extends {React.HTMLProps<HTMLDivElement>}
44
+ // */
45
+ // export interface UploadTriggerProps extends React.HTMLProps<HTMLDivElement> {}
46
+ //
47
+ // /**
48
+ // * Props for the UploadInput component.
49
+ // * @extends {React.HTMLProps<HTMLDivElement>}
50
+ // */
51
+ // export interface UploadInputProps extends React.HTMLProps<HTMLDivElement> {}
52
+ //
53
+ // /**
54
+ // * Props for the UploadContent component.
55
+ // * @extends {React.ComponentPropsWithoutRef<typeof ScrollArea>}
56
+ // */
57
+ // export interface UploadContentProps
58
+ // extends React.ComponentPropsWithoutRef<typeof ScrollArea> {}
59
+ //
60
+ // /**
61
+ // * Props for the UploadItem component.
62
+ // * @extends {React.HTMLProps<HTMLDivElement>}
63
+ // */
64
+ // export interface UploadItemProps extends React.HTMLProps<HTMLDivElement> {
65
+ // attachment: BucketFilesType // The attachment to display
66
+ // }
67
+ //
68
+ // /**
69
+ // * Props for the UploadItemRemove component.
70
+ // * @extends {React.HTMLProps<HTMLDivElement>}
71
+ // */
72
+ // export interface UploadtItemRemoveProps
73
+ // extends React.HTMLProps<HTMLDivElement> {}
74
+ //
75
+ // // NOTE: SHARED TYPES
76
+ // /**
77
+ // * Type representing a selected folder.
78
+ // */
79
+ // export type SelectedFoldersType = Map<
80
+ // string,
81
+ // StateWithExtraFeatures<(BucketFilesType | BucketFoldersType)[]> | null
82
+ // >
83
+ //
84
+ // // ------------------------------------------------------------------------------------------------
85
+ // // NOTE: ADVANCED TYPES
86
+ //
87
+ // /**
88
+ // * Context type for managing advanced upload features.
89
+ // * @template T - The type of attachments.
90
+ // */
91
+ // export interface UploadAdvancedContextType<T extends Record<string, any>>
92
+ // extends UploadContextType<T> {
93
+ // selectedFolder: SelectedFoldersType // Currently selected folders
94
+ // setSelectedFolder: React.Dispatch<React.SetStateAction<SelectedFoldersType>> // Function to update selected folders
95
+ // previewFile: BucketFilesType | null // Currently previewed file
96
+ // setPreviewFile: React.Dispatch<React.SetStateAction<BucketFilesType | null>> // Function to update the previewed file
97
+ // uploadQuery: string // Current search query for uploads
98
+ // setUploadQuery: React.Dispatch<React.SetStateAction<string>> // Function to update the search query
99
+ // selectedAttachments: BucketFilesType[] // Currently selected attachments
100
+ // setSelectedAttachments: React.Dispatch<
101
+ // React.SetStateAction<BucketFilesType[]>
102
+ // > // Function to update selected attachments
103
+ // currentBucket: string // Current bucket name
104
+ // uploadView: 'column' | 'row' // Currently selected view
105
+ // setUploadView: React.Dispatch<React.SetStateAction<'column' | 'row'>> // Function to update the view
106
+ // actions: UploadServerActions
107
+ // }
108
+ //
109
+ // /**
110
+ // * Props for the UploadAdvancedProvider component.
111
+ // * @extends {React.HTMLProps<HTMLDivElement>}
112
+ // */
113
+ // export interface UploadAdvancedProviderProps
114
+ // extends React.HTMLProps<HTMLDivElement> {
115
+ // selectedFolder?: SelectedFoldersType[] // Currently selected folders
116
+ // attachments?: (BucketFilesType | BucketFoldersType)[] // List of attachments
117
+ // currentBucket: string // Current bucket name
118
+ // actions: UploadServerActions
119
+ // }
120
+ //
121
+ // export type UploadServerActions = {
122
+ // /**
123
+ // * this is the context that will be passed to the action
124
+ // * you can use this to access the ctx and mutate and get the attachments.
125
+ // */
126
+ // getInitial: <
127
+ // T extends TRPC_RESPONSE<(BucketFilesType | BucketFoldersType)[]>,
128
+ // >(
129
+ // ctx: Omit<
130
+ // UploadAdvancedContextType<BucketFilesType | BucketFoldersType>,
131
+ // 'actions'
132
+ // >,
133
+ // ) => Promise<T>
134
+ //
135
+ // upload: <T extends TRPC_RESPONSE<BucketFilesType[]>>(
136
+ // _attachments: BucketFilesType[],
137
+ // ctx: Omit<
138
+ // UploadAdvancedContextType<BucketFilesType | BucketFoldersType>,
139
+ // 'actions'
140
+ // >,
141
+ // ) => Promise<T>
142
+ //
143
+ // getFolder: <T extends TRPC_RESPONSE<(BucketFilesType | BucketFoldersType)[]>>(
144
+ // _folder: BucketFoldersType,
145
+ // ctx: Omit<
146
+ // UploadAdvancedContextType<BucketFilesType | BucketFoldersType>,
147
+ // 'actions'
148
+ // >,
149
+ // ) => Promise<T>
150
+ //
151
+ // insertFolder: <T extends TRPC_RESPONSE<BucketFoldersType>>(
152
+ // _folder: BucketFoldersType,
153
+ // ctx: Omit<
154
+ // UploadAdvancedContextType<BucketFilesType | BucketFoldersType>,
155
+ // 'actions'
156
+ // >,
157
+ // ) => Promise<T>
158
+ // }
159
+ //
160
+ // export type WithoutSetKeys<T> = {
161
+ // [K in keyof T as K extends `set${string}` ? never : K]: T[K]
162
+ // }
163
+ //
164
+ // // ------------------------------------------------------------------------------------------------
165
+ // // NOTE: CHUNKS TYPES
166
+ //
167
+ // /**
168
+ // * Props fkjor the UploadDownloadAttachments component. * @extends {React.ComponentPropsWithoutRef<typeof Button>}
169
+ // * @property {string[]} itemsName - Names of the items to download
170
+ // * @property {boolean} withinDropdown - Whether the button is within a dropdown
171
+ // */
172
+ // export interface UploadDownloadAttachmentsProps
173
+ // extends React.ComponentPropsWithoutRef<typeof Button> {
174
+ // itemsName: string[]
175
+ // withinDropdown?: boolean
176
+ // }
177
+ //
178
+ // /**
179
+ // * Props for the UploadRenameAttachmentButton component.
180
+ // *
181
+ // * @property {BucketFilesType|BucketFoldersType} attachment - The attachment to be uploaded or renamed.
182
+ // */
183
+ // export type UploadRenameAttachmentButtonProps = {
184
+ // attachment: BucketFilesType | BucketFoldersType
185
+ // }
186
+ //
187
+ // export type UploadAdvacedAttachmentFolder = {
188
+ // folder: BucketFoldersType
189
+ // }
190
+ //
191
+ // /**
192
+ // * Props for the UploadAttachmentsTreeItem component.
193
+ // */
194
+ // export type UploadAttachmentsTreeItemProps = {
195
+ // data: StateWithExtraFeatures<(BucketFilesType | BucketFoldersType)[]> | null // List of attachments to display
196
+ // uploadQuery: string
197
+ // }
198
+ //
199
+ // /**
200
+ // * Props for the UploadAlertMoveAction component.
201
+ // * @extends {React.ComponentPropsWithoutRef<typeof Button>}
202
+ // */
203
+ // export interface UploadAlertMoveActionProps
204
+ // extends React.ComponentPropsWithoutRef<typeof Button> {
205
+ // itemsName: string[] // Names of items to move
206
+ // }
207
+ //
208
+ // /**
209
+ // * Props for the UploadAlertDeleteAction component.
210
+ // * @extends {UploadAlertMoveActionProps}
211
+ // */
212
+ // export interface UploadAlertDeleteActionProps
213
+ // extends UploadAlertMoveActionProps {
214
+ // itemsToDelete: string[] // IDs of items to delete
215
+ // }
216
+ //
217
+ // // ------------------------------------------------------------------------------------------------
218
+ // // NOTE: UPLOAD SONNER COMPONENTS
219
+ //
220
+ // /**
221
+ // * Props for the UploadSonner component.
222
+ // */
223
+ // export type UploadSonnerProps = {
224
+ // progress: number // Current upload progress
225
+ // files: number // Number of files being uploaded
226
+ // remainingTime?: number // Remaining time for the upload
227
+ // }
228
+ //
229
+ // // ------------------------------------------------------------------------------------------------
230
+ // // NOTE: UPLOAD LIBs
231
+ //
232
+ // /**
233
+ // * Type for the `UploadManager` class.
234
+ // * This class handles file upload, attachment management, and file/folder operations.
235
+ // */
236
+ // export declare class UploadManagerClass {
237
+ // /**
238
+ // * Renames an attachment (file or folder) by its ID.
239
+ // * Updates the name and modification timestamp of the target attachment.
240
+ // * If the attachment is a folder, it recursively renames any matching attachments in its content.
241
+ // *
242
+ // * @param setAttachments - The function to update the attachments state.
243
+ // * @param targetIds - An array of attachment IDs to target for renaming.
244
+ // * @param newName - The new name to assign to the targeted attachment(s).
245
+ // *
246
+ // * @returns void
247
+ // */
248
+ // public static renameAttachmentById(
249
+ // setAttachments: React.Dispatch<
250
+ // React.SetStateAction<(BucketFilesType | BucketFoldersType)[]>
251
+ // >,
252
+ // targetIds: string[],
253
+ // newName: string,
254
+ // ): void
255
+ //
256
+ // /**
257
+ // * Helper method to rename attachments recursively in a folder's content.
258
+ // *
259
+ // * @param attachments - The list of attachments to search through.
260
+ // * @param targetIds - An array of attachment IDs to target for renaming.
261
+ // * @param newName - The new name to assign to the targeted attachment(s).
262
+ // *
263
+ // * @returns A new list of attachments with the renamed attachment(s).
264
+ // */
265
+ // private static renameAttachmentRecursive(
266
+ // attachments: (BucketFilesType | BucketFoldersType)[],
267
+ // targetIds: string[],
268
+ // newName: string,
269
+ // ): (BucketFilesType | BucketFoldersType)[]
270
+ //
271
+ // /**
272
+ // * Selects files from a folder and adds or removes them from the list of selected attachments.
273
+ // * If all files are selected, they will be deselected; otherwise, new files will be selected.
274
+ // *
275
+ // * @param filesInCurrentTree - The list of files in the current folder.
276
+ // * @param setSelectedAttachment - Function to update the selected attachments state.
277
+ // *
278
+ // * @returns void
279
+ // */
280
+ // public static selectAttachmentFromFolderContent({
281
+ // filesInCurrentTree,
282
+ // setSelectedAttachment,
283
+ // }: SelectAttachmentFromFolderContentArgs): void
284
+ //
285
+ // /**
286
+ // * Uploads files with progress tracking and validation.
287
+ // * It performs validation of files, tracks upload progress, and updates the state with new attachments.
288
+ // *
289
+ // * @param e - The event object containing the selected files.
290
+ // * @param selectedFolder - The folder where the files will be uploaded.
291
+ // * @param setAttachments - The function to update the attachments state.
292
+ // *
293
+ // * @returns void
294
+ // */
295
+ // public static advancedUploadAttachments(props: UploadFilesArgs): Promise<void>
296
+ //
297
+ // /**
298
+ // * Simulates the file upload process and provides progress updates.
299
+ // *
300
+ // * @param files - The number of files to upload.
301
+ // * @param toastId - The ID for the toast notification showing the upload progress.
302
+ // *
303
+ // * @returns A promise that resolves when the upload reaches 100% progress.
304
+ // */
305
+ // private static uploadPromise({
306
+ // files,
307
+ // toastId,
308
+ // }: UploadPromiseArgs): Promise<UploadPromiseReturn>
309
+ //
310
+ // /**
311
+ // * Opens a folder and updates the selected folder state.
312
+ // * If the folder is not already in the tree, it is added to the selection.
313
+ // *
314
+ // * @param attachmentFolder - The folder to open.
315
+ // * @param setSelected - The function to update the selected folders state.
316
+ // * @param exist_in_tree - Flag to check if the folder already exists in the selection.
317
+ // *
318
+ // * @returns void
319
+ // */
320
+ // public static folderOpen({
321
+ // attachmentFolder,
322
+ // setSelected,
323
+ // exist_in_tree,
324
+ // }: FolderOpenArgs): void
325
+ //
326
+ // /**
327
+ // * Determines the file type based on the MIME type of the file.
328
+ // *
329
+ // * @param file - The file whose type is to be determined.
330
+ // *
331
+ // * @returns The type of the file (Audio, Text, Image, Video, Pdf, Unknown).
332
+ // */
333
+ // public static getBucketFilesType(file: Blob | null): FileTypeEnum
334
+ //
335
+ // /**
336
+ // * Calculates the remaining time for the file upload based on the current progress.
337
+ // *
338
+ // * @param currentProgress - The current upload progress (0-100).
339
+ // * @param maxProgress - The maximum progress value (usually 100).
340
+ // *
341
+ // * @returns The estimated remaining time for the upload.
342
+ // */
343
+ // public static getRemainingTime(
344
+ // currentProgress: number,
345
+ // maxProgress: number,
346
+ // ): number
347
+ //
348
+ // /**
349
+ // * Formats the given time (in seconds) into a human-readable string (e.g., "2h 30m").
350
+ // *
351
+ // * @param seconds - The time in seconds to format.
352
+ // *
353
+ // * @returns The formatted time string.
354
+ // */
355
+ // public static formatTime(seconds: number): string
356
+ // }
357
+ //
358
+ // /**
359
+ // * Arguments for selecting attachments from folder content.
360
+ // */
361
+ // export type SelectAttachmentFromFolderContentArgs = {
362
+ // filesInCurrentTree: (BucketFilesType | BucketFoldersType)[] // Files in the current tree
363
+ // setSelectedAttachment: React.Dispatch<React.SetStateAction<BucketFilesType[]>> // Function to set selected attachments
364
+ // checkState?: boolean // Optional state check
365
+ // }
366
+ //
367
+ // /**
368
+ // * Arguments for adding a folder to the current path.
369
+ // */
370
+ // export type addFolderToPathArgs = {
371
+ // selectedFolder: BucketFoldersType[] // Currently selected folder
372
+ // setSelectedFolder: React.Dispatch<React.SetStateAction<BucketFoldersType[]>> // Function to set selected folders
373
+ // setAttachments: React.Dispatch<
374
+ // React.SetStateAction<(BucketFilesType | BucketFoldersType)[]>
375
+ // > // Function to set attachments
376
+ // folderName: string | undefined // Name of the folder to add
377
+ // }
378
+ //
379
+ // /**
380
+ // * Arguments for moving attachments to a specified path.
381
+ // */
382
+ // export type MoveAttachmentsToPath = {
383
+ // setAttachments: React.Dispatch<
384
+ // React.SetStateAction<(BucketFilesType | BucketFoldersType)[]>
385
+ // > // Function to set attachments
386
+ // setSelectedAttachment: React.Dispatch<React.SetStateAction<BucketFilesType[]>> // Function to set selected attachments
387
+ // selectedAttachments: BucketFilesType[] // Currently selected attachments
388
+ // path: string // Path to move the attachments to
389
+ // }
390
+ //
391
+ // /**
392
+ // * Arguments for opening a folder.
393
+ // */
394
+ // export type FolderOpenArgs = {
395
+ // attachmentFolder: BucketFoldersType // The folder to open
396
+ // setSelected: React.Dispatch<React.SetStateAction<BucketFoldersType[]>> // Function to set selected folders
397
+ // exist_in_tree: boolean // Whether the folder exists in the tree
398
+ // }
399
+ //
400
+ // /**
401
+ // * Props for handling attachments.
402
+ // */
403
+ // export interface HandleAttachmentProps {
404
+ // e: React.ChangeEvent<HTMLInputElement> // Change event from the input
405
+ // setAttachmentsState: React.Dispatch<React.SetStateAction<BucketFilesType[]>> // Function to set attachments state
406
+ // }
407
+ //
408
+ // /**
409
+ // * Arguments for uploading files.
410
+ // */
411
+ // export type UploadFilesArgs = UploadAdvancedContextType<
412
+ // BucketFilesType | BucketFoldersType
413
+ // > & {
414
+ // e: React.ChangeEvent<HTMLInputElement> // Change event from the input
415
+ // }
416
+ //
417
+ // /**
418
+ // * Arguments for the upload promise.
419
+ // */
420
+ // export type UploadPromiseArgs = {
421
+ // files: number // Number of files to upload
422
+ // toastId: string // ID for the toast notification
423
+ // }
424
+ //
425
+ // /**
426
+ // * Return type for the upload promise.
427
+ // */
428
+ // export type UploadPromiseReturn = {
429
+ // files: number // Number of files uploaded
430
+ // progress: number // Current upload progress
431
+ // remainingTime?: number | undefined // Optional remaining time for the upload
432
+ // message: string // Message indicating the status of the upload
433
+ // toastId: string // ID for the toast notification
434
+ // }
435
+ //
436
+ // //////////////////////////////////////////////////
@@ -0,0 +1,247 @@
1
+ 'use client'
2
+
3
+ import { cn } from '@gentleduck/libs/cn'
4
+ import { type Direction, useDirection } from '@gentleduck/primitives/direction'
5
+ import { Mount } from '@gentleduck/primitives/mount'
6
+ import { ChevronDown } from 'lucide-react'
7
+ import * as React from 'react'
8
+
9
+ const AccordionContext = React.createContext<{
10
+ value: string[]
11
+ readonly onValueChange?: (value: string | string[]) => void
12
+ readonly wrapperRef: React.RefObject<HTMLDivElement | null>
13
+ readonly onItemChange: (value: string, e: React.MouseEvent<HTMLDetailsElement, MouseEvent>) => void
14
+ readonly renderOnce: boolean
15
+ } | null>(null)
16
+
17
+ type AccordionProps = Omit<React.HTMLProps<HTMLDivElement>, 'value' | 'type' | 'ref'> & {
18
+ renderOnce?: boolean
19
+ } & (
20
+ | {
21
+ type?: 'single'
22
+ defaultValue?: string
23
+ value?: string
24
+ onValueChange?: (value: string) => void
25
+ collapsible?: boolean
26
+ }
27
+ | {
28
+ type?: 'multiple'
29
+ defaultValue?: string[]
30
+ onValueChange?: (value: string[]) => void
31
+ value?: string[]
32
+ collapsible?: never
33
+ }
34
+ )
35
+
36
+ const Accordion = React.forwardRef<HTMLDivElement, AccordionProps>(
37
+ (
38
+ {
39
+ className,
40
+ children,
41
+ defaultValue,
42
+ type = 'single',
43
+ value,
44
+ collapsible = true,
45
+ renderOnce = false,
46
+ onValueChange,
47
+ dir,
48
+ ...props
49
+ },
50
+ ref,
51
+ ) => {
52
+ const direction = useDirection(dir as Direction)
53
+ const wrapperRef = React.useRef<HTMLDivElement | null>(null)
54
+ const itemsRef = React.useRef<HTMLDetailsElement[]>([])
55
+
56
+ const [activeValues, setActiveValues] = React.useState<string[]>(() => {
57
+ if (defaultValue) {
58
+ return Array.isArray(defaultValue) ? defaultValue : [defaultValue]
59
+ }
60
+ return []
61
+ })
62
+
63
+ const currentValues = value !== undefined ? (Array.isArray(value) ? value : [value]) : activeValues
64
+
65
+ React.useEffect(() => {
66
+ itemsRef.current = Array.from(
67
+ wrapperRef.current?.querySelectorAll('[data-slot="accordion-item"]') as never as HTMLDetailsElement[],
68
+ )
69
+ }, [])
70
+
71
+ React.useEffect(() => {
72
+ if (defaultValue) {
73
+ itemsRef.current.forEach((item) => {
74
+ if (defaultValue.includes(item.id)) {
75
+ item.open = true
76
+ }
77
+ })
78
+ }
79
+ }, [defaultValue])
80
+
81
+ function handleAccordionItemChange(itemValue: string, e: React.MouseEvent<HTMLDetailsElement, MouseEvent>) {
82
+ let newValues: string[]
83
+
84
+ if (type === 'single') {
85
+ if (collapsible) {
86
+ newValues = currentValues.includes(itemValue) ? [] : [itemValue]
87
+ itemsRef.current.forEach((item) => {
88
+ if (item.id !== itemValue) {
89
+ item.open = false
90
+ }
91
+ })
92
+ } else {
93
+ newValues = [itemValue]
94
+ itemsRef.current.forEach((item) => {
95
+ if (item.id === itemValue) {
96
+ item.open = true
97
+ e.preventDefault()
98
+ } else {
99
+ item.open = false
100
+ }
101
+ })
102
+ }
103
+ } else {
104
+ if (currentValues.includes(itemValue)) {
105
+ newValues = currentValues.filter((v) => v !== itemValue)
106
+ } else {
107
+ newValues = [...currentValues, itemValue]
108
+ }
109
+ itemsRef.current.forEach((item) => {
110
+ if (item.id === itemValue) {
111
+ item.open = !item.open
112
+ e.preventDefault()
113
+ }
114
+ })
115
+ }
116
+
117
+ setActiveValues(newValues)
118
+
119
+ if (type === 'single') {
120
+ ;(onValueChange as ((value: string) => void) | undefined)?.(newValues[0] ?? '')
121
+ } else {
122
+ ;(onValueChange as ((value: string[]) => void) | undefined)?.(newValues)
123
+ }
124
+ }
125
+
126
+ return (
127
+ <AccordionContext.Provider
128
+ value={{
129
+ onItemChange: handleAccordionItemChange,
130
+ onValueChange: onValueChange as never,
131
+ renderOnce,
132
+ value: currentValues,
133
+ wrapperRef,
134
+ }}>
135
+ <div
136
+ className={cn('min-w-100 [interpolate-size:allow-keywords]', className)}
137
+ dir={direction}
138
+ {...props}
139
+ data-slot="accordion"
140
+ ref={(node) => {
141
+ wrapperRef.current = node
142
+ if (typeof ref === 'function') {
143
+ ref(node)
144
+ } else if (ref) {
145
+ ref.current = node
146
+ }
147
+ }}>
148
+ {children}
149
+ </div>
150
+ </AccordionContext.Provider>
151
+ )
152
+ },
153
+ )
154
+ Accordion.displayName = 'Accordion'
155
+
156
+ const AccordionItem = React.forwardRef<
157
+ HTMLDetailsElement,
158
+ Omit<React.HTMLProps<HTMLDetailsElement>, 'value' | 'ref'> & {
159
+ value?: string
160
+ }
161
+ >(({ className, children, onClick, onKeyUp, value, dir, ...props }, ref) => {
162
+ const { onItemChange, value: _value = [], renderOnce } = React.useContext(AccordionContext) ?? {}
163
+ const isActive = _value.includes(value as string)
164
+ const _children = Array.from(children as never as React.ReactNode[])
165
+ const direction = useDirection(dir as Direction)
166
+
167
+ return (
168
+ <details
169
+ className={cn(
170
+ 'group details-content:h-0 details-content:transform-gpu overflow-hidden border-border border-b details-content:transition-all details-content:transition-discrete details-content:duration-[200ms,150ms] details-content:ease-(--duck-motion-ease) details-content:will-change-[height] open:details-content:h-auto',
171
+ className,
172
+ )}
173
+ id={value}
174
+ onClick={(e) => {
175
+ const summary = (e.currentTarget as HTMLDetailsElement).querySelector('summary')
176
+ if (!summary?.contains(e.target as Node)) {
177
+ e.preventDefault()
178
+ return
179
+ }
180
+ onClick?.(e)
181
+ onItemChange?.(value ?? '', e)
182
+ }}
183
+ onKeyUp={onKeyUp}
184
+ dir={direction}
185
+ ref={ref}
186
+ {...props}
187
+ data-slot="accordion-item">
188
+ {_children[0]}
189
+ <Mount open={renderOnce ? isActive : true} renderOnce={renderOnce ?? false}>
190
+ {_children[1]}
191
+ </Mount>
192
+ </details>
193
+ )
194
+ })
195
+ AccordionItem.displayName = 'AccordionItem'
196
+
197
+ const AccordionTrigger = React.forwardRef<
198
+ HTMLElement,
199
+ React.HTMLProps<HTMLElement> & {
200
+ icon?: React.ReactNode
201
+ value?: string
202
+ }
203
+ >(({ className, children, icon, value, ...props }, ref) => {
204
+ return (
205
+ <summary
206
+ className={cn(
207
+ 'flex flex-1 cursor-pointer select-none items-center justify-between whitespace-nowrap py-4 font-medium text-base ring-offset-background transition-all hover:underline focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
208
+ className,
209
+ )}
210
+ ref={ref as React.Ref<HTMLElement>}
211
+ {...props}
212
+ data-slot="accordion-trigger">
213
+ {children}
214
+ <span
215
+ className={cn(
216
+ '[&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:transition-transform [&>svg]:duration-200 group-open:[&>svg]:rotate-180',
217
+ )}
218
+ data-slot="accordion-icon">
219
+ {icon ? icon : <ChevronDown aria-hidden="true" />}
220
+ </span>
221
+ </summary>
222
+ )
223
+ })
224
+ AccordionTrigger.displayName = 'AccordionTrigger'
225
+
226
+ const AccordionContent = React.forwardRef<HTMLDivElement, React.HTMLProps<HTMLDivElement> & { rerender?: boolean }>(
227
+ ({ className, children, rerender = false, dir, ...props }, ref) => {
228
+ const direction = useDirection(dir as Direction)
229
+ return (
230
+ <div
231
+ className={cn(
232
+ 'select-none overflow-hidden pt-0 pb-4 text-base',
233
+ 'transition-all transition-discrete duration-[200ms,150ms] ease-(--duck-motion-ease)',
234
+ className,
235
+ )}
236
+ data-slot="accordion-content"
237
+ dir={direction}
238
+ ref={ref}
239
+ {...props}>
240
+ {children}
241
+ </div>
242
+ )
243
+ },
244
+ )
245
+ AccordionContent.displayName = 'AccordionContent'
246
+
247
+ export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
@@ -0,0 +1 @@
1
+ export * from './accordion'