@appcorp/stellar-solutions-modules 0.1.51 → 0.1.53
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.
|
@@ -11,13 +11,11 @@ export type EnhancedDropzoneProps = {
|
|
|
11
11
|
maxSize?: number;
|
|
12
12
|
minSize?: number;
|
|
13
13
|
disabled?: boolean;
|
|
14
|
-
/**
|
|
15
|
-
|
|
16
|
-
/** Called when selected
|
|
14
|
+
/** Remote image URLs to display as previews */
|
|
15
|
+
value?: string[];
|
|
16
|
+
/** Called when files are selected or removed */
|
|
17
17
|
onChange?: (files: File[]) => void;
|
|
18
|
-
/** Called when
|
|
19
|
-
|
|
20
|
-
/** Called when a provided remote URL preview is removed (if provided) */
|
|
21
|
-
onRemoveUrl?: (url: string) => void;
|
|
18
|
+
/** Called when a remote URL is removed */
|
|
19
|
+
onRemoveRemote?: (url: string) => void;
|
|
22
20
|
};
|
|
23
21
|
export declare const EnhancedDropzone: React.FC<EnhancedDropzoneProps>;
|
|
@@ -61,210 +61,127 @@ var utils_1 = require("../../lib/utils");
|
|
|
61
61
|
var carousel_1 = require("./carousel");
|
|
62
62
|
var button_1 = require("./button");
|
|
63
63
|
var lucide_react_1 = require("lucide-react");
|
|
64
|
-
var dropzone_1 = require("./shadcn-io/dropzone");
|
|
65
64
|
var EnhancedDropzone = function (_a) {
|
|
66
|
-
var id = _a.id, label = _a.label, info = _a.info, error = _a.error, accept = _a.accept, _b = _a.maxFiles, maxFiles = _b === void 0 ? 10 : _b, maxSize = _a.maxSize, minSize = _a.minSize, disabled = _a.disabled, _c = _a.
|
|
67
|
-
//
|
|
68
|
-
var _d = (0, react_1.useState)([]),
|
|
69
|
-
//
|
|
70
|
-
var
|
|
71
|
-
//
|
|
72
|
-
var
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
// Track previous previews and remote map to avoid emitting unchanged values
|
|
78
|
-
var previewsRef = (0, react_1.useRef)([]);
|
|
79
|
-
var remotePreviewsRef = (0, react_1.useRef)({});
|
|
80
|
-
var dropzoneOptions = {
|
|
81
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
82
|
-
accept: (Array.isArray(accept) ? undefined : accept) || undefined,
|
|
83
|
-
maxFiles: maxFiles,
|
|
84
|
-
maxSize: maxSize,
|
|
85
|
-
minSize: minSize,
|
|
86
|
-
disabled: disabled,
|
|
87
|
-
onDrop: function (acceptedFiles) {
|
|
88
|
-
// append files, respecting maxFiles
|
|
89
|
-
var nextFiles = __spreadArray(__spreadArray([], files, true), acceptedFiles, true);
|
|
90
|
-
if (maxFiles && nextFiles.length > maxFiles)
|
|
91
|
-
nextFiles = nextFiles.slice(0, maxFiles);
|
|
92
|
-
setFiles(nextFiles);
|
|
93
|
-
onChange === null || onChange === void 0 ? void 0 : onChange(nextFiles);
|
|
94
|
-
},
|
|
95
|
-
};
|
|
96
|
-
var _g = (0, react_dropzone_1.useDropzone)(dropzoneOptions), getRootProps = _g.getRootProps, getInputProps = _g.getInputProps, isDragActive = _g.isDragActive;
|
|
97
|
-
// Build previews from initial and files
|
|
98
|
-
(0, react_1.useEffect)(function () {
|
|
99
|
-
// cleanup previous object URLs
|
|
100
|
-
(createdUrlsRef.current || []).forEach(function (u) {
|
|
101
|
-
try {
|
|
102
|
-
URL.revokeObjectURL(u);
|
|
103
|
-
}
|
|
104
|
-
catch (_a) { }
|
|
105
|
-
});
|
|
106
|
-
createdUrlsRef.current = [];
|
|
107
|
-
var next = [];
|
|
108
|
-
var remoteMap = {};
|
|
109
|
-
// start with initial items (may be File or string)
|
|
110
|
-
initial.forEach(function (item) {
|
|
111
|
-
if (typeof item === "string") {
|
|
112
|
-
// skip any remote URL the user removed earlier
|
|
113
|
-
if (removedRemoteRef.current.has(item))
|
|
114
|
-
return;
|
|
115
|
-
next.push(item);
|
|
116
|
-
remoteMap[item] = true;
|
|
117
|
-
}
|
|
118
|
-
else if (item instanceof File) {
|
|
65
|
+
var id = _a.id, label = _a.label, info = _a.info, error = _a.error, accept = _a.accept, _b = _a.maxFiles, maxFiles = _b === void 0 ? 10 : _b, maxSize = _a.maxSize, minSize = _a.minSize, disabled = _a.disabled, _c = _a.value, value = _c === void 0 ? [] : _c, onChange = _a.onChange, onRemoveRemote = _a.onRemoveRemote, className = _a.className;
|
|
66
|
+
// Local files selected by user
|
|
67
|
+
var _d = (0, react_1.useState)([]), localFiles = _d[0], setLocalFiles = _d[1];
|
|
68
|
+
// Track object URLs created for local files
|
|
69
|
+
var localPreviewsRef = (0, react_1.useRef)(new Map());
|
|
70
|
+
// Create object URLs for local files synchronously to avoid loading state
|
|
71
|
+
var createObjectURLs = (0, react_1.useCallback)(function () {
|
|
72
|
+
var map = localPreviewsRef.current;
|
|
73
|
+
// Create URLs for new files
|
|
74
|
+
localFiles.forEach(function (file) {
|
|
75
|
+
if (!map.has(file)) {
|
|
119
76
|
try {
|
|
120
|
-
var url = URL.createObjectURL(
|
|
121
|
-
|
|
122
|
-
createdUrlsRef.current.push(url);
|
|
77
|
+
var url = URL.createObjectURL(file);
|
|
78
|
+
map.set(file, url);
|
|
123
79
|
}
|
|
124
|
-
catch (
|
|
125
|
-
|
|
80
|
+
catch (error) {
|
|
81
|
+
console.error("Failed to create object URL:", error);
|
|
126
82
|
}
|
|
127
83
|
}
|
|
128
|
-
else {
|
|
129
|
-
next.push("");
|
|
130
|
-
}
|
|
131
84
|
});
|
|
132
|
-
//
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
catch (_a) {
|
|
140
|
-
next.push("");
|
|
85
|
+
// Clean up URLs for removed files
|
|
86
|
+
var currentFiles = new Set(localFiles);
|
|
87
|
+
Array.from(map.entries()).forEach(function (_a) {
|
|
88
|
+
var file = _a[0], url = _a[1];
|
|
89
|
+
if (!currentFiles.has(file)) {
|
|
90
|
+
URL.revokeObjectURL(url);
|
|
91
|
+
map.delete(file);
|
|
141
92
|
}
|
|
142
93
|
});
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
return true;
|
|
150
|
-
if (!a || !b)
|
|
151
|
-
return false;
|
|
152
|
-
if (a.length !== b.length)
|
|
153
|
-
return false;
|
|
154
|
-
for (var i = 0; i < a.length; i++)
|
|
155
|
-
if (a[i] !== b[i])
|
|
156
|
-
return false;
|
|
157
|
-
return true;
|
|
158
|
-
};
|
|
159
|
-
var remoteKeysEqual = function (m1, m2) {
|
|
160
|
-
var k1 = Object.keys(m1 || {});
|
|
161
|
-
var k2 = Object.keys(m2 || {});
|
|
162
|
-
if (k1.length !== k2.length)
|
|
163
|
-
return false;
|
|
164
|
-
k1.sort();
|
|
165
|
-
k2.sort();
|
|
166
|
-
for (var i = 0; i < k1.length; i++)
|
|
167
|
-
if (k1[i] !== k2[i])
|
|
168
|
-
return false;
|
|
169
|
-
return true;
|
|
170
|
-
};
|
|
171
|
-
var previewsChanged = !arraysEqual(prev, next);
|
|
172
|
-
var remoteChanged = !remoteKeysEqual(remotePreviewsRef.current || {}, remoteMap);
|
|
173
|
-
if (previewsChanged) {
|
|
174
|
-
setPreviews(next);
|
|
175
|
-
previewsRef.current = next.slice();
|
|
176
|
-
}
|
|
177
|
-
if (remoteChanged) {
|
|
178
|
-
setRemotePreviews(remoteMap);
|
|
179
|
-
remotePreviewsRef.current = __assign({}, remoteMap);
|
|
180
|
-
}
|
|
181
|
-
if (previewsChanged) {
|
|
182
|
-
onPreviewsChange === null || onPreviewsChange === void 0 ? void 0 : onPreviewsChange(next);
|
|
183
|
-
}
|
|
184
|
-
// notify parent about the current rendered previews (object URLs and remote URLs)
|
|
185
|
-
onPreviewsChange === null || onPreviewsChange === void 0 ? void 0 : onPreviewsChange(next);
|
|
94
|
+
}, [localFiles]);
|
|
95
|
+
// Run synchronously on every render to avoid "loading" flash
|
|
96
|
+
createObjectURLs();
|
|
97
|
+
// Cleanup on unmount
|
|
98
|
+
(0, react_1.useEffect)(function () {
|
|
99
|
+
var map = localPreviewsRef.current;
|
|
186
100
|
return function () {
|
|
187
|
-
(
|
|
188
|
-
|
|
189
|
-
URL.revokeObjectURL(u);
|
|
190
|
-
}
|
|
191
|
-
catch (_a) { }
|
|
101
|
+
Array.from(map.values()).forEach(function (url) {
|
|
102
|
+
URL.revokeObjectURL(url);
|
|
192
103
|
});
|
|
193
|
-
|
|
104
|
+
map.clear();
|
|
194
105
|
};
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
if (entry === undefined)
|
|
210
|
-
return;
|
|
211
|
-
var isRemote = Boolean(remotePreviews[entry]);
|
|
212
|
-
if (isRemote) {
|
|
213
|
-
// notify parent and mark as removed so it won't reappear from `initial`
|
|
214
|
-
onRemoveUrl === null || onRemoveUrl === void 0 ? void 0 : onRemoveUrl(entry);
|
|
215
|
-
removedRemoteRef.current.add(entry);
|
|
216
|
-
// remove only the specific preview at previewIndex
|
|
217
|
-
setPreviews(function (p) {
|
|
218
|
-
var next = __spreadArray([], p, true);
|
|
219
|
-
next.splice(previewIndex, 1);
|
|
220
|
-
return next;
|
|
221
|
-
});
|
|
222
|
-
setRemotePreviews(function (m) {
|
|
223
|
-
var next = __assign({}, m);
|
|
224
|
-
delete next[entry];
|
|
225
|
-
return next;
|
|
106
|
+
}, []);
|
|
107
|
+
var dropzoneOptions = {
|
|
108
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
109
|
+
accept: (Array.isArray(accept) ? undefined : accept) || undefined,
|
|
110
|
+
maxFiles: maxFiles,
|
|
111
|
+
maxSize: maxSize,
|
|
112
|
+
minSize: minSize,
|
|
113
|
+
disabled: disabled,
|
|
114
|
+
onDrop: (0, react_1.useCallback)(function (acceptedFiles) {
|
|
115
|
+
setLocalFiles(function (prev) {
|
|
116
|
+
var combined = __spreadArray(__spreadArray([], prev, true), acceptedFiles, true);
|
|
117
|
+
var limited = maxFiles ? combined.slice(0, maxFiles) : combined;
|
|
118
|
+
onChange === null || onChange === void 0 ? void 0 : onChange(limited);
|
|
119
|
+
return limited;
|
|
226
120
|
});
|
|
227
|
-
|
|
228
|
-
var updatedPreviews = previews.filter(function (_, i) { return i !== previewIndex; });
|
|
229
|
-
onPreviewsChange === null || onPreviewsChange === void 0 ? void 0 : onPreviewsChange(updatedPreviews);
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
// local file - compute index relative to files array and remove
|
|
233
|
-
var fileIndex = previewIndex - initial.length;
|
|
234
|
-
if (fileIndex >= 0 && fileIndex < files.length) {
|
|
235
|
-
handleRemoveLocal(fileIndex);
|
|
236
|
-
}
|
|
121
|
+
}, [maxFiles, onChange]),
|
|
237
122
|
};
|
|
238
|
-
|
|
239
|
-
//
|
|
240
|
-
|
|
241
|
-
|
|
123
|
+
var _e = (0, react_dropzone_1.useDropzone)(dropzoneOptions), getRootProps = _e.getRootProps, getInputProps = _e.getInputProps, isDragActive = _e.isDragActive;
|
|
124
|
+
// Remove remote URL
|
|
125
|
+
var handleRemoveRemote = (0, react_1.useCallback)(function (url) {
|
|
126
|
+
onRemoveRemote === null || onRemoveRemote === void 0 ? void 0 : onRemoveRemote(url);
|
|
127
|
+
}, [onRemoveRemote]);
|
|
128
|
+
// Remove local file
|
|
129
|
+
var handleRemoveLocal = (0, react_1.useCallback)(function (index) {
|
|
130
|
+
setLocalFiles(function (prev) {
|
|
131
|
+
var updated = prev.filter(function (_, i) { return i !== index; });
|
|
132
|
+
onChange === null || onChange === void 0 ? void 0 : onChange(updated);
|
|
133
|
+
return updated;
|
|
134
|
+
});
|
|
135
|
+
}, [onChange]);
|
|
136
|
+
// Get all preview URLs (remote + local)
|
|
137
|
+
var allPreviews = __spreadArray(__spreadArray([], value.map(function (url) { return ({ type: "remote", url: url, index: 0 }); }), true), localFiles.map(function (file, index) { return ({
|
|
138
|
+
type: "local",
|
|
139
|
+
url: localPreviewsRef.current.get(file) || "",
|
|
140
|
+
index: index,
|
|
141
|
+
}); }), true);
|
|
142
|
+
return (react_1.default.createElement("div", { className: (0, utils_1.cn)("w-full", className) },
|
|
242
143
|
label && (react_1.default.createElement("label", { className: "mb-2 block text-sm font-medium" }, label)),
|
|
243
|
-
react_1.default.createElement("div", __assign({}, getRootProps(), { className: (0, utils_1.cn)("relative w-full rounded-md border border-dashed p-6 text-center
|
|
144
|
+
react_1.default.createElement("div", __assign({}, getRootProps(), { className: (0, utils_1.cn)("relative w-full rounded-md border border-dashed p-6 text-center min-h-[280px] flex items-center justify-center", isDragActive && "ring-2 ring-ring ring-offset-2", disabled && "opacity-60 pointer-events-none") }),
|
|
244
145
|
react_1.default.createElement("input", __assign({}, getInputProps(), { id: id })),
|
|
245
|
-
|
|
246
|
-
react_1.default.createElement("div", { className: "relative w-
|
|
247
|
-
react_1.default.createElement(
|
|
248
|
-
react_1.default.createElement(carousel_1.
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
react_1.default.createElement(
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
146
|
+
allPreviews.length > 0 ? (react_1.default.createElement("div", { className: "flex flex-col items-center w-full" },
|
|
147
|
+
react_1.default.createElement("div", { className: "relative w-full max-w-md" },
|
|
148
|
+
react_1.default.createElement(carousel_1.Carousel, { className: "w-full" },
|
|
149
|
+
react_1.default.createElement(carousel_1.CarouselPrevious, { type: "button", onClick: function (e) { return e.stopPropagation(); }, onPointerDown: function (e) { return e.stopPropagation(); }, onMouseDown: function (e) { return e.stopPropagation(); } }),
|
|
150
|
+
react_1.default.createElement(carousel_1.CarouselNext, { type: "button", onClick: function (e) { return e.stopPropagation(); }, onPointerDown: function (e) { return e.stopPropagation(); }, onMouseDown: function (e) { return e.stopPropagation(); } }),
|
|
151
|
+
react_1.default.createElement(carousel_1.CarouselContent, { className: "ml-0" }, allPreviews.map(function (preview, idx) { return (react_1.default.createElement(carousel_1.CarouselItem, { key: "".concat(preview.type, "-").concat(preview.url, "-").concat(idx), className: "pl-4" },
|
|
152
|
+
react_1.default.createElement("div", { className: "relative aspect-square w-full max-w-xs mx-auto" }, preview.url ? (react_1.default.createElement(react_1.default.Fragment, null,
|
|
153
|
+
react_1.default.createElement("img", { src: preview.url, alt: "Preview ".concat(idx + 1), className: "h-full w-full rounded-lg object-cover", onClick: function (e) { return e.stopPropagation(); } }),
|
|
154
|
+
react_1.default.createElement(button_1.Button, { type: "button", size: "icon", variant: "destructive", onClick: function (e) {
|
|
155
|
+
e.stopPropagation();
|
|
156
|
+
if (preview.type === "remote") {
|
|
157
|
+
handleRemoveRemote(preview.url);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
handleRemoveLocal(preview.index);
|
|
161
|
+
}
|
|
162
|
+
}, className: "absolute right-2 top-2 h-8 w-8 rounded-full", "aria-label": "Remove image" },
|
|
163
|
+
react_1.default.createElement(lucide_react_1.XIcon, { className: "h-4 w-4" })))) : (react_1.default.createElement("div", { className: "flex h-full w-full items-center justify-center rounded-lg bg-muted text-muted-foreground" },
|
|
164
|
+
react_1.default.createElement("span", { className: "text-sm" }, "Loading...")))))); })))),
|
|
165
|
+
react_1.default.createElement("p", { className: "mt-4 text-sm font-medium text-muted-foreground" },
|
|
166
|
+
allPreviews.length,
|
|
167
|
+
" image",
|
|
168
|
+
allPreviews.length !== 1 ? "s" : "",
|
|
169
|
+
" ",
|
|
170
|
+
"selected"))) : (react_1.default.createElement("div", { className: "flex flex-col items-center justify-center gap-2" },
|
|
171
|
+
react_1.default.createElement("div", { className: "flex h-12 w-12 items-center justify-center rounded-lg bg-muted text-muted-foreground" },
|
|
172
|
+
react_1.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "lucide lucide-image" },
|
|
173
|
+
react_1.default.createElement("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2" }),
|
|
174
|
+
react_1.default.createElement("circle", { cx: "9", cy: "9", r: "2" }),
|
|
175
|
+
react_1.default.createElement("path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" }))),
|
|
176
|
+
react_1.default.createElement("div", { className: "space-y-1 text-center" },
|
|
177
|
+
react_1.default.createElement("p", { className: "font-medium text-sm" },
|
|
178
|
+
"Upload ",
|
|
179
|
+
maxFiles === 1 ? "an image" : "images"),
|
|
180
|
+
react_1.default.createElement("p", { className: "text-muted-foreground text-xs" }, "Drag and drop or click to browse"),
|
|
181
|
+
maxFiles > 1 && (react_1.default.createElement("p", { className: "text-muted-foreground text-xs" },
|
|
182
|
+
"Up to ",
|
|
183
|
+
maxFiles,
|
|
184
|
+
" files")))))),
|
|
268
185
|
(error || info) && (react_1.default.createElement("div", { className: "mt-2" }, error ? (react_1.default.createElement("p", { className: "text-xs text-destructive" }, error)) : info ? (react_1.default.createElement("p", { className: "text-xs text-blue-600 dark:text-blue-400" }, info)) : null))));
|
|
269
186
|
};
|
|
270
187
|
exports.EnhancedDropzone = EnhancedDropzone;
|
package/package.json
CHANGED