react-os-shell 3.10.1 → 3.11.2
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/{Browser-3SDMP5NU.js → Browser-FX577ZG2.js} +4 -4
- package/dist/{Browser-3SDMP5NU.js.map → Browser-FX577ZG2.js.map} +1 -1
- package/dist/{Documents-FOCBCZHY.js → Documents-JJKFUSJ6.js} +3 -3
- package/dist/{Documents-FOCBCZHY.js.map → Documents-JJKFUSJ6.js.map} +1 -1
- package/dist/Files-L5SN24XK.js +12 -0
- package/dist/{Files-P37UZJVD.js.map → Files-L5SN24XK.js.map} +1 -1
- package/dist/{Notepad-WDDJQVXF.js → Notepad-S2EZKPZQ.js} +3 -3
- package/dist/{Notepad-WDDJQVXF.js.map → Notepad-S2EZKPZQ.js.map} +1 -1
- package/dist/Preview-BSQJ3GGL.js +8 -0
- package/dist/{Preview-CESYNTOE.js.map → Preview-BSQJ3GGL.js.map} +1 -1
- package/dist/{Spreadsheet-6SICRWKK.js → Spreadsheet-HF47TRAV.js} +4 -4
- package/dist/{Spreadsheet-6SICRWKK.js.map → Spreadsheet-HF47TRAV.js.map} +1 -1
- package/dist/apps/index.js +12 -12
- package/dist/{chunk-OZFGITVF.js → chunk-AW2BPHVS.js} +3 -3
- package/dist/{chunk-OZFGITVF.js.map → chunk-AW2BPHVS.js.map} +1 -1
- package/dist/{chunk-WEQXKNOA.js → chunk-BI5XBNI5.js} +3 -3
- package/dist/{chunk-WEQXKNOA.js.map → chunk-BI5XBNI5.js.map} +1 -1
- package/dist/{chunk-3SOG3MFC.js → chunk-CCIP3ADU.js} +4 -4
- package/dist/{chunk-3SOG3MFC.js.map → chunk-CCIP3ADU.js.map} +1 -1
- package/dist/{chunk-SRFLPGGO.js → chunk-NZLE6YR6.js} +3 -3
- package/dist/{chunk-SRFLPGGO.js.map → chunk-NZLE6YR6.js.map} +1 -1
- package/dist/{chunk-YPIDICFR.js → chunk-OKFJBJY6.js} +3 -3
- package/dist/{chunk-YPIDICFR.js.map → chunk-OKFJBJY6.js.map} +1 -1
- package/dist/{chunk-L5SPKS76.js → chunk-P3DVY4XJ.js} +4 -4
- package/dist/{chunk-L5SPKS76.js.map → chunk-P3DVY4XJ.js.map} +1 -1
- package/dist/index.d.ts +138 -2
- package/dist/index.js +555 -60
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/Files-P37UZJVD.js +0 -12
- package/dist/Preview-CESYNTOE.js +0 -8
package/dist/index.js
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import { subscribePomo, getPomoSnapshot } from './chunk-VGJ3KCOP.js';
|
|
2
2
|
export { setShellTodoProvider } from './chunk-VGJ3KCOP.js';
|
|
3
|
-
import { PREVIEW_OPENED_EVENT, publishDesktopFolders, requestFilesTrashView, FolderGlyph, openPreviewFile, requestFilesDesktopFolderView, FileIconTile, hashGradient } from './chunk-
|
|
4
|
-
export { Breadcrumbs } from './chunk-
|
|
3
|
+
import { PREVIEW_OPENED_EVENT, publishDesktopFolders, requestFilesTrashView, FolderGlyph, openPreviewFile, requestFilesDesktopFolderView, FileIconTile, hashGradient } from './chunk-P3DVY4XJ.js';
|
|
4
|
+
export { Breadcrumbs } from './chunk-P3DVY4XJ.js';
|
|
5
5
|
import { SidebarLayout } from './chunk-YG45DAUT.js';
|
|
6
6
|
export { SidebarLayout } from './chunk-YG45DAUT.js';
|
|
7
7
|
import { playNotification, playStartup, soundsEnabled, getSoundConfig, SOUND_PACK_KEYS, SOUND_PACKS, SOUND_TYPES, SOUND_TYPE_LABELS, setSoundForType, previewSound, setAllSounds, playLogout } from './chunk-D7PYW2QS.js';
|
|
8
|
-
import { setPdfPreview } from './chunk-
|
|
9
|
-
export { ImageAnnotator_default as ImageAnnotator } from './chunk-
|
|
8
|
+
import { setPdfPreview } from './chunk-BI5XBNI5.js';
|
|
9
|
+
export { ImageAnnotator_default as ImageAnnotator } from './chunk-BI5XBNI5.js';
|
|
10
10
|
import { toast_default } from './chunk-VENYVK3L.js';
|
|
11
11
|
export { toast_default as toast } from './chunk-VENYVK3L.js';
|
|
12
|
-
import { EditableGrid } from './chunk-
|
|
13
|
-
export { EditableGrid } from './chunk-
|
|
12
|
+
import { EditableGrid } from './chunk-OKFJBJY6.js';
|
|
13
|
+
export { EditableGrid } from './chunk-OKFJBJY6.js';
|
|
14
14
|
import { useAuth, useShellAuth } from './chunk-ADJ3CERD.js';
|
|
15
15
|
export { ShellAuthProvider, setShellAuthBridge, useShellAuth } from './chunk-ADJ3CERD.js';
|
|
16
|
-
import { APP_VERSION, VERSION } from './chunk-
|
|
17
|
-
export { VERSION } from './chunk-
|
|
16
|
+
import { APP_VERSION, VERSION } from './chunk-NZLE6YR6.js';
|
|
17
|
+
export { VERSION } from './chunk-NZLE6YR6.js';
|
|
18
18
|
import { useWindowManager, PopupMenu, PopupMenuLabel, PopupMenuDivider, PopupMenuItem, WINDOW_REGISTRY, isPageEntry, Modal, useShellPrefs, useIsMobile, ModalActions, useModalActive, client_default, LoadingSpinner, CancelButton, setWindowPosition, ThumbCard, activateModal } from './chunk-HLWEKEKD.js';
|
|
19
19
|
export { CancelButton, CopyButton, DocFavStar, Modal, ModalActions, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, ShellPrefsProvider, WindowCrashedFallback, WindowErrorBoundary, WindowManagerProvider, WindowTitle, commitExposeHighlight, exitExposeMode, getActiveWindowRoute, getExposeHighlight, getWindowPosition, isEntityEntry, isPageEntry, registerModalEscapeInterceptor, setExposeHighlight, setShellApiClient, setShellWindowRegistry, setWindowDefaultPosition, setWindowPosition, subscribeExposeHighlight, toggleExposeMode, useLocalStoragePrefs, useModalActive, useShellPrefs, useWidgetSettings, useWindowManager, useWindowMenuItem, useWindowTitle } from './chunk-HLWEKEKD.js';
|
|
20
20
|
export { ConfirmProvider, confirm, confirmDestructive, prompt } from './chunk-UBN4IUDE.js';
|
|
21
21
|
import { glassStyle, startMenuCategories, navSections, isSection, GLASS_INPUT_BG, navIcons, sectionIcons } from './chunk-ZF6AYO4G.js';
|
|
22
22
|
export { GLASS_DIVIDER, GLASS_INPUT_BG, glassStyle, setShellNavIcons } from './chunk-ZF6AYO4G.js';
|
|
23
|
-
import { createContext, lazy, forwardRef, useCallback, useState, useRef, useEffect, useMemo, useLayoutEffect, useContext, isValidElement, cloneElement, Suspense, Fragment as Fragment$1,
|
|
23
|
+
import { createContext, lazy, forwardRef, useCallback, useState, useRef, useEffect, useMemo, useLayoutEffect, useContext, isValidElement, cloneElement, Suspense, Fragment as Fragment$1, useId, Children, useSyncExternalStore } from 'react';
|
|
24
24
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
25
25
|
import { Dialog, DialogBackdrop, DialogPanel } from '@headlessui/react';
|
|
26
26
|
import { createPortal } from 'react-dom';
|
|
@@ -591,15 +591,6 @@ function SidebarActionButton({
|
|
|
591
591
|
}
|
|
592
592
|
);
|
|
593
593
|
}
|
|
594
|
-
function useClickOutside(ref, onClose) {
|
|
595
|
-
useEffect(() => {
|
|
596
|
-
const handler = (e) => {
|
|
597
|
-
if (ref.current && !ref.current.contains(e.target)) onClose();
|
|
598
|
-
};
|
|
599
|
-
document.addEventListener("mousedown", handler);
|
|
600
|
-
return () => document.removeEventListener("mousedown", handler);
|
|
601
|
-
}, [ref, onClose]);
|
|
602
|
-
}
|
|
603
594
|
|
|
604
595
|
// src/forms/styles.ts
|
|
605
596
|
var INPUT_BASE = "block w-full rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm text-gray-800 placeholder:text-gray-400 shadow-sm focus:border-blue-400 focus:outline-none focus:ring-2 focus:ring-blue-400/30";
|
|
@@ -608,15 +599,43 @@ var INPUT_DISABLED = "disabled:cursor-not-allowed disabled:opacity-60";
|
|
|
608
599
|
function inputClasses(opts) {
|
|
609
600
|
return [INPUT_BASE, opts?.invalid ? INPUT_INVALID : "", INPUT_DISABLED, opts?.className ?? ""].filter(Boolean).join(" ");
|
|
610
601
|
}
|
|
611
|
-
|
|
612
|
-
|
|
602
|
+
var POPUP_MAX_WIDTH = 448;
|
|
603
|
+
var MENU_MAX_HEIGHT = 240;
|
|
604
|
+
var MENU_GAP = 4;
|
|
605
|
+
var VIEWPORT_MARGIN = 8;
|
|
606
|
+
function useDropdownPosition(triggerRef, open) {
|
|
607
|
+
const [pos, setPos] = useState(null);
|
|
613
608
|
useLayoutEffect(() => {
|
|
614
|
-
if (!open)
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
609
|
+
if (!open) {
|
|
610
|
+
setPos(null);
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
const compute = () => {
|
|
614
|
+
const rect = triggerRef.current?.getBoundingClientRect();
|
|
615
|
+
if (!rect) return;
|
|
616
|
+
const spaceBelow = window.innerHeight - rect.bottom - MENU_GAP - VIEWPORT_MARGIN;
|
|
617
|
+
const spaceAbove = rect.top - MENU_GAP - VIEWPORT_MARGIN;
|
|
618
|
+
const placeAbove = spaceBelow < Math.min(MENU_MAX_HEIGHT, 160) && spaceAbove > spaceBelow;
|
|
619
|
+
const maxHeight = Math.max(96, Math.min(MENU_MAX_HEIGHT, placeAbove ? spaceAbove : spaceBelow));
|
|
620
|
+
const next = { minWidth: rect.width, maxHeight };
|
|
621
|
+
if (window.innerWidth - rect.left < POPUP_MAX_WIDTH) {
|
|
622
|
+
next.right = Math.max(VIEWPORT_MARGIN, window.innerWidth - rect.right);
|
|
623
|
+
} else {
|
|
624
|
+
next.left = Math.max(VIEWPORT_MARGIN, rect.left);
|
|
625
|
+
}
|
|
626
|
+
if (placeAbove) next.bottom = window.innerHeight - rect.top + MENU_GAP;
|
|
627
|
+
else next.top = rect.bottom + MENU_GAP;
|
|
628
|
+
setPos(next);
|
|
629
|
+
};
|
|
630
|
+
compute();
|
|
631
|
+
window.addEventListener("scroll", compute, true);
|
|
632
|
+
window.addEventListener("resize", compute);
|
|
633
|
+
return () => {
|
|
634
|
+
window.removeEventListener("scroll", compute, true);
|
|
635
|
+
window.removeEventListener("resize", compute);
|
|
636
|
+
};
|
|
637
|
+
}, [open, triggerRef]);
|
|
638
|
+
return pos;
|
|
620
639
|
}
|
|
621
640
|
function ClearButton({ onClear, ariaLabel = "Clear selection" }) {
|
|
622
641
|
return /* @__PURE__ */ jsx(
|
|
@@ -655,6 +674,7 @@ function SearchableSelect({
|
|
|
655
674
|
};
|
|
656
675
|
const wrapRef = useRef(null);
|
|
657
676
|
const triggerRef = useRef(null);
|
|
677
|
+
const menuRef = useRef(null);
|
|
658
678
|
const adornRef = useRef(null);
|
|
659
679
|
const [adornPad, setAdornPad] = useState(null);
|
|
660
680
|
useLayoutEffect(() => {
|
|
@@ -665,20 +685,26 @@ function SearchableSelect({
|
|
|
665
685
|
const w = adornRef.current?.offsetWidth ?? 0;
|
|
666
686
|
setAdornPad(w ? w + (value && !disabled ? 32 : 8) + 6 : null);
|
|
667
687
|
});
|
|
668
|
-
const
|
|
669
|
-
const alignRight = useDropdownAlignment(triggerRef, open, POPUP_MAX_WIDTH);
|
|
688
|
+
const menuPos = useDropdownPosition(triggerRef, open);
|
|
670
689
|
const selectedLabel = useMemo(() => {
|
|
671
690
|
const match = options.find((o) => o.value === value);
|
|
672
691
|
if (match) return match.label;
|
|
673
692
|
return allowFreeText ? value : "";
|
|
674
693
|
}, [options, value, allowFreeText]);
|
|
675
|
-
|
|
676
|
-
if (
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
694
|
+
useEffect(() => {
|
|
695
|
+
if (!open) return;
|
|
696
|
+
const handler = (e) => {
|
|
697
|
+
const t = e.target;
|
|
698
|
+
if (wrapRef.current?.contains(t) || menuRef.current?.contains(t)) return;
|
|
699
|
+
if (allowFreeText && search.trim() && search.trim() !== value) {
|
|
700
|
+
onChange(search.trim());
|
|
701
|
+
}
|
|
702
|
+
setOpen(false);
|
|
703
|
+
setSearch("");
|
|
704
|
+
};
|
|
705
|
+
document.addEventListener("mousedown", handler);
|
|
706
|
+
return () => document.removeEventListener("mousedown", handler);
|
|
707
|
+
}, [open, allowFreeText, search, value, onChange]);
|
|
682
708
|
const dedupedOptions = useMemo(() => {
|
|
683
709
|
const seen = /* @__PURE__ */ new Set();
|
|
684
710
|
const out = [];
|
|
@@ -749,29 +775,45 @@ function SearchableSelect({
|
|
|
749
775
|
setSearch("");
|
|
750
776
|
} }),
|
|
751
777
|
rightAdornment && !open && /* @__PURE__ */ jsx("div", { ref: adornRef, className: `absolute top-1/2 -translate-y-1/2 ${value && !disabled ? "right-8" : "right-2"} flex items-center gap-1 flex-nowrap justify-end pointer-events-none`, children: rightAdornment }),
|
|
752
|
-
open &&
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
]
|
|
778
|
+
open && createPortal(
|
|
779
|
+
/* @__PURE__ */ jsx(
|
|
780
|
+
"div",
|
|
781
|
+
{
|
|
782
|
+
ref: menuRef,
|
|
783
|
+
className: "fixed z-[400] rounded-2xl overflow-hidden",
|
|
784
|
+
style: {
|
|
785
|
+
left: menuPos?.left,
|
|
786
|
+
right: menuPos?.right,
|
|
787
|
+
top: menuPos?.top,
|
|
788
|
+
bottom: menuPos?.bottom,
|
|
789
|
+
minWidth: menuPos?.minWidth,
|
|
790
|
+
maxWidth: POPUP_MAX_WIDTH,
|
|
791
|
+
width: "max-content",
|
|
792
|
+
// Hidden for the first paint until the layout effect measures the
|
|
793
|
+
// trigger, so the menu never flashes at (0,0).
|
|
794
|
+
visibility: menuPos ? void 0 : "hidden",
|
|
795
|
+
...glassStyle()
|
|
771
796
|
},
|
|
772
|
-
o
|
|
773
|
-
|
|
774
|
-
|
|
797
|
+
children: /* @__PURE__ */ jsx("div", { className: "overflow-y-auto", style: { maxHeight: menuPos?.maxHeight ?? MENU_MAX_HEIGHT }, children: filtered.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-3 py-3 text-sm text-gray-400 text-center", children: "No matches" }) : filtered.map((o) => /* @__PURE__ */ jsxs(
|
|
798
|
+
"button",
|
|
799
|
+
{
|
|
800
|
+
type: "button",
|
|
801
|
+
onMouseDown: () => {
|
|
802
|
+
onChange(o.value);
|
|
803
|
+
setOpen(false);
|
|
804
|
+
setSearch("");
|
|
805
|
+
},
|
|
806
|
+
className: `w-full text-left px-3 py-1.5 text-sm hover:bg-gray-50 flex items-center justify-between gap-2 whitespace-nowrap ${value === o.value ? "text-blue-600 font-medium bg-blue-50/50" : "text-gray-700"}`,
|
|
807
|
+
children: [
|
|
808
|
+
/* @__PURE__ */ jsx("span", { children: o.label }),
|
|
809
|
+
o.sublabel && /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-400 shrink-0", children: o.sublabel })
|
|
810
|
+
]
|
|
811
|
+
},
|
|
812
|
+
o.value
|
|
813
|
+
)) })
|
|
814
|
+
}
|
|
815
|
+
),
|
|
816
|
+
document.body
|
|
775
817
|
)
|
|
776
818
|
] });
|
|
777
819
|
}
|
|
@@ -2574,6 +2616,15 @@ function useTheme() {
|
|
|
2574
2616
|
}, [accentColor, customBgColor, customTitleColor, customWindowColor, customButtonColor]);
|
|
2575
2617
|
return { theme: saved, resolved };
|
|
2576
2618
|
}
|
|
2619
|
+
function useClickOutside(ref, onClose) {
|
|
2620
|
+
useEffect(() => {
|
|
2621
|
+
const handler = (e) => {
|
|
2622
|
+
if (ref.current && !ref.current.contains(e.target)) onClose();
|
|
2623
|
+
};
|
|
2624
|
+
document.addEventListener("mousedown", handler);
|
|
2625
|
+
return () => document.removeEventListener("mousedown", handler);
|
|
2626
|
+
}, [ref, onClose]);
|
|
2627
|
+
}
|
|
2577
2628
|
function StartupAnimation({ onComplete, ready = false, productName = "react-os-shell", subtitle }) {
|
|
2578
2629
|
const [phase, setPhase] = useState("logo");
|
|
2579
2630
|
const [minTimePassed, setMinTimePassed] = useState(false);
|
|
@@ -6436,6 +6487,7 @@ var Radio_default = Radio;
|
|
|
6436
6487
|
function FormField({
|
|
6437
6488
|
label,
|
|
6438
6489
|
htmlFor,
|
|
6490
|
+
labelId,
|
|
6439
6491
|
hint,
|
|
6440
6492
|
error,
|
|
6441
6493
|
required,
|
|
@@ -6443,12 +6495,12 @@ function FormField({
|
|
|
6443
6495
|
children
|
|
6444
6496
|
}) {
|
|
6445
6497
|
return /* @__PURE__ */ jsxs("div", { className, children: [
|
|
6446
|
-
label && /* @__PURE__ */ jsxs("label", { htmlFor, className: "mb-1 block text-xs font-medium text-gray-600", children: [
|
|
6498
|
+
label && /* @__PURE__ */ jsxs("label", { id: labelId, htmlFor, className: "mb-1 block text-xs font-medium text-gray-600", children: [
|
|
6447
6499
|
label,
|
|
6448
6500
|
required && /* @__PURE__ */ jsx("span", { className: "ml-0.5 text-red-500", children: "*" })
|
|
6449
6501
|
] }),
|
|
6450
6502
|
children,
|
|
6451
|
-
error ? /* @__PURE__ */ jsx("p", { className: "mt-1 text-[11px] text-red-600", children: error }) : hint ? /* @__PURE__ */ jsx("p", { className: "mt-1 text-[11px] text-gray-400", children: hint }) : null
|
|
6503
|
+
error ? /* @__PURE__ */ jsx("p", { id: htmlFor ? `${htmlFor}-error` : void 0, className: "mt-1 text-[11px] text-red-600", children: error }) : hint ? /* @__PURE__ */ jsx("p", { id: htmlFor ? `${htmlFor}-hint` : void 0, className: "mt-1 text-[11px] text-gray-400", children: hint }) : null
|
|
6452
6504
|
] });
|
|
6453
6505
|
}
|
|
6454
6506
|
function Label({ required, children, className = "", ...rest }) {
|
|
@@ -6457,6 +6509,449 @@ function Label({ required, children, className = "", ...rest }) {
|
|
|
6457
6509
|
required && /* @__PURE__ */ jsx("span", { className: "ml-0.5 text-red-500", children: "*" })
|
|
6458
6510
|
] });
|
|
6459
6511
|
}
|
|
6512
|
+
function mediaFileName(url) {
|
|
6513
|
+
const path = (url || "").split("?")[0].split("#")[0];
|
|
6514
|
+
const last = path.substring(path.lastIndexOf("/") + 1);
|
|
6515
|
+
try {
|
|
6516
|
+
return decodeURIComponent(last.replace(/^[0-9a-f]{32}_/i, "")) || last || "media";
|
|
6517
|
+
} catch {
|
|
6518
|
+
return last || "media";
|
|
6519
|
+
}
|
|
6520
|
+
}
|
|
6521
|
+
var VIDEO_EXT_RE = /\.(mp4|webm|ogg|ogv|mov|m4v)(\?|#|$)/i;
|
|
6522
|
+
function isVideoUrl(url, accept = "") {
|
|
6523
|
+
if (!url) return false;
|
|
6524
|
+
const acceptsVideo = accept.includes("video");
|
|
6525
|
+
const acceptsImage = accept.includes("image") || accept === "*" || accept === "";
|
|
6526
|
+
return VIDEO_EXT_RE.test(url) || acceptsVideo && !acceptsImage;
|
|
6527
|
+
}
|
|
6528
|
+
function Spinner2({ className = "h-5 w-5" }) {
|
|
6529
|
+
return /* @__PURE__ */ jsxs("svg", { className: `${className} animate-spin text-gray-400`, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
|
|
6530
|
+
/* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
6531
|
+
/* @__PURE__ */ jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" })
|
|
6532
|
+
] });
|
|
6533
|
+
}
|
|
6534
|
+
function UploadGlyph({ className = "h-6 w-6" }) {
|
|
6535
|
+
return /* @__PURE__ */ jsxs(
|
|
6536
|
+
"svg",
|
|
6537
|
+
{
|
|
6538
|
+
viewBox: "0 0 24 24",
|
|
6539
|
+
fill: "none",
|
|
6540
|
+
stroke: "currentColor",
|
|
6541
|
+
strokeWidth: 1.6,
|
|
6542
|
+
strokeLinecap: "round",
|
|
6543
|
+
strokeLinejoin: "round",
|
|
6544
|
+
"aria-hidden": "true",
|
|
6545
|
+
className,
|
|
6546
|
+
children: [
|
|
6547
|
+
/* @__PURE__ */ jsx("path", { d: "M12 15V4" }),
|
|
6548
|
+
/* @__PURE__ */ jsx("path", { d: "M8 8l4-4 4 4" }),
|
|
6549
|
+
/* @__PURE__ */ jsx("path", { d: "M4 15v3a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-3" })
|
|
6550
|
+
]
|
|
6551
|
+
}
|
|
6552
|
+
);
|
|
6553
|
+
}
|
|
6554
|
+
function MediaUploadField({
|
|
6555
|
+
value,
|
|
6556
|
+
onChange,
|
|
6557
|
+
onPick,
|
|
6558
|
+
label,
|
|
6559
|
+
hint,
|
|
6560
|
+
error,
|
|
6561
|
+
required,
|
|
6562
|
+
className,
|
|
6563
|
+
accept = "image/*",
|
|
6564
|
+
fit = "cover",
|
|
6565
|
+
height = 112,
|
|
6566
|
+
placeholder,
|
|
6567
|
+
cta = "Choose from library or upload",
|
|
6568
|
+
acceptHint,
|
|
6569
|
+
showFilename = true,
|
|
6570
|
+
allowReplace = true,
|
|
6571
|
+
allowRemove = true,
|
|
6572
|
+
replaceLabel = "Replace",
|
|
6573
|
+
removeLabel = "Remove",
|
|
6574
|
+
busy = false,
|
|
6575
|
+
busyLabel = "Uploading\u2026",
|
|
6576
|
+
disabled = false
|
|
6577
|
+
}) {
|
|
6578
|
+
const inputRef = useRef(null);
|
|
6579
|
+
const [dragOver, setDragOver] = useState(false);
|
|
6580
|
+
const [focused, setFocused] = useState(false);
|
|
6581
|
+
const fieldId = useId();
|
|
6582
|
+
const objectUrlRef = useRef(null);
|
|
6583
|
+
const [videoBlobUrl, setVideoBlobUrl] = useState(null);
|
|
6584
|
+
useEffect(() => () => {
|
|
6585
|
+
if (objectUrlRef.current) URL.revokeObjectURL(objectUrlRef.current);
|
|
6586
|
+
}, []);
|
|
6587
|
+
const locked = disabled || busy;
|
|
6588
|
+
const acceptsVideo = accept.includes("video");
|
|
6589
|
+
const acceptsImage = accept.includes("image") || accept === "*" || accept === "";
|
|
6590
|
+
const isVideo = !!value && (isVideoUrl(value, accept) || value === videoBlobUrl);
|
|
6591
|
+
const kindWord = acceptsVideo && !acceptsImage ? "video" : acceptsImage && !acceptsVideo ? "image" : "file";
|
|
6592
|
+
const dimLine = placeholder ?? `Upload ${kindWord === "image" ? "an image" : `a ${kindWord}`}`;
|
|
6593
|
+
const emitObjectUrl = (file) => {
|
|
6594
|
+
if (objectUrlRef.current) URL.revokeObjectURL(objectUrlRef.current);
|
|
6595
|
+
const url = URL.createObjectURL(file);
|
|
6596
|
+
objectUrlRef.current = url;
|
|
6597
|
+
setVideoBlobUrl(file.type.startsWith("video/") ? url : null);
|
|
6598
|
+
onChange(url);
|
|
6599
|
+
};
|
|
6600
|
+
const clearValue = () => {
|
|
6601
|
+
if (objectUrlRef.current) {
|
|
6602
|
+
URL.revokeObjectURL(objectUrlRef.current);
|
|
6603
|
+
objectUrlRef.current = null;
|
|
6604
|
+
}
|
|
6605
|
+
setVideoBlobUrl(null);
|
|
6606
|
+
onChange("");
|
|
6607
|
+
};
|
|
6608
|
+
const pick = (file) => {
|
|
6609
|
+
if (locked) return;
|
|
6610
|
+
if (onPick) {
|
|
6611
|
+
onPick(file ?? void 0);
|
|
6612
|
+
return;
|
|
6613
|
+
}
|
|
6614
|
+
if (file) {
|
|
6615
|
+
emitObjectUrl(file);
|
|
6616
|
+
return;
|
|
6617
|
+
}
|
|
6618
|
+
inputRef.current?.click();
|
|
6619
|
+
};
|
|
6620
|
+
const onNativeFile = (e) => {
|
|
6621
|
+
const file = e.target.files?.[0];
|
|
6622
|
+
if (file) emitObjectUrl(file);
|
|
6623
|
+
if (inputRef.current) inputRef.current.value = "";
|
|
6624
|
+
};
|
|
6625
|
+
const dropHandlers = locked ? {} : {
|
|
6626
|
+
onDragOver: (e) => {
|
|
6627
|
+
e.preventDefault();
|
|
6628
|
+
setDragOver(true);
|
|
6629
|
+
},
|
|
6630
|
+
onDragLeave: () => setDragOver(false),
|
|
6631
|
+
onDrop: (e) => {
|
|
6632
|
+
e.preventDefault();
|
|
6633
|
+
setDragOver(false);
|
|
6634
|
+
const file = e.dataTransfer.files?.[0];
|
|
6635
|
+
if (file) pick(file);
|
|
6636
|
+
}
|
|
6637
|
+
};
|
|
6638
|
+
const previewName = value ? mediaFileName(value) : "";
|
|
6639
|
+
const filled = /* @__PURE__ */ jsxs("div", { children: [
|
|
6640
|
+
/* @__PURE__ */ jsxs(
|
|
6641
|
+
"div",
|
|
6642
|
+
{
|
|
6643
|
+
...dropHandlers,
|
|
6644
|
+
className: [
|
|
6645
|
+
"relative overflow-hidden rounded-md border bg-gray-100 transition-colors",
|
|
6646
|
+
dragOver ? "border-blue-500" : "border-gray-200"
|
|
6647
|
+
].join(" "),
|
|
6648
|
+
style: { height },
|
|
6649
|
+
children: [
|
|
6650
|
+
isVideo ? /* @__PURE__ */ jsx(
|
|
6651
|
+
"video",
|
|
6652
|
+
{
|
|
6653
|
+
src: value ?? void 0,
|
|
6654
|
+
muted: true,
|
|
6655
|
+
playsInline: true,
|
|
6656
|
+
preload: "metadata",
|
|
6657
|
+
"aria-label": previewName || void 0,
|
|
6658
|
+
className: "h-full w-full",
|
|
6659
|
+
style: { objectFit: fit }
|
|
6660
|
+
}
|
|
6661
|
+
) : /* @__PURE__ */ jsx("img", { src: value ?? void 0, alt: previewName, className: "h-full w-full", style: { objectFit: fit } }),
|
|
6662
|
+
showFilename && value && /* @__PURE__ */ jsx(
|
|
6663
|
+
"span",
|
|
6664
|
+
{
|
|
6665
|
+
className: "absolute inset-x-1 bottom-1 truncate rounded px-1.5 py-0.5 text-xs text-white",
|
|
6666
|
+
style: { background: "rgba(0,0,0,0.6)" },
|
|
6667
|
+
children: previewName
|
|
6668
|
+
}
|
|
6669
|
+
),
|
|
6670
|
+
busy && /* @__PURE__ */ jsxs(
|
|
6671
|
+
"div",
|
|
6672
|
+
{
|
|
6673
|
+
role: "status",
|
|
6674
|
+
className: "absolute inset-0 flex items-center justify-center gap-2",
|
|
6675
|
+
style: { background: "rgba(255,255,255,0.6)" },
|
|
6676
|
+
children: [
|
|
6677
|
+
/* @__PURE__ */ jsx(Spinner2, {}),
|
|
6678
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-600", children: busyLabel })
|
|
6679
|
+
]
|
|
6680
|
+
}
|
|
6681
|
+
)
|
|
6682
|
+
]
|
|
6683
|
+
}
|
|
6684
|
+
),
|
|
6685
|
+
!disabled && (allowReplace || allowRemove) && /* @__PURE__ */ jsxs("div", { className: "mt-2 flex gap-2", children: [
|
|
6686
|
+
allowReplace && /* @__PURE__ */ jsx(Button_default, { id: fieldId, variant: "secondary", size: "sm", onClick: () => pick(), disabled: busy, children: replaceLabel }),
|
|
6687
|
+
allowRemove && /* @__PURE__ */ jsx(Button_default, { variant: "ghost", size: "sm", onClick: clearValue, disabled: busy, children: removeLabel })
|
|
6688
|
+
] })
|
|
6689
|
+
] });
|
|
6690
|
+
const empty = /* @__PURE__ */ jsx(
|
|
6691
|
+
"button",
|
|
6692
|
+
{
|
|
6693
|
+
type: "button",
|
|
6694
|
+
id: fieldId,
|
|
6695
|
+
onClick: () => pick(),
|
|
6696
|
+
disabled: locked,
|
|
6697
|
+
"aria-label": typeof dimLine === "string" ? dimLine : "Upload media",
|
|
6698
|
+
"aria-busy": busy || void 0,
|
|
6699
|
+
"aria-invalid": error ? true : void 0,
|
|
6700
|
+
"aria-required": required || void 0,
|
|
6701
|
+
"aria-describedby": error ? `${fieldId}-error` : hint ? `${fieldId}-hint` : void 0,
|
|
6702
|
+
onFocus: () => setFocused(true),
|
|
6703
|
+
onBlur: () => setFocused(false),
|
|
6704
|
+
...dropHandlers,
|
|
6705
|
+
className: [
|
|
6706
|
+
"flex w-full flex-col items-center justify-center gap-1.5 rounded-lg border-2 border-dashed text-center transition-colors",
|
|
6707
|
+
locked ? "cursor-not-allowed opacity-60" : "cursor-pointer",
|
|
6708
|
+
dragOver ? "border-blue-500 bg-blue-50" : "border-gray-300 bg-gray-50 hover:bg-gray-100"
|
|
6709
|
+
].join(" "),
|
|
6710
|
+
style: {
|
|
6711
|
+
minHeight: height,
|
|
6712
|
+
outline: "none",
|
|
6713
|
+
boxShadow: focused && !locked ? "0 0 0 2px rgba(59,130,246,0.45)" : void 0
|
|
6714
|
+
},
|
|
6715
|
+
children: busy ? /* @__PURE__ */ jsxs("span", { role: "status", className: "flex flex-col items-center gap-1.5", children: [
|
|
6716
|
+
/* @__PURE__ */ jsx(Spinner2, {}),
|
|
6717
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-500", children: busyLabel })
|
|
6718
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6719
|
+
/* @__PURE__ */ jsx("span", { className: "text-gray-400", children: /* @__PURE__ */ jsx(UploadGlyph, {}) }),
|
|
6720
|
+
/* @__PURE__ */ jsx("span", { className: "px-3 text-xs text-gray-500", children: dimLine }),
|
|
6721
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-blue-600", children: cta }),
|
|
6722
|
+
acceptHint && /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-400", children: acceptHint })
|
|
6723
|
+
] })
|
|
6724
|
+
}
|
|
6725
|
+
);
|
|
6726
|
+
return /* @__PURE__ */ jsxs(FormField, { label, htmlFor: fieldId, hint, error, required, className, children: [
|
|
6727
|
+
value ? filled : empty,
|
|
6728
|
+
!onPick && /* @__PURE__ */ jsx("input", { ref: inputRef, type: "file", accept, className: "hidden", onChange: onNativeFile })
|
|
6729
|
+
] });
|
|
6730
|
+
}
|
|
6731
|
+
var REMOVE_ICON = /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", "aria-hidden": "true", className: "h-3 w-3", children: /* @__PURE__ */ jsx("path", { d: "M6 6l12 12M18 6L6 18" }) });
|
|
6732
|
+
function MediaUploadGrid({
|
|
6733
|
+
items,
|
|
6734
|
+
onPick,
|
|
6735
|
+
onRemove,
|
|
6736
|
+
onReorder,
|
|
6737
|
+
label,
|
|
6738
|
+
hint,
|
|
6739
|
+
error,
|
|
6740
|
+
required,
|
|
6741
|
+
className,
|
|
6742
|
+
accept = "image/*",
|
|
6743
|
+
fit = "cover",
|
|
6744
|
+
thumbSize = 96,
|
|
6745
|
+
placeholder,
|
|
6746
|
+
cta = "Choose from library or upload",
|
|
6747
|
+
acceptHint,
|
|
6748
|
+
showCover = false,
|
|
6749
|
+
coverLabel = "Cover",
|
|
6750
|
+
busy = false,
|
|
6751
|
+
busyLabel = "Uploading\u2026",
|
|
6752
|
+
disabled = false,
|
|
6753
|
+
readOnly = false
|
|
6754
|
+
}) {
|
|
6755
|
+
const gridId = useId();
|
|
6756
|
+
const [zoneDragOver, setZoneDragOver] = useState(false);
|
|
6757
|
+
const [draggingIndex, setDraggingIndex] = useState(null);
|
|
6758
|
+
const [focusedKey, setFocusedKey] = useState(null);
|
|
6759
|
+
const ringStyle = (key) => ({
|
|
6760
|
+
outline: "none",
|
|
6761
|
+
...focusedKey === key && !locked ? { boxShadow: "0 0 0 2px rgba(59,130,246,0.45)" } : {}
|
|
6762
|
+
});
|
|
6763
|
+
const blurKey = (key) => setFocusedKey((k) => k === key ? null : k);
|
|
6764
|
+
const locked = disabled || busy;
|
|
6765
|
+
const canAdd = !!onPick && !locked && !readOnly;
|
|
6766
|
+
const canRemove = !!onRemove && !locked && !readOnly;
|
|
6767
|
+
const reorderEnabled = !!onReorder && !locked && !readOnly;
|
|
6768
|
+
const acceptsVideo = accept.includes("video");
|
|
6769
|
+
const acceptsImage = accept.includes("image") || accept === "*" || accept === "";
|
|
6770
|
+
const kindWord = acceptsVideo && !acceptsImage ? "video" : acceptsImage && !acceptsVideo ? "image" : "file";
|
|
6771
|
+
const dimLine = placeholder ?? `Upload ${kindWord === "image" ? "an image" : `a ${kindWord}`}`;
|
|
6772
|
+
const pick = (file) => {
|
|
6773
|
+
if (!canAdd) return;
|
|
6774
|
+
onPick(file ?? void 0);
|
|
6775
|
+
};
|
|
6776
|
+
const isFileDrag = (e) => Array.from(e.dataTransfer.types || []).includes("Files");
|
|
6777
|
+
const zoneHandlers = canAdd ? {
|
|
6778
|
+
onDragOver: (e) => {
|
|
6779
|
+
if (!isFileDrag(e)) return;
|
|
6780
|
+
e.preventDefault();
|
|
6781
|
+
setZoneDragOver(true);
|
|
6782
|
+
},
|
|
6783
|
+
onDragLeave: () => setZoneDragOver(false),
|
|
6784
|
+
onDrop: (e) => {
|
|
6785
|
+
const file = e.dataTransfer.files?.[0];
|
|
6786
|
+
if (!file) return;
|
|
6787
|
+
e.preventDefault();
|
|
6788
|
+
setZoneDragOver(false);
|
|
6789
|
+
pick(file);
|
|
6790
|
+
}
|
|
6791
|
+
} : {};
|
|
6792
|
+
const square = { width: thumbSize, height: thumbSize };
|
|
6793
|
+
const thumb = (item, index) => {
|
|
6794
|
+
const video = item.kind ? item.kind === "video" : isVideoUrl(item.url, accept);
|
|
6795
|
+
const name = mediaFileName(item.url);
|
|
6796
|
+
const isCover = showCover && (item.cover ?? index === 0);
|
|
6797
|
+
return /* @__PURE__ */ jsxs(
|
|
6798
|
+
"div",
|
|
6799
|
+
{
|
|
6800
|
+
draggable: reorderEnabled || void 0,
|
|
6801
|
+
onDragStart: reorderEnabled ? (e) => {
|
|
6802
|
+
e.dataTransfer.effectAllowed = "move";
|
|
6803
|
+
e.dataTransfer.setData("text/plain", String(index));
|
|
6804
|
+
setDraggingIndex(index);
|
|
6805
|
+
} : void 0,
|
|
6806
|
+
onDragEnd: reorderEnabled ? () => setDraggingIndex(null) : void 0,
|
|
6807
|
+
onDragOver: reorderEnabled ? (e) => {
|
|
6808
|
+
if (draggingIndex == null) return;
|
|
6809
|
+
e.preventDefault();
|
|
6810
|
+
e.stopPropagation();
|
|
6811
|
+
} : void 0,
|
|
6812
|
+
onDrop: reorderEnabled ? (e) => {
|
|
6813
|
+
if (draggingIndex == null) return;
|
|
6814
|
+
e.preventDefault();
|
|
6815
|
+
e.stopPropagation();
|
|
6816
|
+
if (draggingIndex !== index) onReorder(draggingIndex, index);
|
|
6817
|
+
setDraggingIndex(null);
|
|
6818
|
+
} : void 0,
|
|
6819
|
+
tabIndex: reorderEnabled ? 0 : void 0,
|
|
6820
|
+
"aria-label": reorderEnabled ? `${name}, item ${index + 1} of ${items.length}. Use arrow keys to reorder.` : void 0,
|
|
6821
|
+
onKeyDown: reorderEnabled ? (e) => {
|
|
6822
|
+
if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
|
|
6823
|
+
if (index > 0) {
|
|
6824
|
+
e.preventDefault();
|
|
6825
|
+
onReorder(index, index - 1);
|
|
6826
|
+
}
|
|
6827
|
+
} else if (e.key === "ArrowRight" || e.key === "ArrowDown") {
|
|
6828
|
+
if (index < items.length - 1) {
|
|
6829
|
+
e.preventDefault();
|
|
6830
|
+
onReorder(index, index + 1);
|
|
6831
|
+
}
|
|
6832
|
+
}
|
|
6833
|
+
} : void 0,
|
|
6834
|
+
onFocus: reorderEnabled ? (e) => {
|
|
6835
|
+
if (e.target === e.currentTarget) setFocusedKey(`thumb:${item.id}`);
|
|
6836
|
+
} : void 0,
|
|
6837
|
+
onBlur: reorderEnabled ? (e) => {
|
|
6838
|
+
if (e.target === e.currentTarget) blurKey(`thumb:${item.id}`);
|
|
6839
|
+
} : void 0,
|
|
6840
|
+
className: [
|
|
6841
|
+
"relative shrink-0 overflow-hidden rounded-md border border-gray-200 bg-gray-100",
|
|
6842
|
+
draggingIndex === index ? "opacity-50" : ""
|
|
6843
|
+
].join(" "),
|
|
6844
|
+
style: { ...square, cursor: reorderEnabled ? "move" : void 0, ...ringStyle(`thumb:${item.id}`) },
|
|
6845
|
+
children: [
|
|
6846
|
+
video ? /* @__PURE__ */ jsx("video", { src: item.url, muted: true, playsInline: true, preload: "metadata", "aria-label": name, className: "h-full w-full", style: { objectFit: fit } }) : /* @__PURE__ */ jsx("img", { src: item.url, alt: name, className: "h-full w-full", style: { objectFit: fit } }),
|
|
6847
|
+
isCover && /* @__PURE__ */ jsx("span", { className: "absolute left-1 top-1 rounded bg-blue-600 px-1.5 py-0.5 text-xs font-medium text-white", children: coverLabel }),
|
|
6848
|
+
item.caption != null && /* @__PURE__ */ jsx(
|
|
6849
|
+
"span",
|
|
6850
|
+
{
|
|
6851
|
+
className: "absolute inset-x-1 bottom-1 truncate rounded px-1.5 py-0.5 text-xs text-white",
|
|
6852
|
+
style: { background: "rgba(0,0,0,0.6)" },
|
|
6853
|
+
children: item.caption
|
|
6854
|
+
}
|
|
6855
|
+
),
|
|
6856
|
+
canRemove && /* @__PURE__ */ jsx(
|
|
6857
|
+
"button",
|
|
6858
|
+
{
|
|
6859
|
+
type: "button",
|
|
6860
|
+
onClick: () => onRemove(item.id),
|
|
6861
|
+
"aria-label": `Remove ${name}`,
|
|
6862
|
+
onFocus: () => setFocusedKey(`rm:${item.id}`),
|
|
6863
|
+
onBlur: () => blurKey(`rm:${item.id}`),
|
|
6864
|
+
className: "absolute right-1 top-1 flex h-5 w-5 items-center justify-center rounded-full text-white",
|
|
6865
|
+
style: { background: "rgba(0,0,0,0.55)", ...ringStyle(`rm:${item.id}`) },
|
|
6866
|
+
children: REMOVE_ICON
|
|
6867
|
+
}
|
|
6868
|
+
)
|
|
6869
|
+
]
|
|
6870
|
+
},
|
|
6871
|
+
item.id
|
|
6872
|
+
);
|
|
6873
|
+
};
|
|
6874
|
+
const addTile = canAdd && /* @__PURE__ */ jsxs(
|
|
6875
|
+
"button",
|
|
6876
|
+
{
|
|
6877
|
+
type: "button",
|
|
6878
|
+
onClick: () => pick(),
|
|
6879
|
+
"aria-label": "Add media",
|
|
6880
|
+
onFocus: () => setFocusedKey("add"),
|
|
6881
|
+
onBlur: () => blurKey("add"),
|
|
6882
|
+
className: "flex shrink-0 flex-col items-center justify-center gap-1 rounded-md border-2 border-dashed border-gray-300 bg-gray-50 text-gray-400 transition-colors hover:bg-gray-100 hover:text-gray-500",
|
|
6883
|
+
style: { ...square, ...ringStyle("add") },
|
|
6884
|
+
children: [
|
|
6885
|
+
/* @__PURE__ */ jsx(UploadGlyph, { className: "h-5 w-5" }),
|
|
6886
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-500", children: "Add" })
|
|
6887
|
+
]
|
|
6888
|
+
}
|
|
6889
|
+
);
|
|
6890
|
+
const emptyDropzone = canAdd ? /* @__PURE__ */ jsxs(
|
|
6891
|
+
"button",
|
|
6892
|
+
{
|
|
6893
|
+
type: "button",
|
|
6894
|
+
onClick: () => pick(),
|
|
6895
|
+
"aria-label": typeof dimLine === "string" ? dimLine : "Upload media",
|
|
6896
|
+
onFocus: () => setFocusedKey("zone"),
|
|
6897
|
+
onBlur: () => blurKey("zone"),
|
|
6898
|
+
className: [
|
|
6899
|
+
"flex w-full flex-col items-center justify-center gap-1.5 rounded-lg border-2 border-dashed text-center transition-colors cursor-pointer",
|
|
6900
|
+
zoneDragOver ? "border-blue-500 bg-blue-50" : "border-gray-300 bg-gray-50 hover:bg-gray-100"
|
|
6901
|
+
].join(" "),
|
|
6902
|
+
style: { minHeight: thumbSize + 32, ...ringStyle("zone") },
|
|
6903
|
+
children: [
|
|
6904
|
+
/* @__PURE__ */ jsx("span", { className: "text-gray-400", children: /* @__PURE__ */ jsx(UploadGlyph, {}) }),
|
|
6905
|
+
/* @__PURE__ */ jsx("span", { className: "px-3 text-xs text-gray-500", children: dimLine }),
|
|
6906
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-blue-600", children: cta }),
|
|
6907
|
+
acceptHint && /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-400", children: acceptHint })
|
|
6908
|
+
]
|
|
6909
|
+
}
|
|
6910
|
+
) : /* @__PURE__ */ jsx(
|
|
6911
|
+
"div",
|
|
6912
|
+
{
|
|
6913
|
+
className: "flex w-full items-center justify-center rounded-lg border border-gray-200 bg-gray-50 px-3 text-xs text-gray-400",
|
|
6914
|
+
style: { minHeight: thumbSize + 32 },
|
|
6915
|
+
children: "No media."
|
|
6916
|
+
}
|
|
6917
|
+
);
|
|
6918
|
+
return /* @__PURE__ */ jsx(FormField, { label, labelId: label ? `${gridId}-label` : void 0, htmlFor: gridId, hint, error, required, className, children: /* @__PURE__ */ jsxs(
|
|
6919
|
+
"div",
|
|
6920
|
+
{
|
|
6921
|
+
id: gridId,
|
|
6922
|
+
role: "group",
|
|
6923
|
+
"aria-labelledby": label ? `${gridId}-label` : void 0,
|
|
6924
|
+
"aria-describedby": error ? `${gridId}-error` : hint ? `${gridId}-hint` : void 0,
|
|
6925
|
+
"aria-busy": busy || void 0,
|
|
6926
|
+
...zoneHandlers,
|
|
6927
|
+
className: "relative rounded-lg transition-colors",
|
|
6928
|
+
style: {
|
|
6929
|
+
...locked ? { opacity: 0.6 } : {},
|
|
6930
|
+
// Inline box-shadow, not `ring-*` — the kit's shipped stylesheet has no
|
|
6931
|
+
// Tailwind ring machinery (see MediaUploadField's focus ring).
|
|
6932
|
+
...zoneDragOver ? { boxShadow: "0 0 0 2px rgba(59,130,246,0.5)" } : {}
|
|
6933
|
+
},
|
|
6934
|
+
children: [
|
|
6935
|
+
items.length === 0 ? emptyDropzone : /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
6936
|
+
items.map(thumb),
|
|
6937
|
+
addTile
|
|
6938
|
+
] }),
|
|
6939
|
+
busy && /* @__PURE__ */ jsxs(
|
|
6940
|
+
"div",
|
|
6941
|
+
{
|
|
6942
|
+
role: "status",
|
|
6943
|
+
className: "absolute inset-0 flex items-center justify-center gap-2 rounded-lg",
|
|
6944
|
+
style: { background: "rgba(255,255,255,0.6)" },
|
|
6945
|
+
children: [
|
|
6946
|
+
/* @__PURE__ */ jsx(Spinner2, {}),
|
|
6947
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-600", children: busyLabel })
|
|
6948
|
+
]
|
|
6949
|
+
}
|
|
6950
|
+
)
|
|
6951
|
+
]
|
|
6952
|
+
}
|
|
6953
|
+
) });
|
|
6954
|
+
}
|
|
6460
6955
|
function Card({ children, header, footer, padded = true, className = "" }) {
|
|
6461
6956
|
return /* @__PURE__ */ jsxs("div", { className: `rounded-lg border border-gray-200 bg-white shadow-sm ${className}`.trim(), children: [
|
|
6462
6957
|
header && /* @__PURE__ */ jsx("div", { className: "border-b border-gray-100 px-4 py-3 text-sm font-semibold text-gray-900", children: header }),
|
|
@@ -8968,6 +9463,6 @@ function useEditHotkey(callback) {
|
|
|
8968
9463
|
}, [callback, isActive]);
|
|
8969
9464
|
}
|
|
8970
9465
|
|
|
8971
|
-
export { ALT, ALT_SHIFT_D, ALT_SHIFT_E, ALT_SHIFT_N, Accordion, AuthScreen, Avatar, AvatarGroup, Banner, BarChart, BehaviorPanel, BulkImportGrid, Button_default as Button, CMD_A, CMD_DOT, CMD_ENTER, CMD_K, CMD_S, Card, ChangePasswordForm, ChatTemplate, Checkbox_default as Checkbox, CheckoutTemplate, ColoredBadge, ContainerFillChart, Customization, DEV_BANNER_TEXT, DashboardTemplate, DataTablePage, Desktop, DesktopHostProvider, DevIndicator, DonutChart, ENTER, EmailTemplate, EmptyState, EntityList, ErrorPage, FilterBar, FormField, FormLayoutPage, GalleryTemplate, GlobalSearch, HelpCenter, INPUT_BASE, Input_default as Input, Kanban, Label, Layout, ListFooter, LoadingSpinner2 as LoadingSpinner, MOD, Markdown, MilestoneTimeline, NotificationBell, PageHeader, Pagination, PdfActionButton, Radio_default as Radio, ResizableTable, SHIFT, SearchableSelect, Select_default as Select, ServerStatusIndicator, ShellEntityFetcherProvider, ShortcutHelp, SidebarActionButton, SidebarGroupLabel, SidebarNavItem, SoundsPanel, Sparkline, StartMenu, StatCard, StatusBadge, StatusBadgeProvider, SystemPreferences, Tabs, Textarea_default as Textarea, Tooltip, TopNav, WidgetManager, applyDevTitle, createWindowRegistry, findDuplicateKeys, formatDate, inputClasses, isDevEnv, isMac, mergeBulkItems, useClickOutside, useColumnConfig, useDesktopHost, useEditHotkey, useFilters, useInfiniteScroll, useNewHotkey, useShellEntityFetcher, useSort, useTableNav };
|
|
9466
|
+
export { ALT, ALT_SHIFT_D, ALT_SHIFT_E, ALT_SHIFT_N, Accordion, AuthScreen, Avatar, AvatarGroup, Banner, BarChart, BehaviorPanel, BulkImportGrid, Button_default as Button, CMD_A, CMD_DOT, CMD_ENTER, CMD_K, CMD_S, Card, ChangePasswordForm, ChatTemplate, Checkbox_default as Checkbox, CheckoutTemplate, ColoredBadge, ContainerFillChart, Customization, DEV_BANNER_TEXT, DashboardTemplate, DataTablePage, Desktop, DesktopHostProvider, DevIndicator, DonutChart, ENTER, EmailTemplate, EmptyState, EntityList, ErrorPage, FilterBar, FormField, FormLayoutPage, GalleryTemplate, GlobalSearch, HelpCenter, INPUT_BASE, Input_default as Input, Kanban, Label, Layout, ListFooter, LoadingSpinner2 as LoadingSpinner, MOD, Markdown, MediaUploadField, MediaUploadGrid, MilestoneTimeline, NotificationBell, PageHeader, Pagination, PdfActionButton, Radio_default as Radio, ResizableTable, SHIFT, SearchableSelect, Select_default as Select, ServerStatusIndicator, ShellEntityFetcherProvider, ShortcutHelp, SidebarActionButton, SidebarGroupLabel, SidebarNavItem, SoundsPanel, Sparkline, StartMenu, StatCard, StatusBadge, StatusBadgeProvider, SystemPreferences, Tabs, Textarea_default as Textarea, Tooltip, TopNav, WidgetManager, applyDevTitle, createWindowRegistry, findDuplicateKeys, formatDate, inputClasses, isDevEnv, isMac, mediaFileName, mergeBulkItems, useClickOutside, useColumnConfig, useDesktopHost, useEditHotkey, useFilters, useInfiniteScroll, useNewHotkey, useShellEntityFetcher, useSort, useTableNav };
|
|
8972
9467
|
//# sourceMappingURL=index.js.map
|
|
8973
9468
|
//# sourceMappingURL=index.js.map
|