@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/CHANGELOG.md +40 -0
- package/dist/core.cjs.map +1 -1
- package/dist/core.js.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +167 -93
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -11
- package/dist/react.d.ts +1 -11
- package/dist/react.js +163 -89
- package/dist/react.js.map +1 -1
- package/dist/viewers.cjs +75 -266
- package/dist/viewers.cjs.map +1 -1
- package/dist/viewers.js +73 -264
- package/dist/viewers.js.map +1 -1
- package/package.json +3 -2
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 {
|
|
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__ */
|
|
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__ */
|
|
1171
|
-
/* @__PURE__ */
|
|
1172
|
-
/* @__PURE__ */
|
|
1173
|
-
/* @__PURE__ */
|
|
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__ */
|
|
1176
|
-
/* @__PURE__ */
|
|
1177
|
-
onViewAsText && viewAsTextPrimary ? /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1005
|
+
/* @__PURE__ */ jsx5(DownloadIcon, { className: "h-4 w-4" }),
|
|
1197
1006
|
"Download"
|
|
1198
1007
|
]
|
|
1199
1008
|
}
|
|
1200
1009
|
) : null,
|
|
1201
|
-
onViewAsText && !viewAsTextPrimary ? /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
1051
|
+
import { useEffect as useEffect4, useState as useState6 } from "react";
|
|
1243
1052
|
|
|
1244
1053
|
// src/viewers/markup-chrome.tsx
|
|
1245
|
-
import { useState as
|
|
1246
|
-
import { jsx as
|
|
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] =
|
|
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__ */
|
|
1264
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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__ */
|
|
1319
|
-
controlled ? null : /* @__PURE__ */
|
|
1320
|
-
/* @__PURE__ */
|
|
1321
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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] =
|
|
1339
|
-
|
|
1147
|
+
const [errored, setErrored] = useState6(false);
|
|
1148
|
+
useEffect4(() => {
|
|
1340
1149
|
setErrored(false);
|
|
1341
1150
|
}, [reloadKey, url]);
|
|
1342
1151
|
if (unavailable) {
|
|
1343
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
1352
|
-
if (errored) return /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
1390
|
-
if (loading || text === null) return /* @__PURE__ */
|
|
1391
|
-
return /* @__PURE__ */
|
|
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
|
|
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
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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] =
|
|
1433
|
-
|
|
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__ */
|
|
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__ */
|
|
1458
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
1477
|
-
if (loading || text === null) return /* @__PURE__ */
|
|
1478
|
-
return /* @__PURE__ */
|
|
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
|
|
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__ */
|
|
1298
|
+
if (error) return /* @__PURE__ */ jsx9(ViewerError, { message: error, className });
|
|
1490
1299
|
if (loading || text === null) {
|
|
1491
|
-
return /* @__PURE__ */
|
|
1300
|
+
return /* @__PURE__ */ jsx9(ViewerSkeleton, { tone: "plain", className });
|
|
1492
1301
|
}
|
|
1493
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
1499
|
-
/* @__PURE__ */
|
|
1500
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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
|
|
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__ */
|
|
1527
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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__ */
|
|
1433
|
+
return /* @__PURE__ */ jsx11(MediaViewerUnavailable, { ...props, kind });
|
|
1625
1434
|
}
|
|
1626
1435
|
export {
|
|
1627
1436
|
CodeViewer,
|