@embedpdf/viewer-chrome 3.0.0-next.14 → 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 (177) hide show
  1. package/README.md +175 -132
  2. package/dist/annotation-fonts-DWjVOTP0.js +80 -0
  3. package/dist/annotation-fonts-DWjVOTP0.js.map +1 -0
  4. package/dist/annotation-fonts-dpfVkhnq.cjs +91 -0
  5. package/dist/annotation-fonts-dpfVkhnq.cjs.map +1 -0
  6. package/dist/annotation-style-B3XKAyZ-.cjs +879 -0
  7. package/dist/annotation-style-B3XKAyZ-.cjs.map +1 -0
  8. package/dist/annotation-style-CXF3X47Z.js +879 -0
  9. package/dist/annotation-style-CXF3X47Z.js.map +1 -0
  10. package/dist/ar-B132r9bo.cjs +659 -0
  11. package/dist/ar-B132r9bo.cjs.map +1 -0
  12. package/dist/ar-BLWFJoA_.js +659 -0
  13. package/dist/ar-BLWFJoA_.js.map +1 -0
  14. package/dist/attachments-panel-Cxln8xos.cjs +217 -0
  15. package/dist/attachments-panel-Cxln8xos.cjs.map +1 -0
  16. package/dist/attachments-panel-H1ucRbwo.js +217 -0
  17. package/dist/attachments-panel-H1ucRbwo.js.map +1 -0
  18. package/dist/chrome.cjs +399 -242
  19. package/dist/chrome.cjs.map +1 -1
  20. package/dist/chrome.d.cts +5 -35
  21. package/dist/chrome.d.ts +5 -35
  22. package/dist/chrome.js +398 -239
  23. package/dist/chrome.js.map +1 -1
  24. package/dist/commands-BkgLP3Om.js +1348 -0
  25. package/dist/commands-BkgLP3Om.js.map +1 -0
  26. package/dist/commands-DL1gjZt7.cjs +1473 -0
  27. package/dist/commands-DL1gjZt7.cjs.map +1 -0
  28. package/dist/commands.cjs +13 -649
  29. package/dist/commands.d.cts +30 -3
  30. package/dist/commands.d.ts +30 -3
  31. package/dist/commands.js +2 -647
  32. package/dist/comments-panel-BsnWedTh.cjs +514 -0
  33. package/dist/comments-panel-BsnWedTh.cjs.map +1 -0
  34. package/dist/comments-panel-D7Eadws9.js +514 -0
  35. package/dist/comments-panel-D7Eadws9.js.map +1 -0
  36. package/dist/de-7_MvFWzN.cjs +658 -0
  37. package/dist/de-7_MvFWzN.cjs.map +1 -0
  38. package/dist/de-BUhwc9-x.js +658 -0
  39. package/dist/de-BUhwc9-x.js.map +1 -0
  40. package/dist/dialog-BIb373cg.js +55 -0
  41. package/dist/dialog-BIb373cg.js.map +1 -0
  42. package/dist/dialog-CngKTnAM.cjs +60 -0
  43. package/dist/dialog-CngKTnAM.cjs.map +1 -0
  44. package/dist/es-DgYj-1L3.cjs +658 -0
  45. package/dist/es-DgYj-1L3.cjs.map +1 -0
  46. package/dist/es-DoXTqFoO.js +658 -0
  47. package/dist/es-DoXTqFoO.js.map +1 -0
  48. package/dist/form-design-panel-CgV_5YWC.js +418 -0
  49. package/dist/form-design-panel-CgV_5YWC.js.map +1 -0
  50. package/dist/form-design-panel-D0FdmWXW.cjs +418 -0
  51. package/dist/form-design-panel-D0FdmWXW.cjs.map +1 -0
  52. package/dist/fr-B-8NDhBA.js +658 -0
  53. package/dist/fr-B-8NDhBA.js.map +1 -0
  54. package/dist/fr-C856dmQJ.cjs +658 -0
  55. package/dist/fr-C856dmQJ.cjs.map +1 -0
  56. package/dist/he-BFTeNc4t.cjs +659 -0
  57. package/dist/he-BFTeNc4t.cjs.map +1 -0
  58. package/dist/he-Dlh0fNXM.js +659 -0
  59. package/dist/he-Dlh0fNXM.js.map +1 -0
  60. package/dist/icons-1UfLUZ_y.cjs +1029 -0
  61. package/dist/icons-1UfLUZ_y.cjs.map +1 -0
  62. package/dist/icons-7dB0Y1ct.js +875 -0
  63. package/dist/icons-7dB0Y1ct.js.map +1 -0
  64. package/dist/index.cjs +3651 -5447
  65. package/dist/index.cjs.map +1 -1
  66. package/dist/index.d.cts +646 -144
  67. package/dist/index.d.ts +646 -144
  68. package/dist/index.js +3618 -5368
  69. package/dist/index.js.map +1 -1
  70. package/dist/it-Bef-2Yxq.cjs +658 -0
  71. package/dist/it-Bef-2Yxq.cjs.map +1 -0
  72. package/dist/it-BkirG7ol.js +658 -0
  73. package/dist/it-BkirG7ol.js.map +1 -0
  74. package/dist/ja-CGEjCE-s.js +658 -0
  75. package/dist/ja-CGEjCE-s.js.map +1 -0
  76. package/dist/ja-DNw2zqSD.cjs +658 -0
  77. package/dist/ja-DNw2zqSD.cjs.map +1 -0
  78. package/dist/ko-CTkl5vMh.js +658 -0
  79. package/dist/ko-CTkl5vMh.js.map +1 -0
  80. package/dist/ko-YHzeBqP6.cjs +658 -0
  81. package/dist/ko-YHzeBqP6.cjs.map +1 -0
  82. package/dist/labels-BiM9wp9K.cjs +21 -0
  83. package/dist/labels-BiM9wp9K.cjs.map +1 -0
  84. package/dist/labels-C6_i87Oj.js +16 -0
  85. package/dist/labels-C6_i87Oj.js.map +1 -0
  86. package/dist/link-editor-CAS7MZM2.cjs +125 -0
  87. package/dist/link-editor-CAS7MZM2.cjs.map +1 -0
  88. package/dist/link-editor-CkwtqRvb.js +125 -0
  89. package/dist/link-editor-CkwtqRvb.js.map +1 -0
  90. package/dist/measurement-CQdbnIrn.js +325 -0
  91. package/dist/measurement-CQdbnIrn.js.map +1 -0
  92. package/dist/measurement-Cxv1Ahxx.cjs +326 -0
  93. package/dist/measurement-Cxv1Ahxx.cjs.map +1 -0
  94. package/dist/nl-BjkbaLq3.cjs +658 -0
  95. package/dist/nl-BjkbaLq3.cjs.map +1 -0
  96. package/dist/nl-Dya4sR8_.js +658 -0
  97. package/dist/nl-Dya4sR8_.js.map +1 -0
  98. package/dist/outline-panel-BpGtBdj0.cjs +707 -0
  99. package/dist/outline-panel-BpGtBdj0.cjs.map +1 -0
  100. package/dist/outline-panel-DO5_REYw.js +707 -0
  101. package/dist/outline-panel-DO5_REYw.js.map +1 -0
  102. package/dist/outline-properties-BCa2cc0t.js +330 -0
  103. package/dist/outline-properties-BCa2cc0t.js.map +1 -0
  104. package/dist/outline-properties-DT3FIxCw.cjs +330 -0
  105. package/dist/outline-properties-DT3FIxCw.cjs.map +1 -0
  106. package/dist/pl-CKKdVnpZ.cjs +658 -0
  107. package/dist/pl-CKKdVnpZ.cjs.map +1 -0
  108. package/dist/pl-DA9b5NVg.js +658 -0
  109. package/dist/pl-DA9b5NVg.js.map +1 -0
  110. package/dist/print-dialog-BqIrHCBh.cjs +276 -0
  111. package/dist/print-dialog-BqIrHCBh.cjs.map +1 -0
  112. package/dist/print-dialog-DvcI2m2_.js +276 -0
  113. package/dist/print-dialog-DvcI2m2_.js.map +1 -0
  114. package/dist/pt-DLcszlzi.cjs +658 -0
  115. package/dist/pt-DLcszlzi.cjs.map +1 -0
  116. package/dist/pt-Nm8yyjbX.js +658 -0
  117. package/dist/pt-Nm8yyjbX.js.map +1 -0
  118. package/dist/redact-confirm-C6EiK8yN.cjs +83 -0
  119. package/dist/redact-confirm-C6EiK8yN.cjs.map +1 -0
  120. package/dist/redact-confirm-CKuv9iN_.js +83 -0
  121. package/dist/redact-confirm-CKuv9iN_.js.map +1 -0
  122. package/dist/redaction-panel-CgNZ-pQk.js +96 -0
  123. package/dist/redaction-panel-CgNZ-pQk.js.map +1 -0
  124. package/dist/redaction-panel-ZhX0dlMi.cjs +96 -0
  125. package/dist/redaction-panel-ZhX0dlMi.cjs.map +1 -0
  126. package/dist/search-panel-BE4xzWlm.js +249 -0
  127. package/dist/search-panel-BE4xzWlm.js.map +1 -0
  128. package/dist/search-panel-wcbTNG1z.cjs +249 -0
  129. package/dist/search-panel-wcbTNG1z.cjs.map +1 -0
  130. package/dist/sheet-DTBFiwde.cjs +461 -0
  131. package/dist/sheet-DTBFiwde.cjs.map +1 -0
  132. package/dist/sheet-DyjKfAq0.js +378 -0
  133. package/dist/sheet-DyjKfAq0.js.map +1 -0
  134. package/dist/sign-dialog-D5WGx-Yn.cjs +155 -0
  135. package/dist/sign-dialog-D5WGx-Yn.cjs.map +1 -0
  136. package/dist/sign-dialog-DerNe8qT.js +155 -0
  137. package/dist/sign-dialog-DerNe8qT.js.map +1 -0
  138. package/dist/signature-inspector-Bz6TAfZM.cjs +160 -0
  139. package/dist/signature-inspector-Bz6TAfZM.cjs.map +1 -0
  140. package/dist/signature-inspector-CsGr9EBk.js +160 -0
  141. package/dist/signature-inspector-CsGr9EBk.js.map +1 -0
  142. package/dist/signature-maker-D_YfBXLn.cjs +393 -0
  143. package/dist/signature-maker-D_YfBXLn.cjs.map +1 -0
  144. package/dist/signature-maker-Dnth4rV4.js +393 -0
  145. package/dist/signature-maker-Dnth4rV4.js.map +1 -0
  146. package/dist/signatures-panel-Ci_LaI1C.cjs +294 -0
  147. package/dist/signatures-panel-Ci_LaI1C.cjs.map +1 -0
  148. package/dist/signatures-panel-DZ9ywrjz.js +294 -0
  149. package/dist/signatures-panel-DZ9ywrjz.js.map +1 -0
  150. package/dist/stamp-store-BHvRs-Do.cjs +147 -0
  151. package/dist/stamp-store-BHvRs-Do.cjs.map +1 -0
  152. package/dist/stamp-store-WuF-L3Jj.js +112 -0
  153. package/dist/stamp-store-WuF-L3Jj.js.map +1 -0
  154. package/dist/stamps-panel-BrczStaz.js +225 -0
  155. package/dist/stamps-panel-BrczStaz.js.map +1 -0
  156. package/dist/stamps-panel-Cv9nJBwx.cjs +225 -0
  157. package/dist/stamps-panel-Cv9nJBwx.cjs.map +1 -0
  158. package/dist/theme-Be0OZokZ.js +97 -0
  159. package/dist/theme-Be0OZokZ.js.map +1 -0
  160. package/dist/theme-FR26JI3r.cjs +126 -0
  161. package/dist/theme-FR26JI3r.cjs.map +1 -0
  162. package/dist/toolbar-DF361xWY.js +1565 -0
  163. package/dist/toolbar-DF361xWY.js.map +1 -0
  164. package/dist/toolbar-ddvpsvTb.cjs +1660 -0
  165. package/dist/toolbar-ddvpsvTb.cjs.map +1 -0
  166. package/dist/zh-cn-BMPPkLpL.js +658 -0
  167. package/dist/zh-cn-BMPPkLpL.js.map +1 -0
  168. package/dist/zh-cn-CZOO3p4H.cjs +658 -0
  169. package/dist/zh-cn-CZOO3p4H.cjs.map +1 -0
  170. package/package.json +6 -4
  171. package/src/styles.css +161 -89
  172. package/dist/commands.cjs.map +0 -1
  173. package/dist/commands.js.map +0 -1
  174. package/dist/es-BXLlBo2b.cjs +0 -321
  175. package/dist/es-BXLlBo2b.cjs.map +0 -1
  176. package/dist/es-CLgTsFDS.js +0 -321
  177. package/dist/es-CLgTsFDS.js.map +0 -1
