@epicbagel/saas-kit 1.2.3 → 1.4.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 +115 -0
- package/dist/chunk-2TKLS73N.js +121 -0
- package/dist/chunk-4UUTKR3V.cjs +53 -0
- package/dist/chunk-BTHYGHOH.cjs +143 -0
- package/dist/chunk-D5EHW3O2.cjs +52 -0
- package/dist/chunk-F3DAFAMD.js +271 -0
- package/dist/chunk-GRY77463.cjs +121 -0
- package/dist/chunk-HAP6USTP.cjs +46 -0
- package/dist/chunk-HAQOT2CD.js +46 -0
- package/dist/chunk-HHV4G77I.js +55 -0
- package/dist/{chunk-KYQPX754.js → chunk-HRLP4BHJ.js} +7 -7
- package/dist/{chunk-N6V3DDKU.cjs → chunk-IH3COANJ.cjs} +7 -7
- package/dist/chunk-JTI4244T.js +143 -0
- package/dist/chunk-QEJ2STIV.js +53 -0
- package/dist/chunk-TWCJMFST.js +260 -0
- package/dist/chunk-U3YFP6ZV.cjs +273 -0
- package/dist/chunk-VLXPLKFR.cjs +55 -0
- package/dist/chunk-X3PRMR5G.js +52 -0
- package/dist/chunk-ZJFYOXSM.cjs +260 -0
- package/dist/lib/neutral-theme.cjs +39 -236
- package/dist/lib/neutral-theme.d.cts +44 -2
- package/dist/lib/neutral-theme.d.ts +44 -2
- package/dist/lib/neutral-theme.js +23 -219
- package/dist/primitives/activity-feed.cjs +3 -3
- package/dist/primitives/activity-feed.js +4 -4
- package/dist/primitives/board-view.cjs +6 -6
- package/dist/primitives/board-view.js +5 -5
- package/dist/primitives/chat.cjs +14 -14
- package/dist/primitives/chat.js +12 -12
- package/dist/primitives/code-block.cjs +5 -50
- package/dist/primitives/code-block.js +5 -50
- package/dist/primitives/connection.cjs +6 -6
- package/dist/primitives/connection.js +7 -7
- package/dist/primitives/copy-button.cjs +3 -3
- package/dist/primitives/copy-button.js +2 -2
- package/dist/primitives/document-preview.cjs +54 -0
- package/dist/primitives/document-preview.d.cts +30 -0
- package/dist/primitives/document-preview.d.ts +30 -0
- package/dist/primitives/document-preview.js +54 -0
- package/dist/primitives/editable-list.cjs +1 -1
- package/dist/primitives/editable-list.js +1 -1
- package/dist/primitives/field.cjs +12 -239
- package/dist/primitives/field.js +16 -243
- package/dist/primitives/file-dropzone.cjs +3 -3
- package/dist/primitives/file-dropzone.js +2 -2
- package/dist/primitives/file-preview-internals.cjs +20 -0
- package/dist/primitives/file-preview-internals.d.cts +44 -0
- package/dist/primitives/file-preview-internals.d.ts +44 -0
- package/dist/primitives/file-preview-internals.js +20 -0
- package/dist/primitives/file-preview.cjs +327 -0
- package/dist/primitives/file-preview.d.cts +92 -0
- package/dist/primitives/file-preview.d.ts +92 -0
- package/dist/primitives/file-preview.js +327 -0
- package/dist/primitives/filter-bar.cjs +4 -4
- package/dist/primitives/filter-bar.js +3 -3
- package/dist/primitives/image.cjs +4 -48
- package/dist/primitives/image.js +3 -47
- package/dist/primitives/radio-group.cjs +4 -39
- package/dist/primitives/radio-group.js +4 -39
- package/dist/primitives/resource-list.cjs +6 -6
- package/dist/primitives/resource-list.js +5 -5
- package/dist/primitives/responsive-dialog.cjs +26 -142
- package/dist/primitives/responsive-dialog.js +13 -129
- package/dist/primitives/section.cjs +2 -2
- package/dist/primitives/section.js +3 -3
- package/dist/primitives/switch-field.cjs +2 -2
- package/dist/primitives/switch-field.js +3 -3
- package/dist/primitives/theme-selector.cjs +188 -0
- package/dist/primitives/theme-selector.d.cts +78 -0
- package/dist/primitives/theme-selector.d.ts +78 -0
- package/dist/primitives/theme-selector.js +188 -0
- package/dist/primitives/toggle-group.cjs +5 -45
- package/dist/primitives/toggle-group.js +5 -45
- package/package.json +31 -1
- package/dist/{chunk-6OTAGP2I.cjs → chunk-KADJ56AH.cjs} +2 -2
- package/dist/{chunk-EHKMVJ6O.js → chunk-M7FYGAGO.js} +3 -3
- package/dist/{chunk-PVZ4JGDU.js → chunk-MLHNYRFX.js} +6 -6
- package/dist/{chunk-PWOQMTPX.js → chunk-NW3OWKBN.js} +3 -3
- package/dist/{chunk-CYH63OCL.cjs → chunk-SGW4FWBX.cjs} +6 -6
- package/dist/{chunk-ENJNZ323.cjs → chunk-VKIGJNJR.cjs} +2 -2
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use client";
|
|
3
|
+
import {
|
|
4
|
+
PreviewDialog,
|
|
5
|
+
PreviewLoading,
|
|
6
|
+
PreviewNotice,
|
|
7
|
+
PreviewStage
|
|
8
|
+
} from "../chunk-2TKLS73N.js";
|
|
9
|
+
import "../chunk-JTI4244T.js";
|
|
10
|
+
import "../chunk-4HWCNRK4.js";
|
|
11
|
+
import "../chunk-3QT5VYZ3.js";
|
|
12
|
+
import "../chunk-KN4RPX35.js";
|
|
13
|
+
import "../chunk-HQRWRRZJ.js";
|
|
14
|
+
import "../chunk-G6SRSWXB.js";
|
|
15
|
+
export {
|
|
16
|
+
PreviewDialog,
|
|
17
|
+
PreviewLoading,
|
|
18
|
+
PreviewNotice,
|
|
19
|
+
PreviewStage
|
|
20
|
+
};
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }"use client";
|
|
2
|
+
"use client";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
var _chunk4UUTKR3Vcjs = require('../chunk-4UUTKR3V.cjs');
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
var _chunkGRY77463cjs = require('../chunk-GRY77463.cjs');
|
|
12
|
+
require('../chunk-BTHYGHOH.cjs');
|
|
13
|
+
require('../chunk-2BHI5ZWJ.cjs');
|
|
14
|
+
require('../chunk-WDXEJDMO.cjs');
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
var _chunkVLXPLKFRcjs = require('../chunk-VLXPLKFR.cjs');
|
|
18
|
+
require('../chunk-VKIGJNJR.cjs');
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
var _chunkKENBU3NVcjs = require('../chunk-KENBU3NV.cjs');
|
|
22
|
+
require('../chunk-ELPV44S6.cjs');
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
var _chunk373W6VADcjs = require('../chunk-373W6VAD.cjs');
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
var _chunkT2ZFSPE4cjs = require('../chunk-T2ZFSPE4.cjs');
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
var _chunkL4DH72UFcjs = require('../chunk-L4DH72UF.cjs');
|
|
32
|
+
require('../chunk-4LXN6GLZ.cjs');
|
|
33
|
+
require('../chunk-KWLSBTB2.cjs');
|
|
34
|
+
|
|
35
|
+
// src/primitives/file-preview.tsx
|
|
36
|
+
var _lucidereact = require('lucide-react');
|
|
37
|
+
var _react = require('react');
|
|
38
|
+
var _jsxruntime = require('react/jsx-runtime');
|
|
39
|
+
var UNTYPED = /* @__PURE__ */ new Set([
|
|
40
|
+
"",
|
|
41
|
+
"application/octet-stream",
|
|
42
|
+
"binary/octet-stream",
|
|
43
|
+
"application/binary",
|
|
44
|
+
"application/unknown",
|
|
45
|
+
"application/x-download",
|
|
46
|
+
"application/force-download"
|
|
47
|
+
]);
|
|
48
|
+
var TYPE_KINDS = {
|
|
49
|
+
"application/pdf": "pdf",
|
|
50
|
+
"application/x-pdf": "pdf",
|
|
51
|
+
"image/apng": "image",
|
|
52
|
+
"image/avif": "image",
|
|
53
|
+
"image/bmp": "image",
|
|
54
|
+
"image/gif": "image",
|
|
55
|
+
"image/jpeg": "image",
|
|
56
|
+
"image/jpg": "image",
|
|
57
|
+
"image/pjpeg": "image",
|
|
58
|
+
"image/png": "image",
|
|
59
|
+
"image/svg+xml": "image",
|
|
60
|
+
"image/vnd.microsoft.icon": "image",
|
|
61
|
+
"image/webp": "image",
|
|
62
|
+
"image/x-icon": "image",
|
|
63
|
+
"text/markdown": "markdown",
|
|
64
|
+
"text/x-markdown": "markdown",
|
|
65
|
+
// RTF is text/*, but its source is control words, not the document.
|
|
66
|
+
"text/rtf": "none",
|
|
67
|
+
"application/ecmascript": "text",
|
|
68
|
+
"application/graphql": "text",
|
|
69
|
+
"application/javascript": "text",
|
|
70
|
+
"application/json": "text",
|
|
71
|
+
"application/sql": "text",
|
|
72
|
+
"application/toml": "text",
|
|
73
|
+
"application/typescript": "text",
|
|
74
|
+
"application/x-httpd-php": "text",
|
|
75
|
+
"application/x-javascript": "text",
|
|
76
|
+
"application/x-ndjson": "text",
|
|
77
|
+
"application/x-sh": "text",
|
|
78
|
+
"application/x-typescript": "text",
|
|
79
|
+
"application/x-yaml": "text",
|
|
80
|
+
"application/xml": "text",
|
|
81
|
+
"application/yaml": "text",
|
|
82
|
+
"audio/aac": "audio",
|
|
83
|
+
"audio/flac": "audio",
|
|
84
|
+
"audio/mp3": "audio",
|
|
85
|
+
"audio/mp4": "audio",
|
|
86
|
+
"audio/mpeg": "audio",
|
|
87
|
+
"audio/ogg": "audio",
|
|
88
|
+
"audio/opus": "audio",
|
|
89
|
+
"audio/wav": "audio",
|
|
90
|
+
"audio/wave": "audio",
|
|
91
|
+
"audio/webm": "audio",
|
|
92
|
+
"audio/x-flac": "audio",
|
|
93
|
+
"audio/x-m4a": "audio",
|
|
94
|
+
"audio/x-wav": "audio",
|
|
95
|
+
"video/mp4": "video",
|
|
96
|
+
"video/ogg": "video",
|
|
97
|
+
"video/quicktime": "video",
|
|
98
|
+
"video/webm": "video",
|
|
99
|
+
"video/x-m4v": "video"
|
|
100
|
+
};
|
|
101
|
+
var EXTENSION_KINDS = new Map(
|
|
102
|
+
[
|
|
103
|
+
["pdf", "pdf"],
|
|
104
|
+
["image", "apng avif bmp gif ico jfif jpeg jpg png svg webp"],
|
|
105
|
+
["markdown", "markdown md mdown mkd"],
|
|
106
|
+
["audio", "aac flac m4a mp3 oga ogg opus wav weba"],
|
|
107
|
+
["video", "m4v mov mp4 ogv webm"],
|
|
108
|
+
[
|
|
109
|
+
"text",
|
|
110
|
+
"adoc bash bat c cc cfg cjs clj conf cpp cs css csv cts cxx dart diff env erl ex exs fish go gql graphql h hpp hs htm html ini java js json jsonc jsonl jsx kt kts less log lua mjs mts ndjson patch php pl properties ps1 py r rb rs rst sass scala scss sh sql srt svelte swift tex text toml ts tsv tsx txt vtt vue xml yaml yml zsh"
|
|
111
|
+
]
|
|
112
|
+
].flatMap(
|
|
113
|
+
([kind, extensions]) => extensions.split(" ").map((extension) => [extension, kind])
|
|
114
|
+
)
|
|
115
|
+
);
|
|
116
|
+
function kindOfName(name) {
|
|
117
|
+
const base = _nullishCoalesce((_nullishCoalesce(name, () => ( ""))).trim().toLowerCase().split(/[\\/]/).pop(), () => ( ""));
|
|
118
|
+
const dot = base.lastIndexOf(".");
|
|
119
|
+
return dot >= 0 ? EXTENSION_KINDS.get(base.slice(dot + 1)) : void 0;
|
|
120
|
+
}
|
|
121
|
+
function kindOfType(type) {
|
|
122
|
+
const known = TYPE_KINDS[type];
|
|
123
|
+
if (known) return known;
|
|
124
|
+
if (type.startsWith("text/")) return "text";
|
|
125
|
+
if (/^application\/[\w.-]+\+(?:json|xml)$/.test(type)) return "text";
|
|
126
|
+
return void 0;
|
|
127
|
+
}
|
|
128
|
+
function filePreviewKind({ name, mediaType }) {
|
|
129
|
+
const type = (_nullishCoalesce(mediaType, () => ( ""))).split(";", 1)[0].trim().toLowerCase();
|
|
130
|
+
const byName = kindOfName(name);
|
|
131
|
+
if (UNTYPED.has(type)) return _nullishCoalesce(byName, () => ( "none"));
|
|
132
|
+
const byType = kindOfType(type);
|
|
133
|
+
if (byType === "text" && byName === "markdown") return "markdown";
|
|
134
|
+
if (byType) return byType;
|
|
135
|
+
return byName === "text" || byName === "markdown" ? byName : "none";
|
|
136
|
+
}
|
|
137
|
+
function FilePreview({
|
|
138
|
+
open,
|
|
139
|
+
onOpenChange,
|
|
140
|
+
title,
|
|
141
|
+
mediaType,
|
|
142
|
+
kind,
|
|
143
|
+
file,
|
|
144
|
+
src,
|
|
145
|
+
loading = false,
|
|
146
|
+
error,
|
|
147
|
+
onDownload,
|
|
148
|
+
downloading = false,
|
|
149
|
+
downloadLabel = "Download file",
|
|
150
|
+
fallback,
|
|
151
|
+
markdownComponents,
|
|
152
|
+
loadingLabel = "Loading preview\u2026",
|
|
153
|
+
unavailableLabel = "No preview for this file.",
|
|
154
|
+
failedLabel = "This file couldn't be shown here.",
|
|
155
|
+
truncatedLabel = "Showing the start of this file. Download it to see the rest."
|
|
156
|
+
}) {
|
|
157
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
158
|
+
_chunkGRY77463cjs.PreviewDialog,
|
|
159
|
+
{
|
|
160
|
+
open,
|
|
161
|
+
onOpenChange,
|
|
162
|
+
title,
|
|
163
|
+
onDownload,
|
|
164
|
+
downloading,
|
|
165
|
+
downloadLabel,
|
|
166
|
+
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
167
|
+
FilePreviewBody,
|
|
168
|
+
{
|
|
169
|
+
kind: _nullishCoalesce(kind, () => ( filePreviewKind({ name: title, mediaType: _nullishCoalesce(mediaType, () => ( _optionalChain([file, 'optionalAccess', _ => _.type]))) }))),
|
|
170
|
+
title,
|
|
171
|
+
file: _nullishCoalesce(file, () => ( null)),
|
|
172
|
+
src: _nullishCoalesce(src, () => ( null)),
|
|
173
|
+
loading,
|
|
174
|
+
error: _nullishCoalesce(error, () => ( null)),
|
|
175
|
+
fallback,
|
|
176
|
+
download: onDownload ? (
|
|
177
|
+
// Under a muted message: the action keeps the foreground colour.
|
|
178
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
179
|
+
_chunkL4DH72UFcjs.Button,
|
|
180
|
+
{
|
|
181
|
+
type: "button",
|
|
182
|
+
variant: "outline",
|
|
183
|
+
size: "sm",
|
|
184
|
+
className: "text-foreground",
|
|
185
|
+
onClick: onDownload,
|
|
186
|
+
disabled: downloading,
|
|
187
|
+
children: [
|
|
188
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkT2ZFSPE4cjs.Icon, { icon: downloading ? _lucidereact.Loader2 : _lucidereact.Download, size: "sm", spin: downloading }),
|
|
189
|
+
downloadLabel
|
|
190
|
+
]
|
|
191
|
+
}
|
|
192
|
+
)
|
|
193
|
+
) : null,
|
|
194
|
+
markdownComponents,
|
|
195
|
+
loadingLabel,
|
|
196
|
+
unavailableLabel,
|
|
197
|
+
failedLabel,
|
|
198
|
+
truncatedLabel
|
|
199
|
+
}
|
|
200
|
+
)
|
|
201
|
+
}
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
var TEXT_PREVIEW_LIMIT = 5e5;
|
|
205
|
+
function NewTabLink({ node: _node, ...props }) {
|
|
206
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "a", { ...props, target: "_blank", rel: "noopener noreferrer" });
|
|
207
|
+
}
|
|
208
|
+
function startOf(text) {
|
|
209
|
+
if (text.length <= TEXT_PREVIEW_LIMIT) return { text, truncated: false };
|
|
210
|
+
const end = text.lastIndexOf("\n", TEXT_PREVIEW_LIMIT);
|
|
211
|
+
return { text: text.slice(0, end > 0 ? end : TEXT_PREVIEW_LIMIT), truncated: true };
|
|
212
|
+
}
|
|
213
|
+
function useFileText(file, src) {
|
|
214
|
+
const source = _nullishCoalesce(file, () => ( src));
|
|
215
|
+
const [read, setRead] = _react.useState.call(void 0, null);
|
|
216
|
+
_react.useEffect.call(void 0, () => {
|
|
217
|
+
if (!source) return void 0;
|
|
218
|
+
let current = true;
|
|
219
|
+
const controller = new AbortController();
|
|
220
|
+
const text = typeof source === "string" ? fetch(source, { signal: controller.signal }).then((response) => {
|
|
221
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
222
|
+
return response.text();
|
|
223
|
+
}) : source.text();
|
|
224
|
+
text.then(
|
|
225
|
+
(value) => {
|
|
226
|
+
if (current) setRead({ source, result: { status: "read", ...startOf(value) } });
|
|
227
|
+
},
|
|
228
|
+
() => {
|
|
229
|
+
if (current) setRead({ source, result: { status: "failed" } });
|
|
230
|
+
}
|
|
231
|
+
);
|
|
232
|
+
return () => {
|
|
233
|
+
current = false;
|
|
234
|
+
controller.abort();
|
|
235
|
+
};
|
|
236
|
+
}, [source]);
|
|
237
|
+
if (!source) return null;
|
|
238
|
+
return _optionalChain([read, 'optionalAccess', _2 => _2.source]) === source ? read.result : { status: "reading" };
|
|
239
|
+
}
|
|
240
|
+
function useObjectUrl(file, type) {
|
|
241
|
+
const [made, setMade] = _react.useState.call(void 0, null);
|
|
242
|
+
_react.useLayoutEffect.call(void 0, () => {
|
|
243
|
+
if (!file) return void 0;
|
|
244
|
+
const url = URL.createObjectURL(type && file.type !== type ? new Blob([file], { type }) : file);
|
|
245
|
+
setMade({ file, type, url });
|
|
246
|
+
return () => URL.revokeObjectURL(url);
|
|
247
|
+
}, [file, type]);
|
|
248
|
+
return file && _optionalChain([made, 'optionalAccess', _3 => _3.file]) === file && made.type === type ? made.url : null;
|
|
249
|
+
}
|
|
250
|
+
function FilePreviewBody({
|
|
251
|
+
kind,
|
|
252
|
+
title,
|
|
253
|
+
file,
|
|
254
|
+
src,
|
|
255
|
+
loading,
|
|
256
|
+
error,
|
|
257
|
+
fallback,
|
|
258
|
+
download,
|
|
259
|
+
markdownComponents,
|
|
260
|
+
loadingLabel,
|
|
261
|
+
unavailableLabel,
|
|
262
|
+
failedLabel,
|
|
263
|
+
truncatedLabel
|
|
264
|
+
}) {
|
|
265
|
+
const ready = !loading && !error && kind !== "none";
|
|
266
|
+
const reads = kind === "text" || kind === "markdown";
|
|
267
|
+
const text = useFileText(ready && reads ? file : null, ready && reads ? src : null);
|
|
268
|
+
const objectUrl = useObjectUrl(ready && !reads ? file : null, kind === "pdf" ? "application/pdf" : void 0);
|
|
269
|
+
const pending = /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGRY77463cjs.PreviewStage, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGRY77463cjs.PreviewLoading, { label: loadingLabel }) });
|
|
270
|
+
const failed = (message) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGRY77463cjs.PreviewStage, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGRY77463cjs.PreviewNotice, { icon: _lucidereact.FileWarning, alert: true, message, children: _nullishCoalesce(fallback, () => ( download)) }) });
|
|
271
|
+
if (loading) return pending;
|
|
272
|
+
if (error) return failed(error);
|
|
273
|
+
if (kind === "none" || !file && !src) {
|
|
274
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGRY77463cjs.PreviewStage, { children: _nullishCoalesce(fallback, () => ( /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGRY77463cjs.PreviewNotice, { icon: _lucidereact.FileQuestion, message: unavailableLabel, children: download }))) });
|
|
275
|
+
}
|
|
276
|
+
if (reads) {
|
|
277
|
+
if (!text || text.status === "reading") return pending;
|
|
278
|
+
if (text.status === "failed") return failed(failedLabel);
|
|
279
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkGRY77463cjs.PreviewStage, { layout: "scroll", label: `Preview of ${title}`, children: [
|
|
280
|
+
text.truncated && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk373W6VADcjs.Text, { variant: "caption", marginBottom: "sm", children: truncatedLabel }),
|
|
281
|
+
kind === "markdown" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkKENBU3NVcjs.LazyMarkdown, { components: { a: NewTabLink, ...markdownComponents }, children: text.text }) : (
|
|
282
|
+
// The theme's relaxed leading is a fixed 1.8rem, which spaces a
|
|
283
|
+
// file's small monospace lines apart; read it at 20px lines.
|
|
284
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkVLXPLKFRcjs.CodeBlock, { wrap: true, className: "[&>pre]:leading-5", children: text.text })
|
|
285
|
+
)
|
|
286
|
+
] });
|
|
287
|
+
}
|
|
288
|
+
const url = file ? objectUrl : src;
|
|
289
|
+
if (!url) return pending;
|
|
290
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ShownFile, { kind, url, title, failed: failed(failedLabel) }, url);
|
|
291
|
+
}
|
|
292
|
+
function ShownFile({
|
|
293
|
+
kind,
|
|
294
|
+
url,
|
|
295
|
+
title,
|
|
296
|
+
failed
|
|
297
|
+
}) {
|
|
298
|
+
const [broken, setBroken] = _react.useState.call(void 0, false);
|
|
299
|
+
if (broken) return failed;
|
|
300
|
+
const fail = () => setBroken(true);
|
|
301
|
+
const label = `Preview of ${title}`;
|
|
302
|
+
if (kind === "image") {
|
|
303
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGRY77463cjs.PreviewStage, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex h-full w-full items-center justify-center p-4", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4UUTKR3Vcjs.Image, { src: url, alt: title, fit: "contain", radius: "sm", className: "max-h-full max-w-full", onError: fail }) }) });
|
|
304
|
+
}
|
|
305
|
+
if (kind === "audio") {
|
|
306
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGRY77463cjs.PreviewStage, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-full max-w-md p-6", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "audio", { src: url, controls: true, preload: "metadata", "aria-label": label, className: "w-full", onError: fail }) }) });
|
|
307
|
+
}
|
|
308
|
+
if (kind === "video") {
|
|
309
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGRY77463cjs.PreviewStage, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex h-full w-full items-center justify-center p-4", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
310
|
+
"video",
|
|
311
|
+
{
|
|
312
|
+
src: url,
|
|
313
|
+
controls: true,
|
|
314
|
+
playsInline: true,
|
|
315
|
+
preload: "metadata",
|
|
316
|
+
"aria-label": label,
|
|
317
|
+
className: "max-h-full max-w-full rounded-sm",
|
|
318
|
+
onError: fail
|
|
319
|
+
}
|
|
320
|
+
) }) });
|
|
321
|
+
}
|
|
322
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGRY77463cjs.PreviewStage, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "iframe", { src: url, title: label, referrerPolicy: "no-referrer", className: "h-full w-full border-0 bg-background" }) });
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
exports.FilePreview = FilePreview; exports.filePreviewKind = filePreviewKind;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { MarkdownComponents } from './markdown.cjs';
|
|
4
|
+
import 'react-markdown';
|
|
5
|
+
import './rich-text.cjs';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* How FilePreview shows a file: in the browser's PDF viewer (`pdf`), as an
|
|
9
|
+
* image, as text (plain text, CSV, JSON, code), as rendered Markdown, or in
|
|
10
|
+
* an audio or video player. `none` has no preview (Office documents,
|
|
11
|
+
* archives, anything else), so the dialog offers the download instead.
|
|
12
|
+
*/
|
|
13
|
+
type FilePreviewKind = "pdf" | "image" | "text" | "markdown" | "audio" | "video" | "none";
|
|
14
|
+
/** What `filePreviewKind` reads: a chat attachment, a stored file record, `{ name: file.name, mediaType: file.type }`. */
|
|
15
|
+
interface FilePreviewFile {
|
|
16
|
+
/** The file's name, extension included. */
|
|
17
|
+
name?: string | null;
|
|
18
|
+
/** Its media type, as the browser, the upload or the server reported it. */
|
|
19
|
+
mediaType?: string | null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* How FilePreview would show a file, from its media type and its name: the
|
|
23
|
+
* type when it says something, the extension when it is missing or generic
|
|
24
|
+
* (`application/octet-stream`). Text named as Markdown is Markdown, since
|
|
25
|
+
* many systems report a `.md` file as `text/plain`, and a name that says text
|
|
26
|
+
* wins over a type with no preview, since Windows reports a `.csv` as
|
|
27
|
+
* `application/vnd.ms-excel`. Use it to decide whether to open a preview at
|
|
28
|
+
* all, or to label the action that opens a file.
|
|
29
|
+
*/
|
|
30
|
+
declare function filePreviewKind({ name, mediaType }: FilePreviewFile): FilePreviewKind;
|
|
31
|
+
interface FilePreviewProps {
|
|
32
|
+
open: boolean;
|
|
33
|
+
onOpenChange: (open: boolean) => void;
|
|
34
|
+
/** The file's name: the dialog's title, and how its type is told when `mediaType` doesn't say. */
|
|
35
|
+
title: string;
|
|
36
|
+
/** The file's media type. Defaults to `file`'s own. */
|
|
37
|
+
mediaType?: string | null;
|
|
38
|
+
/** How to show it, when the host knows better than the name and the type. Defaults to `filePreviewKind()` of both. */
|
|
39
|
+
kind?: FilePreviewKind;
|
|
40
|
+
/**
|
|
41
|
+
* The file itself, fetched however the host's authentication needs. Text
|
|
42
|
+
* is read from it; a PDF, image or media file plays from an object URL
|
|
43
|
+
* the dialog makes and revokes. Takes precedence over `src`.
|
|
44
|
+
*/
|
|
45
|
+
file?: Blob | null;
|
|
46
|
+
/**
|
|
47
|
+
* A URL the browser can load instead: short-lived or otherwise safe, as
|
|
48
|
+
* for `DocumentPreview`. Text and Markdown are fetched from it, so it must
|
|
49
|
+
* allow that (the same origin, or CORS).
|
|
50
|
+
*/
|
|
51
|
+
src?: string | null;
|
|
52
|
+
/** The host is still fetching the file. */
|
|
53
|
+
loading?: boolean;
|
|
54
|
+
/** The host couldn't get the file: shown in place of the preview. */
|
|
55
|
+
error?: string | null;
|
|
56
|
+
onDownload?: () => void;
|
|
57
|
+
downloading?: boolean;
|
|
58
|
+
/** Names the download action, in the header and under a message. Defaults to "Download file". */
|
|
59
|
+
downloadLabel?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Replaces the message (and its download action) shown when there is no
|
|
62
|
+
* preview, and goes under an error in place of the download action.
|
|
63
|
+
*/
|
|
64
|
+
fallback?: ReactNode;
|
|
65
|
+
/** Per-element overrides for a Markdown file (`h1`, `a`, `code`, …). */
|
|
66
|
+
markdownComponents?: MarkdownComponents;
|
|
67
|
+
/** Defaults to "Loading preview…". */
|
|
68
|
+
loadingLabel?: string;
|
|
69
|
+
/** Shown when there is no preview: a type that has none, or nothing to show. Defaults to "No preview for this file." */
|
|
70
|
+
unavailableLabel?: string;
|
|
71
|
+
/** Shown when the file can't be read, shown or played. Defaults to "This file couldn't be shown here." */
|
|
72
|
+
failedLabel?: string;
|
|
73
|
+
/** Shown over a text file too long to show whole. Defaults to "Showing the start of this file. Download it to see the rest." */
|
|
74
|
+
truncatedLabel?: string;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* A file in the kit's preview dialog (the same dialog as `DocumentPreview`),
|
|
78
|
+
* each type shown its own way: a PDF in the browser's viewer, an image, text
|
|
79
|
+
* (plain text, CSV, JSON, code) as it is, Markdown rendered through
|
|
80
|
+
* `LazyMarkdown`, and audio or video in the browser's player. Anything else
|
|
81
|
+
* (Office documents, archives) shows a message and the download.
|
|
82
|
+
*
|
|
83
|
+
* Presentation only: the host fetches the file with whatever authentication
|
|
84
|
+
* it needs and hands over the `Blob`, or a safe URL as `src`. A PDF from a
|
|
85
|
+
* `Blob` is always shown as `application/pdf`, whatever type the blob
|
|
86
|
+
* carries, so a file can never render as a page of the host's origin. Raw
|
|
87
|
+
* HTML in Markdown is ignored and its links open in a new tab; text is
|
|
88
|
+
* never interpreted.
|
|
89
|
+
*/
|
|
90
|
+
declare function FilePreview({ open, onOpenChange, title, mediaType, kind, file, src, loading, error, onDownload, downloading, downloadLabel, fallback, markdownComponents, loadingLabel, unavailableLabel, failedLabel, truncatedLabel, }: FilePreviewProps): react_jsx_runtime.JSX.Element;
|
|
91
|
+
|
|
92
|
+
export { FilePreview, type FilePreviewFile, type FilePreviewKind, type FilePreviewProps, filePreviewKind };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { MarkdownComponents } from './markdown.js';
|
|
4
|
+
import 'react-markdown';
|
|
5
|
+
import './rich-text.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* How FilePreview shows a file: in the browser's PDF viewer (`pdf`), as an
|
|
9
|
+
* image, as text (plain text, CSV, JSON, code), as rendered Markdown, or in
|
|
10
|
+
* an audio or video player. `none` has no preview (Office documents,
|
|
11
|
+
* archives, anything else), so the dialog offers the download instead.
|
|
12
|
+
*/
|
|
13
|
+
type FilePreviewKind = "pdf" | "image" | "text" | "markdown" | "audio" | "video" | "none";
|
|
14
|
+
/** What `filePreviewKind` reads: a chat attachment, a stored file record, `{ name: file.name, mediaType: file.type }`. */
|
|
15
|
+
interface FilePreviewFile {
|
|
16
|
+
/** The file's name, extension included. */
|
|
17
|
+
name?: string | null;
|
|
18
|
+
/** Its media type, as the browser, the upload or the server reported it. */
|
|
19
|
+
mediaType?: string | null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* How FilePreview would show a file, from its media type and its name: the
|
|
23
|
+
* type when it says something, the extension when it is missing or generic
|
|
24
|
+
* (`application/octet-stream`). Text named as Markdown is Markdown, since
|
|
25
|
+
* many systems report a `.md` file as `text/plain`, and a name that says text
|
|
26
|
+
* wins over a type with no preview, since Windows reports a `.csv` as
|
|
27
|
+
* `application/vnd.ms-excel`. Use it to decide whether to open a preview at
|
|
28
|
+
* all, or to label the action that opens a file.
|
|
29
|
+
*/
|
|
30
|
+
declare function filePreviewKind({ name, mediaType }: FilePreviewFile): FilePreviewKind;
|
|
31
|
+
interface FilePreviewProps {
|
|
32
|
+
open: boolean;
|
|
33
|
+
onOpenChange: (open: boolean) => void;
|
|
34
|
+
/** The file's name: the dialog's title, and how its type is told when `mediaType` doesn't say. */
|
|
35
|
+
title: string;
|
|
36
|
+
/** The file's media type. Defaults to `file`'s own. */
|
|
37
|
+
mediaType?: string | null;
|
|
38
|
+
/** How to show it, when the host knows better than the name and the type. Defaults to `filePreviewKind()` of both. */
|
|
39
|
+
kind?: FilePreviewKind;
|
|
40
|
+
/**
|
|
41
|
+
* The file itself, fetched however the host's authentication needs. Text
|
|
42
|
+
* is read from it; a PDF, image or media file plays from an object URL
|
|
43
|
+
* the dialog makes and revokes. Takes precedence over `src`.
|
|
44
|
+
*/
|
|
45
|
+
file?: Blob | null;
|
|
46
|
+
/**
|
|
47
|
+
* A URL the browser can load instead: short-lived or otherwise safe, as
|
|
48
|
+
* for `DocumentPreview`. Text and Markdown are fetched from it, so it must
|
|
49
|
+
* allow that (the same origin, or CORS).
|
|
50
|
+
*/
|
|
51
|
+
src?: string | null;
|
|
52
|
+
/** The host is still fetching the file. */
|
|
53
|
+
loading?: boolean;
|
|
54
|
+
/** The host couldn't get the file: shown in place of the preview. */
|
|
55
|
+
error?: string | null;
|
|
56
|
+
onDownload?: () => void;
|
|
57
|
+
downloading?: boolean;
|
|
58
|
+
/** Names the download action, in the header and under a message. Defaults to "Download file". */
|
|
59
|
+
downloadLabel?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Replaces the message (and its download action) shown when there is no
|
|
62
|
+
* preview, and goes under an error in place of the download action.
|
|
63
|
+
*/
|
|
64
|
+
fallback?: ReactNode;
|
|
65
|
+
/** Per-element overrides for a Markdown file (`h1`, `a`, `code`, …). */
|
|
66
|
+
markdownComponents?: MarkdownComponents;
|
|
67
|
+
/** Defaults to "Loading preview…". */
|
|
68
|
+
loadingLabel?: string;
|
|
69
|
+
/** Shown when there is no preview: a type that has none, or nothing to show. Defaults to "No preview for this file." */
|
|
70
|
+
unavailableLabel?: string;
|
|
71
|
+
/** Shown when the file can't be read, shown or played. Defaults to "This file couldn't be shown here." */
|
|
72
|
+
failedLabel?: string;
|
|
73
|
+
/** Shown over a text file too long to show whole. Defaults to "Showing the start of this file. Download it to see the rest." */
|
|
74
|
+
truncatedLabel?: string;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* A file in the kit's preview dialog (the same dialog as `DocumentPreview`),
|
|
78
|
+
* each type shown its own way: a PDF in the browser's viewer, an image, text
|
|
79
|
+
* (plain text, CSV, JSON, code) as it is, Markdown rendered through
|
|
80
|
+
* `LazyMarkdown`, and audio or video in the browser's player. Anything else
|
|
81
|
+
* (Office documents, archives) shows a message and the download.
|
|
82
|
+
*
|
|
83
|
+
* Presentation only: the host fetches the file with whatever authentication
|
|
84
|
+
* it needs and hands over the `Blob`, or a safe URL as `src`. A PDF from a
|
|
85
|
+
* `Blob` is always shown as `application/pdf`, whatever type the blob
|
|
86
|
+
* carries, so a file can never render as a page of the host's origin. Raw
|
|
87
|
+
* HTML in Markdown is ignored and its links open in a new tab; text is
|
|
88
|
+
* never interpreted.
|
|
89
|
+
*/
|
|
90
|
+
declare function FilePreview({ open, onOpenChange, title, mediaType, kind, file, src, loading, error, onDownload, downloading, downloadLabel, fallback, markdownComponents, loadingLabel, unavailableLabel, failedLabel, truncatedLabel, }: FilePreviewProps): react_jsx_runtime.JSX.Element;
|
|
91
|
+
|
|
92
|
+
export { FilePreview, type FilePreviewFile, type FilePreviewKind, type FilePreviewProps, filePreviewKind };
|