@embedpdf/react 3.0.0-next.13 → 3.0.0-next.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (232) hide show
  1. package/dist/AnnotationList-CkijRHet-HEFNUIZe.d.cts +877 -0
  2. package/dist/AnnotationList-CkijRHet-HEFNUIZe.d.ts +877 -0
  3. package/dist/actions.cjs +25 -5
  4. package/dist/actions.cjs.map +1 -1
  5. package/dist/actions.d.cts +18 -5
  6. package/dist/actions.d.ts +18 -5
  7. package/dist/actions.js +22 -6
  8. package/dist/actions.js.map +1 -1
  9. package/dist/anchored-DeX95xSd.d.ts +85 -0
  10. package/dist/anchored-DzN3JywS.d.cts +85 -0
  11. package/dist/anchored.cjs +71 -28
  12. package/dist/anchored.cjs.map +1 -1
  13. package/dist/anchored.d.cts +2 -45
  14. package/dist/anchored.d.ts +2 -45
  15. package/dist/anchored.js +56 -19
  16. package/dist/anchored.js.map +1 -1
  17. package/dist/annotation-B48UT2ln.d.ts +302 -0
  18. package/dist/annotation-C1ttM8Wj.js +708 -0
  19. package/dist/annotation-C1ttM8Wj.js.map +1 -0
  20. package/dist/annotation-C9dVwo9b.d.cts +302 -0
  21. package/dist/annotation-Dex5EBda.cjs +830 -0
  22. package/dist/annotation-Dex5EBda.cjs.map +1 -0
  23. package/dist/annotation.cjs +20 -783
  24. package/dist/annotation.d.cts +2 -2
  25. package/dist/annotation.d.ts +2 -2
  26. package/dist/annotation.js +2 -768
  27. package/dist/commands.cjs +68 -28
  28. package/dist/commands.cjs.map +1 -1
  29. package/dist/commands.d.cts +37 -10
  30. package/dist/commands.d.ts +37 -10
  31. package/dist/commands.js +68 -31
  32. package/dist/commands.js.map +1 -1
  33. package/dist/form-55izw0jS.js +511 -0
  34. package/dist/form-55izw0jS.js.map +1 -0
  35. package/dist/form-BNqQfGGH.cjs +548 -0
  36. package/dist/form-BNqQfGGH.cjs.map +1 -0
  37. package/dist/form.cjs +5 -5
  38. package/dist/form.d.cts +32 -25
  39. package/dist/form.d.ts +32 -25
  40. package/dist/form.js +2 -3
  41. package/dist/history.cjs +38 -0
  42. package/dist/history.cjs.map +1 -0
  43. package/dist/history.d.cts +27 -0
  44. package/dist/history.d.ts +27 -0
  45. package/dist/history.js +27 -0
  46. package/dist/history.js.map +1 -0
  47. package/dist/i18n.cjs +26 -30
  48. package/dist/i18n.cjs.map +1 -1
  49. package/dist/i18n.d.cts +24 -21
  50. package/dist/i18n.d.ts +24 -21
  51. package/dist/i18n.js +24 -31
  52. package/dist/i18n.js.map +1 -1
  53. package/dist/index.cjs +213 -57
  54. package/dist/index.d.cts +32 -31
  55. package/dist/index.d.ts +32 -31
  56. package/dist/index.js +33 -29
  57. package/dist/inert-CmBEbKCn.cjs +19 -0
  58. package/dist/inert-CmBEbKCn.cjs.map +1 -0
  59. package/dist/inert-D8fkennb.js +14 -0
  60. package/dist/inert-D8fkennb.js.map +1 -0
  61. package/dist/interaction.cjs +48 -102
  62. package/dist/interaction.cjs.map +1 -1
  63. package/dist/interaction.d.cts +23 -32
  64. package/dist/interaction.d.ts +23 -32
  65. package/dist/interaction.js +33 -102
  66. package/dist/interaction.js.map +1 -1
  67. package/dist/link.cjs +65 -104
  68. package/dist/link.cjs.map +1 -1
  69. package/dist/link.d.cts +21 -16
  70. package/dist/link.d.ts +22 -17
  71. package/dist/link.js +67 -107
  72. package/dist/link.js.map +1 -1
  73. package/dist/measurement.cjs +56 -0
  74. package/dist/measurement.cjs.map +1 -0
  75. package/dist/measurement.d.cts +38 -0
  76. package/dist/measurement.d.ts +38 -0
  77. package/dist/measurement.js +42 -0
  78. package/dist/measurement.js.map +1 -0
  79. package/dist/metadata.cjs +20 -7
  80. package/dist/metadata.cjs.map +1 -1
  81. package/dist/metadata.d.cts +22 -7
  82. package/dist/metadata.d.ts +22 -7
  83. package/dist/metadata.js +20 -10
  84. package/dist/metadata.js.map +1 -1
  85. package/dist/page-edit.cjs +7 -3
  86. package/dist/page-edit.cjs.map +1 -1
  87. package/dist/page-edit.d.cts +6 -2
  88. package/dist/page-edit.d.ts +6 -2
  89. package/dist/page-edit.js +7 -4
  90. package/dist/page-edit.js.map +1 -1
  91. package/dist/page-layers-Bkaaz8Zf.js +26 -0
  92. package/dist/page-layers-Bkaaz8Zf.js.map +1 -0
  93. package/dist/page-layers-BloZDoOV.cjs +37 -0
  94. package/dist/page-layers-BloZDoOV.cjs.map +1 -0
  95. package/dist/page-view.cjs +89 -82
  96. package/dist/page-view.cjs.map +1 -1
  97. package/dist/page-view.d.cts +14 -7
  98. package/dist/page-view.d.ts +18 -11
  99. package/dist/page-view.js +86 -81
  100. package/dist/page-view.js.map +1 -1
  101. package/dist/redaction.cjs +30 -15
  102. package/dist/redaction.cjs.map +1 -1
  103. package/dist/redaction.d.cts +27 -9
  104. package/dist/redaction.d.ts +27 -9
  105. package/dist/redaction.js +29 -18
  106. package/dist/redaction.js.map +1 -1
  107. package/dist/render.cjs +71 -46
  108. package/dist/render.cjs.map +1 -1
  109. package/dist/render.d.cts +17 -5
  110. package/dist/render.d.ts +17 -5
  111. package/dist/render.js +70 -49
  112. package/dist/render.js.map +1 -1
  113. package/dist/runtime-B6xcPsEb.js +398 -0
  114. package/dist/runtime-B6xcPsEb.js.map +1 -0
  115. package/dist/runtime-DBEBlpQV.d.cts +237 -0
  116. package/dist/runtime-V3MVMb91.d.ts +237 -0
  117. package/dist/runtime-fzpGv78v.cjs +555 -0
  118. package/dist/runtime-fzpGv78v.cjs.map +1 -0
  119. package/dist/runtime.cjs +45 -324
  120. package/dist/runtime.d.cts +2 -2
  121. package/dist/runtime.d.ts +2 -2
  122. package/dist/runtime.js +2 -306
  123. package/dist/search.cjs +81 -50
  124. package/dist/search.cjs.map +1 -1
  125. package/dist/search.d.cts +36 -24
  126. package/dist/search.d.ts +36 -24
  127. package/dist/search.js +81 -53
  128. package/dist/search.js.map +1 -1
  129. package/dist/selection.cjs +105 -108
  130. package/dist/selection.cjs.map +1 -1
  131. package/dist/selection.d.cts +54 -26
  132. package/dist/selection.d.ts +56 -28
  133. package/dist/selection.js +103 -110
  134. package/dist/selection.js.map +1 -1
  135. package/dist/shell.cjs +36 -21
  136. package/dist/shell.cjs.map +1 -1
  137. package/dist/shell.d.cts +32 -17
  138. package/dist/shell.d.ts +32 -17
  139. package/dist/shell.js +36 -24
  140. package/dist/shell.js.map +1 -1
  141. package/dist/signature.cjs +29 -48
  142. package/dist/signature.cjs.map +1 -1
  143. package/dist/signature.d.cts +26 -26
  144. package/dist/signature.d.ts +26 -26
  145. package/dist/signature.js +30 -48
  146. package/dist/signature.js.map +1 -1
  147. package/dist/stage-BIG6aeVd.cjs +369 -0
  148. package/dist/stage-BIG6aeVd.cjs.map +1 -0
  149. package/dist/stage-ByFPD-Fv.d.cts +117 -0
  150. package/dist/stage-DaboaheR.d.ts +117 -0
  151. package/dist/stage-DoVekb83.js +302 -0
  152. package/dist/stage-DoVekb83.js.map +1 -0
  153. package/dist/stage-scope-CQgCuf1w.cjs +46 -0
  154. package/dist/stage-scope-CQgCuf1w.cjs.map +1 -0
  155. package/dist/stage-scope-D7ZeNduT.js +23 -0
  156. package/dist/stage-scope-D7ZeNduT.js.map +1 -0
  157. package/dist/stage.cjs +12 -235
  158. package/dist/stage.d.cts +2 -116
  159. package/dist/stage.d.ts +2 -116
  160. package/dist/stage.js +3 -228
  161. package/dist/stamp.cjs +41 -35
  162. package/dist/stamp.cjs.map +1 -1
  163. package/dist/stamp.d.cts +25 -18
  164. package/dist/stamp.d.ts +25 -18
  165. package/dist/stamp.js +40 -37
  166. package/dist/stamp.js.map +1 -1
  167. package/dist/state-0K1I5cM4.d.cts +29 -0
  168. package/dist/state-0K1I5cM4.d.ts +29 -0
  169. package/dist/state-CbgxhwLA.js +62 -0
  170. package/dist/state-CbgxhwLA.js.map +1 -0
  171. package/dist/state-CsfZy_Eq.cjs +73 -0
  172. package/dist/state-CsfZy_Eq.cjs.map +1 -0
  173. package/dist/svg-shapes-Dm1yTR1b.js +40 -0
  174. package/dist/svg-shapes-Dm1yTR1b.js.map +1 -0
  175. package/dist/svg-shapes-zo0GNkc9.cjs +53 -0
  176. package/dist/svg-shapes-zo0GNkc9.cjs.map +1 -0
  177. package/dist/toolbar.cjs +297 -295
  178. package/dist/toolbar.cjs.map +1 -1
  179. package/dist/toolbar.d.cts +58 -68
  180. package/dist/toolbar.d.ts +67 -77
  181. package/dist/toolbar.js +271 -293
  182. package/dist/toolbar.js.map +1 -1
  183. package/dist/view-manager.cjs +34 -0
  184. package/dist/view-manager.cjs.map +1 -0
  185. package/dist/view-manager.d.cts +21 -0
  186. package/dist/view-manager.d.ts +21 -0
  187. package/dist/view-manager.js +23 -0
  188. package/dist/view-manager.js.map +1 -0
  189. package/package.json +41 -38
  190. package/dist/AnnotationListSnapshot-D3mFut1e-C_GMpK25.d.cts +0 -546
  191. package/dist/AnnotationListSnapshot-D3mFut1e-C_GMpK25.d.ts +0 -546
  192. package/dist/annotation-BCED_p9H.d.cts +0 -160
  193. package/dist/annotation-anchors-CetwM1g7.js +0 -15
  194. package/dist/annotation-anchors-CetwM1g7.js.map +0 -1
  195. package/dist/annotation-anchors-DuYRBJLl.cjs +0 -26
  196. package/dist/annotation-anchors-DuYRBJLl.cjs.map +0 -1
  197. package/dist/annotation-hooks-BB5ZhPpf.cjs +0 -16
  198. package/dist/annotation-hooks-BB5ZhPpf.cjs.map +0 -1
  199. package/dist/annotation-hooks-Df8EmzDO.js +0 -11
  200. package/dist/annotation-hooks-Df8EmzDO.js.map +0 -1
  201. package/dist/annotation-k38KDlIZ.d.ts +0 -160
  202. package/dist/annotation-menu.cjs +0 -64
  203. package/dist/annotation-menu.cjs.map +0 -1
  204. package/dist/annotation-menu.d.cts +0 -33
  205. package/dist/annotation-menu.d.ts +0 -33
  206. package/dist/annotation-menu.js +0 -48
  207. package/dist/annotation-menu.js.map +0 -1
  208. package/dist/annotation.cjs.map +0 -1
  209. package/dist/annotation.js.map +0 -1
  210. package/dist/form-BVumS7up.cjs +0 -926
  211. package/dist/form-BVumS7up.cjs.map +0 -1
  212. package/dist/form-CK3mp99m.js +0 -895
  213. package/dist/form-CK3mp99m.js.map +0 -1
  214. package/dist/rolldown-runtime-BBjsoOtd.js +0 -27
  215. package/dist/runtime-DE76hlnl.d.ts +0 -216
  216. package/dist/runtime-umHA_xHt.d.cts +0 -216
  217. package/dist/runtime.cjs.map +0 -1
  218. package/dist/runtime.js.map +0 -1
  219. package/dist/scrollbar.cjs +0 -241
  220. package/dist/scrollbar.cjs.map +0 -1
  221. package/dist/scrollbar.d.cts +0 -42
  222. package/dist/scrollbar.d.ts +0 -42
  223. package/dist/scrollbar.js +0 -213
  224. package/dist/scrollbar.js.map +0 -1
  225. package/dist/stage.cjs.map +0 -1
  226. package/dist/stage.js.map +0 -1
  227. package/dist/views.cjs +0 -35
  228. package/dist/views.cjs.map +0 -1
  229. package/dist/views.d.cts +0 -21
  230. package/dist/views.d.ts +0 -21
  231. package/dist/views.js +0 -27
  232. package/dist/views.js.map +0 -1
