@particle-academy/react-fancy 4.8.1 → 4.10.0
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/README.md +13 -0
- package/dist/index.cjs +554 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +235 -2
- package/dist/index.d.ts +235 -2
- package/dist/index.js +549 -7
- package/dist/index.js.map +1 -1
- package/dist/styles.css +46 -0
- package/dist/styles.css.map +1 -1
- package/docs/AudioViewer.md +29 -0
- package/docs/ImageViewer.md +60 -0
- package/docs/MediaViewer.md +75 -0
- package/docs/PdfViewer.md +29 -0
- package/docs/VideoViewer.md +31 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11654,11 +11654,10 @@ function ContentRenderer({
|
|
|
11654
11654
|
);
|
|
11655
11655
|
}
|
|
11656
11656
|
ContentRenderer.displayName = "ContentRenderer";
|
|
11657
|
-
function toHtml(value, outputFormat, unsafe) {
|
|
11657
|
+
function toHtml(value, outputFormat, unsafe, valueFormat = "auto") {
|
|
11658
11658
|
if (!value) return "";
|
|
11659
11659
|
const raw = (() => {
|
|
11660
|
-
|
|
11661
|
-
const format = detectFormat(value);
|
|
11660
|
+
const format = valueFormat !== "auto" ? valueFormat : outputFormat === "html" ? "html" : detectFormat(value);
|
|
11662
11661
|
if (format === "html") return value;
|
|
11663
11662
|
return marked.parse(value, { async: false }).trim();
|
|
11664
11663
|
})();
|
|
@@ -11671,6 +11670,7 @@ function EditorRoot({
|
|
|
11671
11670
|
defaultValue = "",
|
|
11672
11671
|
onChange,
|
|
11673
11672
|
outputFormat = "html",
|
|
11673
|
+
valueFormat = "auto",
|
|
11674
11674
|
lineSpacing = 1.6,
|
|
11675
11675
|
placeholder,
|
|
11676
11676
|
mode: modeProp,
|
|
@@ -11682,13 +11682,13 @@ function EditorRoot({
|
|
|
11682
11682
|
const mode = useFieldMode(modeProp);
|
|
11683
11683
|
const isView = mode === "view";
|
|
11684
11684
|
const initialHtml = useMemo(
|
|
11685
|
-
() => toHtml(value, outputFormat, unsafe),
|
|
11685
|
+
() => toHtml(value, outputFormat, unsafe, valueFormat),
|
|
11686
11686
|
// Seed the contentEditable from the LIVE value when (re)entering edit mode.
|
|
11687
11687
|
// EditorContent reads this once on mount, and it only mounts in edit mode —
|
|
11688
11688
|
// so this captures the current value on view→edit, not a stale mount snapshot,
|
|
11689
11689
|
// and does NOT re-run on every keystroke.
|
|
11690
11690
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
11691
|
-
[isView, outputFormat, unsafe]
|
|
11691
|
+
[isView, outputFormat, unsafe, valueFormat]
|
|
11692
11692
|
);
|
|
11693
11693
|
const extensions = useMemo(
|
|
11694
11694
|
() => mergeExtensions(instanceExtensions),
|
|
@@ -11765,7 +11765,7 @@ function EditorRoot({
|
|
|
11765
11765
|
ContentRenderer,
|
|
11766
11766
|
{
|
|
11767
11767
|
value,
|
|
11768
|
-
format: outputFormat,
|
|
11768
|
+
format: valueFormat !== "auto" ? valueFormat : outputFormat,
|
|
11769
11769
|
lineSpacing,
|
|
11770
11770
|
extensions: instanceExtensions,
|
|
11771
11771
|
unsafe,
|
|
@@ -13024,6 +13024,108 @@ TreeNavRoot.displayName = "TreeNav";
|
|
|
13024
13024
|
var TreeNav = Object.assign(TreeNavRoot, {
|
|
13025
13025
|
Node: TreeNode
|
|
13026
13026
|
});
|
|
13027
|
+
|
|
13028
|
+
// src/utils/media-type.ts
|
|
13029
|
+
var IMAGE_EXTS = /* @__PURE__ */ new Set([
|
|
13030
|
+
"png",
|
|
13031
|
+
"jpg",
|
|
13032
|
+
"jpeg",
|
|
13033
|
+
"jfif",
|
|
13034
|
+
"pjpeg",
|
|
13035
|
+
"gif",
|
|
13036
|
+
"webp",
|
|
13037
|
+
"avif",
|
|
13038
|
+
"bmp",
|
|
13039
|
+
"ico",
|
|
13040
|
+
"cur",
|
|
13041
|
+
"svg",
|
|
13042
|
+
"svgz",
|
|
13043
|
+
"apng",
|
|
13044
|
+
"tif",
|
|
13045
|
+
"tiff",
|
|
13046
|
+
"heic",
|
|
13047
|
+
"heif"
|
|
13048
|
+
]);
|
|
13049
|
+
var VIDEO_EXTS = /* @__PURE__ */ new Set([
|
|
13050
|
+
"mp4",
|
|
13051
|
+
"m4v",
|
|
13052
|
+
"webm",
|
|
13053
|
+
"ogv",
|
|
13054
|
+
"ogm",
|
|
13055
|
+
"mov",
|
|
13056
|
+
"mkv",
|
|
13057
|
+
"avi",
|
|
13058
|
+
"wmv",
|
|
13059
|
+
"flv",
|
|
13060
|
+
"3gp",
|
|
13061
|
+
"3g2",
|
|
13062
|
+
"mpg",
|
|
13063
|
+
"mpeg"
|
|
13064
|
+
]);
|
|
13065
|
+
var AUDIO_EXTS = /* @__PURE__ */ new Set([
|
|
13066
|
+
"mp3",
|
|
13067
|
+
"wav",
|
|
13068
|
+
"wave",
|
|
13069
|
+
"ogg",
|
|
13070
|
+
"oga",
|
|
13071
|
+
"m4a",
|
|
13072
|
+
"m4b",
|
|
13073
|
+
"aac",
|
|
13074
|
+
"flac",
|
|
13075
|
+
"opus",
|
|
13076
|
+
"weba",
|
|
13077
|
+
"mid",
|
|
13078
|
+
"midi",
|
|
13079
|
+
"aiff",
|
|
13080
|
+
"aif"
|
|
13081
|
+
]);
|
|
13082
|
+
function mimeToKind(mime) {
|
|
13083
|
+
const m = mime.toLowerCase().split(";")[0].trim();
|
|
13084
|
+
if (!m) return "unknown";
|
|
13085
|
+
if (m === "application/pdf" || m === "application/x-pdf") return "pdf";
|
|
13086
|
+
if (m.startsWith("image/")) return "image";
|
|
13087
|
+
if (m.startsWith("video/")) return "video";
|
|
13088
|
+
if (m.startsWith("audio/")) return "audio";
|
|
13089
|
+
if (m === "application/ogg") return "audio";
|
|
13090
|
+
return "unknown";
|
|
13091
|
+
}
|
|
13092
|
+
function extToKind(ext) {
|
|
13093
|
+
const e = ext.toLowerCase();
|
|
13094
|
+
if (e === "pdf") return "pdf";
|
|
13095
|
+
if (IMAGE_EXTS.has(e)) return "image";
|
|
13096
|
+
if (VIDEO_EXTS.has(e)) return "video";
|
|
13097
|
+
if (AUDIO_EXTS.has(e)) return "audio";
|
|
13098
|
+
return "unknown";
|
|
13099
|
+
}
|
|
13100
|
+
function extFromSrc(src) {
|
|
13101
|
+
const clean = src.split(/[?#]/, 1)[0];
|
|
13102
|
+
const lastSeg = clean.split("/").pop() ?? "";
|
|
13103
|
+
const dot = lastSeg.lastIndexOf(".");
|
|
13104
|
+
if (dot <= 0 || dot === lastSeg.length - 1) return null;
|
|
13105
|
+
return lastSeg.slice(dot + 1);
|
|
13106
|
+
}
|
|
13107
|
+
function mimeFromDataUri(src) {
|
|
13108
|
+
if (!/^data:/i.test(src)) return null;
|
|
13109
|
+
const header = src.slice(5).split(",", 1)[0];
|
|
13110
|
+
const mt = header.split(";")[0].trim();
|
|
13111
|
+
return mt || null;
|
|
13112
|
+
}
|
|
13113
|
+
function resolveMediaType({ mime, src }) {
|
|
13114
|
+
if (mime) {
|
|
13115
|
+
const k = mimeToKind(mime);
|
|
13116
|
+
if (k !== "unknown") return k;
|
|
13117
|
+
}
|
|
13118
|
+
if (src) {
|
|
13119
|
+
const dataMime = mimeFromDataUri(src);
|
|
13120
|
+
if (dataMime) {
|
|
13121
|
+
const k = mimeToKind(dataMime);
|
|
13122
|
+
if (k !== "unknown") return k;
|
|
13123
|
+
}
|
|
13124
|
+
const ext = extFromSrc(src);
|
|
13125
|
+
if (ext) return extToKind(ext);
|
|
13126
|
+
}
|
|
13127
|
+
return "unknown";
|
|
13128
|
+
}
|
|
13027
13129
|
var CONFIDENCE_TIERS = [
|
|
13028
13130
|
{ min: 0.85, color: "#10b981", label: "high" },
|
|
13029
13131
|
{ min: 0.6, color: "#f59e0b", label: "medium" },
|
|
@@ -14296,7 +14398,447 @@ function caretRect(ta, start, end) {
|
|
|
14296
14398
|
const y = taRect.top - parentRect.top + offsetY - ta.scrollTop;
|
|
14297
14399
|
return { x, y };
|
|
14298
14400
|
}
|
|
14401
|
+
var DEFAULT_VIEWPORT = { panX: 0, panY: 0, zoom: 1 };
|
|
14402
|
+
var fitClasses = {
|
|
14403
|
+
contain: "h-full w-full object-contain",
|
|
14404
|
+
cover: "h-full w-full object-cover",
|
|
14405
|
+
none: "max-w-none object-none"
|
|
14406
|
+
};
|
|
14407
|
+
function clamp2(n, min, max) {
|
|
14408
|
+
return Math.min(max, Math.max(min, n));
|
|
14409
|
+
}
|
|
14410
|
+
var ImageViewer = forwardRef(
|
|
14411
|
+
({
|
|
14412
|
+
src,
|
|
14413
|
+
alt = "",
|
|
14414
|
+
fit = "contain",
|
|
14415
|
+
zoomable = true,
|
|
14416
|
+
pannable = true,
|
|
14417
|
+
controls,
|
|
14418
|
+
minZoom = 0.25,
|
|
14419
|
+
maxZoom = 8,
|
|
14420
|
+
checkerboard = true,
|
|
14421
|
+
viewport,
|
|
14422
|
+
defaultViewport,
|
|
14423
|
+
onViewportChange,
|
|
14424
|
+
onLoad,
|
|
14425
|
+
onError,
|
|
14426
|
+
className,
|
|
14427
|
+
style
|
|
14428
|
+
}, ref) => {
|
|
14429
|
+
const containerRef = useRef(null);
|
|
14430
|
+
const [status, setStatus] = useState("loading");
|
|
14431
|
+
const isControlled = viewport !== void 0;
|
|
14432
|
+
const [internal, setInternal] = useState(
|
|
14433
|
+
defaultViewport ?? DEFAULT_VIEWPORT
|
|
14434
|
+
);
|
|
14435
|
+
const current = isControlled ? viewport : internal;
|
|
14436
|
+
const currentRef = useRef(current);
|
|
14437
|
+
currentRef.current = current;
|
|
14438
|
+
const setViewport = useCallback(
|
|
14439
|
+
(next) => {
|
|
14440
|
+
const resolved = typeof next === "function" ? next(currentRef.current) : next;
|
|
14441
|
+
if (!isControlled) setInternal(resolved);
|
|
14442
|
+
onViewportChange?.(resolved);
|
|
14443
|
+
},
|
|
14444
|
+
[isControlled, onViewportChange]
|
|
14445
|
+
);
|
|
14446
|
+
const interactive = status === "loaded";
|
|
14447
|
+
const { containerProps, isPanning } = usePanZoom({
|
|
14448
|
+
viewport: current,
|
|
14449
|
+
setViewport,
|
|
14450
|
+
minZoom,
|
|
14451
|
+
maxZoom,
|
|
14452
|
+
pannable: pannable && interactive,
|
|
14453
|
+
zoomable: zoomable && interactive,
|
|
14454
|
+
containerRef
|
|
14455
|
+
});
|
|
14456
|
+
const zoomBy = useCallback(
|
|
14457
|
+
(factor) => {
|
|
14458
|
+
const el = containerRef.current;
|
|
14459
|
+
if (!el) return;
|
|
14460
|
+
const rect = el.getBoundingClientRect();
|
|
14461
|
+
const cx = rect.width / 2;
|
|
14462
|
+
const cy = rect.height / 2;
|
|
14463
|
+
setViewport((prev) => {
|
|
14464
|
+
const newZoom = clamp2(prev.zoom * factor, minZoom, maxZoom);
|
|
14465
|
+
const ratio = newZoom / prev.zoom;
|
|
14466
|
+
return {
|
|
14467
|
+
zoom: newZoom,
|
|
14468
|
+
panX: cx - (cx - prev.panX) * ratio,
|
|
14469
|
+
panY: cy - (cy - prev.panY) * ratio
|
|
14470
|
+
};
|
|
14471
|
+
});
|
|
14472
|
+
},
|
|
14473
|
+
[setViewport, minZoom, maxZoom]
|
|
14474
|
+
);
|
|
14475
|
+
const reset = useCallback(() => setViewport(DEFAULT_VIEWPORT), [setViewport]);
|
|
14476
|
+
const showControls = (controls ?? zoomable) && interactive;
|
|
14477
|
+
const transform = `translate(${current.panX}px, ${current.panY}px) scale(${current.zoom})`;
|
|
14478
|
+
return /* @__PURE__ */ jsxs(
|
|
14479
|
+
"div",
|
|
14480
|
+
{
|
|
14481
|
+
ref,
|
|
14482
|
+
"data-react-fancy-image-viewer": "",
|
|
14483
|
+
className: cn(
|
|
14484
|
+
"relative isolate overflow-hidden rounded-md select-none",
|
|
14485
|
+
checkerboard ? "fancy-checkerboard" : "bg-zinc-100 dark:bg-zinc-900",
|
|
14486
|
+
className
|
|
14487
|
+
),
|
|
14488
|
+
style,
|
|
14489
|
+
children: [
|
|
14490
|
+
/* @__PURE__ */ jsx(
|
|
14491
|
+
"div",
|
|
14492
|
+
{
|
|
14493
|
+
ref: containerRef,
|
|
14494
|
+
"data-canvas-bg": "",
|
|
14495
|
+
className: cn(
|
|
14496
|
+
"absolute inset-0 flex items-center justify-center",
|
|
14497
|
+
isPanning ? "cursor-grabbing" : pannable && interactive ? "cursor-grab" : ""
|
|
14498
|
+
),
|
|
14499
|
+
style: {
|
|
14500
|
+
transform,
|
|
14501
|
+
transformOrigin: "0 0",
|
|
14502
|
+
willChange: "transform",
|
|
14503
|
+
touchAction: zoomable || pannable ? "none" : void 0
|
|
14504
|
+
},
|
|
14505
|
+
onDoubleClick: zoomable ? reset : void 0,
|
|
14506
|
+
...containerProps,
|
|
14507
|
+
children: /* @__PURE__ */ jsx(
|
|
14508
|
+
"img",
|
|
14509
|
+
{
|
|
14510
|
+
src,
|
|
14511
|
+
alt,
|
|
14512
|
+
draggable: false,
|
|
14513
|
+
onLoad: () => {
|
|
14514
|
+
setStatus("loaded");
|
|
14515
|
+
onLoad?.();
|
|
14516
|
+
},
|
|
14517
|
+
onError: () => {
|
|
14518
|
+
setStatus("error");
|
|
14519
|
+
onError?.();
|
|
14520
|
+
},
|
|
14521
|
+
className: cn(
|
|
14522
|
+
"pointer-events-none block",
|
|
14523
|
+
status === "error" && "hidden",
|
|
14524
|
+
fitClasses[fit]
|
|
14525
|
+
)
|
|
14526
|
+
}
|
|
14527
|
+
)
|
|
14528
|
+
}
|
|
14529
|
+
),
|
|
14530
|
+
status === "error" && /* @__PURE__ */ jsxs(
|
|
14531
|
+
"div",
|
|
14532
|
+
{
|
|
14533
|
+
"data-react-fancy-image-viewer-error": "",
|
|
14534
|
+
className: "absolute inset-0 flex flex-col items-center justify-center gap-1 p-4 text-center text-sm text-zinc-500 dark:text-zinc-400",
|
|
14535
|
+
children: [
|
|
14536
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Couldn't load image" }),
|
|
14537
|
+
/* @__PURE__ */ jsx("span", { className: "max-w-full truncate text-xs opacity-70", children: alt || src })
|
|
14538
|
+
]
|
|
14539
|
+
}
|
|
14540
|
+
),
|
|
14541
|
+
showControls && /* @__PURE__ */ jsxs(
|
|
14542
|
+
"div",
|
|
14543
|
+
{
|
|
14544
|
+
"data-react-fancy-image-viewer-controls": "",
|
|
14545
|
+
className: "absolute bottom-2 right-2 flex items-center gap-0.5 rounded-md border border-zinc-200 bg-white/90 p-0.5 text-zinc-700 shadow-sm backdrop-blur dark:border-zinc-700 dark:bg-zinc-900/90 dark:text-zinc-200",
|
|
14546
|
+
children: [
|
|
14547
|
+
/* @__PURE__ */ jsx(
|
|
14548
|
+
"button",
|
|
14549
|
+
{
|
|
14550
|
+
type: "button",
|
|
14551
|
+
"aria-label": "Zoom out",
|
|
14552
|
+
onClick: () => zoomBy(1 / 1.25),
|
|
14553
|
+
className: "flex h-6 w-6 items-center justify-center rounded text-base leading-none hover:bg-zinc-100 dark:hover:bg-zinc-800",
|
|
14554
|
+
children: "\u2212"
|
|
14555
|
+
}
|
|
14556
|
+
),
|
|
14557
|
+
/* @__PURE__ */ jsxs(
|
|
14558
|
+
"button",
|
|
14559
|
+
{
|
|
14560
|
+
type: "button",
|
|
14561
|
+
"aria-label": "Reset zoom",
|
|
14562
|
+
onClick: reset,
|
|
14563
|
+
className: "min-w-[3rem] rounded px-1 text-center text-xs tabular-nums hover:bg-zinc-100 dark:hover:bg-zinc-800",
|
|
14564
|
+
children: [
|
|
14565
|
+
Math.round(current.zoom * 100),
|
|
14566
|
+
"%"
|
|
14567
|
+
]
|
|
14568
|
+
}
|
|
14569
|
+
),
|
|
14570
|
+
/* @__PURE__ */ jsx(
|
|
14571
|
+
"button",
|
|
14572
|
+
{
|
|
14573
|
+
type: "button",
|
|
14574
|
+
"aria-label": "Zoom in",
|
|
14575
|
+
onClick: () => zoomBy(1.25),
|
|
14576
|
+
className: "flex h-6 w-6 items-center justify-center rounded text-base leading-none hover:bg-zinc-100 dark:hover:bg-zinc-800",
|
|
14577
|
+
children: "+"
|
|
14578
|
+
}
|
|
14579
|
+
)
|
|
14580
|
+
]
|
|
14581
|
+
}
|
|
14582
|
+
)
|
|
14583
|
+
]
|
|
14584
|
+
}
|
|
14585
|
+
);
|
|
14586
|
+
}
|
|
14587
|
+
);
|
|
14588
|
+
ImageViewer.displayName = "ImageViewer";
|
|
14589
|
+
var VideoViewer = forwardRef(
|
|
14590
|
+
({
|
|
14591
|
+
src,
|
|
14592
|
+
poster,
|
|
14593
|
+
controls = true,
|
|
14594
|
+
autoPlay = false,
|
|
14595
|
+
loop = false,
|
|
14596
|
+
muted = false,
|
|
14597
|
+
fit = "contain",
|
|
14598
|
+
onError,
|
|
14599
|
+
className,
|
|
14600
|
+
style
|
|
14601
|
+
}, ref) => {
|
|
14602
|
+
const [errored, setErrored] = useState(false);
|
|
14603
|
+
return /* @__PURE__ */ jsx(
|
|
14604
|
+
"div",
|
|
14605
|
+
{
|
|
14606
|
+
ref,
|
|
14607
|
+
"data-react-fancy-video-viewer": "",
|
|
14608
|
+
className: cn(
|
|
14609
|
+
"relative flex items-center justify-center overflow-hidden rounded-md bg-black",
|
|
14610
|
+
className
|
|
14611
|
+
),
|
|
14612
|
+
style,
|
|
14613
|
+
children: errored ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center gap-1 p-4 text-center text-sm text-zinc-400", children: [
|
|
14614
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Couldn't load video" }),
|
|
14615
|
+
/* @__PURE__ */ jsx("span", { className: "max-w-full truncate text-xs opacity-70", children: src })
|
|
14616
|
+
] }) : /* @__PURE__ */ jsx(
|
|
14617
|
+
"video",
|
|
14618
|
+
{
|
|
14619
|
+
src,
|
|
14620
|
+
poster,
|
|
14621
|
+
controls,
|
|
14622
|
+
autoPlay,
|
|
14623
|
+
loop,
|
|
14624
|
+
muted,
|
|
14625
|
+
playsInline: true,
|
|
14626
|
+
onError: () => {
|
|
14627
|
+
setErrored(true);
|
|
14628
|
+
onError?.();
|
|
14629
|
+
},
|
|
14630
|
+
className: cn(
|
|
14631
|
+
"max-h-full max-w-full",
|
|
14632
|
+
fit === "cover" ? "h-full w-full object-cover" : "object-contain"
|
|
14633
|
+
)
|
|
14634
|
+
}
|
|
14635
|
+
)
|
|
14636
|
+
}
|
|
14637
|
+
);
|
|
14638
|
+
}
|
|
14639
|
+
);
|
|
14640
|
+
VideoViewer.displayName = "VideoViewer";
|
|
14641
|
+
var AudioViewer = forwardRef(
|
|
14642
|
+
({
|
|
14643
|
+
src,
|
|
14644
|
+
title,
|
|
14645
|
+
controls = true,
|
|
14646
|
+
autoPlay = false,
|
|
14647
|
+
loop = false,
|
|
14648
|
+
onError,
|
|
14649
|
+
className,
|
|
14650
|
+
style
|
|
14651
|
+
}, ref) => {
|
|
14652
|
+
const [errored, setErrored] = useState(false);
|
|
14653
|
+
return /* @__PURE__ */ jsxs(
|
|
14654
|
+
"div",
|
|
14655
|
+
{
|
|
14656
|
+
ref,
|
|
14657
|
+
"data-react-fancy-audio-viewer": "",
|
|
14658
|
+
className: cn(
|
|
14659
|
+
"flex flex-col gap-2 rounded-lg border border-zinc-200 bg-white p-4 dark:border-zinc-700 dark:bg-zinc-900",
|
|
14660
|
+
className
|
|
14661
|
+
),
|
|
14662
|
+
style,
|
|
14663
|
+
children: [
|
|
14664
|
+
title && /* @__PURE__ */ jsx("div", { className: "truncate text-sm font-medium text-zinc-700 dark:text-zinc-200", children: title }),
|
|
14665
|
+
errored ? /* @__PURE__ */ jsx("div", { className: "text-sm text-zinc-500 dark:text-zinc-400", children: "Couldn't load audio." }) : /* @__PURE__ */ jsx(
|
|
14666
|
+
"audio",
|
|
14667
|
+
{
|
|
14668
|
+
src,
|
|
14669
|
+
controls,
|
|
14670
|
+
autoPlay,
|
|
14671
|
+
loop,
|
|
14672
|
+
onError: () => {
|
|
14673
|
+
setErrored(true);
|
|
14674
|
+
onError?.();
|
|
14675
|
+
},
|
|
14676
|
+
className: "w-full"
|
|
14677
|
+
}
|
|
14678
|
+
)
|
|
14679
|
+
]
|
|
14680
|
+
}
|
|
14681
|
+
);
|
|
14682
|
+
}
|
|
14683
|
+
);
|
|
14684
|
+
AudioViewer.displayName = "AudioViewer";
|
|
14685
|
+
var PdfViewer = forwardRef(
|
|
14686
|
+
({ src, title = "PDF document", className, style }, ref) => {
|
|
14687
|
+
return /* @__PURE__ */ jsx(
|
|
14688
|
+
"div",
|
|
14689
|
+
{
|
|
14690
|
+
ref,
|
|
14691
|
+
"data-react-fancy-pdf-viewer": "",
|
|
14692
|
+
className: cn(
|
|
14693
|
+
"relative h-full min-h-[20rem] w-full overflow-hidden rounded-md bg-zinc-100 dark:bg-zinc-900",
|
|
14694
|
+
className
|
|
14695
|
+
),
|
|
14696
|
+
style,
|
|
14697
|
+
children: /* @__PURE__ */ jsxs("object", { data: src, type: "application/pdf", className: "h-full w-full", children: [
|
|
14698
|
+
/* @__PURE__ */ jsx(
|
|
14699
|
+
"iframe",
|
|
14700
|
+
{
|
|
14701
|
+
src,
|
|
14702
|
+
title,
|
|
14703
|
+
className: "h-full w-full border-0"
|
|
14704
|
+
}
|
|
14705
|
+
),
|
|
14706
|
+
/* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-2 p-4 text-center text-sm text-zinc-500 dark:text-zinc-400", children: [
|
|
14707
|
+
/* @__PURE__ */ jsx("span", { children: "This browser can't display the PDF inline." }),
|
|
14708
|
+
/* @__PURE__ */ jsx(
|
|
14709
|
+
"a",
|
|
14710
|
+
{
|
|
14711
|
+
href: src,
|
|
14712
|
+
download: true,
|
|
14713
|
+
className: "font-medium text-blue-600 hover:underline dark:text-blue-400",
|
|
14714
|
+
children: "Download PDF"
|
|
14715
|
+
}
|
|
14716
|
+
)
|
|
14717
|
+
] })
|
|
14718
|
+
] })
|
|
14719
|
+
}
|
|
14720
|
+
);
|
|
14721
|
+
}
|
|
14722
|
+
);
|
|
14723
|
+
PdfViewer.displayName = "PdfViewer";
|
|
14724
|
+
function basename(src) {
|
|
14725
|
+
if (/^(data|blob):/i.test(src)) return null;
|
|
14726
|
+
const seg = src.split(/[?#]/, 1)[0].split("/").pop();
|
|
14727
|
+
return seg ? decodeURIComponent(seg) : null;
|
|
14728
|
+
}
|
|
14729
|
+
function MediaFallback({ src, mime, label, className }) {
|
|
14730
|
+
const name = label || basename(src);
|
|
14731
|
+
return /* @__PURE__ */ jsxs(
|
|
14732
|
+
"div",
|
|
14733
|
+
{
|
|
14734
|
+
"data-react-fancy-media-fallback": "",
|
|
14735
|
+
className: cn(
|
|
14736
|
+
"flex flex-col items-center justify-center gap-2 rounded-lg border border-zinc-200 bg-white p-6 text-center dark:border-zinc-700 dark:bg-zinc-900",
|
|
14737
|
+
className
|
|
14738
|
+
),
|
|
14739
|
+
children: [
|
|
14740
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-200", children: "No preview available" }),
|
|
14741
|
+
(name || mime) && /* @__PURE__ */ jsxs("span", { className: "max-w-full truncate text-xs text-zinc-500 dark:text-zinc-400", children: [
|
|
14742
|
+
name,
|
|
14743
|
+
name && mime ? " \xB7 " : "",
|
|
14744
|
+
mime
|
|
14745
|
+
] }),
|
|
14746
|
+
/* @__PURE__ */ jsx(
|
|
14747
|
+
"a",
|
|
14748
|
+
{
|
|
14749
|
+
href: src,
|
|
14750
|
+
download: name ?? void 0,
|
|
14751
|
+
className: "text-xs font-medium text-blue-600 hover:underline dark:text-blue-400",
|
|
14752
|
+
children: "Download"
|
|
14753
|
+
}
|
|
14754
|
+
)
|
|
14755
|
+
]
|
|
14756
|
+
}
|
|
14757
|
+
);
|
|
14758
|
+
}
|
|
14759
|
+
var MediaViewer = forwardRef(
|
|
14760
|
+
({
|
|
14761
|
+
src,
|
|
14762
|
+
mime,
|
|
14763
|
+
alt,
|
|
14764
|
+
kind,
|
|
14765
|
+
imageProps,
|
|
14766
|
+
videoProps,
|
|
14767
|
+
audioProps,
|
|
14768
|
+
pdfProps,
|
|
14769
|
+
fallback,
|
|
14770
|
+
onError,
|
|
14771
|
+
className,
|
|
14772
|
+
style
|
|
14773
|
+
}, ref) => {
|
|
14774
|
+
const resolved = kind ?? resolveMediaType({ mime, src });
|
|
14775
|
+
switch (resolved) {
|
|
14776
|
+
case "image":
|
|
14777
|
+
return /* @__PURE__ */ jsx(
|
|
14778
|
+
ImageViewer,
|
|
14779
|
+
{
|
|
14780
|
+
ref,
|
|
14781
|
+
src,
|
|
14782
|
+
alt: alt ?? "",
|
|
14783
|
+
onError,
|
|
14784
|
+
className,
|
|
14785
|
+
style,
|
|
14786
|
+
...imageProps
|
|
14787
|
+
}
|
|
14788
|
+
);
|
|
14789
|
+
case "video":
|
|
14790
|
+
return /* @__PURE__ */ jsx(
|
|
14791
|
+
VideoViewer,
|
|
14792
|
+
{
|
|
14793
|
+
ref,
|
|
14794
|
+
src,
|
|
14795
|
+
onError,
|
|
14796
|
+
className,
|
|
14797
|
+
style,
|
|
14798
|
+
...videoProps
|
|
14799
|
+
}
|
|
14800
|
+
);
|
|
14801
|
+
case "audio":
|
|
14802
|
+
return /* @__PURE__ */ jsx(
|
|
14803
|
+
AudioViewer,
|
|
14804
|
+
{
|
|
14805
|
+
ref,
|
|
14806
|
+
src,
|
|
14807
|
+
title: alt,
|
|
14808
|
+
onError,
|
|
14809
|
+
className,
|
|
14810
|
+
style,
|
|
14811
|
+
...audioProps
|
|
14812
|
+
}
|
|
14813
|
+
);
|
|
14814
|
+
case "pdf":
|
|
14815
|
+
return /* @__PURE__ */ jsx(
|
|
14816
|
+
PdfViewer,
|
|
14817
|
+
{
|
|
14818
|
+
ref,
|
|
14819
|
+
src,
|
|
14820
|
+
title: alt,
|
|
14821
|
+
className,
|
|
14822
|
+
style,
|
|
14823
|
+
...pdfProps
|
|
14824
|
+
}
|
|
14825
|
+
);
|
|
14826
|
+
default:
|
|
14827
|
+
return /* @__PURE__ */ jsx(
|
|
14828
|
+
"div",
|
|
14829
|
+
{
|
|
14830
|
+
ref,
|
|
14831
|
+
"data-react-fancy-media-viewer": "",
|
|
14832
|
+
className,
|
|
14833
|
+
style,
|
|
14834
|
+
children: fallback ?? /* @__PURE__ */ jsx(MediaFallback, { src, mime, label: alt })
|
|
14835
|
+
}
|
|
14836
|
+
);
|
|
14837
|
+
}
|
|
14838
|
+
}
|
|
14839
|
+
);
|
|
14840
|
+
MediaViewer.displayName = "MediaViewer";
|
|
14299
14841
|
|
|
14300
|
-
export { Accordion, AccordionPanel, AccordionPanelContent, AccordionPanelSection, AccordionPanelTrigger, Action, Autocomplete, Avatar, Badge, Brand, Breadcrumbs, Button, Calendar, Callout, Card, Carousel, Chart, ChatDrawer, Checkbox, CheckboxGroup, ColorPicker, Command, Composer, ContentRenderer, ContextMenu, DatePicker, DisplayValue, Dropdown, EMOJI_CATEGORY_ORDER, EMOJI_DATA, EMOJI_ENTRIES, Editor, Emoji, EmojiSelect, FauxClient, Field, FieldModeContext, FileUpload, Form, FormProvider, Heading, Icon, Input, InputTag, Kanban, MagicWand, Menu2 as Menu, MobileMenu, Modal, MoodMeter, MultiSwitch, Navbar, OtpInput, Pagination, Pillbox, Popover, Portal, Profile, Progress, PromptInput, RadioGroup, ReasonTag, SKIN_TONES, Select, Separator, Sidebar, Skeleton, Slider, StickyNote, Switch, Table, Tabs, Text, Textarea, TimeGrid, TimePicker, Timeline, Toast, Tooltip, TreeNav, applyTone, cn, configureIcons, contentEditableAdapter, controlledAdapter, find, hasSkinTones, inputAdapter, registerExtension, registerExtensions, registerIconAddendum, registerIconSet, registerIcons, resolve, sanitizeHref, sanitizeHtml, search, skinTones, textareaAdapter, useAccordion, useAccordionPanel, useAccordionSection, useAnimation, useCarousel, useCommand, useContextMenu, useControllableState, useDropdown, useEditor, useEscapeKey, useFieldMode, useFileUpload, useFloatingPosition, useFocusTrap, useId12 as useId, useKanban, useMenu, useMobileMenu, useModal, useNavbar, useNodeRegistry, useOutsideClick, usePanZoom, usePopover, useSidebar, useTabs, useToast, useTreeNav };
|
|
14842
|
+
export { Accordion, AccordionPanel, AccordionPanelContent, AccordionPanelSection, AccordionPanelTrigger, Action, AudioViewer, Autocomplete, Avatar, Badge, Brand, Breadcrumbs, Button, Calendar, Callout, Card, Carousel, Chart, ChatDrawer, Checkbox, CheckboxGroup, ColorPicker, Command, Composer, ContentRenderer, ContextMenu, DatePicker, DisplayValue, Dropdown, EMOJI_CATEGORY_ORDER, EMOJI_DATA, EMOJI_ENTRIES, Editor, Emoji, EmojiSelect, FauxClient, Field, FieldModeContext, FileUpload, Form, FormProvider, Heading, Icon, ImageViewer, Input, InputTag, Kanban, MagicWand, MediaViewer, Menu2 as Menu, MobileMenu, Modal, MoodMeter, MultiSwitch, Navbar, OtpInput, Pagination, PdfViewer, Pillbox, Popover, Portal, Profile, Progress, PromptInput, RadioGroup, ReasonTag, SKIN_TONES, Select, Separator, Sidebar, Skeleton, Slider, StickyNote, Switch, Table, Tabs, Text, Textarea, TimeGrid, TimePicker, Timeline, Toast, Tooltip, TreeNav, VideoViewer, applyTone, cn, configureIcons, contentEditableAdapter, controlledAdapter, find, hasSkinTones, inputAdapter, registerExtension, registerExtensions, registerIconAddendum, registerIconSet, registerIcons, resolve, resolveMediaType, sanitizeHref, sanitizeHtml, search, skinTones, textareaAdapter, useAccordion, useAccordionPanel, useAccordionSection, useAnimation, useCarousel, useCommand, useContextMenu, useControllableState, useDropdown, useEditor, useEscapeKey, useFieldMode, useFileUpload, useFloatingPosition, useFocusTrap, useId12 as useId, useKanban, useMenu, useMobileMenu, useModal, useNavbar, useNodeRegistry, useOutsideClick, usePanZoom, usePopover, useSidebar, useTabs, useToast, useTreeNav };
|
|
14301
14843
|
//# sourceMappingURL=index.js.map
|
|
14302
14844
|
//# sourceMappingURL=index.js.map
|