react-os-shell 3.10.1 → 3.11.1
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-OMB2YWT7.js} +4 -4
- package/dist/{Browser-3SDMP5NU.js.map → Browser-OMB2YWT7.js.map} +1 -1
- package/dist/{Documents-FOCBCZHY.js → Documents-FNUDJADL.js} +3 -3
- package/dist/{Documents-FOCBCZHY.js.map → Documents-FNUDJADL.js.map} +1 -1
- package/dist/Files-YVG267R2.js +12 -0
- package/dist/{Files-P37UZJVD.js.map → Files-YVG267R2.js.map} +1 -1
- package/dist/{Notepad-WDDJQVXF.js → Notepad-ZOF2A7Q7.js} +3 -3
- package/dist/{Notepad-WDDJQVXF.js.map → Notepad-ZOF2A7Q7.js.map} +1 -1
- package/dist/Preview-PNMJG2WL.js +8 -0
- package/dist/{Preview-CESYNTOE.js.map → Preview-PNMJG2WL.js.map} +1 -1
- package/dist/{Spreadsheet-6SICRWKK.js → Spreadsheet-BPJIYAXF.js} +4 -4
- package/dist/{Spreadsheet-6SICRWKK.js.map → Spreadsheet-BPJIYAXF.js.map} +1 -1
- package/dist/apps/index.js +12 -12
- package/dist/{chunk-SRFLPGGO.js → chunk-5HBGCZKG.js} +3 -3
- package/dist/{chunk-SRFLPGGO.js.map → chunk-5HBGCZKG.js.map} +1 -1
- package/dist/{chunk-3SOG3MFC.js → chunk-76SEPQRP.js} +4 -4
- package/dist/{chunk-3SOG3MFC.js.map → chunk-76SEPQRP.js.map} +1 -1
- package/dist/{chunk-YPIDICFR.js → chunk-GOT6PRT2.js} +3 -3
- package/dist/{chunk-YPIDICFR.js.map → chunk-GOT6PRT2.js.map} +1 -1
- package/dist/{chunk-OZFGITVF.js → chunk-MSP7WNTK.js} +3 -3
- package/dist/{chunk-OZFGITVF.js.map → chunk-MSP7WNTK.js.map} +1 -1
- package/dist/{chunk-WEQXKNOA.js → chunk-PQYTYQ62.js} +3 -3
- package/dist/{chunk-WEQXKNOA.js.map → chunk-PQYTYQ62.js.map} +1 -1
- package/dist/{chunk-L5SPKS76.js → chunk-XORQ5BQL.js} +4 -4
- package/dist/{chunk-L5SPKS76.js.map → chunk-XORQ5BQL.js.map} +1 -1
- package/dist/index.d.ts +138 -2
- package/dist/index.js +456 -12
- 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-XORQ5BQL.js';
|
|
4
|
+
export { Breadcrumbs } from './chunk-XORQ5BQL.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-PQYTYQ62.js';
|
|
9
|
+
export { ImageAnnotator_default as ImageAnnotator } from './chunk-PQYTYQ62.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-GOT6PRT2.js';
|
|
13
|
+
export { EditableGrid } from './chunk-GOT6PRT2.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-5HBGCZKG.js';
|
|
17
|
+
export { VERSION } from './chunk-5HBGCZKG.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';
|
|
@@ -6436,6 +6436,7 @@ var Radio_default = Radio;
|
|
|
6436
6436
|
function FormField({
|
|
6437
6437
|
label,
|
|
6438
6438
|
htmlFor,
|
|
6439
|
+
labelId,
|
|
6439
6440
|
hint,
|
|
6440
6441
|
error,
|
|
6441
6442
|
required,
|
|
@@ -6443,12 +6444,12 @@ function FormField({
|
|
|
6443
6444
|
children
|
|
6444
6445
|
}) {
|
|
6445
6446
|
return /* @__PURE__ */ jsxs("div", { className, children: [
|
|
6446
|
-
label && /* @__PURE__ */ jsxs("label", { htmlFor, className: "mb-1 block text-xs font-medium text-gray-600", children: [
|
|
6447
|
+
label && /* @__PURE__ */ jsxs("label", { id: labelId, htmlFor, className: "mb-1 block text-xs font-medium text-gray-600", children: [
|
|
6447
6448
|
label,
|
|
6448
6449
|
required && /* @__PURE__ */ jsx("span", { className: "ml-0.5 text-red-500", children: "*" })
|
|
6449
6450
|
] }),
|
|
6450
6451
|
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
|
|
6452
|
+
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
6453
|
] });
|
|
6453
6454
|
}
|
|
6454
6455
|
function Label({ required, children, className = "", ...rest }) {
|
|
@@ -6457,6 +6458,449 @@ function Label({ required, children, className = "", ...rest }) {
|
|
|
6457
6458
|
required && /* @__PURE__ */ jsx("span", { className: "ml-0.5 text-red-500", children: "*" })
|
|
6458
6459
|
] });
|
|
6459
6460
|
}
|
|
6461
|
+
function mediaFileName(url) {
|
|
6462
|
+
const path = (url || "").split("?")[0].split("#")[0];
|
|
6463
|
+
const last = path.substring(path.lastIndexOf("/") + 1);
|
|
6464
|
+
try {
|
|
6465
|
+
return decodeURIComponent(last.replace(/^[0-9a-f]{32}_/i, "")) || last || "media";
|
|
6466
|
+
} catch {
|
|
6467
|
+
return last || "media";
|
|
6468
|
+
}
|
|
6469
|
+
}
|
|
6470
|
+
var VIDEO_EXT_RE = /\.(mp4|webm|ogg|ogv|mov|m4v)(\?|#|$)/i;
|
|
6471
|
+
function isVideoUrl(url, accept = "") {
|
|
6472
|
+
if (!url) return false;
|
|
6473
|
+
const acceptsVideo = accept.includes("video");
|
|
6474
|
+
const acceptsImage = accept.includes("image") || accept === "*" || accept === "";
|
|
6475
|
+
return VIDEO_EXT_RE.test(url) || acceptsVideo && !acceptsImage;
|
|
6476
|
+
}
|
|
6477
|
+
function Spinner2({ className = "h-5 w-5" }) {
|
|
6478
|
+
return /* @__PURE__ */ jsxs("svg", { className: `${className} animate-spin text-gray-400`, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
|
|
6479
|
+
/* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
6480
|
+
/* @__PURE__ */ jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" })
|
|
6481
|
+
] });
|
|
6482
|
+
}
|
|
6483
|
+
function UploadGlyph({ className = "h-6 w-6" }) {
|
|
6484
|
+
return /* @__PURE__ */ jsxs(
|
|
6485
|
+
"svg",
|
|
6486
|
+
{
|
|
6487
|
+
viewBox: "0 0 24 24",
|
|
6488
|
+
fill: "none",
|
|
6489
|
+
stroke: "currentColor",
|
|
6490
|
+
strokeWidth: 1.6,
|
|
6491
|
+
strokeLinecap: "round",
|
|
6492
|
+
strokeLinejoin: "round",
|
|
6493
|
+
"aria-hidden": "true",
|
|
6494
|
+
className,
|
|
6495
|
+
children: [
|
|
6496
|
+
/* @__PURE__ */ jsx("path", { d: "M12 15V4" }),
|
|
6497
|
+
/* @__PURE__ */ jsx("path", { d: "M8 8l4-4 4 4" }),
|
|
6498
|
+
/* @__PURE__ */ jsx("path", { d: "M4 15v3a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-3" })
|
|
6499
|
+
]
|
|
6500
|
+
}
|
|
6501
|
+
);
|
|
6502
|
+
}
|
|
6503
|
+
function MediaUploadField({
|
|
6504
|
+
value,
|
|
6505
|
+
onChange,
|
|
6506
|
+
onPick,
|
|
6507
|
+
label,
|
|
6508
|
+
hint,
|
|
6509
|
+
error,
|
|
6510
|
+
required,
|
|
6511
|
+
className,
|
|
6512
|
+
accept = "image/*",
|
|
6513
|
+
fit = "cover",
|
|
6514
|
+
height = 112,
|
|
6515
|
+
placeholder,
|
|
6516
|
+
cta = "Choose from library or upload",
|
|
6517
|
+
acceptHint,
|
|
6518
|
+
showFilename = true,
|
|
6519
|
+
allowReplace = true,
|
|
6520
|
+
allowRemove = true,
|
|
6521
|
+
replaceLabel = "Replace",
|
|
6522
|
+
removeLabel = "Remove",
|
|
6523
|
+
busy = false,
|
|
6524
|
+
busyLabel = "Uploading\u2026",
|
|
6525
|
+
disabled = false
|
|
6526
|
+
}) {
|
|
6527
|
+
const inputRef = useRef(null);
|
|
6528
|
+
const [dragOver, setDragOver] = useState(false);
|
|
6529
|
+
const [focused, setFocused] = useState(false);
|
|
6530
|
+
const fieldId = useId();
|
|
6531
|
+
const objectUrlRef = useRef(null);
|
|
6532
|
+
const [videoBlobUrl, setVideoBlobUrl] = useState(null);
|
|
6533
|
+
useEffect(() => () => {
|
|
6534
|
+
if (objectUrlRef.current) URL.revokeObjectURL(objectUrlRef.current);
|
|
6535
|
+
}, []);
|
|
6536
|
+
const locked = disabled || busy;
|
|
6537
|
+
const acceptsVideo = accept.includes("video");
|
|
6538
|
+
const acceptsImage = accept.includes("image") || accept === "*" || accept === "";
|
|
6539
|
+
const isVideo = !!value && (isVideoUrl(value, accept) || value === videoBlobUrl);
|
|
6540
|
+
const kindWord = acceptsVideo && !acceptsImage ? "video" : acceptsImage && !acceptsVideo ? "image" : "file";
|
|
6541
|
+
const dimLine = placeholder ?? `Upload ${kindWord === "image" ? "an image" : `a ${kindWord}`}`;
|
|
6542
|
+
const emitObjectUrl = (file) => {
|
|
6543
|
+
if (objectUrlRef.current) URL.revokeObjectURL(objectUrlRef.current);
|
|
6544
|
+
const url = URL.createObjectURL(file);
|
|
6545
|
+
objectUrlRef.current = url;
|
|
6546
|
+
setVideoBlobUrl(file.type.startsWith("video/") ? url : null);
|
|
6547
|
+
onChange(url);
|
|
6548
|
+
};
|
|
6549
|
+
const clearValue = () => {
|
|
6550
|
+
if (objectUrlRef.current) {
|
|
6551
|
+
URL.revokeObjectURL(objectUrlRef.current);
|
|
6552
|
+
objectUrlRef.current = null;
|
|
6553
|
+
}
|
|
6554
|
+
setVideoBlobUrl(null);
|
|
6555
|
+
onChange("");
|
|
6556
|
+
};
|
|
6557
|
+
const pick = (file) => {
|
|
6558
|
+
if (locked) return;
|
|
6559
|
+
if (onPick) {
|
|
6560
|
+
onPick(file ?? void 0);
|
|
6561
|
+
return;
|
|
6562
|
+
}
|
|
6563
|
+
if (file) {
|
|
6564
|
+
emitObjectUrl(file);
|
|
6565
|
+
return;
|
|
6566
|
+
}
|
|
6567
|
+
inputRef.current?.click();
|
|
6568
|
+
};
|
|
6569
|
+
const onNativeFile = (e) => {
|
|
6570
|
+
const file = e.target.files?.[0];
|
|
6571
|
+
if (file) emitObjectUrl(file);
|
|
6572
|
+
if (inputRef.current) inputRef.current.value = "";
|
|
6573
|
+
};
|
|
6574
|
+
const dropHandlers = locked ? {} : {
|
|
6575
|
+
onDragOver: (e) => {
|
|
6576
|
+
e.preventDefault();
|
|
6577
|
+
setDragOver(true);
|
|
6578
|
+
},
|
|
6579
|
+
onDragLeave: () => setDragOver(false),
|
|
6580
|
+
onDrop: (e) => {
|
|
6581
|
+
e.preventDefault();
|
|
6582
|
+
setDragOver(false);
|
|
6583
|
+
const file = e.dataTransfer.files?.[0];
|
|
6584
|
+
if (file) pick(file);
|
|
6585
|
+
}
|
|
6586
|
+
};
|
|
6587
|
+
const previewName = value ? mediaFileName(value) : "";
|
|
6588
|
+
const filled = /* @__PURE__ */ jsxs("div", { children: [
|
|
6589
|
+
/* @__PURE__ */ jsxs(
|
|
6590
|
+
"div",
|
|
6591
|
+
{
|
|
6592
|
+
...dropHandlers,
|
|
6593
|
+
className: [
|
|
6594
|
+
"relative overflow-hidden rounded-md border bg-gray-100 transition-colors",
|
|
6595
|
+
dragOver ? "border-blue-500" : "border-gray-200"
|
|
6596
|
+
].join(" "),
|
|
6597
|
+
style: { height },
|
|
6598
|
+
children: [
|
|
6599
|
+
isVideo ? /* @__PURE__ */ jsx(
|
|
6600
|
+
"video",
|
|
6601
|
+
{
|
|
6602
|
+
src: value ?? void 0,
|
|
6603
|
+
muted: true,
|
|
6604
|
+
playsInline: true,
|
|
6605
|
+
preload: "metadata",
|
|
6606
|
+
"aria-label": previewName || void 0,
|
|
6607
|
+
className: "h-full w-full",
|
|
6608
|
+
style: { objectFit: fit }
|
|
6609
|
+
}
|
|
6610
|
+
) : /* @__PURE__ */ jsx("img", { src: value ?? void 0, alt: previewName, className: "h-full w-full", style: { objectFit: fit } }),
|
|
6611
|
+
showFilename && value && /* @__PURE__ */ jsx(
|
|
6612
|
+
"span",
|
|
6613
|
+
{
|
|
6614
|
+
className: "absolute inset-x-1 bottom-1 truncate rounded px-1.5 py-0.5 text-xs text-white",
|
|
6615
|
+
style: { background: "rgba(0,0,0,0.6)" },
|
|
6616
|
+
children: previewName
|
|
6617
|
+
}
|
|
6618
|
+
),
|
|
6619
|
+
busy && /* @__PURE__ */ jsxs(
|
|
6620
|
+
"div",
|
|
6621
|
+
{
|
|
6622
|
+
role: "status",
|
|
6623
|
+
className: "absolute inset-0 flex items-center justify-center gap-2",
|
|
6624
|
+
style: { background: "rgba(255,255,255,0.6)" },
|
|
6625
|
+
children: [
|
|
6626
|
+
/* @__PURE__ */ jsx(Spinner2, {}),
|
|
6627
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-600", children: busyLabel })
|
|
6628
|
+
]
|
|
6629
|
+
}
|
|
6630
|
+
)
|
|
6631
|
+
]
|
|
6632
|
+
}
|
|
6633
|
+
),
|
|
6634
|
+
!disabled && (allowReplace || allowRemove) && /* @__PURE__ */ jsxs("div", { className: "mt-2 flex gap-2", children: [
|
|
6635
|
+
allowReplace && /* @__PURE__ */ jsx(Button_default, { id: fieldId, variant: "secondary", size: "sm", onClick: () => pick(), disabled: busy, children: replaceLabel }),
|
|
6636
|
+
allowRemove && /* @__PURE__ */ jsx(Button_default, { variant: "ghost", size: "sm", onClick: clearValue, disabled: busy, children: removeLabel })
|
|
6637
|
+
] })
|
|
6638
|
+
] });
|
|
6639
|
+
const empty = /* @__PURE__ */ jsx(
|
|
6640
|
+
"button",
|
|
6641
|
+
{
|
|
6642
|
+
type: "button",
|
|
6643
|
+
id: fieldId,
|
|
6644
|
+
onClick: () => pick(),
|
|
6645
|
+
disabled: locked,
|
|
6646
|
+
"aria-label": typeof dimLine === "string" ? dimLine : "Upload media",
|
|
6647
|
+
"aria-busy": busy || void 0,
|
|
6648
|
+
"aria-invalid": error ? true : void 0,
|
|
6649
|
+
"aria-required": required || void 0,
|
|
6650
|
+
"aria-describedby": error ? `${fieldId}-error` : hint ? `${fieldId}-hint` : void 0,
|
|
6651
|
+
onFocus: () => setFocused(true),
|
|
6652
|
+
onBlur: () => setFocused(false),
|
|
6653
|
+
...dropHandlers,
|
|
6654
|
+
className: [
|
|
6655
|
+
"flex w-full flex-col items-center justify-center gap-1.5 rounded-lg border-2 border-dashed text-center transition-colors",
|
|
6656
|
+
locked ? "cursor-not-allowed opacity-60" : "cursor-pointer",
|
|
6657
|
+
dragOver ? "border-blue-500 bg-blue-50" : "border-gray-300 bg-gray-50 hover:bg-gray-100"
|
|
6658
|
+
].join(" "),
|
|
6659
|
+
style: {
|
|
6660
|
+
minHeight: height,
|
|
6661
|
+
outline: "none",
|
|
6662
|
+
boxShadow: focused && !locked ? "0 0 0 2px rgba(59,130,246,0.45)" : void 0
|
|
6663
|
+
},
|
|
6664
|
+
children: busy ? /* @__PURE__ */ jsxs("span", { role: "status", className: "flex flex-col items-center gap-1.5", children: [
|
|
6665
|
+
/* @__PURE__ */ jsx(Spinner2, {}),
|
|
6666
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-500", children: busyLabel })
|
|
6667
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6668
|
+
/* @__PURE__ */ jsx("span", { className: "text-gray-400", children: /* @__PURE__ */ jsx(UploadGlyph, {}) }),
|
|
6669
|
+
/* @__PURE__ */ jsx("span", { className: "px-3 text-xs text-gray-500", children: dimLine }),
|
|
6670
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-blue-600", children: cta }),
|
|
6671
|
+
acceptHint && /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-400", children: acceptHint })
|
|
6672
|
+
] })
|
|
6673
|
+
}
|
|
6674
|
+
);
|
|
6675
|
+
return /* @__PURE__ */ jsxs(FormField, { label, htmlFor: fieldId, hint, error, required, className, children: [
|
|
6676
|
+
value ? filled : empty,
|
|
6677
|
+
!onPick && /* @__PURE__ */ jsx("input", { ref: inputRef, type: "file", accept, className: "hidden", onChange: onNativeFile })
|
|
6678
|
+
] });
|
|
6679
|
+
}
|
|
6680
|
+
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" }) });
|
|
6681
|
+
function MediaUploadGrid({
|
|
6682
|
+
items,
|
|
6683
|
+
onPick,
|
|
6684
|
+
onRemove,
|
|
6685
|
+
onReorder,
|
|
6686
|
+
label,
|
|
6687
|
+
hint,
|
|
6688
|
+
error,
|
|
6689
|
+
required,
|
|
6690
|
+
className,
|
|
6691
|
+
accept = "image/*",
|
|
6692
|
+
fit = "cover",
|
|
6693
|
+
thumbSize = 96,
|
|
6694
|
+
placeholder,
|
|
6695
|
+
cta = "Choose from library or upload",
|
|
6696
|
+
acceptHint,
|
|
6697
|
+
showCover = false,
|
|
6698
|
+
coverLabel = "Cover",
|
|
6699
|
+
busy = false,
|
|
6700
|
+
busyLabel = "Uploading\u2026",
|
|
6701
|
+
disabled = false,
|
|
6702
|
+
readOnly = false
|
|
6703
|
+
}) {
|
|
6704
|
+
const gridId = useId();
|
|
6705
|
+
const [zoneDragOver, setZoneDragOver] = useState(false);
|
|
6706
|
+
const [draggingIndex, setDraggingIndex] = useState(null);
|
|
6707
|
+
const [focusedKey, setFocusedKey] = useState(null);
|
|
6708
|
+
const ringStyle = (key) => ({
|
|
6709
|
+
outline: "none",
|
|
6710
|
+
...focusedKey === key && !locked ? { boxShadow: "0 0 0 2px rgba(59,130,246,0.45)" } : {}
|
|
6711
|
+
});
|
|
6712
|
+
const blurKey = (key) => setFocusedKey((k) => k === key ? null : k);
|
|
6713
|
+
const locked = disabled || busy;
|
|
6714
|
+
const canAdd = !!onPick && !locked && !readOnly;
|
|
6715
|
+
const canRemove = !!onRemove && !locked && !readOnly;
|
|
6716
|
+
const reorderEnabled = !!onReorder && !locked && !readOnly;
|
|
6717
|
+
const acceptsVideo = accept.includes("video");
|
|
6718
|
+
const acceptsImage = accept.includes("image") || accept === "*" || accept === "";
|
|
6719
|
+
const kindWord = acceptsVideo && !acceptsImage ? "video" : acceptsImage && !acceptsVideo ? "image" : "file";
|
|
6720
|
+
const dimLine = placeholder ?? `Upload ${kindWord === "image" ? "an image" : `a ${kindWord}`}`;
|
|
6721
|
+
const pick = (file) => {
|
|
6722
|
+
if (!canAdd) return;
|
|
6723
|
+
onPick(file ?? void 0);
|
|
6724
|
+
};
|
|
6725
|
+
const isFileDrag = (e) => Array.from(e.dataTransfer.types || []).includes("Files");
|
|
6726
|
+
const zoneHandlers = canAdd ? {
|
|
6727
|
+
onDragOver: (e) => {
|
|
6728
|
+
if (!isFileDrag(e)) return;
|
|
6729
|
+
e.preventDefault();
|
|
6730
|
+
setZoneDragOver(true);
|
|
6731
|
+
},
|
|
6732
|
+
onDragLeave: () => setZoneDragOver(false),
|
|
6733
|
+
onDrop: (e) => {
|
|
6734
|
+
const file = e.dataTransfer.files?.[0];
|
|
6735
|
+
if (!file) return;
|
|
6736
|
+
e.preventDefault();
|
|
6737
|
+
setZoneDragOver(false);
|
|
6738
|
+
pick(file);
|
|
6739
|
+
}
|
|
6740
|
+
} : {};
|
|
6741
|
+
const square = { width: thumbSize, height: thumbSize };
|
|
6742
|
+
const thumb = (item, index) => {
|
|
6743
|
+
const video = item.kind ? item.kind === "video" : isVideoUrl(item.url, accept);
|
|
6744
|
+
const name = mediaFileName(item.url);
|
|
6745
|
+
const isCover = showCover && (item.cover ?? index === 0);
|
|
6746
|
+
return /* @__PURE__ */ jsxs(
|
|
6747
|
+
"div",
|
|
6748
|
+
{
|
|
6749
|
+
draggable: reorderEnabled || void 0,
|
|
6750
|
+
onDragStart: reorderEnabled ? (e) => {
|
|
6751
|
+
e.dataTransfer.effectAllowed = "move";
|
|
6752
|
+
e.dataTransfer.setData("text/plain", String(index));
|
|
6753
|
+
setDraggingIndex(index);
|
|
6754
|
+
} : void 0,
|
|
6755
|
+
onDragEnd: reorderEnabled ? () => setDraggingIndex(null) : void 0,
|
|
6756
|
+
onDragOver: reorderEnabled ? (e) => {
|
|
6757
|
+
if (draggingIndex == null) return;
|
|
6758
|
+
e.preventDefault();
|
|
6759
|
+
e.stopPropagation();
|
|
6760
|
+
} : void 0,
|
|
6761
|
+
onDrop: reorderEnabled ? (e) => {
|
|
6762
|
+
if (draggingIndex == null) return;
|
|
6763
|
+
e.preventDefault();
|
|
6764
|
+
e.stopPropagation();
|
|
6765
|
+
if (draggingIndex !== index) onReorder(draggingIndex, index);
|
|
6766
|
+
setDraggingIndex(null);
|
|
6767
|
+
} : void 0,
|
|
6768
|
+
tabIndex: reorderEnabled ? 0 : void 0,
|
|
6769
|
+
"aria-label": reorderEnabled ? `${name}, item ${index + 1} of ${items.length}. Use arrow keys to reorder.` : void 0,
|
|
6770
|
+
onKeyDown: reorderEnabled ? (e) => {
|
|
6771
|
+
if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
|
|
6772
|
+
if (index > 0) {
|
|
6773
|
+
e.preventDefault();
|
|
6774
|
+
onReorder(index, index - 1);
|
|
6775
|
+
}
|
|
6776
|
+
} else if (e.key === "ArrowRight" || e.key === "ArrowDown") {
|
|
6777
|
+
if (index < items.length - 1) {
|
|
6778
|
+
e.preventDefault();
|
|
6779
|
+
onReorder(index, index + 1);
|
|
6780
|
+
}
|
|
6781
|
+
}
|
|
6782
|
+
} : void 0,
|
|
6783
|
+
onFocus: reorderEnabled ? (e) => {
|
|
6784
|
+
if (e.target === e.currentTarget) setFocusedKey(`thumb:${item.id}`);
|
|
6785
|
+
} : void 0,
|
|
6786
|
+
onBlur: reorderEnabled ? (e) => {
|
|
6787
|
+
if (e.target === e.currentTarget) blurKey(`thumb:${item.id}`);
|
|
6788
|
+
} : void 0,
|
|
6789
|
+
className: [
|
|
6790
|
+
"relative shrink-0 overflow-hidden rounded-md border border-gray-200 bg-gray-100",
|
|
6791
|
+
draggingIndex === index ? "opacity-50" : ""
|
|
6792
|
+
].join(" "),
|
|
6793
|
+
style: { ...square, cursor: reorderEnabled ? "move" : void 0, ...ringStyle(`thumb:${item.id}`) },
|
|
6794
|
+
children: [
|
|
6795
|
+
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 } }),
|
|
6796
|
+
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 }),
|
|
6797
|
+
item.caption != null && /* @__PURE__ */ jsx(
|
|
6798
|
+
"span",
|
|
6799
|
+
{
|
|
6800
|
+
className: "absolute inset-x-1 bottom-1 truncate rounded px-1.5 py-0.5 text-xs text-white",
|
|
6801
|
+
style: { background: "rgba(0,0,0,0.6)" },
|
|
6802
|
+
children: item.caption
|
|
6803
|
+
}
|
|
6804
|
+
),
|
|
6805
|
+
canRemove && /* @__PURE__ */ jsx(
|
|
6806
|
+
"button",
|
|
6807
|
+
{
|
|
6808
|
+
type: "button",
|
|
6809
|
+
onClick: () => onRemove(item.id),
|
|
6810
|
+
"aria-label": `Remove ${name}`,
|
|
6811
|
+
onFocus: () => setFocusedKey(`rm:${item.id}`),
|
|
6812
|
+
onBlur: () => blurKey(`rm:${item.id}`),
|
|
6813
|
+
className: "absolute right-1 top-1 flex h-5 w-5 items-center justify-center rounded-full text-white",
|
|
6814
|
+
style: { background: "rgba(0,0,0,0.55)", ...ringStyle(`rm:${item.id}`) },
|
|
6815
|
+
children: REMOVE_ICON
|
|
6816
|
+
}
|
|
6817
|
+
)
|
|
6818
|
+
]
|
|
6819
|
+
},
|
|
6820
|
+
item.id
|
|
6821
|
+
);
|
|
6822
|
+
};
|
|
6823
|
+
const addTile = canAdd && /* @__PURE__ */ jsxs(
|
|
6824
|
+
"button",
|
|
6825
|
+
{
|
|
6826
|
+
type: "button",
|
|
6827
|
+
onClick: () => pick(),
|
|
6828
|
+
"aria-label": "Add media",
|
|
6829
|
+
onFocus: () => setFocusedKey("add"),
|
|
6830
|
+
onBlur: () => blurKey("add"),
|
|
6831
|
+
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",
|
|
6832
|
+
style: { ...square, ...ringStyle("add") },
|
|
6833
|
+
children: [
|
|
6834
|
+
/* @__PURE__ */ jsx(UploadGlyph, { className: "h-5 w-5" }),
|
|
6835
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-500", children: "Add" })
|
|
6836
|
+
]
|
|
6837
|
+
}
|
|
6838
|
+
);
|
|
6839
|
+
const emptyDropzone = canAdd ? /* @__PURE__ */ jsxs(
|
|
6840
|
+
"button",
|
|
6841
|
+
{
|
|
6842
|
+
type: "button",
|
|
6843
|
+
onClick: () => pick(),
|
|
6844
|
+
"aria-label": typeof dimLine === "string" ? dimLine : "Upload media",
|
|
6845
|
+
onFocus: () => setFocusedKey("zone"),
|
|
6846
|
+
onBlur: () => blurKey("zone"),
|
|
6847
|
+
className: [
|
|
6848
|
+
"flex w-full flex-col items-center justify-center gap-1.5 rounded-lg border-2 border-dashed text-center transition-colors cursor-pointer",
|
|
6849
|
+
zoneDragOver ? "border-blue-500 bg-blue-50" : "border-gray-300 bg-gray-50 hover:bg-gray-100"
|
|
6850
|
+
].join(" "),
|
|
6851
|
+
style: { minHeight: thumbSize + 32, ...ringStyle("zone") },
|
|
6852
|
+
children: [
|
|
6853
|
+
/* @__PURE__ */ jsx("span", { className: "text-gray-400", children: /* @__PURE__ */ jsx(UploadGlyph, {}) }),
|
|
6854
|
+
/* @__PURE__ */ jsx("span", { className: "px-3 text-xs text-gray-500", children: dimLine }),
|
|
6855
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-blue-600", children: cta }),
|
|
6856
|
+
acceptHint && /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-400", children: acceptHint })
|
|
6857
|
+
]
|
|
6858
|
+
}
|
|
6859
|
+
) : /* @__PURE__ */ jsx(
|
|
6860
|
+
"div",
|
|
6861
|
+
{
|
|
6862
|
+
className: "flex w-full items-center justify-center rounded-lg border border-gray-200 bg-gray-50 px-3 text-xs text-gray-400",
|
|
6863
|
+
style: { minHeight: thumbSize + 32 },
|
|
6864
|
+
children: "No media."
|
|
6865
|
+
}
|
|
6866
|
+
);
|
|
6867
|
+
return /* @__PURE__ */ jsx(FormField, { label, labelId: label ? `${gridId}-label` : void 0, htmlFor: gridId, hint, error, required, className, children: /* @__PURE__ */ jsxs(
|
|
6868
|
+
"div",
|
|
6869
|
+
{
|
|
6870
|
+
id: gridId,
|
|
6871
|
+
role: "group",
|
|
6872
|
+
"aria-labelledby": label ? `${gridId}-label` : void 0,
|
|
6873
|
+
"aria-describedby": error ? `${gridId}-error` : hint ? `${gridId}-hint` : void 0,
|
|
6874
|
+
"aria-busy": busy || void 0,
|
|
6875
|
+
...zoneHandlers,
|
|
6876
|
+
className: "relative rounded-lg transition-colors",
|
|
6877
|
+
style: {
|
|
6878
|
+
...locked ? { opacity: 0.6 } : {},
|
|
6879
|
+
// Inline box-shadow, not `ring-*` — the kit's shipped stylesheet has no
|
|
6880
|
+
// Tailwind ring machinery (see MediaUploadField's focus ring).
|
|
6881
|
+
...zoneDragOver ? { boxShadow: "0 0 0 2px rgba(59,130,246,0.5)" } : {}
|
|
6882
|
+
},
|
|
6883
|
+
children: [
|
|
6884
|
+
items.length === 0 ? emptyDropzone : /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
6885
|
+
items.map(thumb),
|
|
6886
|
+
addTile
|
|
6887
|
+
] }),
|
|
6888
|
+
busy && /* @__PURE__ */ jsxs(
|
|
6889
|
+
"div",
|
|
6890
|
+
{
|
|
6891
|
+
role: "status",
|
|
6892
|
+
className: "absolute inset-0 flex items-center justify-center gap-2 rounded-lg",
|
|
6893
|
+
style: { background: "rgba(255,255,255,0.6)" },
|
|
6894
|
+
children: [
|
|
6895
|
+
/* @__PURE__ */ jsx(Spinner2, {}),
|
|
6896
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-600", children: busyLabel })
|
|
6897
|
+
]
|
|
6898
|
+
}
|
|
6899
|
+
)
|
|
6900
|
+
]
|
|
6901
|
+
}
|
|
6902
|
+
) });
|
|
6903
|
+
}
|
|
6460
6904
|
function Card({ children, header, footer, padded = true, className = "" }) {
|
|
6461
6905
|
return /* @__PURE__ */ jsxs("div", { className: `rounded-lg border border-gray-200 bg-white shadow-sm ${className}`.trim(), children: [
|
|
6462
6906
|
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 +9412,6 @@ function useEditHotkey(callback) {
|
|
|
8968
9412
|
}, [callback, isActive]);
|
|
8969
9413
|
}
|
|
8970
9414
|
|
|
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 };
|
|
9415
|
+
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
9416
|
//# sourceMappingURL=index.js.map
|
|
8973
9417
|
//# sourceMappingURL=index.js.map
|