@embedpdf/svelte 0.0.0-stage → 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 (261) hide show
  1. package/LICENSE +192 -0
  2. package/README.md +312 -2
  3. package/dist/actions/readers.svelte.d.ts +29 -0
  4. package/dist/actions/readers.svelte.js +55 -0
  5. package/dist/actions.d.ts +13 -0
  6. package/dist/actions.js +13 -0
  7. package/dist/anchored/Anchored.svelte +24 -0
  8. package/dist/anchored/Anchored.svelte.d.ts +4 -0
  9. package/dist/anchored/PlacedAnchored.svelte +97 -0
  10. package/dist/anchored/PlacedAnchored.svelte.d.ts +4 -0
  11. package/dist/anchored/context.d.ts +31 -0
  12. package/dist/anchored/context.js +36 -0
  13. package/dist/anchored/props.d.ts +29 -0
  14. package/dist/anchored/props.js +1 -0
  15. package/dist/anchored.d.ts +12 -0
  16. package/dist/anchored.js +2 -0
  17. package/dist/annotation/AnnotationChrome.svelte +173 -0
  18. package/dist/annotation/AnnotationChrome.svelte.d.ts +11 -0
  19. package/dist/annotation/AnnotationDraftMenu.svelte +27 -0
  20. package/dist/annotation/AnnotationDraftMenu.svelte.d.ts +4 -0
  21. package/dist/annotation/AnnotationFrame.svelte +46 -0
  22. package/dist/annotation/AnnotationFrame.svelte.d.ts +15 -0
  23. package/dist/annotation/AnnotationLayer.svelte +241 -0
  24. package/dist/annotation/AnnotationLayer.svelte.d.ts +4 -0
  25. package/dist/annotation/AnnotationLook.svelte +67 -0
  26. package/dist/annotation/AnnotationLook.svelte.d.ts +21 -0
  27. package/dist/annotation/AnnotationMenu.svelte +47 -0
  28. package/dist/annotation/AnnotationMenu.svelte.d.ts +4 -0
  29. package/dist/annotation/AnnotationRotationBadge.svelte +52 -0
  30. package/dist/annotation/AnnotationRotationBadge.svelte.d.ts +4 -0
  31. package/dist/annotation/AnnotationScene.svelte +27 -0
  32. package/dist/annotation/AnnotationScene.svelte.d.ts +7 -0
  33. package/dist/annotation/FreeTextBox.svelte +55 -0
  34. package/dist/annotation/FreeTextBox.svelte.d.ts +9 -0
  35. package/dist/annotation/NativeDrawing.svelte +61 -0
  36. package/dist/annotation/NativeDrawing.svelte.d.ts +10 -0
  37. package/dist/annotation/StampGhost.svelte +79 -0
  38. package/dist/annotation/StampGhost.svelte.d.ts +7 -0
  39. package/dist/annotation/chrome-paint.svelte.d.ts +30 -0
  40. package/dist/annotation/chrome-paint.svelte.js +27 -0
  41. package/dist/annotation/props.d.ts +181 -0
  42. package/dist/annotation/props.js +1 -0
  43. package/dist/annotation/readers.svelte.d.ts +59 -0
  44. package/dist/annotation/readers.svelte.js +136 -0
  45. package/dist/annotation/state.d.ts +18 -0
  46. package/dist/annotation/state.js +20 -0
  47. package/dist/annotation/text-box.svelte.d.ts +27 -0
  48. package/dist/annotation/text-box.svelte.js +94 -0
  49. package/dist/annotation.d.ts +32 -0
  50. package/dist/annotation.js +31 -0
  51. package/dist/commands/readers.svelte.d.ts +50 -0
  52. package/dist/commands/readers.svelte.js +83 -0
  53. package/dist/commands.d.ts +9 -0
  54. package/dist/commands.js +9 -0
  55. package/dist/form/ButtonControl.svelte +38 -0
  56. package/dist/form/ButtonControl.svelte.d.ts +11 -0
  57. package/dist/form/ComboControl.svelte +52 -0
  58. package/dist/form/ComboControl.svelte.d.ts +11 -0
  59. package/dist/form/FieldPictures.svelte +145 -0
  60. package/dist/form/FieldPictures.svelte.d.ts +3 -0
  61. package/dist/form/FormFocusRing.svelte +25 -0
  62. package/dist/form/FormFocusRing.svelte.d.ts +8 -0
  63. package/dist/form/FormLayer.svelte +98 -0
  64. package/dist/form/FormLayer.svelte.d.ts +3 -0
  65. package/dist/form/ListControl.svelte +49 -0
  66. package/dist/form/ListControl.svelte.d.ts +11 -0
  67. package/dist/form/NativeListBox.svelte +57 -0
  68. package/dist/form/NativeListBox.svelte.d.ts +4 -0
  69. package/dist/form/SignatureControl.svelte +53 -0
  70. package/dist/form/SignatureControl.svelte.d.ts +11 -0
  71. package/dist/form/TextControl.svelte +107 -0
  72. package/dist/form/TextControl.svelte.d.ts +11 -0
  73. package/dist/form/ToggleControl.svelte +50 -0
  74. package/dist/form/ToggleControl.svelte.d.ts +11 -0
  75. package/dist/form/WidgetBox.svelte +82 -0
  76. package/dist/form/WidgetBox.svelte.d.ts +15 -0
  77. package/dist/form/props.d.ts +21 -0
  78. package/dist/form/props.js +1 -0
  79. package/dist/form/readers.svelte.d.ts +46 -0
  80. package/dist/form/readers.svelte.js +52 -0
  81. package/dist/form/widget.d.ts +16 -0
  82. package/dist/form/widget.js +20 -0
  83. package/dist/form.d.ts +11 -0
  84. package/dist/form.js +12 -0
  85. package/dist/history/readers.d.ts +22 -0
  86. package/dist/history/readers.js +21 -0
  87. package/dist/history.d.ts +10 -0
  88. package/dist/history.js +11 -0
  89. package/dist/i18n/readers.svelte.d.ts +32 -0
  90. package/dist/i18n/readers.svelte.js +30 -0
  91. package/dist/i18n.d.ts +8 -0
  92. package/dist/i18n.js +9 -0
  93. package/dist/index.d.ts +28 -0
  94. package/dist/index.js +28 -0
  95. package/dist/interaction/PagePointerSource.svelte +37 -0
  96. package/dist/interaction/PagePointerSource.svelte.d.ts +3 -0
  97. package/dist/interaction/readers.svelte.d.ts +26 -0
  98. package/dist/interaction/readers.svelte.js +47 -0
  99. package/dist/interaction.d.ts +11 -0
  100. package/dist/interaction.js +13 -0
  101. package/dist/link/LinkLayer.svelte +164 -0
  102. package/dist/link/LinkLayer.svelte.d.ts +4 -0
  103. package/dist/link/props.d.ts +17 -0
  104. package/dist/link/props.js +1 -0
  105. package/dist/link/readers.svelte.d.ts +18 -0
  106. package/dist/link/readers.svelte.js +38 -0
  107. package/dist/link.d.ts +11 -0
  108. package/dist/link.js +11 -0
  109. package/dist/measurement/readers.d.ts +44 -0
  110. package/dist/measurement/readers.js +46 -0
  111. package/dist/measurement.d.ts +12 -0
  112. package/dist/measurement.js +13 -0
  113. package/dist/metadata/readers.d.ts +22 -0
  114. package/dist/metadata/readers.js +22 -0
  115. package/dist/metadata.d.ts +12 -0
  116. package/dist/metadata.js +13 -0
  117. package/dist/page-edit/readers.d.ts +7 -0
  118. package/dist/page-edit/readers.js +11 -0
  119. package/dist/page-edit.d.ts +12 -0
  120. package/dist/page-edit.js +13 -0
  121. package/dist/page-view/PageView.svelte +192 -0
  122. package/dist/page-view/PageView.svelte.d.ts +4 -0
  123. package/dist/page-view/props.d.ts +32 -0
  124. package/dist/page-view/props.js +1 -0
  125. package/dist/page-view.d.ts +8 -0
  126. package/dist/page-view.js +7 -0
  127. package/dist/redaction/readers.d.ts +37 -0
  128. package/dist/redaction/readers.js +38 -0
  129. package/dist/redaction.d.ts +12 -0
  130. package/dist/redaction.js +13 -0
  131. package/dist/render/RenderLayer.svelte +116 -0
  132. package/dist/render/RenderLayer.svelte.d.ts +4 -0
  133. package/dist/render/TileImage.svelte +65 -0
  134. package/dist/render/TileImage.svelte.d.ts +11 -0
  135. package/dist/render/TilePlane.svelte +88 -0
  136. package/dist/render/TilePlane.svelte.d.ts +7 -0
  137. package/dist/render/props.d.ts +16 -0
  138. package/dist/render/props.js +1 -0
  139. package/dist/render/readers.svelte.d.ts +9 -0
  140. package/dist/render/readers.svelte.js +13 -0
  141. package/dist/render.d.ts +10 -0
  142. package/dist/render.js +10 -0
  143. package/dist/runtime/DocumentGate.svelte +26 -0
  144. package/dist/runtime/DocumentGate.svelte.d.ts +4 -0
  145. package/dist/runtime/DocumentScope.svelte +14 -0
  146. package/dist/runtime/DocumentScope.svelte.d.ts +4 -0
  147. package/dist/runtime/KernelProvider.svelte +33 -0
  148. package/dist/runtime/KernelProvider.svelte.d.ts +4 -0
  149. package/dist/runtime/SvgShapes.svelte +30 -0
  150. package/dist/runtime/SvgShapes.svelte.d.ts +8 -0
  151. package/dist/runtime/Viewer.svelte +124 -0
  152. package/dist/runtime/Viewer.svelte.d.ts +4 -0
  153. package/dist/runtime/binding.svelte.d.ts +33 -0
  154. package/dist/runtime/binding.svelte.js +71 -0
  155. package/dist/runtime/capability-handle.d.ts +6 -0
  156. package/dist/runtime/capability-handle.js +71 -0
  157. package/dist/runtime/dev.d.ts +10 -0
  158. package/dist/runtime/dev.js +23 -0
  159. package/dist/runtime/documents.svelte.d.ts +34 -0
  160. package/dist/runtime/documents.svelte.js +49 -0
  161. package/dist/runtime/page-layers.svelte.d.ts +20 -0
  162. package/dist/runtime/page-layers.svelte.js +40 -0
  163. package/dist/runtime/page.d.ts +10 -0
  164. package/dist/runtime/page.js +23 -0
  165. package/dist/runtime/props.d.ts +63 -0
  166. package/dist/runtime/props.js +1 -0
  167. package/dist/runtime/readers.svelte.d.ts +47 -0
  168. package/dist/runtime/readers.svelte.js +122 -0
  169. package/dist/runtime/state.svelte.d.ts +35 -0
  170. package/dist/runtime/state.svelte.js +90 -0
  171. package/dist/runtime/theme.d.ts +12 -0
  172. package/dist/runtime/theme.js +15 -0
  173. package/dist/runtime/values.svelte.d.ts +28 -0
  174. package/dist/runtime/values.svelte.js +51 -0
  175. package/dist/runtime.d.ts +26 -0
  176. package/dist/runtime.js +25 -0
  177. package/dist/search/SearchLayer.svelte +94 -0
  178. package/dist/search/SearchLayer.svelte.d.ts +4 -0
  179. package/dist/search/props.d.ts +11 -0
  180. package/dist/search/props.js +1 -0
  181. package/dist/search/readers.svelte.d.ts +41 -0
  182. package/dist/search/readers.svelte.js +40 -0
  183. package/dist/search.d.ts +11 -0
  184. package/dist/search.js +11 -0
  185. package/dist/selection/SelectionClipboard.svelte +35 -0
  186. package/dist/selection/SelectionClipboard.svelte.d.ts +4 -0
  187. package/dist/selection/SelectionHandles.svelte +192 -0
  188. package/dist/selection/SelectionHandles.svelte.d.ts +4 -0
  189. package/dist/selection/SelectionLayer.svelte +67 -0
  190. package/dist/selection/SelectionLayer.svelte.d.ts +3 -0
  191. package/dist/selection/SelectionMenu.svelte +36 -0
  192. package/dist/selection/SelectionMenu.svelte.d.ts +4 -0
  193. package/dist/selection/props.d.ts +26 -0
  194. package/dist/selection/props.js +1 -0
  195. package/dist/selection/readers.svelte.d.ts +31 -0
  196. package/dist/selection/readers.svelte.js +26 -0
  197. package/dist/selection.d.ts +16 -0
  198. package/dist/selection.js +18 -0
  199. package/dist/shell/readers.svelte.d.ts +40 -0
  200. package/dist/shell/readers.svelte.js +40 -0
  201. package/dist/shell/surface-focus.svelte.d.ts +16 -0
  202. package/dist/shell/surface-focus.svelte.js +33 -0
  203. package/dist/shell.d.ts +12 -0
  204. package/dist/shell.js +11 -0
  205. package/dist/signature/readers.svelte.d.ts +43 -0
  206. package/dist/signature/readers.svelte.js +46 -0
  207. package/dist/signature.d.ts +15 -0
  208. package/dist/signature.js +16 -0
  209. package/dist/stage/PageSurface.svelte +126 -0
  210. package/dist/stage/PageSurface.svelte.d.ts +18 -0
  211. package/dist/stage/Scrollbar.svelte +148 -0
  212. package/dist/stage/Scrollbar.svelte.d.ts +4 -0
  213. package/dist/stage/Stage.svelte +181 -0
  214. package/dist/stage/Stage.svelte.d.ts +4 -0
  215. package/dist/stage/StageScope.svelte +14 -0
  216. package/dist/stage/StageScope.svelte.d.ts +9 -0
  217. package/dist/stage/props.d.ts +71 -0
  218. package/dist/stage/props.js +1 -0
  219. package/dist/stage/readers.svelte.d.ts +39 -0
  220. package/dist/stage/readers.svelte.js +84 -0
  221. package/dist/stage/stage-scope.d.ts +18 -0
  222. package/dist/stage/stage-scope.js +35 -0
  223. package/dist/stage/two-way.svelte.d.ts +13 -0
  224. package/dist/stage/two-way.svelte.js +26 -0
  225. package/dist/stage.d.ts +17 -0
  226. package/dist/stage.js +15 -0
  227. package/dist/stamp/readers.svelte.d.ts +50 -0
  228. package/dist/stamp/readers.svelte.js +76 -0
  229. package/dist/stamp.d.ts +16 -0
  230. package/dist/stamp.js +18 -0
  231. package/dist/toolbar/DefaultCollapsed.svelte +39 -0
  232. package/dist/toolbar/DefaultCollapsed.svelte.d.ts +9 -0
  233. package/dist/toolbar/DefaultCommand.svelte +33 -0
  234. package/dist/toolbar/DefaultCommand.svelte.d.ts +8 -0
  235. package/dist/toolbar/DefaultGroupTrigger.svelte +39 -0
  236. package/dist/toolbar/DefaultGroupTrigger.svelte.d.ts +9 -0
  237. package/dist/toolbar/DefaultOverflowMenu.svelte +106 -0
  238. package/dist/toolbar/DefaultOverflowMenu.svelte.d.ts +9 -0
  239. package/dist/toolbar/DefaultOverflowTrigger.svelte +25 -0
  240. package/dist/toolbar/DefaultOverflowTrigger.svelte.d.ts +7 -0
  241. package/dist/toolbar/Measured.svelte +46 -0
  242. package/dist/toolbar/Measured.svelte.d.ts +11 -0
  243. package/dist/toolbar/NativeSlotSocket.svelte +43 -0
  244. package/dist/toolbar/NativeSlotSocket.svelte.d.ts +11 -0
  245. package/dist/toolbar/Toolbar.svelte +314 -0
  246. package/dist/toolbar/Toolbar.svelte.d.ts +4 -0
  247. package/dist/toolbar/paint.d.ts +3 -0
  248. package/dist/toolbar/paint.js +9 -0
  249. package/dist/toolbar/props.d.ts +48 -0
  250. package/dist/toolbar/props.js +1 -0
  251. package/dist/toolbar/strip.svelte.d.ts +14 -0
  252. package/dist/toolbar/strip.svelte.js +35 -0
  253. package/dist/toolbar/views.d.ts +14 -0
  254. package/dist/toolbar/views.js +1 -0
  255. package/dist/toolbar.d.ts +16 -0
  256. package/dist/toolbar.js +12 -0
  257. package/dist/view-manager/readers.d.ts +19 -0
  258. package/dist/view-manager/readers.js +17 -0
  259. package/dist/view-manager.d.ts +11 -0
  260. package/dist/view-manager.js +12 -0
  261. package/package.json +195 -3
