@devultur/convex 1.3.0 → 1.3.1
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/react.d.ts +46 -8
- package/dist/react.js +107 -39
- package/dist/validators.d.ts +5 -5
- package/package.json +3 -3
package/dist/react.d.ts
CHANGED
|
@@ -107,6 +107,32 @@ interface MediaObjectUrl {
|
|
|
107
107
|
*/
|
|
108
108
|
declare function useMediaObjectUrl(media: DevulturMedia | null | undefined, options?: UseMediaObjectUrlOptions): MediaObjectUrl;
|
|
109
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Every string `<Preview>`, `<PdfThumbnail>` and their PDF pages show or announce. Pass any subset as `labels` on a
|
|
112
|
+
* component or on `PdfPreviewProvider`; the component's wins over the provider's, which wins over the English defaults.
|
|
113
|
+
*/
|
|
114
|
+
interface PreviewLabels {
|
|
115
|
+
/** Accessible name of a pdf.js document: its title and page count. */
|
|
116
|
+
document: (title: string, pageCount: number) => string;
|
|
117
|
+
/** Accessible name of one pdf.js page. */
|
|
118
|
+
page: (page: number, pageCount: number) => string;
|
|
119
|
+
/** Announced (visually hidden) while a preview loads, when no `loading` is passed. */
|
|
120
|
+
loading: string;
|
|
121
|
+
/** Note after the last rendered page when a PDF has more than `maxPages`; `fallback` follows it. */
|
|
122
|
+
pageCap: (shown: number, total: number) => string;
|
|
123
|
+
/** `title` of the default fallback's download link when a fetch was refused or the type can't be previewed. */
|
|
124
|
+
error: (code: MediaFetchErrorCode) => string;
|
|
125
|
+
/** Accessible name of a `<PdfThumbnail>`, from its title. */
|
|
126
|
+
thumbnail: (title: string) => string;
|
|
127
|
+
/** Name of a PDF (pdf.js document, `<iframe>` title, thumbnail) with no `title` and no filename. */
|
|
128
|
+
untitledPdf: string;
|
|
129
|
+
/** Name of an image or audio preview with no `title` and no filename. */
|
|
130
|
+
untitledMedia: string;
|
|
131
|
+
/** Text of the default fallback's download link when the media has no filename. */
|
|
132
|
+
download: string;
|
|
133
|
+
}
|
|
134
|
+
declare const defaultPreviewLabels: PreviewLabels;
|
|
135
|
+
|
|
110
136
|
interface PdfPreviewConfig {
|
|
111
137
|
/**
|
|
112
138
|
* Imports pdf.js. Without it, PDFs render in an `<iframe>` (the browser's own viewer) and `<PdfThumbnail>` renders
|
|
@@ -115,15 +141,18 @@ interface PdfPreviewConfig {
|
|
|
115
141
|
pdfjs?: PdfjsLoader;
|
|
116
142
|
/** URL of `pdf.worker.min.mjs`, set on `GlobalWorkerOptions.workerSrc` before a document opens. */
|
|
117
143
|
workerSrc?: string;
|
|
144
|
+
/** Labels for every `<Preview>` and `<PdfThumbnail>` below it; a component's own `labels` win over these. */
|
|
145
|
+
labels?: Partial<PreviewLabels>;
|
|
118
146
|
}
|
|
119
147
|
/**
|
|
120
|
-
* Renders the PDFs of every `<Preview>` and `<PdfThumbnail>` below it with pdf.js, on a `<canvas
|
|
148
|
+
* Renders the PDFs of every `<Preview>` and `<PdfThumbnail>` below it with pdf.js, on a `<canvas>`, and gives them
|
|
149
|
+
* default `labels`.
|
|
121
150
|
*
|
|
122
151
|
* @example
|
|
123
152
|
* import { loadPdfjs } from "@devultur/convex/pdfjs";
|
|
124
153
|
* <PdfPreviewProvider pdfjs={loadPdfjs}>{children}</PdfPreviewProvider>
|
|
125
154
|
*/
|
|
126
|
-
declare function PdfPreviewProvider({ pdfjs, workerSrc, children }: PdfPreviewConfig & {
|
|
155
|
+
declare function PdfPreviewProvider({ pdfjs, workerSrc, labels, children, }: PdfPreviewConfig & {
|
|
127
156
|
children: React.ReactNode;
|
|
128
157
|
}): React.JSX.Element;
|
|
129
158
|
|
|
@@ -140,11 +169,13 @@ interface PdfThumbnailProps {
|
|
|
140
169
|
fallback?: React.ReactNode;
|
|
141
170
|
/** Shown until page 1 is drawn, including while off-screen. Default: nothing. */
|
|
142
171
|
loading?: React.ReactNode;
|
|
143
|
-
/**
|
|
172
|
+
/** Title the accessible name is built from (`labels.thumbnail`). Default: the filename. */
|
|
144
173
|
title?: string;
|
|
145
174
|
className?: string;
|
|
146
175
|
/** Overrides the provider's `workerSrc`. */
|
|
147
176
|
pdfWorkerSrc?: string;
|
|
177
|
+
/** Overrides `thumbnail` and `untitledPdf`; wins over `PdfPreviewProvider`'s `labels`. English by default. */
|
|
178
|
+
labels?: Partial<PreviewLabels>;
|
|
148
179
|
}
|
|
149
180
|
/**
|
|
150
181
|
* Page 1 of a PDF on a small canvas, for lists and upload queues. Nothing is fetched until it nears the viewport.
|
|
@@ -164,9 +195,14 @@ interface PreviewProps {
|
|
|
164
195
|
maxBytes?: number;
|
|
165
196
|
/** Size cap for text previews. Default 1 MiB. */
|
|
166
197
|
maxTextBytes?: number;
|
|
167
|
-
/**
|
|
168
|
-
|
|
169
|
-
|
|
198
|
+
/**
|
|
199
|
+
* Shown for types that don't preview inline and when the fetch fails. Default: a `<DownloadLink>`.
|
|
200
|
+
* As a function it receives why: a `MediaFetchError` when the fetch was refused (`http_error`, `too_large`,
|
|
201
|
+
* `type_mismatch`) or the type doesn't preview inline (`unsupported_type`, nothing fetched), `null` otherwise
|
|
202
|
+
* (a network failure, a PDF pdf.js can't open, or the link after the `maxPages` note).
|
|
203
|
+
*/
|
|
204
|
+
fallback?: React.ReactNode | ((error: MediaFetchError | null) => React.ReactNode);
|
|
205
|
+
/** Shown while a file loads. Default: `labels.loading`, visually hidden, in a `role="status"`. `null` → nothing. */
|
|
170
206
|
loading?: React.ReactNode;
|
|
171
207
|
/** Accessible name of the preview (`alt`, `title`, `aria-label`). Default: the filename (text: none). */
|
|
172
208
|
title?: string;
|
|
@@ -178,6 +214,8 @@ interface PreviewProps {
|
|
|
178
214
|
maxPages?: number;
|
|
179
215
|
/** URL of pdf.js's worker for this preview; overrides `PdfPreviewProvider`'s `workerSrc`. */
|
|
180
216
|
pdfWorkerSrc?: string;
|
|
217
|
+
/** Overrides any string shown or announced; wins over `PdfPreviewProvider`'s `labels`. English by default. */
|
|
218
|
+
labels?: Partial<PreviewLabels>;
|
|
181
219
|
}
|
|
182
220
|
/**
|
|
183
221
|
* Renders a media inline by its content type: images in an `<img>`, PDFs on `<canvas>` pages with pdf.js under a
|
|
@@ -188,7 +226,7 @@ interface PreviewProps {
|
|
|
188
226
|
* @example
|
|
189
227
|
* <Preview media={document.file} maxBytes={20_000_000} className="h-[80vh] w-full" />
|
|
190
228
|
*/
|
|
191
|
-
declare function Preview({ media, contentType, fallback, ...viewProps }: PreviewProps): React.JSX.Element | null;
|
|
229
|
+
declare function Preview({ media, contentType, fallback, loading, labels, ...viewProps }: PreviewProps): React.JSX.Element | null;
|
|
192
230
|
|
|
193
231
|
/** How a content type renders inline: `<img>`, a PDF view (pdf.js canvases or `<iframe>`), `<audio>` or `<pre>`. */
|
|
194
232
|
type PreviewKind = "image" | "pdf" | "audio" | "text";
|
|
@@ -433,4 +471,4 @@ interface UseMediaUploadReturn {
|
|
|
433
471
|
*/
|
|
434
472
|
declare function useMediaUpload(options?: UseMediaUploadOptions): UseMediaUploadReturn;
|
|
435
473
|
|
|
436
|
-
export { type CaptionTrack, CropUpload, type CropUploadLabels, type CropUploadProps, type CropUploadRenderProps, DevulturProvider, DownloadLink, Image, MediaFetchError, type MediaFetchErrorCode, type MediaObjectUrl, type PdfPreviewConfig, PdfPreviewProvider, PdfThumbnail, type PdfThumbnailProps, PdfjsLoader, Preview, type PreviewKind, type PreviewProps, type UploadedMedia, type UseMediaObjectUrlOptions, type UseMediaUploadOptions, type UseMediaUploadReturn, type VideoProps, type VideoState, useDevultur, useDevulturMedia, useDevulturProgress, useMediaObjectUrl, useMediaUpload, useMediaUrl, useVideoProps, useVideoState };
|
|
474
|
+
export { type CaptionTrack, CropUpload, type CropUploadLabels, type CropUploadProps, type CropUploadRenderProps, DevulturProvider, DownloadLink, Image, MediaFetchError, type MediaFetchErrorCode, type MediaObjectUrl, type PdfPreviewConfig, PdfPreviewProvider, PdfThumbnail, type PdfThumbnailProps, PdfjsLoader, Preview, type PreviewKind, type PreviewLabels, type PreviewProps, type UploadedMedia, type UseMediaObjectUrlOptions, type UseMediaUploadOptions, type UseMediaUploadReturn, type VideoProps, type VideoState, defaultPreviewLabels, useDevultur, useDevulturMedia, useDevulturProgress, useMediaObjectUrl, useMediaUpload, useMediaUrl, useVideoProps, useVideoState };
|
package/dist/react.js
CHANGED
|
@@ -381,10 +381,45 @@ function useMediaObjectUrl(media, options) {
|
|
|
381
381
|
|
|
382
382
|
// src/pdf-context.tsx
|
|
383
383
|
import React3 from "react";
|
|
384
|
+
|
|
385
|
+
// src/preview-labels.ts
|
|
386
|
+
var ERROR_TEXT = {
|
|
387
|
+
http_error: "The file couldn't be loaded.",
|
|
388
|
+
too_large: "The file is too large to preview.",
|
|
389
|
+
unsupported_type: "This file type can't be previewed.",
|
|
390
|
+
type_mismatch: "The file's content doesn't match its type."
|
|
391
|
+
};
|
|
392
|
+
var defaultPreviewLabels = {
|
|
393
|
+
document: (title, pageCount) => `${title}, ${pageCount === 1 ? "1 page" : `${pageCount} pages`}`,
|
|
394
|
+
page: (page, pageCount) => `Page ${page} of ${pageCount}`,
|
|
395
|
+
loading: "Loading\u2026",
|
|
396
|
+
pageCap: (shown, total) => `Showing the first ${shown} of ${total} pages.`,
|
|
397
|
+
error: (code) => ERROR_TEXT[code],
|
|
398
|
+
thumbnail: (title) => title,
|
|
399
|
+
untitledPdf: "PDF",
|
|
400
|
+
untitledMedia: "Preview",
|
|
401
|
+
download: "Download"
|
|
402
|
+
};
|
|
403
|
+
function mergePreviewLabels(...sources) {
|
|
404
|
+
const merged = { ...defaultPreviewLabels };
|
|
405
|
+
for (const source of sources) {
|
|
406
|
+
for (const [key, value] of Object.entries(source ?? {})) {
|
|
407
|
+
if (value !== void 0) merged[key] = value;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return merged;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// src/pdf-context.tsx
|
|
384
414
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
385
415
|
var PdfPreviewContext = React3.createContext({});
|
|
386
|
-
function PdfPreviewProvider({
|
|
387
|
-
|
|
416
|
+
function PdfPreviewProvider({
|
|
417
|
+
pdfjs,
|
|
418
|
+
workerSrc,
|
|
419
|
+
labels,
|
|
420
|
+
children
|
|
421
|
+
}) {
|
|
422
|
+
const config = React3.useMemo(() => ({ pdfjs, workerSrc, labels }), [pdfjs, workerSrc, labels]);
|
|
388
423
|
return /* @__PURE__ */ jsx2(PdfPreviewContext.Provider, { value: config, children });
|
|
389
424
|
}
|
|
390
425
|
var loadedModules = /* @__PURE__ */ new WeakMap();
|
|
@@ -413,6 +448,10 @@ function usePdfjs(workerSrcOverride) {
|
|
|
413
448
|
if (!loaded.pdfjs) return { status: "unavailable" };
|
|
414
449
|
return { status: "ready", pdfjs: loaded.pdfjs, workerSrc: workerSrcOverride ?? workerSrc };
|
|
415
450
|
}
|
|
451
|
+
function usePreviewLabels(labels) {
|
|
452
|
+
const providerLabels = React3.useContext(PdfPreviewContext).labels;
|
|
453
|
+
return mergePreviewLabels(providerLabels, labels);
|
|
454
|
+
}
|
|
416
455
|
|
|
417
456
|
// src/pdf-thumbnail.tsx
|
|
418
457
|
import React6 from "react";
|
|
@@ -555,7 +594,7 @@ var VISUALLY_HIDDEN = {
|
|
|
555
594
|
var DEFAULT_MAX_PAGES = 500;
|
|
556
595
|
var keepBytes = (bytes) => bytes;
|
|
557
596
|
function PdfPreview(props) {
|
|
558
|
-
const { media, expectedType, maxBytes,
|
|
597
|
+
const { media, expectedType, maxBytes, renderFallback, loading, labels, title, className, pdfWorkerSrc } = props;
|
|
559
598
|
const pdfjsState = usePdfjs(pdfWorkerSrc);
|
|
560
599
|
const { value: bytes, error } = useMediaResource(media, {
|
|
561
600
|
isEnabled: true,
|
|
@@ -563,9 +602,9 @@ function PdfPreview(props) {
|
|
|
563
602
|
contentType: expectedType,
|
|
564
603
|
decode: keepBytes
|
|
565
604
|
});
|
|
566
|
-
if (error) return /* @__PURE__ */ jsx3(Fragment, { children:
|
|
605
|
+
if (error) return /* @__PURE__ */ jsx3(Fragment, { children: renderFallback(error) });
|
|
567
606
|
if (!bytes || pdfjsState.status === "loading") return /* @__PURE__ */ jsx3(Fragment, { children: loading });
|
|
568
|
-
const label = title ?? media.filename ??
|
|
607
|
+
const label = title ?? media.filename ?? labels.untitledPdf;
|
|
569
608
|
if (pdfjsState.status === "unavailable") return /* @__PURE__ */ jsx3(PdfFrame, { bytes, label, className });
|
|
570
609
|
return /* @__PURE__ */ jsx3(
|
|
571
610
|
PdfCanvasDocument,
|
|
@@ -575,39 +614,54 @@ function PdfPreview(props) {
|
|
|
575
614
|
bytes,
|
|
576
615
|
label,
|
|
577
616
|
className,
|
|
578
|
-
|
|
617
|
+
renderFallback,
|
|
579
618
|
loading,
|
|
580
|
-
|
|
619
|
+
labels,
|
|
620
|
+
maxPages: props.maxPages ?? DEFAULT_MAX_PAGES
|
|
581
621
|
}
|
|
582
622
|
);
|
|
583
623
|
}
|
|
584
624
|
function PdfCanvasDocument(props) {
|
|
585
|
-
const { pdfjs, workerSrc, bytes, label, className,
|
|
625
|
+
const { pdfjs, workerSrc, bytes, label, className, renderFallback, loading, labels, maxPages } = props;
|
|
586
626
|
const { document: document2, error } = usePdfDocument({ pdfjs, bytes, workerSrc });
|
|
587
627
|
const containerRef = React5.useRef(null);
|
|
588
628
|
const [width, setWidth] = React5.useState(null);
|
|
589
629
|
React5.useLayoutEffect(() => {
|
|
590
630
|
if (document2) setWidth(containerRef.current?.clientWidth ?? 0);
|
|
591
631
|
}, [document2]);
|
|
592
|
-
if (error) return /* @__PURE__ */ jsx3(Fragment, { children:
|
|
632
|
+
if (error) return /* @__PURE__ */ jsx3(Fragment, { children: renderFallback(error) });
|
|
593
633
|
if (!document2) return /* @__PURE__ */ jsx3(Fragment, { children: loading });
|
|
594
634
|
const shownPageCount = Math.min(document2.numPages, Math.max(1, maxPages));
|
|
595
635
|
const isTruncated = shownPageCount < document2.numPages;
|
|
596
636
|
const pageNumbers = Array.from({ length: shownPageCount }, (_, index) => index + 1);
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
637
|
+
return /* @__PURE__ */ jsxs2(
|
|
638
|
+
"div",
|
|
639
|
+
{
|
|
640
|
+
ref: containerRef,
|
|
641
|
+
role: "document",
|
|
642
|
+
"aria-label": labels.document(label, document2.numPages),
|
|
643
|
+
className,
|
|
644
|
+
children: [
|
|
645
|
+
width !== null && pageNumbers.map((pageNumber) => /* @__PURE__ */ jsx3(
|
|
646
|
+
PdfPageView,
|
|
647
|
+
{
|
|
648
|
+
document: document2,
|
|
649
|
+
pageNumber,
|
|
650
|
+
width,
|
|
651
|
+
label: labels.page(pageNumber, document2.numPages)
|
|
652
|
+
},
|
|
653
|
+
pageNumber
|
|
654
|
+
)),
|
|
655
|
+
isTruncated && /* @__PURE__ */ jsxs2("p", { children: [
|
|
656
|
+
labels.pageCap(shownPageCount, document2.numPages),
|
|
657
|
+
" ",
|
|
658
|
+
renderFallback(null)
|
|
659
|
+
] })
|
|
660
|
+
]
|
|
661
|
+
}
|
|
662
|
+
);
|
|
609
663
|
}
|
|
610
|
-
function PdfPageView({ document: document2, pageNumber, width }) {
|
|
664
|
+
function PdfPageView({ document: document2, pageNumber, width, label }) {
|
|
611
665
|
const pageRef = React5.useRef(null);
|
|
612
666
|
const canvasRef = React5.useRef(null);
|
|
613
667
|
const isVisible = useIsVisible(pageRef);
|
|
@@ -620,7 +674,7 @@ function PdfPageView({ document: document2, pageNumber, width }) {
|
|
|
620
674
|
shouldExtractText: true
|
|
621
675
|
});
|
|
622
676
|
const placeholderStyle = isRendered ? void 0 : { aspectRatio: "1 / 1.4142", maxWidth: "100%" };
|
|
623
|
-
return /* @__PURE__ */ jsxs2("section", { ref: pageRef, "aria-label":
|
|
677
|
+
return /* @__PURE__ */ jsxs2("section", { ref: pageRef, "aria-label": label, style: placeholderStyle, children: [
|
|
624
678
|
/* @__PURE__ */ jsx3("canvas", { ref: canvasRef, style: { display: "block", maxWidth: "100%" } }),
|
|
625
679
|
text && /* @__PURE__ */ jsx3("p", { style: VISUALLY_HIDDEN, children: text })
|
|
626
680
|
] });
|
|
@@ -645,6 +699,7 @@ function PdfThumbnail(props) {
|
|
|
645
699
|
const containerRef = React6.useRef(null);
|
|
646
700
|
const isVisible = useIsVisible(containerRef);
|
|
647
701
|
const pdfjsState = usePdfjs(props.pdfWorkerSrc);
|
|
702
|
+
const labels = usePreviewLabels(props.labels);
|
|
648
703
|
const expectedType = media ? expectedContentType(media, contentType) : null;
|
|
649
704
|
const isPdf = previewKindOf(expectedType) === "pdf";
|
|
650
705
|
const { value: bytes, error } = useMediaResource(media, {
|
|
@@ -665,7 +720,7 @@ function PdfThumbnail(props) {
|
|
|
665
720
|
workerSrc: pdfjsState.workerSrc,
|
|
666
721
|
bytes,
|
|
667
722
|
width,
|
|
668
|
-
label: props.title ?? media.filename ??
|
|
723
|
+
label: labels.thumbnail(props.title ?? media.filename ?? labels.untitledPdf),
|
|
669
724
|
fallback,
|
|
670
725
|
loading
|
|
671
726
|
}
|
|
@@ -689,21 +744,32 @@ import { VideoPlayer } from "@devultur/react";
|
|
|
689
744
|
import { Fragment as Fragment3, jsx as jsx5 } from "react/jsx-runtime";
|
|
690
745
|
var DEFAULT_MAX_TEXT_BYTES = 1024 * 1024;
|
|
691
746
|
var DEFAULT_MAX_BYTES = 50 * 1024 * 1024;
|
|
692
|
-
function Preview({ media, contentType, fallback, ...viewProps }) {
|
|
747
|
+
function Preview({ media, contentType, fallback, loading, labels, ...viewProps }) {
|
|
748
|
+
const text = usePreviewLabels(labels);
|
|
693
749
|
if (!media) return null;
|
|
694
|
-
const fallbackNode = fallback === void 0 ? /* @__PURE__ */ jsx5(DownloadLink, { media, children: media.filename ?? "Download" }) : fallback;
|
|
695
750
|
if (media.kind === "video") return /* @__PURE__ */ jsx5(VideoPreview, { media, className: viewProps.className });
|
|
751
|
+
const renderFallback = (error) => {
|
|
752
|
+
const fetchError = error instanceof MediaFetchError ? error : null;
|
|
753
|
+
if (typeof fallback === "function") return fallback(fetchError);
|
|
754
|
+
if (fallback !== void 0) return fallback;
|
|
755
|
+
return /* @__PURE__ */ jsx5(DefaultFallback, { media, error: fetchError, labels: text });
|
|
756
|
+
};
|
|
696
757
|
const expectedType = expectedContentType(media, contentType);
|
|
697
758
|
const kind = previewKindOf(expectedType);
|
|
698
|
-
if (!expectedType || !kind) return /* @__PURE__ */ jsx5(Fragment3, { children:
|
|
699
|
-
const
|
|
759
|
+
if (!expectedType || !kind) return /* @__PURE__ */ jsx5(Fragment3, { children: renderFallback(unsupportedType(expectedType)) });
|
|
760
|
+
const loadingNode = loading === void 0 ? /* @__PURE__ */ jsx5(LoadingStatus, { text: text.loading }) : loading;
|
|
761
|
+
const props = { ...viewProps, media, expectedType, renderFallback, loading: loadingNode, labels: text };
|
|
700
762
|
if (kind === "text") return /* @__PURE__ */ jsx5(TextPreview, { ...props });
|
|
701
|
-
if (kind === "pdf") {
|
|
702
|
-
const { maxBytes = DEFAULT_MAX_BYTES, loading = null } = props;
|
|
703
|
-
return /* @__PURE__ */ jsx5(PdfPreview, { ...props, maxBytes, loading });
|
|
704
|
-
}
|
|
763
|
+
if (kind === "pdf") return /* @__PURE__ */ jsx5(PdfPreview, { ...props, maxBytes: props.maxBytes ?? DEFAULT_MAX_BYTES });
|
|
705
764
|
return /* @__PURE__ */ jsx5(BinaryPreview, { ...props, kind });
|
|
706
765
|
}
|
|
766
|
+
var unsupportedType = (contentType) => new MediaFetchError("unsupported_type", `Can't preview ${contentType ?? "an unknown type"} inline`);
|
|
767
|
+
function DefaultFallback({ media, error, labels }) {
|
|
768
|
+
return /* @__PURE__ */ jsx5(DownloadLink, { media, title: error ? labels.error(error.code) : void 0, children: media.filename ?? labels.download });
|
|
769
|
+
}
|
|
770
|
+
function LoadingStatus({ text }) {
|
|
771
|
+
return /* @__PURE__ */ jsx5("span", { role: "status", style: VISUALLY_HIDDEN, children: text });
|
|
772
|
+
}
|
|
707
773
|
function VideoPreview({ media, className }) {
|
|
708
774
|
const videoProps = useVideoProps(media);
|
|
709
775
|
if (!videoProps) return null;
|
|
@@ -714,8 +780,9 @@ function BinaryPreview({
|
|
|
714
780
|
kind,
|
|
715
781
|
expectedType,
|
|
716
782
|
maxBytes = DEFAULT_MAX_BYTES,
|
|
717
|
-
|
|
718
|
-
loading
|
|
783
|
+
renderFallback,
|
|
784
|
+
loading,
|
|
785
|
+
labels,
|
|
719
786
|
title,
|
|
720
787
|
className
|
|
721
788
|
}) {
|
|
@@ -723,9 +790,9 @@ function BinaryPreview({
|
|
|
723
790
|
const isPublicImage = kind === "image" && media.visibility === "public";
|
|
724
791
|
const verified = useMediaObjectUrl(media, { enabled: !isPublicImage, contentType: expectedType, maxBytes });
|
|
725
792
|
const objectUrl = isPublicImage ? url(media) : verified.objectUrl;
|
|
726
|
-
if (verified.error) return /* @__PURE__ */ jsx5(Fragment3, { children:
|
|
793
|
+
if (verified.error) return /* @__PURE__ */ jsx5(Fragment3, { children: renderFallback(verified.error) });
|
|
727
794
|
if (!objectUrl) return /* @__PURE__ */ jsx5(Fragment3, { children: loading });
|
|
728
|
-
const label = title ?? media.filename ??
|
|
795
|
+
const label = title ?? media.filename ?? labels.untitledMedia;
|
|
729
796
|
if (kind === "image") {
|
|
730
797
|
return /* @__PURE__ */ jsx5("img", { src: objectUrl, alt: label, width: media.width, height: media.height, className });
|
|
731
798
|
}
|
|
@@ -736,8 +803,8 @@ function TextPreview({
|
|
|
736
803
|
media,
|
|
737
804
|
expectedType,
|
|
738
805
|
maxTextBytes = DEFAULT_MAX_TEXT_BYTES,
|
|
739
|
-
|
|
740
|
-
loading
|
|
806
|
+
renderFallback,
|
|
807
|
+
loading,
|
|
741
808
|
title,
|
|
742
809
|
className
|
|
743
810
|
}) {
|
|
@@ -747,7 +814,7 @@ function TextPreview({
|
|
|
747
814
|
contentType: expectedType,
|
|
748
815
|
decode: decodeText
|
|
749
816
|
});
|
|
750
|
-
if (error) return /* @__PURE__ */ jsx5(Fragment3, { children:
|
|
817
|
+
if (error) return /* @__PURE__ */ jsx5(Fragment3, { children: renderFallback(error) });
|
|
751
818
|
if (text === null) return /* @__PURE__ */ jsx5(Fragment3, { children: loading });
|
|
752
819
|
return /* @__PURE__ */ jsx5("pre", { title, className, children: text });
|
|
753
820
|
}
|
|
@@ -1366,6 +1433,7 @@ export {
|
|
|
1366
1433
|
PdfPreviewProvider,
|
|
1367
1434
|
PdfThumbnail,
|
|
1368
1435
|
Preview,
|
|
1436
|
+
defaultPreviewLabels,
|
|
1369
1437
|
useDevultur,
|
|
1370
1438
|
useDevulturMedia,
|
|
1371
1439
|
useDevulturProgress,
|
package/dist/validators.d.ts
CHANGED
|
@@ -12,22 +12,22 @@ import { DevulturKind } from '@devultur/core';
|
|
|
12
12
|
*/
|
|
13
13
|
declare const dv: {
|
|
14
14
|
media(kind?: DevulturKind): convex_values.VObject<{
|
|
15
|
-
filename?: string | undefined;
|
|
16
15
|
key?: string | undefined;
|
|
17
|
-
|
|
16
|
+
filename?: string | undefined;
|
|
18
17
|
height?: number | undefined;
|
|
18
|
+
width?: number | undefined;
|
|
19
|
+
visibility: "public" | "private";
|
|
19
20
|
id: string;
|
|
20
21
|
kind: DevulturKind;
|
|
21
|
-
visibility: "public" | "private";
|
|
22
22
|
}, {
|
|
23
|
-
kind: convex_values.VLiteral<DevulturKind, "required"> | convex_values.VUnion<"
|
|
23
|
+
kind: convex_values.VLiteral<DevulturKind, "required"> | convex_values.VUnion<"video" | "image" | "file", [convex_values.VLiteral<"image", "required">, convex_values.VLiteral<"video", "required">, convex_values.VLiteral<"file", "required">], "required", never>;
|
|
24
24
|
id: convex_values.VString<string, "required">;
|
|
25
25
|
visibility: convex_values.VUnion<"public" | "private", [convex_values.VLiteral<"public", "required">, convex_values.VLiteral<"private", "required">], "required", never>;
|
|
26
26
|
filename: convex_values.VString<string | undefined, "optional">;
|
|
27
27
|
key: convex_values.VString<string | undefined, "optional">;
|
|
28
28
|
width: convex_values.VFloat64<number | undefined, "optional">;
|
|
29
29
|
height: convex_values.VFloat64<number | undefined, "optional">;
|
|
30
|
-
}, "required", "
|
|
30
|
+
}, "required", "key" | "filename" | "visibility" | "height" | "width" | "id" | "kind">;
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
export { dv };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devultur/convex",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "Convex component for Devultur media: media records, uploads, transcodes, watch progress and React bindings",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"convex",
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"dist"
|
|
56
56
|
],
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@devultur/core": "1.3.
|
|
59
|
-
"@devultur/react": "1.3.
|
|
58
|
+
"@devultur/core": "1.3.1",
|
|
59
|
+
"@devultur/react": "1.3.1"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
62
|
"convex": ">=1.25.0",
|