@particle-academy/react-fancy 4.8.1 → 4.9.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 CHANGED
@@ -166,6 +166,18 @@ npx vite build # Build demo app (verifies imports work)
166
166
  | Diagram | Entity-relationship diagram with draggable nodes and relation lines | [docs](docs/Diagram.md) |
167
167
  | ContentRenderer | Markdown/HTML content renderer | [docs](docs/ContentRenderer.md) |
168
168
 
169
+ ### Media Viewers
170
+
171
+ Standalone, read-only viewers for displaying media files — drop one in anywhere, or use `<MediaViewer>` to pick the right one from a `mime`/`src` when you don't know the type ahead of time (e.g. showing a file from a tree). SVG renders through `ImageViewer`.
172
+
173
+ | Component | Description | Docs |
174
+ |-----------|-------------|------|
175
+ | MediaViewer | Picks image/video/audio/PDF from `mime` (or `src`) + download fallback | [docs](docs/MediaViewer.md) |
176
+ | ImageViewer | Fit-to-container image with zoom/pan and transparency checkerboard | [docs](docs/ImageViewer.md) |
177
+ | VideoViewer | Native video controls, poster, fit | [docs](docs/VideoViewer.md) |
178
+ | AudioViewer | Themed card around the native audio player | [docs](docs/AudioViewer.md) |
179
+ | PdfViewer | Inline PDF via `<object>`/`<iframe>` with download fallback | [docs](docs/PdfViewer.md) |
180
+
169
181
  ### Human+ Primitives
170
182
 
