@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,43 @@
1
+ /**
2
+ * The signature plugin's readers: `useSignature()` (the API), the state and the settings,
3
+ * `useSignatureEvent()`, and `useSignerRows()`, the people whose marks this browser holds, for a
4
+ * signature picker.
5
+ */
6
+ import type { EventHook } from '@embedpdf/core';
7
+ import { signatureState } from '@embedpdf/plugin-signature';
8
+ import type { SignatureCapability, SignerRow } from '@embedpdf/plugin-signature';
9
+ import { type StateReader } from '../runtime/state.svelte.js';
10
+ import { type CurrentValue } from '../runtime/values.svelte.js';
11
+ /**
12
+ * The signature API for the document in scope: sign, place a mark, fill or clear a field, check
13
+ * the signatures. A handle: keep it whole and call through it (`signature.sign(…)`).
14
+ */
15
+ export declare function useSignature(): SignatureCapability;
16
+ /**
17
+ * The signatures' state: the signed fields with their verdicts (`signatures`), what they allow,
18
+ * the `target`, whether a signing runs (`busy`), a two-step signing in progress, and whether
19
+ * they're read, declared once in `signatureState`. A reactive object (`state.signatures`), or
20
+ * with a selector one value as `{ current }`. Empty without a document.
21
+ *
22
+ * Typed through the declaration, so the published types name it from `@embedpdf/plugin-signature`, a
23
+ * dependency of this package, and not from the engine package `protection`'s type comes from, which
24
+ * isn't one.
25
+ */
26
+ export declare const useSignatureState: StateReader<ReturnType<typeof signatureState.read>>;
27
+ /**
28
+ * The signature settings (`key`, `mode`, `trust`, `allowCertify`), with or without a document.
29
+ * They belong to the plugin; change them with `useSignature().updateSettings()`.
30
+ */
31
+ export declare const useSignatureSettings: import("../index.js").SettingsReader<import("@embedpdf/plugin-signature").SignatureSettings & object>;
32
+ /**
33
+ * Subscribe to one signature event while the component lives:
34
+ * `useSignatureEvent((signature) => signature.onSigned, handler)`.
35
+ */
36
+ export declare function useSignatureEvent<T>(select: (signature: SignatureCapability) => EventHook<T>, handler: (event: T) => void): void;
37
+ /**
38
+ * The people whose marks this browser holds, one row per library of kind `signatures`, for a
39
+ * picker, as `{ current }`: `const rows = useSignerRows()`, then `rows.current`. Derived from the
40
+ * stamp plugin, so it needs `stampPlugin()`: rename, delete and export are the library verbs, and
41
+ * nothing is stored beyond the file.
42
+ */
43
+ export declare function useSignerRows(): CurrentValue<readonly SignerRow[]>;
@@ -0,0 +1,46 @@
1
+ import { signatureState, signerRowsOf, SIGNATURES_LIBRARY_KIND, SignatureToken, } from '@embedpdf/plugin-signature';
2
+ import { useCapability, useCapabilityEvent } from '../runtime/readers.svelte.js';
3
+ import { settingsReader, stateReader } from '../runtime/state.svelte.js';
4
+ import { currentOf, derivedValue } from '../runtime/values.svelte.js';
5
+ import { useStampAssets, useStampLibraries } from '../stamp/readers.svelte.js';
6
+ /**
7
+ * The signature API for the document in scope: sign, place a mark, fill or clear a field, check
8
+ * the signatures. A handle: keep it whole and call through it (`signature.sign(…)`).
9
+ */
10
+ export function useSignature() {
11
+ return useCapability(SignatureToken);
12
+ }
13
+ /**
14
+ * The signatures' state: the signed fields with their verdicts (`signatures`), what they allow,
15
+ * the `target`, whether a signing runs (`busy`), a two-step signing in progress, and whether
16
+ * they're read, declared once in `signatureState`. A reactive object (`state.signatures`), or
17
+ * with a selector one value as `{ current }`. Empty without a document.
18
+ *
19
+ * Typed through the declaration, so the published types name it from `@embedpdf/plugin-signature`, a
20
+ * dependency of this package, and not from the engine package `protection`'s type comes from, which
21
+ * isn't one.
22
+ */
23
+ export const useSignatureState = stateReader(signatureState);
24
+ /**
25
+ * The signature settings (`key`, `mode`, `trust`, `allowCertify`), with or without a document.
26
+ * They belong to the plugin; change them with `useSignature().updateSettings()`.
27
+ */
28
+ export const useSignatureSettings = settingsReader(SignatureToken);
29
+ /**
30
+ * Subscribe to one signature event while the component lives:
31
+ * `useSignatureEvent((signature) => signature.onSigned, handler)`.
32
+ */
33
+ export function useSignatureEvent(select, handler) {
34
+ useCapabilityEvent(SignatureToken, select, handler);
35
+ }
36
+ /**
37
+ * The people whose marks this browser holds, one row per library of kind `signatures`, for a
38
+ * picker, as `{ current }`: `const rows = useSignerRows()`, then `rows.current`. Derived from the
39
+ * stamp plugin, so it needs `stampPlugin()`: rename, delete and export are the library verbs, and
40
+ * nothing is stored beyond the file.
41
+ */
42
+ export function useSignerRows() {
43
+ const libraries = useStampLibraries({ kind: SIGNATURES_LIBRARY_KIND });
44
+ const assets = useStampAssets();
45
+ return currentOf(derivedValue(() => signerRowsOf(libraries.current, assets.current)));
46
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @embedpdf/svelte/signature — signing.
3
+ *
4
+ * Signing for the document in scope (`useSignature()`), its state as a reactive object (the
5
+ * signatures with their verdicts, what they allow, the target, a two-step signing in progress),
6
+ * the settings, the events, and the one derivation a signatures panel needs: the people
7
+ * (libraries of kind `signatures`) with their marks (`useSignerRows()`). The signers
8
+ * (`personalSigner`, `webCryptoSigner`, `remoteSigner`, `createTestSigner`) come with the plugin.
9
+ * An empty signature field is "sign here" in `<FormLayer>` (`@embedpdf/svelte/form`).
10
+ *
11
+ * const signature = useSignature();
12
+ * await signature.placeMark({ assetId }, { field: target }); // sign, fill or ask, by mode
13
+ */
14
+ export * from '@embedpdf/plugin-signature';
15
+ export { useSignature, useSignatureEvent, useSignatureSettings, useSignatureState, useSignerRows, } from './signature/readers.svelte.js';
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @embedpdf/svelte/signature — signing.
3
+ *
4
+ * Signing for the document in scope (`useSignature()`), its state as a reactive object (the
5
+ * signatures with their verdicts, what they allow, the target, a two-step signing in progress),
6
+ * the settings, the events, and the one derivation a signatures panel needs: the people
7
+ * (libraries of kind `signatures`) with their marks (`useSignerRows()`). The signers
8
+ * (`personalSigner`, `webCryptoSigner`, `remoteSigner`, `createTestSigner`) come with the plugin.
9
+ * An empty signature field is "sign here" in `<FormLayer>` (`@embedpdf/svelte/form`).
10
+ *
11
+ * const signature = useSignature();
12
+ * await signature.placeMark({ assetId }, { field: target }); // sign, fill or ask, by mode
13
+ */
14
+ // Registration travels with the UI.
15
+ export * from '@embedpdf/plugin-signature';
16
+ export { useSignature, useSignatureEvent, useSignatureSettings, useSignatureState, useSignerRows, } from './signature/readers.svelte.js';
@@ -0,0 +1,126 @@
1
+ <!--
2
+ One visible page of a Stage: placed where the camera puts it, with its drop shadow, the page
3
+ content (which turns with the page) and the page chrome (which never turns). It provides the
4
+ page context to every layer inside.
5
+
6
+ All geometry comes from the page's transform: the display footprint (`viewWidth`/`viewHeight`,
7
+ already swapped for a quarter turn and snapped to device pixels) and the unturned content box
8
+ (`contentWidth`/`contentHeight`). Nothing here multiplies by the zoom or the pixel ratio.
9
+ -->
10
+ <script lang="ts">
11
+ import { untrack, type Snippet } from 'svelte';
12
+ import { toPageRef } from '@embedpdf/core';
13
+ import type { PageFrame } from '@embedpdf/core-geometry';
14
+ import type { VisiblePage } from '@embedpdf/plugin-stage';
15
+ import type { StageHostCapability } from '@embedpdf/plugin-stage/contract/host';
16
+ import type { PageViewDemand } from '@embedpdf/plugin-render/contract';
17
+ import {
18
+ livePageContext,
19
+ makePageContext,
20
+ pageSurfaceLayout,
21
+ paint,
22
+ stagePageDemand,
23
+ } from '@embedpdf/web';
24
+ import { useViewerSettings } from '../runtime/documents.svelte.js';
25
+ import { setPageContext, type PageContextValue } from '../runtime/page.js';
26
+
27
+ let {
28
+ documentId,
29
+ page,
30
+ frame,
31
+ stage,
32
+ content,
33
+ chrome,
34
+ }: {
35
+ documentId: string;
36
+ /** This page as the stage places it now: a new object on every camera frame. */
37
+ page: VisiblePage;
38
+ /** The bands reserved around the page, in screen pixels; the layout left room for them. */
39
+ frame: PageFrame;
40
+ stage: StageHostCapability;
41
+ content: Snippet<[page: PageContextValue]>;
42
+ chrome?: Snippet<[page: PageContextValue]>;
43
+ } = $props();
44
+
45
+ let contentElement: HTMLDivElement | undefined;
46
+
47
+ // The viewer's `page` settings; `--epdf-page-*` CSS variables win over them.
48
+ const look = useViewerSettings((settings) => settings.page);
49
+
50
+ // The Stage keys its pages by object number, so this surface's number never changes: one
51
+ // PageRef for its lifetime, safe for layers to key their work on.
52
+ const pageRef = toPageRef(untrack(() => page.ref.objectNumber));
53
+ // Each its own derived value, so the context below changes only when one of them does, not on
54
+ // every camera frame.
55
+ const pageIndex = $derived(page.pageIndex);
56
+ const transform = $derived(page.transform);
57
+
58
+ /**
59
+ * How much of this page the view wants, for raster planning: read live from the stage, a zero
60
+ * box while the page is off screen. It reads `page` first, so a reaction that asks (the tile
61
+ * plane) asks again on every camera frame.
62
+ */
63
+ function viewDemand(): PageViewDemand {
64
+ const placed = page;
65
+ return stagePageDemand(stage, pageRef.objectNumber, placed.transform.deviceWidth);
66
+ }
67
+
68
+ const context = $derived(
69
+ makePageContext(
70
+ documentId,
71
+ // The hosting lens: raster planning keys tiles by it, so a thumbnail rail and the main
72
+ // view never fight over one plan.
73
+ stage.getLensId(),
74
+ pageRef,
75
+ pageIndex,
76
+ frame,
77
+ transform,
78
+ () => contentElement!.getBoundingClientRect(),
79
+ viewDemand,
80
+ ),
81
+ );
82
+ const live = livePageContext(() => context);
83
+ setPageContext(live);
84
+
85
+ // The outer box (one frame further out than the footprint, so the content keeps its place),
86
+ // the shadow at the footprint, and the content box centred on it and turned about its centre.
87
+ const layout = $derived(
88
+ pageSurfaceLayout(transform, frame, { x: page.screenX, y: page.screenY }),
89
+ );
90
+ </script>
91
+
92
+ <div
93
+ style:position="absolute"
94
+ style:left="{layout.outer.left}px"
95
+ style:top="{layout.outer.top}px"
96
+ style:width="{layout.outer.width}px"
97
+ style:height="{layout.outer.height}px"
98
+ >
99
+ <!-- The drop shadow only: at the content box, with no fill, so it never shows behind the
100
+ picture, and it stays put while the page turns. -->
101
+ <div
102
+ style:position="absolute"
103
+ style:left="{layout.shadow.left}px"
104
+ style:top="{layout.shadow.top}px"
105
+ style:width="{layout.shadow.width}px"
106
+ style:height="{layout.shadow.height}px"
107
+ style:box-shadow={paint('page-shadow', look.current.shadow)}
108
+ ></div>
109
+ <!-- The page: its background and its layers as one box, the only thing the rotation turns.
110
+ Native text and image selection is off: the selection layer draws its own. -->
111
+ <div
112
+ bind:this={contentElement}
113
+ style="user-select: none; -webkit-user-select: none"
114
+ style:position="absolute"
115
+ style:left="{layout.content.left}px"
116
+ style:top="{layout.content.top}px"
117
+ style:width="{layout.content.width}px"
118
+ style:height="{layout.content.height}px"
119
+ style:background={paint('page-background', look.current.background)}
120
+ style:transform={layout.turn ?? undefined}
121
+ >
122
+ {@render content(live)}
123
+ </div>
124
+ <!-- The page chrome fills the outer box and never turns. -->
125
+ {@render chrome?.(live)}
126
+ </div>
@@ -0,0 +1,18 @@
1
+ import { type Snippet } from 'svelte';
2
+ import type { PageFrame } from '@embedpdf/core-geometry';
3
+ import type { VisiblePage } from '@embedpdf/plugin-stage';
4
+ import type { StageHostCapability } from '@embedpdf/plugin-stage/contract/host';
5
+ import { type PageContextValue } from '../runtime/page.js';
6
+ type $$ComponentProps = {
7
+ documentId: string;
8
+ /** This page as the stage places it now: a new object on every camera frame. */
9
+ page: VisiblePage;
10
+ /** The bands reserved around the page, in screen pixels; the layout left room for them. */
11
+ frame: PageFrame;
12
+ stage: StageHostCapability;
13
+ content: Snippet<[page: PageContextValue]>;
14
+ chrome?: Snippet<[page: PageContextValue]>;
15
+ };
16
+ declare const PageSurface: import("svelte").Component<$$ComponentProps, {}, "">;
17
+ type PageSurface = ReturnType<typeof PageSurface>;
18
+ export default PageSurface;
@@ -0,0 +1,148 @@
1
+ <!--
2
+ A scrollbar for a Stage lens that you style yourself: a view of `stage.getScrollMetrics()`.
3
+
4
+ Thumb drag with pointer capture and a kept grab point, track paging with press-and-hold repeat
5
+ that stops at the pointer, a minimum thumb length on long documents, and macOS-style auto-hide.
6
+ On an unbounded stage the metrics already carry the union of content and view, so the bar
7
+ shrinks as you pan away; the mapping is frozen during a thumb drag, so the thumb never chases
8
+ itself while that union changes.
9
+
10
+ Geometry and behavior live here, looks in your CSS, against
11
+ [data-embedpdf-scrollbar][data-axis="y"][data-state="visible|hidden"]
12
+ [data-embedpdf-scrollbar][data-dragging]
13
+ [data-embedpdf-scrollbar-thumb]
14
+ Unstyled, it's a transparent track at the viewport's edge with a `--epdf-scrollbar-thumb` pill.
15
+ Build anything else (a minimap, a progress ring) from `useScrollMetrics()` and `stage.scrollTo()`.
16
+ -->
17
+ <script lang="ts">
18
+ import {
19
+ createScrollbarPresses,
20
+ paintDefault,
21
+ scrollbarLayout,
22
+ type ScrollbarTrack,
23
+ } from '@embedpdf/web';
24
+ import { useCapability } from '../runtime/readers.svelte.js';
25
+ import type { ScrollbarProps } from './props.js';
26
+ import { asHost, scrollMetricsOf } from './readers.svelte.js';
27
+ import { stageTokenOf } from './stage-scope.js';
28
+
29
+ let {
30
+ axis,
31
+ token: explicitToken,
32
+ autoHide = 1200,
33
+ minThumbSize = 24,
34
+ trackPress = 'page',
35
+ class: className,
36
+ style,
37
+ thumbClass,
38
+ thumbStyle,
39
+ }: ScrollbarProps = $props();
40
+
41
+ const lens = stageTokenOf(() => explicitToken);
42
+ const stage = useCapability(() => asHost(lens()));
43
+ const metrics = scrollMetricsOf(lens);
44
+
45
+ const vertical = $derived(axis === 'y');
46
+ const scrollable = $derived(vertical ? metrics.scrollableY : metrics.scrollableX);
47
+
48
+ let track: HTMLDivElement | undefined = $state();
49
+ let trackPx = $state(0);
50
+ let dragging = $state(false);
51
+ let hovered = $state(false);
52
+ let active = $state(true); // the view moved recently
53
+
54
+ // The thumb along the track: one formula for drawing, dragging and paging, shared with every
55
+ // framework.
56
+ const layout = $derived(scrollbarLayout(metrics, vertical, trackPx, minThumbSize));
57
+
58
+ // ── auto-hide: any metrics change shows the bar and starts the fade again ──
59
+ const hideAfter = $derived(autoHide === false ? 0 : autoHide);
60
+ $effect(() => {
61
+ // Every number, so any movement counts.
62
+ void [metrics.scrollTop, metrics.scrollLeft, metrics.scrollHeight, metrics.scrollWidth];
63
+ void [metrics.clientHeight, metrics.clientWidth];
64
+ if (!hideAfter) return;
65
+ active = true;
66
+ const timer = setTimeout(() => (active = false), hideAfter);
67
+ return () => clearTimeout(timer);
68
+ });
69
+ const shown = $derived(!hideAfter || active || hovered || dragging);
70
+
71
+ // ── the track's length, which the pixel mapping needs ──
72
+ $effect(() => {
73
+ const element = track;
74
+ const isVertical = vertical;
75
+ if (!element) return;
76
+ const measure = () => (trackPx = isVertical ? element.clientHeight : element.clientWidth);
77
+ const observer = new ResizeObserver(measure);
78
+ observer.observe(element);
79
+ measure();
80
+ return () => observer.disconnect();
81
+ });
82
+
83
+ // ── input: `@embedpdf/web`'s press handling (thumb drags, track paging and jumps), handed the
84
+ // bar as it is now on every event. ──
85
+ const presses = createScrollbarPresses((value) => (dragging = value));
86
+ const pressedTrack = (): ScrollbarTrack => ({
87
+ stage,
88
+ vertical,
89
+ element: track!,
90
+ layout,
91
+ // Fresh geometry for paging steps, from the capability rather than the last drawn frame.
92
+ liveLayout: () => scrollbarLayout(stage.getScrollMetrics(), vertical, trackPx, minThumbSize),
93
+ });
94
+
95
+ // No repeat timer outlives the bar.
96
+ $effect(() => () => presses.release());
97
+
98
+ const trackDefaults = $derived(
99
+ vertical
100
+ ? 'position: absolute; top: 0; right: 0; bottom: 0; width: 12px;'
101
+ : 'position: absolute; left: 0; right: 0; bottom: 0; height: 12px;',
102
+ );
103
+ const thumbDefaults = $derived(
104
+ vertical
105
+ ? `position: absolute; left: 2px; right: 2px; top: ${layout.thumbPosition}px; height: ${layout.thumbLength}px;`
106
+ : `position: absolute; top: 2px; bottom: 2px; left: ${layout.thumbPosition}px; width: ${layout.thumbLength}px;`,
107
+ );
108
+ </script>
109
+
110
+ {#if scrollable}
111
+ <!-- The bar drives the Stage, which is no single element to name in aria-controls, and the
112
+ pointer is its input: like a native overlay scrollbar, it takes no focus. -->
113
+ <!-- svelte-ignore a11y_role_has_required_aria_props, a11y_interactive_supports_focus -->
114
+ <div
115
+ bind:this={track}
116
+ role="scrollbar"
117
+ aria-orientation={vertical ? 'vertical' : 'horizontal'}
118
+ aria-valuemin={0}
119
+ aria-valuemax={Math.round(layout.maxOffset)}
120
+ aria-valuenow={Math.round(layout.offset)}
121
+ data-embedpdf-scrollbar=""
122
+ data-axis={axis}
123
+ data-state={shown ? 'visible' : 'hidden'}
124
+ data-dragging={dragging ? '' : undefined}
125
+ class={className}
126
+ style="{trackDefaults} touch-action: none; user-select: none; opacity: {shown
127
+ ? 1
128
+ : 0}; transition: opacity 200ms; pointer-events: {shown ? 'auto' : 'none'};{style
129
+ ? ` ${style}`
130
+ : ''}"
131
+ onpointerdown={(event) => presses.pressTrack(event, pressedTrack(), trackPress)}
132
+ onpointermove={(event) => presses.move(event, pressedTrack())}
133
+ onpointerup={() => presses.release()}
134
+ onpointercancel={() => presses.release()}
135
+ onpointerenter={() => (hovered = true)}
136
+ onpointerleave={() => (hovered = false)}
137
+ >
138
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
139
+ <div
140
+ data-embedpdf-scrollbar-thumb=""
141
+ class={thumbClass}
142
+ style="{thumbDefaults} border-radius: 6px; background: {paintDefault(
143
+ 'scrollbar-thumb',
144
+ )};{thumbStyle ? ` ${thumbStyle}` : ''}"
145
+ onpointerdown={(event) => presses.pressThumb(event, pressedTrack())}
146
+ ></div>
147
+ </div>
148
+ {/if}
@@ -0,0 +1,4 @@
1
+ import type { ScrollbarProps } from './props.js';
2
+ declare const Scrollbar: import("svelte").Component<ScrollbarProps, {}, "">;
3
+ type Scrollbar = ReturnType<typeof Scrollbar>;
4
+ export default Scrollbar;
@@ -0,0 +1,181 @@
1
+ <!--
2
+ The Stage: lays out the document's pages by the camera, keeps only the visible ones mounted,
3
+ and draws its content (the `children` snippet) on each; you bring the layers. Pointer, wheel and touch input go
4
+ through `@embedpdf/web`'s stage surface, so every framework has one feel.
5
+
6
+ Everything inside binds to this lens: a `useStageState()` in a page's chrome or a
7
+ `<Scrollbar>` in the overlay needs no token. The overlay also gets the Stage's projection, so
8
+ anchored UI follows the camera in the same flush as the pages.
9
+ -->
10
+ <script lang="ts">
11
+ import { untrack } from 'svelte';
12
+ import type { CapabilityToken } from '@embedpdf/core';
13
+ import type { PageFrame } from '@embedpdf/core-geometry';
14
+ import { createScrollHandler, DEFAULT_SETTINGS, stageState } from '@embedpdf/plugin-stage';
15
+ import type { VisiblePage } from '@embedpdf/plugin-stage';
16
+ import type { StageHostCapability } from '@embedpdf/plugin-stage/contract/host';
17
+ import { InteractionToken as InteractionPublicToken } from '@embedpdf/plugin-interaction/contract';
18
+ import { InteractionToken } from '@embedpdf/plugin-interaction/contract/host';
19
+ import { createStageSurface, stageViewProjector } from '@embedpdf/web';
20
+ import { setProjectorBinding, setShownPages, type ShownPages } from '../anchored/context.js';
21
+ import {
22
+ useCapabilityEvent,
23
+ useDocumentId,
24
+ useKernelValue,
25
+ useOptionalCapability,
26
+ useOptionalSelector,
27
+ } from '../runtime/readers.svelte.js';
28
+ import { declaredState } from '../runtime/state.svelte.js';
29
+ import { useKernelBinding } from '../runtime/binding.svelte.js';
30
+ import PageSurface from './PageSurface.svelte';
31
+ import type { StageProps } from './props.js';
32
+ import { setStageToken, stageTokenOf } from './stage-scope.js';
33
+ import { syncTwoWay } from './two-way.svelte.js';
34
+
35
+ let {
36
+ children,
37
+ pageChrome,
38
+ overlay,
39
+ tool = $bindable(),
40
+ onToolChange,
41
+ page = $bindable(),
42
+ zoom = $bindable(),
43
+ token: explicitToken,
44
+ class: className,
45
+ style,
46
+ }: StageProps = $props();
47
+
48
+ const token = stageTokenOf(() => explicitToken);
49
+ setStageToken(token);
50
+ // The surface is a host of the lens: it reports the viewport size, drives gestures and reads
51
+ // the lens id. The host contract is the same runtime token, typed wider.
52
+ const hostToken = () => token() as unknown as CapabilityToken<StageHostCapability>;
53
+ const stage = useOptionalCapability(hostToken);
54
+ const interaction = useOptionalCapability(InteractionToken);
55
+ const documentId = useDocumentId();
56
+
57
+ const NO_PAGES: readonly VisiblePage[] = [];
58
+ // The visible pages already fold in the camera (each carries its snapped screen position and
59
+ // transform), so panning gives a new list: no separate camera subscription.
60
+ const pages = useOptionalSelector(hostToken, (lens) => lens.listVisiblePages(), NO_PAGES);
61
+ const settings = useOptionalSelector(hostToken, (lens) => lens.getSettings(), DEFAULT_SETTINGS);
62
+ // The reserved bands around every page, compared by side so an equal frame changes nothing.
63
+ const frame = useOptionalSelector(
64
+ hostToken,
65
+ (lens) => lens.getSettings().pageFrame,
66
+ DEFAULT_SETTINGS.pageFrame,
67
+ (left: PageFrame, right: PageFrame) =>
68
+ left.top === right.top &&
69
+ left.right === right.right &&
70
+ left.bottom === right.bottom &&
71
+ left.left === right.left,
72
+ );
73
+
74
+ // How this view takes pointer input is its own settings: routed to the interaction plugin
75
+ // (which also registers this view's pan-scroll handler, scoped to it, so two Stages on one
76
+ // document never pan each other), or the Stage's own drag-to-pan without it.
77
+ const routed = $derived(settings.current.interaction && interaction.current !== null);
78
+ const panFallback = $derived(settings.current.panFallback);
79
+ const zoomGestures = $derived(settings.current.zoomGestures);
80
+ // The cursor the interaction plugin resolves (text, grab, …), on the viewport while routed.
81
+ const hubCursor = useKernelValue(() => interaction.current?.getCursor() ?? 'default');
82
+
83
+ let element: HTMLDivElement | undefined;
84
+
85
+ $effect(() => {
86
+ const lens = stage.current;
87
+ const hub = routed ? interaction.current : null;
88
+ const gestures = zoomGestures;
89
+ const fallback = panFallback;
90
+ if (!element || !lens) return;
91
+ return untrack(() => {
92
+ const detachSurface = createStageSurface(element!, lens, {
93
+ hub,
94
+ source: lens.getLensId(),
95
+ zoomGestures: gestures,
96
+ });
97
+ const offScroll = hub
98
+ ? hub.registerHandler(createScrollHandler(lens, hub, { panFallback: fallback }), {
99
+ source: lens.getLensId(),
100
+ })
101
+ : null;
102
+ return () => {
103
+ offScroll?.();
104
+ detachSurface();
105
+ };
106
+ });
107
+ });
108
+
109
+ // ── two-way values ─────────────────────────────────────────────────────────
110
+
111
+ // The bound tool wins whenever it's set, again when the document changes.
112
+ $effect(() => {
113
+ const wanted = tool;
114
+ const hub = interaction.current;
115
+ if (wanted === undefined || !hub) return;
116
+ untrack(() => {
117
+ if (hub.getActiveToolId() !== wanted) hub.activateTool(wanted);
118
+ });
119
+ });
120
+ useCapabilityEvent(
121
+ InteractionPublicToken,
122
+ (hub) => hub.onToolChanged,
123
+ (event) => {
124
+ if (tool !== undefined) tool = event.toolId;
125
+ onToolChange?.(event.toolId);
126
+ },
127
+ );
128
+
129
+ const binding = useKernelBinding();
130
+ const view = declaredState(binding, token, stageState.read, stageState.empty);
131
+ syncTwoWay({
132
+ stage: () => view().currentPageIndex,
133
+ bound: () => page,
134
+ ready: () => stage.current !== null,
135
+ write: (value) => (page = value),
136
+ apply: (value) => stage.current?.goToPage(value),
137
+ });
138
+ syncTwoWay({
139
+ stage: () => view().zoomLevel,
140
+ bound: () => zoom,
141
+ ready: () => stage.current !== null,
142
+ write: (value) => (zoom = value),
143
+ apply: (value) => stage.current?.zoomTo(value),
144
+ });
145
+
146
+ // ── what the overlay anchors to ───────────────────────────────────────────
147
+
148
+ // Anchored UI positions through the camera: pure state, no DOM reads. The visible pages are
149
+ // the binding's revision, so a camera change moves the pages and every anchored element in
150
+ // the same flush.
151
+ const projector = stageViewProjector(() => stage.current);
152
+ const projectorBinding = $derived({ projector, revision: pages.current });
153
+ setProjectorBinding(() => projectorBinding);
154
+ // The pages on screen as one value that changes only when a page comes or goes, so anchored
155
+ // UI on the other pages sits out every camera frame.
156
+ const shownKey = $derived(pages.current.map((visible) => visible.ref.objectNumber).join(','));
157
+ const shownPages: ShownPages = $derived(new Set(shownKey ? shownKey.split(',').map(Number) : []));
158
+ setShownPages(() => shownPages);
159
+ </script>
160
+
161
+ <div
162
+ bind:this={element}
163
+ class={className}
164
+ style="position: relative; overflow: hidden; touch-action: none;{routed
165
+ ? ` cursor: ${hubCursor.current};`
166
+ : ''}{style ? ` ${style}` : ''}"
167
+ >
168
+ {#if stage.current}
169
+ {#each pages.current as visible (visible.ref.objectNumber)}
170
+ <PageSurface
171
+ documentId={documentId.current ?? ''}
172
+ page={visible}
173
+ frame={frame.current}
174
+ stage={stage.current}
175
+ content={children}
176
+ chrome={pageChrome}
177
+ />
178
+ {/each}
179
+ {/if}
180
+ {@render overlay?.()}
181
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { StageProps } from './props.js';
2
+ declare const Stage: import("svelte").Component<StageProps, {}, "page" | "zoom" | "tool">;
3
+ type Stage = ReturnType<typeof Stage>;
4
+ export default Stage;
@@ -0,0 +1,14 @@
1
+ <!--
2
+ Binds everything inside to a stage lens: the stage readers and stage chrome inside use `token`
3
+ unless they are given one themselves.
4
+ -->
5
+ <script lang="ts">
6
+ import type { Snippet } from 'svelte';
7
+ import { setStageToken, type StageTokenProp } from './stage-scope.js';
8
+
9
+ let { token, children }: { token: StageTokenProp; children?: Snippet } = $props();
10
+
11
+ setStageToken(() => token);
12
+ </script>
13
+
14
+ {@render children?.()}
@@ -0,0 +1,9 @@
1
+ import type { Snippet } from 'svelte';
2
+ import { type StageTokenProp } from './stage-scope.js';
3
+ type $$ComponentProps = {
4
+ token: StageTokenProp;
5
+ children?: Snippet;
6
+ };
7
+ declare const StageScope: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type StageScope = ReturnType<typeof StageScope>;
9
+ export default StageScope;