@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,38 @@
1
+ import { RedactionToken, redactionState } from '@embedpdf/plugin-redaction';
2
+ import { shallowArray, useCapability, useCapabilityEvent, useOptionalSelector, } from '../runtime/readers.svelte.js';
3
+ import { settingsReader, stateReader } from '../runtime/state.svelte.js';
4
+ import { valueOf } from '../runtime/values.svelte.js';
5
+ /**
6
+ * The redaction API (marking, the pending marks, applying them) of the nearest
7
+ * `<DocumentScope>`'s document, else the active one. Outside a ready document every method throws
8
+ * `not-ready`.
9
+ */
10
+ export function useRedaction() {
11
+ return useCapability(RedactionToken);
12
+ }
13
+ /** Subscribe to one redaction event while the component lives: `useRedactionEvent((redaction) => redaction.onApplied, handler)`. */
14
+ export function useRedactionEvent(select, handler) {
15
+ useCapabilityEvent(RedactionToken, select, handler);
16
+ }
17
+ /**
18
+ * The redaction state: how many marks wait, whether marks are being applied, and the last apply's
19
+ * result (the page's State table, declared once in `redactionState`), as a reactive object
20
+ * (`state.pendingCount`). With a selector, the value it picks as `{ current }`. Empty without a
21
+ * document.
22
+ *
23
+ * Typed through the declaration, so the published types name it from `@embedpdf/plugin-redaction`, a
24
+ * dependency of this package, and not from the engine package `lastResult`'s type comes from, which
25
+ * isn't one.
26
+ */
27
+ export const useRedactionState = stateReader(redactionState);
28
+ /** The redaction settings (`overlay`), with or without a document. */
29
+ export const useRedactionSettings = settingsReader(RedactionToken);
30
+ const NO_MARKS = Object.freeze([]);
31
+ /**
32
+ * The marks waiting to be applied, in page order, or one page's (its ref or its index; a function
33
+ * to follow a prop), as `{ current }`. The plugin's lists keep their identity until the marks
34
+ * change, so a list redraws only then. Empty without a document.
35
+ */
36
+ export function usePendingRedactions(filter) {
37
+ return useOptionalSelector(RedactionToken, (redaction) => redaction.listPending(valueOf(filter)), NO_MARKS, shallowArray);
38
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @embedpdf/svelte/redaction — marking content and removing it for good.
3
+ *
4
+ * Marking rides the annotation plugin (the composed `redact` tool draws on its
5
+ * `<AnnotationLayer>`); these readers surface the workflow around it:
6
+ *
7
+ * const redaction = useRedaction();
8
+ * const state = useRedactionState(); // state.pendingCount, state.applying
9
+ * await redaction.applyAll(); // irreversible: confirm first
10
+ */
11
+ export * from '@embedpdf/plugin-redaction';
12
+ export { usePendingRedactions, useRedaction, useRedactionEvent, useRedactionSettings, useRedactionState, } from './redaction/readers.js';
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @embedpdf/svelte/redaction — marking content and removing it for good.
3
+ *
4
+ * Marking rides the annotation plugin (the composed `redact` tool draws on its
5
+ * `<AnnotationLayer>`); these readers surface the workflow around it:
6
+ *
7
+ * const redaction = useRedaction();
8
+ * const state = useRedactionState(); // state.pendingCount, state.applying
9
+ * await redaction.applyAll(); // irreversible: confirm first
10
+ */
11
+ // Registration travels with the UI.
12
+ export * from '@embedpdf/plugin-redaction';
13
+ export { usePendingRedactions, useRedaction, useRedactionEvent, useRedactionSettings, useRedactionState, } from './redaction/readers.js';
@@ -0,0 +1,116 @@
1
+ <!--
2
+ The page raster, as two planes:
3
+
4
+ - the base plane: one whole-page image at the plugin's resolved render points (the exact
5
+ settled demand capped at the pixel budget on a local engine, the advertised ladder on a
6
+ cloud deployment). Always there; the instant backdrop.
7
+ - the tile plane: the plugin's paint plan above it, which engages only when the view wants
8
+ more pixels than the base may spend. A thumbnail-sized demand engages nothing.
9
+
10
+ The layer only paints: every decision (which pixels, when, what to keep) is the render
11
+ plugin's. Anything mid-gesture is scaled by CSS until the plugin hands down new pixels.
12
+ -->
13
+ <script lang="ts">
14
+ import { untrack } from 'svelte';
15
+ import { RenderToken } from '@embedpdf/plugin-render/contract/host';
16
+ import { partsDrawnTwice, pictureLayerOptionsOf } from '@embedpdf/web';
17
+ import { devWarn } from '../runtime/dev.js';
18
+ import { usePage } from '../runtime/page.js';
19
+ import { usePaintedParts } from '../runtime/page-layers.svelte.js';
20
+ import { useOptionalCapability, useOptionalSelector } from '../runtime/readers.svelte.js';
21
+ import type { RenderLayerProps } from './props.js';
22
+ import TilePlane from './TilePlane.svelte';
23
+
24
+ let { annotations, formFields, tiles = true }: RenderLayerProps = $props();
25
+
26
+ const page = usePage();
27
+ // The layer is a host of the render plugin: it paints conformed sources and drives a view's
28
+ // tile demand. The host lens is the same runtime token, typed wider.
29
+ const render = useOptionalCapability(RenderToken);
30
+ // The same object until a setting it reads changes.
31
+ const settings = useOptionalSelector(
32
+ RenderToken,
33
+ (renderer) => renderer.getPaintSettings(),
34
+ null,
35
+ );
36
+
37
+ const painted = usePaintedParts(() => page.ref);
38
+ const may = useOptionalSelector(RenderToken, (renderer) => renderer.getLayerRights(), null);
39
+ const parts = $derived({ annotations, formFields });
40
+ /** The parts the picture draws; `null` until the page's layers have said what they paint. */
41
+ const layers = $derived(
42
+ painted.current && may.current
43
+ ? pictureLayerOptionsOf(painted.current, parts, may.current)
44
+ : null,
45
+ );
46
+ $effect(() => {
47
+ if (painted.current && partsDrawnTwice(painted.current, parts).length > 0) {
48
+ devWarn(
49
+ 'render-layer-draws-what-a-layer-paints',
50
+ '<RenderLayer annotations> or <RenderLayer formFields> draws what an <AnnotationLayer> ' +
51
+ 'or a <FormLayer> on the page paints too, so it shows twice. Leave the prop out: the ' +
52
+ 'picture leaves out what a layer paints.',
53
+ );
54
+ }
55
+ });
56
+
57
+ // The raster's identity: its conformed width, the parts it draws and the epoch. Under a
58
+ // ladder it moves only at rung crossings; on a local engine it follows the demand up to the
59
+ // budget, so the deep-zoom backdrop never fetches again.
60
+ const sourceKey = useOptionalSelector(
61
+ RenderToken,
62
+ (renderer) =>
63
+ layers
64
+ ? renderer.getSourceKey(page.ref, { scale: page.transform.renderScale, ...layers })
65
+ : null,
66
+ null,
67
+ );
68
+
69
+ let image: HTMLImageElement | undefined;
70
+
71
+ $effect(() => {
72
+ const renderer = render.current;
73
+ const key = sourceKey.current;
74
+ const ref = page.ref;
75
+ const drawn = layers;
76
+ if (!renderer || key === null || !drawn) return;
77
+ const controller = new AbortController();
78
+ let revoke: (() => void) | undefined;
79
+ // Any scale that maps to this key gives this key's request: the plugin conforms it.
80
+ const options = untrack(() => ({
81
+ scale: page.transform.renderScale,
82
+ ...drawn,
83
+ view: page.view,
84
+ }));
85
+ void (async () => {
86
+ try {
87
+ const raster = await renderer.renderSource(ref, { ...options, signal: controller.signal });
88
+ const objectUrl = await raster.objectUrl().abortWith(controller.signal);
89
+ if (controller.signal.aborted) {
90
+ objectUrl.revoke();
91
+ return;
92
+ }
93
+ revoke = objectUrl.revoke;
94
+ // The source is set on a stable element: the browser keeps the old picture until the new
95
+ // one decodes, and never asks for the old URL again, so revoking it on cleanup is safe.
96
+ if (image) image.src = objectUrl.url;
97
+ } catch {
98
+ // Cancelled (the camera moved, the layer unmounted) or the render failed.
99
+ }
100
+ })();
101
+ return () => {
102
+ controller.abort();
103
+ revoke?.();
104
+ };
105
+ });
106
+ </script>
107
+
108
+ <img
109
+ bind:this={image}
110
+ alt=""
111
+ draggable="false"
112
+ style="position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none"
113
+ />
114
+ {#if tiles && settings.current?.tiles && layers}
115
+ <TilePlane {layers} />
116
+ {/if}
@@ -0,0 +1,4 @@
1
+ import type { RenderLayerProps } from './props.js';
2
+ declare const RenderLayer: import("svelte").Component<RenderLayerProps, {}, "">;
3
+ type RenderLayer = ReturnType<typeof RenderLayer>;
4
+ export default RenderLayer;
@@ -0,0 +1,65 @@
1
+ <!--
2
+ One tile: its place, and the shared browser binding (`bindPaintedImage`), which hides the
3
+ image until it's complete, reports it painted after its first chance to show, and reports the
4
+ inverse when it leaves the DOM.
5
+ -->
6
+ <script lang="ts" module>
7
+ let warnedTileSize = false;
8
+ </script>
9
+
10
+ <script lang="ts">
11
+ import { untrack } from 'svelte';
12
+ import type { TilePaintSource } from '@embedpdf/plugin-render/contract/host';
13
+ import { bindPaintedImage } from '@embedpdf/web';
14
+
15
+ let {
16
+ source,
17
+ viewScale,
18
+ onPainted,
19
+ onUnpainted,
20
+ }: {
21
+ source: TilePaintSource;
22
+ /** View pixels per page point: tiles are placed in view pixels. */
23
+ viewScale: number;
24
+ onPainted: () => void;
25
+ onUnpainted: () => void;
26
+ } = $props();
27
+
28
+ let image: HTMLImageElement | undefined;
29
+
30
+ // Bound per bitmap: the handle is the tile's identity. A new plan hands the same tile a new
31
+ // `source` object; only a new handle binds again (a new URL, hidden until it has loaded).
32
+ const handle = $derived(source.handle);
33
+ $effect(() => {
34
+ const picture = handle;
35
+ if (!image) return;
36
+ return untrack(() => bindPaintedImage(image!, picture, { onPainted, onUnpainted }));
37
+ });
38
+
39
+ /** A raster whose size disagrees with its box would be stretched into place: say so once. */
40
+ function checkSize(event: Event) {
41
+ const naturalWidth = (event.currentTarget as HTMLImageElement).naturalWidth;
42
+ if (naturalWidth <= 0 || warnedTileSize) return;
43
+ const expected = Math.round(source.rect.width * source.scale);
44
+ if (Math.abs(naturalWidth - expected) > 1) {
45
+ warnedTileSize = true;
46
+ console.warn(
47
+ `[render] tile bitmap ${naturalWidth}px wide does not match its rect ` +
48
+ `(expected ~${expected}px) — stale raster identity? key=${source.key}`,
49
+ );
50
+ }
51
+ }
52
+ </script>
53
+
54
+ <img
55
+ bind:this={image}
56
+ alt=""
57
+ draggable="false"
58
+ onload={checkSize}
59
+ style:position="absolute"
60
+ style:left="{source.rect.x * viewScale}px"
61
+ style:top="{source.rect.y * viewScale}px"
62
+ style:width="{source.rect.width * viewScale}px"
63
+ style:height="{source.rect.height * viewScale}px"
64
+ style:z-index={source.z}
65
+ />
@@ -0,0 +1,11 @@
1
+ import type { TilePaintSource } from '@embedpdf/plugin-render/contract/host';
2
+ type $$ComponentProps = {
3
+ source: TilePaintSource;
4
+ /** View pixels per page point: tiles are placed in view pixels. */
5
+ viewScale: number;
6
+ onPainted: () => void;
7
+ onUnpainted: () => void;
8
+ };
9
+ declare const TileImage: import("svelte").Component<$$ComponentProps, {}, "">;
10
+ type TileImage = ReturnType<typeof TileImage>;
11
+ export default TileImage;
@@ -0,0 +1,88 @@
1
+ <!--
2
+ The sharp plane above the base: the render plugin's paint plan for this view and page, as
3
+ keyed images. Each tile reports itself painted after its first chance to show (and the inverse
4
+ when it leaves), so older, coarser tiles are released only once their replacement shows.
5
+
6
+ Tiles are placed in view pixels, never in page points under a scaled container: browsers round
7
+ layout lengths to 1/64 of a CSS pixel before transforms apply, and under a large zoom transform
8
+ that rounding becomes visible seams. In view pixels it stays 1/64 of a pixel at every zoom.
9
+ -->
10
+ <script lang="ts">
11
+ import { untrack } from 'svelte';
12
+ import {
13
+ RenderToken,
14
+ type PageLayerOptions,
15
+ type ViewDemand,
16
+ } from '@embedpdf/plugin-render/contract/host';
17
+ import { usePage } from '../runtime/page.js';
18
+ import { useKernelValue, useOptionalCapability } from '../runtime/readers.svelte.js';
19
+ import TileImage from './TileImage.svelte';
20
+
21
+ let { layers }: { layers: PageLayerOptions } = $props();
22
+
23
+ const page = usePage();
24
+ const render = useOptionalCapability(RenderToken);
25
+
26
+ // Which page and which view this plane plans for. The page context is a new value whenever the
27
+ // camera changes it; these change only when the page or the view does (a `<PageView>` can be
28
+ // given another page), so the handle and the page's claim on it follow ownership, never the
29
+ // camera.
30
+ const pageRef = $derived(page.ref);
31
+ const viewId = $derived(page.view);
32
+
33
+ // This view's tile surface: planning state is per view and page, so a thumbnail rail's demand
34
+ // can't disturb the main view's tiles. Reference-counted: one `dispose` per `createViewDemand`.
35
+ let view = $state.raw<ViewDemand | null>(null);
36
+ $effect(() => {
37
+ const renderer = render.current;
38
+ const id = viewId;
39
+ if (!renderer) return;
40
+ const created = untrack(() => renderer.createViewDemand(id));
41
+ view = created;
42
+ return () => created.dispose();
43
+ });
44
+
45
+ // Demand in, plan out: setting the demand is the one call that schedules fetches and plans
46
+ // again. Before the DOM updates, and again on every camera frame (the page's view demand reads
47
+ // the frame), so a move plans before the browser paints.
48
+ $effect.pre(() => {
49
+ const surface = view;
50
+ if (!surface) return;
51
+ const demand = page.getViewDemand?.() ?? { desiredDeviceWidth: page.transform.deviceWidth };
52
+ const ref = pageRef;
53
+ const drawn = layers;
54
+ untrack(() => surface.setDemand(ref, demand, drawn));
55
+ });
56
+
57
+ // The same object until the demand, an epoch or an arriving tile changes it.
58
+ const plan = useKernelValue(() => view?.getPlan(pageRef) ?? null);
59
+
60
+ // Leaving the page (another page, or the plane unmounts) stops its in-flight fetches; the bytes
61
+ // already here stay cached.
62
+ $effect(() => {
63
+ const surface = view;
64
+ const ref = pageRef;
65
+ if (!surface) return;
66
+ return () => surface.release(ref);
67
+ });
68
+ </script>
69
+
70
+ {#if plan.current && plan.current.paint.length > 0}
71
+ <!-- A stacking context of its own: tiles carry z-index ranks (coarse under fine) while two
72
+ generations mix, mid-zoom, and without it those ranks would paint above the annotations,
73
+ the page chrome and the menus. -->
74
+ <div
75
+ style="position: absolute; left: 0; top: 0; pointer-events: none; isolation: isolate"
76
+ style:width="{page.transform.contentWidth}px"
77
+ style:height="{page.transform.contentHeight}px"
78
+ >
79
+ {#each plan.current.paint as source (source.key)}
80
+ <TileImage
81
+ {source}
82
+ viewScale={page.transform.viewScale}
83
+ onPainted={() => view?.markPainted(pageRef, source.key)}
84
+ onUnpainted={() => view?.markUnpainted(pageRef, source.key)}
85
+ />
86
+ {/each}
87
+ </div>
88
+ {/if}
@@ -0,0 +1,7 @@
1
+ import { type PageLayerOptions } from '@embedpdf/plugin-render/contract/host';
2
+ type $$ComponentProps = {
3
+ layers: PageLayerOptions;
4
+ };
5
+ declare const TilePlane: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type TilePlane = ReturnType<typeof TilePlane>;
7
+ export default TilePlane;
@@ -0,0 +1,16 @@
1
+ /** The props of `<RenderLayer>`. */
2
+ export interface RenderLayerProps {
3
+ /**
4
+ * Draw the annotations into the page's picture (`true`) or leave them out (`false`). Left
5
+ * unset, the picture leaves them to an `<AnnotationLayer>` on the page, and otherwise draws them
6
+ * when the user may read them.
7
+ */
8
+ annotations?: boolean;
9
+ /** The same for the form fields, which a `<FormLayer>` paints. */
10
+ formFields?: boolean;
11
+ /**
12
+ * Mount the tile plane (default true). Whether it spends anything is the render plugin's
13
+ * arithmetic: leave it on, and pass false only for a view that must never tile.
14
+ */
15
+ tiles?: boolean;
16
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ /** The render plugin's readers: its API, its settings and its events. */
2
+ import type { EventHook } from '@embedpdf/core';
3
+ import type { RenderCapability } from '@embedpdf/plugin-render';
4
+ /** The render API (`renderPage`, `renderThumbnail`, invalidation, settings), for app code. */
5
+ export declare function useRender(): RenderCapability;
6
+ /** The render settings (`fullPage`, `tiles`, `format`, …), with or without a document. */
7
+ export declare const useRenderSettings: import("../index.js").SettingsReader<import("@embedpdf/plugin-render").RenderSettings & object>;
8
+ /** Subscribe to one render event while the component lives: `useRenderEvent((render) => render.onInvalidated, handler)`. */
9
+ export declare function useRenderEvent<T>(select: (render: RenderCapability) => EventHook<T>, handler: (event: T) => void): void;
@@ -0,0 +1,13 @@
1
+ import { RenderToken } from '@embedpdf/plugin-render';
2
+ import { useCapability, useCapabilityEvent } from '../runtime/readers.svelte.js';
3
+ import { settingsReader } from '../runtime/state.svelte.js';
4
+ /** The render API (`renderPage`, `renderThumbnail`, invalidation, settings), for app code. */
5
+ export function useRender() {
6
+ return useCapability(RenderToken);
7
+ }
8
+ /** The render settings (`fullPage`, `tiles`, `format`, …), with or without a document. */
9
+ export const useRenderSettings = settingsReader(RenderToken);
10
+ /** Subscribe to one render event while the component lives: `useRenderEvent((render) => render.onInvalidated, handler)`. */
11
+ export function useRenderEvent(select, handler) {
12
+ useCapabilityEvent(RenderToken, select, handler);
13
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @embedpdf/svelte/render — the page raster.
3
+ *
4
+ * `<RenderLayer>` draws a page's picture inside a `<Stage>` page or a `<PageView>`; the readers
5
+ * are the render plugin's API, settings and events, for thumbnails and previews of your own.
6
+ */
7
+ export * from '@embedpdf/plugin-render';
8
+ export { default as RenderLayer } from './render/RenderLayer.svelte';
9
+ export type { RenderLayerProps } from './render/props.js';
10
+ export { useRender, useRenderEvent, useRenderSettings } from './render/readers.svelte.js';
package/dist/render.js ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @embedpdf/svelte/render — the page raster.
3
+ *
4
+ * `<RenderLayer>` draws a page's picture inside a `<Stage>` page or a `<PageView>`; the readers
5
+ * are the render plugin's API, settings and events, for thumbnails and previews of your own.
6
+ */
7
+ // Registration travels with the UI.
8
+ export * from '@embedpdf/plugin-render';
9
+ export { default as RenderLayer } from './render/RenderLayer.svelte';
10
+ export { useRender, useRenderEvent, useRenderSettings } from './render/readers.svelte.js';
@@ -0,0 +1,26 @@
1
+ <!--
2
+ Renders its content only while this subtree has a ready document: the structural way to say
3
+ "this UI is defined over a document". Workspace UI (toolbars, commands, translations) lives
4
+ outside the gate; document UI (the Stage, panels, page chrome) inside it. A document that waits
5
+ for its password, or failed, shows `locked` or `error` with it, or else `fallback`.
6
+ `<DocumentScope>` picks which document; this decides whether there is one.
7
+ -->
8
+ <script lang="ts">
9
+ import type { FailedDocumentInfo, LockedDocumentInfo } from '@embedpdf/core';
10
+ import { useDocument } from './documents.svelte.js';
11
+ import type { DocumentGateProps } from './props.js';
12
+
13
+ let { fallback, locked, error, children }: DocumentGateProps = $props();
14
+
15
+ const document = useDocument((info) => info);
16
+ </script>
17
+
18
+ {#if document.current.status === 'ready'}
19
+ {@render children?.()}
20
+ {:else if document.current.status === 'locked' && locked}
21
+ {@render locked(document.current as LockedDocumentInfo)}
22
+ {:else if document.current.status === 'error' && error}
23
+ {@render error(document.current as FailedDocumentInfo)}
24
+ {:else}
25
+ {@render fallback?.()}
26
+ {/if}
@@ -0,0 +1,4 @@
1
+ import type { DocumentGateProps } from './props.js';
2
+ declare const DocumentGate: import("svelte").Component<DocumentGateProps, {}, "">;
3
+ type DocumentGate = ReturnType<typeof DocumentGate>;
4
+ export default DocumentGate;
@@ -0,0 +1,14 @@
1
+ <!--
2
+ Binds everything inside to one document, for panes and side-by-side comparison: the readers and
3
+ `use<Plugin>()` handles inside talk to `id`, not the active document.
4
+ -->
5
+ <script lang="ts">
6
+ import { setDocumentScope } from './binding.svelte.js';
7
+ import type { DocumentScopeProps } from './props.js';
8
+
9
+ let { id, children }: DocumentScopeProps = $props();
10
+
11
+ setDocumentScope(() => id);
12
+ </script>
13
+
14
+ {@render children?.()}
@@ -0,0 +1,4 @@
1
+ import type { DocumentScopeProps } from './props.js';
2
+ declare const DocumentScope: import("svelte").Component<DocumentScopeProps, {}, "">;
3
+ type DocumentScope = ReturnType<typeof DocumentScope>;
4
+ export default DocumentScope;
@@ -0,0 +1,33 @@
1
+ <!--
2
+ Gives everything inside a kernel someone else created and owns, so every reader in it works
3
+ against that kernel: the full viewer's wrapper puts the components it shows in the viewer inside
4
+ one. It never starts or destroys the kernel; `<Viewer>` is the component that owns one.
5
+
6
+ The kernel is read once, like `<Viewer>`'s engine: to give a subtree another kernel, mount a new
7
+ provider (`{#key kernel}`).
8
+ -->
9
+ <script lang="ts">
10
+ import { onDestroy, untrack } from 'svelte';
11
+ import { KernelBinding, setKernelHolder } from './binding.svelte.js';
12
+ import { devWarn } from './dev.js';
13
+ import type { KernelProviderProps } from './props.js';
14
+
15
+ let { kernel, children }: KernelProviderProps = $props();
16
+
17
+ const binding = new KernelBinding(untrack(() => kernel));
18
+ setKernelHolder({ binding });
19
+ // The provider stops following the kernel; the kernel keeps running for its owner.
20
+ onDestroy(() => binding.dispose());
21
+
22
+ $effect(() => {
23
+ if (kernel !== binding.kernel) {
24
+ devWarn(
25
+ 'kernel-provider-kernel',
26
+ '<KernelProvider> reads kernel once; a new value is ignored. To give the subtree another ' +
27
+ 'kernel, mount a new <KernelProvider>, for example inside a {#key kernel} block.',
28
+ );
29
+ }
30
+ });
31
+ </script>
32
+
33
+ {@render children?.()}
@@ -0,0 +1,4 @@
1
+ import type { KernelProviderProps } from './props.js';
2
+ declare const KernelProvider: import("svelte").Component<KernelProviderProps, {}, "">;
3
+ type KernelProvider = ReturnType<typeof KernelProvider>;
4
+ export default KernelProvider;
@@ -0,0 +1,30 @@
1
+ <!--
2
+ Scene shapes as SVG elements: `@embedpdf/web`'s element descriptions (`svgShapesOf`), one
3
+ element each, a clipping `svg` with its children, and the faces their text draws in mounted
4
+ while they show. The annotation and form layers draw their scenes through it, inside an `<svg>`.
5
+ -->
6
+ <svelte:options namespace="svg" />
7
+
8
+ <script lang="ts">
9
+ import { createFontMounts, type SvgShape } from '@embedpdf/web';
10
+ import SvgShapes from './SvgShapes.svelte';
11
+
12
+ let { shapes }: { shapes: readonly SvgShape[] } = $props();
13
+
14
+ // The faces of this level's text: a clipping `svg` mounts its own children's.
15
+ const mounts = createFontMounts();
16
+ $effect(() => () => mounts.release());
17
+ $effect(() => {
18
+ mounts.mount(shapes.flatMap((shape) => (shape.program ? [shape.program] : [])));
19
+ });
20
+ </script>
21
+
22
+ {#each shapes as shape, index (index)}
23
+ <svelte:element this={shape.tag} {...shape.attributes} style:mix-blend-mode={shape.blend}>
24
+ {#if shape.children}
25
+ <SvgShapes shapes={shape.children} />
26
+ {:else if shape.text !== undefined}
27
+ {shape.text}
28
+ {/if}
29
+ </svelte:element>
30
+ {/each}
@@ -0,0 +1,8 @@
1
+ import { type SvgShape } from '@embedpdf/web';
2
+ import SvgShapes from './SvgShapes.svelte';
3
+ type $$ComponentProps = {
4
+ shapes: readonly SvgShape[];
5
+ };
6
+ declare const SvgShapes: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type SvgShapes = ReturnType<typeof SvgShapes>;
8
+ export default SvgShapes;