171
183
  Components for surfaces where humans and AI agents trade control fluidly. Each promoted from the [`dreaming`](https://github.com/Particle-Academy/pa-ux-sandbox/tree/dreaming) sandbox after the API stabilized.
@@ -191,6 +203,7 @@ Components for surfaces where humans and AI agents trade control fluidly. Each p
191
203
  |--------|-------------|------|
192
204
  | Portal | `createPortal` wrapper with automatic dark mode propagation | [docs](docs/Portal.md) |
193
205
  | `cn()` | `clsx` + `tailwind-merge` for conditional class composition | [docs](docs/utilities.md) |
206
+ | `resolveMediaType()` | Resolve `image`/`video`/`audio`/`pdf`/`unknown` from a `mime` and/or `src` | [docs](docs/MediaViewer.md) |
194
207
  | Hooks | useControllableState, useFloatingPosition, useOutsideClick, useEscapeKey, useFocusTrap, useAnimation, useId, usePanZoom | [docs](docs/hooks.md) |
195
208
 
196
209
  ## Customization
package/dist/index.cjs CHANGED
@@ -13026,6 +13026,108 @@ TreeNavRoot.displayName = "TreeNav";
13026
13026
  var TreeNav = Object.assign(TreeNavRoot, {
13027
13027
  Node: TreeNode
13028
13028
  });
13029
+
13030
+ // src/utils/media-type.ts
13031
+ var IMAGE_EXTS = /* @__PURE__ */ new Set([
13032
+ "png",
13033
+ "jpg",
13034
+ "jpeg",
13035
+ "jfif",
13036
+ "pjpeg",
13037
+ "gif",
13038
+ "webp",
13039
+ "avif",
13040
+ "bmp",
13041
+ "ico",
13042
+ "cur",
13043
+ "svg",
13044
+ "svgz",
13045
+ "apng",
13046
+ "tif",
13047
+ "tiff",
13048
+ "heic",
13049
+ "heif"
13050
+ ]);
13051
+ var VIDEO_EXTS = /* @__PURE__ */ new Set([
13052
+ "mp4",
13053
+ "m4v",
13054
+ "webm",
13055
+ "ogv",
13056
+ "ogm",
13057
+ "mov",
13058
+ "mkv",
13059
+ "avi",
13060
+ "wmv",
13061
+ "flv",
13062
+ "3gp",
13063
+ "3g2",
13064
+ "mpg",
13065
+ "mpeg"
13066
+ ]);
13067
+ var AUDIO_EXTS = /* @__PURE__ */ new Set([
13068
+ "mp3",
13069
+ "wav",
13070
+ "wave",
13071
+ "ogg",
13072
+ "oga",
13073
+ "m4a",
13074
+ "m4b",
13075
+ "aac",
13076
+ "flac",
13077
+ "opus",
13078
+ "weba",
13079
+ "mid",
13080
+ "midi",
13081
+ "aiff",
13082
+ "aif"
13083
+ ]);
13084
+ function mimeToKind(mime) {
13085
+ const m = mime.toLowerCase().split(";")[0].trim();
13086
+ if (!m) return "unknown";
13087
+ if (m === "application/pdf" || m === "application/x-pdf") return "pdf";
13088
+ if (m.startsWith("image/")) return "image";
13089
+ if (m.startsWith("video/")) return "video";
13090
+ if (m.startsWith("audio/")) return "audio";
13091
+ if (m === "application/ogg") return "audio";
13092
+ return "unknown";
13093
+ }
13094
+ function extToKind(ext) {
13095
+ const e = ext.toLowerCase();
13096
+ if (e === "pdf") return "pdf";
13097
+ if (IMAGE_EXTS.has(e)) return "image";
13098
+ if (VIDEO_EXTS.has(e)) return "video";
13099
+ if (AUDIO_EXTS.has(e)) return "audio";
13100
+ return "unknown";
13101
+ }
13102
+ function extFromSrc(src) {
13103
+ const clean = src.split(/[?#]/, 1)[0];
13104
+ const lastSeg = clean.split("/").pop() ?? "";
13105
+ const dot = lastSeg.lastIndexOf(".");
13106
+ if (dot <= 0 || dot === lastSeg.length - 1) return null;
13107
+ return lastSeg.slice(dot + 1);
13108
+ }
13109
+ function mimeFromDataUri(src) {
13110
+ if (!/^data:/i.test(src)) return null;
13111
+ const header = src.slice(5).split(",", 1)[0];
13112
+ const mt = header.split(";")[0].trim();
13113
+ return mt || null;
13114
+ }
13115
+ function resolveMediaType({ mime, src }) {
13116
+ if (mime) {
13117
+ const k = mimeToKind(mime);
13118
+ if (k !== "unknown") return k;
13119
+ }
13120
+ if (src) {
13121
+ const dataMime = mimeFromDataUri(src);
13122
+ if (dataMime) {
13123
+ const k = mimeToKind(dataMime);
13124
+ if (k !== "unknown") return k;
13125
+ }
13126
+ const ext = extFromSrc(src);
13127
+ if (ext) return extToKind(ext);
13128
+ }
13129
+ return "unknown";
13130
+ }
13029
13131
  var CONFIDENCE_TIERS = [
13030
13132
  { min: 0.85, color: "#10b981", label: "high" },
13031
13133
  { min: 0.6, color: "#f59e0b", label: "medium" },
@@ -14298,6 +14400,446 @@ function caretRect(ta, start, end) {
14298
14400
  const y = taRect.top - parentRect.top + offsetY - ta.scrollTop;
14299
14401
  return { x, y };
14300
14402
  }
14403
+ var DEFAULT_VIEWPORT = { panX: 0, panY: 0, zoom: 1 };
14404
+ var fitClasses = {
14405
+ contain: "h-full w-full object-contain",
14406
+ cover: "h-full w-full object-cover",
14407
+ none: "max-w-none object-none"
14408
+ };
14409
+ function clamp2(n, min, max) {
14410
+ return Math.min(max, Math.max(min, n));
14411
+ }
14412
+ var ImageViewer = react.forwardRef(
14413
+ ({
14414
+ src,
14415
+ alt = "",
14416
+ fit = "contain",
14417
+ zoomable = true,
14418
+ pannable = true,
14419
+ controls,
14420
+ minZoom = 0.25,
14421
+ maxZoom = 8,
14422
+ checkerboard = true,
14423
+ viewport,
14424
+ defaultViewport,
14425
+ onViewportChange,
14426
+ onLoad,
14427
+ onError,
14428
+ className,
14429
+ style
14430
+ }, ref) => {
14431
+ const containerRef = react.useRef(null);
14432
+ const [status, setStatus] = react.useState("loading");
14433
+ const isControlled = viewport !== void 0;
14434
+ const [internal, setInternal] = react.useState(
14435
+ defaultViewport ?? DEFAULT_VIEWPORT
14436
+ );
14437
+ const current = isControlled ? viewport : internal;
14438
+ const currentRef = react.useRef(current);
14439
+ currentRef.current = current;
14440
+ const setViewport = react.useCallback(
14441
+ (next) => {
14442
+ const resolved = typeof next === "function" ? next(currentRef.current) : next;
14443
+ if (!isControlled) setInternal(resolved);
14444
+ onViewportChange?.(resolved);
14445
+ },
14446
+ [isControlled, onViewportChange]
14447
+ );
14448
+ const interactive = status === "loaded";
14449
+ const { containerProps, isPanning } = usePanZoom({
14450
+ viewport: current,
14451
+ setViewport,
14452
+ minZoom,
14453
+ maxZoom,
14454
+ pannable: pannable && interactive,
14455
+ zoomable: zoomable && interactive,
14456
+ containerRef
14457
+ });
14458
+ const zoomBy = react.useCallback(
14459
+ (factor) => {
14460
+ const el = containerRef.current;
14461
+ if (!el) return;
14462
+ const rect = el.getBoundingClientRect();
14463
+ const cx = rect.width / 2;
14464
+ const cy = rect.height / 2;
14465
+ setViewport((prev) => {
14466
+ const newZoom = clamp2(prev.zoom * factor, minZoom, maxZoom);
14467
+ const ratio = newZoom / prev.zoom;
14468
+ return {
14469
+ zoom: newZoom,
14470
+ panX: cx - (cx - prev.panX) * ratio,
14471
+ panY: cy - (cy - prev.panY) * ratio
14472
+ };
14473
+ });
14474
+ },
14475
+ [setViewport, minZoom, maxZoom]
14476
+ );
14477
+ const reset = react.useCallback(() => setViewport(DEFAULT_VIEWPORT), [setViewport]);
14478
+ const showControls = (controls ?? zoomable) && interactive;
14479
+ const transform = `translate(${current.panX}px, ${current.panY}px) scale(${current.zoom})`;
14480
+ return /* @__PURE__ */ jsxRuntime.jsxs(
14481
+ "div",
14482
+ {
14483
+ ref,
14484
+ "data-react-fancy-image-viewer": "",
14485
+ className: cn(
14486
+ "relative isolate overflow-hidden rounded-md select-none",
14487
+ checkerboard ? "fancy-checkerboard" : "bg-zinc-100 dark:bg-zinc-900",
14488
+ className
14489
+ ),
14490
+ style,
14491
+ children: [
14492
+ /* @__PURE__ */ jsxRuntime.jsx(
14493
+ "div",
14494
+ {
14495
+ ref: containerRef,
14496
+ "data-canvas-bg": "",
14497
+ className: cn(
14498
+ "absolute inset-0 flex items-center justify-center",
14499
+ isPanning ? "cursor-grabbing" : pannable && interactive ? "cursor-grab" : ""
14500
+ ),
14501
+ style: {
14502
+ transform,
14503
+ transformOrigin: "0 0",
14504
+ willChange: "transform",
14505
+ touchAction: zoomable || pannable ? "none" : void 0
14506
+ },
14507
+ onDoubleClick: zoomable ? reset : void 0,
14508
+ ...containerProps,
14509
+ children: /* @__PURE__ */ jsxRuntime.jsx(
14510
+ "img",
14511
+ {
14512
+ src,
14513
+ alt,
14514
+ draggable: false,
14515
+ onLoad: () => {
14516
+ setStatus("loaded");
14517
+ onLoad?.();
14518
+ },
14519
+ onError: () => {
14520
+ setStatus("error");
14521
+ onError?.();
14522
+ },
14523
+ className: cn(
14524
+ "pointer-events-none block",
14525
+ status === "error" && "hidden",
14526
+ fitClasses[fit]
14527
+ )
14528
+ }
14529
+ )
14530
+ }
14531
+ ),
14532
+ status === "error" && /* @__PURE__ */ jsxRuntime.jsxs(
14533
+ "div",
14534
+ {
14535
+ "data-react-fancy-image-viewer-error": "",
14536
+ 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",
14537
+ children: [
14538
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Couldn't load image" }),
14539
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-full truncate text-xs opacity-70", children: alt || src })
14540
+ ]
14541
+ }
14542
+ ),
14543
+ showControls && /* @__PURE__ */ jsxRuntime.jsxs(
14544
+ "div",
14545
+ {
14546
+ "data-react-fancy-image-viewer-controls": "",
14547
+ 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",
14548
+ children: [
14549
+ /* @__PURE__ */ jsxRuntime.jsx(
14550
+ "button",
14551
+ {
14552
+ type: "button",
14553
+ "aria-label": "Zoom out",
14554
+ onClick: () => zoomBy(1 / 1.25),
14555
+ className: "flex h-6 w-6 items-center justify-center rounded text-base leading-none hover:bg-zinc-100 dark:hover:bg-zinc-800",
14556
+ children: "\u2212"
14557
+ }
14558
+ ),
14559
+ /* @__PURE__ */ jsxRuntime.jsxs(
14560
+ "button",
14561
+ {
14562
+ type: "button",
14563
+ "aria-label": "Reset zoom",
14564
+ onClick: reset,
14565
+ className: "min-w-[3rem] rounded px-1 text-center text-xs tabular-nums hover:bg-zinc-100 dark:hover:bg-zinc-800",
14566
+ children: [
14567
+ Math.round(current.zoom * 100),
14568
+ "%"
14569
+ ]
14570
+ }
14571
+ ),
14572
+ /* @__PURE__ */ jsxRuntime.jsx(
14573
+ "button",
14574
+ {
14575
+ type: "button",
14576
+ "aria-label": "Zoom in",
14577
+ onClick: () => zoomBy(1.25),
14578
+ className: "flex h-6 w-6 items-center justify-center rounded text-base leading-none hover:bg-zinc-100 dark:hover:bg-zinc-800",
14579
+ children: "+"
14580
+ }
14581
+ )
14582
+ ]
14583
+ }
14584
+ )
14585
+ ]
14586
+ }
14587
+ );
14588
+ }
14589
+ );
14590
+ ImageViewer.displayName = "ImageViewer";
14591
+ var VideoViewer = react.forwardRef(
14592
+ ({
14593
+ src,
14594
+ poster,
14595
+ controls = true,
14596
+ autoPlay = false,
14597
+ loop = false,
14598
+ muted = false,
14599
+ fit = "contain",
14600
+ onError,
14601
+ className,
14602
+ style
14603
+ }, ref) => {
14604
+ const [errored, setErrored] = react.useState(false);
14605
+ return /* @__PURE__ */ jsxRuntime.jsx(
14606
+ "div",
14607
+ {
14608
+ ref,
14609
+ "data-react-fancy-video-viewer": "",
14610
+ className: cn(
14611
+ "relative flex items-center justify-center overflow-hidden rounded-md bg-black",
14612
+ className
14613
+ ),
14614
+ style,
14615
+ children: errored ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center gap-1 p-4 text-center text-sm text-zinc-400", children: [
14616
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Couldn't load video" }),
14617
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-full truncate text-xs opacity-70", children: src })
14618
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
14619
+ "video",
14620
+ {
14621
+ src,
14622
+ poster,
14623
+ controls,
14624
+ autoPlay,
14625
+ loop,
14626
+ muted,
14627
+ playsInline: true,
14628
+ onError: () => {
14629
+ setErrored(true);
14630
+ onError?.();
14631
+ },
14632
+ className: cn(
14633
+ "max-h-full max-w-full",
14634
+ fit === "cover" ? "h-full w-full object-cover" : "object-contain"
14635
+ )
14636
+ }
14637
+ )
14638
+ }
14639
+ );
14640
+ }
14641
+ );
14642
+ VideoViewer.displayName = "VideoViewer";
14643
+ var AudioViewer = react.forwardRef(
14644
+ ({
14645
+ src,
14646
+ title,
14647
+ controls = true,
14648
+ autoPlay = false,
14649
+ loop = false,
14650
+ onError,
14651
+ className,
14652
+ style
14653
+ }, ref) => {
14654
+ const [errored, setErrored] = react.useState(false);
14655
+ return /* @__PURE__ */ jsxRuntime.jsxs(
14656
+ "div",
14657
+ {
14658
+ ref,
14659
+ "data-react-fancy-audio-viewer": "",
14660
+ className: cn(
14661
+ "flex flex-col gap-2 rounded-lg border border-zinc-200 bg-white p-4 dark:border-zinc-700 dark:bg-zinc-900",
14662
+ className
14663
+ ),
14664
+ style,
14665
+ children: [
14666
+ title && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-sm font-medium text-zinc-700 dark:text-zinc-200", children: title }),
14667
+ errored ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-zinc-500 dark:text-zinc-400", children: "Couldn't load audio." }) : /* @__PURE__ */ jsxRuntime.jsx(
14668
+ "audio",
14669
+ {
14670
+ src,
14671
+ controls,
14672
+ autoPlay,
14673
+ loop,
14674
+ onError: () => {
14675
+ setErrored(true);
14676
+ onError?.();
14677
+ },
14678
+ className: "w-full"
14679
+ }
14680
+ )
14681
+ ]
14682
+ }
14683
+ );
14684
+ }
14685
+ );
14686
+ AudioViewer.displayName = "AudioViewer";
14687
+ var PdfViewer = react.forwardRef(
14688
+ ({ src, title = "PDF document", className, style }, ref) => {
14689
+ return /* @__PURE__ */ jsxRuntime.jsx(
14690
+ "div",
14691
+ {
14692
+ ref,
14693
+ "data-react-fancy-pdf-viewer": "",
14694
+ className: cn(
14695
+ "relative h-full min-h-[20rem] w-full overflow-hidden rounded-md bg-zinc-100 dark:bg-zinc-900",
14696
+ className
14697
+ ),
14698
+ style,
14699
+ children: /* @__PURE__ */ jsxRuntime.jsxs("object", { data: src, type: "application/pdf", className: "h-full w-full", children: [
14700
+ /* @__PURE__ */ jsxRuntime.jsx(
14701
+ "iframe",
14702
+ {
14703
+ src,
14704
+ title,
14705
+ className: "h-full w-full border-0"
14706
+ }
14707
+ ),
14708
+ /* @__PURE__ */ jsxRuntime.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: [
14709
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "This browser can't display the PDF inline." }),
14710
+ /* @__PURE__ */ jsxRuntime.jsx(
14711
+ "a",
14712
+ {
14713
+ href: src,
14714
+ download: true,
14715
+ className: "font-medium text-blue-600 hover:underline dark:text-blue-400",
14716
+ children: "Download PDF"
14717
+ }
14718
+ )
14719
+ ] })
14720
+ ] })
14721
+ }
14722
+ );
14723
+ }
14724
+ );
14725
+ PdfViewer.displayName = "PdfViewer";
14726
+ function basename(src) {
14727
+ if (/^(data|blob):/i.test(src)) return null;
14728
+ const seg = src.split(/[?#]/, 1)[0].split("/").pop();
14729
+ return seg ? decodeURIComponent(seg) : null;
14730
+ }
14731
+ function MediaFallback({ src, mime, label, className }) {
14732
+ const name = label || basename(src);
14733
+ return /* @__PURE__ */ jsxRuntime.jsxs(
14734
+ "div",
14735
+ {
14736
+ "data-react-fancy-media-fallback": "",
14737
+ className: cn(
14738
+ "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",
14739
+ className
14740
+ ),
14741
+ children: [
14742
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-200", children: "No preview available" }),
14743
+ (name || mime) && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "max-w-full truncate text-xs text-zinc-500 dark:text-zinc-400", children: [
14744
+ name,
14745
+ name && mime ? " \xB7 " : "",
14746
+ mime
14747
+ ] }),
14748
+ /* @__PURE__ */ jsxRuntime.jsx(
14749
+ "a",
14750
+ {
14751
+ href: src,
14752
+ download: name ?? void 0,
14753
+ className: "text-xs font-medium text-blue-600 hover:underline dark:text-blue-400",
14754
+ children: "Download"
14755
+ }
14756
+ )
14757
+ ]
14758
+ }
14759
+ );
14760
+ }
14761
+ var MediaViewer = react.forwardRef(
14762
+ ({
14763
+ src,
14764
+ mime,
14765
+ alt,
14766
+ kind,
14767
+ imageProps,
14768
+ videoProps,
14769
+ audioProps,
14770
+ pdfProps,
14771
+ fallback,
14772
+ onError,
14773
+ className,
14774
+ style
14775
+ }, ref) => {
14776
+ const resolved = kind ?? resolveMediaType({ mime, src });
14777
+ switch (resolved) {
14778
+ case "image":
14779
+ return /* @__PURE__ */ jsxRuntime.jsx(
14780
+ ImageViewer,
14781
+ {
14782
+ ref,
14783
+ src,
14784
+ alt: alt ?? "",
14785
+ onError,
14786
+ className,
14787
+ style,
14788
+ ...imageProps
14789
+ }
14790
+ );
14791
+ case "video":
14792
+ return /* @__PURE__ */ jsxRuntime.jsx(
14793
+ VideoViewer,
14794
+ {
14795
+ ref,
14796
+ src,
14797
+ onError,
14798
+ className,
14799
+ style,
14800
+ ...videoProps
14801
+ }
14802
+ );
14803
+ case "audio":
14804
+ return /* @__PURE__ */ jsxRuntime.jsx(
14805
+ AudioViewer,
14806
+ {
14807
+ ref,
14808
+ src,
14809
+ title: alt,
14810
+ onError,
14811
+ className,
14812
+ style,
14813
+ ...audioProps
14814
+ }
14815
+ );
14816
+ case "pdf":
14817
+ return /* @__PURE__ */ jsxRuntime.jsx(
14818
+ PdfViewer,
14819
+ {
14820
+ ref,
14821
+ src,
14822
+ title: alt,
14823
+ className,
14824
+ style,
14825
+ ...pdfProps
14826
+ }
14827
+ );
14828
+ default:
14829
+ return /* @__PURE__ */ jsxRuntime.jsx(
14830
+ "div",
14831
+ {
14832
+ ref,
14833
+ "data-react-fancy-media-viewer": "",
14834
+ className,
14835
+ style,
14836
+ children: fallback ?? /* @__PURE__ */ jsxRuntime.jsx(MediaFallback, { src, mime, label: alt })
14837
+ }
14838
+ );
14839
+ }
14840
+ }
14841
+ );
14842
+ MediaViewer.displayName = "MediaViewer";
14301
14843
 
