@embedpdf/react 3.0.0-next.13 → 3.0.0-next.15

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.
Files changed (232) hide show
  1. package/dist/AnnotationList-CkijRHet-HEFNUIZe.d.cts +877 -0
  2. package/dist/AnnotationList-CkijRHet-HEFNUIZe.d.ts +877 -0
  3. package/dist/actions.cjs +25 -5
  4. package/dist/actions.cjs.map +1 -1
  5. package/dist/actions.d.cts +18 -5
  6. package/dist/actions.d.ts +18 -5
  7. package/dist/actions.js +22 -6
  8. package/dist/actions.js.map +1 -1
  9. package/dist/anchored-DeX95xSd.d.ts +85 -0
  10. package/dist/anchored-DzN3JywS.d.cts +85 -0
  11. package/dist/anchored.cjs +71 -28
  12. package/dist/anchored.cjs.map +1 -1
  13. package/dist/anchored.d.cts +2 -45
  14. package/dist/anchored.d.ts +2 -45
  15. package/dist/anchored.js +56 -19
  16. package/dist/anchored.js.map +1 -1
  17. package/dist/annotation-B48UT2ln.d.ts +302 -0
  18. package/dist/annotation-C1ttM8Wj.js +708 -0
  19. package/dist/annotation-C1ttM8Wj.js.map +1 -0
  20. package/dist/annotation-C9dVwo9b.d.cts +302 -0
  21. package/dist/annotation-Dex5EBda.cjs +830 -0
  22. package/dist/annotation-Dex5EBda.cjs.map +1 -0
  23. package/dist/annotation.cjs +20 -783
  24. package/dist/annotation.d.cts +2 -2
  25. package/dist/annotation.d.ts +2 -2
  26. package/dist/annotation.js +2 -768
  27. package/dist/commands.cjs +68 -28
  28. package/dist/commands.cjs.map +1 -1
  29. package/dist/commands.d.cts +37 -10
  30. package/dist/commands.d.ts +37 -10
  31. package/dist/commands.js +68 -31
  32. package/dist/commands.js.map +1 -1
  33. package/dist/form-55izw0jS.js +511 -0
  34. package/dist/form-55izw0jS.js.map +1 -0
  35. package/dist/form-BNqQfGGH.cjs +548 -0
  36. package/dist/form-BNqQfGGH.cjs.map +1 -0
  37. package/dist/form.cjs +5 -5
  38. package/dist/form.d.cts +32 -25
  39. package/dist/form.d.ts +32 -25
  40. package/dist/form.js +2 -3
  41. package/dist/history.cjs +38 -0
  42. package/dist/history.cjs.map +1 -0
  43. package/dist/history.d.cts +27 -0
  44. package/dist/history.d.ts +27 -0
  45. package/dist/history.js +27 -0
  46. package/dist/history.js.map +1 -0
  47. package/dist/i18n.cjs +26 -30
  48. package/dist/i18n.cjs.map +1 -1
  49. package/dist/i18n.d.cts +24 -21
  50. package/dist/i18n.d.ts +24 -21
  51. package/dist/i18n.js +24 -31
  52. package/dist/i18n.js.map +1 -1
  53. package/dist/index.cjs +213 -57
  54. package/dist/index.d.cts +32 -31
  55. package/dist/index.d.ts +32 -31
  56. package/dist/index.js +33 -29
  57. package/dist/inert-CmBEbKCn.cjs +19 -0
  58. package/dist/inert-CmBEbKCn.cjs.map +1 -0
  59. package/dist/inert-D8fkennb.js +14 -0
  60. package/dist/inert-D8fkennb.js.map +1 -0
  61. package/dist/interaction.cjs +48 -102
  62. package/dist/interaction.cjs.map +1 -1
  63. package/dist/interaction.d.cts +23 -32
  64. package/dist/interaction.d.ts +23 -32
  65. package/dist/interaction.js +33 -102
  66. package/dist/interaction.js.map +1 -1
  67. package/dist/link.cjs +65 -104
  68. package/dist/link.cjs.map +1 -1
  69. package/dist/link.d.cts +21 -16
  70. package/dist/link.d.ts +22 -17
  71. package/dist/link.js +67 -107
  72. package/dist/link.js.map +1 -1
  73. package/dist/measurement.cjs +56 -0
  74. package/dist/measurement.cjs.map +1 -0
  75. package/dist/measurement.d.cts +38 -0
  76. package/dist/measurement.d.ts +38 -0
  77. package/dist/measurement.js +42 -0
  78. package/dist/measurement.js.map +1 -0
  79. package/dist/metadata.cjs +20 -7
  80. package/dist/metadata.cjs.map +1 -1
  81. package/dist/metadata.d.cts +22 -7
  82. package/dist/metadata.d.ts +22 -7
  83. package/dist/metadata.js +20 -10
  84. package/dist/metadata.js.map +1 -1
  85. package/dist/page-edit.cjs +7 -3
  86. package/dist/page-edit.cjs.map +1 -1
  87. package/dist/page-edit.d.cts +6 -2
  88. package/dist/page-edit.d.ts +6 -2
  89. package/dist/page-edit.js +7 -4
  90. package/dist/page-edit.js.map +1 -1
  91. package/dist/page-layers-Bkaaz8Zf.js +26 -0
  92. package/dist/page-layers-Bkaaz8Zf.js.map +1 -0
  93. package/dist/page-layers-BloZDoOV.cjs +37 -0
  94. package/dist/page-layers-BloZDoOV.cjs.map +1 -0
  95. package/dist/page-view.cjs +89 -82
  96. package/dist/page-view.cjs.map +1 -1
  97. package/dist/page-view.d.cts +14 -7
  98. package/dist/page-view.d.ts +18 -11
  99. package/dist/page-view.js +86 -81
  100. package/dist/page-view.js.map +1 -1
  101. package/dist/redaction.cjs +30 -15
  102. package/dist/redaction.cjs.map +1 -1
  103. package/dist/redaction.d.cts +27 -9
  104. package/dist/redaction.d.ts +27 -9
  105. package/dist/redaction.js +29 -18
  106. package/dist/redaction.js.map +1 -1
  107. package/dist/render.cjs +71 -46
  108. package/dist/render.cjs.map +1 -1
  109. package/dist/render.d.cts +17 -5
  110. package/dist/render.d.ts +17 -5
  111. package/dist/render.js +70 -49
  112. package/dist/render.js.map +1 -1
  113. package/dist/runtime-B6xcPsEb.js +398 -0
  114. package/dist/runtime-B6xcPsEb.js.map +1 -0
  115. package/dist/runtime-DBEBlpQV.d.cts +237 -0
  116. package/dist/runtime-V3MVMb91.d.ts +237 -0
  117. package/dist/runtime-fzpGv78v.cjs +555 -0
  118. package/dist/runtime-fzpGv78v.cjs.map +1 -0
  119. package/dist/runtime.cjs +45 -324
  120. package/dist/runtime.d.cts +2 -2
  121. package/dist/runtime.d.ts +2 -2
  122. package/dist/runtime.js +2 -306
  123. package/dist/search.cjs +81 -50
  124. package/dist/search.cjs.map +1 -1
  125. package/dist/search.d.cts +36 -24
  126. package/dist/search.d.ts +36 -24
  127. package/dist/search.js +81 -53
  128. package/dist/search.js.map +1 -1
  129. package/dist/selection.cjs +105 -108
  130. package/dist/selection.cjs.map +1 -1
  131. package/dist/selection.d.cts +54 -26
  132. package/dist/selection.d.ts +56 -28
  133. package/dist/selection.js +103 -110
  134. package/dist/selection.js.map +1 -1
  135. package/dist/shell.cjs +36 -21
  136. package/dist/shell.cjs.map +1 -1
  137. package/dist/shell.d.cts +32 -17
  138. package/dist/shell.d.ts +32 -17
  139. package/dist/shell.js +36 -24
  140. package/dist/shell.js.map +1 -1
  141. package/dist/signature.cjs +29 -48
  142. package/dist/signature.cjs.map +1 -1
  143. package/dist/signature.d.cts +26 -26
  144. package/dist/signature.d.ts +26 -26
  145. package/dist/signature.js +30 -48
  146. package/dist/signature.js.map +1 -1
  147. package/dist/stage-BIG6aeVd.cjs +369 -0
  148. package/dist/stage-BIG6aeVd.cjs.map +1 -0
  149. package/dist/stage-ByFPD-Fv.d.cts +117 -0
  150. package/dist/stage-DaboaheR.d.ts +117 -0
  151. package/dist/stage-DoVekb83.js +302 -0
  152. package/dist/stage-DoVekb83.js.map +1 -0
  153. package/dist/stage-scope-CQgCuf1w.cjs +46 -0
  154. package/dist/stage-scope-CQgCuf1w.cjs.map +1 -0
  155. package/dist/stage-scope-D7ZeNduT.js +23 -0
  156. package/dist/stage-scope-D7ZeNduT.js.map +1 -0
  157. package/dist/stage.cjs +12 -235
  158. package/dist/stage.d.cts +2 -116
  159. package/dist/stage.d.ts +2 -116
  160. package/dist/stage.js +3 -228
  161. package/dist/stamp.cjs +41 -35
  162. package/dist/stamp.cjs.map +1 -1
  163. package/dist/stamp.d.cts +25 -18
  164. package/dist/stamp.d.ts +25 -18
  165. package/dist/stamp.js +40 -37
  166. package/dist/stamp.js.map +1 -1
  167. package/dist/state-0K1I5cM4.d.cts +29 -0
  168. package/dist/state-0K1I5cM4.d.ts +29 -0
  169. package/dist/state-CbgxhwLA.js +62 -0
  170. package/dist/state-CbgxhwLA.js.map +1 -0
  171. package/dist/state-CsfZy_Eq.cjs +73 -0
  172. package/dist/state-CsfZy_Eq.cjs.map +1 -0
  173. package/dist/svg-shapes-Dm1yTR1b.js +40 -0
  174. package/dist/svg-shapes-Dm1yTR1b.js.map +1 -0
  175. package/dist/svg-shapes-zo0GNkc9.cjs +53 -0
  176. package/dist/svg-shapes-zo0GNkc9.cjs.map +1 -0
  177. package/dist/toolbar.cjs +297 -295
  178. package/dist/toolbar.cjs.map +1 -1
  179. package/dist/toolbar.d.cts +58 -68
  180. package/dist/toolbar.d.ts +67 -77
  181. package/dist/toolbar.js +271 -293
  182. package/dist/toolbar.js.map +1 -1
  183. package/dist/view-manager.cjs +34 -0
  184. package/dist/view-manager.cjs.map +1 -0
  185. package/dist/view-manager.d.cts +21 -0
  186. package/dist/view-manager.d.ts +21 -0
  187. package/dist/view-manager.js +23 -0
  188. package/dist/view-manager.js.map +1 -0
  189. package/package.json +41 -38
  190. package/dist/AnnotationListSnapshot-D3mFut1e-C_GMpK25.d.cts +0 -546
  191. package/dist/AnnotationListSnapshot-D3mFut1e-C_GMpK25.d.ts +0 -546
  192. package/dist/annotation-BCED_p9H.d.cts +0 -160
  193. package/dist/annotation-anchors-CetwM1g7.js +0 -15
  194. package/dist/annotation-anchors-CetwM1g7.js.map +0 -1
  195. package/dist/annotation-anchors-DuYRBJLl.cjs +0 -26
  196. package/dist/annotation-anchors-DuYRBJLl.cjs.map +0 -1
  197. package/dist/annotation-hooks-BB5ZhPpf.cjs +0 -16
  198. package/dist/annotation-hooks-BB5ZhPpf.cjs.map +0 -1
  199. package/dist/annotation-hooks-Df8EmzDO.js +0 -11
  200. package/dist/annotation-hooks-Df8EmzDO.js.map +0 -1
  201. package/dist/annotation-k38KDlIZ.d.ts +0 -160
  202. package/dist/annotation-menu.cjs +0 -64
  203. package/dist/annotation-menu.cjs.map +0 -1
  204. package/dist/annotation-menu.d.cts +0 -33
  205. package/dist/annotation-menu.d.ts +0 -33
  206. package/dist/annotation-menu.js +0 -48
  207. package/dist/annotation-menu.js.map +0 -1
  208. package/dist/annotation.cjs.map +0 -1
  209. package/dist/annotation.js.map +0 -1
  210. package/dist/form-BVumS7up.cjs +0 -926
  211. package/dist/form-BVumS7up.cjs.map +0 -1
  212. package/dist/form-CK3mp99m.js +0 -895
  213. package/dist/form-CK3mp99m.js.map +0 -1
  214. package/dist/rolldown-runtime-BBjsoOtd.js +0 -27
  215. package/dist/runtime-DE76hlnl.d.ts +0 -216
  216. package/dist/runtime-umHA_xHt.d.cts +0 -216
  217. package/dist/runtime.cjs.map +0 -1
  218. package/dist/runtime.js.map +0 -1
  219. package/dist/scrollbar.cjs +0 -241
  220. package/dist/scrollbar.cjs.map +0 -1
  221. package/dist/scrollbar.d.cts +0 -42
  222. package/dist/scrollbar.d.ts +0 -42
  223. package/dist/scrollbar.js +0 -213
  224. package/dist/scrollbar.js.map +0 -1
  225. package/dist/stage.cjs.map +0 -1
  226. package/dist/stage.js.map +0 -1
  227. package/dist/views.cjs +0 -35
  228. package/dist/views.cjs.map +0 -1
  229. package/dist/views.d.cts +0 -21
  230. package/dist/views.d.ts +0 -21
  231. package/dist/views.js +0 -27
  232. package/dist/views.js.map +0 -1