package/dist/commands.cjs CHANGED
@@ -1,52 +1,92 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("./rolldown-runtime-DDXJien1.cjs");
3
- const require_runtime = require("./runtime.cjs");
3
+ const require_runtime = require("./runtime-fzpGv78v.cjs");
4
+ const require_state = require("./state-CsfZy_Eq.cjs");
5
+ let _embedpdf_web = require("@embedpdf/web");
4
6
  let react = require("react");
5
7
  let _embedpdf_plugin_commands = require("@embedpdf/plugin-commands");
8
+ let _embedpdf_core_ui = require("@embedpdf/core-ui");
9
+ let _embedpdf_plugin_commands_contract_host = require("@embedpdf/plugin-commands/contract/host");
6
10
  //#region src/commands.ts
7
- /** The commands capability (register/execute/search/categories). */
11
+ /**
12
+ * The commands every viewer has: zoom, pages, view rotation, `tool:<id>` for every tool, copy,
13
+ * delete, download and print, with shortcuts and labels in EmbedPDF's eight languages. Spread
14
+ * them into `commandsPlugin({ commands })`.
15
+ */
16
+ const standardCommands = /* @__PURE__ */ (0, require("@embedpdf/plugin-commands/standard").createStandardCommands)(_embedpdf_web.standardCommandsBrowser);
17
+ /** The commands capability: `execute`, `searchCommands`, `registerCommand`, the categories, the settings calls. */
8
18
  function useCommands() {
9
19
  return require_runtime.useCapability(_embedpdf_plugin_commands.CommandsToken);
10
20
  }