14302
14844
  exports.Accordion = Accordion;
14303
14845
  exports.AccordionPanel = AccordionPanel;
@@ -14305,6 +14847,7 @@ exports.AccordionPanelContent = AccordionPanelContent;
14305
14847
  exports.AccordionPanelSection = AccordionPanelSection;
14306
14848
  exports.AccordionPanelTrigger = AccordionPanelTrigger;
14307
14849
  exports.Action = Action;
14850
+ exports.AudioViewer = AudioViewer;
14308
14851
  exports.Autocomplete = Autocomplete;
14309
14852
  exports.Avatar = Avatar;
14310
14853
  exports.Badge = Badge;
@@ -14341,10 +14884,12 @@ exports.Form = Form;
14341
14884
  exports.FormProvider = FormProvider;
14342
14885
  exports.Heading = Heading;
14343
14886
  exports.Icon = Icon;
14887
+ exports.ImageViewer = ImageViewer;
14344
14888
  exports.Input = Input;
14345
14889
  exports.InputTag = InputTag;
14346
14890
  exports.Kanban = Kanban;
14347
14891
  exports.MagicWand = MagicWand;
14892
+ exports.MediaViewer = MediaViewer;
14348
14893
  exports.Menu = Menu2;
14349
14894
  exports.MobileMenu = MobileMenu;