@@ -0,0 +1,1473 @@
1
+ let _embedpdf_react_runtime = require("@embedpdf/react/runtime");
2
+ let _embedpdf_react_stage = require("@embedpdf/react/stage");
3
+ let _embedpdf_react_page_edit = require("@embedpdf/react/page-edit");
4
+ let _embedpdf_react_outline = require("@embedpdf/react/outline");
5
+ let _embedpdf_react_attachment = require("@embedpdf/react/attachment");
6
+ let _embedpdf_react_interaction = require("@embedpdf/react/interaction");
7
+ let _embedpdf_react_selection = require("@embedpdf/react/selection");
8
+ let _embedpdf_react_annotation = require("@embedpdf/react/annotation");
9
+ let _embedpdf_react_stamp = require("@embedpdf/react/stamp");
10
+ let _embedpdf_react_measurement = require("@embedpdf/react/measurement");
11
+ let _embedpdf_react_redaction = require("@embedpdf/react/redaction");
12
+ let _embedpdf_react_form = require("@embedpdf/react/form");
13
+ let _embedpdf_react_signature = require("@embedpdf/react/signature");
14
+ let _embedpdf_react_link = require("@embedpdf/react/link");
15
+ let _embedpdf_react_i18n = require("@embedpdf/react/i18n");
16
+ let _embedpdf_react_commands = require("@embedpdf/react/commands");
17
+ let _embedpdf_react_history = require("@embedpdf/react/history");
18
+ let _embedpdf_react_shell = require("@embedpdf/react/shell");
19
+ let _embedpdf_core_ui = require("@embedpdf/core-ui");
20
+ let _embedpdf_web = require("@embedpdf/web");
21
+ //#region src/config/attachments.ts
22
+ /**
23
+ * The attachment commands, for the attachments panel (its header, each file's menu) and the
24
+ * strip over a selected file attachment annotation. The panel's commands act on the selected
25
+ * file (`attachment.getSelected()`); the panel selects a file before it opens that file's menu.
26
+ * Adding and deleting need `doc.attachments.modify` (a page's file: the annotation plugin's
27
+ * `canDelete()`) and the `attachments.adding` feature. Saving takes a file out of the document,
28
+ * so it goes with `documents.download` and needs `doc.download`: `readOnly` keeps it.
29
+ */
30
+ /** The attachments panel's id in the layout. */
31
+ const ATTACHMENTS_PANEL = "attachments";
32
+ /** The menu of a file in the attachments panel: the commands below, for that file. */
33
+ const ATTACHMENT_ITEM_MENU = "attachment-item";
34
+ const attachmentOf = (commandContext) => commandContext.tryGet(_embedpdf_react_attachment.AttachmentToken);
35
+ /** The first selected file. */
36
+ const selectedOf$2 = (commandContext) => attachmentOf(commandContext)?.getSelected()[0] ?? null;
37
+ /** Save a file as the browser saves a download, under its cleaned name. */
38
+ async function saveAttachedFile(attachment, file) {
39
+ const { bytes, name, mimeType } = await attachment.download(file);
40
+ (0, _embedpdf_web.saveFile)(bytes, name, mimeType ?? void 0);
41
+ }
42
+ /** The one file attachment annotation selected on the pages, or null. */
43
+ const selectedAnnotationFile = (commandContext) => {
44
+ const selection = commandContext.tryGet(_embedpdf_react_annotation.AnnotationToken)?.selection.list() ?? [];
45
+ const [only] = selection;
46
+ if (selection.length !== 1 || only?.subtype !== "file-attachment") return null;
47
+ const key = (0, _embedpdf_react_annotation.annotationKey)(only.ref);
48
+ return (attachmentOf(commandContext)?.list() ?? []).find((file) => file.home.kind === "page" && (0, _embedpdf_react_annotation.annotationKey)(file.home.ref) === key) ?? null;
49
+ };
50
+ /** Saving: the right to take files out, and the feature on. */
51
+ const SAVES = {
52
+ categories: ["documents.download"],
53
+ allowed: (commandContext) => attachmentOf(commandContext)?.canDownload() ?? true,
54
+ notAllowedKey: "commands.notAllowed.doc-download"
55
+ };
56
+ /** Adding and deleting: the right to, and the feature on. */
57
+ const EDITS$1 = {
58
+ categories: ["attachments.adding"],
59
+ allowed: (commandContext) => attachmentOf(commandContext)?.canAdd() ?? true,
60
+ notAllowedKey: "commands.notAllowed.doc-attachments-modify"
61
+ };
62
+ const attachmentCommands = [
63
+ {
64
+ id: "attachment:add",
65
+ labelKey: "commands.attachment.add",
66
+ icon: "plus",
67
+ ...EDITS$1,
68
+ run: async (commandContext) => {
69
+ const attachment = attachmentOf(commandContext);
70
+ if (!attachment) return;
71
+ const files = commandContext.args?.files ?? [await (0, _embedpdf_web.pickFile)()].filter((file) => file !== null);
72
+ if (files.length === 0) return;
73
+ commandContext.tryGet(_embedpdf_react_shell.ShellToken)?.open(ATTACHMENTS_PANEL);
74
+ await attachment.add(files.map((data) => ({ data })));
75
+ }
76
+ },
77
+ {
78
+ id: "attachment:save",
79
+ labelKey: "commands.attachment.save",
80
+ icon: "download",
81
+ ...SAVES,
82
+ enabled: (commandContext) => selectedOf$2(commandContext) !== null,
83
+ run: async (commandContext) => {
84
+ const attachment = attachmentOf(commandContext);
85
+ const file = selectedOf$2(commandContext);
86
+ if (attachment && file) await saveAttachedFile(attachment, file);
87
+ }
88
+ },
89
+ {
90
+ id: "attachment:go-to",
91
+ labelKey: "commands.attachment.goTo",
92
+ visible: (commandContext) => selectedOf$2(commandContext)?.home.kind === "page",
93
+ run: (commandContext) => {
94
+ const file = selectedOf$2(commandContext);
95
+ if (file) attachmentOf(commandContext)?.reveal(file);
96
+ }
97
+ },
98
+ {
99
+ id: "attachment:delete",
100
+ labelKey: "commands.attachment.delete",
101
+ icon: "trash",
102
+ ...EDITS$1,
103
+ allowed: (commandContext) => {
104
+ const attachment = attachmentOf(commandContext);
105
+ const file = selectedOf$2(commandContext);
106
+ if (!attachment) return true;
107
+ return file ? attachment.canRemove(file) : attachment.canAdd();
108
+ },
109
+ enabled: (commandContext) => selectedOf$2(commandContext) !== null,
110
+ run: async (commandContext) => {
111
+ const attachment = attachmentOf(commandContext);
112
+ const file = selectedOf$2(commandContext);
113
+ if (attachment && file) await attachment.remove(file);
114
+ }
115
+ },
116
+ {
117
+ id: "menu:attachment-item",
118
+ labelKey: "commands.attachment.more",
119
+ icon: "dots",
120
+ menu: ATTACHMENT_ITEM_MENU,
121
+ categories: ["attachments"]
122
+ },
123
+ {
124
+ id: "annotation:save-file",
125
+ labelKey: "commands.annotate.saveFile",
126
+ icon: "download",
127
+ ...SAVES,
128
+ visible: (commandContext) => selectedAnnotationFile(commandContext) !== null,
129
+ run: async (commandContext) => {
130
+ const attachment = attachmentOf(commandContext);
131
+ const file = selectedAnnotationFile(commandContext);
132
+ if (attachment && file) await saveAttachedFile(attachment, file);
133
+ }
134
+ }
135
+ ];
136
+ //#endregion
137
+ //#region src/config/modes.ts
138
+ /** The exclusivity tag every mode surface opens with. */
139
+ const MODE_TAG = "mode";
140
+ /** The open mode's surface (`mode:<mode>`), or `null` while viewing. */
141
+ function openModeSurfaceOf(shell) {
142
+ return shell.listOpenSurfaces().find((surface) => surface.exclusive === "mode")?.id ?? null;
143
+ }
144
+ /** The layout's modes, in bar order, each titled by its first bar with a title. */
145
+ function modeSpecsOf(data) {
146
+ return (0, _embedpdf_core_ui.modesOf)(data).map((mode) => {
147
+ const titled = (0, _embedpdf_core_ui.barsInMode)(data, mode).map((barId) => data.bars[barId]).find((bar) => bar.title !== void 0 || bar.titleKey !== void 0);
148
+ return {
149
+ mode,
150
+ title: titled?.title,
151
+ titleKey: titled?.titleKey
152
+ };
153
+ });
154
+ }
155
+ /** Whether two lists of modes are the same, title for title. */
156
+ const sameModeSpecs = (left, right) => left.length === right.length && left.every((spec, i) => spec.mode === right[i].mode && spec.title === right[i].title && spec.titleKey === right[i].titleKey);
157
+ /**
158
+ * A command for each mode that has none yet (`isTaken` says which ids do): it opens the mode,
159
+ * or closes it when it is open, and shows the default pointer. Without a title, its tab reads
160
+ * the mode's own name.
161
+ */
162
+ function modeCommandsFor(specs, isTaken) {
163
+ return specs.filter((spec) => !isTaken((0, _embedpdf_core_ui.modeCommandOf)(spec.mode))).map((spec) => {
164
+ const id = (0, _embedpdf_core_ui.modeCommandOf)(spec.mode);
165
+ return {
166
+ id,
167
+ label: spec.title ?? (spec.titleKey === void 0 ? spec.mode : void 0),
168
+ labelKey: spec.titleKey,
169
+ run: (commandContext) => {
170
+ commandContext.tryGet(_embedpdf_react_shell.ShellToken)?.toggle(id, { exclusive: MODE_TAG });
171
+ commandContext.tryGet(_embedpdf_react_interaction.InteractionToken)?.activateTool("pointer");
172
+ },
173
+ active: (commandContext) => commandContext.tryGet(_embedpdf_react_shell.ShellToken)?.isOpen(id) ?? false
174
+ };
175
+ });
176
+ }
177
+ //#endregion
178
+ //#region src/config/open-files.ts
179
+ const OPEN_COMMAND_ID = "document:open";
180
+ const PDF_TYPE$1 = "application/pdf";
181
+ /** Whether a file is a PDF, by its type or, where the system gives it none, its name. */
182
+ const isPdfFile = (file) => file.type === PDF_TYPE$1 || /\.pdf$/i.test(file.name);
183
+ /**
184
+ * Whether a drag may bring a PDF: it carries files, and one of them is a PDF or of a type the
185
+ * browser doesn't know. Text, links and anything dragged inside the page carry no files; where
186
+ * the browser doesn't list the files while dragging, they may be PDFs.
187
+ */
188
+ function mayCarryPdf(transfer) {
189
+ if (!transfer || !Array.from(transfer.types).includes("Files")) return false;
190
+ const files = Array.from(transfer.items ?? []).filter((item) => item.kind === "file");
191
+ return files.length === 0 || files.some((item) => item.type === PDF_TYPE$1 || item.type === "");
192
+ }
193
+ const givenFilesOf = (args) => {
194
+ const files = args?.files;
195
+ return Array.isArray(files) ? files : null;
196
+ };
197
+ /** The file the user picks in the file dialog, as a list: empty when they close it. */
198
+ const pickedFiles = () => (0, _embedpdf_web.pickFile)({ accept: `.pdf,${PDF_TYPE$1}` }).then((file) => file ? [file] : []);
199
+ /**
200
+ * Open each file as a new tab, the first one shown. Its tab is there at once, named like a `src`
201
+ * file's (its name without `.pdf`), while the file is read; one that can't be opened says why
202
+ * in its tab.
203
+ */
204
+ function openFiles(documents, files) {
205
+ documents.openAll(files.map((file) => ({
206
+ name: file.name.replace(/\.pdf$/i, "") || file.name,
207
+ source: async () => ({
208
+ kind: "bytes",
209
+ bytes: new Uint8Array(await file.arrayBuffer())
210
+ })
211
+ })));
212
+ }
213
+ const openFileCommand = {
214
+ id: OPEN_COMMAND_ID,
215
+ labelKey: "commands.open",
216
+ icon: "fileImport",
217
+ shortcut: "Mod+O",
218
+ categories: ["documents.open"],
219
+ visible: (commandContext) => commandContext.tryGet(_embedpdf_react_runtime.DocumentsToken)?.canOpenFiles() ?? false,
220
+ run: async (commandContext) => {
221
+ const documents = commandContext.tryGet(_embedpdf_react_runtime.DocumentsToken);
222
+ if (!documents) return;
223
+ openFiles(documents, givenFilesOf(commandContext.args) ?? await pickedFiles());
224
+ }
225
+ };
226
+ //#endregion
227
+ //#region src/config/outline.ts
228
+ /** The outline panel's id in the layout. */
229
+ const OUTLINE_PANEL = "outline";
230
+ /**
231
+ * A request to rename an item in its row: the selected one, once it isn't the item `after`
232
+ * names (an add selects the item it makes). The panel takes the request and closes it.
233
+ */
234
+ const OUTLINE_RENAME = "outline-rename";
235
+ /** The dialog that edits one item's title, look, target and open state (`props.item`). */
236
+ const OUTLINE_PROPERTIES_DIALOG = "outline-properties";
237
+ /** The menu of a row of the outline: the commands below, for that row. */
238
+ const OUTLINE_ITEM_MENU = "outline-item";
239
+ const outlineOf = (commandContext) => commandContext.tryGet(_embedpdf_react_outline.OutlineToken);
240
+ /** The first selected item, as the outline holds it. */
241
+ const selectedOf$1 = (commandContext) => {
242
+ const outline = outlineOf(commandContext);
243
+ const [ref] = outline?.getSelected() ?? [];
244
+ return ref ? outline?.get(ref) ?? null : null;
245
+ };
246
+ const hasSelection$1 = (commandContext) => selectedOf$1(commandContext) !== null;
247
+ /** What a command that changes the outline needs: the right to, and the feature on. */
248
+ const EDITS = {
249
+ categories: ["outline.editing"],
250
+ allowed: (commandContext) => outlineOf(commandContext)?.canEdit() ?? true,
251
+ notAllowedKey: "commands.notAllowed.doc-outline-modify"
252
+ };
253
+ /**
254
+ * Add an item and rename it in its row, as Acrobat's New Bookmark does: it goes to where the
255
+ * view is, after the selected item, or at the end of the outline when none is selected.
256
+ */
257
+ async function addItem(commandContext, input) {
258
+ const outline = outlineOf(commandContext);
259
+ if (!outline) return;
260
+ const shell = commandContext.tryGet(_embedpdf_react_shell.ShellToken);
261
+ const selected = selectedOf$1(commandContext);
262
+ shell?.open(OUTLINE_PANEL);
263
+ shell?.open(OUTLINE_RENAME, { props: { after: selected?.ref.objectNumber ?? null } });
264
+ try {
265
+ await outline.create(input(selected), { select: true });
266
+ } catch (error) {
267
+ shell?.close(OUTLINE_RENAME);
268
+ throw error;
269
+ }
270
+ }
271
+ const outlineCommands = [
272
+ {
273
+ id: "outline:add",
274
+ labelKey: "commands.outline.add",
275
+ icon: "plus",
276
+ shortcut: "Mod+B",
277
+ ...EDITS,
278
+ run: (commandContext) => addItem(commandContext, (selected) => selected ? {
279
+ parent: selected.parent,
280
+ position: { after: selected.ref }
281
+ } : {})
282
+ },
283
+ {
284
+ id: "outline:add-child",
285
+ labelKey: "commands.outline.addChild",
286
+ ...EDITS,
287
+ enabled: hasSelection$1,
288
+ run: (commandContext) => addItem(commandContext, (selected) => selected ? { parent: selected.ref } : {})
289
+ },
290
+ {
291
+ id: "outline:rename",
292
+ labelKey: "commands.outline.rename",
293
+ ...EDITS,
294
+ enabled: hasSelection$1,
295
+ run: (commandContext) => {
296
+ const selected = selectedOf$1(commandContext);
297
+ if (!selected) return;
298
+ commandContext.tryGet(_embedpdf_react_shell.ShellToken)?.open(OUTLINE_RENAME, { props: { item: selected.ref.objectNumber } });
299
+ }
300
+ },
301
+ {
302
+ id: "outline:set-destination",
303
+ labelKey: "commands.outline.setDestination",
304
+ ...EDITS,
305
+ enabled: (commandContext) => hasSelection$1(commandContext) && outlineOf(commandContext)?.getCurrentViewTarget() != null,
306
+ run: async (commandContext) => {
307
+ const outline = outlineOf(commandContext);
308
+ const selected = selectedOf$1(commandContext);
309
+ const target = outline?.getCurrentViewTarget() ?? null;
310
+ if (outline && selected && target) await outline.update(selected.ref, { target });
311
+ }
312
+ },
313
+ {
314
+ id: "outline:properties",
315
+ labelKey: "commands.outline.properties",
316
+ ...EDITS,
317
+ enabled: hasSelection$1,
318
+ run: (commandContext) => {
319
+ const selected = selectedOf$1(commandContext);
320
+ if (!selected) return;
321
+ commandContext.tryGet(_embedpdf_react_shell.ShellToken)?.open(OUTLINE_PROPERTIES_DIALOG, {
322
+ exclusive: "modal",
323
+ props: { item: selected.ref.objectNumber }
324
+ });
325
+ }
326
+ },
327
+ {
328
+ id: "outline:delete",
329
+ labelKey: "commands.outline.delete",
330
+ icon: "trash",
331
+ ...EDITS,
332
+ enabled: hasSelection$1,
333
+ run: async (commandContext) => {
334
+ const outline = outlineOf(commandContext);
335
+ const selected = outline?.getSelected() ?? [];
336
+ if (outline && selected.length > 0) await outline.delete(selected);
337
+ }
338
+ },
339
+ {
340
+ id: "menu:outline-item",
341
+ labelKey: "commands.outline.more",
342
+ icon: "dots",
343
+ menu: OUTLINE_ITEM_MENU,
344
+ ...EDITS
345
+ },
346
+ {
347
+ id: "outline:expand-all",
348
+ labelKey: "commands.outline.expandAll",
349
+ icon: "chevronsDown",
350
+ categories: ["outline"],
351
+ run: (commandContext) => outlineOf(commandContext)?.expandAll()
352
+ },
353
+ {
354
+ id: "outline:collapse-all",
355
+ labelKey: "commands.outline.collapseAll",
356
+ icon: "chevronsUp",
357
+ categories: ["outline"],
358
+ run: (commandContext) => outlineOf(commandContext)?.collapseAll()
359
+ }
360
+ ];
361
+ //#endregion
362
+ //#region src/config/page-commands.ts
363
+ /** The menu of a page: the commands below, for that page and the others selected with it. */
364
+ const PAGE_MENU = "page";
365
+ const PDF_TYPE = "application/pdf";
366
+ const pageEditOf = (commandContext) => commandContext.tryGet(_embedpdf_react_page_edit.PageEditToken);
367
+ const selectedOf = (commandContext) => pageEditOf(commandContext)?.getSelected() ?? [];
368
+ const hasSelection = (commandContext) => selectedOf(commandContext).length > 0;
369
+ /** The document's pages, in display order. */
370
+ const pagesOf = (commandContext) => commandContext.tryGet(_embedpdf_react_runtime.DocumentsToken)?.listPages(commandContext.documentId ?? void 0) ?? [];
371
+ const argsOf = (commandContext) => commandContext.args ?? {};
372
+ /** What a command that changes the pages needs: the right to, and the feature on. */
373
+ const PAGE_EDITS = {
374
+ categories: ["pages"],
375
+ allowed: (commandContext) => pageEditOf(commandContext)?.canEdit() ?? true,
376
+ notAllowedKey: "commands.notAllowed.doc-pages-assemble"
377
+ };
378
+ /**
379
+ * Where new pages go: where the caller says, else after the selected page that comes last, else
380
+ * at the end.
381
+ */
382
+ function insertPositionOf(commandContext) {
383
+ const given = argsOf(commandContext).position;
384
+ if (given) return given;
385
+ const selected = new Set(selectedOf(commandContext).map((ref) => ref.objectNumber));
386
+ const last = pagesOf(commandContext).filter((page) => selected.has(page.ref.objectNumber)).pop();
387
+ return last ? { after: last.ref } : "end";
388
+ }
389
+ /** The PDFs the caller passed, else the one the user picks: empty when they close the dialog. */
390
+ async function filesToInsert(commandContext) {
391
+ const given = argsOf(commandContext).files;
392
+ if (given) return given.filter(isPdfFile);
393
+ const picked = await (0, _embedpdf_web.pickFile)({ accept: `.pdf,${PDF_TYPE}` });
394
+ return picked ? [picked] : [];
395
+ }
396
+ /** The name of a copy of some of the document's pages: the document's own name, then `-pages`. */
397
+ function extractNameOf(commandContext) {
398
+ const id = commandContext.documentId ?? void 0;
399
+ return `${commandContext.tryGet(_embedpdf_react_runtime.DocumentsToken)?.get(id)?.name?.replace(/\.pdf$/i, "") || "document"}-pages.pdf`;
400
+ }
401
+ const rotate = (id, labelKey, icon, delta) => ({
402
+ id,
403
+ labelKey,
404
+ icon,
405
+ ...PAGE_EDITS,
406
+ enabled: hasSelection,
407
+ run: async (commandContext) => {
408
+ const selected = selectedOf(commandContext);
409
+ if (selected.length > 0) await pageEditOf(commandContext)?.rotateBy(selected, delta);
410
+ }
411
+ });
412
+ const pageCommands = [
413
+ rotate("page:rotate-clockwise", "commands.pages.rotateClockwise", "pageRotateClockwise", 90),
414
+ rotate("page:rotate-counterclockwise", "commands.pages.rotateCounterclockwise", "pageRotateCounterClockwise", -90),
415
+ {
416
+ id: "page:delete",
417
+ labelKey: "commands.pages.delete",
418
+ icon: "trash",
419
+ ...PAGE_EDITS,
420
+ enabled: (commandContext) => {
421
+ const count = selectedOf(commandContext).length;
422
+ return count > 0 && count < pagesOf(commandContext).length;
423
+ },
424
+ run: async (commandContext) => {
425
+ const selected = selectedOf(commandContext);
426
+ if (selected.length > 0) await pageEditOf(commandContext)?.delete(selected);
427
+ }
428
+ },
429
+ {
430
+ id: "page:duplicate",
431
+ labelKey: "commands.pages.duplicate",
432
+ icon: "copy",
433
+ categories: PAGE_EDITS.categories,
434
+ allowed: (commandContext) => {
435
+ const pageEdit = pageEditOf(commandContext);
436
+ return pageEdit ? pageEdit.canEdit() && pageEdit.canExtract() : true;
437
+ },
438
+ enabled: hasSelection,
439
+ run: async (commandContext) => {
440
+ const pageEdit = pageEditOf(commandContext);
441
+ const selected = selectedOf(commandContext);
442
+ if (!pageEdit || selected.length === 0) return;
443
+ const { pages } = await pageEdit.duplicate(selected);
444
+ pageEdit.select(pages);
445
+ }
446
+ },
447
+ {
448
+ id: "page:insert-blank",
449
+ labelKey: "commands.pages.insertBlank",
450
+ icon: "filePlus",
451
+ ...PAGE_EDITS,
452
+ run: async (commandContext) => {
453
+ const pageEdit = pageEditOf(commandContext);
454
+ if (!pageEdit) return;
455
+ const { pages } = await pageEdit.insertBlank({ position: insertPositionOf(commandContext) });
456
+ pageEdit.select(pages);
457
+ }
458
+ },
459
+ {
460
+ id: "page:insert-file",
461
+ labelKey: "commands.pages.insertFile",
462
+ icon: "fileImport",
463
+ ...PAGE_EDITS,
464
+ run: async (commandContext) => {
465
+ const pageEdit = pageEditOf(commandContext);
466
+ if (!pageEdit) return;
467
+ let position = insertPositionOf(commandContext);
468
+ const files = await filesToInsert(commandContext);
469
+ const inserted = [];
470
+ for (const file of files) {
471
+ const { pages } = await pageEdit.insertFromBytes(new Uint8Array(await file.arrayBuffer()), { position });
472
+ inserted.push(...pages);
473
+ const last = pages[pages.length - 1];
474
+ if (last) position = { after: last };
475
+ }
476
+ if (inserted.length > 0) pageEdit.select(inserted);
477
+ }
478
+ },
479
+ {
480
+ id: "page:extract",
481
+ labelKey: "commands.pages.extract",
482
+ icon: "fileExport",
483
+ categories: ["documents.download"],
484
+ allowed: (commandContext) => pageEditOf(commandContext)?.canExtract() ?? true,
485
+ notAllowedKey: "commands.notAllowed.doc-download",
486
+ enabled: hasSelection,
487
+ run: async (commandContext) => {
488
+ const selected = selectedOf(commandContext);
489
+ const pageEdit = pageEditOf(commandContext);
490
+ if (!pageEdit || selected.length === 0) return;
491
+ (0, _embedpdf_web.saveFile)(await pageEdit.extract(selected), extractNameOf(commandContext), PDF_TYPE);
492
+ }
493
+ },
494
+ {
495
+ id: "page:select-all",
496
+ labelKey: "commands.pages.selectAll",
497
+ categories: PAGE_EDITS.categories,
498
+ enabled: (commandContext) => selectedOf(commandContext).length < pagesOf(commandContext).length,
499
+ run: (commandContext) => pageEditOf(commandContext)?.select(pagesOf(commandContext).map((page) => page.ref))
500
+ },
501
+ {
502
+ id: "menu:page",
503
+ labelKey: "commands.pages.more",
504
+ icon: "dots",
505
+ menu: PAGE_MENU,
506
+ ...PAGE_EDITS
507
+ }
508
+ ];
509
+ //#endregion
510
+ //#region src/config/commands.ts
511
+ /**
512
+ * The command vocabulary — the semantic layer. Every command is a pure value:
513
+ * label key, icon, shortcut, derivations, and a `run` (or a declarative
514
+ * surface target). Commands reach plugins through a typed
515
+ * `commandContext.tryGet(Token)`, never by string id and cast.
516
+ *
517
+ * Each command names its most specific feature in `categories` (the tree in
518
+ * `../features.ts`), so `disable` and `readOnly` turn it off, and whether the
519
+ * session may run it in `allowed`, from the owning plugin's `can*` check
520
+ * (docs/conventions/permissions.md), so a user who may not doesn't see it.
521
+ * `enabled` is only for what can't run right now.
522
+ *
523
+ * Wiring:
524
+ * zoom/pan/pointer/spread/scroll/rotate → real Stage / Interaction / PageEdit
525
+ * modes → shell exclusive surfaces ('mode')
526
+ * panels → the layout's `panel:<id>` (panels.ts)
527
+ * menus / modals → declarative shell targets
528
+ * annotate + shape tools → real interaction tools
529
+ * form tools → real form plugin palette (draw-to-place)
530
+ * insert tools → real stamp and signature panels +
531
+ * image/attachment click-then-pick
532
+ * history undo/redo → real History
533
+ */
534
+ /** The dialog the Go to Page command opens without a page to go to (ui/go-to-page.tsx). */
535
+ const GO_TO_PAGE_DIALOG = "go-to-page";
536
+ /** The keyboard shortcuts sheet, which `?` opens (ui/shortcuts-sheet.tsx). */
537
+ const SHORTCUTS_DIALOG = "shortcuts";
538
+ /** The confirmation before marked areas are removed for good (ui/redact-confirm.tsx). */
539
+ const REDACT_CONFIRM_DIALOG = "redact-confirm";
540
+ /** The Print dialog: which pages, and whether annotations print (ui/print-dialog.tsx). */
541
+ const PRINT_DIALOG = "print";
542
+ /** The form designer's sidebar (ui/form-design-panel.tsx), which `form:design` opens. */
543
+ const FORM_DESIGN_PANEL = "form-design";
544
+ /** Form design's resting tool, the form plugin's: widgets select, move and resize there. */
545
+ const FORM_DESIGN_TOOL = "form-edit";
546
+ /** The form plugin's field tools, each placing a field (the Form bar's `tool:*` buttons). */
547
+ const FORM_FIELD_TOOLS = [
548
+ "form-text",
549
+ "form-checkbox",
550
+ "form-radio",
551
+ "form-combobox",
552
+ "form-listbox",
553
+ "form-button",
554
+ "form-signature"
555
+ ];
556
+ /**
557
+ * Whether a tool designs a form: design's resting tool, or a field tool. Neither fills, so the
558
+ * form lends its widgets to be selected, moved and resized.
559
+ */
560
+ const isFormDesignTool = (tool) => tool === "form-edit" || tool != null && FORM_FIELD_TOOLS.includes(tool);
561
+ /** Whether a form is being designed: the active tool designs it. */
562
+ const isDesigningForm = (commandContext) => isFormDesignTool(commandContext.tryGet(_embedpdf_react_interaction.InteractionToken)?.getActiveToolId());
563
+ /** Where selection-made stamps go: the user's own library, persisted. */
564
+ const CUSTOM_LIBRARY_ID = "embedpdf-custom";
565
+ const stage = (commandContext) => commandContext.tryGet(_embedpdf_react_stage.StageToken);
566
+ const interaction = (commandContext) => commandContext.tryGet(_embedpdf_react_interaction.InteractionToken);
567
+ const anno = (commandContext) => commandContext.tryGet(_embedpdf_react_annotation.AnnotationToken);
568
+ const textSelection = (commandContext) => commandContext.tryGet(_embedpdf_react_selection.SelectionToken);
569
+ /** Drawing an annotation of any kind: `annotation.canCreate()`. */
570
+ const CREATES_ANNOTATIONS = {
571
+ allowed: (commandContext) => anno(commandContext)?.canCreate() ?? true,
572
+ notAllowedKey: "commands.notAllowed.annotations-create"
573
+ };
574
+ /** Placing and changing form fields: `form.canDesign()`. */
575
+ const DESIGNS_FORMS = {
576
+ allowed: (commandContext) => commandContext.tryGet(_embedpdf_react_form.FormToken)?.canDesign() ?? true,
577
+ notAllowedKey: "commands.notAllowed.doc-forms-modify"
578
+ };
579
+ /** Placing a stamp or a signature mark: `stamp.canPlace()`. */
580
+ const PLACES_STAMPS = {
581
+ allowed: (commandContext) => commandContext.tryGet(_embedpdf_react_stamp.StampToken)?.canPlace(commandContext.documentId ?? void 0) ?? true,
582
+ notAllowedKey: "commands.notAllowed.annotations-create"
583
+ };
584
+ const sameTextRange = (left, right) => left === right || !!left && !!right && left.start.page.objectNumber === right.start.page.objectNumber && left.start.index === right.start.index && left.end.page.objectNumber === right.end.page.objectNumber && left.end.index === right.end.index;
585
+ /**
586
+ * What a command needs to open and close the layout's panel `id`: it runs the panel's own
587
+ * `panel:<id>` command (config/panels.ts), so it opens only what that one may, shows only while
588
+ * the layout has the panel and `visible` says so, and is active while the panel is open.
589
+ */
590
+ const togglesPanel = (id, visible) => ({
591
+ run: (commandContext) => commandContext.tryGet(_embedpdf_react_commands.CommandsToken)?.execute((0, _embedpdf_core_ui.panelCommandOf)(id), { documentId: commandContext.documentId ?? void 0 }),
592
+ active: (commandContext) => commandContext.tryGet(_embedpdf_react_shell.ShellToken)?.isOpen(id) ?? false,
593
+ visible: (commandContext) => (commandContext.tryGet(_embedpdf_react_commands.CommandsToken)?.hasCommand((0, _embedpdf_core_ui.panelCommandOf)(id)) ?? false) && (visible?.(commandContext) ?? true)
594
+ });
595
+ /** A measuring tool can run on the current page: it has a scale (`measurement.canMeasure`). */
596
+ const canMeasureNow = (commandContext) => {
597
+ const page = stage(commandContext)?.getCurrentPage();
598
+ return page != null && (commandContext.tryGet(_embedpdf_react_measurement.MeasurementToken)?.canMeasure(page) ?? false);
599
+ };
600
+ const hasAnnotationSelection = (commandContext) => (anno(commandContext)?.selection.list().length ?? 0) > 0;
601
+ /** Whether people may change every selected annotation by hand (no turned-off feature froze it). */
602
+ const selectionEditable = (commandContext) => {
603
+ const annotation = anno(commandContext);
604
+ return (annotation?.selection.list() ?? []).every(({ ref }) => annotation.isEditable(ref));
605
+ };
606
+ /** Strip items gate per subtype (comment hidden on links/widgets) through
607
+ * one derivation over the selected DTOs, not per-command lookups. */
608
+ const selectionSubtypes = (commandContext) => new Set((anno(commandContext)?.selection.list() ?? []).map((annotation) => annotation.subtype));
609
+ /**
610
+ * The selection's `link` value: a target, `null` (linkable but none set), or
611
+ * `undefined` when the selection cannot carry a link at all (widgets, mixed
612
+ * link states) — the schema decides, never a subtype blocklist.
613
+ */
614
+ /** The selection's link target, as the annotation holds it (destinations in the file's coordinates). */
615
+ const selectionLink = (commandContext) => {
616
+ const props = anno(commandContext)?.selection.getProperties();
617
+ if (!props || !props.properties.some((property) => property.key === "link") || props.mixed.includes("link")) return void 0;
618
+ return props.values.link ?? null;
619
+ };
620
+ /**
621
+ * toolId → the same icon + accent definition its toolbar button uses, recorded
622
+ * as a side effect of the `tool()` command definitions below — one source of
623
+ * truth, so the tool cursor (ui/tool-cursor.tsx) and the button can never
624
+ * drift apart.
625
+ */
626
+ const TOOL_ICONS = {};
627
+ TOOL_ICONS["stamp"] = { icon: "rubberStamp" };
628
+ const toolAccent = (commandContext, toolId, accent) => {
629
+ if (!accent) return null;
630
+ const anno = commandContext.tryGet(_embedpdf_react_annotation.AnnotationToken);
631
+ if (!anno) return null;
632
+ const defaults = anno.tools.getDefaults(toolId);
633
+ const colorOf = (key) => defaults[key] ?? void 0;
634
+ return {
635
+ primary: colorOf(accent.primary),
636
+ secondary: accent.secondary ? colorOf(accent.secondary) : void 0
637
+ };
638
+ };
639
+ /** toolId → the feature its command belongs to, for the tools of yours that extend it. */
640
+ const TOOL_FEATURES = {};
641
+ /** A tool command without its label: activates a real interaction tool; active = it's the tool.
642
+ * The icon previews the tool's current defaults — keyed by the same toolId
643
+ * as run/active, so the accent can't drift to another tool's colors. */
644
+ const toolCommand = (id, toolId, icon, { feature, check, accent }) => {
645
+ if (icon) TOOL_ICONS[toolId] = {
646
+ icon,
647
+ ...accent ? { accent } : {}
648
+ };
649
+ TOOL_FEATURES[toolId] = feature;
650
+ return {
651
+ id,
652
+ ...icon ? { icon } : {},
653
+ categories: [feature],
654
+ ...check,
655
+ run: (commandContext) => interaction(commandContext)?.activateTool(toolId),
656
+ active: (commandContext) => interaction(commandContext)?.getActiveToolId() === toolId,
657
+ enabled: (commandContext) => interaction(commandContext) != null,
658
+ iconAccent: (commandContext) => toolAccent(commandContext, toolId, accent)
659
+ };
660
+ };
661
+ const tool = (id, toolId, labelKey, icon, options) => ({
662
+ ...toolCommand(id, toolId, icon, options),
663
+ labelKey
664
+ });
665
+ /**
666
+ * Selected text made into a highlight, an underline or a strikeout, with the colors of the
667
+ * tool that makes the same: shown only while there's a selection.
668
+ */
669
+ const markupSelection = (id, toolId, labelKey, icon, feature) => ({
670
+ id,
671
+ labelKey,
672
+ icon,
673
+ categories: [feature],
674
+ ...CREATES_ANNOTATIONS,
675
+ visible: (commandContext) => textSelection(commandContext)?.hasSelection() ?? false,
676
+ run: (commandContext) => anno(commandContext)?.createFromSelection(toolId),
677
+ iconAccent: (commandContext) => toolAccent(commandContext, toolId, { primary: "color" })
678
+ });
679
+ /** The page number `page:go-to` was given (`args: { page }`, counted from 1), or `null`. */
680
+ const pageArgOf = (args) => {
681
+ const page = args?.page;
682
+ return typeof page === "number" && Number.isFinite(page) ? Math.round(page) : null;
683
+ };
684
+ /** A fixed zoom level (fraction), e.g. 1 = 100%. */
685
+ const zoomLevel = (id, level, label) => ({
686
+ id,
687
+ labelKey: label,
688
+ run: (commandContext) => stage(commandContext)?.zoomTo({ level }),
689
+ enabled: (commandContext) => stage(commandContext) != null
690
+ });
691
+ const spread = (id, mode, labelKey, icon) => ({
692
+ id,
693
+ labelKey,
694
+ icon,
695
+ run: (commandContext) => stage(commandContext)?.updateSettings({ spread: mode }),
696
+ active: (commandContext) => stage(commandContext)?.getSettings().spread === mode,
697
+ enabled: (commandContext) => stage(commandContext) != null
698
+ });
699
+ const defaultCommands = [
700
+ {
701
+ id: "zoom:in",
702
+ labelKey: "commands.zoom.in",
703
+ icon: "zoomIn",
704
+ shortcut: ["Mod+=", "Mod+NumpadAdd"],
705
+ run: (commandContext) => stage(commandContext)?.zoomIn(),
706
+ enabled: (commandContext) => stage(commandContext) != null
707
+ },
708
+ {
709
+ id: "zoom:out",
710
+ labelKey: "commands.zoom.out",
711
+ icon: "zoomOut",
712
+ shortcut: ["Mod+-", "Mod+NumpadSubtract"],
713
+ run: (commandContext) => stage(commandContext)?.zoomOut(),
714
+ enabled: (commandContext) => stage(commandContext) != null
715
+ },
716
+ {
717
+ id: "zoom:fit-page",
718
+ labelKey: "commands.zoom.fitPage",
719
+ icon: "fitToPage",
720
+ shortcut: "Mod+0",
721
+ run: (commandContext) => stage(commandContext)?.fitPage(),
722
+ active: (commandContext) => stage(commandContext)?.getZoomMode() === _embedpdf_react_stage.ZoomMode.FitPage,
723
+ enabled: (commandContext) => stage(commandContext) != null
724
+ },
725
+ {
726
+ id: "zoom:fit-width",
727
+ labelKey: "commands.zoom.fitWidth",
728
+ icon: "fitToWidth",
729
+ shortcut: "Mod+1",
730
+ run: (commandContext) => stage(commandContext)?.fitWidth(),
731
+ active: (commandContext) => stage(commandContext)?.getZoomMode() === _embedpdf_react_stage.ZoomMode.FitWidth,
732
+ enabled: (commandContext) => stage(commandContext) != null
733
+ },
734
+ {
735
+ id: "zoom:automatic",
736
+ labelKey: "commands.zoom.automatic",
737
+ run: (commandContext) => stage(commandContext)?.fitAutomatic(),
738
+ active: (commandContext) => stage(commandContext)?.getZoomMode() === _embedpdf_react_stage.ZoomMode.Automatic,
739
+ enabled: (commandContext) => stage(commandContext) != null
740
+ },
741
+ zoomLevel("zoom:50", .5, "commands.zoom.p50"),
742
+ zoomLevel("zoom:100", 1, "commands.zoom.p100"),
743
+ zoomLevel("zoom:150", 1.5, "commands.zoom.p150"),
744
+ zoomLevel("zoom:200", 2, "commands.zoom.p200"),
745
+ zoomLevel("zoom:400", 4, "commands.zoom.p400"),
746
+ {
747
+ id: "menu:zoom",
748
+ labelKey: "commands.zoom.menu",
749
+ icon: "zoomIn",
750
+ menu: "zoom"
751
+ },
752
+ {
753
+ id: "page:next",
754
+ labelKey: "commands.page.next",
755
+ icon: "chevronRight",
756
+ shortcut: "ArrowRight",
757
+ run: (commandContext) => stage(commandContext)?.nextPage(),
758
+ enabled: (commandContext) => stage(commandContext)?.canGoNext() ?? false
759
+ },
760
+ {
761
+ id: "page:previous",
762
+ labelKey: "commands.page.previous",
763
+ icon: "chevronLeft",
764
+ shortcut: "ArrowLeft",
765
+ run: (commandContext) => stage(commandContext)?.previousPage(),
766
+ enabled: (commandContext) => stage(commandContext)?.canGoPrevious() ?? false
767
+ },
768
+ {
769
+ id: "page:first",
770
+ labelKey: "commands.page.first",
771
+ shortcut: "Home",
772
+ run: (commandContext) => stage(commandContext)?.goToFirstPage(),
773
+ enabled: (commandContext) => stage(commandContext)?.canGoPrevious() ?? false
774
+ },
775
+ {
776
+ id: "page:last",
777
+ labelKey: "commands.page.last",
778
+ shortcut: "End",
779
+ run: (commandContext) => stage(commandContext)?.goToLastPage(),
780
+ enabled: (commandContext) => stage(commandContext)?.canGoNext() ?? false
781
+ },
782
+ {
783
+ id: "page:go-to",
784
+ labelKey: "commands.page.goTo",
785
+ run: (commandContext) => {
786
+ const view = stage(commandContext);
787
+ if (!view) return;
788
+ const page = pageArgOf(commandContext.args);
789
+ if (page === null) {
790
+ commandContext.tryGet(_embedpdf_react_shell.ShellToken)?.open(GO_TO_PAGE_DIALOG, { exclusive: "modal" });
791
+ return;
792
+ }
793
+ view.goToPage(Math.min(Math.max(page, 1), view.getPageCount()) - 1);
794
+ },
795
+ enabled: (commandContext) => (stage(commandContext)?.getPageCount() ?? 0) > 0
796
+ },
797
+ {
798
+ id: "tool:pan",
799
+ labelKey: "commands.pan",
800
+ icon: "hand",
801
+ run: (commandContext) => interaction(commandContext)?.activateTool("pan"),
802
+ active: (commandContext) => interaction(commandContext)?.getActiveToolId() === "pan",
803
+ enabled: (commandContext) => interaction(commandContext) != null
804
+ },
805
+ {
806
+ id: "tool:pointer",
807
+ labelKey: "commands.pointer",
808
+ icon: "pointer",
809
+ run: (commandContext) => interaction(commandContext)?.activateTool("pointer"),
810
+ active: (commandContext) => interaction(commandContext)?.getActiveToolId() === "pointer",
811
+ enabled: (commandContext) => interaction(commandContext) != null
812
+ },
813
+ {
814
+ id: "menu:document",
815
+ labelKey: "commands.menu",
816
+ icon: "menu",
817
+ menu: "document"
818
+ },
819
+ {
820
+ id: "menu:view",
821
+ labelKey: "commands.viewControls",
822
+ icon: "viewSettings",
823
+ menu: "view"
824
+ },
825
+ ...outlineCommands,
826
+ ...attachmentCommands,
827
+ ...pageCommands,
828
+ openFileCommand,
829
+ {
830
+ id: "document:download",
831
+ labelKey: "commands.download",
832
+ icon: "download",
833
+ shortcut: "Mod+S",
834
+ categories: ["documents.download"],
835
+ allowed: (commandContext) => commandContext.tryGet(_embedpdf_react_runtime.DocumentsToken)?.canDownload() ?? true,
836
+ notAllowedKey: "commands.notAllowed.doc-download",
837
+ run: (commandContext) => {
838
+ const id = commandContext.documentId ?? void 0;
839
+ const documents = commandContext.tryGet(_embedpdf_react_runtime.DocumentsToken);
840
+ if (!documents) return;
841
+ documents.download(id).then((bytes) => (0, _embedpdf_web.saveFile)(bytes, "document.pdf", "application/pdf")).catch((error) => console.warn("[snippet-react] download failed", error));
842
+ },
843
+ enabled: (commandContext) => commandContext.documentId != null
844
+ },
845
+ {
846
+ id: "document:print",
847
+ labelKey: "commands.print",
848
+ icon: "print",
849
+ shortcut: "Mod+P",
850
+ categories: ["documents.print"],
851
+ allowed: (commandContext) => commandContext.tryGet(_embedpdf_react_runtime.DocumentsToken)?.canPrint() ?? true,
852
+ notAllowedKey: "commands.notAllowed.doc-print",
853
+ modal: PRINT_DIALOG,
854
+ enabled: (commandContext) => commandContext.documentId != null
855
+ },
856
+ {
857
+ id: "view:fullscreen",
858
+ labelKey: "commands.fullscreen",
859
+ icon: "externalLink",
860
+ run: () => {
861
+ if (document.fullscreenElement) document.exitFullscreen();
862
+ else document.documentElement.requestFullscreen().catch(() => {});
863
+ },
864
+ active: () => Boolean(document.fullscreenElement)
865
+ },
866
+ spread("view:single-page", "none", "commands.spread.none", "singlePage"),
867
+ spread("view:two-pages", "odd", "commands.spread.odd", "doublePage"),
868
+ spread("view:cover-page", "even", "commands.spread.even", "book2"),
869
+ {
870
+ id: "view:scroll-vertical",
871
+ labelKey: "commands.scroll.vertical",
872
+ icon: "vertical",
873
+ run: (commandContext) => stage(commandContext)?.updateSettings({ layout: "vertical" }),
874
+ active: (commandContext) => stage(commandContext)?.getSettings().layout === "vertical",
875
+ enabled: (commandContext) => stage(commandContext) != null
876
+ },
877
+ {
878
+ id: "view:scroll-horizontal",
879
+ labelKey: "commands.scroll.horizontal",
880
+ icon: "horizontal",
881
+ run: (commandContext) => stage(commandContext)?.updateSettings({ layout: "horizontal" }),
882
+ active: (commandContext) => stage(commandContext)?.getSettings().layout === "horizontal",
883
+ enabled: (commandContext) => stage(commandContext) != null
884
+ },
885
+ {
886
+ id: "view:rotate-clockwise",
887
+ labelKey: "commands.rotate.clockwise",
888
+ icon: "rotateClockwise",
889
+ run: (commandContext) => stage(commandContext)?.rotateViewBy(90),
890
+ enabled: (commandContext) => stage(commandContext) != null
891
+ },
892
+ {
893
+ id: "view:rotate-counterclockwise",
894
+ labelKey: "commands.rotate.counterclockwise",
895
+ icon: "rotateCounterClockwise",
896
+ run: (commandContext) => stage(commandContext)?.rotateViewBy(-90),
897
+ enabled: (commandContext) => stage(commandContext) != null
898
+ },
899
+ {
900
+ id: "mode:view",
901
+ labelKey: "commands.mode.view",
902
+ run: (commandContext) => {
903
+ const shell = commandContext.tryGet(_embedpdf_react_shell.ShellToken);
904
+ const open = shell ? openModeSurfaceOf(shell) : null;
905
+ if (open) shell?.close(open);
906
+ interaction(commandContext)?.activateTool("pointer");
907
+ },
908
+ active: (commandContext) => {
909
+ const shell = commandContext.tryGet(_embedpdf_react_shell.ShellToken);
910
+ return shell ? openModeSurfaceOf(shell) === null : true;
911
+ }
912
+ },
913
+ modeCommand("mode:annotate", "commands.mode.annotate", { feature: "annotations" }),
914
+ modeCommand("mode:shapes", "commands.mode.shapes", { feature: "shapes" }),
915
+ modeCommand("mode:insert", "commands.mode.insert"),
916
+ modeCommand("mode:form", "commands.mode.form", { feature: "forms.building" }),
917
+ modeCommand("mode:redact", "commands.mode.redact", { feature: "redaction" }),
918
+ modeCommand("mode:measure", "commands.mode.measure", { feature: "measurement" }),
919
+ tool("tool:highlight", "highlight", "commands.annotate.highlight", "highlight", {
920
+ feature: "annotations.highlight",
921
+ check: CREATES_ANNOTATIONS,
922
+ accent: { primary: "color" }
923
+ }),
924
+ tool("tool:strikeout", "strikeout", "commands.annotate.strikeout", "strikethrough", {
925
+ feature: "annotations.markup",
926
+ check: CREATES_ANNOTATIONS,
927
+ accent: { primary: "color" }
928
+ }),
929
+ tool("tool:underline", "underline", "commands.annotate.underline", "underline", {
930
+ feature: "annotations.markup",
931
+ check: CREATES_ANNOTATIONS,
932
+ accent: { primary: "color" }
933
+ }),
934
+ tool("tool:squiggly", "squiggly", "commands.annotate.squiggly", "squiggly", {
935
+ feature: "annotations.markup",
936
+ check: CREATES_ANNOTATIONS,
937
+ accent: { primary: "color" }
938
+ }),
939
+ tool("tool:ink", "ink", "commands.annotate.ink", "pencilMarker", {
940
+ feature: "annotations.drawing",
941
+ check: CREATES_ANNOTATIONS,
942
+ accent: { primary: "color" }
943
+ }),
944
+ tool("tool:ink-highlight", "ink-highlight", "commands.annotate.inkHighlight", "inkHighlighter", {
945
+ feature: "annotations.drawing",
946
+ check: CREATES_ANNOTATIONS,
947
+ accent: { primary: "color" }
948
+ }),
949
+ tool("tool:free-text", "free-text", "commands.annotate.text", "freeText", {
950
+ feature: "annotations.text",
951
+ check: CREATES_ANNOTATIONS,
952
+ accent: { primary: "fontColor" }
953
+ }),
954
+ tool("tool:insert-text", "insert-text", "commands.annotate.insertText", "insertText", {
955
+ feature: "annotations.text",
956
+ check: CREATES_ANNOTATIONS,
957
+ accent: { primary: "color" }
958
+ }),
959
+ tool("tool:replace-text", "replace-text", "commands.annotate.replaceText", "replaceText", {
960
+ feature: "annotations.text",
961
+ check: CREATES_ANNOTATIONS,
962
+ accent: { primary: "color" }
963
+ }),
964
+ tool("tool:callout", "free-text-callout", "commands.annotate.callout", "callout", {
965
+ feature: "annotations.text",
966
+ check: CREATES_ANNOTATIONS,
967
+ accent: {
968
+ primary: "color",
969
+ secondary: "interiorColor"
970
+ }
971
+ }),
972
+ tool("tool:note", "note", "commands.annotate.note", "message", {
973
+ feature: "annotations.notes",
974
+ check: CREATES_ANNOTATIONS
975
+ }),
976
+ tool("tool:link", "link", "commands.annotate.link", "link", {
977
+ feature: "annotations.links",
978
+ check: CREATES_ANNOTATIONS
979
+ }),
980
+ tool("tool:square", "square", "commands.shapes.rectangle", "square", {
981
+ feature: "shapes",
982
+ check: CREATES_ANNOTATIONS,
983
+ accent: {
984
+ primary: "color",
985
+ secondary: "interiorColor"
986
+ }
987
+ }),
988
+ tool("tool:circle", "circle", "commands.shapes.circle", "circle", {
989
+ feature: "shapes",
990
+ check: CREATES_ANNOTATIONS,
991
+ accent: {
992
+ primary: "color",
993
+ secondary: "interiorColor"
994
+ }
995
+ }),
996
+ tool("tool:line", "line", "commands.shapes.line", "line", {
997
+ feature: "shapes",
998
+ check: CREATES_ANNOTATIONS,
999
+ accent: { primary: "color" }
1000
+ }),
1001
+ tool("tool:arrow", "arrow", "commands.shapes.arrow", "lineArrow", {
1002
+ feature: "shapes",
1003
+ check: CREATES_ANNOTATIONS,
1004
+ accent: { primary: "color" }
1005
+ }),
1006
+ tool("tool:polygon", "polygon", "commands.shapes.polygon", "polygon", {
1007
+ feature: "shapes",
1008
+ check: CREATES_ANNOTATIONS,
1009
+ accent: {
1010
+ primary: "color",
1011
+ secondary: "interiorColor"
1012
+ }
1013
+ }),
1014
+ tool("tool:polyline", "polyline", "commands.shapes.polyline", "zigzag", {
1015
+ feature: "shapes",
1016
+ check: CREATES_ANNOTATIONS,
1017
+ accent: { primary: "color" }
1018
+ }),
1019
+ {
1020
+ id: "tool:stamp",
1021
+ labelKey: "commands.insert.stamp",
1022
+ icon: "rubberStamp",
1023
+ categories: ["stamps"],
1024
+ ...PLACES_STAMPS,
1025
+ ...togglesPanel("stamps", (commandContext) => commandContext.tryGet(_embedpdf_react_stamp.StampToken) != null)
1026
+ },
1027
+ tool("tool:attachment", "attachment", "commands.insert.attachment", "paperclip", {
1028
+ feature: "attachments.adding",
1029
+ check: CREATES_ANNOTATIONS
1030
+ }),
1031
+ {
1032
+ id: "tool:signature",
1033
+ labelKey: "commands.insert.signature",
1034
+ icon: "signature",
1035
+ categories: ["signatures.signing"],
1036
+ ...PLACES_STAMPS,
1037
+ ...togglesPanel("signatures", (commandContext) => commandContext.tryGet(_embedpdf_react_stamp.StampToken) != null && commandContext.tryGet(_embedpdf_react_signature.SignatureToken) != null)
1038
+ },
1039
+ tool("tool:image", "image", "commands.insert.image", "photo", {
1040
+ feature: "stamps",
1041
+ check: CREATES_ANNOTATIONS
1042
+ }),
1043
+ {
1044
+ id: "form:design",
1045
+ labelKey: "commands.form.design",
1046
+ icon: "formDesign",
1047
+ categories: ["forms.building"],
1048
+ ...DESIGNS_FORMS,
1049
+ run: (commandContext) => {
1050
+ const tools = interaction(commandContext);
1051
+ const shell = commandContext.tryGet(_embedpdf_react_shell.ShellToken);
1052
+ if (!tools) return;
1053
+ if (isDesigningForm(commandContext)) {
1054
+ tools.activateTool("pointer");
1055
+ shell?.close(FORM_DESIGN_PANEL);
1056
+ return;
1057
+ }
1058
+ if (shell && !shell.isOpen("mode:form")) shell.open("mode:form", { exclusive: "mode" });
1059
+ tools.activateTool(FORM_DESIGN_TOOL);
1060
+ shell?.open(FORM_DESIGN_PANEL);
1061
+ },
1062
+ active: isDesigningForm,
1063
+ enabled: (commandContext) => interaction(commandContext) != null
1064
+ },
1065
+ tool("tool:text-field", "form-text", "commands.form.textfield", "formTextfield", {
1066
+ feature: "forms.building",
1067
+ check: DESIGNS_FORMS
1068
+ }),
1069
+ tool("tool:checkbox", "form-checkbox", "commands.form.checkbox", "formCheckbox", {
1070
+ feature: "forms.building",
1071
+ check: DESIGNS_FORMS
1072
+ }),
1073
+ tool("tool:radio", "form-radio", "commands.form.radio", "formRadio", {
1074
+ feature: "forms.building",
1075
+ check: DESIGNS_FORMS
1076
+ }),
1077
+ tool("tool:combo-box", "form-combobox", "commands.form.select", "formSelect", {
1078
+ feature: "forms.building",
1079
+ check: DESIGNS_FORMS
1080
+ }),
1081
+ tool("tool:list-box", "form-listbox", "commands.form.listbox", "formListbox", {
1082
+ feature: "forms.building",
1083
+ check: DESIGNS_FORMS
1084
+ }),
1085
+ tool("tool:button", "form-button", "commands.form.button", "formButton", {
1086
+ feature: "forms.building",
1087
+ check: DESIGNS_FORMS
1088
+ }),
1089
+ tool("tool:signature-field", "form-signature", "commands.form.signature", "signature", {
1090
+ feature: "forms.building",
1091
+ check: DESIGNS_FORMS
1092
+ }),
1093
+ tool("tool:redact", "redact", "commands.redact.mark", "redactArea", {
1094
+ feature: "redaction",
1095
+ check: {
1096
+ allowed: (commandContext) => commandContext.tryGet(_embedpdf_react_redaction.RedactionToken)?.canMark() ?? true,
1097
+ notAllowedKey: "commands.notAllowed.annotations-create"
1098
+ }
1099
+ }),
1100
+ {
1101
+ id: "redaction:apply",
1102
+ labelKey: "commands.redact.applyAll",
1103
+ icon: "redact",
1104
+ categories: ["redaction"],
1105
+ allowed: (commandContext) => commandContext.tryGet(_embedpdf_react_redaction.RedactionToken)?.canApply() ?? true,
1106
+ modal: REDACT_CONFIRM_DIALOG,
1107
+ enabled: (commandContext) => {
1108
+ const redaction = commandContext.tryGet(_embedpdf_react_redaction.RedactionToken);
1109
+ return !!redaction && redaction.getPendingCount() > 0 && !redaction.isApplying();
1110
+ }
1111
+ },
1112
+ {
1113
+ ...tool("tool:distance", "distance", "measurement.distance", "distance", {
1114
+ feature: "measurement",
1115
+ check: CREATES_ANNOTATIONS,
1116
+ accent: { primary: "color" }
1117
+ }),
1118
+ enabled: canMeasureNow
1119
+ },
1120
+ {
1121
+ ...tool("tool:perimeter", "perimeter", "measurement.perimeter", "perimeter", {
1122
+ feature: "measurement",
1123
+ check: CREATES_ANNOTATIONS,
1124
+ accent: { primary: "color" }
1125
+ }),
1126
+ enabled: canMeasureNow
1127
+ },
1128
+ {
1129
+ ...tool("tool:area", "area", "measurement.area", "area", {
1130
+ feature: "measurement",
1131
+ check: CREATES_ANNOTATIONS,
1132
+ accent: { primary: "color" }
1133
+ }),
1134
+ enabled: canMeasureNow
1135
+ },
1136
+ {
1137
+ id: "measurement:calibrate",
1138
+ labelKey: "measurement.calibrate",
1139
+ icon: "calibrate",
1140
+ categories: ["measurement"],
1141
+ allowed: (commandContext) => commandContext.tryGet(_embedpdf_react_measurement.MeasurementToken)?.canCalibrate() ?? true,
1142
+ notAllowedKey: "commands.notAllowed.doc-annotate-modify",
1143
+ enabled: (commandContext) => commandContext.tryGet(_embedpdf_react_measurement.MeasurementToken) != null,
1144
+ active: (commandContext) => interaction(commandContext)?.getActiveToolId() === "calibrate",
1145
+ run: (commandContext) => commandContext.tryGet(_embedpdf_react_measurement.MeasurementToken)?.startCalibration()
1146
+ },
1147
+ {
1148
+ id: "annotation:cancel-creation",
1149
+ labelKey: "commands.annotate.cancelCreation",
1150
+ shortcut: "Escape",
1151
+ enabled: (commandContext) => anno(commandContext)?.draft.get() != null,
1152
+ run: (commandContext) => anno(commandContext)?.draft.cancel()
1153
+ },
1154
+ {
1155
+ id: "annotation:delete",
1156
+ labelKey: "commands.annotate.delete",
1157
+ icon: "trash",
1158
+ shortcut: ["Delete", "Backspace"],
1159
+ categories: ["annotations"],
1160
+ run: (commandContext) => void anno(commandContext)?.selection.delete(),
1161
+ visible: hasAnnotationSelection,
1162
+ enabled: (commandContext) => {
1163
+ const annotation = anno(commandContext);
1164
+ const selected = annotation?.selection.list() ?? [];
1165
+ return selected.length > 0 && selected.every(({ ref }) => annotation.canDelete(ref) && annotation.isEditable(ref));
1166
+ }
1167
+ },
1168
+ {
1169
+ id: "annotation:comment",
1170
+ labelKey: "commands.comment",
1171
+ icon: "comment",
1172
+ categories: ["comments"],
1173
+ ...togglesPanel("comments", (commandContext) => hasAnnotationSelection(commandContext) && !selectionSubtypes(commandContext).has("widget"))
1174
+ },
1175
+ {
1176
+ id: "annotation:style",
1177
+ labelKey: "commands.style",
1178
+ icon: "palette",
1179
+ categories: ["annotations"],
1180
+ ...togglesPanel("style", (commandContext) => (anno(commandContext)?.selection.getProperties().properties.length ?? 0) > 0)
1181
+ },
1182
+ {
1183
+ id: "annotation:stamp-from-selection",
1184
+ labelKey: "commands.annotate.stampFromSelection",
1185
+ icon: "rubberStampPlus",
1186
+ categories: ["stamps"],
1187
+ allowed: (commandContext) => commandContext.tryGet(_embedpdf_react_stamp.StampToken)?.canCreateFromAnnotations(commandContext.documentId ?? void 0) ?? true,
1188
+ notAllowedKey: "commands.notAllowed.doc-download",
1189
+ run: (commandContext) => {
1190
+ const annotation = anno(commandContext);
1191
+ const stamp = commandContext.tryGet(_embedpdf_react_stamp.StampToken);
1192
+ const documentId = commandContext.documentId;
1193
+ if (!annotation || !stamp || documentId == null) return;
1194
+ const dtos = annotation.selection.list();
1195
+ const page = dtos[0]?.ref.page;
1196
+ if (page === void 0) return;
1197
+ const i18n = commandContext.tryGet(_embedpdf_react_i18n.I18nToken);
1198
+ const label = i18n?.t("demo.stampsCustomLabel") ?? "Custom stamp";
1199
+ const libraryName = i18n?.t("demo.stampsCustomLibrary") ?? "My stamps";
1200
+ const libraryId = CUSTOM_LIBRARY_ID;
1201
+ (stamp.getLibrary(libraryId) ? Promise.resolve(libraryId) : stamp.createLibrary(libraryName, {
1202
+ id: libraryId,
1203
+ categories: ["custom"]
1204
+ }).then(({ library }) => library.id)).then((id) => stamp.createAssetFromAnnotations(page, dtos.map((annotation) => annotation.ref), {
1205
+ libraryId: id,
1206
+ label: `${label} ${stamp.listAssets({ libraryId: id }).length + 1}`
1207
+ }, { documentId })).then(async () => {
1208
+ const shell = commandContext.tryGet(_embedpdf_react_shell.ShellToken);
1209
+ if (!shell) return;
1210
+ if (!shell.isOpen("stamps")) await commandContext.tryGet(_embedpdf_react_commands.CommandsToken)?.execute((0, _embedpdf_core_ui.panelCommandOf)("stamps"), { documentId });
1211
+ shell.updateSurfaceProps("stamps", { libraryId });
1212
+ }).catch((error) => console.warn("[embedpdf] stamp from selection failed", error));
1213
+ },
1214
+ visible: (commandContext) => commandContext.tryGet(_embedpdf_react_stamp.StampToken) != null && hasAnnotationSelection(commandContext) && !selectionSubtypes(commandContext).has("widget") && !selectionSubtypes(commandContext).has("redact") && new Set((anno(commandContext)?.selection.list() ?? []).map((annotation) => annotation.ref.page.objectNumber)).size === 1
1215
+ },
1216
+ {
1217
+ id: "annotation:group",
1218
+ labelKey: "commands.annotate.group",
1219
+ icon: "group",
1220
+ categories: ["annotations"],
1221
+ run: (commandContext) => void anno(commandContext)?.selection.group(),
1222
+ visible: (commandContext) => (anno(commandContext)?.selection.canGroup() ?? false) && selectionEditable(commandContext)
1223
+ },
1224
+ {
1225
+ id: "annotation:ungroup",
1226
+ labelKey: "commands.annotate.ungroup",
1227
+ icon: "ungroup",
1228
+ categories: ["annotations"],
1229
+ run: (commandContext) => void anno(commandContext)?.selection.ungroup(),
1230
+ visible: (commandContext) => (anno(commandContext)?.selection.canUngroup() ?? false) && selectionEditable(commandContext)
1231
+ },
1232
+ {
1233
+ id: "selection:copy",
1234
+ labelKey: "commands.selection.copy",
1235
+ icon: "copy",
1236
+ categories: ["text.copy"],
1237
+ allowed: (commandContext) => textSelection(commandContext)?.canCopy() ?? true,
1238
+ notAllowedKey: "commands.notAllowed.doc-text-copy",
1239
+ visible: (commandContext) => textSelection(commandContext)?.hasSelection() ?? false,
1240
+ run: (commandContext) => {
1241
+ const selection = textSelection(commandContext);
1242
+ if (!selection) return;
1243
+ const copiedRange = selection.getRange();
1244
+ (0, _embedpdf_react_selection.copySelection)(selection).then((text) => {
1245
+ if (text !== "" && sameTextRange(selection.getRange(), copiedRange)) selection.clear();
1246
+ }, () => {});
1247
+ }
1248
+ },
1249
+ markupSelection("selection:highlight", "highlight", "commands.annotate.highlight", "highlight", "annotations.highlight"),
1250
+ markupSelection("selection:underline", "underline", "commands.annotate.underline", "underline", "annotations.markup"),
1251
+ markupSelection("selection:strikeout", "strikeout", "commands.annotate.strikeout", "strikethrough", "annotations.markup"),
1252
+ {
1253
+ id: "annotation:link",
1254
+ labelKey: "commands.annotate.link",
1255
+ icon: "link",
1256
+ categories: ["annotations.links"],
1257
+ run: (commandContext) => commandContext.tryGet(_embedpdf_react_shell.ShellToken)?.toggle("link-editor"),
1258
+ active: (commandContext) => commandContext.tryGet(_embedpdf_react_shell.ShellToken)?.isOpen("link-editor") ?? false,
1259
+ visible: (commandContext) => selectionLink(commandContext) === null
1260
+ },
1261
+ {
1262
+ id: "annotation:goto-link",
1263
+ labelKey: "commands.annotate.gotoLink",
1264
+ icon: "externalLink",
1265
+ run: (commandContext) => {
1266
+ const target = selectionLink(commandContext);
1267
+ if (target) commandContext.tryGet(_embedpdf_react_link.LinkToken)?.activate(target);
1268
+ },
1269
+ visible: (commandContext) => selectionLink(commandContext) != null
1270
+ },
1271
+ {
1272
+ id: "annotation:remove-link",
1273
+ labelKey: "commands.annotate.removeLink",
1274
+ icon: "linkOff",
1275
+ categories: ["annotations.links"],
1276
+ run: (commandContext) => anno(commandContext)?.selection.updateLink(null),
1277
+ visible: (commandContext) => selectionLink(commandContext) != null
1278
+ },
1279
+ {
1280
+ id: "help:shortcuts",
1281
+ labelKey: "commands.shortcuts",
1282
+ shortcut: "?",
1283
+ modal: SHORTCUTS_DIALOG,
1284
+ enabled: (commandContext) => commandContext.tryGet(_embedpdf_react_shell.ShellToken) != null
1285
+ },
1286
+ {
1287
+ id: "history:undo",
1288
+ labelKey: "commands.undo",
1289
+ icon: "arrowBackUp",
1290
+ shortcut: "Mod+z",
1291
+ run: (commandContext) => commandContext.tryGet(_embedpdf_react_history.HistoryToken)?.undo(),
1292
+ enabled: (commandContext) => commandContext.tryGet(_embedpdf_react_history.HistoryToken)?.canUndo() ?? false
1293
+ },
1294
+ {
1295
+ id: "history:redo",
1296
+ labelKey: "commands.redo",
1297
+ icon: "arrowForwardUp",
1298
+ shortcut: ["Shift+Mod+z", "Mod+y"],
1299
+ run: (commandContext) => commandContext.tryGet(_embedpdf_react_history.HistoryToken)?.redo(),
1300
+ enabled: (commandContext) => commandContext.tryGet(_embedpdf_react_history.HistoryToken)?.canRedo() ?? false
1301
+ }
1302
+ ];
1303
+ const MODE_SURFACES = [
1304
+ "mode:annotate",
1305
+ "mode:shapes",
1306
+ "mode:insert",
1307
+ "mode:form",
1308
+ "mode:redact",
1309
+ "mode:measure"
1310
+ ];
1311
+ function modeCommand(id, labelKey, { feature } = {}) {
1312
+ return {
1313
+ id,
1314
+ labelKey,
1315
+ ...feature ? { categories: [feature] } : {},
1316
+ run: (commandContext) => {
1317
+ commandContext.tryGet(_embedpdf_react_shell.ShellToken)?.toggle(id, { exclusive: "mode" });
1318
+ interaction(commandContext)?.activateTool("pointer");
1319
+ },
1320
+ active: (commandContext) => commandContext.tryGet(_embedpdf_react_shell.ShellToken)?.isOpen(id) ?? false
1321
+ };
1322
+ }
1323
+ /**
1324
+ * A `tool:<id>` command for each tool of yours (`plugins.annotation.tools`) that no command has
1325
+ * (`isTaken` says which ids do): labelled by its `meta.label`, else its id; drawn with its
1326
+ * `meta.icon`, else the icon of the tool it extends; in that tool's feature, else `annotations`.
1327
+ */
1328
+ function toolCommandsFor(tools, isTaken) {
1329
+ return tools.flatMap((input) => {
1330
+ const id = `tool:${input.id}`;
1331
+ if (isTaken(id)) return [];
1332
+ const base = input.extends;
1333
+ const meta = input.meta ?? {};
1334
+ const icon = typeof meta.icon === "string" ? meta.icon : base && TOOL_ICONS[base]?.icon;
1335
+ return [{
1336
+ ...toolCommand(id, input.id, icon || void 0, {
1337
+ feature: base && TOOL_FEATURES[base] || "annotations",
1338
+ check: CREATES_ANNOTATIONS,
1339
+ ...base && TOOL_ICONS[base]?.accent ? { accent: TOOL_ICONS[base].accent } : {}
1340
+ }),
1341
+ label: typeof meta.label === "string" ? meta.label : input.id
1342
+ }];
1343
+ });
1344
+ }
1345
+ //#endregion
1346
+ Object.defineProperty(exports, "FORM_DESIGN_PANEL", {
1347
+ enumerable: true,
1348
+ get: function() {
1349
+ return FORM_DESIGN_PANEL;
1350
+ }
1351
+ });
1352
+ Object.defineProperty(exports, "FORM_DESIGN_TOOL", {
1353
+ enumerable: true,
1354
+ get: function() {
1355
+ return FORM_DESIGN_TOOL;
1356
+ }
1357
+ });
1358
+ Object.defineProperty(exports, "GO_TO_PAGE_DIALOG", {
1359
+ enumerable: true,
1360
+ get: function() {
1361
+ return GO_TO_PAGE_DIALOG;
1362
+ }
1363
+ });
1364
+ Object.defineProperty(exports, "MODE_SURFACES", {
1365
+ enumerable: true,
1366
+ get: function() {
1367
+ return MODE_SURFACES;
1368
+ }
1369
+ });
1370
+ Object.defineProperty(exports, "OPEN_COMMAND_ID", {
1371
+ enumerable: true,
1372
+ get: function() {
1373
+ return OPEN_COMMAND_ID;
1374
+ }
1375
+ });
1376
+ Object.defineProperty(exports, "OUTLINE_PROPERTIES_DIALOG", {
1377
+ enumerable: true,
1378
+ get: function() {
1379
+ return OUTLINE_PROPERTIES_DIALOG;
1380
+ }
1381
+ });
1382
+ Object.defineProperty(exports, "OUTLINE_RENAME", {
1383
+ enumerable: true,
1384
+ get: function() {
1385
+ return OUTLINE_RENAME;
1386
+ }
1387
+ });
1388
+ Object.defineProperty(exports, "PRINT_DIALOG", {
1389
+ enumerable: true,
1390
+ get: function() {
1391
+ return PRINT_DIALOG;
1392
+ }
1393
+ });
1394
+ Object.defineProperty(exports, "REDACT_CONFIRM_DIALOG", {
1395
+ enumerable: true,
1396
+ get: function() {
1397
+ return REDACT_CONFIRM_DIALOG;
1398
+ }
1399
+ });
1400
+ Object.defineProperty(exports, "SHORTCUTS_DIALOG", {
1401
+ enumerable: true,
1402
+ get: function() {
1403
+ return SHORTCUTS_DIALOG;
1404
+ }
1405
+ });
1406
+ Object.defineProperty(exports, "TOOL_ICONS", {
1407
+ enumerable: true,
1408
+ get: function() {
1409
+ return TOOL_ICONS;
1410
+ }
1411
+ });
1412
+ Object.defineProperty(exports, "defaultCommands", {
1413
+ enumerable: true,
1414
+ get: function() {
1415
+ return defaultCommands;
1416
+ }
1417
+ });
1418
+ Object.defineProperty(exports, "isDesigningForm", {
1419
+ enumerable: true,
1420
+ get: function() {
1421
+ return isDesigningForm;
1422
+ }
1423
+ });
1424
+ Object.defineProperty(exports, "isFormDesignTool", {
1425
+ enumerable: true,
1426
+ get: function() {
1427
+ return isFormDesignTool;
1428
+ }
1429
+ });
1430
+ Object.defineProperty(exports, "isPdfFile", {
1431
+ enumerable: true,
1432
+ get: function() {
1433
+ return isPdfFile;
1434
+ }
1435
+ });
1436
+ Object.defineProperty(exports, "mayCarryPdf", {
1437
+ enumerable: true,
1438
+ get: function() {
1439
+ return mayCarryPdf;
1440
+ }
1441
+ });
1442
+ Object.defineProperty(exports, "modeCommandsFor", {
1443
+ enumerable: true,
1444
+ get: function() {
1445
+ return modeCommandsFor;
1446
+ }
1447
+ });
1448
+ Object.defineProperty(exports, "modeSpecsOf", {
1449
+ enumerable: true,
1450
+ get: function() {
1451
+ return modeSpecsOf;
1452
+ }
1453
+ });
1454
+ Object.defineProperty(exports, "openModeSurfaceOf", {
1455
+ enumerable: true,
1456
+ get: function() {
1457
+ return openModeSurfaceOf;
1458
+ }
1459
+ });
1460
+ Object.defineProperty(exports, "sameModeSpecs", {
1461
+ enumerable: true,
1462
+ get: function() {
1463
+ return sameModeSpecs;
1464
+ }
1465
+ });
1466
+ Object.defineProperty(exports, "toolCommandsFor", {
1467
+ enumerable: true,
1468
+ get: function() {
1469
+ return toolCommandsFor;
1470
+ }
1471
+ });
1472
+
1473
+ //# sourceMappingURL=commands-DL1gjZt7.cjs.map