11
- /** A command resolved against this subtree's document, reactively. */
21
+ /** Subscribe to one commands event for the mounted lifetime: `useCommandsEvent((commands) => commands.onExecuted, handler)`. */
22
+ function useCommandsEvent(select, handler) {
23
+ require_runtime.useCapabilityEvent(_embedpdf_plugin_commands.CommandsToken, select, handler);
24
+ }
25
+ /**
26
+ * The commands settings (`commands`, `disabledCategories`, `disabledCommands`, `notAllowed`),
27
+ * with or without a document. Takes a selector.
28
+ */
29
+ const useCommandsSettings = require_state.settingsHook(_embedpdf_plugin_commands.CommandsToken);
30
+ /** A shortcut as a tooltip shows it, for this platform: `'⌘K'` on a Mac, `'Ctrl+K'` elsewhere. */
31
+ function formatShortcut(shortcut, options = {}) {
32
+ return (0, _embedpdf_core_ui.formatShortcut)(shortcut, { isMac: options.isMac ?? (0, _embedpdf_web.isMacPlatform)() });
33
+ }
34
+ /**
35
+ * A command for this component's document (the nearest <DocumentScope>, else the active one):
36
+ * its label, icon, state, `run` and `shortcut`. Re-renders when any of them changes. Always a
37
+ * command: an id no plugin registered is labelled with its id, neither visible nor enabled, and
38
+ * warns once in development.
39
+ */
12
40
  function useCommand(id) {
13
41
  const commands = require_runtime.useCapability(_embedpdf_plugin_commands.CommandsToken);
14
- const documentId = require_runtime.useDocumentId();
15
- return require_runtime.useKernelValue(() => commands.resolve(id, documentId ?? void 0), _embedpdf_plugin_commands.resolvedCommandsEqual);
42
+ const documentId = require_runtime.useDocumentId() ?? void 0;
43
+ const resolved = require_runtime.useKernelValue(() => commands.resolveCommand(id, documentId), _embedpdf_plugin_commands.resolvedCommandsEqual);
44
+ if (resolved === null) require_runtime.devWarn(`useCommand:${id}`, `useCommand(): ${(0, _embedpdf_plugin_commands.unknownCommandWarning)(id, commands.listCommandIds())}`);
45
+ return (0, react.useMemo)(() => (0, _embedpdf_plugin_commands.boundCommandOf)(resolved ?? (0, _embedpdf_plugin_commands.unregisteredCommand)(id), (commandId) => commands.execute(commandId, { documentId }), { isMac: (0, _embedpdf_web.isMacPlatform)() }), [
46
+ resolved,
47
+ commands,
48
+ documentId,
49
+ id
50
+ ]);
16
51
  }
17
- /** Is this environment mac-like? Decides how 'Mod' resolves and displays. */
18
- const isMacPlatform = () => typeof navigator !== "undefined" && /Mac|iP(hone|ad|od)/.test(navigator.platform);
19
- const isEditableTarget = (target) => {
20
- const el = target;
21
- if (!el || !el.tagName) return false;
22
- return el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.isContentEditable;
23
- };
24
52
  /**
25
- * Bind every registered shortcut. One listener for the whole registry —
26
- * matching is pure (ui-core), execution goes through the one command path.
27
- * Strokes from editable elements are ignored.
53
+ * Turn every command's shortcut into a working key, for the active document. Call it once, near
54
+ * the top of your viewer. Keys typed into text fields are left alone, and so is a key whose
55
+ * command can't run right now. A command that's turned off or not allowed still takes its key,
56
+ * and `onRefused` says why. The keys work anywhere on the page; with `target`, only while focus
57
+ * is inside that element, for a page with more than one viewer.
28
58
  */
29
59
  function useCommandShortcuts(options) {
30
- const commands = require_runtime.useCapability(_embedpdf_plugin_commands.CommandsToken);
60
+ const commands = require_runtime.useCapability(_embedpdf_plugin_commands_contract_host.CommandsToken);
31
61
  const isMac = options?.isMac;
62
+ const target = options?.target;
63
+ const onRefused = (0, react.useRef)(options?.onRefused);
64
+ onRefused.current = options?.onRefused;
32
65
  (0, react.useEffect)(() => {
33
- const mac = isMac ?? isMacPlatform();
34
- const onKeyDown = (event) => {
35
- if (event.defaultPrevented || isEditableTarget(event.target)) return;
36
- const id = commands.matchStroke(event, { isMac: mac });
37
- if (!id) return;
38
- event.preventDefault();
39
- commands.execute(id);
40
- };
41
- window.addEventListener("keydown", onKeyDown);
42
- return () => window.removeEventListener("keydown", onKeyDown);
43
- }, [commands, isMac]);
66
+ const report = (commandId, refusal) => onRefused.current?.(commandId, refusal);
67
+ if (!target) return (0, _embedpdf_web.bindCommandShortcuts)(commands, {
68
+ isMac,
69
+ onRefused: report
70
+ });
71
+ return target.current ? (0, _embedpdf_web.bindCommandShortcuts)(commands, {
72
+ isMac,
73
+ target: target.current,
74
+ onRefused: report
75
+ }) : void 0;
76
+ }, [
77
+ commands,
78
+ isMac,
79
+ target
80
+ ]);
44
81
  }
45
82
  //#endregion
46
- exports.isMacPlatform = isMacPlatform;
83
+ exports.formatShortcut = formatShortcut;
84
+ exports.standardCommands = standardCommands;
47
85
  exports.useCommand = useCommand;
48
86
  exports.useCommandShortcuts = useCommandShortcuts;
49
87
  exports.useCommands = useCommands;