@@ -0,0 +1,398 @@
1
+ import { Fragment, jsx } from "react/jsx-runtime";
2
+ import { DocumentsToken, createKernel, documentState, documentsState, isLocalEngine, shallowEqual, standInFor, viewerSettingsOf } from "@embedpdf/core";
3
+ import { browserClock, epdfThemeVariables, makePageContext as makePageContext$1, mountWebFont, saveFile } from "@embedpdf/web";
4
+ import { createContext, forwardRef, useContext, useEffect, useImperativeHandle, useRef, useState, useSyncExternalStore } from "react";
5
+ //#region src/theme.ts
6
+ /**
7
+ * The CSS variables of a theme, for a `style` prop: `<div style={epdfTheme({ accent })}>`.
8
+ * Everything inside the element follows them, and a CSS variable wins over any setting.
9
+ */
10
+ function epdfTheme(theme) {
11
+ return epdfThemeVariables(theme);
12
+ }
13
+ //#endregion
14
+ //#region src/dev.ts
15
+ /**
16
+ * Development-time guardrails. Every warning fires once per process (keyed),
17
+ * says what is wrong and what to do instead, and compiles out of production
18
+ * builds ({@link isDev}).
19
+ */
20
+ const warned = /* @__PURE__ */ new Set();
21
+ /**
22
+ * Whether this is a development build, as the app's bundler says: every bundler replaces
23
+ * `process.env.NODE_ENV`, with `"production"` in a production build, so there this is `false`
24
+ * and the warnings behind it compile out. A page with no bundler has no `process` at all, and
25
+ * counts as development: the warnings help most while you try the package out.
26
+ */
27
+ function isDev() {
28
+ try {
29
+ return process.env.NODE_ENV !== "production";
30
+ } catch {
31
+ return true;
32
+ }
33
+ }
34
+ /** Warn once per key. No-op in production. */
35
+ function devWarn(key, message) {
36
+ if (!isDev() || warned.has(key)) return;
37
+ warned.add(key);
38
+ console.warn(`[embedpdf] ${message}`);
39
+ }
40
+ //#endregion
41
+ //#region src/runtime.tsx
42
+ const KernelCtx = createContext(null);
43
+ /** The document a subtree is bound to. null => use the active document. */
44
+ const DocumentScopeCtx = createContext(null);
45
+ function useKernel() {
46
+ const kernel = useContext(KernelCtx);
47
+ if (!kernel) throw new Error("useKernel must be used within <Viewer>/<EmbedPDF>");
48
+ return kernel;
49
+ }
50
+ /**
51
+ * Give a subtree a kernel someone else created and owns, so every hook in it
52
+ * works against that kernel. The full viewer's wrapper puts the children it
53
+ * slots into the viewer inside one. The provider never starts or destroys the
54
+ * kernel; `<Viewer>` is the component that owns one.
55
+ */
56
+ function KernelProvider({ kernel, children }) {
57
+ return /* @__PURE__ */ jsx(KernelCtx.Provider, {
58
+ value: kernel,
59
+ children
60
+ });
61
+ }
62
+ const shallowArray = (left, right) => left === right || left.length === right.length && left.every((item, i) => item === right[i]);
63
+ /** Read a value derived from the kernel, cached by equality (no tearing loop). */
64
+ function useKernelValue(select, isEqual = Object.is) {
65
+ const kernel = useKernel();
66
+ const last = useRef(null);
67
+ const get = () => {
68
+ const next = select(kernel);
69
+ if (last.current && isEqual(last.current.v, next)) return last.current.v;
70
+ last.current = { v: next };
71
+ return next;
72
+ };
73
+ return useSyncExternalStore(kernel.subscribe, get, get);
74
+ }
75
+ function useActiveDocumentId() {
76
+ return useKernelValue((kernel) => kernel.documents.getActiveId());
77
+ }
78
+ /** The document id for this subtree: the nearest <DocumentScope>, else the active doc. */
79
+ function useDocumentId() {
80
+ const scoped = useDocumentScope();
81
+ const active = useActiveDocumentId();
82
+ return scoped ?? active;
83
+ }
84
+ /**
85
+ * The document the nearest <DocumentScope> binds this subtree to, or null when
86
+ * it follows the active document. For resolvers that pass it to
87
+ * `kernel.tryCapability`, which reads the active document at call time; UI
88
+ * that needs the id itself uses {@link useDocumentId}.
89
+ */
90
+ function useDocumentScope() {
91
+ return useContext(DocumentScopeCtx);
92
+ }
93
+ /** Bind a subtree to a specific document (panes, comparison). */
94
+ function DocumentScope({ id, children }) {
95
+ return /* @__PURE__ */ jsx(DocumentScopeCtx.Provider, {
96
+ value: id,
97
+ children
98
+ });
99
+ }
100
+ /**
101
+ * Render children only while this subtree has a ready document — the
102
+ * structural way to say "this UI is defined over a document". An empty
103
+ * workspace is a legitimate, designable state (the Viewer no longer blocks on
104
+ * documents so chrome can render at t≈0): workspace-scoped UI (toolbars,
105
+ * commands, i18n) lives outside the gate; document-scoped UI (Stage, panels,
106
+ * page chrome) lives inside it. A document that waits for its password, or
107
+ * failed, renders `locked` or `error` with it, or else `fallback`. Sibling of
108
+ * <DocumentScope>, which picks which document; this one handles whether.
109
+ */
110
+ function DocumentGate({ fallback = null, locked, error, children }) {
111
+ const document = useDocument();
112
+ if (document.status === "ready") return /* @__PURE__ */ jsx(Fragment, { children });
113
+ if (document.status === "locked" && locked) return /* @__PURE__ */ jsx(Fragment, { children: locked(document) });
114
+ if (document.status === "error" && error) return /* @__PURE__ */ jsx(Fragment, { children: error(document) });
115
+ return /* @__PURE__ */ jsx(Fragment, { children: fallback });
116
+ }
117
+ /**
118
+ * Resolve a capability by token, binding document-scoped ones to this
119
+ * subtree's document. Resolution is a reactive read (`tryCapability` through
120
+ * the kernel's one change stream), not a memoized call — under the
121
+ * request-time lifecycle a document can become resolvable while its id stays
122
+ * the same, so any id-keyed cache goes stale; subscribing makes staleness
123
+ * structurally impossible.
124
+ *
125
+ * Outside a document (none open, not ready yet, or none in scope), a document
126
+ * plugin resolves to its stand-in (`standInFor` from `@embedpdf/core`):
127
+ * rendering never fails, and a method called too early refuses with
128
+ * `not-ready` (a method that returns a promise rejects). A token no plugin
129
+ * provides still throws the kernel's reason, because that is a setup mistake.
130
+ */
131
+ function useCapability(token) {
132
+ const kernel = useKernel();
133
+ const capability = useOptionalCapability(token);
134
+ if (capability) return capability;
135
+ if (kernel.scopeOf(token) === "document") return standInFor(kernel, token);
136
+ return kernel.capability(token);
137
+ }
138
+ /** Like `useCapability`, but null while the token can't resolve (no plugin,
139
+ * no document, or a document that isn't ready yet). */
140
+ function useOptionalCapability(token) {
141
+ const scoped = useDocumentScope();
142
+ return useKernelValue((kernel) => kernel.tryCapability(token, scoped ?? void 0));
143
+ }
144
+ /**
145
+ * Subscribe to a selector over a (document-resolved) capability. Strict:
146
+ * while the token can't resolve, it throws the kernel's reason (`no
147
+ * document`, `document is loading`), for code that knows a document exists,
148
+ * such as anything inside a <DocumentGate>. `useOptionalSelector` is its
149
+ * total twin.
150
+ */
151
+ function useSelector(token, select, isEqual = Object.is) {
152
+ const kernel = useKernel();
153
+ const scoped = useDocumentScope();
154
+ const capability = useOptionalCapability(token) ?? kernel.capability(token, scoped ?? void 0);
155
+ const last = useRef(null);
156
+ const get = () => {
157
+ const next = select(capability);
158
+ if (last.current && isEqual(last.current.v, next)) return last.current.v;
159
+ last.current = { v: next };
160
+ return next;
161
+ };
162
+ return useSyncExternalStore(kernel.subscribe, get, get);
163
+ }
164
+ /**
165
+ * Null-safe `useSelector`: `fallback` whenever the token can't resolve — no
166
+ * provider, or a document-scoped token with no document. For chrome that stays
167
+ * mounted across the empty-workspace state (a zoom readout, a mode band).
168
+ *
169
+ * The `select` guard also swallows reads through a capability whose document
170
+ * closed between the store notification and this render — that teardown race
171
+ * resolves to `fallback` for one frame, then re-renders against the new state.
172
+ */
173
+ function useOptionalSelector(token, select, fallback, isEqual = Object.is) {
174
+ const kernel = useKernel();
175
+ const capability = useOptionalCapability(token);
176
+ const last = useRef(null);
177
+ const get = () => {
178
+ let next;
179
+ if (capability === null) next = fallback;
180
+ else try {
181
+ next = select(capability);
182
+ } catch {
183
+ next = fallback;
184
+ }
185
+ if (last.current && isEqual(last.current.v, next)) return last.current.v;
186
+ last.current = { v: next };
187
+ return next;
188
+ };
189
+ return useSyncExternalStore(kernel.subscribe, get, get);
190
+ }
191
+ /**
192
+ * Subscribe to a capability's {@link EventHook} for the mounted lifetime —
193
+ * `useCapabilityEvent(ActionsToken, (actions) => actions.onExecuted, handler)`. Events
194
+ * carry occurrences, never state (a late subscriber that needs the current
195
+ * value uses `useSelector`). The handler rides a ref, so a fresh closure per
196
+ * render never resubscribes. Null-safe: no plugin/document → no subscription.
197
+ */
198
+ function useCapabilityEvent(token, select, handler) {
199
+ const capability = useOptionalCapability(token);
200
+ const handlerRef = useRef(handler);
201
+ handlerRef.current = handler;
202
+ const selectRef = useRef(select);
203
+ selectRef.current = select;
204
+ useEffect(() => {
205
+ if (!capability) return;
206
+ return selectRef.current(capability)((event) => handlerRef.current(event));
207
+ }, [capability]);
208
+ }
209
+ /**
210
+ * The documents API: open, close, unlock, download, and the tabs. Inside a
211
+ * <DocumentScope>, the calls that leave out the document use that one, so
212
+ * `download()` without an id downloads the document in scope. The object
213
+ * never changes, so it's safe in effects and callbacks. What to show comes
214
+ * from `useDocument()` and `useDocumentsState()`.
215
+ */
216
+ function useDocuments() {
217
+ return useCapability(DocumentsToken);
218
+ }
219
+ /** Read a state declaration's value through the kernel, or the value `select` picks from it. */
220
+ function useDeclared(token, read, empty, select) {
221
+ const scoped = useDocumentScope();
222
+ return useKernelValue((kernel) => {
223
+ const capability = kernel.tryCapability(token, scoped ?? void 0);
224
+ const state = capability ? read(capability) : empty;
225
+ return select ? select(state) : state;
226
+ }, shallowEqual);
227
+ }
228
+ /**
229
+ * The document this component talks to: the one its <DocumentScope> names, or
230
+ * else the active one. Its `id`, `name`, `status`, `pageCount`,
231
+ * `hasUnsavedChanges`, and why it's locked or failed. With no document, an
232
+ * empty one that reads as still opening. Takes a selector, and re-renders only
233
+ * when what it returns changes.
234
+ */
235
+ function useDocument(select) {
236
+ return useDeclared(DocumentsToken, documentState.read, documentState.empty, select);
237
+ }
238
+ /**
239
+ * Every open document, in tab order (loading, locked and failed ones too),
240
+ * and the active one's id. Takes a selector, and re-renders only when what it
241
+ * returns changes.
242
+ */
243
+ function useDocumentsState(select) {
244
+ return useDeclared(DocumentsToken, documentsState.read, documentsState.empty, select);
245
+ }
246
+ /** Subscribe to one documents event for the mounted lifetime: `useDocumentsEvent((documents) => documents.onOpened, handler)`. */
247
+ function useDocumentsEvent(select, handler) {
248
+ useCapabilityEvent(DocumentsToken, select, handler);
249
+ }
250
+ const NO_PAGES = Object.freeze([]);
251
+ /**
252
+ * The pages of the document this component talks to, in order: each with its
253
+ * `ref`, `index`, `label`, size and rotation. Needs no Stage, so a thumbnail
254
+ * list or a page picker works anywhere. The same array until a page is added,
255
+ * removed, moved or rotated; empty with no document.
256
+ */
257
+ function usePageList() {
258
+ const documentId = useDocumentId();
259
+ return useKernelValue((kernel) => documentId ? kernel.documents.listPages(documentId) : NO_PAGES);
260
+ }
261
+ /**
262
+ * The viewer's own settings (`<Viewer identity scope accent page>`), or the
263
+ * value `select` picks from them: the accent every part without a color of its
264
+ * own follows, and how pages look. What paints a page or an accent reads it
265
+ * here, through `paint()` from `@embedpdf/web`, so a CSS variable still wins.
266
+ */
267
+ function useViewerSettings(select) {
268
+ return useKernelValue((kernel) => {
269
+ const settings = kernel.getSettings();
270
+ return select ? select(settings) : settings;
271
+ }, shallowEqual);
272
+ }
273
+ /**
274
+ * Owns the kernel as an effect-scoped resource: each effect setup creates and
275
+ * starts exactly one kernel; each cleanup destroys exactly that one. That is
276
+ * the contract StrictMode exercises (two kernels in dev, the first fully
277
+ * destroyed) — the kernel itself is never restarted after destroy.
278
+ *
279
+ * The kernel is published to context the moment it exists — before `start()`
280
+ * resolves — so the `fallback` can use workspace capabilities (i18n copy on a
281
+ * loading screen). The one exception is the very first render, which happens
282
+ * before the effect: it renders nothing. Children mount once `start()` resolves
283
+ * — which never touches the engine, so the shell is alive while WASM compiles
284
+ * or the transport connects. `initialDocuments` open in the background and
285
+ * stream into the registry (`useDocuments()` is reactive); per-document
286
+ * loading UI is the Stage's job, not a root gate.
287
+ *
288
+ * Engine ownership. When `engine` is a thunk, the Viewer owns it: each effect
289
+ * setup constructs one engine (construction is synchronous and inert — boot
290
+ * happens lazily inside the engine) and each cleanup destroys exactly that one
291
+ * — after the kernel, so handles close first. When `engine` is an instance it
292
+ * is borrowed and never destroyed here; the Viewer only warms up a local
293
+ * engine so the WASM boot overlaps plugin initialization. StrictMode's
294
+ * double-mount therefore constructs two independent thunk engines and tears
295
+ * the first fully down, matching the kernel's own effect-scoped lifecycle.
296
+ * That means dev-only double resource use (two worker spawns, two font
297
+ * fetches, briefly overlapping) — deliberate, because it is exactly the
298
+ * leak-detection contract StrictMode exists to exercise; production mounts
299
+ * once and boots once.
300
+ */
301
+ const Viewer = forwardRef(function Viewer({ engine, plugins, initialDocuments, fallback, renderError, onReady, identity, scope, accent, page, children }, ref) {
302
+ const initial = useRef({
303
+ engine,
304
+ plugins,
305
+ initialDocuments
306
+ });
307
+ const settings = viewerSettingsOf({
308
+ identity,
309
+ scope,
310
+ accent,
311
+ page
312
+ });
313
+ const latestSettings = useRef(settings);
314
+ latestSettings.current = settings;
315
+ const warned = useRef(false);
316
+ if (isDev() && !warned.current) {
317
+ if (initial.current.engine !== engine || initial.current.plugins !== plugins) {
318
+ warned.current = true;
319
+ console.warn("[embedpdf] <Viewer> engine/plugins are init-only. A changed identity is ignored — pass stable references (module scope, useState, or useMemo). An inline `plugins={[...]}` array recreates its identity every render.");
320
+ }
321
+ }
322
+ const [boot, setBoot] = useState({
323
+ phase: "booting",
324
+ kernel: null
325
+ });
326
+ const onReadyRef = useRef(onReady);
327
+ onReadyRef.current = onReady;
328
+ useImperativeHandle(ref, () => boot.phase === "ready" ? boot.kernel : null, [boot]);
329
+ useEffect(() => {
330
+ const captured = initial.current;
331
+ const ownsEngine = typeof captured.engine === "function";
332
+ const engine = ownsEngine ? captured.engine() : captured.engine;
333
+ if (isLocalEngine(engine)) engine.warmup();
334
+ let kernel;
335
+ try {
336
+ kernel = createKernel({
337
+ engine,
338
+ plugins: captured.plugins,
339
+ settings: latestSettings.current,
340
+ clock: browserClock()
341
+ });
342
+ } catch (error) {
343
+ setBoot({
344
+ phase: "error",
345
+ error
346
+ });
347
+ if (ownsEngine) engine.destroy();
348
+ return;
349
+ }
350
+ let alive = true;
351
+ setBoot({
352
+ phase: "booting",
353
+ kernel
354
+ });
355
+ kernel.start().then(() => {
356
+ if (!alive) return;
357
+ onReadyRef.current?.(kernel);
358
+ setBoot({
359
+ phase: "ready",
360
+ kernel
361
+ });
362
+ kernel.documents.openAll(captured.initialDocuments ?? []);
363
+ }, (error) => {
364
+ if (alive) setBoot({
365
+ phase: "error",
366
+ error
367
+ });
368
+ });
369
+ return () => {
370
+ alive = false;
371
+ kernel.destroy().then(() => {
372
+ if (ownsEngine) engine.destroy();
373
+ });
374
+ };
375
+ }, []);
376
+ const liveKernel = boot.phase === "error" ? null : boot.kernel;
377
+ useEffect(() => {
378
+ liveKernel?.updateSettings(latestSettings.current);
379
+ });
380
+ if (boot.phase === "error") return /* @__PURE__ */ jsx(Fragment, { children: renderError ? renderError(boot.error) : null });
381
+ if (!boot.kernel) return null;
382
+ return /* @__PURE__ */ jsx(KernelCtx.Provider, {
383
+ value: boot.kernel,
384
+ children: boot.phase === "ready" ? children : fallback ?? null
385
+ });
386
+ });
387
+ const EmbedPDF = Viewer;
388
+ const PageCtx = createContext(null);
389
+ const PageProvider = PageCtx.Provider;
390
+ function usePage() {
391
+ const context = useContext(PageCtx);
392
+ if (!context) throw new Error("usePage must be used inside <PageView> or a <Stage> page");
393
+ return context;
394
+ }
395
+ //#endregion
396
+ export { useOptionalSelector as C, useViewerSettings as D, useSelector as E, devWarn as O, useOptionalCapability as S, usePageList as T, useDocuments as _, PageProvider as a, useKernel as b, mountWebFont as c, useActiveDocumentId as d, useCapability as f, useDocumentScope as g, useDocumentId as h, KernelProvider as i, epdfTheme as k, saveFile as l, useDocument as m, DocumentScope as n, Viewer as o, useCapabilityEvent as p, EmbedPDF as r, makePageContext$1 as s, DocumentGate as t, shallowArray as u, useDocumentsEvent as v, usePage as w, useKernelValue as x, useDocumentsState as y };
397
+
398
+ //# sourceMappingURL=runtime-B6xcPsEb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-B6xcPsEb.js","names":[],"sources":["../src/theme.ts","../src/dev.ts","../src/runtime.tsx"],"sourcesContent":["/**\n * `epdfTheme()`: a theme written with setting names, as a style for the\n * element around your viewer. The variables and their lookup are framework-free\n * (`@embedpdf/web`); this only types the result as React's style.\n */\nimport type * as React from 'react';\nimport { epdfThemeVariables, type EpdfTheme } from '@embedpdf/web';\n\nexport type { EpdfTheme } from '@embedpdf/web';\n\n/**\n * The CSS variables of a theme, for a `style` prop: `<div style={epdfTheme({ accent })}>`.\n * Everything inside the element follows them, and a CSS variable wins over any setting.\n */\nexport function epdfTheme(theme: EpdfTheme): React.CSSProperties {\n return epdfThemeVariables(theme) as React.CSSProperties;\n}\n","/**\n * Development-time guardrails. Every warning fires once per process (keyed),\n * says what is wrong and what to do instead, and compiles out of production\n * builds ({@link isDev}).\n */\nconst warned = new Set<string>();\n\n/**\n * Whether this is a development build, as the app's bundler says: every bundler replaces\n * `process.env.NODE_ENV`, with `\"production\"` in a production build, so there this is `false`\n * and the warnings behind it compile out. A page with no bundler has no `process` at all, and\n * counts as development: the warnings help most while you try the package out.\n */\nexport function isDev(): boolean {\n try {\n return process.env.NODE_ENV !== 'production';\n } catch {\n return true;\n }\n}\n\n/** Warn once per key. No-op in production. */\nexport function devWarn(key: string, message: string): void {\n if (!isDev() || warned.has(key)) return;\n warned.add(key);\n console.warn(`[embedpdf] ${message}`);\n}\n\n/** Test seam: forget every warning so a suite can assert one fires again. */\nexport function resetDevWarnings(): void {\n warned.clear();\n}\n","/**\n * @embedpdf/react — the generic binding.\n *\n * Binds the kernel's one change stream to React (useSyncExternalStore), resolves\n * capabilities (document-scoped ones against the active or `<DocumentScope>`-given\n * document, with a stand-in while there is none), and provides the page\n * coordinate context. Every plugin and layer rides on this — there is no\n * per-plugin framework code.\n */\n\n// One-line-per-feature: registration travels with the UI.\nexport * from '@embedpdf/core';\n// What a page with a viewer needs from the browser: handing bytes to the user as a download,\n// and a font the engine draws with, for text you draw yourself.\nexport { mountWebFont, saveFile } from '@embedpdf/web';\n// The page context every layer draws through; its conversions are shared with every framework.\nexport { makePageContext } from '@embedpdf/web';\n// A theme written with setting names, as the style for the element around a viewer.\nexport { epdfTheme } from './theme';\nexport type { EpdfTheme } from './theme';\nimport * as React from 'react';\nimport {\n createContext,\n forwardRef,\n useContext,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n useSyncExternalStore,\n} from 'react';\nimport {\n DocumentsToken,\n createKernel,\n documentState,\n documentsState,\n isLocalEngine,\n shallowEqual,\n standInFor,\n viewerSettingsOf,\n} from '@embedpdf/core';\nimport type {\n AnyPlugin,\n CapabilityToken,\n DocumentInfo,\n DocumentsCapability,\n DocumentsState,\n Engine,\n EngineFactory,\n EventHook,\n FailedDocumentInfo,\n Identity,\n InitialDocument,\n Kernel,\n LockedDocumentInfo,\n PageInfo,\n ViewerPageSettings,\n ViewerSettings,\n} from '@embedpdf/core';\n// Pure coordinate math from the geometry base — not from stage-core. The\n// PageContext seam stays stage-agnostic (it must also serve standalone PageView).\nimport type { PageTransform } from '@embedpdf/core-geometry';\nimport type { PageViewDemand } from '@embedpdf/plugin-render/contract';\nimport { browserClock } from '@embedpdf/web';\nimport type { PageContext } from '@embedpdf/web';\n\nimport { isDev } from './dev';\n\nconst KernelCtx = createContext<Kernel | null>(null);\n/** The document a subtree is bound to. null => use the active document. */\nconst DocumentScopeCtx = createContext<string | null>(null);\n\nexport function useKernel(): Kernel {\n const kernel = useContext(KernelCtx);\n if (!kernel) throw new Error('useKernel must be used within <Viewer>/<EmbedPDF>');\n return kernel;\n}\n\nexport interface KernelProviderProps {\n kernel: Kernel;\n children?: React.ReactNode;\n}\n/**\n * Give a subtree a kernel someone else created and owns, so every hook in it\n * works against that kernel. The full viewer's wrapper puts the children it\n * slots into the viewer inside one. The provider never starts or destroys the\n * kernel; `<Viewer>` is the component that owns one.\n */\nexport function KernelProvider({ kernel, children }: KernelProviderProps) {\n return <KernelCtx.Provider value={kernel}>{children}</KernelCtx.Provider>;\n}\n\nexport const shallowArray = <T,>(left: readonly T[], right: readonly T[]): boolean =>\n left === right || (left.length === right.length && left.every((item, i) => item === right[i]));\n\n/** Read a value derived from the kernel, cached by equality (no tearing loop). */\nexport function useKernelValue<R>(\n select: (kernel: Kernel) => R,\n isEqual: (left: R, right: R) => boolean = Object.is,\n): R {\n const kernel = useKernel();\n const last = useRef<{ v: R } | null>(null);\n const get = () => {\n const next = select(kernel);\n if (last.current && isEqual(last.current.v, next)) return last.current.v;\n last.current = { v: next };\n return next;\n };\n return useSyncExternalStore(kernel.subscribe, get, get);\n}\n\nexport function useActiveDocumentId(): string | null {\n return useKernelValue((kernel) => kernel.documents.getActiveId());\n}\n\n/** The document id for this subtree: the nearest <DocumentScope>, else the active doc. */\nexport function useDocumentId(): string | null {\n const scoped = useDocumentScope();\n const active = useActiveDocumentId();\n return scoped ?? active;\n}\n\n/**\n * The document the nearest <DocumentScope> binds this subtree to, or null when\n * it follows the active document. For resolvers that pass it to\n * `kernel.tryCapability`, which reads the active document at call time; UI\n * that needs the id itself uses {@link useDocumentId}.\n */\nexport function useDocumentScope(): string | null {\n return useContext(DocumentScopeCtx);\n}\n\nexport interface DocumentScopeProps {\n id: string;\n children: React.ReactNode;\n}\n/** Bind a subtree to a specific document (panes, comparison). */\nexport function DocumentScope({ id, children }: DocumentScopeProps) {\n return <DocumentScopeCtx.Provider value={id}>{children}</DocumentScopeCtx.Provider>;\n}\n\nexport interface DocumentGateProps {\n /** Shown while this subtree has no document: none is open, or it's still opening. */\n fallback?: React.ReactNode;\n /** Shown while the document waits for its password; `fallback` without it. */\n locked?: (document: LockedDocumentInfo) => React.ReactNode;\n /** Shown when the document couldn't be opened, with why; `fallback` without it. */\n error?: (document: FailedDocumentInfo) => React.ReactNode;\n children?: React.ReactNode;\n}\n/**\n * Render children only while this subtree has a ready document — the\n * structural way to say \"this UI is defined over a document\". An empty\n * workspace is a legitimate, designable state (the Viewer no longer blocks on\n * documents so chrome can render at t≈0): workspace-scoped UI (toolbars,\n * commands, i18n) lives outside the gate; document-scoped UI (Stage, panels,\n * page chrome) lives inside it. A document that waits for its password, or\n * failed, renders `locked` or `error` with it, or else `fallback`. Sibling of\n * <DocumentScope>, which picks which document; this one handles whether.\n */\nexport function DocumentGate({ fallback = null, locked, error, children }: DocumentGateProps) {\n const document = useDocument();\n if (document.status === 'ready') return <>{children}</>;\n if (document.status === 'locked' && locked) {\n return <>{locked(document as LockedDocumentInfo)}</>;\n }\n if (document.status === 'error' && error) return <>{error(document as FailedDocumentInfo)}</>;\n return <>{fallback}</>;\n}\n\n/**\n * Resolve a capability by token, binding document-scoped ones to this\n * subtree's document. Resolution is a reactive read (`tryCapability` through\n * the kernel's one change stream), not a memoized call — under the\n * request-time lifecycle a document can become resolvable while its id stays\n * the same, so any id-keyed cache goes stale; subscribing makes staleness\n * structurally impossible.\n *\n * Outside a document (none open, not ready yet, or none in scope), a document\n * plugin resolves to its stand-in (`standInFor` from `@embedpdf/core`):\n * rendering never fails, and a method called too early refuses with\n * `not-ready` (a method that returns a promise rejects). A token no plugin\n * provides still throws the kernel's reason, because that is a setup mistake.\n */\nexport function useCapability<T>(token: CapabilityToken<T>): T {\n const kernel = useKernel();\n const capability = useOptionalCapability(token);\n if (capability) return capability;\n if (kernel.scopeOf(token) === 'document') return standInFor(kernel, token);\n return kernel.capability(token);\n}\n\n/** Like `useCapability`, but null while the token can't resolve (no plugin,\n * no document, or a document that isn't ready yet). */\nexport function useOptionalCapability<T>(token: CapabilityToken<T>): T | null {\n const scoped = useDocumentScope();\n return useKernelValue((kernel) => kernel.tryCapability(token, scoped ?? undefined));\n}\n\n/**\n * Subscribe to a selector over a (document-resolved) capability. Strict:\n * while the token can't resolve, it throws the kernel's reason (`no\n * document`, `document is loading`), for code that knows a document exists,\n * such as anything inside a <DocumentGate>. `useOptionalSelector` is its\n * total twin.\n */\nexport function useSelector<C, R>(\n token: CapabilityToken<C>,\n select: (capability: C) => R,\n isEqual: (left: R, right: R) => boolean = Object.is,\n): R {\n const kernel = useKernel();\n const scoped = useDocumentScope();\n const capability = useOptionalCapability(token) ?? kernel.capability(token, scoped ?? undefined);\n const last = useRef<{ v: R } | null>(null);\n const get = () => {\n const next = select(capability);\n if (last.current && isEqual(last.current.v, next)) return last.current.v;\n last.current = { v: next };\n return next;\n };\n return useSyncExternalStore(kernel.subscribe, get, get);\n}\n\n/**\n * Null-safe `useSelector`: `fallback` whenever the token can't resolve — no\n * provider, or a document-scoped token with no document. For chrome that stays\n * mounted across the empty-workspace state (a zoom readout, a mode band).\n *\n * The `select` guard also swallows reads through a capability whose document\n * closed between the store notification and this render — that teardown race\n * resolves to `fallback` for one frame, then re-renders against the new state.\n */\nexport function useOptionalSelector<C, R>(\n token: CapabilityToken<C>,\n select: (capability: C) => R,\n fallback: R,\n isEqual: (left: R, right: R) => boolean = Object.is,\n): R {\n const kernel = useKernel();\n const capability = useOptionalCapability(token);\n const last = useRef<{ v: R } | null>(null);\n const get = () => {\n let next: R;\n if (capability === null) {\n next = fallback;\n } else {\n try {\n next = select(capability);\n } catch {\n next = fallback;\n }\n }\n if (last.current && isEqual(last.current.v, next)) return last.current.v;\n last.current = { v: next };\n return next;\n };\n return useSyncExternalStore(kernel.subscribe, get, get);\n}\n\n/**\n * Subscribe to a capability's {@link EventHook} for the mounted lifetime —\n * `useCapabilityEvent(ActionsToken, (actions) => actions.onExecuted, handler)`. Events\n * carry occurrences, never state (a late subscriber that needs the current\n * value uses `useSelector`). The handler rides a ref, so a fresh closure per\n * render never resubscribes. Null-safe: no plugin/document → no subscription.\n */\nexport function useCapabilityEvent<C, T>(\n token: CapabilityToken<C>,\n select: (capability: C) => EventHook<T>,\n handler: (event: T) => void,\n): void {\n const capability = useOptionalCapability(token);\n const handlerRef = useRef(handler);\n handlerRef.current = handler;\n const selectRef = useRef(select);\n selectRef.current = select;\n useEffect(() => {\n if (!capability) return;\n return selectRef.current(capability)((event) => handlerRef.current(event));\n }, [capability]);\n}\n\n/**\n * The documents API: open, close, unlock, download, and the tabs. Inside a\n * <DocumentScope>, the calls that leave out the document use that one, so\n * `download()` without an id downloads the document in scope. The object\n * never changes, so it's safe in effects and callbacks. What to show comes\n * from `useDocument()` and `useDocumentsState()`.\n */\nexport function useDocuments(): DocumentsCapability {\n return useCapability(DocumentsToken);\n}\n\n/** Read a state declaration's value through the kernel, or the value `select` picks from it. */\nfunction useDeclared<Capability, State extends object, Selected>(\n token: CapabilityToken<Capability>,\n read: (capability: Capability) => State,\n empty: State,\n select: ((state: State) => Selected) | undefined,\n): Selected {\n const scoped = useDocumentScope();\n return useKernelValue((kernel) => {\n const capability = kernel.tryCapability(token, scoped ?? undefined);\n const state = capability ? read(capability) : empty;\n return select ? select(state) : (state as unknown as Selected);\n }, shallowEqual);\n}\n\n/**\n * The document this component talks to: the one its <DocumentScope> names, or\n * else the active one. Its `id`, `name`, `status`, `pageCount`,\n * `hasUnsavedChanges`, and why it's locked or failed. With no document, an\n * empty one that reads as still opening. Takes a selector, and re-renders only\n * when what it returns changes.\n */\nexport function useDocument<Selected = DocumentInfo>(\n select?: (document: DocumentInfo) => Selected,\n): Selected {\n return useDeclared(DocumentsToken, documentState.read, documentState.empty, select);\n}\n\n/**\n * Every open document, in tab order (loading, locked and failed ones too),\n * and the active one's id. Takes a selector, and re-renders only when what it\n * returns changes.\n */\nexport function useDocumentsState<Selected = DocumentsState>(\n select?: (state: DocumentsState) => Selected,\n): Selected {\n return useDeclared(DocumentsToken, documentsState.read, documentsState.empty, select);\n}\n\n/** Subscribe to one documents event for the mounted lifetime: `useDocumentsEvent((documents) => documents.onOpened, handler)`. */\nexport function useDocumentsEvent<T>(\n select: (documents: DocumentsCapability) => EventHook<T>,\n handler: (event: T) => void,\n): void {\n useCapabilityEvent(DocumentsToken, select, handler);\n}\n\nconst NO_PAGES: readonly PageInfo[] = Object.freeze([]);\n\n/**\n * The pages of the document this component talks to, in order: each with its\n * `ref`, `index`, `label`, size and rotation. Needs no Stage, so a thumbnail\n * list or a page picker works anywhere. The same array until a page is added,\n * removed, moved or rotated; empty with no document.\n */\nexport function usePageList(): readonly PageInfo[] {\n const documentId = useDocumentId();\n return useKernelValue((kernel) =>\n documentId ? kernel.documents.listPages(documentId) : NO_PAGES,\n );\n}\n\n/**\n * The viewer's own settings (`<Viewer identity scope accent page>`), or the\n * value `select` picks from them: the accent every part without a color of its\n * own follows, and how pages look. What paints a page or an accent reads it\n * here, through `paint()` from `@embedpdf/web`, so a CSS variable still wins.\n */\nexport function useViewerSettings<Selected = ViewerSettings>(\n select?: (settings: ViewerSettings) => Selected,\n): Selected {\n return useKernelValue((kernel) => {\n const settings = kernel.getSettings();\n return select ? select(settings) : (settings as unknown as Selected);\n }, shallowEqual);\n}\n\n// `InitialDocument` is the kernel's type (re-exported via `export * from\n// '@embedpdf/core'` above) — one shared shape for every adapter.\n\nexport interface ViewerProps {\n /**\n * The engine, as an instance or a thunk. Engines construct synchronously and\n * boot lazily (`localEngine()` allocates nothing until first use), so\n * ownership follows the shape of what you pass:\n *\n * - An **instance** (`engine={engine}`) is borrowed: the Viewer uses it and\n * never destroys it, because you acquired it and therefore own it. The\n * common path — a module-scope `const engine = localEngine()` shared\n * across viewers and route changes. The Viewer warms up a local engine\n * on mount so the boot overlaps app initialization.\n * - A **thunk** (`engine={() => localEngine()}`) is viewer-owned: the\n * Viewer calls it on mount and `destroy()`s the result on unmount. Use it\n * for per-mount isolation (StrictMode/HMR-clean teardown, independent\n * multi-viewer engines).\n *\n * Init-only: captured on first render; later identity changes are ignored (dev warns).\n */\n engine: Engine | EngineFactory;\n /** Init-only: captured on first render; later identity changes are ignored (dev warns). */\n plugins: AnyPlugin[];\n /** Documents to open on startup (with optional tab names). Init-only. */\n initialDocuments?: InitialDocument[];\n fallback?: React.ReactNode;\n /** Rendered when kernel construction or `start()` fails. Without it a boot\n * failure renders nothing — but never a silent forever-fallback. */\n renderError?: (error: unknown) => React.ReactNode;\n /** Called once the kernel has started — before `children` mount and before\n * `initialDocuments` open. The imperative door for code outside React\n * (register commands, subscribe events). The `ref` carries the same kernel. */\n onReady?: (kernel: Kernel) => void;\n /**\n * Who the user is, for every document opened without an `identity` of its\n * own (which replaces this one). Documents opened after a change use the new\n * value; open ones keep theirs. The local engine only: the cloud engine reads\n * it from the document's token.\n */\n identity?: Identity;\n /**\n * What the user may do, as permissions, in every document opened without a\n * `scope` of its own (which replaces this one). Left out, they may do\n * everything. Changes reach the documents opened after them, as `identity`.\n */\n scope?: readonly string[];\n /** The color every part without a color of its own follows. CSS `--epdf-accent` wins over it. */\n accent?: string;\n /** How pages look: `background` before the picture arrives, and the `shadow` under each page. */\n page?: Partial<ViewerPageSettings>;\n children?: React.ReactNode;\n}\n\ntype BootState =\n | { phase: 'booting'; kernel: Kernel | null }\n | { phase: 'ready'; kernel: Kernel }\n | { phase: 'error'; error: unknown };\n\n/**\n * Owns the kernel as an effect-scoped resource: each effect setup creates and\n * starts exactly one kernel; each cleanup destroys exactly that one. That is\n * the contract StrictMode exercises (two kernels in dev, the first fully\n * destroyed) — the kernel itself is never restarted after destroy.\n *\n * The kernel is published to context the moment it exists — before `start()`\n * resolves — so the `fallback` can use workspace capabilities (i18n copy on a\n * loading screen). The one exception is the very first render, which happens\n * before the effect: it renders nothing. Children mount once `start()` resolves\n * — which never touches the engine, so the shell is alive while WASM compiles\n * or the transport connects. `initialDocuments` open in the background and\n * stream into the registry (`useDocuments()` is reactive); per-document\n * loading UI is the Stage's job, not a root gate.\n *\n * Engine ownership. When `engine` is a thunk, the Viewer owns it: each effect\n * setup constructs one engine (construction is synchronous and inert — boot\n * happens lazily inside the engine) and each cleanup destroys exactly that one\n * — after the kernel, so handles close first. When `engine` is an instance it\n * is borrowed and never destroyed here; the Viewer only warms up a local\n * engine so the WASM boot overlaps plugin initialization. StrictMode's\n * double-mount therefore constructs two independent thunk engines and tears\n * the first fully down, matching the kernel's own effect-scoped lifecycle.\n * That means dev-only double resource use (two worker spawns, two font\n * fetches, briefly overlapping) — deliberate, because it is exactly the\n * leak-detection contract StrictMode exists to exercise; production mounts\n * once and boots once.\n */\nexport const Viewer = forwardRef<Kernel | null, ViewerProps>(function Viewer(\n {\n engine,\n plugins,\n initialDocuments,\n fallback,\n renderError,\n onReady,\n identity,\n scope,\n accent,\n page,\n children,\n }: ViewerProps,\n ref,\n) {\n // Init-only inputs: the kernel's lifetime is the component's lifetime, so a\n // changed engine/plugins identity cannot mean \"rebuild the workspace\" —\n // that would silently drop every open document. Capture once, warn in dev.\n const initial = useRef({ engine, plugins, initialDocuments });\n // The viewer's settings follow the props. The first ones go to the kernel when it's\n // created, so the initial documents open with them; later ones as they change.\n const settings = viewerSettingsOf({ identity, scope, accent, page });\n const latestSettings = useRef(settings);\n latestSettings.current = settings;\n const warned = useRef(false);\n if (isDev() && !warned.current) {\n if (initial.current.engine !== engine || initial.current.plugins !== plugins) {\n warned.current = true;\n console.warn(\n '[embedpdf] <Viewer> engine/plugins are init-only. A changed identity is ignored — ' +\n 'pass stable references (module scope, useState, or useMemo). ' +\n 'An inline `plugins={[...]}` array recreates its identity every render.',\n );\n }\n }\n\n const [boot, setBoot] = useState<BootState>({ phase: 'booting', kernel: null });\n const onReadyRef = useRef(onReady);\n onReadyRef.current = onReady;\n // The ref is the started kernel (null before boot and after an error).\n useImperativeHandle<Kernel | null, Kernel | null>(\n ref,\n () => (boot.phase === 'ready' ? boot.kernel : null),\n [boot],\n );\n useEffect(() => {\n const captured = initial.current;\n // A thunk is viewer-owned: call it now, destroy on unmount. An instance is\n // borrowed: use as-is, never destroy. Construction is synchronous and inert\n // either way — the engine boots lazily on first use — so a local engine's\n // `warmup()` overlaps the WASM boot with plugin initialization.\n const ownsEngine = typeof captured.engine === 'function';\n const engine: Engine = ownsEngine\n ? (captured.engine as EngineFactory)()\n : (captured.engine as Engine);\n if (isLocalEngine(engine)) engine.warmup();\n let kernel: Kernel;\n try {\n kernel = createKernel({\n engine,\n plugins: captured.plugins,\n settings: latestSettings.current,\n clock: browserClock(),\n });\n } catch (error) {\n setBoot({ phase: 'error', error }); // plan/graph errors surface, not throw mid-render\n if (ownsEngine) void engine.destroy();\n return;\n }\n let alive = true;\n setBoot({ phase: 'booting', kernel }); // context carries the kernel from this frame on\n kernel.start().then(\n () => {\n if (!alive) return; // unmounted mid-boot — don't open anything\n onReadyRef.current?.(kernel);\n setBoot({ phase: 'ready', kernel });\n // Kernel-owned boot policy: all tabs appear immediately in array\n // order; the `active` entry (else the first) is selected; failures\n // surface as tab status. See DocumentsCapability.openAll.\n kernel.documents.openAll(captured.initialDocuments ?? []);\n },\n (error) => {\n if (alive) setBoot({ phase: 'error', error });\n },\n );\n return () => {\n alive = false;\n // Kernel first (closes every document handle), then the engine we own —\n // ownership follows acquisition. `engine.destroy()` joins an in-flight\n // boot (or no-ops if it never started), so an unmount mid-boot is safe.\n void kernel.destroy().then(() => {\n if (ownsEngine) void engine.destroy();\n });\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // After every render: props compare by value (an inline `page={{ shadow: 'none' }}` is a new\n // object each time), and settings that didn't change change nothing.\n const liveKernel = boot.phase === 'error' ? null : boot.kernel;\n useEffect(() => {\n liveKernel?.updateSettings(latestSettings.current);\n });\n\n if (boot.phase === 'error') {\n return <>{renderError ? renderError(boot.error) : null}</>;\n }\n if (!boot.kernel) return null; // pre-effect first render only\n return (\n <KernelCtx.Provider value={boot.kernel}>\n {boot.phase === 'ready' ? children : (fallback ?? null)}\n </KernelCtx.Provider>\n );\n});\nexport const EmbedPDF = Viewer;\n\n/**\n * PageContext — the seam. A layer depends only on this, never on the Stage. So the\n * same layer works inside a virtualized Stage and in a standalone <PageView>.\n * Its members are documented on `PageContext` in `@embedpdf/web`.\n */\nexport type PageContextValue = PageContext<PageTransform, PageViewDemand>;\n\nconst PageCtx = createContext<PageContextValue | null>(null);\nexport const PageProvider = PageCtx.Provider;\n\nexport function usePage(): PageContextValue {\n const context = useContext(PageCtx);\n if (!context) throw new Error('usePage must be used inside <PageView> or a <Stage> page');\n return context;\n}\n"],"mappings":"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"}