dn-react-router-toolkit 0.1.3 → 0.1.5

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.
@@ -13,193 +13,256 @@ function cn(...classes) {
13
13
  return classes.filter(Boolean).join(" ").trim();
14
14
  }
15
15
 
16
- // src/file-kit/client/drop_file_input.tsx
17
- function useDropFileInput({
18
- defaultValue,
19
- options,
20
- uploadFile,
21
- onFileInput,
22
- onFileUploaded,
23
- limit
24
- } = {}) {
25
- const [files, setFiles] = useState(
26
- defaultValue ? (Array.isArray(defaultValue) ? defaultValue : [defaultValue]).map((v) => {
27
- return {
28
- key: v4(),
29
- item: v
16
+ // src/file-kit/client/metadata.ts
17
+ function generateMetadata(blob) {
18
+ return new Promise((resolve, reject) => {
19
+ if (blob.type.startsWith("image/")) {
20
+ const img = new Image();
21
+ img.src = URL.createObjectURL(blob);
22
+ img.onload = () => {
23
+ resolve({
24
+ width: img.width,
25
+ height: img.height
26
+ });
30
27
  };
31
- }).slice(0, limit ? limit : Infinity) : []
32
- );
33
- const fileRef = useRef([]);
34
- useEffect(() => {
35
- fileRef.current = files;
36
- }, [files]);
37
- const Component = useCallback(
38
- function Component2({
39
- className,
40
- container = "border border-dashed border-neutral-300 rounded flex items-center justify-center",
41
- draggingClassName,
42
- name,
43
- hideMessage = false,
44
- children,
45
- ...props
46
- }) {
47
- const [isDragging, setIsDragging] = useState(false);
48
- const handleDragEnter = useCallback((e) => {
49
- e.preventDefault();
50
- e.stopPropagation();
51
- setIsDragging(true);
52
- }, []);
53
- const handleDragLeave = useCallback((e) => {
54
- e.preventDefault();
55
- e.stopPropagation();
56
- setIsDragging(false);
57
- }, []);
58
- const handleDragOver = useCallback((e) => {
59
- e.preventDefault();
60
- e.stopPropagation();
61
- }, []);
62
- const handleFiles = useCallback(
63
- async (files2) => {
64
- if (limit && fileRef.current.length >= limit) {
65
- alert(`\uD30C\uC77C\uC740 \uCD5C\uB300 ${limit}\uAC1C \uC5C5\uB85C\uB4DC\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.`);
66
- return;
67
- }
68
- const filteredFiles = files2.filter((file) => {
69
- return true;
70
- });
71
- if (files2.length !== filteredFiles.length) {
72
- alert(`${props.accept} \uD615\uC2DD\uC758 \uD30C\uC77C\uB9CC \uC5C5\uB85C\uB4DC\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.`);
73
- }
74
- const limitedFiles = filteredFiles.slice(
75
- 0,
76
- limit ? limit - fileRef.current.length : Infinity
77
- );
78
- if (limitedFiles.length === 0) {
79
- return;
80
- }
81
- if (onFileInput) {
82
- onFileInput(limitedFiles);
83
- }
84
- for (const file of limitedFiles) {
85
- const fileItem = {
86
- key: v4()
87
- };
88
- setFiles((prevFiles) => [...prevFiles, fileItem]);
89
- uploadFile?.(file, options).then(async (item) => {
90
- await onFileUploaded?.(item);
91
- setFiles(
92
- (prevFiles) => prevFiles.map((f) => {
93
- if (f.key === fileItem.key) {
94
- return {
95
- ...f,
96
- item
97
- };
98
- }
99
- return f;
100
- })
101
- );
102
- });
103
- }
104
- },
105
- [props.accept]
106
- );
107
- const handleDrop = useCallback(
108
- (e) => {
28
+ img.onerror = reject;
29
+ return;
30
+ }
31
+ if (blob.type.startsWith("video/")) {
32
+ const video = document.createElement("video");
33
+ video.src = URL.createObjectURL(blob);
34
+ video.onloadedmetadata = () => {
35
+ resolve({
36
+ width: video.videoWidth,
37
+ height: video.videoHeight,
38
+ duration: video.duration
39
+ });
40
+ };
41
+ video.onerror = reject;
42
+ return;
43
+ }
44
+ resolve({});
45
+ });
46
+ }
47
+
48
+ // src/file-kit/client/drop_file_input.tsx
49
+ function createUseDropFileInput({
50
+ uploadFile
51
+ }) {
52
+ return function useDropFileInput({
53
+ defaultValue,
54
+ options,
55
+ onChange,
56
+ onFileInput,
57
+ onFileUploaded,
58
+ limit
59
+ } = {}) {
60
+ const [files, setFiles] = useState(
61
+ defaultValue ? (Array.isArray(defaultValue) ? defaultValue : [defaultValue]).map((v) => {
62
+ return {
63
+ key: v4(),
64
+ item: v
65
+ };
66
+ }).slice(0, limit ? limit : Infinity) : []
67
+ );
68
+ const fileRef = useRef([]);
69
+ useEffect(() => {
70
+ fileRef.current = files;
71
+ onChange?.(files.map((f) => f.item).filter(Boolean));
72
+ }, [files]);
73
+ const Component = useCallback(
74
+ function Component2({
75
+ className,
76
+ container = "border border-dashed border-neutral-300 rounded flex items-center justify-center",
77
+ draggingClassName,
78
+ name,
79
+ hideMessage = false,
80
+ children,
81
+ ...props
82
+ }) {
83
+ const [isDragging, setIsDragging] = useState(false);
84
+ const handleDragEnter = useCallback((e) => {
85
+ e.preventDefault();
86
+ e.stopPropagation();
87
+ setIsDragging(true);
88
+ }, []);
89
+ const handleDragLeave = useCallback((e) => {
109
90
  e.preventDefault();
110
91
  e.stopPropagation();
111
92
  setIsDragging(false);
112
- if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
113
- handleFiles(Array.from(e.dataTransfer.files));
114
- e.dataTransfer.clearData();
115
- }
116
- },
117
- [handleFiles]
118
- );
119
- const inputRef = useRef(null);
120
- const handleClick = useCallback(() => {
121
- inputRef.current?.click();
122
- }, []);
123
- const handleKeyDown = useCallback(
124
- (e) => {
125
- if (e.key === "Enter" || e.key === " ") {
126
- handleClick();
127
- }
128
- },
129
- [handleClick]
130
- );
131
- const handleChange = useCallback(
132
- (e) => {
133
- if (e.target.files && e.target.files.length > 0) {
134
- handleFiles(Array.from(e.target.files));
135
- e.target.value = "";
136
- }
137
- },
138
- [handleFiles]
139
- );
140
- return /* @__PURE__ */ React.createElement(
141
- "div",
142
- {
143
- className: cn(
144
- className,
145
- container,
146
- draggingClassName?.(isDragging) || (isDragging ? "bg-neutral-300/25" : "hover:bg-neutral-300/25"),
147
- "transition-colors cursor-pointer"
148
- ),
149
- onDragEnter: handleDragEnter,
150
- onDragLeave: handleDragLeave,
151
- onDragOver: handleDragOver,
152
- onDrop: handleDrop,
153
- onClick: handleClick,
154
- onChange: handleChange,
155
- onKeyDown: handleKeyDown,
156
- tabIndex: 0,
157
- role: "button"
158
- },
159
- /* @__PURE__ */ React.createElement("input", { ...props, defaultValue: "", type: "file", hidden: true, ref: inputRef }),
160
- /* @__PURE__ */ React.createElement(
161
- "input",
162
- {
163
- name,
164
- hidden: true,
165
- readOnly: true,
166
- value: files.map((file) => {
167
- if (file.item && typeof file.item === "object" && "id" in file.item) {
168
- return file.item.id;
93
+ }, []);
94
+ const handleDragOver = useCallback((e) => {
95
+ e.preventDefault();
96
+ e.stopPropagation();
97
+ }, []);
98
+ const handleFiles = useCallback(
99
+ async (files2) => {
100
+ if (limit && fileRef.current.length >= limit) {
101
+ alert(`\uD30C\uC77C\uC740 \uCD5C\uB300 ${limit}\uAC1C \uC5C5\uB85C\uB4DC\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.`);
102
+ return;
103
+ }
104
+ const filteredFiles = files2.filter((file) => {
105
+ if (!props.accept) {
106
+ return true;
169
107
  }
170
- return null;
171
- }).filter(Boolean).join(",")
172
- }
173
- ),
174
- children || !(hideMessage && !isDragging) && /* @__PURE__ */ React.createElement(DropFileMessageBox, null)
175
- );
176
- },
177
- [limit, fileRef, files, options, uploadFile, onFileInput, onFileUploaded]
178
- );
179
- const loadedFileIds = files.map((file) => {
180
- if (file.item && typeof file.item === "object" && "id" in file.item) {
181
- return file.item.id;
182
- }
183
- return null;
184
- }).filter(Boolean);
185
- const loadedFileIdsString = loadedFileIds.join(",");
186
- const fileIds = useMemo(
187
- () => loadedFileIdsString.split(",").filter(Boolean),
188
- [loadedFileIdsString]
189
- );
190
- return {
191
- fileIds,
192
- files,
193
- setFiles,
194
- Component
108
+ const accepts = props.accept.split(",");
109
+ for (const accept of accepts) {
110
+ const trimmedAccept = accept.trim();
111
+ if (file.type === trimmedAccept || file.type.endsWith(trimmedAccept) || file.name.endsWith(trimmedAccept)) {
112
+ return true;
113
+ }
114
+ if (trimmedAccept.endsWith("/*")) {
115
+ const baseType = trimmedAccept.replace("/*", "");
116
+ if (file.type.startsWith(baseType + "/")) {
117
+ return true;
118
+ }
119
+ }
120
+ }
121
+ return false;
122
+ });
123
+ if (files2.length !== filteredFiles.length) {
124
+ alert(`${props.accept} \uD615\uC2DD\uC758 \uD30C\uC77C\uB9CC \uC5C5\uB85C\uB4DC\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.`);
125
+ }
126
+ const limitedFiles = filteredFiles.slice(
127
+ 0,
128
+ limit ? limit - fileRef.current.length : Infinity
129
+ );
130
+ if (limitedFiles.length === 0) {
131
+ return;
132
+ }
133
+ if (onFileInput) {
134
+ onFileInput(limitedFiles);
135
+ }
136
+ for (const file of limitedFiles) {
137
+ const { width, height } = await generateMetadata(file);
138
+ const fileItem = {
139
+ key: v4(),
140
+ width: Number(width) || void 0,
141
+ height: Number(height) || void 0
142
+ };
143
+ setFiles((prevFiles) => [...prevFiles, fileItem]);
144
+ uploadFile?.(file, options).then(async (item) => {
145
+ await onFileUploaded?.(item);
146
+ setFiles(
147
+ (prevFiles) => prevFiles.map((f) => {
148
+ if (f.key === fileItem.key) {
149
+ return {
150
+ ...f,
151
+ item
152
+ };
153
+ }
154
+ return f;
155
+ })
156
+ );
157
+ });
158
+ }
159
+ },
160
+ [props.accept]
161
+ );
162
+ const handleDrop = useCallback(
163
+ (e) => {
164
+ e.preventDefault();
165
+ e.stopPropagation();
166
+ setIsDragging(false);
167
+ if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
168
+ handleFiles(Array.from(e.dataTransfer.files));
169
+ e.dataTransfer.clearData();
170
+ }
171
+ },
172
+ [handleFiles]
173
+ );
174
+ const inputRef = useRef(null);
175
+ const handleClick = useCallback(() => {
176
+ inputRef.current?.click();
177
+ }, []);
178
+ const handleKeyDown = useCallback(
179
+ (e) => {
180
+ if (e.key === "Enter" || e.key === " ") {
181
+ handleClick();
182
+ }
183
+ },
184
+ [handleClick]
185
+ );
186
+ const handleChange = useCallback(
187
+ (e) => {
188
+ if (e.target.files && e.target.files.length > 0) {
189
+ handleFiles(Array.from(e.target.files));
190
+ e.target.value = "";
191
+ }
192
+ },
193
+ [handleFiles]
194
+ );
195
+ return /* @__PURE__ */ React.createElement(
196
+ "div",
197
+ {
198
+ className: cn(
199
+ className,
200
+ container,
201
+ draggingClassName?.(isDragging) || (isDragging ? "bg-neutral-300/25" : "hover:bg-neutral-300/25"),
202
+ "transition-colors cursor-pointer"
203
+ ),
204
+ onDragEnter: handleDragEnter,
205
+ onDragLeave: handleDragLeave,
206
+ onDragOver: handleDragOver,
207
+ onDrop: handleDrop,
208
+ onClick: handleClick,
209
+ onChange: handleChange,
210
+ onKeyDown: handleKeyDown,
211
+ tabIndex: 0,
212
+ role: "button"
213
+ },
214
+ /* @__PURE__ */ React.createElement(
215
+ "input",
216
+ {
217
+ ...props,
218
+ defaultValue: "",
219
+ type: "file",
220
+ hidden: true,
221
+ ref: inputRef
222
+ }
223
+ ),
224
+ /* @__PURE__ */ React.createElement(
225
+ "input",
226
+ {
227
+ name,
228
+ hidden: true,
229
+ readOnly: true,
230
+ value: files.map((file) => {
231
+ if (file.item && typeof file.item === "object" && "id" in file.item) {
232
+ return file.item.id;
233
+ }
234
+ return null;
235
+ }).filter(Boolean).join(",")
236
+ }
237
+ ),
238
+ children || !(hideMessage && !isDragging) && /* @__PURE__ */ React.createElement(DropFileMessageBox, null)
239
+ );
240
+ },
241
+ [limit, fileRef, files, options, uploadFile, onFileInput, onFileUploaded]
242
+ );
243
+ const loadedFileIds = files.map((file) => {
244
+ if (file.item && typeof file.item === "object" && "id" in file.item) {
245
+ return file.item.id;
246
+ }
247
+ return null;
248
+ }).filter(Boolean);
249
+ const loadedFileIdsString = loadedFileIds.join(",");
250
+ const fileIds = useMemo(
251
+ () => loadedFileIdsString.split(",").filter(Boolean),
252
+ [loadedFileIdsString]
253
+ );
254
+ return {
255
+ fileIds,
256
+ files,
257
+ setFiles,
258
+ Component
259
+ };
195
260
  };
196
261
  }
197
262
  function DropFileMessageBox() {
198
263
  return /* @__PURE__ */ React.createElement("div", { className: "text-sm pointer-events-none flex justify-center items-center" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-col items-center" }, /* @__PURE__ */ React.createElement("span", null, "\uD30C\uC77C\uC744 \uC5EC\uAE30\uB85C \uB04C\uC5B4\uB2E4 \uB193\uAC70\uB098 \uD074\uB9AD\uD574\uC11C \uC120\uD0DD\uD574 \uC8FC\uC138\uC694")));
199
264
  }
200
- var drop_file_input_default = useDropFileInput;
201
265
  export {
202
266
  DropFileMessageBox,
203
- drop_file_input_default as default,
204
- useDropFileInput
267
+ createUseDropFileInput as default
205
268
  };
@@ -1,5 +1,6 @@
1
1
  type FileUploaderOptions = {
2
2
  metadata?: Record<string, unknown>;
3
+ convertToWebp?: boolean;
3
4
  };
4
5
  declare class FileUploader {
5
6
  endpoint: string;
@@ -1,5 +1,6 @@
1
1
  type FileUploaderOptions = {
2
2
  metadata?: Record<string, unknown>;
3
+ convertToWebp?: boolean;
3
4
  };
4
5
  declare class FileUploader {
5
6
  endpoint: string;
@@ -23,6 +23,40 @@ __export(file_uploader_exports, {
23
23
  FileUploader: () => FileUploader
24
24
  });
25
25
  module.exports = __toCommonJS(file_uploader_exports);
26
+
27
+ // src/file-kit/client/metadata.ts
28
+ function generateMetadata(blob) {
29
+ return new Promise((resolve, reject) => {
30
+ if (blob.type.startsWith("image/")) {
31
+ const img = new Image();
32
+ img.src = URL.createObjectURL(blob);
33
+ img.onload = () => {
34
+ resolve({
35
+ width: img.width,
36
+ height: img.height
37
+ });
38
+ };
39
+ img.onerror = reject;
40
+ return;
41
+ }
42
+ if (blob.type.startsWith("video/")) {
43
+ const video = document.createElement("video");
44
+ video.src = URL.createObjectURL(blob);
45
+ video.onloadedmetadata = () => {
46
+ resolve({
47
+ width: video.videoWidth,
48
+ height: video.videoHeight,
49
+ duration: video.duration
50
+ });
51
+ };
52
+ video.onerror = reject;
53
+ return;
54
+ }
55
+ resolve({});
56
+ });
57
+ }
58
+
59
+ // src/file-kit/client/file_uploader.ts
26
60
  var FileUploader = class {
27
61
  endpoint;
28
62
  constructor(endpoint = "/api/files") {
@@ -42,45 +76,18 @@ var FileUploader = class {
42
76
  }
43
77
  async uploadBlob(blob, name = "blob", options = {}) {
44
78
  const { type, size } = blob;
45
- const metadataForMedia = await new Promise(
46
- (resolve, reject) => {
47
- if (blob.type.startsWith("image/")) {
48
- const img = new Image();
49
- img.src = URL.createObjectURL(blob);
50
- img.onload = () => {
51
- resolve({
52
- ...options.metadata,
53
- width: img.width,
54
- height: img.height
55
- });
56
- };
57
- img.onerror = reject;
58
- return;
59
- }
60
- if (blob.type.startsWith("video/")) {
61
- const video = document.createElement("video");
62
- video.src = URL.createObjectURL(blob);
63
- video.onloadedmetadata = () => {
64
- resolve({
65
- ...options.metadata,
66
- width: video.videoWidth,
67
- height: video.videoHeight,
68
- duration: video.duration
69
- });
70
- };
71
- video.onerror = reject;
72
- return;
73
- }
74
- resolve(options.metadata || {});
75
- }
76
- );
79
+ const metadataForMedia = await generateMetadata(blob);
80
+ const metadata = {
81
+ ...metadataForMedia,
82
+ ...options.metadata
83
+ };
77
84
  const res1 = await fetch(this.endpoint, {
78
85
  method: "POST",
79
86
  body: JSON.stringify({
80
87
  name: name.replace(/ /g, "_"),
81
88
  type,
82
89
  size,
83
- metadata: metadataForMedia
90
+ metadata
84
91
  })
85
92
  });
86
93
  if (!res1.ok) {
@@ -1,3 +1,35 @@
1
+ // src/file-kit/client/metadata.ts
2
+ function generateMetadata(blob) {
3
+ return new Promise((resolve, reject) => {
4
+ if (blob.type.startsWith("image/")) {
5
+ const img = new Image();
6
+ img.src = URL.createObjectURL(blob);
7
+ img.onload = () => {
8
+ resolve({
9
+ width: img.width,
10
+ height: img.height
11
+ });
12
+ };
13
+ img.onerror = reject;
14
+ return;
15
+ }
16
+ if (blob.type.startsWith("video/")) {
17
+ const video = document.createElement("video");
18
+ video.src = URL.createObjectURL(blob);
19
+ video.onloadedmetadata = () => {
20
+ resolve({
21
+ width: video.videoWidth,
22
+ height: video.videoHeight,
23
+ duration: video.duration
24
+ });
25
+ };
26
+ video.onerror = reject;
27
+ return;
28
+ }
29
+ resolve({});
30
+ });
31
+ }
32
+
1
33
  // src/file-kit/client/file_uploader.ts
2
34
  var FileUploader = class {
3
35
  endpoint;
@@ -18,45 +50,18 @@ var FileUploader = class {
18
50
  }
19
51
  async uploadBlob(blob, name = "blob", options = {}) {
20
52
  const { type, size } = blob;
21
- const metadataForMedia = await new Promise(
22
- (resolve, reject) => {
23
- if (blob.type.startsWith("image/")) {
24
- const img = new Image();
25
- img.src = URL.createObjectURL(blob);
26
- img.onload = () => {
27
- resolve({
28
- ...options.metadata,
29
- width: img.width,
30
- height: img.height
31
- });
32
- };
33
- img.onerror = reject;
34
- return;
35
- }
36
- if (blob.type.startsWith("video/")) {
37
- const video = document.createElement("video");
38
- video.src = URL.createObjectURL(blob);
39
- video.onloadedmetadata = () => {
40
- resolve({
41
- ...options.metadata,
42
- width: video.videoWidth,
43
- height: video.videoHeight,
44
- duration: video.duration
45
- });
46
- };
47
- video.onerror = reject;
48
- return;
49
- }
50
- resolve(options.metadata || {});
51
- }
52
- );
53
+ const metadataForMedia = await generateMetadata(blob);
54
+ const metadata = {
55
+ ...metadataForMedia,
56
+ ...options.metadata
57
+ };
53
58
  const res1 = await fetch(this.endpoint, {
54
59
  method: "POST",
55
60
  body: JSON.stringify({
56
61
  name: name.replace(/ /g, "_"),
57
62
  type,
58
63
  size,
59
- metadata: metadataForMedia
64
+ metadata
60
65
  })
61
66
  });
62
67
  if (!res1.ok) {
@@ -0,0 +1,3 @@
1
+ declare function generateMetadata(blob: Blob | File): Promise<Record<string, unknown>>;
2
+
3
+ export { generateMetadata };
@@ -0,0 +1,3 @@
1
+ declare function generateMetadata(blob: Blob | File): Promise<Record<string, unknown>>;
2
+
3
+ export { generateMetadata };