14350
14895
  exports.Modal = Modal;
@@ -14353,6 +14898,7 @@ exports.MultiSwitch = MultiSwitch;
14353
14898
  exports.Navbar = Navbar;
14354
14899
  exports.OtpInput = OtpInput;
14355
14900
  exports.Pagination = Pagination;
14901
+ exports.PdfViewer = PdfViewer;
14356
14902
  exports.Pillbox = Pillbox;
14357
14903
  exports.Popover = Popover;
14358
14904
  exports.Portal = Portal;
@@ -14379,6 +14925,7 @@ exports.Timeline = Timeline;
14379
14925
  exports.Toast = Toast;
14380
14926
  exports.Tooltip = Tooltip;
14381
14927
  exports.TreeNav = TreeNav;
14928
+ exports.VideoViewer = VideoViewer;
14382
14929
  exports.applyTone = applyTone;
14383
14930
  exports.cn = cn;
14384
14931
  exports.configureIcons = configureIcons;
@@ -14393,6 +14940,7 @@ exports.registerIconAddendum = registerIconAddendum;
14393
14940
  exports.registerIconSet = registerIconSet;
14394
14941
  exports.registerIcons = registerIcons;
14395
14942
  exports.resolve = resolve;
14943
+ exports.resolveMediaType = resolveMediaType;
14396
14944
  exports.sanitizeHref = sanitizeHref;
14397
14945
  exports.sanitizeHtml = sanitizeHtml;
14398
14946
  exports.search = search;