88
+ exports.useCommandsEvent = useCommandsEvent;
89
+ exports.useCommandsSettings = useCommandsSettings;
50
90
  Object.keys(_embedpdf_plugin_commands).forEach(function(k) {
51
91
  if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
52
92
  enumerable: true,
@@ -1 +1 @@
1
- {"version":3,"file":"commands.cjs","names":["useCapability","CommandsToken","useDocumentId","useKernelValue","resolvedCommandsEqual"],"sources":["../src/commands.ts"],"sourcesContent":["/**\n * The React surface for @embedpdf/plugin-commands.\n *\n * Command state is a pure derivation over the store, so these hooks are thin:\n * `useCommand` re-resolves on the kernel's one change stream (cached by value\n * equality — locale flips, permission changes, and active-tool changes all\n * propagate with zero events), and `useCommandShortcuts` is the ~20 lines of\n * DOM that turn the registry's pure stroke matcher into a live keymap.\n */\n\n// One-line-per-feature: registration travels with the UI.\n// (resolvedCommandsEqual lives in the plugin now — it's pure value equality\n// over ResolvedCommand, framework-free — and arrives through this star.)\nexport * from '@embedpdf/plugin-commands';\nimport { useEffect } from 'react';\nimport { CommandsToken, resolvedCommandsEqual } from '@embedpdf/plugin-commands';\nimport type { CommandsCapability, ResolvedCommand } from '@embedpdf/plugin-commands';\nimport { useCapability, useDocumentId, useKernelValue } from './runtime';\n\n/** The commands capability (register/execute/search/categories). */\nexport function useCommands(): CommandsCapability {\n return useCapability(CommandsToken);\n}\n\n/** A command resolved against this subtree's document, reactively. */\nexport function useCommand(id: string): ResolvedCommand | null {\n const commands = useCapability(CommandsToken);\n const documentId = useDocumentId();\n return useKernelValue(() => commands.resolve(id, documentId ?? undefined), resolvedCommandsEqual);\n}\n\n/** Is this environment mac-like? Decides how 'Mod' resolves and displays. */\nexport const isMacPlatform = (): boolean =>\n typeof navigator !== 'undefined' && /Mac|iP(hone|ad|od)/.test(navigator.platform);\n\nconst isEditableTarget = (target: EventTarget | null): boolean => {\n const el = target as HTMLElement | null;\n if (!el || !el.tagName) return false;\n return el.tagName === 'INPUT' || el.tagName === 'TEXTAREA' || el.isContentEditable;\n};\n\n/**\n * Bind every registered shortcut. One listener for the whole registry —\n * matching is pure (ui-core), execution goes through the one command path.\n * Strokes from editable elements are ignored.\n */\nexport function useCommandShortcuts(options?: { isMac?: boolean }): void {\n const commands = useCapability(CommandsToken);\n const isMac = options?.isMac;\n useEffect(() => {\n const mac = isMac ?? isMacPlatform();\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.defaultPrevented || isEditableTarget(event.target)) return;\n const id = commands.matchStroke(event, { isMac: mac });\n if (!id) return;\n event.preventDefault();\n commands.execute(id);\n };\n window.addEventListener('keydown', onKeyDown);\n return () => window.removeEventListener('keydown', onKeyDown);\n }, [commands, isMac]);\n}\n"],"mappings":";;;;;;;AAoBA,SAAgB,cAAkC;CAChD,OAAOA,gBAAAA,cAAcC,0BAAAA,aAAa;AACpC;;AAGA,SAAgB,WAAW,IAAoC;CAC7D,MAAM,WAAWD,gBAAAA,cAAcC,0BAAAA,aAAa;CAC5C,MAAM,aAAaC,gBAAAA,cAAc;CACjC,OAAOC,gBAAAA,qBAAqB,SAAS,QAAQ,IAAI,cAAc,KAAA,CAAS,GAAGC,0BAAAA,qBAAqB;AAClG;;AAGA,MAAa,sBACX,OAAO,cAAc,eAAe,qBAAqB,KAAK,UAAU,QAAQ;AAElF,MAAM,oBAAoB,WAAwC;CAChE,MAAM,KAAK;CACX,IAAI,CAAC,MAAM,CAAC,GAAG,SAAS,OAAO;CAC/B,OAAO,GAAG,YAAY,WAAW,GAAG,YAAY,cAAc,GAAG;AACnE;;;;;;AAOA,SAAgB,oBAAoB,SAAqC;CACvE,MAAM,WAAWJ,gBAAAA,cAAcC,0BAAAA,aAAa;CAC5C,MAAM,QAAQ,SAAS;CACvB,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,MAAM,MAAM,SAAS,cAAc;EACnC,MAAM,aAAa,UAAyB;GAC1C,IAAI,MAAM,oBAAoB,iBAAiB,MAAM,MAAM,GAAG;GAC9D,MAAM,KAAK,SAAS,YAAY,OAAO,EAAE,OAAO,IAAI,CAAC;GACrD,IAAI,CAAC,IAAI;GACT,MAAM,eAAe;GACrB,SAAS,QAAQ,EAAE;EACrB;EACA,OAAO,iBAAiB,WAAW,SAAS;EAC5C,aAAa,OAAO,oBAAoB,WAAW,SAAS;CAC9D,GAAG,CAAC,UAAU,KAAK,CAAC;AACtB"}
1
+ {"version":3,"file":"commands.cjs","names":["standardCommandsBrowser","useCapability","CommandsToken","settingsHook","useDocumentId","useKernelValue","resolvedCommandsEqual","CommandsHostToken"],"sources":["../src/commands.ts"],"sourcesContent":["/**\n * The React surface for @embedpdf/plugin-commands: the standard commands, a\n * command as a button needs it, the settings, and keyboard shortcuts. A\n * command's state is read from live state, so `useCommand` re-renders on the\n * kernel's one change stream, only when what the command shows changed.\n */\n\n// One-line-per-feature: registration travels with the UI.\nexport * from '@embedpdf/plugin-commands';\nimport { useEffect, useMemo, useRef, type RefObject } from 'react';\nimport { formatShortcut as formatKeys } from '@embedpdf/core-ui';\nimport {\n CommandsToken,\n boundCommandOf,\n resolvedCommandsEqual,\n unknownCommandWarning,\n unregisteredCommand,\n} from '@embedpdf/plugin-commands';\nimport type {\n BoundCommand,\n CommandId,\n CommandRefusal,\n CommandsCapability,\n} from '@embedpdf/plugin-commands';\nimport { CommandsToken as CommandsHostToken } from '@embedpdf/plugin-commands/contract/host';\nimport { createStandardCommands } from '@embedpdf/plugin-commands/standard';\nimport type { EventHook } from '@embedpdf/core';\nimport { bindCommandShortcuts, isMacPlatform, standardCommandsBrowser } from '@embedpdf/web';\nimport { devWarn } from './dev';\nimport { useCapability, useCapabilityEvent, useDocumentId, useKernelValue } from './runtime';\nimport { settingsHook } from './state';\n\n/**\n * The commands every viewer has: zoom, pages, view rotation, `tool:<id>` for every tool, copy,\n * delete, download and print, with shortcuts and labels in EmbedPDF's eight languages. Spread\n * them into `commandsPlugin({ commands })`.\n */\nexport const standardCommands = /* @__PURE__ */ createStandardCommands(standardCommandsBrowser);\n\n/** The commands capability: `execute`, `searchCommands`, `registerCommand`, the categories, the settings calls. */\nexport function useCommands(): CommandsCapability {\n return useCapability(CommandsToken);\n}\n\n/** Subscribe to one commands event for the mounted lifetime: `useCommandsEvent((commands) => commands.onExecuted, handler)`. */\nexport function useCommandsEvent<T>(\n select: (commands: CommandsCapability) => EventHook<T>,\n handler: (event: T) => void,\n): void {\n useCapabilityEvent(CommandsToken, select, handler);\n}\n\n/**\n * The commands settings (`commands`, `disabledCategories`, `disabledCommands`, `notAllowed`),\n * with or without a document. Takes a selector.\n */\nexport const useCommandsSettings = settingsHook(CommandsToken);\n\n/** A shortcut as a tooltip shows it, for this platform: `'⌘K'` on a Mac, `'Ctrl+K'` elsewhere. */\nexport function formatShortcut(shortcut: string, options: { isMac?: boolean } = {}): string {\n return formatKeys(shortcut, { isMac: options.isMac ?? isMacPlatform() });\n}\n\n/**\n * A command for this component's document (the nearest <DocumentScope>, else the active one):\n * its label, icon, state, `run` and `shortcut`. Re-renders when any of them changes. Always a\n * command: an id no plugin registered is labelled with its id, neither visible nor enabled, and\n * warns once in development.\n */\nexport function useCommand(id: string): BoundCommand {\n const commands = useCapability(CommandsToken);\n const documentId = useDocumentId() ?? undefined;\n const resolved = useKernelValue(\n () => commands.resolveCommand(id, documentId),\n resolvedCommandsEqual,\n );\n if (resolved === null) {\n devWarn(`useCommand:${id}`, `useCommand(): ${unknownCommandWarning(id, commands.listCommandIds())}`);\n }\n return useMemo(\n () =>\n boundCommandOf(\n resolved ?? unregisteredCommand(id),\n (commandId) => commands.execute(commandId, { documentId }),\n { isMac: isMacPlatform() },\n ),\n [resolved, commands, documentId, id],\n );\n}\n\n/**\n * Turn every command's shortcut into a working key, for the active document. Call it once, near\n * the top of your viewer. Keys typed into text fields are left alone, and so is a key whose\n * command can't run right now. A command that's turned off or not allowed still takes its key,\n * and `onRefused` says why. The keys work anywhere on the page; with `target`, only while focus\n * is inside that element, for a page with more than one viewer.\n */\nexport function useCommandShortcuts(options?: {\n isMac?: boolean;\n target?: RefObject<HTMLElement | null>;\n onRefused?: (commandId: CommandId, refusal: CommandRefusal) => void;\n}): void {\n const commands = useCapability(CommandsHostToken);\n const isMac = options?.isMac;\n const target = options?.target;\n // The latest callback, so a new function each render doesn't bind the keys again.\n const onRefused = useRef(options?.onRefused);\n onRefused.current = options?.onRefused;\n useEffect(() => {\n const report = (commandId: CommandId, refusal: CommandRefusal) =>\n onRefused.current?.(commandId, refusal);\n if (!target) return bindCommandShortcuts(commands, { isMac, onRefused: report });\n // The element mounts before this effect runs, so its ref is set by now.\n return target.current\n ? bindCommandShortcuts(commands, { isMac, target: target.current, onRefused: report })\n : undefined;\n }, [commands, isMac, target]);\n}\n"],"mappings":";;;;;;;;;;;;;;;AAqCA,MAAa,mBAAmC,iBAAA,+CAAA,CAAA,CAAA,uBAAA,CAAuBA,cAAAA,uBAAuB;;AAG9F,SAAgB,cAAkC;CAChD,OAAOC,gBAAAA,cAAcC,0BAAAA,aAAa;AACpC;;AAGA,SAAgB,iBACd,QACA,SACM;CACN,gBAAA,mBAAmBA,0BAAAA,eAAe,QAAQ,OAAO;AACnD;;;;;AAMA,MAAa,sBAAsBC,cAAAA,aAAaD,0BAAAA,aAAa;;AAG7D,SAAgB,eAAe,UAAkB,UAA+B,CAAC,GAAW;CAC1F,QAAA,GAAA,kBAAA,eAAA,CAAkB,UAAU,EAAE,OAAO,QAAQ,UAAA,GAAA,cAAA,cAAA,CAAuB,EAAE,CAAC;AACzE;;;;;;;AAQA,SAAgB,WAAW,IAA0B;CACnD,MAAM,WAAWD,gBAAAA,cAAcC,0BAAAA,aAAa;CAC5C,MAAM,aAAaE,gBAAAA,cAAc,KAAK,KAAA;CACtC,MAAM,WAAWC,gBAAAA,qBACT,SAAS,eAAe,IAAI,UAAU,GAC5CC,0BAAAA,qBACF;CACA,IAAI,aAAa,MACf,gBAAA,QAAQ,cAAc,MAAM,kBAAA,GAAA,0BAAA,sBAAA,CAAuC,IAAI,SAAS,eAAe,CAAC,GAAG;CAErG,QAAA,GAAA,MAAA,QAAA,QAAA,GAAA,0BAAA,eAAA,CAGM,aAAA,GAAA,0BAAA,oBAAA,CAAgC,EAAE,IACjC,cAAc,SAAS,QAAQ,WAAW,EAAE,WAAW,CAAC,GACzD,EAAE,QAAA,GAAA,cAAA,cAAA,CAAqB,EAAE,CAC3B,GACF;EAAC;EAAU;EAAU;EAAY;CAAE,CACrC;AACF;;;;;;;;AASA,SAAgB,oBAAoB,SAI3B;CACP,MAAM,WAAWL,gBAAAA,cAAcM,wCAAAA,aAAiB;CAChD,MAAM,QAAQ,SAAS;CACvB,MAAM,SAAS,SAAS;CAExB,MAAM,aAAA,GAAA,MAAA,OAAA,CAAmB,SAAS,SAAS;CAC3C,UAAU,UAAU,SAAS;CAC7B,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,MAAM,UAAU,WAAsB,YACpC,UAAU,UAAU,WAAW,OAAO;EACxC,IAAI,CAAC,QAAQ,QAAA,GAAA,cAAA,qBAAA,CAA4B,UAAU;GAAE;GAAO,WAAW;EAAO,CAAC;EAE/E,OAAO,OAAO,WAAA,GAAA,cAAA,qBAAA,CACW,UAAU;GAAE;GAAO,QAAQ,OAAO;GAAS,WAAW;EAAO,CAAC,IACnF,KAAA;CACN,GAAG;EAAC;EAAU;EAAO;CAAM,CAAC;AAC9B"}
@@ -1,20 +1,47 @@
1
- import { CommandsCapability, ResolvedCommand } from "@embedpdf/plugin-commands";
1
+ import { t as SettingsHook } from "./state-0K1I5cM4.cjs";
2
+ import { EventHook } from "@embedpdf/core";
3
+ import { RefObject } from "react";
4
+ import { BoundCommand, CommandId, CommandRefusal, CommandsCapability } from "@embedpdf/plugin-commands";
2
5
  export * from "@embedpdf/plugin-commands";
3
6
  //#region src/commands.d.ts
4
- /** The commands capability (register/execute/search/categories). */
7
+ /**
8
+ * The commands every viewer has: zoom, pages, view rotation, `tool:<id>` for every tool, copy,
9
+ * delete, download and print, with shortcuts and labels in EmbedPDF's eight languages. Spread
10
+ * them into `commandsPlugin({ commands })`.
11
+ */
12
+ declare const standardCommands: readonly (import("@embedpdf/plugin-commands").CommandDef | import("@embedpdf/plugin-commands").CommandFamily)[];
13
+ /** The commands capability: `execute`, `searchCommands`, `registerCommand`, the categories, the settings calls. */
5
14
  declare function useCommands(): CommandsCapability;
6
- /** A command resolved against this subtree's document, reactively. */
7
- declare function useCommand(id: string): ResolvedCommand | null;
8
- /** Is this environment mac-like? Decides how 'Mod' resolves and displays. */
9
- declare const isMacPlatform: () => boolean;
15
+ /** Subscribe to one commands event for the mounted lifetime: `useCommandsEvent((commands) => commands.onExecuted, handler)`. */
16
+ declare function useCommandsEvent<T>(select: (commands: CommandsCapability) => EventHook<T>, handler: (event: T) => void): void;
17
+ /**
18
+ * The commands settings (`commands`, `disabledCategories`, `disabledCommands`, `notAllowed`),
19
+ * with or without a document. Takes a selector.
20
+ */
21
+ declare const useCommandsSettings: SettingsHook<import("@embedpdf/plugin-commands").CommandsSettings>;
22
+ /** A shortcut as a tooltip shows it, for this platform: `'⌘K'` on a Mac, `'Ctrl+K'` elsewhere. */
23
+ declare function formatShortcut(shortcut: string, options?: {
24
+ isMac?: boolean;
25
+ }): string;
26
+ /**
27
+ * A command for this component's document (the nearest <DocumentScope>, else the active one):
28
+ * its label, icon, state, `run` and `shortcut`. Re-renders when any of them changes. Always a
29
+ * command: an id no plugin registered is labelled with its id, neither visible nor enabled, and
30
+ * warns once in development.
31
+ */
32
+ declare function useCommand(id: string): BoundCommand;
10
33
  /**
11
- * Bind every registered shortcut. One listener for the whole registry —
12
- * matching is pure (ui-core), execution goes through the one command path.
13
- * Strokes from editable elements are ignored.
34
+ * Turn every command's shortcut into a working key, for the active document. Call it once, near
35
+ * the top of your viewer. Keys typed into text fields are left alone, and so is a key whose
36
+ * command can't run right now. A command that's turned off or not allowed still takes its key,
37
+ * and `onRefused` says why. The keys work anywhere on the page; with `target`, only while focus
38
+ * is inside that element, for a page with more than one viewer.
14
39
  */
15
40
  declare function useCommandShortcuts(options?: {
16
41
  isMac?: boolean;
42
+ target?: RefObject<HTMLElement | null>;
43
+ onRefused?: (commandId: CommandId, refusal: CommandRefusal) => void;
17
44
  }): void;
18
45
  //#endregion
19
- export { isMacPlatform, useCommand, useCommandShortcuts, useCommands };
46
+ export { formatShortcut, standardCommands, useCommand, useCommandShortcuts, useCommands, useCommandsEvent, useCommandsSettings };
20
47
  //# sourceMappingURL=commands.d.cts.map
@@ -1,20 +1,47 @@
1
- import { CommandsCapability, ResolvedCommand } from "@embedpdf/plugin-commands";
1
+ import { t as SettingsHook } from "./state-0K1I5cM4.js";
2
+ import { EventHook } from "@embedpdf/core";
3
+ import { RefObject } from "react";
4
+ import { BoundCommand, CommandId, CommandRefusal, CommandsCapability } from "@embedpdf/plugin-commands";
2
5
  export * from "@embedpdf/plugin-commands";
3
6
  //#region src/commands.d.ts
4
- /** The commands capability (register/execute/search/categories). */
7
+ /**
8
+ * The commands every viewer has: zoom, pages, view rotation, `tool:<id>` for every tool, copy,
9
+ * delete, download and print, with shortcuts and labels in EmbedPDF's eight languages. Spread
10
+ * them into `commandsPlugin({ commands })`.
11
+ */
12
+ declare const standardCommands: readonly (import("@embedpdf/plugin-commands").CommandDef | import("@embedpdf/plugin-commands").CommandFamily)[];
13
+ /** The commands capability: `execute`, `searchCommands`, `registerCommand`, the categories, the settings calls. */
5
14
  declare function useCommands(): CommandsCapability;
6
- /** A command resolved against this subtree's document, reactively. */
7
- declare function useCommand(id: string): ResolvedCommand | null;
8
- /** Is this environment mac-like? Decides how 'Mod' resolves and displays. */
9
- declare const isMacPlatform: () => boolean;
15
+ /** Subscribe to one commands event for the mounted lifetime: `useCommandsEvent((commands) => commands.onExecuted, handler)`. */
16
+ declare function useCommandsEvent<T>(select: (commands: CommandsCapability) => EventHook<T>, handler: (event: T) => void): void;
17
+ /**
18
+ * The commands settings (`commands`, `disabledCategories`, `disabledCommands`, `notAllowed`),
19
+ * with or without a document. Takes a selector.
20
+ */
21
+ declare const useCommandsSettings: SettingsHook<import("@embedpdf/plugin-commands").CommandsSettings>;
22
+ /** A shortcut as a tooltip shows it, for this platform: `'⌘K'` on a Mac, `'Ctrl+K'` elsewhere. */
23
+ declare function formatShortcut(shortcut: string, options?: {
24
+ isMac?: boolean;
25
+ }): string;
26
+ /**
27
+ * A command for this component's document (the nearest <DocumentScope>, else the active one):
28
+ * its label, icon, state, `run` and `shortcut`. Re-renders when any of them changes. Always a
29
+ * command: an id no plugin registered is labelled with its id, neither visible nor enabled, and
30
+ * warns once in development.
31
+ */
32
+ declare function useCommand(id: string): BoundCommand;
10
33
  /**
11
- * Bind every registered shortcut. One listener for the whole registry —
12
- * matching is pure (ui-core), execution goes through the one command path.
13
- * Strokes from editable elements are ignored.
34
+ * Turn every command's shortcut into a working key, for the active document. Call it once, near
35
+ * the top of your viewer. Keys typed into text fields are left alone, and so is a key whose
36
+ * command can't run right now. A command that's turned off or not allowed still takes its key,
37
+ * and `onRefused` says why. The keys work anywhere on the page; with `target`, only while focus
38
+ * is inside that element, for a page with more than one viewer.
14
39
  */
15
40
  declare function useCommandShortcuts(options?: {
16
41
  isMac?: boolean;
42
+ target?: RefObject<HTMLElement | null>;
43
+ onRefused?: (commandId: CommandId, refusal: CommandRefusal) => void;
17
44
  }): void;
18
45
  //#endregion
19
- export { isMacPlatform, useCommand, useCommandShortcuts, useCommands };
46
+ export { formatShortcut, standardCommands, useCommand, useCommandShortcuts, useCommands, useCommandsEvent, useCommandsSettings };
20
47
  //# sourceMappingURL=commands.d.ts.map
package/dist/commands.js CHANGED
@@ -1,48 +1,85 @@
1
- import "./rolldown-runtime-BBjsoOtd.js";
2
- import { useCapability, useDocumentId, useKernelValue } from "./runtime.js";
3
- import { useEffect } from "react";
4
- import { CommandsToken, resolvedCommandsEqual } from "@embedpdf/plugin-commands";
1
+ import { O as devWarn, f as useCapability, h as useDocumentId, p as useCapabilityEvent, x as useKernelValue } from "./runtime-B6xcPsEb.js";
2
+ import { t as settingsHook } from "./state-CbgxhwLA.js";
3
+ import { bindCommandShortcuts, isMacPlatform, standardCommandsBrowser } from "@embedpdf/web";
4
+ import { useEffect, useMemo, useRef } from "react";
5
+ import { CommandsToken, boundCommandOf, resolvedCommandsEqual, unknownCommandWarning, unregisteredCommand } from "@embedpdf/plugin-commands";
6
+ import { formatShortcut as formatShortcut$1 } from "@embedpdf/core-ui";
7
+ import { CommandsToken as CommandsToken$1 } from "@embedpdf/plugin-commands/contract/host";
8
+ import { createStandardCommands } from "@embedpdf/plugin-commands/standard";
5
9
  export * from "@embedpdf/plugin-commands";
6
10
  //#region src/commands.ts
7
- /** The commands capability (register/execute/search/categories). */
11
+ /**
12
+ * The commands every viewer has: zoom, pages, view rotation, `tool:<id>` for every tool, copy,
13
+ * delete, download and print, with shortcuts and labels in EmbedPDF's eight languages. Spread
14
+ * them into `commandsPlugin({ commands })`.
15
+ */
16
+ const standardCommands = /* @__PURE__ */ createStandardCommands(standardCommandsBrowser);
17
+ /** The commands capability: `execute`, `searchCommands`, `registerCommand`, the categories, the settings calls. */
8
18
  function useCommands() {
9
19
  return useCapability(CommandsToken);
10
20
  }
11
- /** A command resolved against this subtree's document, reactively. */
21
+ /** Subscribe to one commands event for the mounted lifetime: `useCommandsEvent((commands) => commands.onExecuted, handler)`. */
22
+ function useCommandsEvent(select, handler) {
23
+ useCapabilityEvent(CommandsToken, select, handler);
24
+ }
25
+ /**
26
+ * The commands settings (`commands`, `disabledCategories`, `disabledCommands`, `notAllowed`),
27
+ * with or without a document. Takes a selector.
28
+ */
29
+ const useCommandsSettings = settingsHook(CommandsToken);
30
+ /** A shortcut as a tooltip shows it, for this platform: `'⌘K'` on a Mac, `'Ctrl+K'` elsewhere. */
31
+ function formatShortcut(shortcut, options = {}) {
32
+ return formatShortcut$1(shortcut, { isMac: options.isMac ?? isMacPlatform() });
33
+ }
34
+ /**
35
+ * A command for this component's document (the nearest <DocumentScope>, else the active one):
36
+ * its label, icon, state, `run` and `shortcut`. Re-renders when any of them changes. Always a
37
+ * command: an id no plugin registered is labelled with its id, neither visible nor enabled, and
38
+ * warns once in development.
39
+ */
12
40
  function useCommand(id) {
13
41
  const commands = useCapability(CommandsToken);
14
- const documentId = useDocumentId();
15
- return useKernelValue(() => commands.resolve(id, documentId ?? void 0), resolvedCommandsEqual);
42
+ const documentId = useDocumentId() ?? void 0;
43
+ const resolved = useKernelValue(() => commands.resolveCommand(id, documentId), resolvedCommandsEqual);
44
+ if (resolved === null) devWarn(`useCommand:${id}`, `useCommand(): ${unknownCommandWarning(id, commands.listCommandIds())}`);
45
+ return useMemo(() => boundCommandOf(resolved ?? unregisteredCommand(id), (commandId) => commands.execute(commandId, { documentId }), { isMac: isMacPlatform() }), [
46
+ resolved,
47
+ commands,
48
+ documentId,
49
+ id
50
+ ]);
16
51
  }
17
- /** Is this environment mac-like? Decides how 'Mod' resolves and displays. */
18
- const isMacPlatform = () => typeof navigator !== "undefined" && /Mac|iP(hone|ad|od)/.test(navigator.platform);
19
- const isEditableTarget = (target) => {
20
- const el = target;
21
- if (!el || !el.tagName) return false;
22
- return el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.isContentEditable;
23
- };
24
52
  /**
25
- * Bind every registered shortcut. One listener for the whole registry —
26
- * matching is pure (ui-core), execution goes through the one command path.
27
- * Strokes from editable elements are ignored.
53
+ * Turn every command's shortcut into a working key, for the active document. Call it once, near
54
+ * the top of your viewer. Keys typed into text fields are left alone, and so is a key whose
55
+ * command can't run right now. A command that's turned off or not allowed still takes its key,
56
+ * and `onRefused` says why. The keys work anywhere on the page; with `target`, only while focus
57
+ * is inside that element, for a page with more than one viewer.
28
58
  */
29
59
  function useCommandShortcuts(options) {
30
- const commands = useCapability(CommandsToken);
60
+ const commands = useCapability(CommandsToken$1);
31
61
  const isMac = options?.isMac;
62
+ const target = options?.target;
63
+ const onRefused = useRef(options?.onRefused);
64
+ onRefused.current = options?.onRefused;
32
65
  useEffect(() => {
33
- const mac = isMac ?? isMacPlatform();
34
- const onKeyDown = (event) => {
35
- if (event.defaultPrevented || isEditableTarget(event.target)) return;
36
- const id = commands.matchStroke(event, { isMac: mac });
37
- if (!id) return;
38
- event.preventDefault();
39
- commands.execute(id);
40
- };
41
- window.addEventListener("keydown", onKeyDown);
42
- return () => window.removeEventListener("keydown", onKeyDown);
43
- }, [commands, isMac]);
66
+ const report = (commandId, refusal) => onRefused.current?.(commandId, refusal);
67
+ if (!target) return bindCommandShortcuts(commands, {
68
+ isMac,
69
+ onRefused: report
70
+ });
71
+ return target.current ? bindCommandShortcuts(commands, {
72
+ isMac,
73
+ target: target.current,
74
+ onRefused: report
75
+ }) : void 0;
76
+ }, [
77
+ commands,
78
+ isMac,
79
+ target
80
+ ]);
44
81
  }