@@ -0,0 +1,124 @@
1
+ <!--
2
+ The viewer: owns the kernel for as long as it is mounted, and gives it to everything inside.
3
+
4
+ The kernel is made in the browser only, when the viewer mounts (an effect, so server rendering
5
+ makes nothing). Its fallback shows from then on, with the kernel already in context, so a
6
+ loading screen can use workspace plugins. The content mounts once `start()` resolves, which
7
+ never touches the engine: the shell is alive while WASM compiles or the transport connects.
8
+ `initialDocuments` then open in the background; per-document loading is `<DocumentGate>`'s job.
9
+
10
+ Engine ownership follows the shape of `engine`: a function is the viewer's own (made on mount,
11
+ destroyed after the kernel on unmount), an instance is borrowed (warmed up, never destroyed).
12
+ -->
13
+ <script lang="ts">
14
+ import { untrack } from 'svelte';
15
+ import { createKernel, isLocalEngine, viewerSettingsOf } from '@embedpdf/core';
16
+ import type { Engine, EngineFactory, Kernel, ViewerSettings } from '@embedpdf/core';
17
+ import { browserClock } from '@embedpdf/web';
18
+ import { KernelBinding, setKernelHolder } from './binding.svelte.js';
19
+ import { isDev } from './dev.js';
20
+ import type { ViewerProps } from './props.js';
21
+
22
+ let {
23
+ engine,
24
+ plugins,
25
+ initialDocuments,
26
+ onReady,
27
+ identity,
28
+ scope,
29
+ accent,
30
+ page,
31
+ fallback,
32
+ error: renderError,
33
+ children,
34
+ }: ViewerProps = $props();
35
+
36
+ type Boot =
37
+ | { phase: 'booting'; binding: KernelBinding | null }
38
+ | { phase: 'ready'; binding: KernelBinding }
39
+ | { phase: 'error'; error: unknown };
40
+
41
+ let boot = $state.raw<Boot>({ phase: 'booting', binding: null });
42
+ setKernelHolder({
43
+ get binding() {
44
+ return boot.phase === 'error' ? null : boot.binding;
45
+ },
46
+ });
47
+
48
+ // The viewer's settings as the props give them: a prop left out is its default.
49
+ const settings = $derived<ViewerSettings>(viewerSettingsOf({ identity, scope, accent, page }));
50
+
51
+ // One kernel per mount. Everything is read untracked, so nothing a prop does later runs this
52
+ // again: `engine`, `plugins` and `initialDocuments` are read once.
53
+ $effect(() =>
54
+ untrack(() => {
55
+ const ownsEngine = typeof engine === 'function';
56
+ const created: Engine = ownsEngine ? (engine as EngineFactory)() : (engine as Engine);
57
+ if (isLocalEngine(created)) created.warmup();
58
+ let kernel: Kernel;
59
+ try {
60
+ kernel = createKernel({ engine: created, plugins, settings, clock: browserClock() });
61
+ } catch (error) {
62
+ // A plugin graph that can't be built shows `error`, not an exception mid-render.
63
+ boot = { phase: 'error', error };
64
+ if (ownsEngine) void created.destroy();
65
+ return;
66
+ }
67
+ const binding = new KernelBinding(kernel);
68
+ const documents = initialDocuments ?? [];
69
+ let alive = true;
70
+ boot = { phase: 'booting', binding };
71
+ kernel.start().then(
72
+ () => {
73
+ if (!alive) return; // unmounted while starting: open nothing
74
+ onReady?.(kernel);
75
+ boot = { phase: 'ready', binding };
76
+ // Every tab appears at once in order; the `active` entry (else the first) is selected,
77
+ // and a failure shows as that tab's status.
78
+ kernel.documents.openAll(documents);
79
+ },
80
+ (error: unknown) => {
81
+ if (alive) boot = { phase: 'error', error };
82
+ },
83
+ );
84
+ return () => {
85
+ alive = false;
86
+ binding.dispose();
87
+ // The kernel first (it closes every document handle), then the engine we own.
88
+ void kernel.destroy().then(() => {
89
+ if (ownsEngine) void created.destroy();
90
+ });
91
+ };
92
+ }),
93
+ );
94
+
95
+ // Later settings reach the kernel as they change; settings that didn't change change nothing.
96
+ $effect(() => {
97
+ const next = settings;
98
+ if (boot.phase !== 'error') boot.binding?.kernel.updateSettings(next);
99
+ });
100
+
101
+ // `engine` and `plugins` are read once: say so when they change after the viewer mounted.
102
+ const mounted = untrack(() => ({ engine, plugins }));
103
+ let warned = false;
104
+ $effect(() => {
105
+ if (warned || !isDev()) return;
106
+ if (engine !== mounted.engine || plugins !== mounted.plugins) {
107
+ warned = true;
108
+ console.warn(
109
+ '[embedpdf] <Viewer> reads engine and plugins once, when it mounts; a new value is ignored. ' +
110
+ 'To use other ones, mount a new <Viewer>, for example inside a {#key} block.',
111
+ );
112
+ }
113
+ });
114
+ </script>
115
+
116
+ {#if boot.phase === 'error'}
117
+ {@render renderError?.(boot.error)}
118
+ {:else if boot.binding}
119
+ {#if boot.phase === 'ready'}
120
+ {@render children?.()}
121
+ {:else}
122
+ {@render fallback?.()}
123
+ {/if}
124
+ {/if}
@@ -0,0 +1,4 @@
1
+ import type { ViewerProps } from './props.js';
2
+ declare const Viewer: import("svelte").Component<ViewerProps, {}, "">;
3
+ type Viewer = ReturnType<typeof Viewer>;
4
+ export default Viewer;
@@ -0,0 +1,33 @@
1
+ import type { Kernel } from '@embedpdf/core';
2
+ export declare class KernelBinding {
3
+ #private;
4
+ readonly kernel: Kernel;
5
+ constructor(kernel: Kernel);
6
+ /** Read inside a `$derived` or an effect to run it again after every kernel change. */
7
+ track(): void;
8
+ /** Stop following the kernel; the viewer calls it when it unmounts. */
9
+ dispose(): void;
10
+ }
11
+ /** What `<Viewer>` and `<KernelProvider>` provide: the binding, once the kernel exists. */
12
+ export interface KernelHolder {
13
+ readonly binding: KernelBinding | null;
14
+ }
15
+ /** For `<Viewer>` and `<KernelProvider>`: provide the kernel to everything inside it. */
16
+ export declare function setKernelHolder(holder: KernelHolder): void;
17
+ /**
18
+ * The binding of the nearest `<Viewer>` or `<KernelProvider>`. Everything inside one is created
19
+ * after its kernel, so the binding is there whenever a component inside asks.
20
+ */
21
+ export declare function useKernelBinding(): KernelBinding;
22
+ /**
23
+ * The kernel of the nearest `<Viewer>` or `<KernelProvider>`: for code that needs it whole
24
+ * (`onReady` gives it too).
25
+ */
26
+ export declare function useKernel(): Kernel;
27
+ /** For `<DocumentScope>`: bind a subtree to the document `id()` names. */
28
+ export declare function setDocumentScope(id: () => string): void;
29
+ /**
30
+ * The document the nearest `<DocumentScope>` names, as a function readers call each time (so a
31
+ * changed `id` reaches them), or one that answers null: follow the active document.
32
+ */
33
+ export declare function documentScopeOf(): () => string | null;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * The kernel as Svelte sees it, and the two contexts every reader starts from.
3
+ *
4
+ * The kernel has one change stream (`kernel.subscribe`). {@link KernelBinding} turns it into one
5
+ * signal: a version that moves on every change. A reader reads that version inside a `$derived`,
6
+ * so it computes again after any change and passes a value on only when it differs. The binding
7
+ * subscribes for the kernel's whole life, so a reader works the same inside a template, an effect
8
+ * or an event handler.
9
+ *
10
+ * `<Viewer>` puts the binding in context (`<KernelProvider>` too, for a kernel it doesn't own);
11
+ * `<DocumentScope>` puts the document a subtree talks to.
12
+ */
13
+ import { getContext, hasContext, setContext, untrack } from 'svelte';
14
+ export class KernelBinding {
15
+ kernel;
16
+ #version = $state(0);
17
+ #unsubscribe;
18
+ constructor(kernel) {
19
+ this.kernel = kernel;
20
+ // `untrack`: a change can be announced while a reaction runs (a verb called from an effect),
21
+ // and the version is a counter nobody reads to decide what to write.
22
+ this.#unsubscribe = kernel.subscribe(() => untrack(() => this.#version++));
23
+ }
24
+ /** Read inside a `$derived` or an effect to run it again after every kernel change. */
25
+ track() {
26
+ void this.#version;
27
+ }
28
+ /** Stop following the kernel; the viewer calls it when it unmounts. */
29
+ dispose() {
30
+ this.#unsubscribe();
31
+ }
32
+ }
33
+ const KERNEL = Symbol('embedpdf.kernel');
34
+ const DOCUMENT_SCOPE = Symbol('embedpdf.document-scope');
35
+ /** For `<Viewer>` and `<KernelProvider>`: provide the kernel to everything inside it. */
36
+ export function setKernelHolder(holder) {
37
+ setContext(KERNEL, holder);
38
+ }
39
+ /**
40
+ * The binding of the nearest `<Viewer>` or `<KernelProvider>`. Everything inside one is created
41
+ * after its kernel, so the binding is there whenever a component inside asks.
42
+ */
43
+ export function useKernelBinding() {
44
+ // Untracked: the binding never changes for a component's lifetime, so nothing re-runs on it.
45
+ const binding = hasContext(KERNEL)
46
+ ? untrack(() => getContext(KERNEL).binding)
47
+ : null;
48
+ if (!binding) {
49
+ throw new Error('[embedpdf] This must be used inside <Viewer> or <KernelProvider>.');
50
+ }
51
+ return binding;
52
+ }
53
+ /**
54
+ * The kernel of the nearest `<Viewer>` or `<KernelProvider>`: for code that needs it whole
55
+ * (`onReady` gives it too).
56
+ */
57
+ export function useKernel() {
58
+ return useKernelBinding().kernel;
59
+ }
60
+ /** For `<DocumentScope>`: bind a subtree to the document `id()` names. */
61
+ export function setDocumentScope(id) {
62
+ setContext(DOCUMENT_SCOPE, id);
63
+ }
64
+ const ACTIVE = () => null;
65
+ /**
66
+ * The document the nearest `<DocumentScope>` names, as a function readers call each time (so a
67
+ * changed `id` reaches them), or one that answers null: follow the active document.
68
+ */
69
+ export function documentScopeOf() {
70
+ return hasContext(DOCUMENT_SCOPE) ? getContext(DOCUMENT_SCOPE) : ACTIVE;
71
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * A handle over `resolve()`. Members are cached by name, so `stage.zoomIn` is the same function
3
+ * every time, and a namespace (`annotation.comments`) is itself a handle. A member that is a
4
+ * plain value is read as it is now.
5
+ */
6
+ export declare function capabilityHandle<T>(resolve: () => unknown, track: () => void): T;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * What `useStage()`, `useDocuments()` and every other `use<Plugin>()` return: a handle that is
3
+ * always the capability of the document in scope.
4
+ *
5
+ * A component calls `use<Plugin>()` once, when it is created, but the document it talks to can
6
+ * change (another tab becomes active, a `<DocumentScope id>` changes) and can be missing (none is
7
+ * open yet). So the handle resolves the capability again on every call. Without a ready document
8
+ * it reaches the plugin's stand-in (`standInFor` from `@embedpdf/core`), whose calls refuse with
9
+ * `not-ready`: a method that returns a promise rejects, the others throw.
10
+ *
11
+ * Reads follow the capability vocabulary (docs/conventions/naming.md): a member named `get*`,
12
+ * `list*`, `is*`, `has*` or `can*` reads state, so calling it in a template or a `$derived`
13
+ * subscribes to the kernel: `{#if annotation.canCreate()}` updates when the answer changes. Every
14
+ * other member is a verb or an event and subscribes to nothing: an effect that calls
15
+ * `stage.reveal(index)` runs again only when `index` changes.
16
+ */
17
+ import { untrack } from 'svelte';
18
+ import { isReadMember } from '@embedpdf/core';
19
+ /**
20
+ * A handle over `resolve()`. Members are cached by name, so `stage.zoomIn` is the same function
21
+ * every time, and a namespace (`annotation.comments`) is itself a handle. A member that is a
22
+ * plain value is read as it is now.
23
+ */
24
+ export function capabilityHandle(resolve, track) {
25
+ return memberHandle(resolve, track, null);
26
+ }
27
+ function memberHandle(resolve, track, call) {
28
+ const members = new Map();
29
+ // A function target, so a member can be called and can have members of its own.
30
+ const target = call ? function member() { } : {};
31
+ return new Proxy(target, {
32
+ apply: (_target, _this, args) => call(args),
33
+ has(_target, key) {
34
+ const value = untrack(resolve);
35
+ return (typeof value === 'object' || typeof value === 'function') && value !== null
36
+ ? key in value
37
+ : false;
38
+ },
39
+ get(_target, key) {
40
+ // Not a thenable, and inspecting it never resolves anything.
41
+ if (typeof key === 'symbol' || key === 'then')
42
+ return undefined;
43
+ const value = untrack(() => resolve()?.[key]);
44
+ if (typeof value !== 'function' && (typeof value !== 'object' || value === null)) {
45
+ return value;
46
+ }
47
+ let member = members.get(key);
48
+ if (!member) {
49
+ const resolveMember = () => resolve()[key];
50
+ member = memberHandle(resolveMember, track, (args) => invoke(resolve, key, args, track));
51
+ members.set(key, member);
52
+ }
53
+ return member;
54
+ },
55
+ });
56
+ }
57
+ /**
58
+ * Call `key` on what `resolve()` gives now, with it as `this`. `Reflect.apply`, not `.apply`: a
59
+ * stand-in's member answers every property, `apply` too.
60
+ */
61
+ function invoke(resolve, key, args, track) {
62
+ if (isReadMember(key)) {
63
+ track();
64
+ const owner = resolve();
65
+ return Reflect.apply(owner[key], owner, args);
66
+ }
67
+ return untrack(() => {
68
+ const owner = resolve();
69
+ return Reflect.apply(owner[key], owner, args);
70
+ });
71
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Whether this is a development build: `DEV` from `esm-env`, as Svelte and SvelteKit read it.
3
+ * The app's bundler picks it by its `development` or `production` condition, so in a production
4
+ * build this is `false` and the warnings behind it compile out.
5
+ */
6
+ export declare const isDev: () => boolean;
7
+ /** Warn once per key. No-op in production. */
8
+ export declare function devWarn(key: string, message: string): void;
9
+ /** Forget every warning, so a test can assert one fires again. */
10
+ export declare function resetDevWarnings(): void;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Development-time guardrails. Every warning fires once per process (keyed), says what is wrong
3
+ * and what to do instead, and compiles out of production builds ({@link isDev}).
4
+ */
5
+ import { DEV } from 'esm-env';
6
+ const warned = new Set();
7
+ /**
8
+ * Whether this is a development build: `DEV` from `esm-env`, as Svelte and SvelteKit read it.
9
+ * The app's bundler picks it by its `development` or `production` condition, so in a production
10
+ * build this is `false` and the warnings behind it compile out.
11
+ */
12
+ export const isDev = () => DEV;
13
+ /** Warn once per key. No-op in production. */
14
+ export function devWarn(key, message) {
15
+ if (!isDev() || warned.has(key))
16
+ return;
17
+ warned.add(key);
18
+ console.warn(`[embedpdf] ${message}`);
19
+ }
20
+ /** Forget every warning, so a test can assert one fires again. */
21
+ export function resetDevWarnings() {
22
+ warned.clear();
23
+ }
@@ -0,0 +1,34 @@
1
+ import type { DocumentInfo, DocumentsCapability, DocumentsState, EventHook, PageInfo, ViewerSettings } from '@embedpdf/core';
2
+ import { type CurrentValue } from './values.svelte.js';
3
+ /**
4
+ * The documents API: open, close, unlock, download, and the tabs. Inside a `<DocumentScope>`, the
5
+ * calls that leave out the document use that one, so `download()` without an id downloads the
6
+ * document in scope. What to show comes from `useDocument()` and `useDocumentsState()`.
7
+ */
8
+ export declare function useDocuments(): DocumentsCapability;
9
+ /**
10
+ * The document this component talks to: the one its `<DocumentScope>` names, or else the active
11
+ * one. Its `id`, `name`, `status`, `pageCount`, `hasUnsavedChanges`, and why it's locked or
12
+ * failed. With no document, an empty one that reads as still opening.
13
+ */
14
+ export declare function useDocument(): Readonly<DocumentInfo>;
15
+ export declare function useDocument<Selected>(select: (document: DocumentInfo) => Selected): CurrentValue<Selected>;
16
+ /** Every open document, in tab order (loading, locked and failed ones too), and the active one's id. */
17
+ export declare function useDocumentsState(): Readonly<DocumentsState>;
18
+ export declare function useDocumentsState<Selected>(select: (state: DocumentsState) => Selected): CurrentValue<Selected>;
19
+ /** Subscribe to one documents event while the component lives: `useDocumentsEvent((documents) => documents.onOpened, handler)`. */
20
+ export declare function useDocumentsEvent<T>(select: (documents: DocumentsCapability) => EventHook<T>, handler: (event: T) => void): void;
21
+ /**
22
+ * The pages of the document this component talks to, in order: each with its `ref`, `index`,
23
+ * `label`, size and rotation. Needs no Stage. The same array until a page is added, removed,
24
+ * moved or rotated; empty with no document.
25
+ */
26
+ export declare function usePageList(): CurrentValue<readonly PageInfo[]>;
27
+ /**
28
+ * The viewer's own settings (`<Viewer identity scope accent page>`), or the value `select` picks
29
+ * from them: the accent every part without a color of its own follows, and how pages look. What
30
+ * paints a page or an accent reads it here, through `paint()` from `@embedpdf/web`, so a CSS
31
+ * variable still wins.
32
+ */
33
+ export declare function useViewerSettings(): Readonly<ViewerSettings>;
34
+ export declare function useViewerSettings<Selected>(select: (settings: ViewerSettings) => Selected): CurrentValue<Selected>;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * The documents and the viewer's own settings, for components: the documents API, the document
3
+ * in scope, every open document, its pages, and the settings `<Viewer>` takes as props.
4
+ */
5
+ import { DocumentsToken, documentState, documentsState, shallowEqual } from '@embedpdf/core';
6
+ import { useKernelBinding } from './binding.svelte.js';
7
+ import { useCapability, useCapabilityEvent, useDocumentId, useKernelValue } from './readers.svelte.js';
8
+ import { declaredState, readRecord } from './state.svelte.js';
9
+ import { derivedValue } from './values.svelte.js';
10
+ /**
11
+ * The documents API: open, close, unlock, download, and the tabs. Inside a `<DocumentScope>`, the
12
+ * calls that leave out the document use that one, so `download()` without an id downloads the
13
+ * document in scope. What to show comes from `useDocument()` and `useDocumentsState()`.
14
+ */
15
+ export function useDocuments() {
16
+ return useCapability(DocumentsToken);
17
+ }
18
+ export function useDocument(select) {
19
+ const binding = useKernelBinding();
20
+ const whole = declaredState(binding, DocumentsToken, documentState.read, documentState.empty);
21
+ return readRecord(whole, Object.keys(documentState.empty), select);
22
+ }
23
+ export function useDocumentsState(select) {
24
+ const binding = useKernelBinding();
25
+ const whole = declaredState(binding, DocumentsToken, documentsState.read, documentsState.empty);
26
+ return readRecord(whole, Object.keys(documentsState.empty), select);
27
+ }
28
+ /** Subscribe to one documents event while the component lives: `useDocumentsEvent((documents) => documents.onOpened, handler)`. */
29
+ export function useDocumentsEvent(select, handler) {
30
+ useCapabilityEvent(DocumentsToken, select, handler);
31
+ }
32
+ const NO_PAGES = Object.freeze([]);
33
+ /**
34
+ * The pages of the document this component talks to, in order: each with its `ref`, `index`,
35
+ * `label`, size and rotation. Needs no Stage. The same array until a page is added, removed,
36
+ * moved or rotated; empty with no document.
37
+ */
38
+ export function usePageList() {
39
+ const documentId = useDocumentId();
40
+ return useKernelValue((kernel) => documentId.current ? kernel.documents.listPages(documentId.current) : NO_PAGES);
41
+ }
42
+ export function useViewerSettings(select) {
43
+ const binding = useKernelBinding();
44
+ const whole = derivedValue(() => {
45
+ binding.track();
46
+ return binding.kernel.getSettings();
47
+ }, shallowEqual);
48
+ return readRecord(whole, ['identity', 'scope', 'accent', 'page'], select);
49
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The Svelte side of `@embedpdf/web`'s page layers: a layer says, for as long as it lives, which
3
+ * part of its page it paints, and the render layer reads which parts are painted, to leave them
4
+ * out of the page's picture.
5
+ */
6
+ import { type PagePart, type PaintedParts } from '@embedpdf/web';
7
+ /**
8
+ * Say, for as long as this component lives, that it paints `part` of its page (`pageRef()`, the
9
+ * page context's `ref`; `null` while it paints nothing). Said as the component starts, so a render
10
+ * layer started alongside knows it by the time it's mounted.
11
+ */
12
+ export declare function usePaintsPagePart(pageRef: () => object | null, part: PagePart): void;
13
+ /**
14
+ * Which parts of the page (`pageRef()`, the page context's `ref`) the layers on it paint: `null`
15
+ * until this component is mounted, when every layer started with it has said what it paints, so
16
+ * the page's picture is never asked for with a part another layer is about to take.
17
+ */
18
+ export declare function usePaintedParts(pageRef: () => object): {
19
+ readonly current: PaintedParts | null;
20
+ };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * The Svelte side of `@embedpdf/web`'s page layers: a layer says, for as long as it lives, which
3
+ * part of its page it paints, and the render layer reads which parts are painted, to leave them
4
+ * out of the page's picture.
5
+ */
6
+ import { pageLayersOf } from '@embedpdf/web';
7
+ import { untrack } from 'svelte';
8
+ /**
9
+ * Say, for as long as this component lives, that it paints `part` of its page (`pageRef()`, the
10
+ * page context's `ref`; `null` while it paints nothing). Said as the component starts, so a render
11
+ * layer started alongside knows it by the time it's mounted.
12
+ */
13
+ export function usePaintsPagePart(pageRef, part) {
14
+ $effect.pre(() => {
15
+ const ref = pageRef();
16
+ if (!ref)
17
+ return;
18
+ return untrack(() => pageLayersOf(ref).paint(part));
19
+ });
20
+ }
21
+ /**
22
+ * Which parts of the page (`pageRef()`, the page context's `ref`) the layers on it paint: `null`
23
+ * until this component is mounted, when every layer started with it has said what it paints, so
24
+ * the page's picture is never asked for with a part another layer is about to take.
25
+ */
26
+ export function usePaintedParts(pageRef) {
27
+ let painted = $state.raw(null);
28
+ $effect(() => {
29
+ const layers = pageLayersOf(pageRef());
30
+ return untrack(() => {
31
+ painted = layers.painted();
32
+ return layers.subscribe(() => (painted = layers.painted()));
33
+ });
34
+ });
35
+ return {
36
+ get current() {
37
+ return painted;
38
+ },
39
+ };
40
+ }
@@ -0,0 +1,10 @@
1
+ import type { PageTransform } from '@embedpdf/core-geometry';
2
+ import type { PageViewDemand } from '@embedpdf/plugin-render/contract';
3
+ import type { PageContext } from '@embedpdf/web';
4
+ export { livePageContext, makePageContext } from '@embedpdf/web';
5
+ /** The page context. Its members are documented on `PageContext` in `@embedpdf/web`. */
6
+ export type PageContextValue = PageContext<PageTransform, PageViewDemand>;
7
+ /** For page surfaces (`<Stage>`'s pages, `<PageView>`): provide the page to everything inside. */
8
+ export declare function setPageContext(page: PageContextValue): void;
9
+ /** The page this layer draws on. Throws outside a page surface. */
10
+ export declare function usePage(): PageContextValue;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * The page context: what a layer knows about the page it draws on. A layer depends only on this,
3
+ * never on the Stage, so the same layer works on a Stage page and on a single `<PageView>`.
4
+ *
5
+ * A page surface provides it as a function that returns the current value; `usePage()` gives a
6
+ * layer an object that reads through that function on every access, so `page.transform` in a
7
+ * template or a `$derived` follows the zoom.
8
+ */
9
+ import { getContext, hasContext, setContext } from 'svelte';
10
+ // Built by `makePageContext`, and kept current by `livePageContext`, from `@embedpdf/web`.
11
+ export { livePageContext, makePageContext } from '@embedpdf/web';
12
+ const PAGE = Symbol('embedpdf.page');
13
+ /** For page surfaces (`<Stage>`'s pages, `<PageView>`): provide the page to everything inside. */
14
+ export function setPageContext(page) {
15
+ setContext(PAGE, page);
16
+ }
17
+ /** The page this layer draws on. Throws outside a page surface. */
18
+ export function usePage() {
19
+ if (!hasContext(PAGE)) {
20
+ throw new Error('[embedpdf] usePage() must be used inside <PageView> or a <Stage> page.');
21
+ }
22
+ return getContext(PAGE);
23
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * The props of the runtime's components: `<Viewer>`, `<KernelProvider>`, `<DocumentGate>` and
3
+ * `<DocumentScope>`.
4
+ */
5
+ import type { Snippet } from 'svelte';
6
+ import type { AnyPlugin, Engine, EngineFactory, FailedDocumentInfo, Identity, InitialDocument, Kernel, LockedDocumentInfo, ViewerPageSettings } from '@embedpdf/core';
7
+ export interface ViewerProps {
8
+ /**
9
+ * The engine, as an instance or a function. An instance (`{engine}`) is borrowed: the viewer
10
+ * uses it and never destroys it, so one engine made at module scope serves every viewer; a
11
+ * local engine is warmed up on mount. A function (`engine={() => localEngine()}`) is the
12
+ * viewer's own: called on mount, destroyed on unmount. Read once, when the viewer mounts.
13
+ */
14
+ engine: Engine | EngineFactory;
15
+ /** The plugins. Read once, when the viewer mounts. */
16
+ plugins: AnyPlugin[];
17
+ /** Documents to open on startup, with optional tab names. Read once. */
18
+ initialDocuments?: InitialDocument[];
19
+ /**
20
+ * Called once the viewer has started, before the content mounts and before `initialDocuments`
21
+ * open: the door for code that isn't a component (register commands, subscribe to events).
22
+ */
23
+ onReady?: (kernel: Kernel) => void;
24
+ /**
25
+ * Who the user is, for every document opened without an `identity` of its own. Documents
26
+ * opened after a change use the new value; open ones keep theirs. The local engine only: the
27
+ * cloud engine reads it from the document's token.
28
+ */
29
+ identity?: Identity;
30
+ /**
31
+ * What the user may do, as permissions, in every document opened without a `scope` of its own.
32
+ * Left out, they may do everything. Changes reach the documents opened after them.
33
+ */
34
+ scope?: readonly string[];
35
+ /** The color every part without a color of its own follows. CSS `--epdf-accent` wins over it. */
36
+ accent?: string;
37
+ /** How pages look: `background` before the picture arrives, and the `shadow` under each page. */
38
+ page?: Partial<ViewerPageSettings>;
39
+ /** Shown while the viewer starts. */
40
+ fallback?: Snippet;
41
+ /** Shown when the viewer couldn't start, with why. Without it, a failed start shows nothing. */
42
+ error?: Snippet<[error: unknown]>;
43
+ children?: Snippet;
44
+ }
45
+ export interface KernelProviderProps {
46
+ /** The kernel everything inside reads. Read once: a new kernel takes a new provider. */
47
+ kernel: Kernel;
48
+ children?: Snippet;
49
+ }
50
+ export interface DocumentGateProps {
51
+ /** Shown while this subtree has no document: none is open, or it's still opening. */
52
+ fallback?: Snippet;
53
+ /** Shown while the document waits for its password; `fallback` without it. */
54
+ locked?: Snippet<[document: LockedDocumentInfo]>;
55
+ /** Shown when the document couldn't be opened, with why; `fallback` without it. */
56
+ error?: Snippet<[document: FailedDocumentInfo]>;
57
+ children?: Snippet;
58
+ }
59
+ export interface DocumentScopeProps {
60
+ /** The document everything inside talks to. */
61
+ id: string;
62
+ children?: Snippet;
63
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,47 @@
1
+ import type { CapabilityToken, EventHook, Kernel } from '@embedpdf/core';
2
+ import { type CurrentValue, type MaybeGetter } from './values.svelte.js';
3
+ /** Equal when the two arrays hold the same items in the same order. */
4
+ export declare const shallowArray: <T>(left: readonly T[], right: readonly T[]) => boolean;
5
+ /**
6
+ * A value derived from the kernel, computed again after every kernel change and passed on only
7
+ * when `isEqual` says it changed.
8
+ */
9
+ export declare function useKernelValue<R>(select: (kernel: Kernel) => R, isEqual?: (left: R, right: R) => boolean): CurrentValue<R>;
10
+ /** The active document's id, or null with none open. */
11
+ export declare function useActiveDocumentId(): CurrentValue<string | null>;
12
+ /** The document the nearest `<DocumentScope>` names, or null when this subtree follows the active one. */
13
+ export declare function useDocumentScope(): CurrentValue<string | null>;
14
+ /** The document this subtree talks to: the nearest `<DocumentScope>`'s, else the active one. */
15
+ export declare function useDocumentId(): CurrentValue<string | null>;
16
+ /**
17
+ * A plugin's capability, as a handle that is always the capability of the document in scope
18
+ * (see `./capability-handle.ts`). Outside a ready document a document plugin's calls refuse with
19
+ * `not-ready` (a method that returns a promise rejects), and its settings calls still work. A token no plugin provides throws now: a setup
20
+ * mistake. The token may be a function, for a component whose token is a prop.
21
+ */
22
+ export declare function useCapability<T>(token: MaybeGetter<CapabilityToken<T>>): T;
23
+ /**
24
+ * The capability itself, or null while the token can't resolve (no plugin, no document, or a
25
+ * document that isn't ready yet). The object is the plugin's own, so it can be handed to code
26
+ * that keeps it, such as an effect that registers something with it.
27
+ */
28
+ export declare function useOptionalCapability<T>(token: MaybeGetter<CapabilityToken<T>>): CurrentValue<T | null>;
29
+ /**
30
+ * A value selected from a capability. Strict: while the token can't resolve, reading it throws
31
+ * the kernel's reason (no document, the document is loading), for code that knows a document
32
+ * exists, such as anything inside a `<DocumentGate>`. {@link useOptionalSelector} is its total twin.
33
+ */
34
+ export declare function useSelector<C, R>(token: MaybeGetter<CapabilityToken<C>>, select: (capability: C) => R, isEqual?: (left: R, right: R) => boolean): CurrentValue<R>;
35
+ /**
36
+ * A value selected from a capability, or `fallback` while the token can't resolve: for chrome
37
+ * that stays mounted while no document is open (a zoom readout). A read through a capability
38
+ * whose document closed a moment ago gives `fallback` too.
39
+ */
40
+ export declare function useOptionalSelector<C, R>(token: MaybeGetter<CapabilityToken<C>>, select: (capability: C) => R, fallback: R, isEqual?: (left: R, right: R) => boolean): CurrentValue<R>;
41
+ /**
42
+ * Subscribe to one of a capability's events while the component lives:
43
+ * `useCapabilityEvent(StageToken, (stage) => stage.onZoomChanged, handler)`. It subscribes again
44
+ * when the document in scope changes, and not at all without one. Events say what happened;
45
+ * the current value is a state reader's.
46
+ */
47
+ export declare function useCapabilityEvent<C, T>(token: MaybeGetter<CapabilityToken<C>>, select: (capability: C) => EventHook<T>, handler: (event: T) => void): void;