docblocks-react-ui 0.3.1 → 0.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/CHANGELOG.md +102 -0
- package/README.md +1 -0
- package/dist/{Editor-BvKqUGXH.mjs → Editor-BgG_An_T.mjs} +490 -280
- package/dist/{constants-D4FTL0ph.mjs → constants-BaAj3jDA.mjs} +52 -1
- package/dist/{index-DG0lJy_t.d.mts → index-1dJBnGYv.d.mts} +11 -8
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +2 -2
- package/dist/mermaid/index.mjs +2 -2
- package/dist/pdf/index.d.mts +1 -1
- package/dist/pdf/index.mjs +318 -51
- package/dist/styles.css +54 -0
- package/package.json +2 -2
|
@@ -43,6 +43,40 @@ function assertNever(value) {
|
|
|
43
43
|
throw new Error(`Unhandled value: ${String(value)}`);
|
|
44
44
|
}
|
|
45
45
|
//#endregion
|
|
46
|
+
//#region src/shared/ui/icons/ChevronLeft.tsx
|
|
47
|
+
function ChevronLeft(props) {
|
|
48
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
49
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
50
|
+
width: 24,
|
|
51
|
+
height: 24,
|
|
52
|
+
viewBox: "0 0 24 24",
|
|
53
|
+
fill: "none",
|
|
54
|
+
stroke: "currentColor",
|
|
55
|
+
strokeWidth: 2,
|
|
56
|
+
strokeLinecap: "round",
|
|
57
|
+
strokeLinejoin: "round",
|
|
58
|
+
...props,
|
|
59
|
+
children: /* @__PURE__ */ jsx("path", { d: "m15 18-6-6 6-6" })
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
//#region src/shared/ui/icons/ChevronRight.tsx
|
|
64
|
+
function ChevronRight(props) {
|
|
65
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
66
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
67
|
+
width: 24,
|
|
68
|
+
height: 24,
|
|
69
|
+
viewBox: "0 0 24 24",
|
|
70
|
+
fill: "none",
|
|
71
|
+
stroke: "currentColor",
|
|
72
|
+
strokeWidth: 2,
|
|
73
|
+
strokeLinecap: "round",
|
|
74
|
+
strokeLinejoin: "round",
|
|
75
|
+
...props,
|
|
76
|
+
children: /* @__PURE__ */ jsx("path", { d: "m9 18 6-6-6-6" })
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
46
80
|
//#region src/shared/ui/icons/TriangleAlert.tsx
|
|
47
81
|
function TriangleAlert(props) {
|
|
48
82
|
return /* @__PURE__ */ jsxs("svg", {
|
|
@@ -64,6 +98,23 @@ function TriangleAlert(props) {
|
|
|
64
98
|
});
|
|
65
99
|
}
|
|
66
100
|
//#endregion
|
|
101
|
+
//#region src/shared/ui/icons/X.tsx
|
|
102
|
+
function X(props) {
|
|
103
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
104
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
105
|
+
width: 24,
|
|
106
|
+
height: 24,
|
|
107
|
+
viewBox: "0 0 24 24",
|
|
108
|
+
fill: "none",
|
|
109
|
+
stroke: "currentColor",
|
|
110
|
+
strokeWidth: 2,
|
|
111
|
+
strokeLinecap: "round",
|
|
112
|
+
strokeLinejoin: "round",
|
|
113
|
+
...props,
|
|
114
|
+
children: [/* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }), /* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })]
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
//#endregion
|
|
67
118
|
//#region src/pdf/constants.ts
|
|
68
119
|
/** The iframe's embeddable-url gate: only the http(s) scheme may stand the
|
|
69
120
|
* viewer's iframe. The data / blob / javascript schemes (and the
|
|
@@ -78,4 +129,4 @@ function isEmbeddablePdfUrl(url) {
|
|
|
78
129
|
}
|
|
79
130
|
}
|
|
80
131
|
//#endregion
|
|
81
|
-
export {
|
|
132
|
+
export { ChevronLeft as a, isSafeDownloadHref as c, cn as d, ChevronRight as i, preventDefault as l, X as n, assertNever as o, TriangleAlert as r, clamp as s, isEmbeddablePdfUrl as t, stopPropagation as u };
|
|
@@ -1227,15 +1227,18 @@ declare function EditorProvider(props: EditorProviderProps): import("react").JSX
|
|
|
1227
1227
|
//#endregion
|
|
1228
1228
|
//#region src/editor-provider/constants.d.ts
|
|
1229
1229
|
/**
|
|
1230
|
-
* The
|
|
1231
|
-
*
|
|
1232
|
-
*
|
|
1233
|
-
*
|
|
1234
|
-
*
|
|
1235
|
-
*
|
|
1236
|
-
*
|
|
1230
|
+
* The embed sandbox (the default when no `embedSandbox` policy is supplied):
|
|
1231
|
+
* the embedded content runs with its own origin's grants (`allow-same-origin`
|
|
1232
|
+
* — the real-app requirement: a dashboard's own storage / cookies stand,
|
|
1233
|
+
* so the app boots like in a plain tab) + scripts, forms, and popups.
|
|
1234
|
+
* The frame's document stands a separate document either way: a
|
|
1235
|
+
* cross-origin embed cannot reach the parent's DOM or state. The one
|
|
1236
|
+
* posture consequence: a same-origin URL (the page's own origin) reaches
|
|
1237
|
+
* the parent over `window.parent` — the document author's own choice to
|
|
1238
|
+
* embed it. The `embedSandbox` policy stands the restriction (the
|
|
1239
|
+
* opaque-origin stand — no `allow-same-origin` — for the untrusted embeds).
|
|
1237
1240
|
*/
|
|
1238
|
-
declare const DEFAULT_EMBED_SANDBOX = "allow-scripts allow-forms allow-popups";
|
|
1241
|
+
declare const DEFAULT_EMBED_SANDBOX = "allow-scripts allow-same-origin allow-forms allow-popups";
|
|
1239
1242
|
//#endregion
|
|
1240
1243
|
//#region src/editor-provider/context.d.ts
|
|
1241
1244
|
/** Read the per-instance editor context; throws outside an EditorProvider. */
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as BlockRendererMap, r as BlockRendererProps, t as BlockRenderer } from "./index-YJcgf8Hh.mjs";
|
|
2
|
-
import { $ as ProtocolLimits, A as filterIsComplete, B as DatabaseBridge, C as DatabaseTableView, Ct as BlobSubtype, D as DatabaseTableRow, E as DatabaseTablePhase, F as BridgeTableDescription, G as IsoInstant, H as FilterConditionInput, I as BridgeValueInput, J as OperationStatus, K as MutationContext, L as CellMap, M as BatchOp, N as BridgeColumn, O as UseDatabaseTable, P as BridgeColumnAnnotation, Q as ProtocolDescriptor, R as CellValueParse, S as DatabaseTableProps, St as BlobStore, T as useDatabaseTable, Tt as createMemoryBlobStore, U as FilterInput, V as DomainEvent, W as Id, X as PageSnapshot, Y as PageQuery, Z as ProtocolCapability, _ as PresencePeer, _t as isBridgeError, a as EditorContextValue, at as SortInput, b as useTableList, bt as BlobMeta, c as EmbedSandboxPolicy, ct as SubscriptionStatus, d as PdfPreview, dt as TableEvent, et as QueryOperator, f as PdfPreviewProps, ft as TableRef, g as PresenceIdentity, gt as BridgeErrorCode, h as PresenceCrypto, ht as BridgeError, i as AccessLevel, it as RowWire, j as FilterBuilder, k as emptyFilter, l as MentionEntry, lt as TableDescription, m as SyncEmbedResolver, mt as BRIDGE_ERROR_CODES, n as DEFAULT_EMBED_SANDBOX, nt as Revision, o as EditorMode, ot as SubscriptionHandle, p as PresenceConfig, pt as TableSnapshot, q as MutationReceipt, r as EditorProvider, rt as RowPage, s as EditorProviderProps, st as SubscriptionObserver, t as useEditorContext, tt as QuerySemantics, u as MentionProvider, ut as TableEnvelopeBase, v as PresenceSharing, vt as isBridgeErrorCode, w as UseTableList, wt as blobSubtypeOf, x as DatabaseTable, xt as BlobRef, y as PresenceSharingMode, yt as toBridgeError, z as Column } from "./index-
|
|
2
|
+
import { $ as ProtocolLimits, A as filterIsComplete, B as DatabaseBridge, C as DatabaseTableView, Ct as BlobSubtype, D as DatabaseTableRow, E as DatabaseTablePhase, F as BridgeTableDescription, G as IsoInstant, H as FilterConditionInput, I as BridgeValueInput, J as OperationStatus, K as MutationContext, L as CellMap, M as BatchOp, N as BridgeColumn, O as UseDatabaseTable, P as BridgeColumnAnnotation, Q as ProtocolDescriptor, R as CellValueParse, S as DatabaseTableProps, St as BlobStore, T as useDatabaseTable, Tt as createMemoryBlobStore, U as FilterInput, V as DomainEvent, W as Id, X as PageSnapshot, Y as PageQuery, Z as ProtocolCapability, _ as PresencePeer, _t as isBridgeError, a as EditorContextValue, at as SortInput, b as useTableList, bt as BlobMeta, c as EmbedSandboxPolicy, ct as SubscriptionStatus, d as PdfPreview, dt as TableEvent, et as QueryOperator, f as PdfPreviewProps, ft as TableRef, g as PresenceIdentity, gt as BridgeErrorCode, h as PresenceCrypto, ht as BridgeError, i as AccessLevel, it as RowWire, j as FilterBuilder, k as emptyFilter, l as MentionEntry, lt as TableDescription, m as SyncEmbedResolver, mt as BRIDGE_ERROR_CODES, n as DEFAULT_EMBED_SANDBOX, nt as Revision, o as EditorMode, ot as SubscriptionHandle, p as PresenceConfig, pt as TableSnapshot, q as MutationReceipt, r as EditorProvider, rt as RowPage, s as EditorProviderProps, st as SubscriptionObserver, t as useEditorContext, tt as QuerySemantics, u as MentionProvider, ut as TableEnvelopeBase, v as PresenceSharing, vt as isBridgeErrorCode, w as UseTableList, wt as blobSubtypeOf, x as DatabaseTable, xt as BlobRef, y as PresenceSharingMode, yt as toBridgeError, z as Column } from "./index-1dJBnGYv.mjs";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { ComponentType, ReactNode } from "react";
|
|
5
5
|
import { Block, BlockId, BlockType, Doc, DocMeta, PresenceState, Selection, SelectionView, SyncEmbedRef, TextRun } from "docblocks-core";
|
|
@@ -294,7 +294,7 @@ declare function AlertDescription({ className, ...props }: React.ComponentProps<
|
|
|
294
294
|
//#endregion
|
|
295
295
|
//#region src/shared/ui/Badge.d.ts
|
|
296
296
|
declare const badgeVariants: (props?: ({
|
|
297
|
-
variant?: "default" | "
|
|
297
|
+
variant?: "default" | "destructive" | "outline" | "secondary" | "custom" | null | undefined;
|
|
298
298
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
299
299
|
declare function Badge({ className, variant, asChild, ...props }: React.ComponentProps<"span"> & VariantProps<typeof badgeVariants> & {
|
|
300
300
|
asChild?: boolean;
|
|
@@ -305,7 +305,7 @@ declare function BareSelect({ className, children, ...props }: React.ComponentPr
|
|
|
305
305
|
//#endregion
|
|
306
306
|
//#region src/shared/ui/Button.d.ts
|
|
307
307
|
declare const buttonVariants: (props?: ({
|
|
308
|
-
variant?: "link" | "default" | "
|
|
308
|
+
variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
|
|
309
309
|
size?: "default" | "icon" | "sm" | "lg" | "xl" | null | undefined;
|
|
310
310
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
311
311
|
declare function Button({ className, variant, size, asChild, type, ...props }: React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & {
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { $ as PopoverHeader, A as SelectTrigger, At as isBridgeErrorCode, B as DropdownMenuRadioGroup, Bt as useMeta, C as SelectContent, Ct as BASELINE_CAPABILITIES, D as SelectScrollDownButton, Dt as BRIDGE_ERROR_CODES, E as SelectLabel, Et as validateProtocolDescriptor, F as DropdownMenuContent, Ft as columnAnnotation, G as DropdownMenuSubContent, Gt as useText, H as DropdownMenuSeparator, Ht as usePresenceSharing, I as DropdownMenuGroup, It as ScrollArea, J as Separator, Jt as blobSubtypeOf, K as DropdownMenuSubTrigger, L as DropdownMenuItem, Lt as Input, M as Label, Mt as conditionMatches, N as DropdownMenu, Nt as parseCellValue, O as SelectScrollUpButton, Ot as BridgeError, P as DropdownMenuCheckboxItem, Pt as TEXT_TYPES, Q as PopoverDescription, R as DropdownMenuLabel, Rt as useBlock, S as Select, St as AlertTitle, T as SelectItem, Tt as isDatabaseBridge, U as DropdownMenuShortcut, Ut as useSelection, V as DropdownMenuRadioItem, Vt as usePresence, W as DropdownMenuSub, Wt as useSelectionView, X as PopoverAnchor, Y as Popover, Yt as createMemoryBlobStore, Z as PopoverContent, _ as FilterBuilder, _t as BareSelect, a as SHAPE_FONT_STACKS, at as CardAction, b as Skeleton, bt as Alert, ct as CardFooter, d as useEditorContext, dt as Pen, et as PopoverTitle, f as DEFAULT_EMBED_SANDBOX, ft as Eye, g as newMutationContext, gt as buttonVariants, h as cellValueEqual, ht as Button, i as SHAPE_FONT_OPTIONS, it as Card, j as SelectValue, jt as toBridgeError, k as SelectSeparator, kt as isBridgeError, l as markToggleAction, lt as CardHeader, m as useDatabaseTable, mt as BookOpen, nt as DocblocksI18nProvider, o as FORMAT_PALETTE, ot as CardContent, p as GridBody, q as DropdownMenuTrigger, qt as renderRuns, rt as Checkbox, st as CardDescription, t as Editor, tt as PopoverTrigger, u as EditorProvider, ut as CardTitle, v as emptyFilter, vt as Badge, w as SelectGroup, wt as PROTOCOL_VERSION, x as SegmentSelector, xt as AlertDescription, y as filterIsComplete, yt as badgeVariants, z as DropdownMenuPortal, zt as useDoc } from "./Editor-
|
|
2
|
-
import {
|
|
1
|
+
import { $ as PopoverHeader, A as SelectTrigger, At as isBridgeErrorCode, B as DropdownMenuRadioGroup, Bt as useMeta, C as SelectContent, Ct as BASELINE_CAPABILITIES, D as SelectScrollDownButton, Dt as BRIDGE_ERROR_CODES, E as SelectLabel, Et as validateProtocolDescriptor, F as DropdownMenuContent, Ft as columnAnnotation, G as DropdownMenuSubContent, Gt as useText, H as DropdownMenuSeparator, Ht as usePresenceSharing, I as DropdownMenuGroup, It as ScrollArea, J as Separator, Jt as blobSubtypeOf, K as DropdownMenuSubTrigger, L as DropdownMenuItem, Lt as Input, M as Label, Mt as conditionMatches, N as DropdownMenu, Nt as parseCellValue, O as SelectScrollUpButton, Ot as BridgeError, P as DropdownMenuCheckboxItem, Pt as TEXT_TYPES, Q as PopoverDescription, R as DropdownMenuLabel, Rt as useBlock, S as Select, St as AlertTitle, T as SelectItem, Tt as isDatabaseBridge, U as DropdownMenuShortcut, Ut as useSelection, V as DropdownMenuRadioItem, Vt as usePresence, W as DropdownMenuSub, Wt as useSelectionView, X as PopoverAnchor, Y as Popover, Yt as createMemoryBlobStore, Z as PopoverContent, _ as FilterBuilder, _t as BareSelect, a as SHAPE_FONT_STACKS, at as CardAction, b as Skeleton, bt as Alert, ct as CardFooter, d as useEditorContext, dt as Pen, et as PopoverTitle, f as DEFAULT_EMBED_SANDBOX, ft as Eye, g as newMutationContext, gt as buttonVariants, h as cellValueEqual, ht as Button, i as SHAPE_FONT_OPTIONS, it as Card, j as SelectValue, jt as toBridgeError, k as SelectSeparator, kt as isBridgeError, l as markToggleAction, lt as CardHeader, m as useDatabaseTable, mt as BookOpen, nt as DocblocksI18nProvider, o as FORMAT_PALETTE, ot as CardContent, p as GridBody, q as DropdownMenuTrigger, qt as renderRuns, rt as Checkbox, st as CardDescription, t as Editor, tt as PopoverTrigger, u as EditorProvider, ut as CardTitle, v as emptyFilter, vt as Badge, w as SelectGroup, wt as PROTOCOL_VERSION, x as SegmentSelector, xt as AlertDescription, y as filterIsComplete, yt as badgeVariants, z as DropdownMenuPortal, zt as useDoc } from "./Editor-BgG_An_T.mjs";
|
|
2
|
+
import { d as cn, l as preventDefault } from "./constants-BaAj3jDA.mjs";
|
|
3
3
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import { useTranslation } from "react-i18next";
|
package/dist/mermaid/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Kt as INLINE_CODE_CLASS, St as AlertTitle, b as Skeleton, bt as Alert, c as textOf, d as useEditorContext, ft as Eye, n as childrenSlot, pt as CodeXml, r as CodeHeader, s as TextBlock, x as SegmentSelector, xt as AlertDescription } from "../Editor-
|
|
2
|
-
import {
|
|
1
|
+
import { Kt as INLINE_CODE_CLASS, St as AlertTitle, b as Skeleton, bt as Alert, c as textOf, d as useEditorContext, ft as Eye, n as childrenSlot, pt as CodeXml, r as CodeHeader, s as TextBlock, x as SegmentSelector, xt as AlertDescription } from "../Editor-BgG_An_T.mjs";
|
|
2
|
+
import { r as TriangleAlert } from "../constants-BaAj3jDA.mjs";
|
|
3
3
|
import { t as LoaderCircle } from "../LoaderCircle-AGVFE4IP.mjs";
|
|
4
4
|
import { useEffect, useRef, useState } from "react";
|
|
5
5
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
package/dist/pdf/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { f as PdfPreviewProps } from "../index-
|
|
1
|
+
import { f as PdfPreviewProps } from "../index-1dJBnGYv.mjs";
|
|
2
2
|
//#region src/pdf/PdfFirstPage.d.ts
|
|
3
3
|
declare function PdfFirstPage({ id, url, name }: PdfPreviewProps): import("react").JSX.Element;
|
|
4
4
|
//#endregion
|
package/dist/pdf/index.mjs
CHANGED
|
@@ -1,9 +1,54 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as ChevronLeft, c as isSafeDownloadHref, d as cn, i as ChevronRight, n as X, r as TriangleAlert, t as isEmbeddablePdfUrl } from "../constants-BaAj3jDA.mjs";
|
|
2
2
|
import { t as LoaderCircle } from "../LoaderCircle-AGVFE4IP.mjs";
|
|
3
|
-
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import { useTranslation } from "react-i18next";
|
|
6
6
|
import { GlobalWorkerOptions, RenderingCancelledException, getDocument } from "pdfjs-dist";
|
|
7
|
+
import { createPortal } from "react-dom";
|
|
8
|
+
//#region src/shared/ui/icons/Maximize.tsx
|
|
9
|
+
function Maximize(props) {
|
|
10
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
11
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
12
|
+
width: 24,
|
|
13
|
+
height: 24,
|
|
14
|
+
viewBox: "0 0 24 24",
|
|
15
|
+
fill: "none",
|
|
16
|
+
stroke: "currentColor",
|
|
17
|
+
strokeWidth: 2,
|
|
18
|
+
strokeLinecap: "round",
|
|
19
|
+
strokeLinejoin: "round",
|
|
20
|
+
...props,
|
|
21
|
+
children: [
|
|
22
|
+
/* @__PURE__ */ jsx("path", { d: "M8 3H5a2 2 0 0 0-2 2v3" }),
|
|
23
|
+
/* @__PURE__ */ jsx("path", { d: "M21 8V5a2 2 0 0 0-2-2h-3" }),
|
|
24
|
+
/* @__PURE__ */ jsx("path", { d: "M3 16v3a2 2 0 0 0 2 2h3" }),
|
|
25
|
+
/* @__PURE__ */ jsx("path", { d: "M16 21h3a2 2 0 0 0 2-2v-3" })
|
|
26
|
+
]
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/shared/ui/icons/Minimize.tsx
|
|
31
|
+
function Minimize(props) {
|
|
32
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
33
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
34
|
+
width: 24,
|
|
35
|
+
height: 24,
|
|
36
|
+
viewBox: "0 0 24 24",
|
|
37
|
+
fill: "none",
|
|
38
|
+
stroke: "currentColor",
|
|
39
|
+
strokeWidth: 2,
|
|
40
|
+
strokeLinecap: "round",
|
|
41
|
+
strokeLinejoin: "round",
|
|
42
|
+
...props,
|
|
43
|
+
children: [
|
|
44
|
+
/* @__PURE__ */ jsx("path", { d: "M8 3v3a2 2 0 0 1-2 2H3" }),
|
|
45
|
+
/* @__PURE__ */ jsx("path", { d: "M21 8h-3a2 2 0 0 1-2-2V3" }),
|
|
46
|
+
/* @__PURE__ */ jsx("path", { d: "M3 16h3a2 2 0 0 1 2 2v3" }),
|
|
47
|
+
/* @__PURE__ */ jsx("path", { d: "M16 21v-3a2 2 0 0 1 2-2h3" })
|
|
48
|
+
]
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
7
52
|
//#region src/pdf/pdf-worker.ts
|
|
8
53
|
/** The pdfjs-dist worker wiring (the side-effect): the worker file is
|
|
9
54
|
* copied next to this entry at build time (dist/pdf/), so the relative
|
|
@@ -28,26 +73,74 @@ if (typeof window !== "undefined") fetch(WORKER_URL, { method: "HEAD" }).catch((
|
|
|
28
73
|
});
|
|
29
74
|
//#endregion
|
|
30
75
|
//#region src/pdf/PdfFirstPage.tsx
|
|
31
|
-
/** The
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
76
|
+
/** The PDF preview of one `pdf`-subtype image block: fetch the resolved
|
|
77
|
+
* blob, render the pages to a canvas via pdfjs-dist. The inline view stands
|
|
78
|
+
* the first page over the page row; the controls (the previous/next page
|
|
79
|
+
* buttons + the page indicator + the fullscreen toggle) stand a bar under
|
|
80
|
+
* the canvas. The fullscreen mode opens a portal overlay over the viewport
|
|
81
|
+
* (the page scaled to fill the viewport, the same page navigation, the
|
|
82
|
+
* Escape key / the close button / the outside click exit). A failure stands
|
|
83
|
+
* the error note over the native iframe fallback (the document stays
|
|
84
|
+
* viewable). The in-flight fetch is aborted on unmount / url change and the
|
|
85
|
+
* render task + document are released, so a torn-down preview leaves no
|
|
86
|
+
* network request or pdf.js worker behind. */
|
|
87
|
+
/** Render one page to a canvas (the natural page size, the backing store
|
|
88
|
+
* scaled by the device pixel ratio for a crisp retina display). Returns the
|
|
89
|
+
* render task (the caller awaits its promise + cancels it on teardown).
|
|
90
|
+
* Does NOT await the promise itself, so the caller can cancel the in-flight
|
|
91
|
+
* render before it completes. */
|
|
92
|
+
function renderPageToCanvas(pdf, pageNumber, canvas) {
|
|
93
|
+
return pdf.getPage(pageNumber).then((page) => {
|
|
94
|
+
const ratio = window.devicePixelRatio || 1;
|
|
95
|
+
const viewport = page.getViewport({ scale: ratio });
|
|
96
|
+
canvas.width = Math.max(1, Math.floor(viewport.width));
|
|
97
|
+
canvas.height = Math.max(1, Math.floor(viewport.height));
|
|
98
|
+
canvas.style.width = `${Math.max(1, Math.floor(viewport.width / ratio))}px`;
|
|
99
|
+
canvas.style.height = `${Math.max(1, Math.floor(viewport.height / ratio))}px`;
|
|
100
|
+
return page.render({
|
|
101
|
+
canvas,
|
|
102
|
+
viewport
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
/** Render one page to a canvas, scaled to fill the container (the
|
|
107
|
+
* object-fit: contain behavior — the page's aspect ratio is preserved, the
|
|
108
|
+
* page fills the container's width or height). Returns the render task. */
|
|
109
|
+
function renderPageToCanvasScaled(pdf, pageNumber, canvas, containerWidth, containerHeight) {
|
|
110
|
+
return pdf.getPage(pageNumber).then((page) => {
|
|
111
|
+
const pageViewport = page.getViewport({ scale: 1 });
|
|
112
|
+
const scale = Math.min(containerWidth / pageViewport.width, containerHeight / pageViewport.height);
|
|
113
|
+
const ratio = window.devicePixelRatio || 1;
|
|
114
|
+
const viewport = page.getViewport({ scale: scale * ratio });
|
|
115
|
+
canvas.width = Math.max(1, Math.floor(viewport.width));
|
|
116
|
+
canvas.height = Math.max(1, Math.floor(viewport.height));
|
|
117
|
+
canvas.style.width = `${Math.max(1, Math.floor(viewport.width / ratio))}px`;
|
|
118
|
+
canvas.style.height = `${Math.max(1, Math.floor(viewport.height / ratio))}px`;
|
|
119
|
+
return page.render({
|
|
120
|
+
canvas,
|
|
121
|
+
viewport
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
}
|
|
39
125
|
function PdfFirstPage({ id, url, name }) {
|
|
40
126
|
const { t } = useTranslation("blocks");
|
|
41
127
|
const canvasRef = useRef(null);
|
|
128
|
+
const fullscreenCanvasRef = useRef(null);
|
|
129
|
+
const fullscreenContainerRef = useRef(null);
|
|
42
130
|
const loadingTaskRef = useRef(null);
|
|
43
|
-
const
|
|
131
|
+
const pdfDocRef = useRef(null);
|
|
44
132
|
const [phase, setPhase] = useState("loading");
|
|
45
133
|
const [error, setError] = useState(null);
|
|
134
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
135
|
+
const [totalPages, setTotalPages] = useState(0);
|
|
136
|
+
const [isFullscreen, setIsFullscreen] = useState(false);
|
|
46
137
|
useEffect(() => {
|
|
47
138
|
const controller = new AbortController();
|
|
48
139
|
let cancelled = false;
|
|
49
140
|
setPhase("loading");
|
|
50
141
|
setError(null);
|
|
142
|
+
setCurrentPage(1);
|
|
143
|
+
setTotalPages(0);
|
|
51
144
|
const run = async () => {
|
|
52
145
|
try {
|
|
53
146
|
const response = await fetch(url, { signal: controller.signal });
|
|
@@ -66,28 +159,9 @@ function PdfFirstPage({ id, url, name }) {
|
|
|
66
159
|
task.destroy().catch(() => void 0);
|
|
67
160
|
return;
|
|
68
161
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
task.destroy().catch(() => void 0);
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
const canvas = canvasRef.current;
|
|
76
|
-
if (canvas === null) return;
|
|
77
|
-
const ratio = window.devicePixelRatio || 1;
|
|
78
|
-
const viewport = page.getViewport({ scale: ratio });
|
|
79
|
-
canvas.width = Math.max(1, Math.floor(viewport.width));
|
|
80
|
-
canvas.height = Math.max(1, Math.floor(viewport.height));
|
|
81
|
-
canvas.style.width = `${Math.max(1, Math.floor(viewport.width / ratio))}px`;
|
|
82
|
-
canvas.style.height = `${Math.max(1, Math.floor(viewport.height / ratio))}px`;
|
|
83
|
-
const renderTask = page.render({
|
|
84
|
-
canvas,
|
|
85
|
-
viewport
|
|
86
|
-
});
|
|
87
|
-
renderTaskRef.current = renderTask;
|
|
88
|
-
await renderTask.promise;
|
|
89
|
-
if (renderTaskRef.current === renderTask) renderTaskRef.current = null;
|
|
90
|
-
if (!cancelled) setPhase("ready");
|
|
162
|
+
pdfDocRef.current = pdf;
|
|
163
|
+
setTotalPages(pdf.numPages);
|
|
164
|
+
setPhase("ready");
|
|
91
165
|
} catch (cause) {
|
|
92
166
|
if (cancelled || cause instanceof RenderingCancelledException || cause instanceof DOMException && cause.name === "AbortError") return;
|
|
93
167
|
const message = cause instanceof Error ? cause.message : String(cause);
|
|
@@ -99,14 +173,85 @@ function PdfFirstPage({ id, url, name }) {
|
|
|
99
173
|
return () => {
|
|
100
174
|
cancelled = true;
|
|
101
175
|
controller.abort();
|
|
102
|
-
|
|
103
|
-
renderTaskRef.current = null;
|
|
104
|
-
if (renderTask !== null) renderTask.cancel();
|
|
176
|
+
pdfDocRef.current = null;
|
|
105
177
|
const task = loadingTaskRef.current;
|
|
106
178
|
loadingTaskRef.current = null;
|
|
107
179
|
if (task !== null) task.destroy().catch(() => void 0);
|
|
108
180
|
};
|
|
109
181
|
}, [url]);
|
|
182
|
+
useEffect(() => {
|
|
183
|
+
if (phase !== "ready") return;
|
|
184
|
+
const pdf = pdfDocRef.current;
|
|
185
|
+
const canvas = canvasRef.current;
|
|
186
|
+
if (pdf === null || canvas === null) return;
|
|
187
|
+
let cancelled = false;
|
|
188
|
+
let renderTask = null;
|
|
189
|
+
const run = async () => {
|
|
190
|
+
try {
|
|
191
|
+
renderTask = await renderPageToCanvas(pdf, currentPage, canvas);
|
|
192
|
+
await renderTask.promise;
|
|
193
|
+
} catch (cause) {
|
|
194
|
+
if (cancelled || cause instanceof RenderingCancelledException || cause instanceof DOMException && cause.name === "AbortError") return;
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
run();
|
|
198
|
+
return () => {
|
|
199
|
+
cancelled = true;
|
|
200
|
+
if (renderTask !== null) renderTask.cancel();
|
|
201
|
+
};
|
|
202
|
+
}, [
|
|
203
|
+
url,
|
|
204
|
+
currentPage,
|
|
205
|
+
phase
|
|
206
|
+
]);
|
|
207
|
+
useEffect(() => {
|
|
208
|
+
if (!isFullscreen || phase !== "ready") return;
|
|
209
|
+
const pdf = pdfDocRef.current;
|
|
210
|
+
const canvas = fullscreenCanvasRef.current;
|
|
211
|
+
const container = fullscreenContainerRef.current;
|
|
212
|
+
if (pdf === null || canvas === null || container === null) return;
|
|
213
|
+
let cancelled = false;
|
|
214
|
+
let renderTask = null;
|
|
215
|
+
const render = () => {
|
|
216
|
+
const width = container.clientWidth;
|
|
217
|
+
const height = container.clientHeight;
|
|
218
|
+
if (width === 0 || height === 0) return;
|
|
219
|
+
(async () => {
|
|
220
|
+
try {
|
|
221
|
+
renderTask = await renderPageToCanvasScaled(pdf, currentPage, canvas, width, height);
|
|
222
|
+
await renderTask.promise;
|
|
223
|
+
} catch (cause) {
|
|
224
|
+
if (cancelled || cause instanceof RenderingCancelledException || cause instanceof DOMException && cause.name === "AbortError") return;
|
|
225
|
+
}
|
|
226
|
+
})();
|
|
227
|
+
};
|
|
228
|
+
render();
|
|
229
|
+
const observer = new ResizeObserver(() => render());
|
|
230
|
+
observer.observe(container);
|
|
231
|
+
return () => {
|
|
232
|
+
cancelled = true;
|
|
233
|
+
observer.disconnect();
|
|
234
|
+
if (renderTask !== null) renderTask.cancel();
|
|
235
|
+
};
|
|
236
|
+
}, [
|
|
237
|
+
isFullscreen,
|
|
238
|
+
currentPage,
|
|
239
|
+
phase
|
|
240
|
+
]);
|
|
241
|
+
useEffect(() => {
|
|
242
|
+
if (!isFullscreen) return;
|
|
243
|
+
const onKeyDown = (event) => {
|
|
244
|
+
if (event.key === "Escape") setIsFullscreen(false);
|
|
245
|
+
};
|
|
246
|
+
window.addEventListener("keydown", onKeyDown);
|
|
247
|
+
return () => window.removeEventListener("keydown", onKeyDown);
|
|
248
|
+
}, [isFullscreen]);
|
|
249
|
+
const prevPage = useCallback(() => {
|
|
250
|
+
setCurrentPage((page) => Math.max(1, page - 1));
|
|
251
|
+
}, []);
|
|
252
|
+
const nextPage = useCallback(() => {
|
|
253
|
+
setCurrentPage((page) => Math.min(totalPages, page + 1));
|
|
254
|
+
}, [totalPages]);
|
|
110
255
|
if (phase === "error") return /* @__PURE__ */ jsxs("div", {
|
|
111
256
|
"data-slot": "docblocks/image-pdf-preview",
|
|
112
257
|
"data-block-id": id,
|
|
@@ -139,26 +284,148 @@ function PdfFirstPage({ id, url, name }) {
|
|
|
139
284
|
children: name ?? "document"
|
|
140
285
|
})]
|
|
141
286
|
});
|
|
287
|
+
const inlineControls = /* @__PURE__ */ jsxs("div", {
|
|
288
|
+
"data-slot": "docblocks/image-pdf-controls",
|
|
289
|
+
className: "\n flex items-center justify-center gap-1 rounded-(--docblocks-radius)\n border-(length:--docblocks-table-border-width) border-(--docblocks-table-border-color) bg-(--muted) px-2 py-1\n ",
|
|
290
|
+
children: [
|
|
291
|
+
/* @__PURE__ */ jsx("button", {
|
|
292
|
+
type: "button",
|
|
293
|
+
"data-slot": "docblocks/image-pdf-prev",
|
|
294
|
+
onClick: prevPage,
|
|
295
|
+
disabled: currentPage <= 1,
|
|
296
|
+
"aria-label": t("code.pdfPrevPage"),
|
|
297
|
+
className: "\n flex size-6 items-center justify-center rounded-sm text-(--muted-foreground) transition-colors\n hover:bg-(--accent) hover:text-(--accent-foreground)\n disabled:pointer-events-none disabled:opacity-40\n ",
|
|
298
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4" })
|
|
299
|
+
}),
|
|
300
|
+
/* @__PURE__ */ jsxs("span", {
|
|
301
|
+
"data-slot": "docblocks/image-pdf-page-indicator",
|
|
302
|
+
className: "px-1 text-xs text-(--muted-foreground) tabular-nums",
|
|
303
|
+
children: [
|
|
304
|
+
currentPage,
|
|
305
|
+
" / ",
|
|
306
|
+
totalPages
|
|
307
|
+
]
|
|
308
|
+
}),
|
|
309
|
+
/* @__PURE__ */ jsx("button", {
|
|
310
|
+
type: "button",
|
|
311
|
+
"data-slot": "docblocks/image-pdf-next",
|
|
312
|
+
onClick: nextPage,
|
|
313
|
+
disabled: currentPage >= totalPages,
|
|
314
|
+
"aria-label": t("code.pdfNextPage"),
|
|
315
|
+
className: "\n flex size-6 items-center justify-center rounded-sm text-(--muted-foreground) transition-colors\n hover:bg-(--accent) hover:text-(--accent-foreground)\n disabled:pointer-events-none disabled:opacity-40\n ",
|
|
316
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-4" })
|
|
317
|
+
}),
|
|
318
|
+
/* @__PURE__ */ jsx("button", {
|
|
319
|
+
type: "button",
|
|
320
|
+
"data-slot": "docblocks/image-pdf-fullscreen",
|
|
321
|
+
onClick: () => setIsFullscreen(true),
|
|
322
|
+
"aria-label": t("code.pdfFullscreen"),
|
|
323
|
+
className: "\n ml-1 flex size-6 items-center justify-center rounded-sm text-(--muted-foreground) transition-colors\n hover:bg-(--accent) hover:text-(--accent-foreground)\n ",
|
|
324
|
+
children: /* @__PURE__ */ jsx(Maximize, { className: "size-4" })
|
|
325
|
+
})
|
|
326
|
+
]
|
|
327
|
+
});
|
|
328
|
+
const fullscreenControls = /* @__PURE__ */ jsxs("div", {
|
|
329
|
+
"data-slot": "docblocks/image-pdf-controls",
|
|
330
|
+
className: "\n flex items-center justify-center gap-1 rounded-(--radius) border border-(--border) bg-(--muted) px-2 py-1\n ",
|
|
331
|
+
children: [
|
|
332
|
+
/* @__PURE__ */ jsx("button", {
|
|
333
|
+
type: "button",
|
|
334
|
+
"data-slot": "docblocks/image-pdf-prev",
|
|
335
|
+
onClick: prevPage,
|
|
336
|
+
disabled: currentPage <= 1,
|
|
337
|
+
"aria-label": t("code.pdfPrevPage"),
|
|
338
|
+
className: "\n flex size-6 items-center justify-center rounded-sm text-(--muted-foreground) transition-colors\n hover:bg-(--accent) hover:text-(--accent-foreground)\n disabled:pointer-events-none disabled:opacity-40\n ",
|
|
339
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4" })
|
|
340
|
+
}),
|
|
341
|
+
/* @__PURE__ */ jsxs("span", {
|
|
342
|
+
"data-slot": "docblocks/image-pdf-page-indicator",
|
|
343
|
+
className: "px-1 text-xs text-(--muted-foreground) tabular-nums",
|
|
344
|
+
children: [
|
|
345
|
+
currentPage,
|
|
346
|
+
" / ",
|
|
347
|
+
totalPages
|
|
348
|
+
]
|
|
349
|
+
}),
|
|
350
|
+
/* @__PURE__ */ jsx("button", {
|
|
351
|
+
type: "button",
|
|
352
|
+
"data-slot": "docblocks/image-pdf-next",
|
|
353
|
+
onClick: nextPage,
|
|
354
|
+
disabled: currentPage >= totalPages,
|
|
355
|
+
"aria-label": t("code.pdfNextPage"),
|
|
356
|
+
className: "\n flex size-6 items-center justify-center rounded-sm text-(--muted-foreground) transition-colors\n hover:bg-(--accent) hover:text-(--accent-foreground)\n disabled:pointer-events-none disabled:opacity-40\n ",
|
|
357
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-4" })
|
|
358
|
+
}),
|
|
359
|
+
/* @__PURE__ */ jsx("button", {
|
|
360
|
+
type: "button",
|
|
361
|
+
"data-slot": "docblocks/image-pdf-minimize",
|
|
362
|
+
onClick: () => setIsFullscreen(false),
|
|
363
|
+
"aria-label": t("code.pdfCloseFullscreen"),
|
|
364
|
+
className: "\n ml-1 flex size-6 items-center justify-center rounded-sm text-(--muted-foreground) transition-colors\n hover:bg-(--accent) hover:text-(--accent-foreground)\n ",
|
|
365
|
+
children: /* @__PURE__ */ jsx(Minimize, { className: "size-4" })
|
|
366
|
+
})
|
|
367
|
+
]
|
|
368
|
+
});
|
|
142
369
|
return /* @__PURE__ */ jsxs("div", {
|
|
143
370
|
"data-slot": "docblocks/image-pdf-preview",
|
|
144
371
|
"data-block-id": id,
|
|
145
372
|
"data-block-type": "image",
|
|
146
373
|
"data-phase": phase,
|
|
147
|
-
className: "relative mx-0 my-(--docblocks-block-spacing) flex
|
|
148
|
-
children: [
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
"
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
374
|
+
className: "relative mx-0 my-(--docblocks-block-spacing) flex flex-col items-center gap-2",
|
|
375
|
+
children: [
|
|
376
|
+
/* @__PURE__ */ jsxs("div", {
|
|
377
|
+
className: "relative flex w-full justify-center",
|
|
378
|
+
children: [/* @__PURE__ */ jsx("canvas", {
|
|
379
|
+
ref: canvasRef,
|
|
380
|
+
"data-slot": "docblocks/image-pdf-canvas",
|
|
381
|
+
className: cn(`
|
|
382
|
+
block max-w-full rounded-(--docblocks-image-radius) border-(length:--docblocks-table-border-width)
|
|
383
|
+
border-(--docblocks-table-border-color) bg-(--background)
|
|
384
|
+
`, phase === "ready" ? "h-auto" : "hidden")
|
|
385
|
+
}), phase === "loading" && /* @__PURE__ */ jsxs("div", {
|
|
386
|
+
className: "flex h-48 w-full items-center justify-center gap-2 text-sm text-(--muted-foreground)",
|
|
387
|
+
children: [/* @__PURE__ */ jsx(LoaderCircle, { className: "size-4 animate-spin" }), /* @__PURE__ */ jsx("span", {
|
|
388
|
+
"data-slot": "docblocks/image-pdf-loading",
|
|
389
|
+
children: t("code.pdfLoading")
|
|
390
|
+
})]
|
|
391
|
+
})]
|
|
392
|
+
}),
|
|
393
|
+
phase === "ready" && inlineControls,
|
|
394
|
+
isFullscreen && createPortal(/* @__PURE__ */ jsxs("div", {
|
|
395
|
+
"data-slot": "docblocks/image-pdf-fullscreen-overlay",
|
|
396
|
+
className: "fixed inset-0 z-50 flex flex-col items-center justify-center gap-3 bg-(--background)",
|
|
397
|
+
role: "dialog",
|
|
398
|
+
"aria-modal": "true",
|
|
399
|
+
"aria-label": t("code.pdfFullscreen"),
|
|
400
|
+
onClick: (event) => {
|
|
401
|
+
const target = event.target;
|
|
402
|
+
if (target === null) return;
|
|
403
|
+
if (target.closest("[data-slot=\"docblocks/image-pdf-fullscreen-canvas\"]") !== null) return;
|
|
404
|
+
if (target.closest("[data-slot=\"docblocks/image-pdf-controls\"]") !== null) return;
|
|
405
|
+
setIsFullscreen(false);
|
|
406
|
+
},
|
|
407
|
+
children: [
|
|
408
|
+
/* @__PURE__ */ jsx("button", {
|
|
409
|
+
type: "button",
|
|
410
|
+
"data-slot": "docblocks/image-pdf-fullscreen-close",
|
|
411
|
+
onClick: () => setIsFullscreen(false),
|
|
412
|
+
"aria-label": t("code.pdfCloseFullscreen"),
|
|
413
|
+
className: "\n absolute top-4 right-4 flex size-8 items-center justify-center rounded-md text-(--foreground)\n transition-colors\n hover:bg-(--accent)\n ",
|
|
414
|
+
children: /* @__PURE__ */ jsx(X, { className: "size-5" })
|
|
415
|
+
}),
|
|
416
|
+
/* @__PURE__ */ jsx("div", {
|
|
417
|
+
ref: fullscreenContainerRef,
|
|
418
|
+
className: "flex h-[calc(100vh-6rem)] w-[calc(100vw-4rem)] items-center justify-center overflow-hidden",
|
|
419
|
+
children: /* @__PURE__ */ jsx("canvas", {
|
|
420
|
+
ref: fullscreenCanvasRef,
|
|
421
|
+
"data-slot": "docblocks/image-pdf-fullscreen-canvas",
|
|
422
|
+
className: "max-h-full max-w-full border border-(--border) bg-(--background) shadow-lg"
|
|
423
|
+
})
|
|
424
|
+
}),
|
|
425
|
+
fullscreenControls
|
|
426
|
+
]
|
|
427
|
+
}), document.body)
|
|
428
|
+
]
|
|
162
429
|
});
|
|
163
430
|
}
|
|
164
431
|
//#endregion
|