@mbao01/common 0.0.33 → 0.0.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/types/components/FileUploader/FileUploader.d.ts +14 -0
- package/dist/types/components/FileUploader/FileUploaderContext.d.ts +3 -0
- package/dist/types/components/FileUploader/index.d.ts +1 -0
- package/dist/types/components/FileUploader/types.d.ts +22 -0
- package/dist/types/components/FileUploader/useFileUpload.d.ts +1 -0
- package/dist/types/components/Form/OtpInput/OtpInput.d.ts +2 -0
- package/dist/types/components/Form/OtpInput/index.d.ts +1 -0
- package/dist/types/components/Form/OtpInput/types.d.ts +6 -0
- package/dist/types/components/Form/index.d.ts +1 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +4 -2
- package/src/components/FileUploader/FileUploader.tsx +319 -0
- package/src/components/FileUploader/FileUploaderContext.tsx +5 -0
- package/src/components/FileUploader/index.ts +1 -0
- package/src/components/FileUploader/types.ts +27 -0
- package/src/components/FileUploader/useFileUpload.ts +10 -0
- package/src/components/Form/OtpInput/OtpInput.tsx +34 -0
- package/src/components/Form/OtpInput/index.ts +1 -0
- package/src/components/Form/OtpInput/types.ts +7 -0
- package/src/components/Form/index.ts +1 -0
- package/src/index.ts +1 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import type { FileUploaderInputProps, FileUploaderProps } from "./types";
|
|
3
|
+
export declare const FileUploader: {
|
|
4
|
+
({ className, dropzoneOptions, value, onValueChange, reSelect, orientation, children, dir, ...props }: FileUploaderProps): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
displayName: string;
|
|
6
|
+
Content: import("react").ForwardRefExoticComponent<import("react").HTMLAttributes<HTMLDivElement> & import("react").RefAttributes<HTMLDivElement>>;
|
|
7
|
+
Input: {
|
|
8
|
+
({ className, children, ...props }: FileUploaderInputProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
displayName: string;
|
|
10
|
+
};
|
|
11
|
+
Item: import("react").ForwardRefExoticComponent<{
|
|
12
|
+
index: number;
|
|
13
|
+
} & import("react").HTMLAttributes<HTMLDivElement> & import("react").RefAttributes<HTMLDivElement>>;
|
|
14
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { FileUploader } from "./FileUploader";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Dispatch, SetStateAction } from "react";
|
|
2
|
+
import type { DropzoneState, DropzoneOptions } from "react-dropzone";
|
|
3
|
+
export type FileUploaderProps = {
|
|
4
|
+
value: File[] | null;
|
|
5
|
+
reSelect?: boolean;
|
|
6
|
+
onValueChange: (value: File[] | null) => void;
|
|
7
|
+
dropzoneOptions: DropzoneOptions;
|
|
8
|
+
orientation?: "horizontal" | "vertical";
|
|
9
|
+
} & React.HTMLAttributes<HTMLDivElement>;
|
|
10
|
+
export type FileUploaderInputProps = React.InputHTMLAttributes<HTMLInputElement>;
|
|
11
|
+
export type DirectionOptions = "rtl" | "ltr" | undefined;
|
|
12
|
+
export type FileUploaderContextType = {
|
|
13
|
+
dropzoneState: DropzoneState;
|
|
14
|
+
isLOF: boolean;
|
|
15
|
+
isFileTooBig: boolean;
|
|
16
|
+
removeFileFromSet: (index: number) => void;
|
|
17
|
+
removeAll: () => void;
|
|
18
|
+
activeIndex: number;
|
|
19
|
+
setActiveIndex: Dispatch<SetStateAction<number>>;
|
|
20
|
+
orientation: "horizontal" | "vertical";
|
|
21
|
+
direction: DirectionOptions;
|
|
22
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const useFileUpload: () => import("./types").FileUploaderContextType;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { OtpInput } from "./OtpInput";
|
package/dist/types/index.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export * from "./components/Table";
|
|
|
24
24
|
export * from "./components/Tabs";
|
|
25
25
|
export * from "./components/Text";
|
|
26
26
|
/** data input */
|
|
27
|
+
export * from "./components/FileUploader";
|
|
27
28
|
export * from "./components/Form";
|
|
28
29
|
export * from "./components/Combobox";
|
|
29
30
|
export * from "./components/DatePicker";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mbao01/common",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.35",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "Ayomide Bakare",
|
|
7
7
|
"license": "MIT",
|
|
@@ -91,7 +91,9 @@
|
|
|
91
91
|
"date-fns": "^3.6.0",
|
|
92
92
|
"embla-carousel-react": "^8.0.2",
|
|
93
93
|
"react-day-picker": "^8.10.0",
|
|
94
|
+
"react-dropzone": "^14.2.3",
|
|
94
95
|
"react-international-phone": "^4.2.6",
|
|
96
|
+
"react-otp-input": "^3.1.1",
|
|
95
97
|
"sonner": "^1.4.41",
|
|
96
98
|
"tailwind-merge": "^2.2.1",
|
|
97
99
|
"tailwindcss-animate": "^1.0.7",
|
|
@@ -143,5 +145,5 @@
|
|
|
143
145
|
"react-dom": "^18.2.0",
|
|
144
146
|
"typescript": "^5.2.2"
|
|
145
147
|
},
|
|
146
|
-
"gitHead": "
|
|
148
|
+
"gitHead": "4e024b19d151c05b6c1580f461e348f5376c33b9"
|
|
147
149
|
}
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { forwardRef, useCallback, useEffect, useRef, useState } from "react";
|
|
4
|
+
import { useDropzone, FileRejection } from "react-dropzone";
|
|
5
|
+
import { toast } from "sonner";
|
|
6
|
+
import { TrashIcon } from "@radix-ui/react-icons";
|
|
7
|
+
import type {
|
|
8
|
+
DirectionOptions,
|
|
9
|
+
FileUploaderInputProps,
|
|
10
|
+
FileUploaderProps,
|
|
11
|
+
} from "./types";
|
|
12
|
+
import { cn } from "../../utilities";
|
|
13
|
+
import { FileUploaderContext } from "./FileUploaderContext";
|
|
14
|
+
import { useFileUpload } from "./useFileUpload";
|
|
15
|
+
|
|
16
|
+
export const FileUploader = ({
|
|
17
|
+
className,
|
|
18
|
+
dropzoneOptions,
|
|
19
|
+
value,
|
|
20
|
+
onValueChange,
|
|
21
|
+
reSelect,
|
|
22
|
+
orientation = "vertical",
|
|
23
|
+
children,
|
|
24
|
+
dir,
|
|
25
|
+
...props
|
|
26
|
+
}: FileUploaderProps) => {
|
|
27
|
+
const [isFileTooBig, setIsFileTooBig] = useState(false);
|
|
28
|
+
const [isLOF, setIsLOF] = useState(false);
|
|
29
|
+
const [activeIndex, setActiveIndex] = useState(-1);
|
|
30
|
+
const {
|
|
31
|
+
accept = {
|
|
32
|
+
"image/*": [".jpg", ".jpeg", ".png", ".gif"],
|
|
33
|
+
},
|
|
34
|
+
maxFiles = 1,
|
|
35
|
+
maxSize = 4 * 1024 * 1024,
|
|
36
|
+
multiple = true,
|
|
37
|
+
} = dropzoneOptions;
|
|
38
|
+
|
|
39
|
+
const reSelectAll = maxFiles === 1 ? true : reSelect;
|
|
40
|
+
const direction: DirectionOptions = dir === "rtl" ? "rtl" : "ltr";
|
|
41
|
+
|
|
42
|
+
const removeFileFromSet = useCallback(
|
|
43
|
+
(i: number) => {
|
|
44
|
+
if (!value) return;
|
|
45
|
+
const newFiles = value.filter((_, index) => index !== i);
|
|
46
|
+
onValueChange(newFiles);
|
|
47
|
+
},
|
|
48
|
+
[value, onValueChange]
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const removeAll = useCallback(() => {
|
|
52
|
+
onValueChange(null);
|
|
53
|
+
}, [onValueChange]);
|
|
54
|
+
|
|
55
|
+
const handleKeyDown = useCallback(
|
|
56
|
+
(e: React.KeyboardEvent<HTMLDivElement>) => {
|
|
57
|
+
e.preventDefault();
|
|
58
|
+
e.stopPropagation();
|
|
59
|
+
|
|
60
|
+
if (!value) return;
|
|
61
|
+
|
|
62
|
+
const moveNext = () => {
|
|
63
|
+
const nextIndex = activeIndex + 1;
|
|
64
|
+
setActiveIndex(nextIndex > value.length - 1 ? 0 : nextIndex);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const movePrev = () => {
|
|
68
|
+
const nextIndex = activeIndex - 1;
|
|
69
|
+
setActiveIndex(nextIndex < 0 ? value.length - 1 : nextIndex);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const prevKey =
|
|
73
|
+
orientation === "horizontal"
|
|
74
|
+
? direction === "ltr"
|
|
75
|
+
? "ArrowLeft"
|
|
76
|
+
: "ArrowRight"
|
|
77
|
+
: "ArrowUp";
|
|
78
|
+
|
|
79
|
+
const nextKey =
|
|
80
|
+
orientation === "horizontal"
|
|
81
|
+
? direction === "ltr"
|
|
82
|
+
? "ArrowRight"
|
|
83
|
+
: "ArrowLeft"
|
|
84
|
+
: "ArrowDown";
|
|
85
|
+
|
|
86
|
+
if (e.key === nextKey) {
|
|
87
|
+
moveNext();
|
|
88
|
+
} else if (e.key === prevKey) {
|
|
89
|
+
movePrev();
|
|
90
|
+
} else if (e.key === "Enter" || e.key === "Space") {
|
|
91
|
+
if (activeIndex === -1) {
|
|
92
|
+
dropzoneState.inputRef.current?.click();
|
|
93
|
+
}
|
|
94
|
+
} else if (e.key === "Delete" || e.key === "Backspace") {
|
|
95
|
+
if (activeIndex !== -1) {
|
|
96
|
+
removeFileFromSet(activeIndex);
|
|
97
|
+
if (value.length - 1 === 0) {
|
|
98
|
+
setActiveIndex(-1);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
movePrev();
|
|
102
|
+
}
|
|
103
|
+
} else if (e.key === "Escape") {
|
|
104
|
+
setActiveIndex(-1);
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
108
|
+
[value, activeIndex, removeFileFromSet]
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const onDrop = useCallback(
|
|
112
|
+
(acceptedFiles: File[], rejectedFiles: FileRejection[]) => {
|
|
113
|
+
const files = acceptedFiles;
|
|
114
|
+
|
|
115
|
+
if (!files) {
|
|
116
|
+
toast.error("file error , probably too big");
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const newValues: File[] = value ? [...value] : [];
|
|
121
|
+
|
|
122
|
+
if (reSelectAll) {
|
|
123
|
+
newValues.splice(0, newValues.length);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
files.forEach((file) => {
|
|
127
|
+
if (newValues.length < maxFiles) {
|
|
128
|
+
newValues.push(file);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
onValueChange(newValues);
|
|
133
|
+
|
|
134
|
+
if (rejectedFiles.length > 0) {
|
|
135
|
+
for (const rejectedFile of rejectedFiles) {
|
|
136
|
+
if (rejectedFile.errors[0]?.code === "file-too-large") {
|
|
137
|
+
toast.error(
|
|
138
|
+
`File is too large. Max size is ${maxSize / 1024 / 1024}MB`
|
|
139
|
+
);
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
if (rejectedFile.errors[0]?.message) {
|
|
143
|
+
toast.error(rejectedFile.errors[0].message);
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
150
|
+
[reSelectAll, value]
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
if (!value) return;
|
|
155
|
+
if (value.length === maxFiles) {
|
|
156
|
+
setIsLOF(true);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
setIsLOF(false);
|
|
160
|
+
}, [value, maxFiles]);
|
|
161
|
+
|
|
162
|
+
const opts = dropzoneOptions
|
|
163
|
+
? dropzoneOptions
|
|
164
|
+
: { accept, maxFiles, maxSize, multiple };
|
|
165
|
+
|
|
166
|
+
const dropzoneState = useDropzone({
|
|
167
|
+
...opts,
|
|
168
|
+
onDrop,
|
|
169
|
+
onDropRejected: () => setIsFileTooBig(true),
|
|
170
|
+
onDropAccepted: () => setIsFileTooBig(false),
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
return (
|
|
174
|
+
<FileUploaderContext.Provider
|
|
175
|
+
value={{
|
|
176
|
+
dropzoneState,
|
|
177
|
+
isLOF,
|
|
178
|
+
isFileTooBig,
|
|
179
|
+
removeFileFromSet,
|
|
180
|
+
removeAll,
|
|
181
|
+
activeIndex,
|
|
182
|
+
setActiveIndex,
|
|
183
|
+
orientation,
|
|
184
|
+
direction,
|
|
185
|
+
}}
|
|
186
|
+
>
|
|
187
|
+
<div
|
|
188
|
+
tabIndex={0}
|
|
189
|
+
onKeyDownCapture={handleKeyDown}
|
|
190
|
+
className={cn(
|
|
191
|
+
"grid w-full focus:outline-none overflow-hidden ",
|
|
192
|
+
className,
|
|
193
|
+
{
|
|
194
|
+
"gap-2": value && value.length > 0,
|
|
195
|
+
}
|
|
196
|
+
)}
|
|
197
|
+
dir={dir}
|
|
198
|
+
{...props}
|
|
199
|
+
>
|
|
200
|
+
{children}
|
|
201
|
+
</div>
|
|
202
|
+
</FileUploaderContext.Provider>
|
|
203
|
+
);
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
FileUploader.displayName = "FileUploader";
|
|
207
|
+
|
|
208
|
+
const FileUploaderContent = forwardRef<
|
|
209
|
+
HTMLDivElement,
|
|
210
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
211
|
+
>(({ children, className, ...props }, ref) => {
|
|
212
|
+
const { orientation } = useFileUpload();
|
|
213
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
214
|
+
|
|
215
|
+
return (
|
|
216
|
+
<div
|
|
217
|
+
className={cn("w-full px-1")}
|
|
218
|
+
ref={containerRef}
|
|
219
|
+
aria-description="content file holder"
|
|
220
|
+
>
|
|
221
|
+
<div
|
|
222
|
+
{...props}
|
|
223
|
+
ref={ref}
|
|
224
|
+
className={cn(
|
|
225
|
+
"flex rounded-xl gap-1",
|
|
226
|
+
orientation === "horizontal" ? "flex-raw flex-wrap" : "flex-col",
|
|
227
|
+
className
|
|
228
|
+
)}
|
|
229
|
+
>
|
|
230
|
+
{children}
|
|
231
|
+
</div>
|
|
232
|
+
</div>
|
|
233
|
+
);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
FileUploaderContent.displayName = "FileUploaderContent";
|
|
237
|
+
|
|
238
|
+
const FileUploaderItem = forwardRef<
|
|
239
|
+
HTMLDivElement,
|
|
240
|
+
{ index: number } & React.HTMLAttributes<HTMLDivElement>
|
|
241
|
+
>(({ className, index, children, ...props }, ref) => {
|
|
242
|
+
const { removeFileFromSet, activeIndex, direction } = useFileUpload();
|
|
243
|
+
const isSelected = index === activeIndex;
|
|
244
|
+
return (
|
|
245
|
+
<div
|
|
246
|
+
ref={ref}
|
|
247
|
+
className={cn(
|
|
248
|
+
"h-6 p-1 justify-between cursor-pointer relative",
|
|
249
|
+
className,
|
|
250
|
+
isSelected ? "bg-muted" : ""
|
|
251
|
+
)}
|
|
252
|
+
{...props}
|
|
253
|
+
>
|
|
254
|
+
<div className="text-sm leading-none tracking-tight flex items-center gap-1.5 h-full w-full">
|
|
255
|
+
{children}
|
|
256
|
+
</div>
|
|
257
|
+
<button
|
|
258
|
+
type="button"
|
|
259
|
+
className={cn(
|
|
260
|
+
"absolute",
|
|
261
|
+
direction === "rtl" ? "top-1 left-1" : "top-1 right-1"
|
|
262
|
+
)}
|
|
263
|
+
onClick={() => removeFileFromSet(index)}
|
|
264
|
+
>
|
|
265
|
+
<span className="sr-only">remove item {index}</span>
|
|
266
|
+
<TrashIcon className="w-4 h-4 hover:stroke-destructive duration-200 ease-in-out" />
|
|
267
|
+
</button>
|
|
268
|
+
</div>
|
|
269
|
+
);
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
FileUploaderItem.displayName = "FileUploaderItem";
|
|
273
|
+
|
|
274
|
+
const FileUploaderInput = ({
|
|
275
|
+
className,
|
|
276
|
+
children,
|
|
277
|
+
...props
|
|
278
|
+
}: FileUploaderInputProps) => {
|
|
279
|
+
const { dropzoneState, isFileTooBig, isLOF } = useFileUpload();
|
|
280
|
+
const rootProps = isLOF ? {} : dropzoneState.getRootProps();
|
|
281
|
+
return (
|
|
282
|
+
<div
|
|
283
|
+
{...props}
|
|
284
|
+
className={`relative w-full ${
|
|
285
|
+
isLOF ? "opacity-50 cursor-not-allowed " : "cursor-pointer "
|
|
286
|
+
}`}
|
|
287
|
+
>
|
|
288
|
+
<div
|
|
289
|
+
className={cn(
|
|
290
|
+
`w-full rounded-lg duration-300 ease-in-out
|
|
291
|
+
${
|
|
292
|
+
dropzoneState.isDragAccept
|
|
293
|
+
? "border-green-500"
|
|
294
|
+
: dropzoneState.isDragReject || isFileTooBig
|
|
295
|
+
? "border-red-500"
|
|
296
|
+
: "border-gray-300"
|
|
297
|
+
}`,
|
|
298
|
+
className
|
|
299
|
+
)}
|
|
300
|
+
{...rootProps}
|
|
301
|
+
>
|
|
302
|
+
{children}
|
|
303
|
+
</div>
|
|
304
|
+
<input
|
|
305
|
+
{...props}
|
|
306
|
+
disabled={isLOF}
|
|
307
|
+
ref={dropzoneState.inputRef}
|
|
308
|
+
{...dropzoneState.getInputProps()}
|
|
309
|
+
className={`${isLOF ? "cursor-not-allowed" : ""}`}
|
|
310
|
+
/>
|
|
311
|
+
</div>
|
|
312
|
+
);
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
FileUploaderInput.displayName = "FileInput";
|
|
316
|
+
|
|
317
|
+
FileUploader.Content = FileUploaderContent;
|
|
318
|
+
FileUploader.Input = FileUploaderInput;
|
|
319
|
+
FileUploader.Item = FileUploaderItem;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { FileUploader } from "./FileUploader";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Dispatch, SetStateAction } from "react";
|
|
2
|
+
import type { DropzoneState, DropzoneOptions } from "react-dropzone";
|
|
3
|
+
|
|
4
|
+
export type FileUploaderProps = {
|
|
5
|
+
value: File[] | null;
|
|
6
|
+
reSelect?: boolean;
|
|
7
|
+
onValueChange: (value: File[] | null) => void;
|
|
8
|
+
dropzoneOptions: DropzoneOptions;
|
|
9
|
+
orientation?: "horizontal" | "vertical";
|
|
10
|
+
} & React.HTMLAttributes<HTMLDivElement>;
|
|
11
|
+
|
|
12
|
+
export type FileUploaderInputProps =
|
|
13
|
+
React.InputHTMLAttributes<HTMLInputElement>;
|
|
14
|
+
|
|
15
|
+
export type DirectionOptions = "rtl" | "ltr" | undefined;
|
|
16
|
+
|
|
17
|
+
export type FileUploaderContextType = {
|
|
18
|
+
dropzoneState: DropzoneState;
|
|
19
|
+
isLOF: boolean;
|
|
20
|
+
isFileTooBig: boolean;
|
|
21
|
+
removeFileFromSet: (index: number) => void;
|
|
22
|
+
removeAll: () => void;
|
|
23
|
+
activeIndex: number;
|
|
24
|
+
setActiveIndex: Dispatch<SetStateAction<number>>;
|
|
25
|
+
orientation: "horizontal" | "vertical";
|
|
26
|
+
direction: DirectionOptions;
|
|
27
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
import { FileUploaderContext } from "./FileUploaderContext";
|
|
3
|
+
|
|
4
|
+
export const useFileUpload = () => {
|
|
5
|
+
const context = useContext(FileUploaderContext);
|
|
6
|
+
if (!context) {
|
|
7
|
+
throw new Error("useFileUpload must be used within a FileUploaderProvider");
|
|
8
|
+
}
|
|
9
|
+
return context;
|
|
10
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import OTPInput from "react-otp-input";
|
|
2
|
+
import { type OtpInputProps } from "./types";
|
|
3
|
+
import { Input } from "../Input";
|
|
4
|
+
import { cn } from "../../../utilities";
|
|
5
|
+
import { useState } from "react";
|
|
6
|
+
|
|
7
|
+
export const OtpInput = ({
|
|
8
|
+
className,
|
|
9
|
+
inputProps,
|
|
10
|
+
...props
|
|
11
|
+
}: OtpInputProps) => {
|
|
12
|
+
const [otp, setOtp] = useState("");
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<OTPInput
|
|
16
|
+
{...props}
|
|
17
|
+
value={otp}
|
|
18
|
+
onChange={setOtp}
|
|
19
|
+
renderInput={(renderProps) => (
|
|
20
|
+
<Input
|
|
21
|
+
{...inputProps}
|
|
22
|
+
{...renderProps}
|
|
23
|
+
className={cn(
|
|
24
|
+
"!w-12 !appearance-none selection:bg-base text-base-content",
|
|
25
|
+
className
|
|
26
|
+
)}
|
|
27
|
+
/>
|
|
28
|
+
)}
|
|
29
|
+
containerStyle={`flex justify-center items-center flex-wrap text-2xl font-bold ${
|
|
30
|
+
props.renderSeparator ? "gap-1" : "gap-x-3 gap-y-2"
|
|
31
|
+
}`}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { OtpInput } from "./OtpInput";
|
package/src/index.ts
CHANGED
|
@@ -26,6 +26,7 @@ export * from "./components/Tabs";
|
|
|
26
26
|
export * from "./components/Text";
|
|
27
27
|
|
|
28
28
|
/** data input */
|
|
29
|
+
export * from "./components/FileUploader";
|
|
29
30
|
export * from "./components/Form";
|
|
30
31
|
export * from "./components/Combobox";
|
|
31
32
|
export * from "./components/DatePicker";
|