45
82
  //#endregion
46
- export { isMacPlatform, useCommand, useCommandShortcuts, useCommands };
83
+ export { formatShortcut, standardCommands, useCommand, useCommandShortcuts, useCommands, useCommandsEvent, useCommandsSettings };
47
84
 
48
85
  //# sourceMappingURL=commands.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"commands.js","names":[],"sources":["../src/commands.ts"],"sourcesContent":["/**\n * The React surface for @embedpdf/plugin-commands.\n *\n * Command state is a pure derivation over the store, so these hooks are thin:\n * `useCommand` re-resolves on the kernel's one change stream (cached by value\n * equality — locale flips, permission changes, and active-tool changes all\n * propagate with zero events), and `useCommandShortcuts` is the ~20 lines of\n * DOM that turn the registry's pure stroke matcher into a live keymap.\n */\n\n// One-line-per-feature: registration travels with the UI.\n// (resolvedCommandsEqual lives in the plugin now — it's pure value equality\n// over ResolvedCommand, framework-free — and arrives through this star.)\nexport * from '@embedpdf/plugin-commands';\nimport { useEffect } from 'react';\nimport { CommandsToken, resolvedCommandsEqual } from '@embedpdf/plugin-commands';\nimport type { CommandsCapability, ResolvedCommand } from '@embedpdf/plugin-commands';\nimport { useCapability, useDocumentId, useKernelValue } from './runtime';\n\n/** The commands capability (register/execute/search/categories). */\nexport function useCommands(): CommandsCapability {\n return useCapability(CommandsToken);\n}\n\n/** A command resolved against this subtree's document, reactively. */\nexport function useCommand(id: string): ResolvedCommand | null {\n const commands = useCapability(CommandsToken);\n const documentId = useDocumentId();\n return useKernelValue(() => commands.resolve(id, documentId ?? undefined), resolvedCommandsEqual);\n}\n\n/** Is this environment mac-like? Decides how 'Mod' resolves and displays. */\nexport const isMacPlatform = (): boolean =>\n typeof navigator !== 'undefined' && /Mac|iP(hone|ad|od)/.test(navigator.platform);\n\nconst isEditableTarget = (target: EventTarget | null): boolean => {\n const el = target as HTMLElement | null;\n if (!el || !el.tagName) return false;\n return el.tagName === 'INPUT' || el.tagName === 'TEXTAREA' || el.isContentEditable;\n};\n\n/**\n * Bind every registered shortcut. One listener for the whole registry —\n * matching is pure (ui-core), execution goes through the one command path.\n * Strokes from editable elements are ignored.\n */\nexport function useCommandShortcuts(options?: { isMac?: boolean }): void {\n const commands = useCapability(CommandsToken);\n const isMac = options?.isMac;\n useEffect(() => {\n const mac = isMac ?? isMacPlatform();\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.defaultPrevented || isEditableTarget(event.target)) return;\n const id = commands.matchStroke(event, { isMac: mac });\n if (!id) return;\n event.preventDefault();\n commands.execute(id);\n };\n window.addEventListener('keydown', onKeyDown);\n return () => window.removeEventListener('keydown', onKeyDown);\n }, [commands, isMac]);\n}\n"],"mappings":";;;;;;;AAoBA,SAAgB,cAAkC;CAChD,OAAO,cAAc,aAAa;AACpC;;AAGA,SAAgB,WAAW,IAAoC;CAC7D,MAAM,WAAW,cAAc,aAAa;CAC5C,MAAM,aAAa,cAAc;CACjC,OAAO,qBAAqB,SAAS,QAAQ,IAAI,cAAc,KAAA,CAAS,GAAG,qBAAqB;AAClG;;AAGA,MAAa,sBACX,OAAO,cAAc,eAAe,qBAAqB,KAAK,UAAU,QAAQ;AAElF,MAAM,oBAAoB,WAAwC;CAChE,MAAM,KAAK;CACX,IAAI,CAAC,MAAM,CAAC,GAAG,SAAS,OAAO;CAC/B,OAAO,GAAG,YAAY,WAAW,GAAG,YAAY,cAAc,GAAG;AACnE;;;;;;AAOA,SAAgB,oBAAoB,SAAqC;CACvE,MAAM,WAAW,cAAc,aAAa;CAC5C,MAAM,QAAQ,SAAS;CACvB,gBAAgB;EACd,MAAM,MAAM,SAAS,cAAc;EACnC,MAAM,aAAa,UAAyB;GAC1C,IAAI,MAAM,oBAAoB,iBAAiB,MAAM,MAAM,GAAG;GAC9D,MAAM,KAAK,SAAS,YAAY,OAAO,EAAE,OAAO,IAAI,CAAC;GACrD,IAAI,CAAC,IAAI;GACT,MAAM,eAAe;GACrB,SAAS,QAAQ,EAAE;EACrB;EACA,OAAO,iBAAiB,WAAW,SAAS;EAC5C,aAAa,OAAO,oBAAoB,WAAW,SAAS;CAC9D,GAAG,CAAC,UAAU,KAAK,CAAC;AACtB"}
