@embedpdf/svelte 0.0.0-stage → 3.0.0-next.16

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 (269) 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 +51 -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 +28 -0
  48. package/dist/annotation/text-box.svelte.js +87 -0
  49. package/dist/annotation.d.ts +32 -0
  50. package/dist/annotation.js +31 -0
  51. package/dist/attachment/readers.d.ts +23 -0
  52. package/dist/attachment/readers.js +21 -0
  53. package/dist/attachment.d.ts +13 -0
  54. package/dist/attachment.js +14 -0
  55. package/dist/commands/readers.svelte.d.ts +50 -0
  56. package/dist/commands/readers.svelte.js +83 -0
  57. package/dist/commands.d.ts +9 -0
  58. package/dist/commands.js +9 -0
  59. package/dist/form/ButtonControl.svelte +38 -0
  60. package/dist/form/ButtonControl.svelte.d.ts +11 -0
  61. package/dist/form/ComboControl.svelte +52 -0
  62. package/dist/form/ComboControl.svelte.d.ts +11 -0
  63. package/dist/form/FieldPictures.svelte +145 -0
  64. package/dist/form/FieldPictures.svelte.d.ts +3 -0
  65. package/dist/form/FormFocusRing.svelte +25 -0
  66. package/dist/form/FormFocusRing.svelte.d.ts +8 -0
  67. package/dist/form/FormLayer.svelte +98 -0
  68. package/dist/form/FormLayer.svelte.d.ts +3 -0
  69. package/dist/form/ListControl.svelte +49 -0
  70. package/dist/form/ListControl.svelte.d.ts +11 -0
  71. package/dist/form/NativeListBox.svelte +57 -0
  72. package/dist/form/NativeListBox.svelte.d.ts +4 -0
  73. package/dist/form/SignatureControl.svelte +53 -0
  74. package/dist/form/SignatureControl.svelte.d.ts +11 -0
  75. package/dist/form/TextControl.svelte +107 -0
  76. package/dist/form/TextControl.svelte.d.ts +11 -0
  77. package/dist/form/ToggleControl.svelte +50 -0
  78. package/dist/form/ToggleControl.svelte.d.ts +11 -0
  79. package/dist/form/WidgetBox.svelte +82 -0
  80. package/dist/form/WidgetBox.svelte.d.ts +15 -0
  81. package/dist/form/props.d.ts +21 -0
  82. package/dist/form/props.js +1 -0
  83. package/dist/form/readers.svelte.d.ts +46 -0
  84. package/dist/form/readers.svelte.js +52 -0
  85. package/dist/form/widget.d.ts +16 -0
  86. package/dist/form/widget.js +20 -0
  87. package/dist/form.d.ts +11 -0
  88. package/dist/form.js +12 -0
  89. package/dist/history/readers.d.ts +22 -0
  90. package/dist/history/readers.js +21 -0
  91. package/dist/history.d.ts +10 -0
  92. package/dist/history.js +11 -0
  93. package/dist/i18n/readers.svelte.d.ts +32 -0
  94. package/dist/i18n/readers.svelte.js +30 -0
  95. package/dist/i18n.d.ts +8 -0
  96. package/dist/i18n.js +9 -0
  97. package/dist/index.d.ts +30 -0
  98. package/dist/index.js +30 -0
  99. package/dist/interaction/PagePointerSource.svelte +37 -0
  100. package/dist/interaction/PagePointerSource.svelte.d.ts +3 -0
  101. package/dist/interaction/readers.svelte.d.ts +26 -0
  102. package/dist/interaction/readers.svelte.js +47 -0
  103. package/dist/interaction.d.ts +11 -0
  104. package/dist/interaction.js +13 -0
  105. package/dist/link/LinkLayer.svelte +164 -0
  106. package/dist/link/LinkLayer.svelte.d.ts +4 -0
  107. package/dist/link/props.d.ts +17 -0
  108. package/dist/link/props.js +1 -0
  109. package/dist/link/readers.svelte.d.ts +18 -0
  110. package/dist/link/readers.svelte.js +38 -0
  111. package/dist/link.d.ts +11 -0
  112. package/dist/link.js +11 -0
  113. package/dist/measurement/readers.d.ts +44 -0
  114. package/dist/measurement/readers.js +46 -0
  115. package/dist/measurement.d.ts +12 -0
  116. package/dist/measurement.js +13 -0
  117. package/dist/metadata/readers.d.ts +22 -0
  118. package/dist/metadata/readers.js +22 -0
  119. package/dist/metadata.d.ts +12 -0
  120. package/dist/metadata.js +13 -0
  121. package/dist/outline/readers.d.ts +26 -0
  122. package/dist/outline/readers.js +22 -0
  123. package/dist/outline.d.ts +12 -0
  124. package/dist/outline.js +13 -0
  125. package/dist/page-edit/readers.d.ts +17 -0
  126. package/dist/page-edit/readers.js +18 -0
  127. package/dist/page-edit.d.ts +12 -0
  128. package/dist/page-edit.js +13 -0
  129. package/dist/page-view/PageView.svelte +192 -0
  130. package/dist/page-view/PageView.svelte.d.ts +4 -0
  131. package/dist/page-view/props.d.ts +32 -0
  132. package/dist/page-view/props.js +1 -0
  133. package/dist/page-view.d.ts +8 -0
  134. package/dist/page-view.js +7 -0
  135. package/dist/redaction/readers.d.ts +37 -0
  136. package/dist/redaction/readers.js +38 -0
  137. package/dist/redaction.d.ts +12 -0
  138. package/dist/redaction.js +13 -0
  139. package/dist/render/RenderLayer.svelte +116 -0
  140. package/dist/render/RenderLayer.svelte.d.ts +4 -0
  141. package/dist/render/TileImage.svelte +65 -0
  142. package/dist/render/TileImage.svelte.d.ts +11 -0
  143. package/dist/render/TilePlane.svelte +88 -0
  144. package/dist/render/TilePlane.svelte.d.ts +7 -0
  145. package/dist/render/props.d.ts +16 -0
  146. package/dist/render/props.js +1 -0
  147. package/dist/render/readers.svelte.d.ts +9 -0
  148. package/dist/render/readers.svelte.js +13 -0
  149. package/dist/render.d.ts +10 -0
  150. package/dist/render.js +10 -0
  151. package/dist/runtime/DocumentGate.svelte +26 -0
  152. package/dist/runtime/DocumentGate.svelte.d.ts +4 -0
  153. package/dist/runtime/DocumentScope.svelte +14 -0
  154. package/dist/runtime/DocumentScope.svelte.d.ts +4 -0
  155. package/dist/runtime/KernelProvider.svelte +33 -0
  156. package/dist/runtime/KernelProvider.svelte.d.ts +4 -0
  157. package/dist/runtime/SvgShapes.svelte +30 -0
  158. package/dist/runtime/SvgShapes.svelte.d.ts +8 -0
  159. package/dist/runtime/Viewer.svelte +130 -0
  160. package/dist/runtime/Viewer.svelte.d.ts +4 -0
  161. package/dist/runtime/binding.svelte.d.ts +33 -0
  162. package/dist/runtime/binding.svelte.js +71 -0
  163. package/dist/runtime/capability-handle.d.ts +6 -0
  164. package/dist/runtime/capability-handle.js +71 -0
  165. package/dist/runtime/dev.d.ts +10 -0
  166. package/dist/runtime/dev.js +23 -0
  167. package/dist/runtime/documents.svelte.d.ts +34 -0
  168. package/dist/runtime/documents.svelte.js +49 -0
  169. package/dist/runtime/page-layers.svelte.d.ts +20 -0
  170. package/dist/runtime/page-layers.svelte.js +40 -0
  171. package/dist/runtime/page.d.ts +10 -0
  172. package/dist/runtime/page.js +23 -0
  173. package/dist/runtime/props.d.ts +63 -0
  174. package/dist/runtime/props.js +1 -0
  175. package/dist/runtime/readers.svelte.d.ts +47 -0
  176. package/dist/runtime/readers.svelte.js +122 -0
  177. package/dist/runtime/state.svelte.d.ts +35 -0
  178. package/dist/runtime/state.svelte.js +90 -0
  179. package/dist/runtime/theme.d.ts +12 -0
  180. package/dist/runtime/theme.js +15 -0
  181. package/dist/runtime/values.svelte.d.ts +28 -0
  182. package/dist/runtime/values.svelte.js +51 -0
  183. package/dist/runtime.d.ts +26 -0
  184. package/dist/runtime.js +25 -0
  185. package/dist/search/SearchLayer.svelte +94 -0
  186. package/dist/search/SearchLayer.svelte.d.ts +4 -0
  187. package/dist/search/props.d.ts +11 -0
  188. package/dist/search/props.js +1 -0
  189. package/dist/search/readers.svelte.d.ts +41 -0
  190. package/dist/search/readers.svelte.js +40 -0
  191. package/dist/search.d.ts +11 -0
  192. package/dist/search.js +11 -0
  193. package/dist/selection/SelectionClipboard.svelte +35 -0
  194. package/dist/selection/SelectionClipboard.svelte.d.ts +4 -0
  195. package/dist/selection/SelectionHandles.svelte +192 -0
  196. package/dist/selection/SelectionHandles.svelte.d.ts +4 -0
  197. package/dist/selection/SelectionLayer.svelte +67 -0
  198. package/dist/selection/SelectionLayer.svelte.d.ts +3 -0
  199. package/dist/selection/SelectionMenu.svelte +36 -0
  200. package/dist/selection/SelectionMenu.svelte.d.ts +4 -0
  201. package/dist/selection/props.d.ts +26 -0
  202. package/dist/selection/props.js +1 -0
  203. package/dist/selection/readers.svelte.d.ts +31 -0
  204. package/dist/selection/readers.svelte.js +26 -0
  205. package/dist/selection.d.ts +16 -0
  206. package/dist/selection.js +18 -0
  207. package/dist/shell/readers.svelte.d.ts +40 -0
  208. package/dist/shell/readers.svelte.js +40 -0
  209. package/dist/shell/surface-focus.svelte.d.ts +16 -0
  210. package/dist/shell/surface-focus.svelte.js +33 -0
  211. package/dist/shell.d.ts +12 -0
  212. package/dist/shell.js +11 -0
  213. package/dist/signature/readers.svelte.d.ts +43 -0
  214. package/dist/signature/readers.svelte.js +46 -0
  215. package/dist/signature.d.ts +15 -0
  216. package/dist/signature.js +16 -0
  217. package/dist/stage/PageSurface.svelte +126 -0
  218. package/dist/stage/PageSurface.svelte.d.ts +18 -0
  219. package/dist/stage/Scrollbar.svelte +148 -0
  220. package/dist/stage/Scrollbar.svelte.d.ts +4 -0
  221. package/dist/stage/Stage.svelte +181 -0
  222. package/dist/stage/Stage.svelte.d.ts +4 -0
  223. package/dist/stage/StageScope.svelte +14 -0
  224. package/dist/stage/StageScope.svelte.d.ts +9 -0
  225. package/dist/stage/props.d.ts +71 -0
  226. package/dist/stage/props.js +1 -0
  227. package/dist/stage/readers.svelte.d.ts +39 -0
  228. package/dist/stage/readers.svelte.js +84 -0
  229. package/dist/stage/stage-scope.d.ts +18 -0
  230. package/dist/stage/stage-scope.js +35 -0
  231. package/dist/stage/two-way.svelte.d.ts +13 -0
  232. package/dist/stage/two-way.svelte.js +26 -0
  233. package/dist/stage.d.ts +17 -0
  234. package/dist/stage.js +15 -0
  235. package/dist/stamp/readers.svelte.d.ts +50 -0
  236. package/dist/stamp/readers.svelte.js +76 -0
  237. package/dist/stamp.d.ts +16 -0
  238. package/dist/stamp.js +18 -0
  239. package/dist/toolbar/DefaultCollapsed.svelte +39 -0
  240. package/dist/toolbar/DefaultCollapsed.svelte.d.ts +9 -0
  241. package/dist/toolbar/DefaultCommand.svelte +33 -0
  242. package/dist/toolbar/DefaultCommand.svelte.d.ts +8 -0
  243. package/dist/toolbar/DefaultGroupTrigger.svelte +39 -0
  244. package/dist/toolbar/DefaultGroupTrigger.svelte.d.ts +9 -0
  245. package/dist/toolbar/DefaultOverflowMenu.svelte +106 -0
  246. package/dist/toolbar/DefaultOverflowMenu.svelte.d.ts +9 -0
  247. package/dist/toolbar/DefaultOverflowTrigger.svelte +25 -0
  248. package/dist/toolbar/DefaultOverflowTrigger.svelte.d.ts +7 -0
  249. package/dist/toolbar/Measured.svelte +46 -0
  250. package/dist/toolbar/Measured.svelte.d.ts +11 -0
  251. package/dist/toolbar/NativeSlotSocket.svelte +43 -0
  252. package/dist/toolbar/NativeSlotSocket.svelte.d.ts +11 -0
  253. package/dist/toolbar/Toolbar.svelte +314 -0
  254. package/dist/toolbar/Toolbar.svelte.d.ts +4 -0
  255. package/dist/toolbar/paint.d.ts +3 -0
  256. package/dist/toolbar/paint.js +9 -0
  257. package/dist/toolbar/props.d.ts +48 -0
  258. package/dist/toolbar/props.js +1 -0
  259. package/dist/toolbar/strip.svelte.d.ts +14 -0
  260. package/dist/toolbar/strip.svelte.js +35 -0
  261. package/dist/toolbar/views.d.ts +14 -0
  262. package/dist/toolbar/views.js +1 -0
  263. package/dist/toolbar.d.ts +16 -0
  264. package/dist/toolbar.js +12 -0
  265. package/dist/view-manager/readers.d.ts +19 -0
  266. package/dist/view-manager/readers.js +17 -0
  267. package/dist/view-manager.d.ts +11 -0
  268. package/dist/view-manager.js +12 -0
  269. package/package.json +207 -3
