@ai-matrx/media 0.4.4 → 0.5.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/dist/viewers.js CHANGED
@@ -115,13 +115,6 @@ function DownloadIcon(props) {
115
115
  /* @__PURE__ */ jsx("path", { d: "m7 10 5 5 5-5" })
116
116
  ] });
117
117
  }
118
- function ExternalLinkIcon(props) {
119
- return /* @__PURE__ */ jsxs("svg", { ...svgProps(props), children: [
120
- /* @__PURE__ */ jsx("path", { d: "M15 3h6v6" }),
121
- /* @__PURE__ */ jsx("path", { d: "M10 14 21 3" }),
122
- /* @__PURE__ */ jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" })
123
- ] });
124
- }
125
118
  function FileIcon(props) {
126
119
  return /* @__PURE__ */ jsxs("svg", { ...svgProps(props), children: [
127
120
  /* @__PURE__ */ jsx("path", { d: "M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z" }),
@@ -234,12 +227,6 @@ function VideoIcon(props) {
234
227
  /* @__PURE__ */ jsx("rect", { x: "2", y: "6", width: "14", height: "12", rx: "2" })
235
228
  ] });
236
229
  }
237
- function XIcon(props) {
238
- return /* @__PURE__ */ jsxs("svg", { ...svgProps(props), children: [
239
- /* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
240
- /* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
241
- ] });
242
- }
243
230
  function AlertCircleIcon(props) {
244
231
  return /* @__PURE__ */ jsxs("svg", { ...svgProps(props), children: [
245
232
  /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
@@ -247,12 +234,6 @@ function AlertCircleIcon(props) {
247
234
  /* @__PURE__ */ jsx("line", { x1: "12", x2: "12.01", y1: "16", y2: "16" })
248
235
  ] });
249
236
  }
250
- function CheckCircle2Icon(props) {
251
- return /* @__PURE__ */ jsxs("svg", { ...svgProps(props), children: [
252
- /* @__PURE__ */ jsx("path", { d: "M21.801 10A10 10 0 1 1 17 3.335" }),
253
- /* @__PURE__ */ jsx("path", { d: "m9 11 3 3L22 4" })
254
- ] });
255
- }
256
237
  function GlobeIcon(props) {
257
238
  return /* @__PURE__ */ jsxs("svg", { ...svgProps(props), children: [
258
239
  /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
@@ -971,181 +952,9 @@ function FileIcon2({
971
952
  );
972
953
  }
973
954
 
974
- // src/react/upload-progress-list.tsx
975
- import { memo, useEffect as useEffect4, useRef as useRef2, useState as useState5 } from "react";
976
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
977
- var AUTO_DISMISS_MS = 1e4;
978
- function formatFileSize(bytes) {
979
- if (bytes == null || !Number.isFinite(bytes) || bytes < 0) return "\u2014";
980
- if (bytes < 1024) return `${bytes} B`;
981
- const units = ["KB", "MB", "GB", "TB"];
982
- let value = bytes;
983
- let unit = -1;
984
- do {
985
- value /= 1024;
986
- unit += 1;
987
- } while (value >= 1024 && unit < units.length - 1);
988
- return `${value >= 10 ? Math.round(value) : value.toFixed(1)} ${units[unit] ?? "TB"}`;
989
- }
990
- function UploadProgressListImpl({
991
- uploads,
992
- onDismiss,
993
- onOpenFile,
994
- className
995
- }) {
996
- const [hovered, setHovered] = useState5(false);
997
- const activeCount = uploads.filter((u) => u.status === "uploading").length;
998
- const successCount = uploads.filter((u) => u.status === "success").length;
999
- const errorCount = uploads.filter((u) => u.status === "error").length;
1000
- const timersRef = useRef2(
1001
- /* @__PURE__ */ new Map()
1002
- );
1003
- const onDismissRef = useRef2(onDismiss);
1004
- onDismissRef.current = onDismiss;
1005
- useEffect4(() => {
1006
- const timers = timersRef.current;
1007
- if (hovered) {
1008
- timers.forEach((t) => clearTimeout(t));
1009
- timers.clear();
1010
- return;
1011
- }
1012
- for (const u of uploads) {
1013
- if (u.status !== "success") continue;
1014
- if (timers.has(u.id)) continue;
1015
- const elapsed = u.completedAt ? Date.now() - u.completedAt : 0;
1016
- const remaining = Math.max(0, AUTO_DISMISS_MS - elapsed);
1017
- const handle = setTimeout(() => {
1018
- timers.delete(u.id);
1019
- onDismissRef.current(u.id);
1020
- }, remaining);
1021
- timers.set(u.id, handle);
1022
- }
1023
- const liveSuccessIds = new Set(
1024
- uploads.filter((u) => u.status === "success").map((u) => u.id)
1025
- );
1026
- for (const [id, handle] of timers) {
1027
- if (!liveSuccessIds.has(id)) {
1028
- clearTimeout(handle);
1029
- timers.delete(id);
1030
- }
1031
- }
1032
- }, [uploads, hovered]);
1033
- useEffect4(() => {
1034
- const timers = timersRef.current;
1035
- return () => {
1036
- timers.forEach((t) => clearTimeout(t));
1037
- timers.clear();
1038
- };
1039
- }, []);
1040
- if (uploads.length === 0) return null;
1041
- const headerLabel = activeCount > 0 ? `Uploading ${activeCount} file${activeCount === 1 ? "" : "s"}\u2026` : errorCount > 0 && successCount === 0 ? `${errorCount} upload${errorCount === 1 ? "" : "s"} failed` : `Uploaded ${successCount} file${successCount === 1 ? "" : "s"}`;
1042
- const completedIds = uploads.filter((u) => u.status === "success" || u.status === "error").map((u) => u.id);
1043
- return /* @__PURE__ */ jsxs4(
1044
- "div",
1045
- {
1046
- className: cn(
1047
- "overflow-hidden rounded-lg border bg-background/95 shadow-lg backdrop-blur",
1048
- className
1049
- ),
1050
- onMouseEnter: () => setHovered(true),
1051
- onMouseLeave: () => setHovered(false),
1052
- "aria-label": "Uploads",
1053
- children: [
1054
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center justify-between gap-2 border-b bg-muted/40 px-3 py-1.5", children: [
1055
- /* @__PURE__ */ jsx5("span", { className: "truncate text-xs font-medium text-foreground", children: headerLabel }),
1056
- completedIds.length > 0 ? /* @__PURE__ */ jsx5(
1057
- "button",
1058
- {
1059
- type: "button",
1060
- onClick: () => {
1061
- for (const id of completedIds) onDismiss(id);
1062
- },
1063
- className: "shrink-0 rounded px-1.5 py-0.5 text-[11px] text-muted-foreground hover:bg-accent hover:text-foreground",
1064
- children: "Clear"
1065
- }
1066
- ) : null
1067
- ] }),
1068
- /* @__PURE__ */ jsx5("ul", { className: "max-h-72 space-y-1 overflow-y-auto p-2", children: uploads.map((u) => {
1069
- const percent = u.fileSize > 0 ? Math.min(100, Math.round(u.bytesUploaded / u.fileSize * 100)) : 0;
1070
- const done = u.status === "success";
1071
- const failed = u.status === "error";
1072
- const canOpen = done && !!u.fileId && !!onOpenFile;
1073
- return /* @__PURE__ */ jsxs4(
1074
- "li",
1075
- {
1076
- className: cn(
1077
- "flex items-center gap-2 rounded-md px-2 py-1.5 text-xs",
1078
- canOpen && "cursor-pointer hover:bg-accent/60"
1079
- ),
1080
- onClick: canOpen ? () => onOpenFile(u.fileId) : void 0,
1081
- children: [
1082
- /* @__PURE__ */ jsx5(FileIcon2, { fileName: u.fileName, size: 18, className: "shrink-0" }),
1083
- /* @__PURE__ */ jsxs4("div", { className: "min-w-0 flex-1", children: [
1084
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center justify-between gap-2", children: [
1085
- /* @__PURE__ */ jsx5("span", { className: "truncate font-medium text-foreground", children: u.fileName }),
1086
- /* @__PURE__ */ jsx5("span", { className: "shrink-0 tabular-nums text-muted-foreground", children: failed ? "Failed" : done ? "Done" : `${percent}%` })
1087
- ] }),
1088
- done ? null : /* @__PURE__ */ jsx5("div", { className: "mt-1 h-1 w-full rounded bg-muted", children: /* @__PURE__ */ jsx5(
1089
- "div",
1090
- {
1091
- className: cn(
1092
- "h-1 rounded transition-all",
1093
- failed ? "bg-destructive" : "bg-primary"
1094
- ),
1095
- style: { width: failed ? "100%" : `${percent}%` }
1096
- }
1097
- ) }),
1098
- failed && u.error ? /* @__PURE__ */ jsx5("p", { className: "mt-0.5 truncate text-[10px] text-destructive", children: u.error }) : !done ? /* @__PURE__ */ jsxs4("p", { className: "mt-0.5 text-[10px] text-muted-foreground", children: [
1099
- formatFileSize(u.bytesUploaded),
1100
- " /",
1101
- " ",
1102
- formatFileSize(u.fileSize)
1103
- ] }) : null
1104
- ] }),
1105
- canOpen ? /* @__PURE__ */ jsxs4("span", { className: "flex shrink-0 items-center gap-1 rounded px-1.5 py-0.5 text-[11px] font-medium text-primary", children: [
1106
- /* @__PURE__ */ jsx5(ExternalLinkIcon, { className: "h-3 w-3", width: 12, height: 12 }),
1107
- "Open"
1108
- ] }) : done ? /* @__PURE__ */ jsx5(
1109
- CheckCircle2Icon,
1110
- {
1111
- className: "h-4 w-4 shrink-0 text-emerald-500",
1112
- width: 16,
1113
- height: 16
1114
- }
1115
- ) : failed ? /* @__PURE__ */ jsx5(
1116
- AlertCircleIcon,
1117
- {
1118
- className: "h-4 w-4 shrink-0 text-destructive",
1119
- width: 16,
1120
- height: 16
1121
- }
1122
- ) : null,
1123
- done || failed ? /* @__PURE__ */ jsx5(
1124
- "button",
1125
- {
1126
- type: "button",
1127
- onClick: (e) => {
1128
- e.stopPropagation();
1129
- onDismiss(u.id);
1130
- },
1131
- "aria-label": "Dismiss",
1132
- className: "flex h-5 w-5 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground",
1133
- children: /* @__PURE__ */ jsx5(XIcon, { className: "h-3 w-3", width: 12, height: 12 })
1134
- }
1135
- ) : null
1136
- ]
1137
- },
1138
- u.id
1139
- );
1140
- }) })
1141
- ]
1142
- }
1143
- );
1144
- }
1145
- var UploadProgressList = memo(UploadProgressListImpl);
1146
-
1147
955
  // src/viewers/generic-viewer.tsx
1148
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
956
+ import { formatFileSize } from "@ai-matrx/kit/format";
957
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1149
958
  function GenericViewer({
1150
959
  fileName,
1151
960
  fileSize,
@@ -1159,7 +968,7 @@ function GenericViewer({
1159
968
  const viewAsTextBusy = generic?.viewAsTextBusy ?? false;
1160
969
  const hasViewAsText = typeof onViewAsText === "function";
1161
970
  const hasDownload = typeof onDownload === "function";
1162
- return /* @__PURE__ */ jsxs5(
971
+ return /* @__PURE__ */ jsxs4(
1163
972
  "div",
1164
973
  {
1165
974
  className: cn(
@@ -1167,14 +976,14 @@ function GenericViewer({
1167
976
  className
1168
977
  ),
1169
978
  children: [
1170
- /* @__PURE__ */ jsx6(FileIcon2, { fileName, size: 48 }),
1171
- /* @__PURE__ */ jsxs5("div", { children: [
1172
- /* @__PURE__ */ jsx6("p", { className: "max-w-md truncate text-sm font-medium", children: fileName }),
1173
- /* @__PURE__ */ jsx6("p", { className: "text-xs text-muted-foreground", children: formatFileSize(fileSize ?? null) })
979
+ /* @__PURE__ */ jsx5(FileIcon2, { fileName, size: 48 }),
980
+ /* @__PURE__ */ jsxs4("div", { children: [
981
+ /* @__PURE__ */ jsx5("p", { className: "max-w-md truncate text-sm font-medium", children: fileName }),
982
+ /* @__PURE__ */ jsx5("p", { className: "text-xs text-muted-foreground", children: formatFileSize(fileSize ?? null) })
1174
983
  ] }),
1175
- /* @__PURE__ */ jsx6("p", { className: "max-w-sm text-sm text-muted-foreground", children: generic?.message ?? (hasViewAsText ? "No built-in previewer for this file type." : "This file type can't be previewed here.") }),
1176
- /* @__PURE__ */ jsxs5("div", { className: "flex flex-wrap items-center justify-center gap-2", children: [
1177
- onViewAsText && viewAsTextPrimary ? /* @__PURE__ */ jsx6(
984
+ /* @__PURE__ */ jsx5("p", { className: "max-w-sm text-sm text-muted-foreground", children: generic?.message ?? (hasViewAsText ? "No built-in previewer for this file type." : "This file type can't be previewed here.") }),
985
+ /* @__PURE__ */ jsxs4("div", { className: "flex flex-wrap items-center justify-center gap-2", children: [
986
+ onViewAsText && viewAsTextPrimary ? /* @__PURE__ */ jsx5(
1178
987
  ViewAsTextButton,
1179
988
  {
1180
989
  onClick: onViewAsText,
@@ -1183,7 +992,7 @@ function GenericViewer({
1183
992
  variant: "primary"
1184
993
  }
1185
994
  ) : null,
1186
- onDownload ? /* @__PURE__ */ jsxs5(
995
+ onDownload ? /* @__PURE__ */ jsxs4(
1187
996
  "button",
1188
997
  {
1189
998
  type: "button",
@@ -1193,12 +1002,12 @@ function GenericViewer({
1193
1002
  hasViewAsText && viewAsTextPrimary ? "border border-input bg-background text-foreground hover:bg-accent hover:text-accent-foreground" : "bg-primary text-primary-foreground hover:bg-primary/90"
1194
1003
  ),
1195
1004
  children: [
1196
- /* @__PURE__ */ jsx6(DownloadIcon, { className: "h-4 w-4" }),
1005
+ /* @__PURE__ */ jsx5(DownloadIcon, { className: "h-4 w-4" }),
1197
1006
  "Download"
1198
1007
  ]
1199
1008
  }
1200
1009
  ) : null,
1201
- onViewAsText && !viewAsTextPrimary ? /* @__PURE__ */ jsx6(
1010
+ onViewAsText && !viewAsTextPrimary ? /* @__PURE__ */ jsx5(
1202
1011
  ViewAsTextButton,
1203
1012
  {
1204
1013
  onClick: onViewAsText,
@@ -1208,7 +1017,7 @@ function GenericViewer({
1208
1017
  }
1209
1018
  ) : null
1210
1019
  ] }),
1211
- !hasDownload && !hasViewAsText ? /* @__PURE__ */ jsx6("p", { className: "max-w-sm text-[11px] text-muted-foreground/70", children: "Download it from the file's actions menu to open it in another application." }) : null
1020
+ !hasDownload && !hasViewAsText ? /* @__PURE__ */ jsx5("p", { className: "max-w-sm text-[11px] text-muted-foreground/70", children: "Download it from the file's actions menu to open it in another application." }) : null
1212
1021
  ]
1213
1022
  }
1214
1023
  );
@@ -1219,7 +1028,7 @@ function ViewAsTextButton({
1219
1028
  busy,
1220
1029
  variant
1221
1030
  }) {
1222
- return /* @__PURE__ */ jsxs5(
1031
+ return /* @__PURE__ */ jsxs4(
1223
1032
  "button",
1224
1033
  {
1225
1034
  type: "button",
@@ -1231,7 +1040,7 @@ function ViewAsTextButton({
1231
1040
  variant === "primary" ? "bg-primary text-primary-foreground hover:bg-primary/90" : "border border-input bg-background text-foreground hover:bg-accent hover:text-accent-foreground"
1232
1041
  ),
1233
1042
  children: [
1234
- busy ? /* @__PURE__ */ jsx6(SpinnerIcon, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx6(FileTextIcon, { className: "h-4 w-4" }),
1043
+ busy ? /* @__PURE__ */ jsx5(SpinnerIcon, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx5(FileTextIcon, { className: "h-4 w-4" }),
1235
1044
  label
1236
1045
  ]
1237
1046
  }
@@ -1239,13 +1048,13 @@ function ViewAsTextButton({
1239
1048
  }
1240
1049
 
1241
1050
  // src/viewers/html-viewer.tsx
1242
- import { useEffect as useEffect5, useState as useState7 } from "react";
1051
+ import { useEffect as useEffect4, useState as useState6 } from "react";
1243
1052
 
1244
1053
  // src/viewers/markup-chrome.tsx
1245
- import { useState as useState6 } from "react";
1246
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1054
+ import { useState as useState5 } from "react";
1055
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1247
1056
  function useMarkupMode(controls) {
1248
- const [localMode, setLocalMode] = useState6("rendered");
1057
+ const [localMode, setLocalMode] = useState5("rendered");
1249
1058
  const controlled = controls?.mode !== void 0;
1250
1059
  return {
1251
1060
  mode: controls?.mode ?? localMode,
@@ -1260,23 +1069,23 @@ function MarkupModeToggle({
1260
1069
  renderedIcon = "image",
1261
1070
  className
1262
1071
  }) {
1263
- return /* @__PURE__ */ jsxs6("div", { className: cn("flex items-center gap-0.5", className), children: [
1264
- /* @__PURE__ */ jsx7(
1072
+ return /* @__PURE__ */ jsxs5("div", { className: cn("flex items-center gap-0.5", className), children: [
1073
+ /* @__PURE__ */ jsx6(
1265
1074
  ToggleButton,
1266
1075
  {
1267
1076
  active: mode === "rendered",
1268
1077
  onClick: () => onChange("rendered"),
1269
1078
  label: renderedLabel,
1270
- icon: renderedIcon === "globe" ? /* @__PURE__ */ jsx7(GlobeIcon, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx7(ImageIcon, { className: "h-3.5 w-3.5" })
1079
+ icon: renderedIcon === "globe" ? /* @__PURE__ */ jsx6(GlobeIcon, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx6(ImageIcon, { className: "h-3.5 w-3.5" })
1271
1080
  }
1272
1081
  ),
1273
- /* @__PURE__ */ jsx7(
1082
+ /* @__PURE__ */ jsx6(
1274
1083
  ToggleButton,
1275
1084
  {
1276
1085
  active: mode === "source",
1277
1086
  onClick: () => onChange("source"),
1278
1087
  label: "Source",
1279
- icon: /* @__PURE__ */ jsx7(CodeIcon, { className: "h-3.5 w-3.5" })
1088
+ icon: /* @__PURE__ */ jsx6(CodeIcon, { className: "h-3.5 w-3.5" })
1280
1089
  }
1281
1090
  )
1282
1091
  ] });
@@ -1287,7 +1096,7 @@ function ToggleButton({
1287
1096
  icon,
1288
1097
  label
1289
1098
  }) {
1290
- return /* @__PURE__ */ jsxs6(
1099
+ return /* @__PURE__ */ jsxs5(
1291
1100
  "button",
1292
1101
  {
1293
1102
  type: "button",
@@ -1299,14 +1108,14 @@ function ToggleButton({
1299
1108
  ),
1300
1109
  children: [
1301
1110
  icon,
1302
- /* @__PURE__ */ jsx7("span", { children: label })
1111
+ /* @__PURE__ */ jsx6("span", { children: label })
1303
1112
  ]
1304
1113
  }
1305
1114
  );
1306
1115
  }
1307
1116
 
1308
1117
  // src/viewers/html-viewer.tsx
1309
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1118
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1310
1119
  var VIEWPORT_WIDTH = {
1311
1120
  mobile: 390,
1312
1121
  tablet: 768,
@@ -1315,10 +1124,10 @@ var VIEWPORT_WIDTH = {
1315
1124
  function HtmlViewer(props) {
1316
1125
  const { className, fileName, markupControls } = props;
1317
1126
  const { mode, setMode, controlled } = useMarkupMode(markupControls);
1318
- return /* @__PURE__ */ jsxs7("div", { className: cn("flex h-full w-full flex-col", className), children: [
1319
- controlled ? null : /* @__PURE__ */ jsxs7("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-border/60 bg-background px-3 py-1.5 text-xs", children: [
1320
- /* @__PURE__ */ jsx8("span", { className: "truncate font-medium text-foreground", children: fileName }),
1321
- /* @__PURE__ */ jsx8(
1127
+ return /* @__PURE__ */ jsxs6("div", { className: cn("flex h-full w-full flex-col", className), children: [
1128
+ controlled ? null : /* @__PURE__ */ jsxs6("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-border/60 bg-background px-3 py-1.5 text-xs", children: [
1129
+ /* @__PURE__ */ jsx7("span", { className: "truncate font-medium text-foreground", children: fileName }),
1130
+ /* @__PURE__ */ jsx7(
1322
1131
  MarkupModeToggle,
1323
1132
  {
1324
1133
  mode,
@@ -1328,19 +1137,19 @@ function HtmlViewer(props) {
1328
1137
  }
1329
1138
  )
1330
1139
  ] }),
1331
- /* @__PURE__ */ jsx8("div", { className: "relative min-h-0 flex-1", children: mode === "rendered" ? /* @__PURE__ */ jsx8(HtmlRenderedView, { ...props }) : /* @__PURE__ */ jsx8(HtmlSourceView, { ...props }) })
1140
+ /* @__PURE__ */ jsx7("div", { className: "relative min-h-0 flex-1", children: mode === "rendered" ? /* @__PURE__ */ jsx7(HtmlRenderedView, { ...props }) : /* @__PURE__ */ jsx7(HtmlSourceView, { ...props }) })
1332
1141
  ] });
1333
1142
  }
1334
1143
  function HtmlRenderedView({ source, fileName, markupControls }) {
1335
1144
  const { url, unavailable } = useViewerDisplayUrl(source);
1336
1145
  const viewport = markupControls?.viewport ?? "auto";
1337
1146
  const reloadKey = markupControls?.reloadKey ?? 0;
1338
- const [errored, setErrored] = useState7(false);
1339
- useEffect5(() => {
1147
+ const [errored, setErrored] = useState6(false);
1148
+ useEffect4(() => {
1340
1149
  setErrored(false);
1341
1150
  }, [reloadKey, url]);
1342
1151
  if (unavailable) {
1343
- return /* @__PURE__ */ jsx8(
1152
+ return /* @__PURE__ */ jsx7(
1344
1153
  ViewerError,
1345
1154
  {
1346
1155
  title: "This page isn't available",
@@ -1348,18 +1157,18 @@ function HtmlRenderedView({ source, fileName, markupControls }) {
1348
1157
  }
1349
1158
  );
1350
1159
  }
1351
- if (!url) return /* @__PURE__ */ jsx8(ViewerSkeleton, {});
1352
- if (errored) return /* @__PURE__ */ jsx8(ViewerError, { title: "Preview unavailable" });
1160
+ if (!url) return /* @__PURE__ */ jsx7(ViewerSkeleton, {});
1161
+ if (errored) return /* @__PURE__ */ jsx7(ViewerError, { title: "Preview unavailable" });
1353
1162
  const constrained = viewport !== "auto";
1354
1163
  const width = constrained ? VIEWPORT_WIDTH[viewport] : void 0;
1355
- return /* @__PURE__ */ jsx8(
1164
+ return /* @__PURE__ */ jsx7(
1356
1165
  "div",
1357
1166
  {
1358
1167
  className: cn(
1359
1168
  "h-full w-full overflow-auto bg-muted/10",
1360
1169
  constrained && "flex items-start justify-center"
1361
1170
  ),
1362
- children: /* @__PURE__ */ jsx8(
1171
+ children: /* @__PURE__ */ jsx7(
1363
1172
  "div",
1364
1173
  {
1365
1174
  className: cn(
@@ -1367,7 +1176,7 @@ function HtmlRenderedView({ source, fileName, markupControls }) {
1367
1176
  constrained ? "my-4 overflow-hidden rounded-md border border-border/60 shadow-lg" : "w-full"
1368
1177
  ),
1369
1178
  style: constrained ? { width } : void 0,
1370
- children: /* @__PURE__ */ jsx8(
1179
+ children: /* @__PURE__ */ jsx7(
1371
1180
  "iframe",
1372
1181
  {
1373
1182
  src: url,
@@ -1386,13 +1195,13 @@ function HtmlRenderedView({ source, fileName, markupControls }) {
1386
1195
  }
1387
1196
  function HtmlSourceView({ source, maxBytes = 1024 * 1024 }) {
1388
1197
  const { text, error, loading } = useViewerText(source, maxBytes);
1389
- if (error) return /* @__PURE__ */ jsx8(ViewerError, { title: "Couldn't load source", message: error });
1390
- if (loading || text === null) return /* @__PURE__ */ jsx8(ViewerSkeleton, {});
1391
- return /* @__PURE__ */ jsx8("pre", { className: "h-full w-full overflow-auto bg-muted/10 p-4 font-mono text-xs leading-relaxed break-all whitespace-pre-wrap", children: text });
1198
+ if (error) return /* @__PURE__ */ jsx7(ViewerError, { title: "Couldn't load source", message: error });
1199
+ if (loading || text === null) return /* @__PURE__ */ jsx7(ViewerSkeleton, {});
1200
+ return /* @__PURE__ */ jsx7("pre", { className: "h-full w-full overflow-auto bg-muted/10 p-4 font-mono text-xs leading-relaxed break-all whitespace-pre-wrap", children: text });
1392
1201
  }
1393
1202
 
1394
1203
  // src/viewers/svg-viewer.tsx
1395
- import { useEffect as useEffect6, useState as useState8 } from "react";
1204
+ import { useEffect as useEffect5, useState as useState7 } from "react";
1396
1205
 
1397
1206
  // src/viewers/transparency-grid.ts
1398
1207
  var TRANSPARENCY_GRID_STYLE = {
@@ -1402,11 +1211,11 @@ var TRANSPARENCY_GRID_STYLE = {
1402
1211
  };
1403
1212
 
1404
1213
  // src/viewers/svg-viewer.tsx
1405
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1214
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1406
1215
  function SvgViewer(props) {
1407
1216
  const { className, markupControls } = props;
1408
1217
  const { mode, setMode, controlled } = useMarkupMode(markupControls);
1409
- return /* @__PURE__ */ jsxs8(
1218
+ return /* @__PURE__ */ jsxs7(
1410
1219
  "div",
1411
1220
  {
1412
1221
  className: cn(
@@ -1414,7 +1223,7 @@ function SvgViewer(props) {
1414
1223
  className
1415
1224
  ),
1416
1225
  children: [
1417
- controlled ? null : /* @__PURE__ */ jsx9(
1226
+ controlled ? null : /* @__PURE__ */ jsx8(
1418
1227
  MarkupModeToggle,
1419
1228
  {
1420
1229
  mode,
@@ -1422,15 +1231,15 @@ function SvgViewer(props) {
1422
1231
  className: "absolute top-3 right-3 z-10 rounded-md border border-border bg-background/95 p-0.5 shadow-sm backdrop-blur-sm"
1423
1232
  }
1424
1233
  ),
1425
- mode === "rendered" ? /* @__PURE__ */ jsx9(SvgRenderedView, { ...props }) : /* @__PURE__ */ jsx9(SvgSourceView, { ...props })
1234
+ mode === "rendered" ? /* @__PURE__ */ jsx8(SvgRenderedView, { ...props }) : /* @__PURE__ */ jsx8(SvgSourceView, { ...props })
1426
1235
  ]
1427
1236
  }
1428
1237
  );
1429
1238
  }
1430
1239
  function SvgRenderedView({ source, fileName }) {
1431
1240
  const fromClient = useMediaBlob(source.kind === "ref" ? source.ref : null);
1432
- const [normalizedUrl, setNormalizedUrl] = useState8(null);
1433
- useEffect6(() => {
1241
+ const [normalizedUrl, setNormalizedUrl] = useState7(null);
1242
+ useEffect5(() => {
1434
1243
  const blob = fromClient.blob;
1435
1244
  if (!blob || blob.type === "image/svg+xml") {
1436
1245
  setNormalizedUrl(null);
@@ -1445,7 +1254,7 @@ function SvgRenderedView({ source, fileName }) {
1445
1254
  const loading = source.kind === "ref" && fromClient.loading;
1446
1255
  const error = source.kind === "ref" ? fromClient.error : null;
1447
1256
  if (error) {
1448
- return /* @__PURE__ */ jsx9(
1257
+ return /* @__PURE__ */ jsx8(
1449
1258
  ViewerError,
1450
1259
  {
1451
1260
  title: "SVG could not be rendered",
@@ -1454,13 +1263,13 @@ function SvgRenderedView({ source, fileName }) {
1454
1263
  }
1455
1264
  );
1456
1265
  }
1457
- if (loading || !url) return /* @__PURE__ */ jsx9(ViewerSkeleton, { className: "flex-1" });
1458
- return /* @__PURE__ */ jsx9(
1266
+ if (loading || !url) return /* @__PURE__ */ jsx8(ViewerSkeleton, { className: "flex-1" });
1267
+ return /* @__PURE__ */ jsx8(
1459
1268
  "div",
1460
1269
  {
1461
1270
  className: "flex flex-1 items-center justify-center overflow-auto p-4",
1462
1271
  style: TRANSPARENCY_GRID_STYLE,
1463
- children: /* @__PURE__ */ jsx9(
1272
+ children: /* @__PURE__ */ jsx8(
1464
1273
  "img",
1465
1274
  {
1466
1275
  src: url,
@@ -1473,40 +1282,40 @@ function SvgRenderedView({ source, fileName }) {
1473
1282
  }
1474
1283
  function SvgSourceView({ source, maxBytes = 1024 * 1024 }) {
1475
1284
  const { text, error, loading } = useViewerText(source, maxBytes);
1476
- if (error) return /* @__PURE__ */ jsx9(ViewerError, { title: "Could not load source", message: error });
1477
- if (loading || text === null) return /* @__PURE__ */ jsx9(ViewerSkeleton, { className: "flex-1" });
1478
- return /* @__PURE__ */ jsx9("pre", { className: "m-0 flex-1 overflow-auto bg-muted/20 px-4 py-3 font-mono text-xs leading-relaxed break-words whitespace-pre-wrap text-foreground", children: text });
1285
+ if (error) return /* @__PURE__ */ jsx8(ViewerError, { title: "Could not load source", message: error });
1286
+ if (loading || text === null) return /* @__PURE__ */ jsx8(ViewerSkeleton, { className: "flex-1" });
1287
+ return /* @__PURE__ */ jsx8("pre", { className: "m-0 flex-1 overflow-auto bg-muted/20 px-4 py-3 font-mono text-xs leading-relaxed break-words whitespace-pre-wrap text-foreground", children: text });
1479
1288
  }
1480
1289
 
1481
1290
  // src/viewers/text-viewer.tsx
1482
- import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1291
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1483
1292
  function TextViewer({
1484
1293
  source,
1485
1294
  className,
1486
1295
  maxBytes = 1024 * 1024
1487
1296
  }) {
1488
1297
  const { text, error, loading, truncated } = useViewerText(source, maxBytes);
1489
- if (error) return /* @__PURE__ */ jsx10(ViewerError, { message: error, className });
1298
+ if (error) return /* @__PURE__ */ jsx9(ViewerError, { message: error, className });
1490
1299
  if (loading || text === null) {
1491
- return /* @__PURE__ */ jsx10(ViewerSkeleton, { tone: "plain", className });
1300
+ return /* @__PURE__ */ jsx9(ViewerSkeleton, { tone: "plain", className });
1492
1301
  }
1493
- return /* @__PURE__ */ jsxs9(
1302
+ return /* @__PURE__ */ jsxs8(
1494
1303
  "div",
1495
1304
  {
1496
1305
  className: cn("flex h-full w-full flex-col overflow-hidden", className),
1497
1306
  children: [
1498
- /* @__PURE__ */ jsxs9(ViewerToolbar, { children: [
1499
- /* @__PURE__ */ jsx10("span", { className: "text-muted-foreground", children: truncated ? `Preview ${truncationNote(maxBytes)}.` : `${text.length.toLocaleString()} characters` }),
1500
- /* @__PURE__ */ jsx10(ViewerCopyButton, { text })
1307
+ /* @__PURE__ */ jsxs8(ViewerToolbar, { children: [
1308
+ /* @__PURE__ */ jsx9("span", { className: "text-muted-foreground", children: truncated ? `Preview ${truncationNote(maxBytes)}.` : `${text.length.toLocaleString()} characters` }),
1309
+ /* @__PURE__ */ jsx9(ViewerCopyButton, { text })
1501
1310
  ] }),
1502
- /* @__PURE__ */ jsx10("pre", { className: "flex-1 overflow-auto bg-background p-3 font-mono text-xs leading-5 break-words whitespace-pre-wrap", children: text })
1311
+ /* @__PURE__ */ jsx9("pre", { className: "flex-1 overflow-auto bg-background p-3 font-mono text-xs leading-5 break-words whitespace-pre-wrap", children: text })
1503
1312
  ]
1504
1313
  }
1505
1314
  );
1506
1315
  }
1507
1316
 
1508
1317
  // src/viewers/unavailable-viewer.tsx
1509
- import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
1318
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1510
1319
  var ENGINE_FOR_KIND = {
1511
1320
  pdf: "a PDF engine (e.g. PDF.js / react-pdf)",
1512
1321
  markdown: "a Markdown renderer",
@@ -1523,22 +1332,22 @@ function MediaViewerUnavailable({
1523
1332
  }) {
1524
1333
  const engine = ENGINE_FOR_KIND[kind] ?? `a "${kind}" viewer`;
1525
1334
  const generic = props.generic;
1526
- return /* @__PURE__ */ jsxs10("div", { className: cn("flex h-full w-full flex-col", props.className), children: [
1527
- /* @__PURE__ */ jsxs10("div", { className: "shrink-0 border-b border-amber-500/30 bg-amber-500/10 px-3 py-2 text-center text-xs text-amber-700 dark:text-amber-300", children: [
1335
+ return /* @__PURE__ */ jsxs9("div", { className: cn("flex h-full w-full flex-col", props.className), children: [
1336
+ /* @__PURE__ */ jsxs9("div", { className: "shrink-0 border-b border-amber-500/30 bg-amber-500/10 px-3 py-2 text-center text-xs text-amber-700 dark:text-amber-300", children: [
1528
1337
  "No ",
1529
1338
  kind,
1530
1339
  " viewer is registered in this app, so this file can't be displayed here. An app developer registers ",
1531
1340
  engine,
1532
1341
  " with",
1533
1342
  " ",
1534
- /* @__PURE__ */ jsxs10("code", { className: "font-mono", children: [
1343
+ /* @__PURE__ */ jsxs9("code", { className: "font-mono", children: [
1535
1344
  'registerMediaViewer("',
1536
1345
  kind,
1537
1346
  '", \u2026)'
1538
1347
  ] }),
1539
1348
  "."
1540
1349
  ] }),
1541
- /* @__PURE__ */ jsx11("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx11(
1350
+ /* @__PURE__ */ jsx10("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx10(
1542
1351
  GenericViewer,
1543
1352
  {
1544
1353
  ...props,
@@ -1606,7 +1415,7 @@ function getPreviewKind(fileName, mimeType) {
1606
1415
  }
1607
1416
 
1608
1417
  // src/viewers/media-file-viewer.tsx
1609
- import { jsx as jsx12 } from "react/jsx-runtime";
1418
+ import { jsx as jsx11 } from "react/jsx-runtime";
1610
1419
  var BUILT_IN = {
1611
1420
  text: TextViewer,
1612
1421
  code: CodeViewer,
@@ -1621,7 +1430,7 @@ function MediaFileViewer({
1621
1430
  const kind = previewKind ?? getPreviewKind(props.fileName, props.mimeType ?? null);
1622
1431
  const viewer = getMediaViewer(kind) ?? BUILT_IN[kind];
1623
1432
  if (viewer) return createElement3(viewer, props);
1624
- return /* @__PURE__ */ jsx12(MediaViewerUnavailable, { ...props, kind });
1433
+ return /* @__PURE__ */ jsx11(MediaViewerUnavailable, { ...props, kind });
1625
1434
  }
1626
1435
  export {
1627
1436
  CodeViewer,