1
+ {"version":3,"file":"commands.js","names":["formatKeys","CommandsHostToken"],"sources":["../src/commands.ts"],"sourcesContent":["/**\n * The React surface for @embedpdf/plugin-commands: the standard commands, a\n * command as a button needs it, the settings, and keyboard shortcuts. A\n * command's state is read from live state, so `useCommand` re-renders on the\n * kernel's one change stream, only when what the command shows changed.\n */\n\n// One-line-per-feature: registration travels with the UI.\nexport * from '@embedpdf/plugin-commands';\nimport { useEffect, useMemo, useRef, type RefObject } from 'react';\nimport { formatShortcut as formatKeys } from '@embedpdf/core-ui';\nimport {\n CommandsToken,\n boundCommandOf,\n resolvedCommandsEqual,\n unknownCommandWarning,\n unregisteredCommand,\n} from '@embedpdf/plugin-commands';\nimport type {\n BoundCommand,\n CommandId,\n CommandRefusal,\n CommandsCapability,\n} from '@embedpdf/plugin-commands';\nimport { CommandsToken as CommandsHostToken } from '@embedpdf/plugin-commands/contract/host';\nimport { createStandardCommands } from '@embedpdf/plugin-commands/standard';\nimport type { EventHook } from '@embedpdf/core';\nimport { bindCommandShortcuts, isMacPlatform, standardCommandsBrowser } from '@embedpdf/web';\nimport { devWarn } from './dev';\nimport { useCapability, useCapabilityEvent, useDocumentId, useKernelValue } from './runtime';\nimport { settingsHook } from './state';\n\n/**\n * The commands every viewer has: zoom, pages, view rotation, `tool:<id>` for every tool, copy,\n * delete, download and print, with shortcuts and labels in EmbedPDF's eight languages. Spread\n * them into `commandsPlugin({ commands })`.\n */\nexport const standardCommands = /* @__PURE__ */ createStandardCommands(standardCommandsBrowser);\n\n/** The commands capability: `execute`, `searchCommands`, `registerCommand`, the categories, the settings calls. */\nexport function useCommands(): CommandsCapability {\n return useCapability(CommandsToken);\n}\n\n/** Subscribe to one commands event for the mounted lifetime: `useCommandsEvent((commands) => commands.onExecuted, handler)`. */\nexport function useCommandsEvent<T>(\n select: (commands: CommandsCapability) => EventHook<T>,\n handler: (event: T) => void,\n): void {\n useCapabilityEvent(CommandsToken, select, handler);\n}\n\n/**\n * The commands settings (`commands`, `disabledCategories`, `disabledCommands`, `notAllowed`),\n * with or without a document. Takes a selector.\n */\nexport const useCommandsSettings = settingsHook(CommandsToken);\n\n/** A shortcut as a tooltip shows it, for this platform: `'⌘K'` on a Mac, `'Ctrl+K'` elsewhere. */\nexport function formatShortcut(shortcut: string, options: { isMac?: boolean } = {}): string {\n return formatKeys(shortcut, { isMac: options.isMac ?? isMacPlatform() });\n}\n\n/**\n * A command for this component's document (the nearest <DocumentScope>, else the active one):\n * its label, icon, state, `run` and `shortcut`. Re-renders when any of them changes. Always a\n * command: an id no plugin registered is labelled with its id, neither visible nor enabled, and\n * warns once in development.\n */\nexport function useCommand(id: string): BoundCommand {\n const commands = useCapability(CommandsToken);\n const documentId = useDocumentId() ?? undefined;\n const resolved = useKernelValue(\n () => commands.resolveCommand(id, documentId),\n resolvedCommandsEqual,\n );\n if (resolved === null) {\n devWarn(`useCommand:${id}`, `useCommand(): ${unknownCommandWarning(id, commands.listCommandIds())}`);\n }\n return useMemo(\n () =>\n boundCommandOf(\n resolved ?? unregisteredCommand(id),\n (commandId) => commands.execute(commandId, { documentId }),\n { isMac: isMacPlatform() },\n ),\n [resolved, commands, documentId, id],\n );\n}\n\n/**\n * Turn every command's shortcut into a working key, for the active document. Call it once, near\n * the top of your viewer. Keys typed into text fields are left alone, and so is a key whose\n * command can't run right now. A command that's turned off or not allowed still takes its key,\n * and `onRefused` says why. The keys work anywhere on the page; with `target`, only while focus\n * is inside that element, for a page with more than one viewer.\n */\nexport function useCommandShortcuts(options?: {\n isMac?: boolean;\n target?: RefObject<HTMLElement | null>;\n onRefused?: (commandId: CommandId, refusal: CommandRefusal) => void;\n}): void {\n const commands = useCapability(CommandsHostToken);\n const isMac = options?.isMac;\n const target = options?.target;\n // The latest callback, so a new function each render doesn't bind the keys again.\n const onRefused = useRef(options?.onRefused);\n onRefused.current = options?.onRefused;\n useEffect(() => {\n const report = (commandId: CommandId, refusal: CommandRefusal) =>\n onRefused.current?.(commandId, refusal);\n if (!target) return bindCommandShortcuts(commands, { isMac, onRefused: report });\n // The element mounts before this effect runs, so its ref is set by now.\n return target.current\n ? bindCommandShortcuts(commands, { isMac, target: target.current, onRefused: report })\n : undefined;\n }, [commands, isMac, target]);\n}\n"],"mappings":";;;;;;;;;;;;;;;AAqCA,MAAa,mBAAmC,uCAAuB,uBAAuB;;AAG9F,SAAgB,cAAkC;CAChD,OAAO,cAAc,aAAa;AACpC;;AAGA,SAAgB,iBACd,QACA,SACM;CACN,mBAAmB,eAAe,QAAQ,OAAO;AACnD;;;;;AAMA,MAAa,sBAAsB,aAAa,aAAa;;AAG7D,SAAgB,eAAe,UAAkB,UAA+B,CAAC,GAAW;CAC1F,OAAOA,iBAAW,UAAU,EAAE,OAAO,QAAQ,SAAS,cAAc,EAAE,CAAC;AACzE;;;;;;;AAQA,SAAgB,WAAW,IAA0B;CACnD,MAAM,WAAW,cAAc,aAAa;CAC5C,MAAM,aAAa,cAAc,KAAK,KAAA;CACtC,MAAM,WAAW,qBACT,SAAS,eAAe,IAAI,UAAU,GAC5C,qBACF;CACA,IAAI,aAAa,MACf,QAAQ,cAAc,MAAM,iBAAiB,sBAAsB,IAAI,SAAS,eAAe,CAAC,GAAG;CAErG,OAAO,cAEH,eACE,YAAY,oBAAoB,EAAE,IACjC,cAAc,SAAS,QAAQ,WAAW,EAAE,WAAW,CAAC,GACzD,EAAE,OAAO,cAAc,EAAE,CAC3B,GACF;EAAC;EAAU;EAAU;EAAY;CAAE,CACrC;AACF;;;;;;;;AASA,SAAgB,oBAAoB,SAI3B;CACP,MAAM,WAAW,cAAcC,eAAiB;CAChD,MAAM,QAAQ,SAAS;CACvB,MAAM,SAAS,SAAS;CAExB,MAAM,YAAY,OAAO,SAAS,SAAS;CAC3C,UAAU,UAAU,SAAS;CAC7B,gBAAgB;EACd,MAAM,UAAU,WAAsB,YACpC,UAAU,UAAU,WAAW,OAAO;EACxC,IAAI,CAAC,QAAQ,OAAO,qBAAqB,UAAU;GAAE;GAAO,WAAW;EAAO,CAAC;EAE/E,OAAO,OAAO,UACV,qBAAqB,UAAU;GAAE;GAAO,QAAQ,OAAO;GAAS,WAAW;EAAO,CAAC,IACnF,KAAA;CACN,GAAG;EAAC;EAAU;EAAO;CAAM,CAAC;AAC9B"}