@@ -0,0 +1,314 @@
1
+ <!--
2
+ <Toolbar>: measures what fits and makes room, and you draw every part.
3
+
4
+ 1. A hidden measurement layer renders every unit in every variant (and the folded groups and
5
+ the "More" button), each watched with `observeLength` from @embedpdf/web along the toolbar
6
+ (widths, or heights when it is vertical), so a new language, a font loading, browser zoom
7
+ and your CSS all re-measure on their own (`createToolbarLengths`).
8
+ 2. core-ui's `solve()` gives each unit a variant, a folded group or the "More" menu
9
+ (`layoutToolbar` turns that into parts).
10
+ 3. The live row draws the parts; the "More" menu is derived from what didn't fit
11
+ (`projectOverflow`), never written by hand.
12
+
13
+ The toolbar is one tab stop with arrow keys along it (`attachToolbarFocus`), and its default
14
+ menus take the menu keys (`attachMenuKeys`). Every part is a snippet with a plain default:
15
+ `command`, `custom`, `collapsed`, `groupTrigger`, `separator`, `overflowTrigger` and
16
+ `overflowMenu`. The defaults' colors come from the `--epdf-toolbar-*` CSS variables only.
17
+ -->
18
+ <script lang="ts">
19
+ import { untrack } from 'svelte';
20
+ import { layoutToolbar, normalizeBar, type LiveSection } from '@embedpdf/core-ui';
21
+ // The "More" menu asks which menu a command opens, a host fact, so the host lens is bound here.
22
+ import { CommandsToken } from '@embedpdf/plugin-commands/contract/host';
23
+ import { unregisteredCommand } from '@embedpdf/plugin-commands/contract';
24
+ import type { ResolvedCommand } from '@embedpdf/plugin-commands/contract';
25
+ import {
26
+ TOOLBAR_ITEM_ATTRIBUTE,
27
+ attachToolbarFocus,
28
+ createToolbarLengths,
29
+ observeContentLength,
30
+ toolbarMeasureKey,
31
+ type RovingFocus,
32
+ } from '@embedpdf/web';
33
+ import { useKernelBinding } from '../runtime/binding.svelte.js';
34
+ import { useCapability, useDocumentId } from '../runtime/readers.svelte.js';
35
+ import DefaultCollapsed from './DefaultCollapsed.svelte';
36
+ import DefaultCommand from './DefaultCommand.svelte';
37
+ import DefaultGroupTrigger from './DefaultGroupTrigger.svelte';
38
+ import DefaultOverflowMenu from './DefaultOverflowMenu.svelte';
39
+ import DefaultOverflowTrigger from './DefaultOverflowTrigger.svelte';
40
+ import Measured from './Measured.svelte';
41
+ import NativeSlotSocket from './NativeSlotSocket.svelte';
42
+ import type { ToolbarProps } from './props.js';
43
+ import type { OverflowMenuView, ToolbarPart } from './views.js';
44
+
45
+ let {
46
+ bar,
47
+ orientation = 'horizontal',
48
+ gap = 8,
49
+ separatorWidth = 1,
50
+ 'aria-label': ariaLabel,
51
+ class: className,
52
+ style,
53
+ command,
54
+ custom,
55
+ collapsed,
56
+ groupTrigger,
57
+ separator,
58
+ overflowTrigger,
59
+ overflowMenu,
60
+ }: ToolbarProps = $props();
61
+
62
+ const binding = useKernelBinding();
63
+ const commands = useCapability(CommandsToken);
64
+ const documentId = useDocumentId();
65
+ const vertical = $derived(orientation === 'vertical');
66
+
67
+ // ── measuring ──────────────────────────────────────────────────────────────
68
+
69
+ let container: HTMLDivElement | undefined = $state();
70
+ let containerLength = $state(0);
71
+ $effect(() => {
72
+ const element = container;
73
+ const along = orientation;
74
+ if (!element) return;
75
+ return untrack(() =>
76
+ observeContentLength(element, along, (length) => (containerLength = length)),
77
+ );
78
+ });
79
+
80
+ // A length that changed by more than half a pixel fits (and draws) again. Untracked: a report
81
+ // can come from an effect, which must not run again because the count moved.
82
+ const lengths = createToolbarLengths();
83
+ let measured = $state(0);
84
+ function report(key: string, length: number) {
85
+ untrack(() => {
86
+ if (lengths.report(orientation, key, length)) measured += 1;
87
+ });
88
+ }
89
+
90
+ // ── the fit ────────────────────────────────────────────────────────────────
91
+
92
+ const normalized = $derived(normalizeBar(bar));
93
+
94
+ const resolve = (id: string): ResolvedCommand | null =>
95
+ commands.resolveCommand(id, documentId.current ?? undefined);
96
+ const execute = (id: string): void =>
97
+ void commands.execute(id, { documentId: documentId.current ?? undefined });
98
+
99
+ // Command state is derived on read, so this runs again on every kernel change: labels, `active`
100
+ // and `visible` (and with them the measurement layer) stay live. A toolbar is a few dozen
101
+ // items, so drawing it again on each change is the simple, correct baseline.
102
+ const layout = $derived.by(() => {
103
+ binding.track();
104
+ void measured;
105
+ return layoutToolbar({
106
+ bar: normalized,
107
+ resolve,
108
+ unregistered: unregisteredCommand,
109
+ execute,
110
+ menuTarget: (id) => commands.getMenuTarget(id),
111
+ metrics: lengths.metrics(orientation, gap, separatorWidth),
112
+ measureKey: toolbarMeasureKey,
113
+ containerLength,
114
+ orientation,
115
+ });
116
+ });
117
+
118
+ // ── the "More" menu ────────────────────────────────────────────────────────
119
+
120
+ let overflowOpen = $state(false);
121
+ const hasOverflow = $derived(layout.hasOverflow);
122
+ $effect(() => {
123
+ if (!hasOverflow) overflowOpen = false;
124
+ });
125
+ const toggleOverflow = () => (overflowOpen = !overflowOpen);
126
+ const noop = () => {};
127
+
128
+ const overflowView: OverflowMenuView = $derived({
129
+ sections: layout.overflow,
130
+ isOpen: overflowOpen,
131
+ close: () => (overflowOpen = false),
132
+ resolve,
133
+ execute,
134
+ });
135
+
136
+ // ── the keyboard ───────────────────────────────────────────────────────────
137
+
138
+ // One tab stop, and arrow keys along the toolbar. The handle is no state: nothing draws from it.
139
+ const keyboard: { focus: RovingFocus | null } = { focus: null };
140
+ $effect(() => {
141
+ const element = container;
142
+ const along = orientation;
143
+ if (!element) return;
144
+ return untrack(() => {
145
+ const focus = attachToolbarFocus(element, along);
146
+ keyboard.focus = focus;
147
+ return () => {
148
+ focus.detach();
149
+ keyboard.focus = null;
150
+ };
151
+ });
152
+ });
153
+ // Any draw can add, remove or disable an item, so the tab stop is checked after each one: a new
154
+ // fit, the "More" menu, or snippets of yours that draw the parts. An effect runs after the DOM
155
+ // it follows is updated.
156
+ $effect(() => {
157
+ void [layout, overflowOpen, command, custom, collapsed, groupTrigger, overflowTrigger];
158
+ untrack(() => keyboard.focus?.refresh());
159
+ });
160
+
161
+ // ── layout ─────────────────────────────────────────────────────────────────
162
+
163
+ /**
164
+ * The sections run along the toolbar. The center one carries auto margins: it centers in the
165
+ * space the other two leave, and gives way before anything overlaps. The toolbar itself has no
166
+ * gap, so what the fit says fits, fits. Sections never grow or shrink: fitting is the solver's
167
+ * job, not flexbox's.
168
+ */
169
+ const sectionStyle = (name: LiveSection['name']) =>
170
+ `display: flex; flex-direction: ${vertical ? 'column' : 'row'}; align-items: center; ` +
171
+ `gap: ${gap}px; flex: 0 0 auto;` +
172
+ (name !== 'center'
173
+ ? ''
174
+ : vertical
175
+ ? ' margin-top: auto; margin-bottom: auto;'
176
+ : ' margin-left: auto; margin-right: auto;');
177
+
178
+ /** The default separator: a 1px line across the toolbar, flat in a vertical one. */
179
+ const separatorStyle = $derived(
180
+ `${vertical ? 'height' : 'width'}: 1px; align-self: stretch; background: currentColor; ` +
181
+ 'opacity: 0.2',
182
+ );
183
+
184
+ /** The toolbar runs along its orientation; a `style` of yours comes after. */
185
+ const rootStyle = $derived(
186
+ `position: relative; display: flex; flex-direction: ${vertical ? 'column' : 'row'}; ` +
187
+ `align-items: center; ${style ?? ''}`,
188
+ );
189
+
190
+ /** Marks the element around each item of the live row: its first focusable element is a stop. */
191
+ const TOOLBAR_ITEM = { [TOOLBAR_ITEM_ATTRIBUTE]: '' };
192
+
193
+ /**
194
+ * The hidden measurement layer: a row for a horizontal toolbar, a column for a vertical one, and
195
+ * no height either way, so it never adds to the page. A column keeps each item at its own
196
+ * width, so no text wraps and changes the heights it reports.
197
+ */
198
+ const measureLayerStyle = $derived(
199
+ 'position: absolute; left: 0; top: 0; height: 0; overflow: hidden; visibility: hidden; ' +
200
+ 'pointer-events: none; display: flex; white-space: nowrap;' +
201
+ (vertical ? ' flex-direction: column; align-items: flex-start;' : ''),
202
+ );
203
+ </script>
204
+
205
+ {#snippet commandButton(item: ResolvedCommand, variant: string, run: () => void)}
206
+ {#if command}
207
+ {@render command(item, variant, run)}
208
+ {:else}
209
+ <DefaultCommand command={item} {run} />
210
+ {/if}
211
+ {/snippet}
212
+
213
+ {#snippet part(item: ToolbarPart, layer: 'live' | 'measure')}
214
+ {#if item.kind === 'command'}
215
+ {@render commandButton(item.command, item.variant, item.run)}
216
+ {:else if item.kind === 'custom'}
217
+ {#if custom}
218
+ {@render custom(item.name, item.variant, {
219
+ layer,
220
+ measure: (length) => report(item.measureKey, length),
221
+ })}
222
+ {:else}
223
+ <NativeSlotSocket
224
+ name={item.name}
225
+ {orientation}
226
+ onLength={(length) => report(item.measureKey, length)}
227
+ >
228
+ {#if item.terminal}
229
+ {@render commandButton(item.terminal, 'icon', item.runTerminal)}
230
+ {/if}
231
+ </NativeSlotSocket>
232
+ {/if}
233
+ {:else if item.kind === 'collapsed'}
234
+ {#if collapsed}
235
+ {@render collapsed(item.view)}
236
+ {:else}
237
+ <DefaultCollapsed view={item.view} {orientation} />
238
+ {/if}
239
+ {:else if groupTrigger}
240
+ {@render groupTrigger(item.view)}
241
+ {:else}
242
+ <DefaultGroupTrigger view={item.view} {orientation} />
243
+ {/if}
244
+ {/snippet}
245
+
246
+ {#snippet moreButton(isOpen: boolean, toggle: () => void)}
247
+ {#if overflowTrigger}
248
+ {@render overflowTrigger(isOpen, toggle)}
249
+ {:else}
250
+ <DefaultOverflowTrigger {isOpen} {toggle} />
251
+ {/if}
252
+ {/snippet}
253
+
254
+ <div
255
+ bind:this={container}
256
+ role="toolbar"
257
+ aria-orientation={orientation}
258
+ aria-label={ariaLabel}
259
+ class={className}
260
+ style={rootStyle}
261
+ >
262
+ {#each layout.sections as section (section.name)}
263
+ <div style={sectionStyle(section.name)}>
264
+ {#each section.groups as group, index (group.id)}
265
+ {#if index > 0}
266
+ {#if separator}
267
+ {@render separator()}
268
+ {:else}
269
+ <span style={separatorStyle}></span>
270
+ {/if}
271
+ {/if}
272
+ {#each group.parts as item (item.key)}
273
+ <!-- The element around an item adds no box: the item lays out as the section's child. -->
274
+ <span {...TOOLBAR_ITEM} style="display: contents">{@render part(item, 'live')}</span>
275
+ {/each}
276
+ {/each}
277
+ {#if section.name === 'end' && layout.hasOverflow}
278
+ <span {...TOOLBAR_ITEM} style="position: relative; display: inline-flex">
279
+ {@render moreButton(overflowOpen, toggleOverflow)}
280
+ {#if overflowMenu}
281
+ {@render overflowMenu(overflowView)}
282
+ {:else}
283
+ <DefaultOverflowMenu view={overflowView} {orientation} />
284
+ {/if}
285
+ </span>
286
+ {/if}
287
+ </div>
288
+ {/each}
289
+
290
+ <!-- The measurement layer: hidden, inert and observed. Text reflow (a language, a font,
291
+ browser zoom) fires the observers; no code handles it. -->
292
+ <div aria-hidden="true" inert style={measureLayerStyle}>
293
+ {#each layout.measured as measuredPart (measuredPart.measureKey)}
294
+ <!-- A custom item without a `custom` snippet is a socket, measured where it renders: a
295
+ second <slot> of its name here would take the projected children from the row. One
296
+ whose snippet draws nothing here is measured where it renders too, by `ctx.measure`. -->
297
+ {#if measuredPart.kind !== 'custom' || custom}
298
+ <Measured
299
+ {orientation}
300
+ onlyWhenDrawn={measuredPart.kind === 'custom'}
301
+ onLength={(length) => report(measuredPart.measureKey, length)}
302
+ >
303
+ {@render part(measuredPart, 'measure')}
304
+ </Measured>
305
+ {/if}
306
+ {/each}
307
+ <Measured
308
+ {orientation}
309
+ onLength={(length) => report(toolbarMeasureKey.overflowTrigger, length)}
310
+ >
311
+ {@render moreButton(false, noop)}
312
+ </Measured>
313
+ </div>
314
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { ToolbarProps } from './props.js';
2
+ declare const Toolbar: import("svelte").Component<ToolbarProps, {}, "">;
3
+ type Toolbar = ReturnType<typeof Toolbar>;
4
+ export default Toolbar;
@@ -0,0 +1,3 @@
1
+ export declare const SURFACE: string;
2
+ export declare const BORDER: string;
3
+ export declare const ACTIVE: string;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The default parts' colors: CSS variables only, because the defaults are meant to be replaced.
3
+ * `--epdf-toolbar-surface` (the "More" menu and folded groups), `--epdf-toolbar-border` and
4
+ * `--epdf-toolbar-active` (a pressed or open button).
5
+ */
6
+ import { paintDefault } from '@embedpdf/web';
7
+ export const SURFACE = paintDefault('toolbar-surface');
8
+ export const BORDER = paintDefault('toolbar-border');
9
+ export const ACTIVE = paintDefault('toolbar-active');
@@ -0,0 +1,48 @@
1
+ /** The props of `<Toolbar>`: the bar and how it runs, and a snippet for every part you draw. */
2
+ import type { Snippet } from 'svelte';
3
+ import type { BarSchema, CustomSlotCtx } from '@embedpdf/core-ui';
4
+ import type { ResolvedCommand } from '@embedpdf/plugin-commands/contract';
5
+ import type { CollapsedGroupView, GroupDisclosureView, OverflowMenuView } from './views.js';
6
+ export interface ToolbarProps {
7
+ /** What goes in the toolbar: its sections, groups and items. */
8
+ bar: BarSchema;
9
+ /**
10
+ * Which way the toolbar runs. A vertical toolbar fits the height it's given, so give it one; it
11
+ * stacks its sections top, middle and bottom, and draws every command at `'icon'`, with the
12
+ * label for a tooltip. Default `'horizontal'`.
13
+ */
14
+ orientation?: 'horizontal' | 'vertical';
15
+ /** Px between adjacent items (the CSS flex gap; the fit budgets the same number). Default 8. */
16
+ gap?: number;
17
+ /**
18
+ * The thickness of the separator your `separator` snippet draws: its width across a horizontal
19
+ * toolbar, its height in a vertical one. Default 1.
20
+ */
21
+ separatorWidth?: number;
22
+ /** The toolbar's name for screen readers, for a page with more than one toolbar. */
23
+ 'aria-label'?: string;
24
+ class?: string;
25
+ style?: string;
26
+ /** A command's button at a variant. Default: a plain `<button>` with the command's label. */
27
+ command?: Snippet<[command: ResolvedCommand, variant: string, run: () => void]>;
28
+ /**
29
+ * Your own items, by `name` (from `custom(name, command)`): it draws every custom item in the
30
+ * bar, in the live row and in the hidden measurement layer (`ctx.layer`). Without it, each item
31
+ * is a native `<slot name>` element with its command's button inside, for a custom element's
32
+ * children to fill. An item the snippet draws nothing for in the measurement layer
33
+ * (`ctx.layer === 'measure'`) is measured where it renders instead: report its length with
34
+ * `ctx.measure`. The first element of an item that takes focus is the item's stop in the
35
+ * toolbar's arrow-key order.
36
+ */
37
+ custom?: Snippet<[name: string, variant: string, ctx: CustomSlotCtx]>;
38
+ /** A folded group: its button and its menu. Default: a `<select>` for `'select'`, a menu button for `'menu'`. */
39
+ collapsed?: Snippet<[view: CollapsedGroupView]>;
40
+ /** The button of a group that shed items, and its menu. Default: a chevron opening a menu. */
41
+ groupTrigger?: Snippet<[view: GroupDisclosureView]>;
42
+ /** The line between groups. Default: a 1px line across the toolbar. */
43
+ separator?: Snippet;
44
+ /** The "More" button. Default: a plain ⋯ button. */
45
+ overflowTrigger?: Snippet<[isOpen: boolean, toggle: () => void]>;
46
+ /** The "More" menu, with its sections, rows and the call that runs each one. Default: a minimal popover. */
47
+ overflowMenu?: Snippet<[view: OverflowMenuView]>;
48
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ import type { BarSchema, StripView as StripViewOf, StripViewGroup as StripViewGroupOf } from '@embedpdf/core-ui';
2
+ import type { ResolvedCommand } from '@embedpdf/plugin-commands/contract';
3
+ import { type CurrentValue, type MaybeGetter } from '../runtime/values.svelte.js';
4
+ /** A group of a strip: its visible commands, in bar order. Groups are separator boundaries. */
5
+ export type StripViewGroup = StripViewGroupOf<ResolvedCommand>;
6
+ /** A strip, resolved: only visible commands, only groups with one; `execute` runs one for this component's document. */
7
+ export type StripView = StripViewOf<ResolvedCommand>;
8
+ /**
9
+ * The strip a bar shows now, as `{ current }`: the schema says what could appear, each command's
10
+ * `visible` decides what does. `null` while nothing applies, so `{#if strip.current}` is all the
11
+ * show-and-hide logic a strip needs. `current` changes only when a command in it changes. Pass a
12
+ * function for a bar that changes.
13
+ */
14
+ export declare function useStripView(bar: MaybeGetter<BarSchema | undefined>): CurrentValue<StripView | null>;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * `useStripView(bar)`: a bar projected through the command registry, live and unmeasured.
3
+ * `<Toolbar>`'s sibling, for a contextual strip (a chrome schema's `strips`) that has no width to
4
+ * fit into.
5
+ */
6
+ import { normalizeBar, sameStripGroups, stripGroupsOf } from '@embedpdf/core-ui';
7
+ import { CommandsToken } from '@embedpdf/plugin-commands/contract/host';
8
+ import { resolvedCommandsEqual } from '@embedpdf/plugin-commands/contract';
9
+ import { useCapability, useDocumentId, useKernelValue } from '../runtime/readers.svelte.js';
10
+ import { currentOf, derivedValue, valueOf, } from '../runtime/values.svelte.js';
11
+ const sameGroups = (left, right) => sameStripGroups(left, right, resolvedCommandsEqual);
12
+ const NO_GROUPS = Object.freeze([]);
13
+ /**
14
+ * The strip a bar shows now, as `{ current }`: the schema says what could appear, each command's
15
+ * `visible` decides what does. `null` while nothing applies, so `{#if strip.current}` is all the
16
+ * show-and-hide logic a strip needs. `current` changes only when a command in it changes. Pass a
17
+ * function for a bar that changes.
18
+ */
19
+ export function useStripView(bar) {
20
+ const commands = useCapability(CommandsToken);
21
+ const documentId = useDocumentId();
22
+ const normalized = $derived.by(() => {
23
+ const schema = valueOf(bar);
24
+ return schema ? normalizeBar(schema) : null;
25
+ });
26
+ const groups = useKernelValue(() => normalized
27
+ ? stripGroupsOf(normalized, (id) => commands.resolveCommand(id, documentId.current ?? undefined))
28
+ : NO_GROUPS, sameGroups);
29
+ return currentOf(derivedValue(() => groups.current.length === 0
30
+ ? null
31
+ : {
32
+ groups: groups.current,
33
+ execute: (id) => void commands.execute(id, { documentId: documentId.current ?? undefined }),
34
+ }));
35
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The views `<Toolbar>`'s snippets receive and the parts it draws: core-ui's (`layoutToolbar`,
3
+ * `groupMenuView`), over the commands plugin's resolved command.
4
+ */
5
+ import type { CollapsedGroupView as CollapsedGroupViewOf, GroupDisclosureView as GroupDisclosureViewOf, OverflowMenuView as OverflowMenuViewOf, ToolbarPart as ToolbarPartOf } from '@embedpdf/core-ui';
6
+ import type { ResolvedCommand } from '@embedpdf/plugin-commands/contract';
7
+ /** What the `collapsed` snippet draws: a group folded into one control. */
8
+ export type CollapsedGroupView = CollapsedGroupViewOf<ResolvedCommand>;
9
+ /** What the `groupTrigger` snippet draws: the button inside a group that shed some of its items. */
10
+ export type GroupDisclosureView = GroupDisclosureViewOf<ResolvedCommand>;
11
+ /** What the `overflowMenu` snippet draws: the "More" menu. */
12
+ export type OverflowMenuView = OverflowMenuViewOf<ResolvedCommand>;
13
+ /** One thing in the toolbar, as `<Toolbar>` draws it. */
14
+ export type ToolbarPart = ToolbarPartOf<ResolvedCommand>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @embedpdf/svelte/toolbar — a toolbar that fits the room it has.
3
+ *
4
+ * `<Toolbar>` fits a bar of commands into its width, or its height when it's vertical (labels
5
+ * become icons, groups fold, the rest goes into a "More" menu), is one tab stop with arrow keys
6
+ * along it, and lets you draw every part with snippets; `useStripView()` is a strip that doesn't
7
+ * fit itself; and the schema a bar is written in comes from here too.
8
+ */
9
+ export { DEFAULT_IMPORTANCE, PINNED, custom, group, item } from '@embedpdf/core-ui';
10
+ export type { BarChild, BarGroup, BarItem, BarSchema, BarSections, CustomItem, Importance, OverflowRow, OverflowSection, Variant, } from '@embedpdf/core-ui';
11
+ export { default as Toolbar } from './toolbar/Toolbar.svelte';
12
+ export type { ToolbarProps } from './toolbar/props.js';
13
+ export type { CustomSlotCtx } from '@embedpdf/core-ui';
14
+ export type { CollapsedGroupView, GroupDisclosureView, OverflowMenuView } from './toolbar/views.js';
15
+ export { useStripView } from './toolbar/strip.svelte.js';
16
+ export type { StripView, StripViewGroup } from './toolbar/strip.svelte.js';
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @embedpdf/svelte/toolbar — a toolbar that fits the room it has.
3
+ *
4
+ * `<Toolbar>` fits a bar of commands into its width, or its height when it's vertical (labels
5
+ * become icons, groups fold, the rest goes into a "More" menu), is one tab stop with arrow keys
6
+ * along it, and lets you draw every part with snippets; `useStripView()` is a strip that doesn't
7
+ * fit itself; and the schema a bar is written in comes from here too.
8
+ */
9
+ // The toolbar's vocabulary: the schema a bar is written in.
10
+ export { DEFAULT_IMPORTANCE, PINNED, custom, group, item } from '@embedpdf/core-ui';
11
+ export { default as Toolbar } from './toolbar/Toolbar.svelte';
12
+ export { useStripView } from './toolbar/strip.svelte.js';
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The view manager's readers: the API, the panes as a reactive object, and its events. The view
3
+ * manager is a workspace plugin, so all three work before any document opens.
4
+ */
5
+ import type { EventHook } from '@embedpdf/core';
6
+ import type { ViewManagerCapability } from '@embedpdf/plugin-view-manager';
7
+ /** The view manager's API (panes and their tabs), for app code. */
8
+ export declare function useViewManager(): ViewManagerCapability;
9
+ /**
10
+ * The panes, in order, and the focused one's id (the page's State table, declared once in
11
+ * `viewManagerState`), as a reactive object: `state.panes`. With a selector, the value it picks as
12
+ * `{ current }`, which changes only when that value does.
13
+ */
14
+ export declare const useViewManagerState: import("../index.js").StateReader<{
15
+ panes: readonly import("@embedpdf/plugin-view-manager").PaneInfo[];
16
+ focusedPaneId: string | null;
17
+ }>;
18
+ /** Subscribe to one view-manager event while the component lives: `useViewManagerEvent((viewManager) => viewManager.onDocumentMoved, handler)`. */
19
+ export declare function useViewManagerEvent<T>(select: (viewManager: ViewManagerCapability) => EventHook<T>, handler: (event: T) => void): void;
@@ -0,0 +1,17 @@
1
+ import { ViewManagerToken, viewManagerState } from '@embedpdf/plugin-view-manager';
2
+ import { useCapability, useCapabilityEvent } from '../runtime/readers.svelte.js';
3
+ import { stateReader } from '../runtime/state.svelte.js';
4
+ /** The view manager's API (panes and their tabs), for app code. */
5
+ export function useViewManager() {
6
+ return useCapability(ViewManagerToken);
7
+ }
8
+ /**
9
+ * The panes, in order, and the focused one's id (the page's State table, declared once in
10
+ * `viewManagerState`), as a reactive object: `state.panes`. With a selector, the value it picks as
11
+ * `{ current }`, which changes only when that value does.
12
+ */
13
+ export const useViewManagerState = stateReader(viewManagerState);
14
+ /** Subscribe to one view-manager event while the component lives: `useViewManagerEvent((viewManager) => viewManager.onDocumentMoved, handler)`. */
15
+ export function useViewManagerEvent(select, handler) {
16
+ useCapabilityEvent(ViewManagerToken, select, handler);
17
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @embedpdf/svelte/view-manager — panes, each with its own tabs.
3
+ *
4
+ * It stays headless: it gives you the panes, and you lay them out (split, grid, stacked), draw
5
+ * each pane's tab strip over `pane.documentIds`, and wrap its body in
6
+ * `<DocumentScope id={pane.activeDocumentId}>` so its Stage shows that pane's document. The
7
+ * readers are the plugin's: `useViewManager()` (the API), `useViewManagerState()` and
8
+ * `useViewManagerEvent()`.
9
+ */
10
+ export * from '@embedpdf/plugin-view-manager';
11
+ export { useViewManager, useViewManagerEvent, useViewManagerState, } from './view-manager/readers.js';
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @embedpdf/svelte/view-manager — panes, each with its own tabs.
3
+ *
4
+ * It stays headless: it gives you the panes, and you lay them out (split, grid, stacked), draw
5
+ * each pane's tab strip over `pane.documentIds`, and wrap its body in
6
+ * `<DocumentScope id={pane.activeDocumentId}>` so its Stage shows that pane's document. The
7
+ * readers are the plugin's: `useViewManager()` (the API), `useViewManagerState()` and
8
+ * `useViewManagerEvent()`.
9
+ */
10
+ // Registration travels with the UI.
11
+ export * from '@embedpdf/plugin-view-manager';
12
+ export { useViewManager, useViewManagerEvent, useViewManagerState, } from './view-manager/readers.js';