@caprionlinesrl/puck-plugin-media 0.1.4

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/index.mjs ADDED
@@ -0,0 +1,2990 @@
1
+ "use client";
2
+
3
+ // src/createMediaPlugin.tsx
4
+ import { Image as Image2 } from "lucide-react";
5
+
6
+ // src/components/ImageField/ImageField.tsx
7
+ import { useState as useState4 } from "react";
8
+ import { createPortal } from "react-dom";
9
+ import { FieldLabel } from "@puckeditor/core";
10
+ import { ImagePlus, X as X4 } from "lucide-react";
11
+
12
+ // src/components/ImagePickerModal/ImagePickerModal.tsx
13
+ import { useState as useState3, useEffect as useEffect4, useCallback as useCallback3 } from "react";
14
+ import { ArrowLeft, Loader2 as Loader25 } from "lucide-react";
15
+
16
+ // src/components/Modal/Modal.tsx
17
+ import { useEffect } from "react";
18
+ import { X, Loader2 } from "lucide-react";
19
+
20
+ // src/components/Modal/Modal.module.css
21
+ var Modal_default = {
22
+ backdrop: "Modal_backdrop",
23
+ fadeIn: "Modal_fadeIn",
24
+ modal: "Modal_modal",
25
+ slideUp: "Modal_slideUp",
26
+ small: "Modal_small",
27
+ header: "Modal_header",
28
+ title: "Modal_title",
29
+ headerActions: "Modal_headerActions",
30
+ closeButton: "Modal_closeButton",
31
+ toolbar: "Modal_toolbar",
32
+ content: "Modal_content",
33
+ loading: "Modal_loading",
34
+ spinner: "Modal_spinner",
35
+ spin: "Modal_spin",
36
+ empty: "Modal_empty",
37
+ footer: "Modal_footer"
38
+ };
39
+
40
+ // src/components/Modal/Modal.tsx
41
+ import { jsx, jsxs } from "react/jsx-runtime";
42
+ function Modal({
43
+ title,
44
+ onClose,
45
+ size = "default",
46
+ headerLeft,
47
+ headerActions,
48
+ toolbar,
49
+ children,
50
+ footer,
51
+ overlay,
52
+ loading = false,
53
+ empty = false,
54
+ emptyMessage = "No items found"
55
+ }) {
56
+ useEffect(() => {
57
+ const handleEscape = (e) => {
58
+ if (e.key === "Escape") {
59
+ onClose();
60
+ }
61
+ };
62
+ window.addEventListener("keydown", handleEscape);
63
+ return () => window.removeEventListener("keydown", handleEscape);
64
+ }, [onClose]);
65
+ useEffect(() => {
66
+ const originalOverflow = document.body.style.overflow;
67
+ document.body.style.overflow = "hidden";
68
+ return () => {
69
+ document.body.style.overflow = originalOverflow;
70
+ };
71
+ }, []);
72
+ const handleBackdropClick = (e) => {
73
+ if (e.target === e.currentTarget) {
74
+ onClose();
75
+ }
76
+ };
77
+ return /* @__PURE__ */ jsx("div", { className: Modal_default.backdrop, onClick: handleBackdropClick, children: /* @__PURE__ */ jsxs(
78
+ "div",
79
+ {
80
+ className: `${Modal_default.modal} ${size === "small" ? Modal_default.small : ""}`,
81
+ role: "dialog",
82
+ "aria-modal": "true",
83
+ "aria-labelledby": "modal-title",
84
+ onClick: (e) => e.stopPropagation(),
85
+ children: [
86
+ /* @__PURE__ */ jsxs("div", { className: Modal_default.header, children: [
87
+ headerLeft,
88
+ /* @__PURE__ */ jsx("h2", { id: "modal-title", className: Modal_default.title, children: title }),
89
+ /* @__PURE__ */ jsxs("div", { className: Modal_default.headerActions, children: [
90
+ headerActions,
91
+ /* @__PURE__ */ jsx(
92
+ "button",
93
+ {
94
+ type: "button",
95
+ onClick: (e) => {
96
+ e.stopPropagation();
97
+ onClose();
98
+ },
99
+ className: Modal_default.closeButton,
100
+ "aria-label": "Close",
101
+ children: /* @__PURE__ */ jsx(X, { size: 20 })
102
+ }
103
+ )
104
+ ] })
105
+ ] }),
106
+ toolbar && /* @__PURE__ */ jsx("div", { className: Modal_default.toolbar, children: toolbar }),
107
+ /* @__PURE__ */ jsx("div", { className: Modal_default.content, children: loading ? /* @__PURE__ */ jsxs("div", { className: Modal_default.loading, children: [
108
+ /* @__PURE__ */ jsx(Loader2, { size: 32, className: Modal_default.spinner }),
109
+ /* @__PURE__ */ jsx("span", { children: "Loading..." })
110
+ ] }) : empty ? /* @__PURE__ */ jsx("div", { className: Modal_default.empty, children: emptyMessage }) : children }),
111
+ footer && /* @__PURE__ */ jsx("div", { className: Modal_default.footer, children: footer }),
112
+ overlay
113
+ ]
114
+ }
115
+ ) });
116
+ }
117
+
118
+ // src/components/SearchBar/SearchBar.tsx
119
+ import { useRef, useEffect as useEffect2 } from "react";
120
+ import { Search, X as X2 } from "lucide-react";
121
+
122
+ // src/components/SearchBar/SearchBar.module.css
123
+ var SearchBar_default = {
124
+ container: "SearchBar_container",
125
+ icon: "SearchBar_icon",
126
+ input: "SearchBar_input",
127
+ clearButton: "SearchBar_clearButton"
128
+ };
129
+
130
+ // src/components/SearchBar/SearchBar.tsx
131
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
132
+ function SearchBar({
133
+ value,
134
+ onChange,
135
+ placeholder = "Search...",
136
+ autoFocus = false
137
+ }) {
138
+ const inputRef = useRef(null);
139
+ useEffect2(() => {
140
+ if (autoFocus && inputRef.current) {
141
+ inputRef.current.focus();
142
+ }
143
+ }, [autoFocus]);
144
+ const handleClear = () => {
145
+ onChange("");
146
+ inputRef.current?.focus();
147
+ };
148
+ return /* @__PURE__ */ jsxs2("div", { className: SearchBar_default.container, children: [
149
+ /* @__PURE__ */ jsx2(Search, { size: 18, className: SearchBar_default.icon }),
150
+ /* @__PURE__ */ jsx2(
151
+ "input",
152
+ {
153
+ ref: inputRef,
154
+ type: "search",
155
+ value,
156
+ onChange: (e) => onChange(e.target.value),
157
+ placeholder,
158
+ className: SearchBar_default.input
159
+ }
160
+ ),
161
+ value && /* @__PURE__ */ jsx2(
162
+ "button",
163
+ {
164
+ type: "button",
165
+ onClick: handleClear,
166
+ className: SearchBar_default.clearButton,
167
+ "aria-label": "Clear search",
168
+ children: /* @__PURE__ */ jsx2(X2, { size: 16 })
169
+ }
170
+ )
171
+ ] });
172
+ }
173
+
174
+ // src/components/LoadMoreButton/LoadMoreButton.tsx
175
+ import { Loader2 as Loader22 } from "lucide-react";
176
+
177
+ // src/components/LoadMoreButton/LoadMoreButton.module.css
178
+ var LoadMoreButton_default = {
179
+ container: "LoadMoreButton_container",
180
+ button: "LoadMoreButton_button",
181
+ spinner: "LoadMoreButton_spinner",
182
+ spin: "LoadMoreButton_spin"
183
+ };
184
+
185
+ // src/components/LoadMoreButton/LoadMoreButton.tsx
186
+ import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
187
+ function LoadMoreButton({ onClick, loading = false }) {
188
+ return /* @__PURE__ */ jsx3("div", { className: LoadMoreButton_default.container, children: /* @__PURE__ */ jsx3(
189
+ "button",
190
+ {
191
+ type: "button",
192
+ onClick,
193
+ disabled: loading,
194
+ className: LoadMoreButton_default.button,
195
+ children: loading ? /* @__PURE__ */ jsxs3(Fragment, { children: [
196
+ /* @__PURE__ */ jsx3(Loader22, { size: 16, className: LoadMoreButton_default.spinner }),
197
+ "Loading..."
198
+ ] }) : "Load more"
199
+ }
200
+ ) });
201
+ }
202
+
203
+ // src/components/ConfirmDialog/ConfirmDialog.tsx
204
+ import { useEffect as useEffect3 } from "react";
205
+ import { Loader2 as Loader23 } from "lucide-react";
206
+
207
+ // src/components/ConfirmDialog/ConfirmDialog.module.css
208
+ var ConfirmDialog_default = {
209
+ overlay: "ConfirmDialog_overlay",
210
+ fadeIn: "ConfirmDialog_fadeIn",
211
+ dialog: "ConfirmDialog_dialog",
212
+ slideUp: "ConfirmDialog_slideUp",
213
+ title: "ConfirmDialog_title",
214
+ message: "ConfirmDialog_message",
215
+ actions: "ConfirmDialog_actions",
216
+ cancelButton: "ConfirmDialog_cancelButton",
217
+ confirmButton: "ConfirmDialog_confirmButton",
218
+ danger: "ConfirmDialog_danger",
219
+ spinner: "ConfirmDialog_spinner",
220
+ spin: "ConfirmDialog_spin"
221
+ };
222
+
223
+ // src/components/ConfirmDialog/ConfirmDialog.tsx
224
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
225
+ function ConfirmDialog({
226
+ title,
227
+ message,
228
+ confirmLabel,
229
+ onConfirm,
230
+ onCancel,
231
+ loading = false,
232
+ variant = "danger"
233
+ }) {
234
+ useEffect3(() => {
235
+ const handleEscape = (e) => {
236
+ if (e.key === "Escape" && !loading) {
237
+ e.stopPropagation();
238
+ onCancel();
239
+ }
240
+ };
241
+ window.addEventListener("keydown", handleEscape);
242
+ return () => window.removeEventListener("keydown", handleEscape);
243
+ }, [onCancel, loading]);
244
+ return /* @__PURE__ */ jsx4("div", { className: ConfirmDialog_default.overlay, children: /* @__PURE__ */ jsxs4("div", { className: ConfirmDialog_default.dialog, children: [
245
+ /* @__PURE__ */ jsx4("h3", { className: ConfirmDialog_default.title, children: title }),
246
+ /* @__PURE__ */ jsx4("p", { className: ConfirmDialog_default.message, children: message }),
247
+ /* @__PURE__ */ jsxs4("div", { className: ConfirmDialog_default.actions, children: [
248
+ /* @__PURE__ */ jsx4(
249
+ "button",
250
+ {
251
+ type: "button",
252
+ onClick: onCancel,
253
+ className: ConfirmDialog_default.cancelButton,
254
+ disabled: loading,
255
+ children: "Cancel"
256
+ }
257
+ ),
258
+ /* @__PURE__ */ jsx4(
259
+ "button",
260
+ {
261
+ type: "button",
262
+ onClick: onConfirm,
263
+ className: `${ConfirmDialog_default.confirmButton} ${variant === "danger" ? ConfirmDialog_default.danger : ""}`,
264
+ disabled: loading,
265
+ children: loading ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
266
+ /* @__PURE__ */ jsx4(Loader23, { size: 16, className: ConfirmDialog_default.spinner }),
267
+ confirmLabel
268
+ ] }) : confirmLabel
269
+ }
270
+ )
271
+ ] })
272
+ ] }) });
273
+ }
274
+
275
+ // src/components/SelectionToolbar/SelectionToolbar.tsx
276
+ import { Check } from "lucide-react";
277
+
278
+ // src/components/SelectionToolbar/SelectionToolbar.module.css
279
+ var SelectionToolbar_default = {
280
+ toolbar: "SelectionToolbar_toolbar",
281
+ selectAllButton: "SelectionToolbar_selectAllButton",
282
+ checkbox: "SelectionToolbar_checkbox",
283
+ checked: "SelectionToolbar_checked",
284
+ indeterminate: "SelectionToolbar_indeterminate",
285
+ indeterminateLine: "SelectionToolbar_indeterminateLine",
286
+ actions: "SelectionToolbar_actions",
287
+ cancelButton: "SelectionToolbar_cancelButton",
288
+ deleteButton: "SelectionToolbar_deleteButton"
289
+ };
290
+
291
+ // src/components/SelectionToolbar/SelectionToolbar.tsx
292
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
293
+ function SelectionToolbar({
294
+ selectedCount,
295
+ totalCount: _totalCount,
296
+ onSelectAll,
297
+ onCancel,
298
+ onDelete,
299
+ isAllSelected,
300
+ isIndeterminate,
301
+ deleteLabel = "Delete"
302
+ }) {
303
+ void _totalCount;
304
+ return /* @__PURE__ */ jsxs5("div", { className: SelectionToolbar_default.toolbar, children: [
305
+ /* @__PURE__ */ jsxs5(
306
+ "button",
307
+ {
308
+ type: "button",
309
+ onClick: onSelectAll,
310
+ className: `${SelectionToolbar_default.selectAllButton} ${isAllSelected ? SelectionToolbar_default.checked : ""} ${isIndeterminate ? SelectionToolbar_default.indeterminate : ""}`,
311
+ "aria-label": isAllSelected ? "Deselect all" : "Select all",
312
+ children: [
313
+ /* @__PURE__ */ jsxs5("div", { className: SelectionToolbar_default.checkbox, children: [
314
+ isAllSelected && /* @__PURE__ */ jsx5(Check, { size: 14, strokeWidth: 3 }),
315
+ isIndeterminate && !isAllSelected && /* @__PURE__ */ jsx5("div", { className: SelectionToolbar_default.indeterminateLine })
316
+ ] }),
317
+ /* @__PURE__ */ jsx5("span", { children: "Select All" })
318
+ ]
319
+ }
320
+ ),
321
+ /* @__PURE__ */ jsxs5("div", { className: SelectionToolbar_default.actions, children: [
322
+ /* @__PURE__ */ jsx5(
323
+ "button",
324
+ {
325
+ type: "button",
326
+ onClick: onCancel,
327
+ className: SelectionToolbar_default.cancelButton,
328
+ children: "Cancel"
329
+ }
330
+ ),
331
+ /* @__PURE__ */ jsxs5(
332
+ "button",
333
+ {
334
+ type: "button",
335
+ onClick: onDelete,
336
+ className: SelectionToolbar_default.deleteButton,
337
+ disabled: selectedCount === 0,
338
+ children: [
339
+ deleteLabel,
340
+ " (",
341
+ selectedCount,
342
+ ")"
343
+ ]
344
+ }
345
+ )
346
+ ] })
347
+ ] });
348
+ }
349
+
350
+ // src/components/ImageGrid/ImageGrid.tsx
351
+ import { Pencil, Check as Check2 } from "lucide-react";
352
+
353
+ // src/components/ImageGrid/ImageGrid.module.css
354
+ var ImageGrid_default = {
355
+ grid: "ImageGrid_grid",
356
+ itemContainer: "ImageGrid_itemContainer",
357
+ item: "ImageGrid_item",
358
+ selected: "ImageGrid_selected",
359
+ imageWrapper: "ImageGrid_imageWrapper",
360
+ image: "ImageGrid_image",
361
+ checkmark: "ImageGrid_checkmark",
362
+ checkbox: "ImageGrid_checkbox",
363
+ checkboxChecked: "ImageGrid_checkboxChecked",
364
+ info: "ImageGrid_info",
365
+ infoRow: "ImageGrid_infoRow",
366
+ infoText: "ImageGrid_infoText",
367
+ filename: "ImageGrid_filename",
368
+ meta: "ImageGrid_meta",
369
+ editButton: "ImageGrid_editButton"
370
+ };
371
+
372
+ // src/components/ImageGrid/ImageGrid.tsx
373
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
374
+ function ImageGrid({
375
+ items,
376
+ onSelect,
377
+ selectedId,
378
+ onEditAlt,
379
+ manageMode = false,
380
+ selectedIds,
381
+ onToggleSelect
382
+ }) {
383
+ const formatFileSize2 = (bytes) => {
384
+ if (!bytes) return "";
385
+ if (bytes < 1024) return `${bytes} B`;
386
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
387
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
388
+ };
389
+ const handleItemClick = (item) => {
390
+ if (manageMode && onToggleSelect) {
391
+ onToggleSelect(item);
392
+ } else {
393
+ onSelect(item);
394
+ }
395
+ };
396
+ const handleEditClick = (e, item) => {
397
+ e.stopPropagation();
398
+ onEditAlt?.(item);
399
+ };
400
+ const isSelected = (item) => {
401
+ if (manageMode) {
402
+ return selectedIds?.has(item.id) ?? false;
403
+ }
404
+ return selectedId === item.id;
405
+ };
406
+ return /* @__PURE__ */ jsx6("div", { className: ImageGrid_default.grid, children: items.map((item) => {
407
+ const selected = isSelected(item);
408
+ const isSelectedForInsert = !manageMode && selectedId === item.id;
409
+ return /* @__PURE__ */ jsxs6("div", { className: ImageGrid_default.itemContainer, children: [
410
+ /* @__PURE__ */ jsx6(
411
+ "button",
412
+ {
413
+ type: "button",
414
+ onClick: () => handleItemClick(item),
415
+ className: `${ImageGrid_default.item} ${isSelectedForInsert ? ImageGrid_default.selected : ""}`,
416
+ title: item.filename,
417
+ children: /* @__PURE__ */ jsxs6("div", { className: ImageGrid_default.imageWrapper, children: [
418
+ /* @__PURE__ */ jsx6(
419
+ "img",
420
+ {
421
+ src: item.thumbnailUrl || item.url,
422
+ alt: item.filename || "",
423
+ className: ImageGrid_default.image,
424
+ loading: "lazy"
425
+ }
426
+ ),
427
+ manageMode && /* @__PURE__ */ jsx6("div", { className: `${ImageGrid_default.checkbox} ${selected ? ImageGrid_default.checkboxChecked : ""}`, children: selected && /* @__PURE__ */ jsx6(Check2, { size: 14, strokeWidth: 3 }) }),
428
+ isSelectedForInsert && /* @__PURE__ */ jsx6("div", { className: ImageGrid_default.checkmark, children: /* @__PURE__ */ jsx6(
429
+ "svg",
430
+ {
431
+ width: "16",
432
+ height: "16",
433
+ viewBox: "0 0 16 16",
434
+ fill: "none",
435
+ xmlns: "http://www.w3.org/2000/svg",
436
+ children: /* @__PURE__ */ jsx6(
437
+ "path",
438
+ {
439
+ d: "M13.5 4.5L6 12L2.5 8.5",
440
+ stroke: "currentColor",
441
+ strokeWidth: "2",
442
+ strokeLinecap: "round",
443
+ strokeLinejoin: "round"
444
+ }
445
+ )
446
+ }
447
+ ) })
448
+ ] })
449
+ }
450
+ ),
451
+ /* @__PURE__ */ jsx6("div", { className: ImageGrid_default.info, children: /* @__PURE__ */ jsxs6("div", { className: ImageGrid_default.infoRow, children: [
452
+ /* @__PURE__ */ jsxs6("div", { className: ImageGrid_default.infoText, children: [
453
+ item.filename && /* @__PURE__ */ jsx6("span", { className: ImageGrid_default.filename, children: item.filename }),
454
+ /* @__PURE__ */ jsxs6("span", { className: ImageGrid_default.meta, children: [
455
+ item.width && item.height && /* @__PURE__ */ jsxs6("span", { children: [
456
+ item.width,
457
+ "\xD7",
458
+ item.height
459
+ ] }),
460
+ item.size && /* @__PURE__ */ jsx6("span", { children: formatFileSize2(item.size) })
461
+ ] })
462
+ ] }),
463
+ !manageMode && onEditAlt && /* @__PURE__ */ jsx6(
464
+ "button",
465
+ {
466
+ type: "button",
467
+ onClick: (e) => handleEditClick(e, item),
468
+ className: ImageGrid_default.editButton,
469
+ "aria-label": "Edit alt",
470
+ children: /* @__PURE__ */ jsx6(Pencil, { size: 14 })
471
+ }
472
+ )
473
+ ] }) })
474
+ ] }, item.id);
475
+ }) });
476
+ }
477
+
478
+ // src/components/UploadDropzone/UploadDropzone.tsx
479
+ import { useState as useState2, useRef as useRef3, useCallback as useCallback2 } from "react";
480
+ import { Upload } from "lucide-react";
481
+
482
+ // src/hooks/useUpload.ts
483
+ import { useState, useCallback, useRef as useRef2 } from "react";
484
+ var DEFAULT_CONFIG = {
485
+ accept: "image/*",
486
+ maxSize: 10 * 1024 * 1024,
487
+ // 10MB
488
+ multiple: true
489
+ };
490
+ var MAX_CONCURRENT_UPLOADS = 3;
491
+ var generateId = () => `upload-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
492
+ var formatFileSize = (bytes) => {
493
+ if (bytes < 1024) return `${bytes} B`;
494
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
495
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
496
+ };
497
+ var validateFile = (file, config) => {
498
+ if (file.size > config.maxSize) {
499
+ return {
500
+ valid: false,
501
+ error: `File too large. Maximum size is ${formatFileSize(config.maxSize)}`
502
+ };
503
+ }
504
+ const acceptedTypes = config.accept.split(",").map((t) => t.trim());
505
+ const isAccepted = acceptedTypes.some((type) => {
506
+ if (type === "*/*" || type === "*") return true;
507
+ if (type.endsWith("/*")) {
508
+ const category = type.slice(0, -2);
509
+ return file.type.startsWith(category);
510
+ }
511
+ if (type.startsWith(".")) {
512
+ return file.name.toLowerCase().endsWith(type.toLowerCase());
513
+ }
514
+ return file.type === type;
515
+ });
516
+ if (!isAccepted) {
517
+ return {
518
+ valid: false,
519
+ error: `File type not accepted. Accepted types: ${config.accept}`
520
+ };
521
+ }
522
+ return { valid: true };
523
+ };
524
+ var createPreviewUrl = (file) => {
525
+ if (file.type.startsWith("image/")) {
526
+ return URL.createObjectURL(file);
527
+ }
528
+ return void 0;
529
+ };
530
+ function useUpload({
531
+ upload,
532
+ config,
533
+ onUploadComplete
534
+ }) {
535
+ const [uploading, setUploading] = useState([]);
536
+ const activeUploadsRef = useRef2(/* @__PURE__ */ new Set());
537
+ const uploadConfig = { ...DEFAULT_CONFIG, ...config };
538
+ const startUpload = useCallback(
539
+ async (id, file) => {
540
+ try {
541
+ const result = await upload(file, {
542
+ onProgress: (percent) => {
543
+ setUploading(
544
+ (current) => current.map((f) => f.id === id ? { ...f, progress: percent } : f)
545
+ );
546
+ }
547
+ });
548
+ const singleResult = Array.isArray(result) ? result[0] : result;
549
+ setUploading(
550
+ (current) => current.map(
551
+ (f) => f.id === id ? { ...f, status: "completed", progress: 100, result: singleResult } : f
552
+ )
553
+ );
554
+ onUploadComplete?.(singleResult);
555
+ } catch (error) {
556
+ const errorMessage = error instanceof Error ? error.message : "Upload failed";
557
+ setUploading(
558
+ (current) => current.map(
559
+ (f) => f.id === id ? { ...f, status: "error", error: errorMessage } : f
560
+ )
561
+ );
562
+ } finally {
563
+ activeUploadsRef.current.delete(id);
564
+ processQueue();
565
+ }
566
+ },
567
+ [upload, onUploadComplete]
568
+ );
569
+ const processQueue = useCallback(() => {
570
+ setUploading((current) => {
571
+ const pending = current.filter(
572
+ (f) => f.status === "pending" && !activeUploadsRef.current.has(f.id)
573
+ );
574
+ const activeCount = activeUploadsRef.current.size;
575
+ const slotsAvailable = MAX_CONCURRENT_UPLOADS - activeCount;
576
+ if (slotsAvailable <= 0 || pending.length === 0) {
577
+ return current;
578
+ }
579
+ const toStart = pending.slice(0, slotsAvailable);
580
+ toStart.forEach((file) => {
581
+ activeUploadsRef.current.add(file.id);
582
+ startUpload(file.id, file.file);
583
+ });
584
+ return current.map(
585
+ (f) => toStart.some((t) => t.id === f.id) ? { ...f, status: "uploading" } : f
586
+ );
587
+ });
588
+ }, [startUpload]);
589
+ const addFiles = useCallback(
590
+ (files) => {
591
+ const fileArray = Array.from(files);
592
+ const filesToAdd = uploadConfig.multiple ? fileArray : fileArray.slice(0, 1);
593
+ const newUploads = filesToAdd.map((file) => {
594
+ const validation = validateFile(file, uploadConfig);
595
+ const previewUrl = createPreviewUrl(file);
596
+ return {
597
+ id: generateId(),
598
+ file,
599
+ progress: 0,
600
+ status: validation.valid ? "pending" : "error",
601
+ error: validation.error,
602
+ previewUrl
603
+ };
604
+ });
605
+ setUploading((current) => [...newUploads, ...current]);
606
+ setTimeout(processQueue, 0);
607
+ },
608
+ [uploadConfig, processQueue]
609
+ );
610
+ const cancelUpload = useCallback((id) => {
611
+ setUploading((current) => {
612
+ const file = current.find((f) => f.id === id);
613
+ if (file?.previewUrl) {
614
+ URL.revokeObjectURL(file.previewUrl);
615
+ }
616
+ return current.filter((f) => f.id !== id);
617
+ });
618
+ activeUploadsRef.current.delete(id);
619
+ }, []);
620
+ const clearCompleted = useCallback(() => {
621
+ setUploading((current) => {
622
+ current.filter((f) => f.status === "completed" || f.status === "error").forEach((f) => {
623
+ if (f.previewUrl) {
624
+ URL.revokeObjectURL(f.previewUrl);
625
+ }
626
+ });
627
+ return current.filter((f) => f.status === "pending" || f.status === "uploading");
628
+ });
629
+ }, []);
630
+ const isUploading = uploading.some(
631
+ (f) => f.status === "pending" || f.status === "uploading"
632
+ );
633
+ return {
634
+ uploading,
635
+ isUploading,
636
+ addFiles,
637
+ cancelUpload,
638
+ clearCompleted,
639
+ uploadConfig
640
+ };
641
+ }
642
+
643
+ // src/components/UploadDropzone/UploadDropzone.module.css
644
+ var UploadDropzone_default = {
645
+ dropzone: "UploadDropzone_dropzone",
646
+ disabled: "UploadDropzone_disabled",
647
+ dragging: "UploadDropzone_dragging",
648
+ input: "UploadDropzone_input",
649
+ icon: "UploadDropzone_icon",
650
+ text: "UploadDropzone_text",
651
+ hint: "UploadDropzone_hint"
652
+ };
653
+
654
+ // src/components/UploadDropzone/UploadDropzone.tsx
655
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
656
+ function UploadDropzone({
657
+ onFilesSelected,
658
+ config,
659
+ disabled = false
660
+ }) {
661
+ const [isDragging, setIsDragging] = useState2(false);
662
+ const inputRef = useRef3(null);
663
+ const dragCounterRef = useRef3(0);
664
+ const handleDragEnter = useCallback2((e) => {
665
+ e.preventDefault();
666
+ e.stopPropagation();
667
+ dragCounterRef.current++;
668
+ if (e.dataTransfer.items && e.dataTransfer.items.length > 0) {
669
+ setIsDragging(true);
670
+ }
671
+ }, []);
672
+ const handleDragLeave = useCallback2((e) => {
673
+ e.preventDefault();
674
+ e.stopPropagation();
675
+ dragCounterRef.current--;
676
+ if (dragCounterRef.current === 0) {
677
+ setIsDragging(false);
678
+ }
679
+ }, []);
680
+ const handleDragOver = useCallback2((e) => {
681
+ e.preventDefault();
682
+ e.stopPropagation();
683
+ }, []);
684
+ const handleDrop = useCallback2(
685
+ (e) => {
686
+ e.preventDefault();
687
+ e.stopPropagation();
688
+ setIsDragging(false);
689
+ dragCounterRef.current = 0;
690
+ if (disabled) return;
691
+ const { files } = e.dataTransfer;
692
+ if (files && files.length > 0) {
693
+ onFilesSelected(files);
694
+ }
695
+ },
696
+ [disabled, onFilesSelected]
697
+ );
698
+ const handleClick = useCallback2(() => {
699
+ if (!disabled && inputRef.current) {
700
+ inputRef.current.click();
701
+ }
702
+ }, [disabled]);
703
+ const handleInputChange = useCallback2(
704
+ (e) => {
705
+ const { files } = e.target;
706
+ if (files && files.length > 0) {
707
+ onFilesSelected(files);
708
+ e.target.value = "";
709
+ }
710
+ },
711
+ [onFilesSelected]
712
+ );
713
+ const formatAcceptedTypes = (accept) => {
714
+ const types = accept.split(",").map((t) => t.trim());
715
+ const formatted = types.map((type) => {
716
+ if (type === "image/*") return "Images";
717
+ if (type === "image/jpeg") return "JPG";
718
+ if (type === "image/png") return "PNG";
719
+ if (type === "image/gif") return "GIF";
720
+ if (type === "image/webp") return "WebP";
721
+ if (type === "image/svg+xml") return "SVG";
722
+ return type.replace("image/", "").toUpperCase();
723
+ });
724
+ return formatted.join(", ");
725
+ };
726
+ return /* @__PURE__ */ jsxs7(
727
+ "div",
728
+ {
729
+ className: `${UploadDropzone_default.dropzone} ${isDragging ? UploadDropzone_default.dragging : ""} ${disabled ? UploadDropzone_default.disabled : ""}`,
730
+ onDragEnter: handleDragEnter,
731
+ onDragLeave: handleDragLeave,
732
+ onDragOver: handleDragOver,
733
+ onDrop: handleDrop,
734
+ onClick: handleClick,
735
+ role: "button",
736
+ tabIndex: disabled ? -1 : 0,
737
+ onKeyDown: (e) => {
738
+ if (e.key === "Enter" || e.key === " ") {
739
+ e.preventDefault();
740
+ handleClick();
741
+ }
742
+ },
743
+ children: [
744
+ /* @__PURE__ */ jsx7(
745
+ "input",
746
+ {
747
+ ref: inputRef,
748
+ type: "file",
749
+ accept: config.accept,
750
+ multiple: config.multiple,
751
+ onChange: handleInputChange,
752
+ className: UploadDropzone_default.input,
753
+ disabled
754
+ }
755
+ ),
756
+ /* @__PURE__ */ jsx7(Upload, { size: 24, className: UploadDropzone_default.icon }),
757
+ /* @__PURE__ */ jsx7("span", { className: UploadDropzone_default.text, children: isDragging ? "Drop files here" : "Drop files here or click to upload" }),
758
+ /* @__PURE__ */ jsxs7("span", { className: UploadDropzone_default.hint, children: [
759
+ formatAcceptedTypes(config.accept),
760
+ " (max ",
761
+ formatFileSize(config.maxSize),
762
+ ")"
763
+ ] })
764
+ ]
765
+ }
766
+ );
767
+ }
768
+
769
+ // src/components/UploadQueue/UploadQueue.tsx
770
+ import { X as X3, CheckCircle, AlertCircle, Loader2 as Loader24 } from "lucide-react";
771
+
772
+ // src/components/UploadQueue/UploadQueue.module.css
773
+ var UploadQueue_default = {
774
+ container: "UploadQueue_container",
775
+ header: "UploadQueue_header",
776
+ title: "UploadQueue_title",
777
+ clearButton: "UploadQueue_clearButton",
778
+ list: "UploadQueue_list",
779
+ item: "UploadQueue_item",
780
+ preview: "UploadQueue_preview",
781
+ previewImage: "UploadQueue_previewImage",
782
+ previewPlaceholder: "UploadQueue_previewPlaceholder",
783
+ progressOverlay: "UploadQueue_progressOverlay",
784
+ progressBar: "UploadQueue_progressBar",
785
+ progressText: "UploadQueue_progressText",
786
+ info: "UploadQueue_info",
787
+ filename: "UploadQueue_filename",
788
+ size: "UploadQueue_size",
789
+ error: "UploadQueue_error",
790
+ actions: "UploadQueue_actions",
791
+ cancelButton: "UploadQueue_cancelButton",
792
+ spinner: "UploadQueue_spinner",
793
+ spin: "UploadQueue_spin",
794
+ successIcon: "UploadQueue_successIcon",
795
+ errorIcon: "UploadQueue_errorIcon",
796
+ completed: "UploadQueue_completed"
797
+ };
798
+
799
+ // src/components/UploadQueue/UploadQueue.tsx
800
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
801
+ function UploadQueue({ files, onCancel, onClearCompleted }) {
802
+ if (files.length === 0) return null;
803
+ const hasCompleted = files.some((f) => f.status === "completed" || f.status === "error");
804
+ return /* @__PURE__ */ jsxs8("div", { className: UploadQueue_default.container, children: [
805
+ /* @__PURE__ */ jsxs8("div", { className: UploadQueue_default.header, children: [
806
+ /* @__PURE__ */ jsxs8("span", { className: UploadQueue_default.title, children: [
807
+ "Uploading (",
808
+ files.filter((f) => f.status === "uploading" || f.status === "pending").length,
809
+ ")"
810
+ ] }),
811
+ hasCompleted && /* @__PURE__ */ jsx8(
812
+ "button",
813
+ {
814
+ type: "button",
815
+ onClick: onClearCompleted,
816
+ className: UploadQueue_default.clearButton,
817
+ children: "Clear completed"
818
+ }
819
+ )
820
+ ] }),
821
+ /* @__PURE__ */ jsx8("div", { className: UploadQueue_default.list, children: files.map((file) => /* @__PURE__ */ jsx8(UploadItem, { file, onCancel: () => onCancel(file.id) }, file.id)) })
822
+ ] });
823
+ }
824
+ function UploadItem({ file, onCancel }) {
825
+ return /* @__PURE__ */ jsxs8("div", { className: `${UploadQueue_default.item} ${UploadQueue_default[file.status]}`, children: [
826
+ /* @__PURE__ */ jsxs8("div", { className: UploadQueue_default.preview, children: [
827
+ file.previewUrl ? /* @__PURE__ */ jsx8("img", { src: file.previewUrl, alt: "", className: UploadQueue_default.previewImage }) : /* @__PURE__ */ jsx8("div", { className: UploadQueue_default.previewPlaceholder }),
828
+ file.status === "uploading" && /* @__PURE__ */ jsxs8("div", { className: UploadQueue_default.progressOverlay, children: [
829
+ /* @__PURE__ */ jsx8(
830
+ "div",
831
+ {
832
+ className: UploadQueue_default.progressBar,
833
+ style: { height: `${100 - file.progress}%` }
834
+ }
835
+ ),
836
+ /* @__PURE__ */ jsxs8("span", { className: UploadQueue_default.progressText, children: [
837
+ file.progress,
838
+ "%"
839
+ ] })
840
+ ] })
841
+ ] }),
842
+ /* @__PURE__ */ jsxs8("div", { className: UploadQueue_default.info, children: [
843
+ /* @__PURE__ */ jsx8("span", { className: UploadQueue_default.filename, title: file.file.name, children: file.file.name }),
844
+ /* @__PURE__ */ jsx8("span", { className: UploadQueue_default.size, children: formatFileSize(file.file.size) }),
845
+ file.error && /* @__PURE__ */ jsx8("span", { className: UploadQueue_default.error, children: file.error })
846
+ ] }),
847
+ /* @__PURE__ */ jsxs8("div", { className: UploadQueue_default.actions, children: [
848
+ file.status === "pending" && /* @__PURE__ */ jsx8(
849
+ "button",
850
+ {
851
+ type: "button",
852
+ onClick: onCancel,
853
+ className: UploadQueue_default.cancelButton,
854
+ "aria-label": "Cancel upload",
855
+ children: /* @__PURE__ */ jsx8(X3, { size: 16 })
856
+ }
857
+ ),
858
+ file.status === "uploading" && /* @__PURE__ */ jsx8(Loader24, { size: 18, className: UploadQueue_default.spinner }),
859
+ file.status === "completed" && /* @__PURE__ */ jsx8(CheckCircle, { size: 18, className: UploadQueue_default.successIcon }),
860
+ file.status === "error" && /* @__PURE__ */ jsx8(AlertCircle, { size: 18, className: UploadQueue_default.errorIcon })
861
+ ] })
862
+ ] });
863
+ }
864
+
865
+ // src/components/ImagePickerModal/ImagePickerModal.module.css
866
+ var ImagePickerModal_default = {
867
+ backButton: "ImagePickerModal_backButton",
868
+ selectModeButton: "ImagePickerModal_selectModeButton",
869
+ toolbar: "ImagePickerModal_toolbar",
870
+ uploadSection: "ImagePickerModal_uploadSection",
871
+ footer: "ImagePickerModal_footer",
872
+ footerInfo: "ImagePickerModal_footerInfo",
873
+ footerImage: "ImagePickerModal_footerImage",
874
+ footerFilename: "ImagePickerModal_footerFilename",
875
+ footerMeta: "ImagePickerModal_footerMeta",
876
+ selectButton: "ImagePickerModal_selectButton",
877
+ editContent: "ImagePickerModal_editContent",
878
+ editPreview: "ImagePickerModal_editPreview",
879
+ editImage: "ImagePickerModal_editImage",
880
+ editInfo: "ImagePickerModal_editInfo",
881
+ editInfoRow: "ImagePickerModal_editInfoRow",
882
+ editInfoLabel: "ImagePickerModal_editInfoLabel",
883
+ editInfoValue: "ImagePickerModal_editInfoValue",
884
+ editField: "ImagePickerModal_editField",
885
+ editFieldHeader: "ImagePickerModal_editFieldHeader",
886
+ editFieldLabel: "ImagePickerModal_editFieldLabel",
887
+ langTabs: "ImagePickerModal_langTabs",
888
+ langTab: "ImagePickerModal_langTab",
889
+ langTabActive: "ImagePickerModal_langTabActive",
890
+ editInput: "ImagePickerModal_editInput",
891
+ editFooter: "ImagePickerModal_editFooter",
892
+ saveButton: "ImagePickerModal_saveButton",
893
+ spinner: "ImagePickerModal_spinner",
894
+ spin: "ImagePickerModal_spin"
895
+ };
896
+
897
+ // src/components/ImagePickerModal/ImagePickerModal.tsx
898
+ import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
899
+ var DEFAULT_UPLOAD_CONFIG = {
900
+ accept: "image/*",
901
+ maxSize: 10 * 1024 * 1024,
902
+ multiple: true
903
+ };
904
+ var PAGE_SIZE = 20;
905
+ function ImagePickerModal({
906
+ languages,
907
+ imageOptions,
908
+ title = "Select Image",
909
+ selectedImage,
910
+ onSelect,
911
+ onClose,
912
+ selectable = true
913
+ }) {
914
+ const { fetchList, upload, update, delete: deleteImage, uploadConfig } = imageOptions;
915
+ const [view, setView] = useState3("picker");
916
+ const [editingItem, setEditingItem] = useState3(null);
917
+ const [selectMode, setSelectMode] = useState3(false);
918
+ const [selectedForDelete, setSelectedForDelete] = useState3(/* @__PURE__ */ new Set());
919
+ const [items, setItems] = useState3([]);
920
+ const [search, setSearch] = useState3("");
921
+ const [loading, setLoading] = useState3(true);
922
+ const [page, setPage] = useState3(1);
923
+ const [hasMore, setHasMore] = useState3(false);
924
+ const [selectedItem, setSelectedItem] = useState3(null);
925
+ const [altValues, setAltValues] = useState3({});
926
+ const [activeLang, setActiveLang] = useState3(languages[0]?.code || "it");
927
+ const [isSaving, setIsSaving] = useState3(false);
928
+ const [showDeleteConfirm, setShowDeleteConfirm] = useState3(false);
929
+ const [isDeleting, setIsDeleting] = useState3(false);
930
+ const canUpload = !!upload;
931
+ const {
932
+ uploading,
933
+ isUploading,
934
+ addFiles,
935
+ cancelUpload,
936
+ clearCompleted,
937
+ uploadConfig: mergedUploadConfig
938
+ } = useUpload({
939
+ upload: upload || (async () => {
940
+ throw new Error("Upload not configured");
941
+ }),
942
+ config: uploadConfig || DEFAULT_UPLOAD_CONFIG,
943
+ onUploadComplete: (newItem) => {
944
+ setItems((prev) => [newItem, ...prev]);
945
+ }
946
+ });
947
+ const loadItems = useCallback3(
948
+ async (searchQuery, pageNum, append = false) => {
949
+ setLoading(true);
950
+ try {
951
+ const result = await fetchList({
952
+ query: searchQuery || void 0,
953
+ page: pageNum,
954
+ pageSize: PAGE_SIZE
955
+ });
956
+ const newItems = Array.isArray(result) ? result : result.items;
957
+ const more = Array.isArray(result) ? newItems.length === PAGE_SIZE : result.hasMore ?? false;
958
+ setItems((prev) => append ? [...prev, ...newItems] : newItems);
959
+ setHasMore(more);
960
+ } catch (error) {
961
+ console.error("Failed to fetch images:", error);
962
+ setItems([]);
963
+ setHasMore(false);
964
+ } finally {
965
+ setLoading(false);
966
+ }
967
+ },
968
+ [fetchList]
969
+ );
970
+ useEffect4(() => {
971
+ const timer = setTimeout(() => {
972
+ setPage(1);
973
+ loadItems(search, 1);
974
+ }, 300);
975
+ return () => clearTimeout(timer);
976
+ }, [search, loadItems]);
977
+ useEffect4(() => {
978
+ if (selectedImage) {
979
+ const existingItem = items.find((item) => item.id === selectedImage.id);
980
+ if (existingItem) {
981
+ setSelectedItem(existingItem);
982
+ }
983
+ }
984
+ }, [selectedImage, items]);
985
+ const handleClose = useCallback3(() => {
986
+ onClose();
987
+ }, [onClose]);
988
+ const handleLoadMore = () => {
989
+ const nextPage = page + 1;
990
+ setPage(nextPage);
991
+ loadItems(search, nextPage, true);
992
+ };
993
+ const handleImageClick = (item) => {
994
+ if (selectedItem?.id === item.id) {
995
+ setSelectedItem(null);
996
+ } else {
997
+ setSelectedItem(item);
998
+ }
999
+ };
1000
+ const handleConfirmSelection = () => {
1001
+ if (!selectedItem || !onSelect) return;
1002
+ onSelect(selectedItem);
1003
+ };
1004
+ const handleEditAlt = (item) => {
1005
+ setEditingItem(item);
1006
+ setAltValues(item.alt || {});
1007
+ setActiveLang(languages[0]?.code || "it");
1008
+ setView("edit");
1009
+ };
1010
+ const handleAltChange = (langCode, value) => {
1011
+ setAltValues((prev) => ({
1012
+ ...prev,
1013
+ [langCode]: value
1014
+ }));
1015
+ };
1016
+ const handleSaveAlt = async () => {
1017
+ if (!editingItem || !update) return;
1018
+ setIsSaving(true);
1019
+ try {
1020
+ await update(editingItem.id, { alt: altValues });
1021
+ setItems(
1022
+ (prev) => prev.map(
1023
+ (item) => item.id === editingItem.id ? { ...item, alt: altValues } : item
1024
+ )
1025
+ );
1026
+ if (selectedItem?.id === editingItem.id) {
1027
+ setSelectedItem((prev) => prev ? { ...prev, alt: altValues } : null);
1028
+ }
1029
+ setView("picker");
1030
+ setEditingItem(null);
1031
+ setAltValues({});
1032
+ } catch (error) {
1033
+ console.error("Failed to update alt text:", error);
1034
+ } finally {
1035
+ setIsSaving(false);
1036
+ }
1037
+ };
1038
+ const handleToggleSelect = (item) => {
1039
+ setSelectedForDelete((prev) => {
1040
+ const newSet = new Set(prev);
1041
+ if (newSet.has(item.id)) {
1042
+ newSet.delete(item.id);
1043
+ } else {
1044
+ newSet.add(item.id);
1045
+ }
1046
+ return newSet;
1047
+ });
1048
+ };
1049
+ const handleSelectAll = () => {
1050
+ if (selectedForDelete.size === items.length) {
1051
+ setSelectedForDelete(/* @__PURE__ */ new Set());
1052
+ } else {
1053
+ setSelectedForDelete(new Set(items.map((item) => item.id)));
1054
+ }
1055
+ };
1056
+ const handleConfirmDelete = async () => {
1057
+ if (!deleteImage || selectedForDelete.size === 0) return;
1058
+ setIsDeleting(true);
1059
+ try {
1060
+ const deletePromises = Array.from(selectedForDelete).map((id) => deleteImage(id));
1061
+ await Promise.all(deletePromises);
1062
+ setItems((prev) => prev.filter((item) => !selectedForDelete.has(item.id)));
1063
+ if (selectedItem && selectedForDelete.has(selectedItem.id)) {
1064
+ setSelectedItem(null);
1065
+ }
1066
+ setShowDeleteConfirm(false);
1067
+ setSelectedForDelete(/* @__PURE__ */ new Set());
1068
+ setSelectMode(false);
1069
+ } catch (error) {
1070
+ console.error("Failed to delete images:", error);
1071
+ } finally {
1072
+ setIsDeleting(false);
1073
+ }
1074
+ };
1075
+ const formatFileSize2 = (bytes) => {
1076
+ if (!bytes) return "";
1077
+ if (bytes < 1024) return `${bytes} B`;
1078
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
1079
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
1080
+ };
1081
+ const isAllSelected = items.length > 0 && selectedForDelete.size === items.length;
1082
+ const isSomeSelected = selectedForDelete.size > 0 && selectedForDelete.size < items.length;
1083
+ if (view === "edit" && editingItem) {
1084
+ return /* @__PURE__ */ jsx9(
1085
+ Modal,
1086
+ {
1087
+ title: "Edit Image Details",
1088
+ onClose: handleClose,
1089
+ headerLeft: /* @__PURE__ */ jsx9(
1090
+ "button",
1091
+ {
1092
+ type: "button",
1093
+ onClick: () => {
1094
+ setView("picker");
1095
+ setEditingItem(null);
1096
+ setAltValues({});
1097
+ },
1098
+ className: ImagePickerModal_default.backButton,
1099
+ "aria-label": "Back to grid",
1100
+ children: /* @__PURE__ */ jsx9(ArrowLeft, { size: 20 })
1101
+ }
1102
+ ),
1103
+ footer: /* @__PURE__ */ jsxs9("div", { className: ImagePickerModal_default.editFooter, children: [
1104
+ /* @__PURE__ */ jsx9("div", {}),
1105
+ /* @__PURE__ */ jsx9(
1106
+ "button",
1107
+ {
1108
+ type: "button",
1109
+ onClick: handleSaveAlt,
1110
+ className: ImagePickerModal_default.saveButton,
1111
+ disabled: isSaving || !update,
1112
+ children: isSaving ? /* @__PURE__ */ jsxs9(Fragment3, { children: [
1113
+ /* @__PURE__ */ jsx9(Loader25, { size: 16, className: ImagePickerModal_default.spinner }),
1114
+ "Saving..."
1115
+ ] }) : "Save"
1116
+ }
1117
+ )
1118
+ ] }),
1119
+ children: /* @__PURE__ */ jsxs9("div", { className: ImagePickerModal_default.editContent, children: [
1120
+ /* @__PURE__ */ jsx9("div", { className: ImagePickerModal_default.editPreview, children: /* @__PURE__ */ jsx9(
1121
+ "img",
1122
+ {
1123
+ src: editingItem.url,
1124
+ alt: editingItem.filename || "",
1125
+ className: ImagePickerModal_default.editImage
1126
+ }
1127
+ ) }),
1128
+ /* @__PURE__ */ jsxs9("div", { className: ImagePickerModal_default.editInfo, children: [
1129
+ /* @__PURE__ */ jsxs9("div", { className: ImagePickerModal_default.editInfoRow, children: [
1130
+ /* @__PURE__ */ jsx9("span", { className: ImagePickerModal_default.editInfoLabel, children: "Filename" }),
1131
+ /* @__PURE__ */ jsx9("span", { className: ImagePickerModal_default.editInfoValue, children: editingItem.filename })
1132
+ ] }),
1133
+ editingItem.width && editingItem.height && /* @__PURE__ */ jsxs9("div", { className: ImagePickerModal_default.editInfoRow, children: [
1134
+ /* @__PURE__ */ jsx9("span", { className: ImagePickerModal_default.editInfoLabel, children: "Dimensions" }),
1135
+ /* @__PURE__ */ jsxs9("span", { className: ImagePickerModal_default.editInfoValue, children: [
1136
+ editingItem.width,
1137
+ "\xD7",
1138
+ editingItem.height
1139
+ ] })
1140
+ ] }),
1141
+ editingItem.size && /* @__PURE__ */ jsxs9("div", { className: ImagePickerModal_default.editInfoRow, children: [
1142
+ /* @__PURE__ */ jsx9("span", { className: ImagePickerModal_default.editInfoLabel, children: "Size" }),
1143
+ /* @__PURE__ */ jsx9("span", { className: ImagePickerModal_default.editInfoValue, children: formatFileSize2(editingItem.size) })
1144
+ ] })
1145
+ ] }),
1146
+ /* @__PURE__ */ jsxs9("div", { className: ImagePickerModal_default.editField, children: [
1147
+ /* @__PURE__ */ jsxs9("div", { className: ImagePickerModal_default.editFieldHeader, children: [
1148
+ /* @__PURE__ */ jsx9("label", { className: ImagePickerModal_default.editFieldLabel, children: "Alt" }),
1149
+ /* @__PURE__ */ jsx9("div", { className: ImagePickerModal_default.langTabs, children: languages.map((lang) => /* @__PURE__ */ jsx9(
1150
+ "button",
1151
+ {
1152
+ type: "button",
1153
+ onClick: () => setActiveLang(lang.code),
1154
+ className: `${ImagePickerModal_default.langTab} ${activeLang === lang.code ? ImagePickerModal_default.langTabActive : ""}`,
1155
+ children: lang.code.toUpperCase()
1156
+ },
1157
+ lang.code
1158
+ )) })
1159
+ ] }),
1160
+ /* @__PURE__ */ jsx9(
1161
+ "input",
1162
+ {
1163
+ type: "text",
1164
+ value: altValues[activeLang] || "",
1165
+ onChange: (e) => handleAltChange(activeLang, e.target.value),
1166
+ placeholder: `Alt text in ${languages.find((l) => l.code === activeLang)?.label || activeLang}...`,
1167
+ className: ImagePickerModal_default.editInput
1168
+ }
1169
+ )
1170
+ ] })
1171
+ ] })
1172
+ }
1173
+ );
1174
+ }
1175
+ const renderFooter = () => {
1176
+ if (selectMode) {
1177
+ return /* @__PURE__ */ jsx9(
1178
+ SelectionToolbar,
1179
+ {
1180
+ selectedCount: selectedForDelete.size,
1181
+ totalCount: items.length,
1182
+ onSelectAll: handleSelectAll,
1183
+ onCancel: () => {
1184
+ setSelectMode(false);
1185
+ setSelectedForDelete(/* @__PURE__ */ new Set());
1186
+ },
1187
+ onDelete: () => setShowDeleteConfirm(true),
1188
+ isAllSelected,
1189
+ isIndeterminate: isSomeSelected
1190
+ }
1191
+ );
1192
+ }
1193
+ if (selectedItem && selectable) {
1194
+ return /* @__PURE__ */ jsxs9("div", { className: ImagePickerModal_default.footer, children: [
1195
+ /* @__PURE__ */ jsxs9("div", { className: ImagePickerModal_default.footerInfo, children: [
1196
+ /* @__PURE__ */ jsx9(
1197
+ "img",
1198
+ {
1199
+ src: selectedItem.thumbnailUrl || selectedItem.url,
1200
+ alt: "",
1201
+ className: ImagePickerModal_default.footerImage
1202
+ }
1203
+ ),
1204
+ /* @__PURE__ */ jsx9("span", { className: ImagePickerModal_default.footerFilename, children: selectedItem.filename }),
1205
+ selectedItem.width && selectedItem.height && /* @__PURE__ */ jsxs9("span", { className: ImagePickerModal_default.footerMeta, children: [
1206
+ selectedItem.width,
1207
+ "\xD7",
1208
+ selectedItem.height
1209
+ ] })
1210
+ ] }),
1211
+ /* @__PURE__ */ jsx9(
1212
+ "button",
1213
+ {
1214
+ type: "button",
1215
+ onClick: handleConfirmSelection,
1216
+ className: ImagePickerModal_default.selectButton,
1217
+ children: "Select Image"
1218
+ }
1219
+ )
1220
+ ] });
1221
+ }
1222
+ return void 0;
1223
+ };
1224
+ return /* @__PURE__ */ jsxs9(
1225
+ Modal,
1226
+ {
1227
+ title,
1228
+ onClose: handleClose,
1229
+ headerActions: !selectMode && deleteImage ? /* @__PURE__ */ jsx9(
1230
+ "button",
1231
+ {
1232
+ type: "button",
1233
+ onClick: () => setSelectMode(true),
1234
+ className: ImagePickerModal_default.selectModeButton,
1235
+ children: "Select Items"
1236
+ }
1237
+ ) : void 0,
1238
+ toolbar: /* @__PURE__ */ jsx9("div", { className: ImagePickerModal_default.toolbar, children: /* @__PURE__ */ jsx9(
1239
+ SearchBar,
1240
+ {
1241
+ value: search,
1242
+ onChange: setSearch,
1243
+ placeholder: "Search images...",
1244
+ autoFocus: !selectMode
1245
+ }
1246
+ ) }),
1247
+ footer: renderFooter(),
1248
+ overlay: showDeleteConfirm ? /* @__PURE__ */ jsx9(
1249
+ ConfirmDialog,
1250
+ {
1251
+ title: "Delete Images",
1252
+ message: `Are you sure you want to delete ${selectedForDelete.size} image${selectedForDelete.size > 1 ? "s" : ""}? This action cannot be undone.`,
1253
+ confirmLabel: isDeleting ? "Deleting..." : `Delete ${selectedForDelete.size} image${selectedForDelete.size > 1 ? "s" : ""}`,
1254
+ onConfirm: handleConfirmDelete,
1255
+ onCancel: () => setShowDeleteConfirm(false),
1256
+ loading: isDeleting,
1257
+ variant: "danger"
1258
+ }
1259
+ ) : void 0,
1260
+ loading: loading && items.length === 0,
1261
+ empty: !loading && items.length === 0,
1262
+ emptyMessage: "No images found",
1263
+ children: [
1264
+ canUpload && !selectMode && /* @__PURE__ */ jsxs9("div", { className: ImagePickerModal_default.uploadSection, children: [
1265
+ /* @__PURE__ */ jsx9(
1266
+ UploadDropzone,
1267
+ {
1268
+ onFilesSelected: addFiles,
1269
+ config: mergedUploadConfig,
1270
+ disabled: isUploading && uploading.length >= 10
1271
+ }
1272
+ ),
1273
+ uploading.length > 0 && /* @__PURE__ */ jsx9(
1274
+ UploadQueue,
1275
+ {
1276
+ files: uploading,
1277
+ onCancel: cancelUpload,
1278
+ onClearCompleted: clearCompleted
1279
+ }
1280
+ )
1281
+ ] }),
1282
+ /* @__PURE__ */ jsx9(
1283
+ ImageGrid,
1284
+ {
1285
+ items,
1286
+ onSelect: handleImageClick,
1287
+ selectedId: selectedItem?.id,
1288
+ onEditAlt: update ? handleEditAlt : void 0,
1289
+ manageMode: selectMode,
1290
+ selectedIds: selectedForDelete,
1291
+ onToggleSelect: handleToggleSelect
1292
+ }
1293
+ ),
1294
+ hasMore && /* @__PURE__ */ jsx9(LoadMoreButton, { onClick: handleLoadMore, loading })
1295
+ ]
1296
+ }
1297
+ );
1298
+ }
1299
+
1300
+ // src/components/ImageField/ImageField.module.css
1301
+ var ImageField_default = {
1302
+ container: "ImageField_container",
1303
+ preview: "ImageField_preview",
1304
+ image: "ImageField_image",
1305
+ overlay: "ImageField_overlay",
1306
+ changeButton: "ImageField_changeButton",
1307
+ removeButton: "ImageField_removeButton",
1308
+ selectButton: "ImageField_selectButton"
1309
+ };
1310
+
1311
+ // src/components/ImageField/ImageField.tsx
1312
+ import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
1313
+ function ImageField({
1314
+ value,
1315
+ onChange,
1316
+ field,
1317
+ languages,
1318
+ imageOptions
1319
+ }) {
1320
+ const [isModalOpen, setIsModalOpen] = useState4(false);
1321
+ const handleSelect = (item) => {
1322
+ onChange(item);
1323
+ setIsModalOpen(false);
1324
+ };
1325
+ const handleRemove = (e) => {
1326
+ e.stopPropagation();
1327
+ onChange(null);
1328
+ };
1329
+ const handleOpenModal = () => {
1330
+ setIsModalOpen(true);
1331
+ };
1332
+ const getAltDisplay = () => {
1333
+ if (!value?.alt) return "";
1334
+ for (const lang of languages) {
1335
+ if (value.alt[lang.code]) {
1336
+ return value.alt[lang.code];
1337
+ }
1338
+ }
1339
+ return "";
1340
+ };
1341
+ return /* @__PURE__ */ jsxs10(FieldLabel, { label: field.label || "Image", children: [
1342
+ /* @__PURE__ */ jsx10("div", { className: ImageField_default.container, children: value ? /* @__PURE__ */ jsxs10("div", { className: ImageField_default.preview, children: [
1343
+ /* @__PURE__ */ jsx10(
1344
+ "img",
1345
+ {
1346
+ src: value.url,
1347
+ alt: getAltDisplay(),
1348
+ className: ImageField_default.image
1349
+ }
1350
+ ),
1351
+ /* @__PURE__ */ jsxs10("div", { className: ImageField_default.overlay, children: [
1352
+ /* @__PURE__ */ jsx10(
1353
+ "button",
1354
+ {
1355
+ type: "button",
1356
+ onClick: handleOpenModal,
1357
+ className: ImageField_default.changeButton,
1358
+ children: "Change"
1359
+ }
1360
+ ),
1361
+ /* @__PURE__ */ jsx10(
1362
+ "button",
1363
+ {
1364
+ type: "button",
1365
+ onClick: handleRemove,
1366
+ className: ImageField_default.removeButton,
1367
+ "aria-label": "Remove image",
1368
+ children: /* @__PURE__ */ jsx10(X4, { size: 16 })
1369
+ }
1370
+ )
1371
+ ] })
1372
+ ] }) : /* @__PURE__ */ jsxs10(
1373
+ "button",
1374
+ {
1375
+ type: "button",
1376
+ onClick: handleOpenModal,
1377
+ className: ImageField_default.selectButton,
1378
+ children: [
1379
+ /* @__PURE__ */ jsx10(ImagePlus, { size: 24 }),
1380
+ /* @__PURE__ */ jsx10("span", { children: "Select image" })
1381
+ ]
1382
+ }
1383
+ ) }),
1384
+ isModalOpen && createPortal(
1385
+ /* @__PURE__ */ jsx10(
1386
+ ImagePickerModal,
1387
+ {
1388
+ languages,
1389
+ imageOptions,
1390
+ title: "Select Image",
1391
+ selectedImage: value,
1392
+ onSelect: handleSelect,
1393
+ onClose: () => setIsModalOpen(false)
1394
+ }
1395
+ ),
1396
+ document.body
1397
+ )
1398
+ ] });
1399
+ }
1400
+
1401
+ // src/components/GalleryField/GalleryField.tsx
1402
+ import { useState as useState6 } from "react";
1403
+ import { createPortal as createPortal2 } from "react-dom";
1404
+ import { FieldLabel as FieldLabel2 } from "@puckeditor/core";
1405
+ import { Images, X as X5 } from "lucide-react";
1406
+
1407
+ // src/components/GalleryPickerModal/GalleryPickerModal.tsx
1408
+ import { useState as useState5, useEffect as useEffect5, useCallback as useCallback4, useRef as useRef4 } from "react";
1409
+ import { Plus, ArrowLeft as ArrowLeft2, Loader2 as Loader26, Check as Check3 } from "lucide-react";
1410
+
1411
+ // src/components/GalleryPickerModal/GalleryPickerModal.module.css
1412
+ var GalleryPickerModal_default = {
1413
+ backButton: "GalleryPickerModal_backButton",
1414
+ selectModeButton: "GalleryPickerModal_selectModeButton",
1415
+ toolbar: "GalleryPickerModal_toolbar",
1416
+ createButton: "GalleryPickerModal_createButton",
1417
+ createForm: "GalleryPickerModal_createForm",
1418
+ createInput: "GalleryPickerModal_createInput",
1419
+ createSubmitButton: "GalleryPickerModal_createSubmitButton",
1420
+ createCancelButton: "GalleryPickerModal_createCancelButton",
1421
+ uploadSection: "GalleryPickerModal_uploadSection",
1422
+ galleryGrid: "GalleryPickerModal_galleryGrid",
1423
+ galleryCard: "GalleryPickerModal_galleryCard",
1424
+ galleryCardButton: "GalleryPickerModal_galleryCardButton",
1425
+ selected: "GalleryPickerModal_selected",
1426
+ checkbox: "GalleryPickerModal_checkbox",
1427
+ checkboxChecked: "GalleryPickerModal_checkboxChecked",
1428
+ galleryCover: "GalleryPickerModal_galleryCover",
1429
+ galleryCoverPlaceholder: "GalleryPickerModal_galleryCoverPlaceholder",
1430
+ galleryInfo: "GalleryPickerModal_galleryInfo",
1431
+ galleryName: "GalleryPickerModal_galleryName",
1432
+ galleryCount: "GalleryPickerModal_galleryCount",
1433
+ footer: "GalleryPickerModal_footer",
1434
+ footerInfo: "GalleryPickerModal_footerInfo",
1435
+ footerText: "GalleryPickerModal_footerText",
1436
+ selectButton: "GalleryPickerModal_selectButton",
1437
+ editContent: "GalleryPickerModal_editContent",
1438
+ editPreview: "GalleryPickerModal_editPreview",
1439
+ editImage: "GalleryPickerModal_editImage",
1440
+ editInfo: "GalleryPickerModal_editInfo",
1441
+ editInfoRow: "GalleryPickerModal_editInfoRow",
1442
+ editInfoLabel: "GalleryPickerModal_editInfoLabel",
1443
+ editInfoValue: "GalleryPickerModal_editInfoValue",
1444
+ editField: "GalleryPickerModal_editField",
1445
+ editFieldHeader: "GalleryPickerModal_editFieldHeader",
1446
+ editFieldLabel: "GalleryPickerModal_editFieldLabel",
1447
+ langTabs: "GalleryPickerModal_langTabs",
1448
+ langTab: "GalleryPickerModal_langTab",
1449
+ langTabActive: "GalleryPickerModal_langTabActive",
1450
+ editInput: "GalleryPickerModal_editInput",
1451
+ editFooter: "GalleryPickerModal_editFooter",
1452
+ saveButton: "GalleryPickerModal_saveButton",
1453
+ spinner: "GalleryPickerModal_spinner",
1454
+ spin: "GalleryPickerModal_spin"
1455
+ };
1456
+
1457
+ // src/components/GalleryPickerModal/GalleryPickerModal.tsx
1458
+ import { Fragment as Fragment4, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
1459
+ var DEFAULT_UPLOAD_CONFIG2 = {
1460
+ accept: "image/*",
1461
+ maxSize: 10 * 1024 * 1024,
1462
+ multiple: true
1463
+ };
1464
+ var PAGE_SIZE2 = 20;
1465
+ function GalleryPickerModal({
1466
+ languages,
1467
+ galleryOptions,
1468
+ title = "Select Gallery",
1469
+ selectedGallery: _initialSelectedGallery,
1470
+ onSelect,
1471
+ onClose,
1472
+ selectable = true
1473
+ }) {
1474
+ void _initialSelectedGallery;
1475
+ const { fetchList, fetch, create, delete: deleteGallery, upload, removeImage, updateImage } = galleryOptions;
1476
+ const [viewMode, setViewMode] = useState5("list");
1477
+ const [editingImage, setEditingImage] = useState5(null);
1478
+ const [galleries, setGalleries] = useState5([]);
1479
+ const [selectedGalleryItem, setSelectedGalleryItem] = useState5(null);
1480
+ const [search, setSearch] = useState5("");
1481
+ const [loading, setLoading] = useState5(true);
1482
+ const [page, setPage] = useState5(1);
1483
+ const [hasMore, setHasMore] = useState5(false);
1484
+ const [gallerySelectMode, setGallerySelectMode] = useState5(false);
1485
+ const [selectedGalleryIds, setSelectedGalleryIds] = useState5(/* @__PURE__ */ new Set());
1486
+ const [imageSelectMode, setImageSelectMode] = useState5(false);
1487
+ const [selectedImageIds, setSelectedImageIds] = useState5(/* @__PURE__ */ new Set());
1488
+ const [showDeleteConfirm, setShowDeleteConfirm] = useState5(false);
1489
+ const [deleteTarget, setDeleteTarget] = useState5("gallery");
1490
+ const [isDeleting, setIsDeleting] = useState5(false);
1491
+ const [isCreating, setIsCreating] = useState5(false);
1492
+ const [newGalleryName, setNewGalleryName] = useState5("");
1493
+ const [createLoading, setCreateLoading] = useState5(false);
1494
+ const [altValues, setAltValues] = useState5({});
1495
+ const [activeLang, setActiveLang] = useState5(languages[0]?.code || "it");
1496
+ const [isSaving, setIsSaving] = useState5(false);
1497
+ const newGalleryInputRef = useRef4(null);
1498
+ const {
1499
+ uploading,
1500
+ isUploading,
1501
+ addFiles,
1502
+ cancelUpload,
1503
+ clearCompleted,
1504
+ uploadConfig: mergedUploadConfig
1505
+ } = useUpload({
1506
+ upload: async (file, callbacks) => {
1507
+ if (!selectedGalleryItem) throw new Error("No gallery selected");
1508
+ const result = await upload(selectedGalleryItem.id, file, callbacks);
1509
+ return Array.isArray(result) ? result[0] : result;
1510
+ },
1511
+ config: DEFAULT_UPLOAD_CONFIG2,
1512
+ onUploadComplete: (newItem) => {
1513
+ if (selectedGalleryItem) {
1514
+ setSelectedGalleryItem((prev) => {
1515
+ if (!prev) return prev;
1516
+ return {
1517
+ ...prev,
1518
+ images: [newItem, ...prev.images],
1519
+ imageCount: (prev.imageCount || 0) + 1
1520
+ };
1521
+ });
1522
+ }
1523
+ }
1524
+ });
1525
+ const loadGalleries = useCallback4(
1526
+ async (searchQuery, pageNum, append = false) => {
1527
+ setLoading(true);
1528
+ try {
1529
+ const result = await fetchList({
1530
+ query: searchQuery || void 0,
1531
+ page: pageNum,
1532
+ pageSize: PAGE_SIZE2
1533
+ });
1534
+ const newItems = Array.isArray(result) ? result : result.items;
1535
+ const more = Array.isArray(result) ? newItems.length === PAGE_SIZE2 : result.hasMore ?? false;
1536
+ setGalleries((prev) => append ? [...prev, ...newItems] : newItems);
1537
+ setHasMore(more);
1538
+ } catch (error) {
1539
+ console.error("Failed to fetch galleries:", error);
1540
+ setGalleries([]);
1541
+ setHasMore(false);
1542
+ } finally {
1543
+ setLoading(false);
1544
+ }
1545
+ },
1546
+ [fetchList]
1547
+ );
1548
+ const loadGalleryDetail = useCallback4(
1549
+ async (id) => {
1550
+ setLoading(true);
1551
+ try {
1552
+ const gallery = await fetch(id);
1553
+ setSelectedGalleryItem(gallery);
1554
+ } catch (error) {
1555
+ console.error("Failed to fetch gallery:", error);
1556
+ } finally {
1557
+ setLoading(false);
1558
+ }
1559
+ },
1560
+ [fetch]
1561
+ );
1562
+ useEffect5(() => {
1563
+ if (viewMode === "list") {
1564
+ const timer = setTimeout(() => {
1565
+ setPage(1);
1566
+ loadGalleries(search, 1);
1567
+ }, 300);
1568
+ return () => clearTimeout(timer);
1569
+ }
1570
+ }, [search, loadGalleries, viewMode]);
1571
+ useEffect5(() => {
1572
+ if (isCreating && newGalleryInputRef.current) {
1573
+ newGalleryInputRef.current.focus();
1574
+ }
1575
+ }, [isCreating]);
1576
+ const handleClose = useCallback4(() => {
1577
+ onClose();
1578
+ }, [onClose]);
1579
+ const handleLoadMore = () => {
1580
+ const nextPage = page + 1;
1581
+ setPage(nextPage);
1582
+ loadGalleries(search, nextPage, true);
1583
+ };
1584
+ const handleGalleryClick = (gallery) => {
1585
+ if (gallerySelectMode) {
1586
+ setSelectedGalleryIds((prev) => {
1587
+ const newSet = new Set(prev);
1588
+ if (newSet.has(gallery.id)) {
1589
+ newSet.delete(gallery.id);
1590
+ } else {
1591
+ newSet.add(gallery.id);
1592
+ }
1593
+ return newSet;
1594
+ });
1595
+ } else {
1596
+ setViewMode("detail");
1597
+ loadGalleryDetail(gallery.id);
1598
+ }
1599
+ };
1600
+ const handleCreateGallery = async () => {
1601
+ if (!newGalleryName.trim()) return;
1602
+ setCreateLoading(true);
1603
+ try {
1604
+ const newGallery = await create(newGalleryName.trim());
1605
+ setGalleries((prev) => [newGallery, ...prev]);
1606
+ setIsCreating(false);
1607
+ setNewGalleryName("");
1608
+ } catch (error) {
1609
+ console.error("Failed to create gallery:", error);
1610
+ } finally {
1611
+ setCreateLoading(false);
1612
+ }
1613
+ };
1614
+ const handleSelectAllGalleries = () => {
1615
+ if (selectedGalleryIds.size === galleries.length) {
1616
+ setSelectedGalleryIds(/* @__PURE__ */ new Set());
1617
+ } else {
1618
+ setSelectedGalleryIds(new Set(galleries.map((g) => g.id)));
1619
+ }
1620
+ };
1621
+ const handleSelectAllImages = () => {
1622
+ if (!selectedGalleryItem) return;
1623
+ if (selectedImageIds.size === selectedGalleryItem.images.length) {
1624
+ setSelectedImageIds(/* @__PURE__ */ new Set());
1625
+ } else {
1626
+ setSelectedImageIds(new Set(selectedGalleryItem.images.map((img) => img.id)));
1627
+ }
1628
+ };
1629
+ const handleToggleImageSelect = (image) => {
1630
+ setSelectedImageIds((prev) => {
1631
+ const newSet = new Set(prev);
1632
+ if (newSet.has(image.id)) {
1633
+ newSet.delete(image.id);
1634
+ } else {
1635
+ newSet.add(image.id);
1636
+ }
1637
+ return newSet;
1638
+ });
1639
+ };
1640
+ const handleConfirmDelete = async () => {
1641
+ setIsDeleting(true);
1642
+ try {
1643
+ if (deleteTarget === "gallery") {
1644
+ const deletePromises = Array.from(selectedGalleryIds).map((id) => deleteGallery(id));
1645
+ await Promise.all(deletePromises);
1646
+ setGalleries((prev) => prev.filter((g) => !selectedGalleryIds.has(g.id)));
1647
+ setSelectedGalleryIds(/* @__PURE__ */ new Set());
1648
+ setGallerySelectMode(false);
1649
+ } else {
1650
+ if (!selectedGalleryItem) return;
1651
+ const removePromises = Array.from(selectedImageIds).map(
1652
+ (imageId) => removeImage(selectedGalleryItem.id, imageId)
1653
+ );
1654
+ await Promise.all(removePromises);
1655
+ setSelectedGalleryItem((prev) => {
1656
+ if (!prev) return prev;
1657
+ return {
1658
+ ...prev,
1659
+ images: prev.images.filter((img) => !selectedImageIds.has(img.id)),
1660
+ imageCount: (prev.imageCount || prev.images.length) - selectedImageIds.size
1661
+ };
1662
+ });
1663
+ setSelectedImageIds(/* @__PURE__ */ new Set());
1664
+ setImageSelectMode(false);
1665
+ }
1666
+ setShowDeleteConfirm(false);
1667
+ } catch (error) {
1668
+ console.error("Failed to delete:", error);
1669
+ } finally {
1670
+ setIsDeleting(false);
1671
+ }
1672
+ };
1673
+ const handleEditAlt = (image) => {
1674
+ setEditingImage(image);
1675
+ setAltValues(image.alt || {});
1676
+ setActiveLang(languages[0]?.code || "it");
1677
+ setViewMode("editImage");
1678
+ };
1679
+ const handleAltChange = (langCode, value) => {
1680
+ setAltValues((prev) => ({
1681
+ ...prev,
1682
+ [langCode]: value
1683
+ }));
1684
+ };
1685
+ const handleSaveAlt = async () => {
1686
+ if (!selectedGalleryItem || !editingImage || !updateImage) return;
1687
+ setIsSaving(true);
1688
+ try {
1689
+ await updateImage(selectedGalleryItem.id, editingImage.id, { alt: altValues });
1690
+ setSelectedGalleryItem((prev) => {
1691
+ if (!prev) return prev;
1692
+ return {
1693
+ ...prev,
1694
+ images: prev.images.map(
1695
+ (img) => img.id === editingImage.id ? { ...img, alt: altValues } : img
1696
+ )
1697
+ };
1698
+ });
1699
+ setViewMode("detail");
1700
+ setEditingImage(null);
1701
+ setAltValues({});
1702
+ } catch (error) {
1703
+ console.error("Failed to update alt text:", error);
1704
+ } finally {
1705
+ setIsSaving(false);
1706
+ }
1707
+ };
1708
+ const handleSelectGallery = () => {
1709
+ if (selectedGalleryItem && onSelect) {
1710
+ onSelect(selectedGalleryItem);
1711
+ }
1712
+ };
1713
+ const formatFileSize2 = (bytes) => {
1714
+ if (!bytes) return "";
1715
+ if (bytes < 1024) return `${bytes} B`;
1716
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
1717
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
1718
+ };
1719
+ const isAllGalleriesSelected = galleries.length > 0 && selectedGalleryIds.size === galleries.length;
1720
+ const isSomeGalleriesSelected = selectedGalleryIds.size > 0 && selectedGalleryIds.size < galleries.length;
1721
+ const isAllImagesSelected = selectedGalleryItem && selectedGalleryItem.images.length > 0 && selectedImageIds.size === selectedGalleryItem.images.length;
1722
+ const isSomeImagesSelected = selectedImageIds.size > 0 && selectedGalleryItem && selectedImageIds.size < selectedGalleryItem.images.length;
1723
+ if (viewMode === "editImage" && editingImage) {
1724
+ return /* @__PURE__ */ jsx11(
1725
+ Modal,
1726
+ {
1727
+ title: "Edit Image Details",
1728
+ onClose: handleClose,
1729
+ headerLeft: /* @__PURE__ */ jsx11(
1730
+ "button",
1731
+ {
1732
+ type: "button",
1733
+ onClick: () => {
1734
+ setViewMode("detail");
1735
+ setEditingImage(null);
1736
+ setAltValues({});
1737
+ },
1738
+ className: GalleryPickerModal_default.backButton,
1739
+ "aria-label": "Back to gallery",
1740
+ children: /* @__PURE__ */ jsx11(ArrowLeft2, { size: 20 })
1741
+ }
1742
+ ),
1743
+ footer: /* @__PURE__ */ jsxs11("div", { className: GalleryPickerModal_default.editFooter, children: [
1744
+ /* @__PURE__ */ jsx11("div", {}),
1745
+ /* @__PURE__ */ jsx11(
1746
+ "button",
1747
+ {
1748
+ type: "button",
1749
+ onClick: handleSaveAlt,
1750
+ className: GalleryPickerModal_default.saveButton,
1751
+ disabled: isSaving || !updateImage,
1752
+ children: isSaving ? /* @__PURE__ */ jsxs11(Fragment4, { children: [
1753
+ /* @__PURE__ */ jsx11(Loader26, { size: 16, className: GalleryPickerModal_default.spinner }),
1754
+ "Saving..."
1755
+ ] }) : "Save"
1756
+ }
1757
+ )
1758
+ ] }),
1759
+ children: /* @__PURE__ */ jsxs11("div", { className: GalleryPickerModal_default.editContent, children: [
1760
+ /* @__PURE__ */ jsx11("div", { className: GalleryPickerModal_default.editPreview, children: /* @__PURE__ */ jsx11(
1761
+ "img",
1762
+ {
1763
+ src: editingImage.url,
1764
+ alt: editingImage.filename || "",
1765
+ className: GalleryPickerModal_default.editImage
1766
+ }
1767
+ ) }),
1768
+ /* @__PURE__ */ jsxs11("div", { className: GalleryPickerModal_default.editInfo, children: [
1769
+ /* @__PURE__ */ jsxs11("div", { className: GalleryPickerModal_default.editInfoRow, children: [
1770
+ /* @__PURE__ */ jsx11("span", { className: GalleryPickerModal_default.editInfoLabel, children: "Filename" }),
1771
+ /* @__PURE__ */ jsx11("span", { className: GalleryPickerModal_default.editInfoValue, children: editingImage.filename })
1772
+ ] }),
1773
+ editingImage.width && editingImage.height && /* @__PURE__ */ jsxs11("div", { className: GalleryPickerModal_default.editInfoRow, children: [
1774
+ /* @__PURE__ */ jsx11("span", { className: GalleryPickerModal_default.editInfoLabel, children: "Dimensions" }),
1775
+ /* @__PURE__ */ jsxs11("span", { className: GalleryPickerModal_default.editInfoValue, children: [
1776
+ editingImage.width,
1777
+ "\xD7",
1778
+ editingImage.height
1779
+ ] })
1780
+ ] }),
1781
+ editingImage.size && /* @__PURE__ */ jsxs11("div", { className: GalleryPickerModal_default.editInfoRow, children: [
1782
+ /* @__PURE__ */ jsx11("span", { className: GalleryPickerModal_default.editInfoLabel, children: "Size" }),
1783
+ /* @__PURE__ */ jsx11("span", { className: GalleryPickerModal_default.editInfoValue, children: formatFileSize2(editingImage.size) })
1784
+ ] })
1785
+ ] }),
1786
+ /* @__PURE__ */ jsxs11("div", { className: GalleryPickerModal_default.editField, children: [
1787
+ /* @__PURE__ */ jsxs11("div", { className: GalleryPickerModal_default.editFieldHeader, children: [
1788
+ /* @__PURE__ */ jsx11("label", { className: GalleryPickerModal_default.editFieldLabel, children: "Alt" }),
1789
+ /* @__PURE__ */ jsx11("div", { className: GalleryPickerModal_default.langTabs, children: languages.map((lang) => /* @__PURE__ */ jsx11(
1790
+ "button",
1791
+ {
1792
+ type: "button",
1793
+ onClick: () => setActiveLang(lang.code),
1794
+ className: `${GalleryPickerModal_default.langTab} ${activeLang === lang.code ? GalleryPickerModal_default.langTabActive : ""}`,
1795
+ children: lang.code.toUpperCase()
1796
+ },
1797
+ lang.code
1798
+ )) })
1799
+ ] }),
1800
+ /* @__PURE__ */ jsx11(
1801
+ "input",
1802
+ {
1803
+ type: "text",
1804
+ value: altValues[activeLang] || "",
1805
+ onChange: (e) => handleAltChange(activeLang, e.target.value),
1806
+ placeholder: `Alt text in ${languages.find((l) => l.code === activeLang)?.label || activeLang}...`,
1807
+ className: GalleryPickerModal_default.editInput
1808
+ }
1809
+ )
1810
+ ] })
1811
+ ] })
1812
+ }
1813
+ );
1814
+ }
1815
+ if (viewMode === "detail" && selectedGalleryItem) {
1816
+ const renderDetailFooter = () => {
1817
+ if (imageSelectMode) {
1818
+ return /* @__PURE__ */ jsx11(
1819
+ SelectionToolbar,
1820
+ {
1821
+ selectedCount: selectedImageIds.size,
1822
+ totalCount: selectedGalleryItem.images.length,
1823
+ onSelectAll: handleSelectAllImages,
1824
+ onCancel: () => {
1825
+ setImageSelectMode(false);
1826
+ setSelectedImageIds(/* @__PURE__ */ new Set());
1827
+ },
1828
+ onDelete: () => {
1829
+ setDeleteTarget("image");
1830
+ setShowDeleteConfirm(true);
1831
+ },
1832
+ isAllSelected: !!isAllImagesSelected,
1833
+ isIndeterminate: !!isSomeImagesSelected,
1834
+ deleteLabel: "Remove"
1835
+ }
1836
+ );
1837
+ }
1838
+ if (selectable) {
1839
+ return /* @__PURE__ */ jsxs11("div", { className: GalleryPickerModal_default.footer, children: [
1840
+ /* @__PURE__ */ jsx11("div", { className: GalleryPickerModal_default.footerInfo, children: /* @__PURE__ */ jsxs11("span", { className: GalleryPickerModal_default.footerText, children: [
1841
+ selectedGalleryItem.images.length,
1842
+ " ",
1843
+ selectedGalleryItem.images.length === 1 ? "image" : "images"
1844
+ ] }) }),
1845
+ /* @__PURE__ */ jsx11(
1846
+ "button",
1847
+ {
1848
+ type: "button",
1849
+ onClick: handleSelectGallery,
1850
+ className: GalleryPickerModal_default.selectButton,
1851
+ children: "Select this Gallery"
1852
+ }
1853
+ )
1854
+ ] });
1855
+ }
1856
+ return void 0;
1857
+ };
1858
+ return /* @__PURE__ */ jsx11(
1859
+ Modal,
1860
+ {
1861
+ title: selectedGalleryItem.name,
1862
+ onClose: handleClose,
1863
+ headerLeft: /* @__PURE__ */ jsx11(
1864
+ "button",
1865
+ {
1866
+ type: "button",
1867
+ onClick: () => {
1868
+ setViewMode("list");
1869
+ setSelectedGalleryItem(null);
1870
+ },
1871
+ className: GalleryPickerModal_default.backButton,
1872
+ "aria-label": "Back to galleries",
1873
+ children: /* @__PURE__ */ jsx11(ArrowLeft2, { size: 20 })
1874
+ }
1875
+ ),
1876
+ headerActions: !imageSelectMode && typeof removeImage === "function" ? /* @__PURE__ */ jsx11(
1877
+ "button",
1878
+ {
1879
+ type: "button",
1880
+ onClick: () => setImageSelectMode(true),
1881
+ className: GalleryPickerModal_default.selectModeButton,
1882
+ children: "Select Items"
1883
+ }
1884
+ ) : void 0,
1885
+ toolbar: !imageSelectMode ? /* @__PURE__ */ jsxs11("div", { className: GalleryPickerModal_default.uploadSection, children: [
1886
+ /* @__PURE__ */ jsx11(
1887
+ UploadDropzone,
1888
+ {
1889
+ onFilesSelected: addFiles,
1890
+ config: mergedUploadConfig,
1891
+ disabled: isUploading && uploading.length >= 10
1892
+ }
1893
+ ),
1894
+ uploading.length > 0 && /* @__PURE__ */ jsx11(
1895
+ UploadQueue,
1896
+ {
1897
+ files: uploading,
1898
+ onCancel: cancelUpload,
1899
+ onClearCompleted: clearCompleted
1900
+ }
1901
+ )
1902
+ ] }) : void 0,
1903
+ footer: renderDetailFooter(),
1904
+ overlay: showDeleteConfirm ? /* @__PURE__ */ jsx11(
1905
+ ConfirmDialog,
1906
+ {
1907
+ title: "Remove Images",
1908
+ message: `Are you sure you want to remove ${selectedImageIds.size} ${selectedImageIds.size > 1 ? "images" : "image"} from this gallery?`,
1909
+ confirmLabel: isDeleting ? "Removing..." : `Remove ${selectedImageIds.size} ${selectedImageIds.size > 1 ? "images" : "image"}`,
1910
+ onConfirm: handleConfirmDelete,
1911
+ onCancel: () => setShowDeleteConfirm(false),
1912
+ loading: isDeleting,
1913
+ variant: "danger"
1914
+ }
1915
+ ) : void 0,
1916
+ loading,
1917
+ empty: !loading && selectedGalleryItem.images.length === 0,
1918
+ emptyMessage: "No images in this gallery. Upload some images above.",
1919
+ children: /* @__PURE__ */ jsx11(
1920
+ ImageGrid,
1921
+ {
1922
+ items: selectedGalleryItem.images,
1923
+ onSelect: () => {
1924
+ },
1925
+ onEditAlt: updateImage ? handleEditAlt : void 0,
1926
+ manageMode: imageSelectMode,
1927
+ selectedIds: selectedImageIds,
1928
+ onToggleSelect: handleToggleImageSelect
1929
+ }
1930
+ )
1931
+ }
1932
+ );
1933
+ }
1934
+ const renderListFooter = () => {
1935
+ if (gallerySelectMode) {
1936
+ return /* @__PURE__ */ jsx11(
1937
+ SelectionToolbar,
1938
+ {
1939
+ selectedCount: selectedGalleryIds.size,
1940
+ totalCount: galleries.length,
1941
+ onSelectAll: handleSelectAllGalleries,
1942
+ onCancel: () => {
1943
+ setGallerySelectMode(false);
1944
+ setSelectedGalleryIds(/* @__PURE__ */ new Set());
1945
+ },
1946
+ onDelete: () => {
1947
+ setDeleteTarget("gallery");
1948
+ setShowDeleteConfirm(true);
1949
+ },
1950
+ isAllSelected: isAllGalleriesSelected,
1951
+ isIndeterminate: isSomeGalleriesSelected
1952
+ }
1953
+ );
1954
+ }
1955
+ return void 0;
1956
+ };
1957
+ return /* @__PURE__ */ jsxs11(
1958
+ Modal,
1959
+ {
1960
+ title,
1961
+ onClose: handleClose,
1962
+ headerActions: !gallerySelectMode && typeof deleteGallery === "function" ? /* @__PURE__ */ jsx11(
1963
+ "button",
1964
+ {
1965
+ type: "button",
1966
+ onClick: () => setGallerySelectMode(true),
1967
+ className: GalleryPickerModal_default.selectModeButton,
1968
+ children: "Select Items"
1969
+ }
1970
+ ) : void 0,
1971
+ toolbar: !gallerySelectMode ? /* @__PURE__ */ jsxs11("div", { className: GalleryPickerModal_default.toolbar, children: [
1972
+ /* @__PURE__ */ jsx11(
1973
+ SearchBar,
1974
+ {
1975
+ value: search,
1976
+ onChange: setSearch,
1977
+ placeholder: "Search galleries...",
1978
+ autoFocus: true
1979
+ }
1980
+ ),
1981
+ /* @__PURE__ */ jsxs11(
1982
+ "button",
1983
+ {
1984
+ type: "button",
1985
+ onClick: () => setIsCreating(true),
1986
+ className: GalleryPickerModal_default.createButton,
1987
+ children: [
1988
+ /* @__PURE__ */ jsx11(Plus, { size: 18 }),
1989
+ "New Gallery"
1990
+ ]
1991
+ }
1992
+ )
1993
+ ] }) : void 0,
1994
+ footer: renderListFooter(),
1995
+ overlay: showDeleteConfirm ? /* @__PURE__ */ jsx11(
1996
+ ConfirmDialog,
1997
+ {
1998
+ title: "Delete Galleries",
1999
+ message: `Are you sure you want to delete ${selectedGalleryIds.size} ${selectedGalleryIds.size > 1 ? "galleries" : "gallery"}? This action cannot be undone.`,
2000
+ confirmLabel: isDeleting ? "Deleting..." : `Delete ${selectedGalleryIds.size} ${selectedGalleryIds.size > 1 ? "galleries" : "gallery"}`,
2001
+ onConfirm: handleConfirmDelete,
2002
+ onCancel: () => setShowDeleteConfirm(false),
2003
+ loading: isDeleting,
2004
+ variant: "danger"
2005
+ }
2006
+ ) : void 0,
2007
+ loading: loading && galleries.length === 0,
2008
+ empty: !loading && galleries.length === 0,
2009
+ emptyMessage: "No galleries found",
2010
+ children: [
2011
+ isCreating && /* @__PURE__ */ jsxs11("div", { className: GalleryPickerModal_default.createForm, children: [
2012
+ /* @__PURE__ */ jsx11(
2013
+ "input",
2014
+ {
2015
+ ref: newGalleryInputRef,
2016
+ type: "text",
2017
+ value: newGalleryName,
2018
+ onChange: (e) => setNewGalleryName(e.target.value),
2019
+ placeholder: "Gallery name...",
2020
+ className: GalleryPickerModal_default.createInput,
2021
+ onKeyDown: (e) => {
2022
+ if (e.key === "Enter") handleCreateGallery();
2023
+ if (e.key === "Escape") {
2024
+ setIsCreating(false);
2025
+ setNewGalleryName("");
2026
+ }
2027
+ }
2028
+ }
2029
+ ),
2030
+ /* @__PURE__ */ jsx11(
2031
+ "button",
2032
+ {
2033
+ type: "button",
2034
+ onClick: handleCreateGallery,
2035
+ disabled: !newGalleryName.trim() || createLoading,
2036
+ className: GalleryPickerModal_default.createSubmitButton,
2037
+ children: createLoading ? /* @__PURE__ */ jsx11(Loader26, { size: 16, className: GalleryPickerModal_default.spinner }) : "Create"
2038
+ }
2039
+ ),
2040
+ /* @__PURE__ */ jsx11(
2041
+ "button",
2042
+ {
2043
+ type: "button",
2044
+ onClick: () => {
2045
+ setIsCreating(false);
2046
+ setNewGalleryName("");
2047
+ },
2048
+ className: GalleryPickerModal_default.createCancelButton,
2049
+ children: "Cancel"
2050
+ }
2051
+ )
2052
+ ] }),
2053
+ /* @__PURE__ */ jsx11("div", { className: GalleryPickerModal_default.galleryGrid, children: galleries.map((gallery) => {
2054
+ const isSelected = selectedGalleryIds.has(gallery.id);
2055
+ return /* @__PURE__ */ jsx11("div", { className: GalleryPickerModal_default.galleryCard, children: /* @__PURE__ */ jsxs11(
2056
+ "button",
2057
+ {
2058
+ type: "button",
2059
+ onClick: () => handleGalleryClick(gallery),
2060
+ className: `${GalleryPickerModal_default.galleryCardButton} ${gallerySelectMode && isSelected ? GalleryPickerModal_default.selected : ""}`,
2061
+ children: [
2062
+ gallerySelectMode && /* @__PURE__ */ jsx11("div", { className: `${GalleryPickerModal_default.checkbox} ${isSelected ? GalleryPickerModal_default.checkboxChecked : ""}`, children: isSelected && /* @__PURE__ */ jsx11(Check3, { size: 14, strokeWidth: 3 }) }),
2063
+ /* @__PURE__ */ jsx11("div", { className: GalleryPickerModal_default.galleryCover, children: gallery.coverImage ? /* @__PURE__ */ jsx11(
2064
+ "img",
2065
+ {
2066
+ src: gallery.coverImage.thumbnailUrl || gallery.coverImage.url,
2067
+ alt: ""
2068
+ }
2069
+ ) : /* @__PURE__ */ jsx11("div", { className: GalleryPickerModal_default.galleryCoverPlaceholder }) }),
2070
+ /* @__PURE__ */ jsxs11("div", { className: GalleryPickerModal_default.galleryInfo, children: [
2071
+ /* @__PURE__ */ jsx11("span", { className: GalleryPickerModal_default.galleryName, children: gallery.name }),
2072
+ /* @__PURE__ */ jsxs11("span", { className: GalleryPickerModal_default.galleryCount, children: [
2073
+ gallery.imageCount ?? gallery.images.length,
2074
+ " ",
2075
+ (gallery.imageCount ?? gallery.images.length) === 1 ? "image" : "images"
2076
+ ] })
2077
+ ] })
2078
+ ]
2079
+ }
2080
+ ) }, gallery.id);
2081
+ }) }),
2082
+ hasMore && /* @__PURE__ */ jsx11(LoadMoreButton, { onClick: handleLoadMore, loading })
2083
+ ]
2084
+ }
2085
+ );
2086
+ }
2087
+
2088
+ // src/components/GalleryField/GalleryField.module.css
2089
+ var GalleryField_default = {
2090
+ container: "GalleryField_container",
2091
+ preview: "GalleryField_preview",
2092
+ header: "GalleryField_header",
2093
+ name: "GalleryField_name",
2094
+ count: "GalleryField_count",
2095
+ thumbnails: "GalleryField_thumbnails",
2096
+ thumbnail: "GalleryField_thumbnail",
2097
+ more: "GalleryField_more",
2098
+ actions: "GalleryField_actions",
2099
+ changeButton: "GalleryField_changeButton",
2100
+ removeButton: "GalleryField_removeButton",
2101
+ selectButton: "GalleryField_selectButton"
2102
+ };
2103
+
2104
+ // src/components/GalleryField/GalleryField.tsx
2105
+ import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
2106
+ function GalleryField({
2107
+ value,
2108
+ onChange,
2109
+ field,
2110
+ languages,
2111
+ galleryOptions
2112
+ }) {
2113
+ const [isModalOpen, setIsModalOpen] = useState6(false);
2114
+ const handleSelect = (gallery) => {
2115
+ onChange(gallery);
2116
+ setIsModalOpen(false);
2117
+ };
2118
+ const handleRemove = (e) => {
2119
+ e.stopPropagation();
2120
+ onChange(null);
2121
+ };
2122
+ const handleOpenModal = () => {
2123
+ setIsModalOpen(true);
2124
+ };
2125
+ const previewImages = value?.images?.slice(0, 4) || [];
2126
+ const remainingCount = (value?.images?.length || 0) - 4;
2127
+ return /* @__PURE__ */ jsxs12(FieldLabel2, { label: field.label || "Gallery", children: [
2128
+ /* @__PURE__ */ jsx12("div", { className: GalleryField_default.container, children: value ? /* @__PURE__ */ jsxs12("div", { className: GalleryField_default.preview, children: [
2129
+ /* @__PURE__ */ jsxs12("div", { className: GalleryField_default.header, children: [
2130
+ /* @__PURE__ */ jsx12("span", { className: GalleryField_default.name, children: value.name }),
2131
+ /* @__PURE__ */ jsxs12("span", { className: GalleryField_default.count, children: [
2132
+ value.images.length,
2133
+ " ",
2134
+ value.images.length === 1 ? "image" : "images"
2135
+ ] })
2136
+ ] }),
2137
+ previewImages.length > 0 && /* @__PURE__ */ jsxs12("div", { className: GalleryField_default.thumbnails, children: [
2138
+ previewImages.map((img) => /* @__PURE__ */ jsx12("div", { className: GalleryField_default.thumbnail, children: /* @__PURE__ */ jsx12("img", { src: img.url, alt: "" }) }, img.id)),
2139
+ remainingCount > 0 && /* @__PURE__ */ jsxs12("div", { className: GalleryField_default.more, children: [
2140
+ "+",
2141
+ remainingCount
2142
+ ] })
2143
+ ] }),
2144
+ /* @__PURE__ */ jsxs12("div", { className: GalleryField_default.actions, children: [
2145
+ /* @__PURE__ */ jsx12(
2146
+ "button",
2147
+ {
2148
+ type: "button",
2149
+ onClick: handleOpenModal,
2150
+ className: GalleryField_default.changeButton,
2151
+ children: "Change Gallery"
2152
+ }
2153
+ ),
2154
+ /* @__PURE__ */ jsx12(
2155
+ "button",
2156
+ {
2157
+ type: "button",
2158
+ onClick: handleRemove,
2159
+ className: GalleryField_default.removeButton,
2160
+ "aria-label": "Remove gallery",
2161
+ children: /* @__PURE__ */ jsx12(X5, { size: 16 })
2162
+ }
2163
+ )
2164
+ ] })
2165
+ ] }) : /* @__PURE__ */ jsxs12(
2166
+ "button",
2167
+ {
2168
+ type: "button",
2169
+ onClick: handleOpenModal,
2170
+ className: GalleryField_default.selectButton,
2171
+ children: [
2172
+ /* @__PURE__ */ jsx12(Images, { size: 24 }),
2173
+ /* @__PURE__ */ jsx12("span", { children: "Select gallery" })
2174
+ ]
2175
+ }
2176
+ ) }),
2177
+ isModalOpen && createPortal2(
2178
+ /* @__PURE__ */ jsx12(
2179
+ GalleryPickerModal,
2180
+ {
2181
+ languages,
2182
+ galleryOptions,
2183
+ title: "Select Gallery",
2184
+ onSelect: handleSelect,
2185
+ onClose: () => setIsModalOpen(false)
2186
+ }
2187
+ ),
2188
+ document.body
2189
+ )
2190
+ ] });
2191
+ }
2192
+
2193
+ // src/components/DocumentField/DocumentField.tsx
2194
+ import { useState as useState8 } from "react";
2195
+ import { createPortal as createPortal3 } from "react-dom";
2196
+ import { FieldLabel as FieldLabel3 } from "@puckeditor/core";
2197
+ import { FileText as FileText2, File as File2, X as X6 } from "lucide-react";
2198
+
2199
+ // src/components/DocumentPickerModal/DocumentPickerModal.tsx
2200
+ import { useState as useState7, useEffect as useEffect6, useCallback as useCallback5 } from "react";
2201
+ import { FileText, File, ArrowLeft as ArrowLeft3, Loader2 as Loader27, Check as Check4, Pencil as Pencil2 } from "lucide-react";
2202
+
2203
+ // src/components/DocumentPickerModal/DocumentPickerModal.module.css
2204
+ var DocumentPickerModal_default = {
2205
+ backButton: "DocumentPickerModal_backButton",
2206
+ selectModeButton: "DocumentPickerModal_selectModeButton",
2207
+ toolbar: "DocumentPickerModal_toolbar",
2208
+ uploadSection: "DocumentPickerModal_uploadSection",
2209
+ documentList: "DocumentPickerModal_documentList",
2210
+ documentItemContainer: "DocumentPickerModal_documentItemContainer",
2211
+ documentItem: "DocumentPickerModal_documentItem",
2212
+ selected: "DocumentPickerModal_selected",
2213
+ checkbox: "DocumentPickerModal_checkbox",
2214
+ checkboxChecked: "DocumentPickerModal_checkboxChecked",
2215
+ documentIcon: "DocumentPickerModal_documentIcon",
2216
+ pdfIcon: "DocumentPickerModal_pdfIcon",
2217
+ fileIcon: "DocumentPickerModal_fileIcon",
2218
+ documentInfo: "DocumentPickerModal_documentInfo",
2219
+ documentName: "DocumentPickerModal_documentName",
2220
+ documentMeta: "DocumentPickerModal_documentMeta",
2221
+ checkmark: "DocumentPickerModal_checkmark",
2222
+ editButton: "DocumentPickerModal_editButton",
2223
+ footer: "DocumentPickerModal_footer",
2224
+ footerInfo: "DocumentPickerModal_footerInfo",
2225
+ footerIcon: "DocumentPickerModal_footerIcon",
2226
+ footerFilename: "DocumentPickerModal_footerFilename",
2227
+ footerMeta: "DocumentPickerModal_footerMeta",
2228
+ selectButton: "DocumentPickerModal_selectButton",
2229
+ editContent: "DocumentPickerModal_editContent",
2230
+ editPreview: "DocumentPickerModal_editPreview",
2231
+ editIcon: "DocumentPickerModal_editIcon",
2232
+ editInfo: "DocumentPickerModal_editInfo",
2233
+ editInfoRow: "DocumentPickerModal_editInfoRow",
2234
+ editInfoLabel: "DocumentPickerModal_editInfoLabel",
2235
+ editInfoValue: "DocumentPickerModal_editInfoValue",
2236
+ editField: "DocumentPickerModal_editField",
2237
+ editFieldHeader: "DocumentPickerModal_editFieldHeader",
2238
+ editFieldLabel: "DocumentPickerModal_editFieldLabel",
2239
+ langTabs: "DocumentPickerModal_langTabs",
2240
+ langTab: "DocumentPickerModal_langTab",
2241
+ langTabActive: "DocumentPickerModal_langTabActive",
2242
+ editInput: "DocumentPickerModal_editInput",
2243
+ editFooter: "DocumentPickerModal_editFooter",
2244
+ saveButton: "DocumentPickerModal_saveButton",
2245
+ spinner: "DocumentPickerModal_spinner",
2246
+ spin: "DocumentPickerModal_spin"
2247
+ };
2248
+
2249
+ // src/components/DocumentPickerModal/DocumentPickerModal.tsx
2250
+ import { Fragment as Fragment5, jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
2251
+ var DEFAULT_UPLOAD_CONFIG3 = {
2252
+ accept: ".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt",
2253
+ maxSize: 20 * 1024 * 1024,
2254
+ multiple: true
2255
+ };
2256
+ var PAGE_SIZE3 = 20;
2257
+ function DocumentPickerModal({
2258
+ languages,
2259
+ documentOptions,
2260
+ title = "Select Document",
2261
+ selectedDocument,
2262
+ onSelect,
2263
+ onClose,
2264
+ selectable = true
2265
+ }) {
2266
+ const { fetchList, upload, update, delete: deleteDocument, uploadConfig } = documentOptions;
2267
+ const [view, setView] = useState7("picker");
2268
+ const [editingItem, setEditingItem] = useState7(null);
2269
+ const [selectMode, setSelectMode] = useState7(false);
2270
+ const [selectedForDelete, setSelectedForDelete] = useState7(/* @__PURE__ */ new Set());
2271
+ const [items, setItems] = useState7([]);
2272
+ const [search, setSearch] = useState7("");
2273
+ const [loading, setLoading] = useState7(true);
2274
+ const [page, setPage] = useState7(1);
2275
+ const [hasMore, setHasMore] = useState7(false);
2276
+ const [selectedItem, setSelectedItem] = useState7(null);
2277
+ const [titleValues, setTitleValues] = useState7({});
2278
+ const [activeLang, setActiveLang] = useState7(languages[0]?.code || "it");
2279
+ const [isSaving, setIsSaving] = useState7(false);
2280
+ const [showDeleteConfirm, setShowDeleteConfirm] = useState7(false);
2281
+ const [isDeleting, setIsDeleting] = useState7(false);
2282
+ const canUpload = !!upload;
2283
+ const {
2284
+ uploading,
2285
+ isUploading,
2286
+ addFiles,
2287
+ cancelUpload,
2288
+ clearCompleted,
2289
+ uploadConfig: mergedUploadConfig
2290
+ } = useUpload({
2291
+ upload: upload || (async () => {
2292
+ throw new Error("Upload not configured");
2293
+ }),
2294
+ config: uploadConfig || DEFAULT_UPLOAD_CONFIG3,
2295
+ onUploadComplete: (newItem) => {
2296
+ setItems((prev) => [newItem, ...prev]);
2297
+ }
2298
+ });
2299
+ const loadItems = useCallback5(
2300
+ async (searchQuery, pageNum, append = false) => {
2301
+ setLoading(true);
2302
+ try {
2303
+ const result = await fetchList({
2304
+ query: searchQuery || void 0,
2305
+ page: pageNum,
2306
+ pageSize: PAGE_SIZE3
2307
+ });
2308
+ const newItems = Array.isArray(result) ? result : result.items;
2309
+ const more = Array.isArray(result) ? newItems.length === PAGE_SIZE3 : result.hasMore ?? false;
2310
+ setItems((prev) => append ? [...prev, ...newItems] : newItems);
2311
+ setHasMore(more);
2312
+ } catch (error) {
2313
+ console.error("Failed to fetch documents:", error);
2314
+ setItems([]);
2315
+ setHasMore(false);
2316
+ } finally {
2317
+ setLoading(false);
2318
+ }
2319
+ },
2320
+ [fetchList]
2321
+ );
2322
+ useEffect6(() => {
2323
+ const timer = setTimeout(() => {
2324
+ setPage(1);
2325
+ loadItems(search, 1);
2326
+ }, 300);
2327
+ return () => clearTimeout(timer);
2328
+ }, [search, loadItems]);
2329
+ useEffect6(() => {
2330
+ if (selectedDocument) {
2331
+ const existingItem = items.find((item) => item.id === selectedDocument.id);
2332
+ if (existingItem) {
2333
+ setSelectedItem(existingItem);
2334
+ }
2335
+ }
2336
+ }, [selectedDocument, items]);
2337
+ const handleClose = useCallback5(() => {
2338
+ onClose();
2339
+ }, [onClose]);
2340
+ const handleLoadMore = () => {
2341
+ const nextPage = page + 1;
2342
+ setPage(nextPage);
2343
+ loadItems(search, nextPage, true);
2344
+ };
2345
+ const handleDocumentClick = (item) => {
2346
+ if (selectMode) {
2347
+ setSelectedForDelete((prev) => {
2348
+ const newSet = new Set(prev);
2349
+ if (newSet.has(item.id)) {
2350
+ newSet.delete(item.id);
2351
+ } else {
2352
+ newSet.add(item.id);
2353
+ }
2354
+ return newSet;
2355
+ });
2356
+ } else {
2357
+ if (selectedItem?.id === item.id) {
2358
+ setSelectedItem(null);
2359
+ } else {
2360
+ setSelectedItem(item);
2361
+ }
2362
+ }
2363
+ };
2364
+ const handleConfirmSelection = () => {
2365
+ if (!selectedItem || !onSelect) return;
2366
+ onSelect(selectedItem);
2367
+ };
2368
+ const handleEditTitle = (item) => {
2369
+ setEditingItem(item);
2370
+ setTitleValues(item.title || {});
2371
+ setActiveLang(languages[0]?.code || "it");
2372
+ setView("edit");
2373
+ };
2374
+ const handleTitleChange = (langCode, value) => {
2375
+ setTitleValues((prev) => ({
2376
+ ...prev,
2377
+ [langCode]: value
2378
+ }));
2379
+ };
2380
+ const handleSaveTitle = async () => {
2381
+ if (!editingItem || !update) return;
2382
+ setIsSaving(true);
2383
+ try {
2384
+ await update(editingItem.id, { title: titleValues });
2385
+ setItems(
2386
+ (prev) => prev.map(
2387
+ (item) => item.id === editingItem.id ? { ...item, title: titleValues } : item
2388
+ )
2389
+ );
2390
+ if (selectedItem?.id === editingItem.id) {
2391
+ setSelectedItem((prev) => prev ? { ...prev, title: titleValues } : null);
2392
+ }
2393
+ setView("picker");
2394
+ setEditingItem(null);
2395
+ setTitleValues({});
2396
+ } catch (error) {
2397
+ console.error("Failed to update title:", error);
2398
+ } finally {
2399
+ setIsSaving(false);
2400
+ }
2401
+ };
2402
+ const handleSelectAll = () => {
2403
+ if (selectedForDelete.size === items.length) {
2404
+ setSelectedForDelete(/* @__PURE__ */ new Set());
2405
+ } else {
2406
+ setSelectedForDelete(new Set(items.map((item) => item.id)));
2407
+ }
2408
+ };
2409
+ const handleConfirmDelete = async () => {
2410
+ if (!deleteDocument || selectedForDelete.size === 0) return;
2411
+ setIsDeleting(true);
2412
+ try {
2413
+ const deletePromises = Array.from(selectedForDelete).map((id) => deleteDocument(id));
2414
+ await Promise.all(deletePromises);
2415
+ setItems((prev) => prev.filter((item) => !selectedForDelete.has(item.id)));
2416
+ if (selectedItem && selectedForDelete.has(selectedItem.id)) {
2417
+ setSelectedItem(null);
2418
+ }
2419
+ setShowDeleteConfirm(false);
2420
+ setSelectedForDelete(/* @__PURE__ */ new Set());
2421
+ setSelectMode(false);
2422
+ } catch (error) {
2423
+ console.error("Failed to delete documents:", error);
2424
+ } finally {
2425
+ setIsDeleting(false);
2426
+ }
2427
+ };
2428
+ const getIcon = (mimeType) => {
2429
+ if (mimeType === "application/pdf") {
2430
+ return /* @__PURE__ */ jsx13(FileText, { size: 20, className: DocumentPickerModal_default.pdfIcon });
2431
+ }
2432
+ return /* @__PURE__ */ jsx13(File, { size: 20, className: DocumentPickerModal_default.fileIcon });
2433
+ };
2434
+ const isAllSelected = items.length > 0 && selectedForDelete.size === items.length;
2435
+ const isSomeSelected = selectedForDelete.size > 0 && selectedForDelete.size < items.length;
2436
+ if (view === "edit" && editingItem) {
2437
+ return /* @__PURE__ */ jsx13(
2438
+ Modal,
2439
+ {
2440
+ title: "Edit Document Details",
2441
+ onClose: handleClose,
2442
+ size: "small",
2443
+ headerLeft: /* @__PURE__ */ jsx13(
2444
+ "button",
2445
+ {
2446
+ type: "button",
2447
+ onClick: () => {
2448
+ setView("picker");
2449
+ setEditingItem(null);
2450
+ setTitleValues({});
2451
+ },
2452
+ className: DocumentPickerModal_default.backButton,
2453
+ "aria-label": "Back to list",
2454
+ children: /* @__PURE__ */ jsx13(ArrowLeft3, { size: 20 })
2455
+ }
2456
+ ),
2457
+ footer: /* @__PURE__ */ jsxs13("div", { className: DocumentPickerModal_default.editFooter, children: [
2458
+ /* @__PURE__ */ jsx13("div", {}),
2459
+ /* @__PURE__ */ jsx13(
2460
+ "button",
2461
+ {
2462
+ type: "button",
2463
+ onClick: handleSaveTitle,
2464
+ className: DocumentPickerModal_default.saveButton,
2465
+ disabled: isSaving || !update,
2466
+ children: isSaving ? /* @__PURE__ */ jsxs13(Fragment5, { children: [
2467
+ /* @__PURE__ */ jsx13(Loader27, { size: 16, className: DocumentPickerModal_default.spinner }),
2468
+ "Saving..."
2469
+ ] }) : "Save"
2470
+ }
2471
+ )
2472
+ ] }),
2473
+ children: /* @__PURE__ */ jsxs13("div", { className: DocumentPickerModal_default.editContent, children: [
2474
+ /* @__PURE__ */ jsx13("div", { className: DocumentPickerModal_default.editPreview, children: /* @__PURE__ */ jsx13("div", { className: DocumentPickerModal_default.editIcon, children: getIcon(editingItem.mimeType) }) }),
2475
+ /* @__PURE__ */ jsxs13("div", { className: DocumentPickerModal_default.editInfo, children: [
2476
+ /* @__PURE__ */ jsxs13("div", { className: DocumentPickerModal_default.editInfoRow, children: [
2477
+ /* @__PURE__ */ jsx13("span", { className: DocumentPickerModal_default.editInfoLabel, children: "Filename" }),
2478
+ /* @__PURE__ */ jsx13("span", { className: DocumentPickerModal_default.editInfoValue, children: editingItem.filename })
2479
+ ] }),
2480
+ /* @__PURE__ */ jsxs13("div", { className: DocumentPickerModal_default.editInfoRow, children: [
2481
+ /* @__PURE__ */ jsx13("span", { className: DocumentPickerModal_default.editInfoLabel, children: "Type" }),
2482
+ /* @__PURE__ */ jsx13("span", { className: DocumentPickerModal_default.editInfoValue, children: editingItem.extension?.toUpperCase() })
2483
+ ] }),
2484
+ /* @__PURE__ */ jsxs13("div", { className: DocumentPickerModal_default.editInfoRow, children: [
2485
+ /* @__PURE__ */ jsx13("span", { className: DocumentPickerModal_default.editInfoLabel, children: "Size" }),
2486
+ /* @__PURE__ */ jsx13("span", { className: DocumentPickerModal_default.editInfoValue, children: formatFileSize(editingItem.size) })
2487
+ ] })
2488
+ ] }),
2489
+ /* @__PURE__ */ jsxs13("div", { className: DocumentPickerModal_default.editField, children: [
2490
+ /* @__PURE__ */ jsxs13("div", { className: DocumentPickerModal_default.editFieldHeader, children: [
2491
+ /* @__PURE__ */ jsx13("label", { className: DocumentPickerModal_default.editFieldLabel, children: "Title" }),
2492
+ /* @__PURE__ */ jsx13("div", { className: DocumentPickerModal_default.langTabs, children: languages.map((lang) => /* @__PURE__ */ jsx13(
2493
+ "button",
2494
+ {
2495
+ type: "button",
2496
+ onClick: () => setActiveLang(lang.code),
2497
+ className: `${DocumentPickerModal_default.langTab} ${activeLang === lang.code ? DocumentPickerModal_default.langTabActive : ""}`,
2498
+ children: lang.code.toUpperCase()
2499
+ },
2500
+ lang.code
2501
+ )) })
2502
+ ] }),
2503
+ /* @__PURE__ */ jsx13(
2504
+ "input",
2505
+ {
2506
+ type: "text",
2507
+ value: titleValues[activeLang] || "",
2508
+ onChange: (e) => handleTitleChange(activeLang, e.target.value),
2509
+ placeholder: `Title in ${languages.find((l) => l.code === activeLang)?.label || activeLang}...`,
2510
+ className: DocumentPickerModal_default.editInput
2511
+ }
2512
+ )
2513
+ ] })
2514
+ ] })
2515
+ }
2516
+ );
2517
+ }
2518
+ const renderFooter = () => {
2519
+ if (selectMode) {
2520
+ return /* @__PURE__ */ jsx13(
2521
+ SelectionToolbar,
2522
+ {
2523
+ selectedCount: selectedForDelete.size,
2524
+ totalCount: items.length,
2525
+ onSelectAll: handleSelectAll,
2526
+ onCancel: () => {
2527
+ setSelectMode(false);
2528
+ setSelectedForDelete(/* @__PURE__ */ new Set());
2529
+ },
2530
+ onDelete: () => setShowDeleteConfirm(true),
2531
+ isAllSelected,
2532
+ isIndeterminate: isSomeSelected
2533
+ }
2534
+ );
2535
+ }
2536
+ if (selectedItem && selectable) {
2537
+ return /* @__PURE__ */ jsxs13("div", { className: DocumentPickerModal_default.footer, children: [
2538
+ /* @__PURE__ */ jsxs13("div", { className: DocumentPickerModal_default.footerInfo, children: [
2539
+ /* @__PURE__ */ jsx13("div", { className: DocumentPickerModal_default.footerIcon, children: getIcon(selectedItem.mimeType) }),
2540
+ /* @__PURE__ */ jsx13("span", { className: DocumentPickerModal_default.footerFilename, children: selectedItem.filename }),
2541
+ /* @__PURE__ */ jsxs13("span", { className: DocumentPickerModal_default.footerMeta, children: [
2542
+ selectedItem.extension?.toUpperCase(),
2543
+ " - ",
2544
+ formatFileSize(selectedItem.size)
2545
+ ] })
2546
+ ] }),
2547
+ /* @__PURE__ */ jsx13(
2548
+ "button",
2549
+ {
2550
+ type: "button",
2551
+ onClick: handleConfirmSelection,
2552
+ className: DocumentPickerModal_default.selectButton,
2553
+ children: "Select Document"
2554
+ }
2555
+ )
2556
+ ] });
2557
+ }
2558
+ return void 0;
2559
+ };
2560
+ return /* @__PURE__ */ jsxs13(
2561
+ Modal,
2562
+ {
2563
+ title,
2564
+ onClose: handleClose,
2565
+ size: "small",
2566
+ headerActions: !selectMode && deleteDocument ? /* @__PURE__ */ jsx13(
2567
+ "button",
2568
+ {
2569
+ type: "button",
2570
+ onClick: () => setSelectMode(true),
2571
+ className: DocumentPickerModal_default.selectModeButton,
2572
+ children: "Select Items"
2573
+ }
2574
+ ) : void 0,
2575
+ toolbar: /* @__PURE__ */ jsx13("div", { className: DocumentPickerModal_default.toolbar, children: /* @__PURE__ */ jsx13(
2576
+ SearchBar,
2577
+ {
2578
+ value: search,
2579
+ onChange: setSearch,
2580
+ placeholder: "Search documents...",
2581
+ autoFocus: !selectMode
2582
+ }
2583
+ ) }),
2584
+ footer: renderFooter(),
2585
+ overlay: showDeleteConfirm ? /* @__PURE__ */ jsx13(
2586
+ ConfirmDialog,
2587
+ {
2588
+ title: "Delete Documents",
2589
+ message: `Are you sure you want to delete ${selectedForDelete.size} document${selectedForDelete.size > 1 ? "s" : ""}? This action cannot be undone.`,
2590
+ confirmLabel: isDeleting ? "Deleting..." : `Delete ${selectedForDelete.size} document${selectedForDelete.size > 1 ? "s" : ""}`,
2591
+ onConfirm: handleConfirmDelete,
2592
+ onCancel: () => setShowDeleteConfirm(false),
2593
+ loading: isDeleting,
2594
+ variant: "danger"
2595
+ }
2596
+ ) : void 0,
2597
+ loading: loading && items.length === 0,
2598
+ empty: !loading && items.length === 0,
2599
+ emptyMessage: "No documents found",
2600
+ children: [
2601
+ canUpload && !selectMode && /* @__PURE__ */ jsxs13("div", { className: DocumentPickerModal_default.uploadSection, children: [
2602
+ /* @__PURE__ */ jsx13(
2603
+ UploadDropzone,
2604
+ {
2605
+ onFilesSelected: addFiles,
2606
+ config: mergedUploadConfig,
2607
+ disabled: isUploading && uploading.length >= 10
2608
+ }
2609
+ ),
2610
+ uploading.length > 0 && /* @__PURE__ */ jsx13(
2611
+ UploadQueue,
2612
+ {
2613
+ files: uploading,
2614
+ onCancel: cancelUpload,
2615
+ onClearCompleted: clearCompleted
2616
+ }
2617
+ )
2618
+ ] }),
2619
+ /* @__PURE__ */ jsx13("div", { className: DocumentPickerModal_default.documentList, children: items.map((item) => {
2620
+ const isSelected = selectMode ? selectedForDelete.has(item.id) : selectedItem?.id === item.id;
2621
+ return /* @__PURE__ */ jsxs13("div", { className: DocumentPickerModal_default.documentItemContainer, children: [
2622
+ /* @__PURE__ */ jsxs13(
2623
+ "button",
2624
+ {
2625
+ type: "button",
2626
+ onClick: () => handleDocumentClick(item),
2627
+ className: `${DocumentPickerModal_default.documentItem} ${isSelected ? DocumentPickerModal_default.selected : ""}`,
2628
+ children: [
2629
+ selectMode && /* @__PURE__ */ jsx13("div", { className: `${DocumentPickerModal_default.checkbox} ${isSelected ? DocumentPickerModal_default.checkboxChecked : ""}`, children: isSelected && /* @__PURE__ */ jsx13(Check4, { size: 14, strokeWidth: 3 }) }),
2630
+ /* @__PURE__ */ jsx13("div", { className: DocumentPickerModal_default.documentIcon, children: getIcon(item.mimeType) }),
2631
+ /* @__PURE__ */ jsxs13("div", { className: DocumentPickerModal_default.documentInfo, children: [
2632
+ /* @__PURE__ */ jsx13("span", { className: DocumentPickerModal_default.documentName, children: item.title?.[languages[0]?.code] || item.filename }),
2633
+ /* @__PURE__ */ jsxs13("span", { className: DocumentPickerModal_default.documentMeta, children: [
2634
+ item.extension?.toUpperCase(),
2635
+ " - ",
2636
+ formatFileSize(item.size)
2637
+ ] })
2638
+ ] }),
2639
+ !selectMode && selectedItem?.id === item.id && /* @__PURE__ */ jsx13("div", { className: DocumentPickerModal_default.checkmark, children: /* @__PURE__ */ jsx13(
2640
+ "svg",
2641
+ {
2642
+ width: "16",
2643
+ height: "16",
2644
+ viewBox: "0 0 16 16",
2645
+ fill: "none",
2646
+ xmlns: "http://www.w3.org/2000/svg",
2647
+ children: /* @__PURE__ */ jsx13(
2648
+ "path",
2649
+ {
2650
+ d: "M13.5 4.5L6 12L2.5 8.5",
2651
+ stroke: "currentColor",
2652
+ strokeWidth: "2",
2653
+ strokeLinecap: "round",
2654
+ strokeLinejoin: "round"
2655
+ }
2656
+ )
2657
+ }
2658
+ ) })
2659
+ ]
2660
+ }
2661
+ ),
2662
+ !selectMode && update && /* @__PURE__ */ jsx13(
2663
+ "button",
2664
+ {
2665
+ type: "button",
2666
+ onClick: (e) => {
2667
+ e.stopPropagation();
2668
+ handleEditTitle(item);
2669
+ },
2670
+ className: DocumentPickerModal_default.editButton,
2671
+ "aria-label": "Edit title",
2672
+ children: /* @__PURE__ */ jsx13(Pencil2, { size: 14 })
2673
+ }
2674
+ )
2675
+ ] }, item.id);
2676
+ }) }),
2677
+ hasMore && /* @__PURE__ */ jsx13(LoadMoreButton, { onClick: handleLoadMore, loading })
2678
+ ]
2679
+ }
2680
+ );
2681
+ }
2682
+
2683
+ // src/components/DocumentField/DocumentField.module.css
2684
+ var DocumentField_default = {
2685
+ container: "DocumentField_container",
2686
+ preview: "DocumentField_preview",
2687
+ iconWrapper: "DocumentField_iconWrapper",
2688
+ pdfIcon: "DocumentField_pdfIcon",
2689
+ fileIcon: "DocumentField_fileIcon",
2690
+ info: "DocumentField_info",
2691
+ title: "DocumentField_title",
2692
+ meta: "DocumentField_meta",
2693
+ actions: "DocumentField_actions",
2694
+ changeButton: "DocumentField_changeButton",
2695
+ removeButton: "DocumentField_removeButton",
2696
+ selectButton: "DocumentField_selectButton"
2697
+ };
2698
+
2699
+ // src/components/DocumentField/DocumentField.tsx
2700
+ import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
2701
+ function DocumentField({
2702
+ value,
2703
+ onChange,
2704
+ field,
2705
+ languages,
2706
+ documentOptions
2707
+ }) {
2708
+ const [isModalOpen, setIsModalOpen] = useState8(false);
2709
+ const handleSelect = (item) => {
2710
+ onChange(item);
2711
+ setIsModalOpen(false);
2712
+ };
2713
+ const handleRemove = (e) => {
2714
+ e.stopPropagation();
2715
+ onChange(null);
2716
+ };
2717
+ const handleOpenModal = () => {
2718
+ setIsModalOpen(true);
2719
+ };
2720
+ const getTitleDisplay = () => {
2721
+ if (value?.title) {
2722
+ for (const lang of languages) {
2723
+ if (value.title[lang.code]) {
2724
+ return value.title[lang.code];
2725
+ }
2726
+ }
2727
+ }
2728
+ return value?.filename || "";
2729
+ };
2730
+ const getIcon = () => {
2731
+ if (value?.mimeType === "application/pdf") {
2732
+ return /* @__PURE__ */ jsx14(FileText2, { size: 24, className: DocumentField_default.pdfIcon });
2733
+ }
2734
+ return /* @__PURE__ */ jsx14(File2, { size: 24, className: DocumentField_default.fileIcon });
2735
+ };
2736
+ return /* @__PURE__ */ jsxs14(FieldLabel3, { label: field.label || "Document", children: [
2737
+ /* @__PURE__ */ jsx14("div", { className: DocumentField_default.container, children: value ? /* @__PURE__ */ jsxs14("div", { className: DocumentField_default.preview, children: [
2738
+ /* @__PURE__ */ jsx14("div", { className: DocumentField_default.iconWrapper, children: getIcon() }),
2739
+ /* @__PURE__ */ jsxs14("div", { className: DocumentField_default.info, children: [
2740
+ /* @__PURE__ */ jsx14("span", { className: DocumentField_default.title, children: getTitleDisplay() }),
2741
+ /* @__PURE__ */ jsxs14("span", { className: DocumentField_default.meta, children: [
2742
+ value.extension?.toUpperCase(),
2743
+ " \u2022 ",
2744
+ formatFileSize(value.size)
2745
+ ] })
2746
+ ] }),
2747
+ /* @__PURE__ */ jsxs14("div", { className: DocumentField_default.actions, children: [
2748
+ /* @__PURE__ */ jsx14(
2749
+ "button",
2750
+ {
2751
+ type: "button",
2752
+ onClick: handleOpenModal,
2753
+ className: DocumentField_default.changeButton,
2754
+ children: "Change"
2755
+ }
2756
+ ),
2757
+ /* @__PURE__ */ jsx14(
2758
+ "button",
2759
+ {
2760
+ type: "button",
2761
+ onClick: handleRemove,
2762
+ className: DocumentField_default.removeButton,
2763
+ "aria-label": "Remove document",
2764
+ children: /* @__PURE__ */ jsx14(X6, { size: 16 })
2765
+ }
2766
+ )
2767
+ ] })
2768
+ ] }) : /* @__PURE__ */ jsxs14(
2769
+ "button",
2770
+ {
2771
+ type: "button",
2772
+ onClick: handleOpenModal,
2773
+ className: DocumentField_default.selectButton,
2774
+ children: [
2775
+ /* @__PURE__ */ jsx14(FileText2, { size: 24 }),
2776
+ /* @__PURE__ */ jsx14("span", { children: "Select document" })
2777
+ ]
2778
+ }
2779
+ ) }),
2780
+ isModalOpen && createPortal3(
2781
+ /* @__PURE__ */ jsx14(
2782
+ DocumentPickerModal,
2783
+ {
2784
+ languages,
2785
+ documentOptions,
2786
+ title: "Select Document",
2787
+ onSelect: handleSelect,
2788
+ onClose: () => setIsModalOpen(false)
2789
+ }
2790
+ ),
2791
+ document.body
2792
+ )
2793
+ ] });
2794
+ }
2795
+
2796
+ // src/components/MediaPanel/MediaPanel.tsx
2797
+ import { useState as useState9 } from "react";
2798
+ import { createPortal as createPortal4 } from "react-dom";
2799
+ import { Image, Images as Images2, FileText as FileText3 } from "lucide-react";
2800
+
2801
+ // src/components/MediaPanel/MediaPanel.module.css
2802
+ var MediaPanel_default = {
2803
+ panel: "MediaPanel_panel",
2804
+ item: "MediaPanel_item"
2805
+ };
2806
+
2807
+ // src/components/MediaPanel/MediaPanel.tsx
2808
+ import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
2809
+ function MediaPanel({
2810
+ languages,
2811
+ imageOptions,
2812
+ galleryOptions,
2813
+ documentOptions
2814
+ }) {
2815
+ const [openModal, setOpenModal] = useState9(null);
2816
+ const handleCloseModal = () => {
2817
+ setOpenModal(null);
2818
+ };
2819
+ return /* @__PURE__ */ jsxs15("div", { className: MediaPanel_default.panel, children: [
2820
+ /* @__PURE__ */ jsxs15(
2821
+ "button",
2822
+ {
2823
+ type: "button",
2824
+ className: MediaPanel_default.item,
2825
+ onClick: () => setOpenModal("image"),
2826
+ children: [
2827
+ /* @__PURE__ */ jsx15(Image, { size: 20 }),
2828
+ /* @__PURE__ */ jsx15("span", { children: "Images" })
2829
+ ]
2830
+ }
2831
+ ),
2832
+ galleryOptions && /* @__PURE__ */ jsxs15(
2833
+ "button",
2834
+ {
2835
+ type: "button",
2836
+ className: MediaPanel_default.item,
2837
+ onClick: () => setOpenModal("gallery"),
2838
+ children: [
2839
+ /* @__PURE__ */ jsx15(Images2, { size: 20 }),
2840
+ /* @__PURE__ */ jsx15("span", { children: "Gallery" })
2841
+ ]
2842
+ }
2843
+ ),
2844
+ documentOptions && /* @__PURE__ */ jsxs15(
2845
+ "button",
2846
+ {
2847
+ type: "button",
2848
+ className: MediaPanel_default.item,
2849
+ onClick: () => setOpenModal("document"),
2850
+ children: [
2851
+ /* @__PURE__ */ jsx15(FileText3, { size: 20 }),
2852
+ /* @__PURE__ */ jsx15("span", { children: "Documents" })
2853
+ ]
2854
+ }
2855
+ ),
2856
+ openModal === "image" && createPortal4(
2857
+ /* @__PURE__ */ jsx15(
2858
+ ImagePickerModal,
2859
+ {
2860
+ languages,
2861
+ imageOptions,
2862
+ title: "Media Library",
2863
+ selectable: false,
2864
+ onClose: handleCloseModal
2865
+ }
2866
+ ),
2867
+ document.body
2868
+ ),
2869
+ openModal === "gallery" && galleryOptions && createPortal4(
2870
+ /* @__PURE__ */ jsx15(
2871
+ GalleryPickerModal,
2872
+ {
2873
+ languages,
2874
+ galleryOptions,
2875
+ title: "Gallery Library",
2876
+ selectable: false,
2877
+ onClose: handleCloseModal
2878
+ }
2879
+ ),
2880
+ document.body
2881
+ ),
2882
+ openModal === "document" && documentOptions && createPortal4(
2883
+ /* @__PURE__ */ jsx15(
2884
+ DocumentPickerModal,
2885
+ {
2886
+ languages,
2887
+ documentOptions,
2888
+ title: "Document Library",
2889
+ selectable: false,
2890
+ onClose: handleCloseModal
2891
+ }
2892
+ ),
2893
+ document.body
2894
+ )
2895
+ ] });
2896
+ }
2897
+
2898
+ // src/createMediaPlugin.tsx
2899
+ import { jsx as jsx16 } from "react/jsx-runtime";
2900
+ function createMediaPlugin(options) {
2901
+ const {
2902
+ languages = [
2903
+ { code: "en", label: "English" },
2904
+ { code: "it", label: "Italiano" }
2905
+ ],
2906
+ image,
2907
+ gallery,
2908
+ document: document2
2909
+ } = options;
2910
+ const fieldTypes = {
2911
+ // Image field type (always available)
2912
+ image: (props) => {
2913
+ const fieldProps = props;
2914
+ return /* @__PURE__ */ jsx16(
2915
+ ImageField,
2916
+ {
2917
+ ...fieldProps,
2918
+ languages,
2919
+ imageOptions: image
2920
+ }
2921
+ );
2922
+ }
2923
+ };
2924
+ if (gallery) {
2925
+ fieldTypes.gallery = (props) => {
2926
+ const fieldProps = props;
2927
+ return /* @__PURE__ */ jsx16(
2928
+ GalleryField,
2929
+ {
2930
+ ...fieldProps,
2931
+ languages,
2932
+ galleryOptions: gallery
2933
+ }
2934
+ );
2935
+ };
2936
+ }
2937
+ if (document2) {
2938
+ fieldTypes.document = (props) => {
2939
+ const fieldProps = props;
2940
+ return /* @__PURE__ */ jsx16(
2941
+ DocumentField,
2942
+ {
2943
+ ...fieldProps,
2944
+ languages,
2945
+ documentOptions: document2
2946
+ }
2947
+ );
2948
+ };
2949
+ }
2950
+ return {
2951
+ name: "puck-media",
2952
+ label: "Media",
2953
+ icon: /* @__PURE__ */ jsx16(Image2, { size: 20 }),
2954
+ render: () => /* @__PURE__ */ jsx16(
2955
+ MediaPanel,
2956
+ {
2957
+ languages,
2958
+ imageOptions: image,
2959
+ galleryOptions: gallery,
2960
+ documentOptions: document2
2961
+ }
2962
+ ),
2963
+ overrides: {
2964
+ fieldTypes
2965
+ }
2966
+ };
2967
+ }
2968
+
2969
+ // src/types.ts
2970
+ var DEFAULT_LANGUAGES = [
2971
+ { code: "en", label: "English" },
2972
+ { code: "it", label: "Italiano" }
2973
+ ];
2974
+ export {
2975
+ DEFAULT_LANGUAGES,
2976
+ DocumentField,
2977
+ DocumentPickerModal,
2978
+ GalleryField,
2979
+ GalleryPickerModal,
2980
+ ImageField,
2981
+ ImageGrid,
2982
+ ImagePickerModal,
2983
+ MediaPanel,
2984
+ UploadDropzone,
2985
+ UploadQueue,
2986
+ createMediaPlugin,
2987
+ formatFileSize,
2988
+ useUpload
2989
+ };
2990
+ //# sourceMappingURL=index.mjs.map