@embedpdf/viewer-chrome 3.0.0-next.15 → 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 (200) hide show
  1. package/dist/{annotation-fonts-BqoLZ4Mp.js → annotation-fonts-DWjVOTP0.js} +2 -2
  2. package/dist/{annotation-fonts-BqoLZ4Mp.js.map → annotation-fonts-DWjVOTP0.js.map} +1 -1
  3. package/dist/{annotation-fonts-Dt0IQXhz.cjs → annotation-fonts-dpfVkhnq.cjs} +2 -2
  4. package/dist/{annotation-fonts-Dt0IQXhz.cjs.map → annotation-fonts-dpfVkhnq.cjs.map} +1 -1
  5. package/dist/{annotation-style-Bzvvp8-N.cjs → annotation-style-B3XKAyZ-.cjs} +3 -3
  6. package/dist/{annotation-style-Bzvvp8-N.cjs.map → annotation-style-B3XKAyZ-.cjs.map} +1 -1
  7. package/dist/{annotation-style--rPIZsuP.js → annotation-style-CXF3X47Z.js} +3 -3
  8. package/dist/{annotation-style--rPIZsuP.js.map → annotation-style-CXF3X47Z.js.map} +1 -1
  9. package/dist/{ar-DnEj5vbP.cjs → ar-B132r9bo.cjs} +93 -1
  10. package/dist/ar-B132r9bo.cjs.map +1 -0
  11. package/dist/{ar-D9XKAmDx.js → ar-BLWFJoA_.js} +93 -1
  12. package/dist/ar-BLWFJoA_.js.map +1 -0
  13. package/dist/attachments-panel-Cxln8xos.cjs +217 -0
  14. package/dist/attachments-panel-Cxln8xos.cjs.map +1 -0
  15. package/dist/attachments-panel-H1ucRbwo.js +217 -0
  16. package/dist/attachments-panel-H1ucRbwo.js.map +1 -0
  17. package/dist/chrome.cjs +21 -0
  18. package/dist/chrome.cjs.map +1 -1
  19. package/dist/chrome.js +21 -0
  20. package/dist/chrome.js.map +1 -1
  21. package/dist/{commands-BmgxhJ8B.js → commands-BkgLP3Om.js} +418 -23
  22. package/dist/commands-BkgLP3Om.js.map +1 -0
  23. package/dist/{commands-CYt4SFUX.cjs → commands-DL1gjZt7.cjs} +433 -20
  24. package/dist/commands-DL1gjZt7.cjs.map +1 -0
  25. package/dist/commands.cjs +2 -1
  26. package/dist/commands.d.cts +3 -1
  27. package/dist/commands.d.ts +3 -1
  28. package/dist/commands.js +2 -2
  29. package/dist/{comments-panel-pEcQg4Vs.cjs → comments-panel-BsnWedTh.cjs} +2 -2
  30. package/dist/{comments-panel-pEcQg4Vs.cjs.map → comments-panel-BsnWedTh.cjs.map} +1 -1
  31. package/dist/{comments-panel-MUVgLCBI.js → comments-panel-D7Eadws9.js} +2 -2
  32. package/dist/{comments-panel-MUVgLCBI.js.map → comments-panel-D7Eadws9.js.map} +1 -1
  33. package/dist/{de-Dv6zvbnd.cjs → de-7_MvFWzN.cjs} +93 -1
  34. package/dist/de-7_MvFWzN.cjs.map +1 -0
  35. package/dist/{de-Bdr4aWzm.js → de-BUhwc9-x.js} +93 -1
  36. package/dist/de-BUhwc9-x.js.map +1 -0
  37. package/dist/{dialog-B5GBisKv.js → dialog-BIb373cg.js} +3 -3
  38. package/dist/dialog-BIb373cg.js.map +1 -0
  39. package/dist/{dialog-t8F13BL_.cjs → dialog-CngKTnAM.cjs} +3 -3
  40. package/dist/dialog-CngKTnAM.cjs.map +1 -0
  41. package/dist/{es-BP09DR9w.cjs → es-DgYj-1L3.cjs} +93 -1
  42. package/dist/es-DgYj-1L3.cjs.map +1 -0
  43. package/dist/{es-BSXz5tBv.js → es-DoXTqFoO.js} +93 -1
  44. package/dist/es-DoXTqFoO.js.map +1 -0
  45. package/dist/{form-design-panel-vWWU9uB-.js → form-design-panel-CgV_5YWC.js} +3 -3
  46. package/dist/{form-design-panel-vWWU9uB-.js.map → form-design-panel-CgV_5YWC.js.map} +1 -1
  47. package/dist/{form-design-panel-B5MXTZ96.cjs → form-design-panel-D0FdmWXW.cjs} +3 -3
  48. package/dist/{form-design-panel-B5MXTZ96.cjs.map → form-design-panel-D0FdmWXW.cjs.map} +1 -1
  49. package/dist/{fr-Ckn3K9v1.js → fr-B-8NDhBA.js} +93 -1
  50. package/dist/fr-B-8NDhBA.js.map +1 -0
  51. package/dist/{fr-BBQQn7tJ.cjs → fr-C856dmQJ.cjs} +93 -1
  52. package/dist/fr-C856dmQJ.cjs.map +1 -0
  53. package/dist/{he-DRsG7bH7.cjs → he-BFTeNc4t.cjs} +93 -1
  54. package/dist/he-BFTeNc4t.cjs.map +1 -0
  55. package/dist/{he-wdGU5PkU.js → he-Dlh0fNXM.js} +93 -1
  56. package/dist/he-Dlh0fNXM.js.map +1 -0
  57. package/dist/{icons-x0Tc05bs.cjs → icons-1UfLUZ_y.cjs} +20 -1
  58. package/dist/icons-1UfLUZ_y.cjs.map +1 -0
  59. package/dist/{icons-BrK5iVL8.js → icons-7dB0Y1ct.js} +20 -1
  60. package/dist/icons-7dB0Y1ct.js.map +1 -0
  61. package/dist/index.cjs +740 -171
  62. package/dist/index.cjs.map +1 -1
  63. package/dist/index.d.cts +16 -2
  64. package/dist/index.d.ts +16 -2
  65. package/dist/index.js +727 -170
  66. package/dist/index.js.map +1 -1
  67. package/dist/{it-BuP4o0xQ.cjs → it-Bef-2Yxq.cjs} +93 -1
  68. package/dist/it-Bef-2Yxq.cjs.map +1 -0
  69. package/dist/{it-Us-VmvIu.js → it-BkirG7ol.js} +93 -1
  70. package/dist/it-BkirG7ol.js.map +1 -0
  71. package/dist/{ja-Cizj0-5O.js → ja-CGEjCE-s.js} +93 -1
  72. package/dist/ja-CGEjCE-s.js.map +1 -0
  73. package/dist/{ja-DovEd6ts.cjs → ja-DNw2zqSD.cjs} +93 -1
  74. package/dist/ja-DNw2zqSD.cjs.map +1 -0
  75. package/dist/{ko-DlrXliE1.js → ko-CTkl5vMh.js} +93 -1
  76. package/dist/ko-CTkl5vMh.js.map +1 -0
  77. package/dist/{ko-B-qJEol2.cjs → ko-YHzeBqP6.cjs} +93 -1
  78. package/dist/ko-YHzeBqP6.cjs.map +1 -0
  79. package/dist/{link-editor-CSjqPnj1.cjs → link-editor-CAS7MZM2.cjs} +2 -2
  80. package/dist/{link-editor-CSjqPnj1.cjs.map → link-editor-CAS7MZM2.cjs.map} +1 -1
  81. package/dist/{link-editor-SxM1nnJU.js → link-editor-CkwtqRvb.js} +2 -2
  82. package/dist/{link-editor-SxM1nnJU.js.map → link-editor-CkwtqRvb.js.map} +1 -1
  83. package/dist/{measurement-Bs61XWbJ.js → measurement-CQdbnIrn.js} +2 -2
  84. package/dist/{measurement-Bs61XWbJ.js.map → measurement-CQdbnIrn.js.map} +1 -1
  85. package/dist/{measurement-CcCsHPOX.cjs → measurement-Cxv1Ahxx.cjs} +2 -2
  86. package/dist/{measurement-CcCsHPOX.cjs.map → measurement-Cxv1Ahxx.cjs.map} +1 -1
  87. package/dist/{nl-D3KZDDiJ.cjs → nl-BjkbaLq3.cjs} +93 -1
  88. package/dist/nl-BjkbaLq3.cjs.map +1 -0
  89. package/dist/{nl-0aF7M_0h.js → nl-Dya4sR8_.js} +93 -1
  90. package/dist/nl-Dya4sR8_.js.map +1 -0
  91. package/dist/outline-panel-BpGtBdj0.cjs +707 -0
  92. package/dist/outline-panel-BpGtBdj0.cjs.map +1 -0
  93. package/dist/outline-panel-DO5_REYw.js +707 -0
  94. package/dist/outline-panel-DO5_REYw.js.map +1 -0
  95. package/dist/outline-properties-BCa2cc0t.js +330 -0
  96. package/dist/outline-properties-BCa2cc0t.js.map +1 -0
  97. package/dist/outline-properties-DT3FIxCw.cjs +330 -0
  98. package/dist/outline-properties-DT3FIxCw.cjs.map +1 -0
  99. package/dist/{pl-DSFhAUqx.cjs → pl-CKKdVnpZ.cjs} +93 -1
  100. package/dist/pl-CKKdVnpZ.cjs.map +1 -0
  101. package/dist/{pl-BW--AaCI.js → pl-DA9b5NVg.js} +93 -1
  102. package/dist/pl-DA9b5NVg.js.map +1 -0
  103. package/dist/print-dialog-BqIrHCBh.cjs +276 -0
  104. package/dist/print-dialog-BqIrHCBh.cjs.map +1 -0
  105. package/dist/print-dialog-DvcI2m2_.js +276 -0
  106. package/dist/print-dialog-DvcI2m2_.js.map +1 -0
  107. package/dist/{pt-C5S-8MC5.cjs → pt-DLcszlzi.cjs} +93 -1
  108. package/dist/pt-DLcszlzi.cjs.map +1 -0
  109. package/dist/{pt-DIhpU5pT.js → pt-Nm8yyjbX.js} +93 -1
  110. package/dist/pt-Nm8yyjbX.js.map +1 -0
  111. package/dist/{redact-confirm-CX_SY2ZN.cjs → redact-confirm-C6EiK8yN.cjs} +2 -2
  112. package/dist/{redact-confirm-CX_SY2ZN.cjs.map → redact-confirm-C6EiK8yN.cjs.map} +1 -1
  113. package/dist/{redact-confirm-B6j36TPw.js → redact-confirm-CKuv9iN_.js} +2 -2
  114. package/dist/{redact-confirm-B6j36TPw.js.map → redact-confirm-CKuv9iN_.js.map} +1 -1
  115. package/dist/{redaction-panel-IJDshSJI.js → redaction-panel-CgNZ-pQk.js} +2 -2
  116. package/dist/{redaction-panel-IJDshSJI.js.map → redaction-panel-CgNZ-pQk.js.map} +1 -1
  117. package/dist/{redaction-panel-BmoIl-Ll.cjs → redaction-panel-ZhX0dlMi.cjs} +2 -2
  118. package/dist/{redaction-panel-BmoIl-Ll.cjs.map → redaction-panel-ZhX0dlMi.cjs.map} +1 -1
  119. package/dist/{search-panel-HfIhJm1M.js → search-panel-BE4xzWlm.js} +4 -4
  120. package/dist/{search-panel-HfIhJm1M.js.map → search-panel-BE4xzWlm.js.map} +1 -1
  121. package/dist/{search-panel-s9IoiOtv.cjs → search-panel-wcbTNG1z.cjs} +4 -4
  122. package/dist/{search-panel-s9IoiOtv.cjs.map → search-panel-wcbTNG1z.cjs.map} +1 -1
  123. package/dist/{sheet-BDsa_Sup.cjs → sheet-DTBFiwde.cjs} +30 -11
  124. package/dist/sheet-DTBFiwde.cjs.map +1 -0
  125. package/dist/{sheet-R6XDgyEf.js → sheet-DyjKfAq0.js} +25 -12
  126. package/dist/sheet-DyjKfAq0.js.map +1 -0
  127. package/dist/{sign-dialog-CgnR7akj.cjs → sign-dialog-D5WGx-Yn.cjs} +2 -2
  128. package/dist/{sign-dialog-CgnR7akj.cjs.map → sign-dialog-D5WGx-Yn.cjs.map} +1 -1
  129. package/dist/{sign-dialog-GDqCoQhA.js → sign-dialog-DerNe8qT.js} +2 -2
  130. package/dist/{sign-dialog-GDqCoQhA.js.map → sign-dialog-DerNe8qT.js.map} +1 -1
  131. package/dist/{signature-inspector-DyO313Qf.cjs → signature-inspector-Bz6TAfZM.cjs} +4 -10
  132. package/dist/signature-inspector-Bz6TAfZM.cjs.map +1 -0
  133. package/dist/{signature-inspector-okFz8do6.js → signature-inspector-CsGr9EBk.js} +4 -10
  134. package/dist/signature-inspector-CsGr9EBk.js.map +1 -0
  135. package/dist/{signature-maker-BoYa8vgA.cjs → signature-maker-D_YfBXLn.cjs} +3 -3
  136. package/dist/{signature-maker-BoYa8vgA.cjs.map → signature-maker-D_YfBXLn.cjs.map} +1 -1
  137. package/dist/{signature-maker-BhCmYyHD.js → signature-maker-Dnth4rV4.js} +3 -3
  138. package/dist/{signature-maker-BhCmYyHD.js.map → signature-maker-Dnth4rV4.js.map} +1 -1
  139. package/dist/{signatures-panel-B56PC6d9.cjs → signatures-panel-Ci_LaI1C.cjs} +4 -10
  140. package/dist/signatures-panel-Ci_LaI1C.cjs.map +1 -0
  141. package/dist/{signatures-panel-CgnFfhFm.js → signatures-panel-DZ9ywrjz.js} +4 -10
  142. package/dist/signatures-panel-DZ9ywrjz.js.map +1 -0
  143. package/dist/{stamps-panel-CDO0FPyK.js → stamps-panel-BrczStaz.js} +4 -10
  144. package/dist/stamps-panel-BrczStaz.js.map +1 -0
  145. package/dist/{stamps-panel-B9NYGayn.cjs → stamps-panel-Cv9nJBwx.cjs} +4 -10
  146. package/dist/stamps-panel-Cv9nJBwx.cjs.map +1 -0
  147. package/dist/theme-Be0OZokZ.js +97 -0
  148. package/dist/theme-Be0OZokZ.js.map +1 -0
  149. package/dist/theme-FR26JI3r.cjs +126 -0
  150. package/dist/theme-FR26JI3r.cjs.map +1 -0
  151. package/dist/{toolbar-z9od3tKl.js → toolbar-DF361xWY.js} +7 -6
  152. package/dist/toolbar-DF361xWY.js.map +1 -0
  153. package/dist/{toolbar-CJu2wKTU.cjs → toolbar-ddvpsvTb.cjs} +7 -6
  154. package/dist/toolbar-ddvpsvTb.cjs.map +1 -0
  155. package/dist/{zh-cn-CxkUUBct.js → zh-cn-BMPPkLpL.js} +93 -1
  156. package/dist/zh-cn-BMPPkLpL.js.map +1 -0
  157. package/dist/{zh-cn-3tmMeHqv.cjs → zh-cn-CZOO3p4H.cjs} +93 -1
  158. package/dist/zh-cn-CZOO3p4H.cjs.map +1 -0
  159. package/package.json +4 -4
  160. package/src/styles.css +8 -0
  161. package/dist/ar-D9XKAmDx.js.map +0 -1
  162. package/dist/ar-DnEj5vbP.cjs.map +0 -1
  163. package/dist/commands-BmgxhJ8B.js.map +0 -1
  164. package/dist/commands-CYt4SFUX.cjs.map +0 -1
  165. package/dist/de-Bdr4aWzm.js.map +0 -1
  166. package/dist/de-Dv6zvbnd.cjs.map +0 -1
  167. package/dist/dialog-B5GBisKv.js.map +0 -1
  168. package/dist/dialog-t8F13BL_.cjs.map +0 -1
  169. package/dist/es-BP09DR9w.cjs.map +0 -1
  170. package/dist/es-BSXz5tBv.js.map +0 -1
  171. package/dist/fr-BBQQn7tJ.cjs.map +0 -1
  172. package/dist/fr-Ckn3K9v1.js.map +0 -1
  173. package/dist/he-DRsG7bH7.cjs.map +0 -1
  174. package/dist/he-wdGU5PkU.js.map +0 -1
  175. package/dist/icons-BrK5iVL8.js.map +0 -1
  176. package/dist/icons-x0Tc05bs.cjs.map +0 -1
  177. package/dist/it-BuP4o0xQ.cjs.map +0 -1
  178. package/dist/it-Us-VmvIu.js.map +0 -1
  179. package/dist/ja-Cizj0-5O.js.map +0 -1
  180. package/dist/ja-DovEd6ts.cjs.map +0 -1
  181. package/dist/ko-B-qJEol2.cjs.map +0 -1
  182. package/dist/ko-DlrXliE1.js.map +0 -1
  183. package/dist/nl-0aF7M_0h.js.map +0 -1
  184. package/dist/nl-D3KZDDiJ.cjs.map +0 -1
  185. package/dist/pl-BW--AaCI.js.map +0 -1
  186. package/dist/pl-DSFhAUqx.cjs.map +0 -1
  187. package/dist/pt-C5S-8MC5.cjs.map +0 -1
  188. package/dist/pt-DIhpU5pT.js.map +0 -1
  189. package/dist/sheet-BDsa_Sup.cjs.map +0 -1
  190. package/dist/sheet-R6XDgyEf.js.map +0 -1
  191. package/dist/signature-inspector-DyO313Qf.cjs.map +0 -1
  192. package/dist/signature-inspector-okFz8do6.js.map +0 -1
  193. package/dist/signatures-panel-B56PC6d9.cjs.map +0 -1
  194. package/dist/signatures-panel-CgnFfhFm.js.map +0 -1
  195. package/dist/stamps-panel-B9NYGayn.cjs.map +0 -1
  196. package/dist/stamps-panel-CDO0FPyK.js.map +0 -1
  197. package/dist/toolbar-CJu2wKTU.cjs.map +0 -1
  198. package/dist/toolbar-z9od3tKl.js.map +0 -1
  199. package/dist/zh-cn-3tmMeHqv.cjs.map +0 -1
  200. package/dist/zh-cn-CxkUUBct.js.map +0 -1
@@ -1,10 +1,11 @@
1
- const require_icons = require("./icons-x0Tc05bs.cjs");
1
+ const require_icons = require("./icons-1UfLUZ_y.cjs");
2
2
  const require_stamp_store = require("./stamp-store-BHvRs-Do.cjs");
3
3
  let react = require("react");
4
4
  let _embedpdf_react_interaction = require("@embedpdf/react/interaction");
5
5
  let _embedpdf_react_stamp = require("@embedpdf/react/stamp");
6
6
  let _embedpdf_react_i18n = require("@embedpdf/react/i18n");
7
7
  let _embedpdf_react_shell = require("@embedpdf/react/shell");
8
+ let _embedpdf_web = require("@embedpdf/web");
8
9
  let react_jsx_runtime = require("react/jsx-runtime");
9
10
  //#region src/ui/stamps-panel.tsx
10
11
  /**
@@ -80,14 +81,7 @@ function StampsPanel() {
80
81
  * or another viewer. */
81
82
  const exportPdf = async (libraryId, name) => {
82
83
  const bytes = await stamp.exportLibrary(libraryId).catch(() => null);
83
- if (!bytes) return;
84
- const blob = new Blob([bytes], { type: "application/pdf" });
85
- const url = URL.createObjectURL(blob);
86
- const anchor = document.createElement("a");
87
- anchor.href = url;
88
- anchor.download = `${name || "stamps"}.pdf`;
89
- anchor.click();
90
- URL.revokeObjectURL(url);
84
+ if (bytes) (0, _embedpdf_web.saveFile)(bytes, `${name || "stamps"}.pdf`, "application/pdf");
91
85
  };
92
86
  const selectedId = libraries.length === 1 ? libraries[0].id : libraries.some((library) => library.id === picked) ? picked : ALL;
93
87
  const selected = selectedId === ALL ? null : libraries.find((library) => library.id === selectedId) ?? null;
@@ -228,4 +222,4 @@ function StampAssetCell({ asset, armed, onArm }) {
228
222
  //#endregion
229
223
  exports.StampsPanel = StampsPanel;
230
224
 
231
- //# sourceMappingURL=stamps-panel-B9NYGayn.cjs.map
225
+ //# sourceMappingURL=stamps-panel-Cv9nJBwx.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stamps-panel-Cv9nJBwx.cjs","names":["useStampSettings","ensureDefaultLibrary","resolveStampsLocale","DEFAULT_LIBRARY_ID","Icon"],"sources":["../src/ui/stamps-panel.tsx"],"sourcesContent":["/**\n * The stamps sidebar (right panel). The stamp plugin owns the libraries, the\n * asset bytes and the cached previews; this panel is the picker over them:\n *\n * a library <select> (\"All stamps\" + one per library, shown once there\n * are two) → a two-column grid of thumbnails → click a stamp → `armAsset`\n * arms the annotation plugin's stamp tool → hovering a page ghosts the\n * exact placement → each click on a page places one.\n *\n * Deliberately not a file dialog: picking arbitrary image bytes is the Image\n * tool's job (a click-then-pick tool, `tool:image`). The stamp button\n * opens a library; a library is a set of reusable, named assets — the two\n * gestures are different, so they are different controls.\n *\n * The panel stays open while you place, so a stamp can be dropped on several\n * pages and swapped without a round trip through the toolbar. A command can\n * open it on a library (`annotation:stamp-from-selection` → \"My stamps\")\n * through the surface's open props.\n */\nimport { useEffect, useRef, useState } from 'react';\nimport { useInteractionState } from '@embedpdf/react/interaction';\nimport {\n useStamp,\n useStampAssetPreviewUrl,\n useStampAssets,\n useStampLibraries,\n type StampAsset,\n} from '@embedpdf/react/stamp';\nimport { useSurface } from '@embedpdf/react/shell';\nimport { useI18nState, useT } from '@embedpdf/react/i18n';\nimport { saveFile } from '@embedpdf/web';\nimport { useStampSettings } from '../config-context';\nimport {\n DEFAULT_LIBRARY_ID,\n ensureDefaultLibrary,\n resolveStampsLocale,\n} from '../config/default-stamps';\nimport { Icon } from './icons';\nimport { restoreStampLibrariesOnce } from './stamp-store';\n\nconst ALL = 'all';\n\nexport function StampsPanel() {\n const t = useT();\n const stamp = useStamp();\n const { standard, sidebar } = useStampSettings();\n // Which catalogs this sidebar shows (`plugins.stamp.sidebar`): the plain stamps by\n // default — never the people's marks, which have their own panel.\n const libraries = useStampLibraries({ kind: sidebar ?? ['stamps'] });\n const assets = useStampAssets();\n const { activeToolId } = useInteractionState();\n const { locale } = useI18nState();\n const surface = useSurface('stamps');\n const fileRef = useRef<HTMLInputElement>(null);\n const [armedId, setArmedId] = useState<string | null>(null);\n const [busy, setBusy] = useState<'loading' | 'importing' | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [picked, setPicked] = useState<string>(ALL);\n\n // A command opened the panel on a library (the surface's `libraryId` prop).\n const openedOn = surface.props?.libraryId;\n useEffect(() => {\n if (typeof openedOn === 'string') setPicked(openedOn);\n }, [openedOn]);\n\n // First open: the user's stored libraries (the workspace store restores\n // them; this only awaits it), then the built-in library for this locale —\n // never at viewer boot, so a viewer whose user never opens this panel pays\n // nothing for it. A locale change while open swaps the built-in library;\n // the user's own are untouched.\n useEffect(() => {\n let live = true;\n setBusy('loading');\n restoreStampLibrariesOnce(stamp)\n .then(() => ensureDefaultLibrary(stamp, resolveStampsLocale(locale), standard))\n .catch((error: unknown) => {\n console.error('[embedpdf] default stamps failed:', error);\n if (live) setError(t('demo.stampsError'));\n })\n .finally(() => live && setBusy(null));\n return () => {\n live = false;\n };\n // `t` and `standard` are init-stable; only the locale re-runs this.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [stamp, locale]);\n\n // The interaction hub owns tool state: leaving the stamp tool (picking\n // another tool, pressing Escape) un-highlights the gallery.\n useEffect(() => {\n if (activeToolId !== 'stamp') setArmedId(null);\n }, [activeToolId]);\n\n const arm = (asset: StampAsset) => {\n setError(null);\n setArmedId(asset.id);\n void stamp.armAsset(asset.id).catch((error) => {\n console.error('[embedpdf] arm stamp failed:', error);\n setArmedId(null);\n setError(t('demo.stampsArmError'));\n });\n };\n\n const importPdf = (file: File) => {\n setError(null);\n setBusy('importing');\n // The file name is only a fallback: an Acrobat-authored or previously\n // exported library names itself through its /Title.\n stamp\n .importLibrary(file, { name: file.name.replace(/\\.pdf$/i, '') })\n .then(({ library }) => setPicked(library.id))\n .catch((error) => {\n console.error('[embedpdf] stamp library import failed:', error);\n setError(t('demo.stampsImportError'));\n })\n .finally(() => setBusy(null));\n };\n\n /** The library as the PDF it is — title, registry, artwork — for Acrobat\n * or another viewer. */\n const exportPdf = async (libraryId: string, name: string) => {\n const bytes = await stamp.exportLibrary(libraryId).catch(() => null);\n if (bytes) saveFile(bytes, `${name || 'stamps'}.pdf`, 'application/pdf');\n };\n\n // A removed library falls back to \"All\"; the picker never names a ghost.\n // One library needs no picker: it is simply the selection (so its export\n // button is reachable).\n const selectedId =\n libraries.length === 1\n ? libraries[0].id\n : libraries.some((library) => library.id === picked)\n ? picked\n : ALL;\n const selected =\n selectedId === ALL ? null : (libraries.find((library) => library.id === selectedId) ?? null);\n const shown =\n selectedId === ALL ? assets : assets.filter((asset) => asset.libraryId === selectedId);\n const isDefault = (libraryId: string) => libraryId === DEFAULT_LIBRARY_ID;\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col\">\n {libraries.length > 0 && (\n <div className=\"border-border-subtle flex items-center gap-1 border-b p-2\">\n {libraries.length > 1 ? (\n <select\n value={selectedId}\n onChange={(event) => setPicked(event.target.value)}\n aria-label={t('panels.stamps')}\n className=\"border-border bg-surface text-fg min-w-0 flex-1 rounded border px-2 py-1.5 text-sm\"\n >\n <option value={ALL}>{t('demo.stampsAll')}</option>\n {libraries.map((library) => (\n <option key={library.id} value={library.id}>\n {library.name}\n </option>\n ))}\n </select>\n ) : (\n <span className=\"text-fg-muted min-w-0 flex-1 truncate px-1 text-xs font-semibold uppercase tracking-wide\">\n {libraries[0].name}\n </span>\n )}\n {selected && (\n <>\n <button\n type=\"button\"\n onClick={() => exportPdf(selected.id, selected.name)}\n title={t('demo.stampsExportLibrary')}\n className=\"text-fg-muted hover:text-fg grid h-7 w-7 shrink-0 place-items-center rounded\"\n >\n <Icon name=\"download\" size={14} />\n </button>\n {!isDefault(selected.id) && (\n <button\n type=\"button\"\n onClick={() => void stamp.deleteLibrary(selected.id)}\n title={t('demo.stampsRemoveLibrary')}\n className=\"text-fg-muted hover:text-fg grid h-7 w-7 shrink-0 place-items-center rounded\"\n >\n <Icon name=\"trash\" size={14} />\n </button>\n )}\n </>\n )}\n </div>\n )}\n\n <div className=\"min-h-0 flex-1 overflow-y-auto p-3\">\n {busy === 'loading' && shown.length === 0 ? (\n <div className=\"flex flex-col items-center gap-3 px-4 py-10 text-center\">\n <div className=\"border-border-subtle border-t-accent h-6 w-6 animate-spin rounded-full border-2\" />\n <p className=\"text-fg-muted text-sm\">{t('demo.stampsLoading')}</p>\n </div>\n ) : shown.length === 0 ? (\n <div className=\"flex flex-col items-center gap-3 px-4 py-10 text-center\">\n <Icon name=\"rubberStamp\" size={32} className=\"text-fg-muted\" />\n <p className=\"text-fg-muted text-sm\">{t('demo.stampsEmpty')}</p>\n </div>\n ) : (\n <ul className=\"grid grid-cols-2 gap-3\">\n {shown.map((asset) => (\n <li key={asset.id} className=\"group relative\">\n <StampAssetCell\n asset={asset}\n armed={armedId === asset.id}\n onArm={() => arm(asset)}\n />\n {!isDefault(asset.libraryId) && (\n <button\n type=\"button\"\n onClick={() => void stamp.deleteAsset(asset.id)}\n title={t('demo.stampsRemoveStamp')}\n className=\"bg-surface border-border text-fg-muted hover:text-fg absolute end-1 top-1 grid h-5 w-5 place-items-center rounded-full border opacity-0 shadow-sm focus:opacity-100 group-hover:opacity-100\"\n >\n <Icon name=\"x\" size={12} />\n </button>\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n\n {(error || armedId) && (\n <div\n className={`border-border-subtle shrink-0 border-t px-3 py-2 text-xs ${\n error ? 'text-red-600' : 'text-fg-muted'\n }`}\n >\n {error ?? t('demo.stampsArmedHint')}\n </div>\n )}\n\n <div className=\"border-border-subtle shrink-0 border-t p-3\">\n <button\n type=\"button\"\n disabled={busy != null}\n onClick={() => fileRef.current?.click()}\n title={t('demo.stampsImportHint')}\n className=\"border-border text-fg hover:bg-hover flex w-full items-center justify-center gap-2 rounded-md border px-3 py-1.5 text-sm disabled:opacity-40\"\n >\n <Icon name=\"rubberStampPlus\" size={16} />\n {busy === 'importing' ? t('demo.stampsImporting') : t('demo.stampsImport')}\n </button>\n <input\n ref={fileRef}\n type=\"file\"\n accept=\"application/pdf\"\n className=\"hidden\"\n onChange={(event) => {\n const file = event.currentTarget.files?.[0];\n event.currentTarget.value = ''; // allow re-picking the same file\n if (file) importPdf(file);\n }}\n />\n </div>\n </div>\n );\n}\n\n/** One grid cell: the plugin's cached preview through the object-URL hook\n * (the DOM resource's lifetime belongs to the framework layer, not the\n * store). Image only — the artwork is the label; the label is the\n * tooltip for the curious. */\nfunction StampAssetCell({\n asset,\n armed,\n onArm,\n}: {\n asset: StampAsset;\n armed: boolean;\n onArm: () => void;\n}) {\n const url = useStampAssetPreviewUrl(asset.id);\n return (\n <button\n type=\"button\"\n onClick={onArm}\n title={asset.label}\n aria-pressed={armed}\n className={`flex aspect-square w-full items-center justify-center rounded-md border p-2 ${\n armed\n ? 'border-accent bg-accent-light ring-accent ring-2'\n : 'border-border-subtle hover:border-border hover:bg-hover'\n }`}\n >\n {url ? (\n <img src={url} alt={asset.label} className=\"max-h-full max-w-full object-contain\" />\n ) : (\n <span className=\"text-fg truncate text-sm\">{asset.label}</span>\n )}\n </button>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,97 @@
1
+ import { createContext, useContext, useEffect, useLayoutEffect, useMemo, useState } from "react";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region src/ui/theme.tsx
4
+ /**
5
+ * Light/dark theme — one class, and the CSS variables in styles.css do the
6
+ * rest (both toolbars, sidebars, popovers, and the canvas re-theme from it).
7
+ * The mode follows the embedder's `theme` preference while the viewer runs;
8
+ * `'system'` follows the OS setting, and switches when the user changes it.
9
+ * The class lands on <html> by default; a delivery that must not touch the
10
+ * page (the <embedpdf-viewer> shadow root) passes `target` and the class stays
11
+ * inside its own subtree. The theme's tokens are CSS variables too: a delivery
12
+ * applies {@link themeTokenCss} on the viewer's root.
13
+ */
14
+ /**
15
+ * The viewer's look, by name: each is the CSS variable `--epdf-<name>`, which the chrome's
16
+ * stylesheet declares with a default for each mode and mixes every other shade from.
17
+ */
18
+ const THEME_TOKENS = [
19
+ "accent",
20
+ "background",
21
+ "surface",
22
+ "surface-raised",
23
+ "text",
24
+ "text-muted",
25
+ "border",
26
+ "hover",
27
+ "canvas",
28
+ "radius",
29
+ "font"
30
+ ];
31
+ /** Normalize the shorthand — deliveries use this to read one shape. */
32
+ const themeConfigOf = (theme) => typeof theme === "string" ? { preference: theme } : theme ?? {};
33
+ const isThemeToken = (name) => THEME_TOKENS.includes(name);
34
+ /** The declarations of `tokens` that are tokens with a CSS value; each other entry warns. */
35
+ function tokenDeclarations(tokens) {
36
+ return Object.entries(tokens).filter(([name, value]) => {
37
+ if (value === void 0) return false;
38
+ if (!isThemeToken(name)) {
39
+ console.warn(`[embedpdf] theme: "${name}" isn't a token, ignored`);
40
+ return false;
41
+ }
42
+ if (typeof value !== "string" || /[{};]/.test(value)) {
43
+ console.warn(`[embedpdf] theme: ignoring the invalid value of "${name}"`);
44
+ return false;
45
+ }
46
+ return true;
47
+ }).map(([name, value]) => `--epdf-${name}:var(--embedpdf-host-${name},${value});`).join("");
48
+ }
49
+ /**
50
+ * The CSS that applies a theme's tokens on the viewer's root (`root`, a selector), for a sheet
51
+ * after the chrome's: its tokens win over the defaults in both modes by coming later, and its
52
+ * dark ones win in dark by naming the class too. A value is a default only: the page's own
53
+ * `--epdf-*` variable still wins, read on the host as the chrome's stylesheet does. Empty when
54
+ * the theme sets no token.
55
+ */
56
+ function themeTokenCss(theme, root) {
57
+ const { accent, tokens, dark } = themeConfigOf(theme);
58
+ const both = tokenDeclarations({
59
+ ...accent === void 0 ? null : { accent },
60
+ ...tokens
61
+ });
62
+ const darkOnly = dark ? tokenDeclarations(dark) : "";
63
+ return (both ? `${root}{${both}}` : "") + (darkOnly ? `${root}.dark{${darkOnly}}` : "");
64
+ }
65
+ const ThemeCtx = createContext(null);
66
+ const DARK_QUERY = "(prefers-color-scheme: dark)";
67
+ const systemMode = () => typeof window !== "undefined" && window.matchMedia?.(DARK_QUERY).matches ? "dark" : "light";
68
+ function ThemeProvider({ children, preference = "system", target }) {
69
+ const [system, setSystem] = useState(systemMode);
70
+ useEffect(() => {
71
+ if (preference !== "system" || typeof window === "undefined" || !window.matchMedia) return;
72
+ const query = window.matchMedia(DARK_QUERY);
73
+ const follow = () => setSystem(query.matches ? "dark" : "light");
74
+ follow();
75
+ query.addEventListener("change", follow);
76
+ return () => query.removeEventListener("change", follow);
77
+ }, [preference]);
78
+ const mode = preference === "system" ? system : preference;
79
+ useLayoutEffect(() => {
80
+ (target ?? document.documentElement).classList.toggle("dark", mode === "dark");
81
+ }, [mode, target]);
82
+ const value = useMemo(() => ({ mode }), [mode]);
83
+ return /* @__PURE__ */ jsx(ThemeCtx.Provider, {
84
+ value,
85
+ children
86
+ });
87
+ }
88
+ /** The mode the viewer shows now. */
89
+ function useTheme() {
90
+ const ctx = useContext(ThemeCtx);
91
+ if (!ctx) throw new Error("useTheme must be used within <ThemeProvider>");
92
+ return ctx;
93
+ }
94
+ //#endregion
95
+ export { useTheme as a, themeTokenCss as i, ThemeProvider as n, themeConfigOf as r, THEME_TOKENS as t };
96
+
97
+ //# sourceMappingURL=theme-Be0OZokZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-Be0OZokZ.js","names":[],"sources":["../src/ui/theme.tsx"],"sourcesContent":["/**\n * Light/dark theme — one class, and the CSS variables in styles.css do the\n * rest (both toolbars, sidebars, popovers, and the canvas re-theme from it).\n * The mode follows the embedder's `theme` preference while the viewer runs;\n * `'system'` follows the OS setting, and switches when the user changes it.\n * The class lands on <html> by default; a delivery that must not touch the\n * page (the <embedpdf-viewer> shadow root) passes `target` and the class stays\n * inside its own subtree. The theme's tokens are CSS variables too: a delivery\n * applies {@link themeTokenCss} on the viewer's root.\n */\nimport { createContext, useContext, useEffect, useLayoutEffect, useMemo, useState } from 'react';\n\nexport type ThemeMode = 'light' | 'dark';\nexport type ThemePreference = ThemeMode | 'system';\n\n// ── tokens ───────────────────────────────────────────────────────────────────\n\n/**\n * The viewer's look, by name: each is the CSS variable `--epdf-<name>`, which the chrome's\n * stylesheet declares with a default for each mode and mixes every other shade from.\n */\nexport const THEME_TOKENS = [\n 'accent',\n 'background',\n 'surface',\n 'surface-raised',\n 'text',\n 'text-muted',\n 'border',\n 'hover',\n 'canvas',\n 'radius',\n 'font',\n] as const;\n\n/** A token's name: `surface` is the CSS variable `--epdf-surface`. */\nexport type ThemeToken = (typeof THEME_TOKENS)[number];\n\n/** Token values by name, each a CSS value: `{ surface: '#fbfaf7', radius: '2px' }`. */\nexport type ThemeTokens = { readonly [Name in ThemeToken]?: string };\n\nexport interface ThemeConfig {\n /** 'system' (default) follows the OS. */\n preference?: ThemePreference;\n /** The accent color in both modes: the same as `tokens.accent`, which wins when both are set. */\n accent?: string;\n /** Token values for both modes, over the viewer's defaults. */\n tokens?: ThemeTokens;\n /** Token values for dark mode only, over `tokens`. */\n dark?: ThemeTokens;\n}\n\n/** Normalize the shorthand — deliveries use this to read one shape. */\nexport const themeConfigOf = (theme: ThemePreference | ThemeConfig | undefined): ThemeConfig =>\n typeof theme === 'string' ? { preference: theme } : (theme ?? {});\n\nconst isThemeToken = (name: string): name is ThemeToken =>\n (THEME_TOKENS as readonly string[]).includes(name);\n\n/** The declarations of `tokens` that are tokens with a CSS value; each other entry warns. */\nfunction tokenDeclarations(tokens: ThemeTokens): string {\n return Object.entries(tokens)\n .filter(([name, value]) => {\n if (value === undefined) return false;\n if (!isThemeToken(name)) {\n console.warn(`[embedpdf] theme: \"${name}\" isn't a token, ignored`);\n return false;\n }\n if (typeof value !== 'string' || /[{};]/.test(value)) {\n console.warn(`[embedpdf] theme: ignoring the invalid value of \"${name}\"`);\n return false;\n }\n return true;\n })\n .map(([name, value]) => `--epdf-${name}:var(--embedpdf-host-${name},${value});`)\n .join('');\n}\n\n/**\n * The CSS that applies a theme's tokens on the viewer's root (`root`, a selector), for a sheet\n * after the chrome's: its tokens win over the defaults in both modes by coming later, and its\n * dark ones win in dark by naming the class too. A value is a default only: the page's own\n * `--epdf-*` variable still wins, read on the host as the chrome's stylesheet does. Empty when\n * the theme sets no token.\n */\nexport function themeTokenCss(theme: ThemePreference | ThemeConfig | undefined, root: string) {\n const { accent, tokens, dark } = themeConfigOf(theme);\n const both = tokenDeclarations({ ...(accent === undefined ? null : { accent }), ...tokens });\n const darkOnly = dark ? tokenDeclarations(dark) : '';\n return (both ? `${root}{${both}}` : '') + (darkOnly ? `${root}.dark{${darkOnly}}` : '');\n}\n\nconst ThemeCtx = createContext<{ mode: ThemeMode } | null>(null);\n\nconst DARK_QUERY = '(prefers-color-scheme: dark)';\n\nconst systemMode = (): ThemeMode =>\n typeof window !== 'undefined' && window.matchMedia?.(DARK_QUERY).matches ? 'dark' : 'light';\n\nexport function ThemeProvider({\n children,\n preference = 'system',\n target,\n}: {\n children: React.ReactNode;\n /** The mode, or 'system' (default) to follow the OS setting. */\n preference?: ThemePreference;\n /** Where the `.dark` class goes. Default: document.documentElement. */\n target?: HTMLElement | null;\n}) {\n const [system, setSystem] = useState<ThemeMode>(systemMode);\n useEffect(() => {\n if (preference !== 'system' || typeof window === 'undefined' || !window.matchMedia) return;\n const query = window.matchMedia(DARK_QUERY);\n const follow = () => setSystem(query.matches ? 'dark' : 'light');\n follow();\n query.addEventListener('change', follow);\n return () => query.removeEventListener('change', follow);\n }, [preference]);\n const mode = preference === 'system' ? system : preference;\n // Before the paint, so the viewer never shows a frame in the other mode.\n useLayoutEffect(() => {\n (target ?? document.documentElement).classList.toggle('dark', mode === 'dark');\n }, [mode, target]);\n const value = useMemo(() => ({ mode }), [mode]);\n return <ThemeCtx.Provider value={value}>{children}</ThemeCtx.Provider>;\n}\n\n/** The mode the viewer shows now. */\nexport function useTheme() {\n const ctx = useContext(ThemeCtx);\n if (!ctx) throw new Error('useTheme must be used within <ThemeProvider>');\n return ctx;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAqBA,MAAa,eAAe;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAoBA,MAAa,iBAAiB,UAC5B,OAAO,UAAU,WAAW,EAAE,YAAY,MAAM,IAAK,SAAS,CAAC;AAEjE,MAAM,gBAAgB,SACnB,aAAmC,SAAS,IAAI;;AAGnD,SAAS,kBAAkB,QAA6B;CACtD,OAAO,OAAO,QAAQ,MAAM,CAAC,CAC1B,QAAQ,CAAC,MAAM,WAAW;EACzB,IAAI,UAAU,KAAA,GAAW,OAAO;EAChC,IAAI,CAAC,aAAa,IAAI,GAAG;GACvB,QAAQ,KAAK,sBAAsB,KAAK,yBAAyB;GACjE,OAAO;EACT;EACA,IAAI,OAAO,UAAU,YAAY,QAAQ,KAAK,KAAK,GAAG;GACpD,QAAQ,KAAK,oDAAoD,KAAK,EAAE;GACxE,OAAO;EACT;EACA,OAAO;CACT,CAAC,CAAC,CACD,KAAK,CAAC,MAAM,WAAW,UAAU,KAAK,uBAAuB,KAAK,GAAG,MAAM,GAAG,CAAC,CAC/E,KAAK,EAAE;AACZ;;;;;;;;AASA,SAAgB,cAAc,OAAkD,MAAc;CAC5F,MAAM,EAAE,QAAQ,QAAQ,SAAS,cAAc,KAAK;CACpD,MAAM,OAAO,kBAAkB;EAAE,GAAI,WAAW,KAAA,IAAY,OAAO,EAAE,OAAO;EAAI,GAAG;CAAO,CAAC;CAC3F,MAAM,WAAW,OAAO,kBAAkB,IAAI,IAAI;CAClD,QAAQ,OAAO,GAAG,KAAK,GAAG,KAAK,KAAK,OAAO,WAAW,GAAG,KAAK,QAAQ,SAAS,KAAK;AACtF;AAEA,MAAM,WAAW,cAA0C,IAAI;AAE/D,MAAM,aAAa;AAEnB,MAAM,mBACJ,OAAO,WAAW,eAAe,OAAO,aAAa,UAAU,CAAC,CAAC,UAAU,SAAS;AAEtF,SAAgB,cAAc,EAC5B,UACA,aAAa,UACb,UAOC;CACD,MAAM,CAAC,QAAQ,aAAa,SAAoB,UAAU;CAC1D,gBAAgB;EACd,IAAI,eAAe,YAAY,OAAO,WAAW,eAAe,CAAC,OAAO,YAAY;EACpF,MAAM,QAAQ,OAAO,WAAW,UAAU;EAC1C,MAAM,eAAe,UAAU,MAAM,UAAU,SAAS,OAAO;EAC/D,OAAO;EACP,MAAM,iBAAiB,UAAU,MAAM;EACvC,aAAa,MAAM,oBAAoB,UAAU,MAAM;CACzD,GAAG,CAAC,UAAU,CAAC;CACf,MAAM,OAAO,eAAe,WAAW,SAAS;CAEhD,sBAAsB;EACpB,CAAC,UAAU,SAAS,gBAAA,CAAiB,UAAU,OAAO,QAAQ,SAAS,MAAM;CAC/E,GAAG,CAAC,MAAM,MAAM,CAAC;CACjB,MAAM,QAAQ,eAAe,EAAE,KAAK,IAAI,CAAC,IAAI,CAAC;CAC9C,OAAO,oBAAC,SAAS,UAAV;EAA0B;EAAQ;CAA4B,CAAA;AACvE;;AAGA,SAAgB,WAAW;CACzB,MAAM,MAAM,WAAW,QAAQ;CAC/B,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,8CAA8C;CACxE,OAAO;AACT"}
@@ -0,0 +1,126 @@
1
+ let react = require("react");
2
+ let react_jsx_runtime = require("react/jsx-runtime");
3
+ //#region src/ui/theme.tsx
4
+ /**
5
+ * Light/dark theme — one class, and the CSS variables in styles.css do the
6
+ * rest (both toolbars, sidebars, popovers, and the canvas re-theme from it).
7
+ * The mode follows the embedder's `theme` preference while the viewer runs;
8
+ * `'system'` follows the OS setting, and switches when the user changes it.
9
+ * The class lands on <html> by default; a delivery that must not touch the
10
+ * page (the <embedpdf-viewer> shadow root) passes `target` and the class stays
11
+ * inside its own subtree. The theme's tokens are CSS variables too: a delivery
12
+ * applies {@link themeTokenCss} on the viewer's root.
13
+ */
14
+ /**
15
+ * The viewer's look, by name: each is the CSS variable `--epdf-<name>`, which the chrome's
16
+ * stylesheet declares with a default for each mode and mixes every other shade from.
17
+ */
18
+ const THEME_TOKENS = [
19
+ "accent",
20
+ "background",
21
+ "surface",
22
+ "surface-raised",
23
+ "text",
24
+ "text-muted",
25
+ "border",
26
+ "hover",
27
+ "canvas",
28
+ "radius",
29
+ "font"
30
+ ];
31
+ /** Normalize the shorthand — deliveries use this to read one shape. */
32
+ const themeConfigOf = (theme) => typeof theme === "string" ? { preference: theme } : theme ?? {};
33
+ const isThemeToken = (name) => THEME_TOKENS.includes(name);
34
+ /** The declarations of `tokens` that are tokens with a CSS value; each other entry warns. */
35
+ function tokenDeclarations(tokens) {
36
+ return Object.entries(tokens).filter(([name, value]) => {
37
+ if (value === void 0) return false;
38
+ if (!isThemeToken(name)) {
39
+ console.warn(`[embedpdf] theme: "${name}" isn't a token, ignored`);
40
+ return false;
41
+ }
42
+ if (typeof value !== "string" || /[{};]/.test(value)) {
43
+ console.warn(`[embedpdf] theme: ignoring the invalid value of "${name}"`);
44
+ return false;
45
+ }
46
+ return true;
47
+ }).map(([name, value]) => `--epdf-${name}:var(--embedpdf-host-${name},${value});`).join("");
48
+ }
49
+ /**
50
+ * The CSS that applies a theme's tokens on the viewer's root (`root`, a selector), for a sheet
51
+ * after the chrome's: its tokens win over the defaults in both modes by coming later, and its
52
+ * dark ones win in dark by naming the class too. A value is a default only: the page's own
53
+ * `--epdf-*` variable still wins, read on the host as the chrome's stylesheet does. Empty when
54
+ * the theme sets no token.
55
+ */
56
+ function themeTokenCss(theme, root) {
57
+ const { accent, tokens, dark } = themeConfigOf(theme);
58
+ const both = tokenDeclarations({
59
+ ...accent === void 0 ? null : { accent },
60
+ ...tokens
61
+ });
62
+ const darkOnly = dark ? tokenDeclarations(dark) : "";
63
+ return (both ? `${root}{${both}}` : "") + (darkOnly ? `${root}.dark{${darkOnly}}` : "");
64
+ }
65
+ const ThemeCtx = (0, react.createContext)(null);
66
+ const DARK_QUERY = "(prefers-color-scheme: dark)";
67
+ const systemMode = () => typeof window !== "undefined" && window.matchMedia?.(DARK_QUERY).matches ? "dark" : "light";
68
+ function ThemeProvider({ children, preference = "system", target }) {
69
+ const [system, setSystem] = (0, react.useState)(systemMode);
70
+ (0, react.useEffect)(() => {
71
+ if (preference !== "system" || typeof window === "undefined" || !window.matchMedia) return;
72
+ const query = window.matchMedia(DARK_QUERY);
73
+ const follow = () => setSystem(query.matches ? "dark" : "light");
74
+ follow();
75
+ query.addEventListener("change", follow);
76
+ return () => query.removeEventListener("change", follow);
77
+ }, [preference]);
78
+ const mode = preference === "system" ? system : preference;
79
+ (0, react.useLayoutEffect)(() => {
80
+ (target ?? document.documentElement).classList.toggle("dark", mode === "dark");
81
+ }, [mode, target]);
82
+ const value = (0, react.useMemo)(() => ({ mode }), [mode]);
83
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThemeCtx.Provider, {
84
+ value,
85
+ children
86
+ });
87
+ }
88
+ /** The mode the viewer shows now. */
89
+ function useTheme() {
90
+ const ctx = (0, react.useContext)(ThemeCtx);
91
+ if (!ctx) throw new Error("useTheme must be used within <ThemeProvider>");
92
+ return ctx;
93
+ }
94
+ //#endregion
95
+ Object.defineProperty(exports, "THEME_TOKENS", {
96
+ enumerable: true,
97
+ get: function() {
98
+ return THEME_TOKENS;
99
+ }
100
+ });
101
+ Object.defineProperty(exports, "ThemeProvider", {
102
+ enumerable: true,
103
+ get: function() {
104
+ return ThemeProvider;
105
+ }
106
+ });
107
+ Object.defineProperty(exports, "themeConfigOf", {
108
+ enumerable: true,
109
+ get: function() {
110
+ return themeConfigOf;
111
+ }
112
+ });
113
+ Object.defineProperty(exports, "themeTokenCss", {
114
+ enumerable: true,
115
+ get: function() {
116
+ return themeTokenCss;
117
+ }
118
+ });
119
+ Object.defineProperty(exports, "useTheme", {
120
+ enumerable: true,
121
+ get: function() {
122
+ return useTheme;
123
+ }
124
+ });
125
+
126
+ //# sourceMappingURL=theme-FR26JI3r.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-FR26JI3r.cjs","names":[],"sources":["../src/ui/theme.tsx"],"sourcesContent":["/**\n * Light/dark theme — one class, and the CSS variables in styles.css do the\n * rest (both toolbars, sidebars, popovers, and the canvas re-theme from it).\n * The mode follows the embedder's `theme` preference while the viewer runs;\n * `'system'` follows the OS setting, and switches when the user changes it.\n * The class lands on <html> by default; a delivery that must not touch the\n * page (the <embedpdf-viewer> shadow root) passes `target` and the class stays\n * inside its own subtree. The theme's tokens are CSS variables too: a delivery\n * applies {@link themeTokenCss} on the viewer's root.\n */\nimport { createContext, useContext, useEffect, useLayoutEffect, useMemo, useState } from 'react';\n\nexport type ThemeMode = 'light' | 'dark';\nexport type ThemePreference = ThemeMode | 'system';\n\n// ── tokens ───────────────────────────────────────────────────────────────────\n\n/**\n * The viewer's look, by name: each is the CSS variable `--epdf-<name>`, which the chrome's\n * stylesheet declares with a default for each mode and mixes every other shade from.\n */\nexport const THEME_TOKENS = [\n 'accent',\n 'background',\n 'surface',\n 'surface-raised',\n 'text',\n 'text-muted',\n 'border',\n 'hover',\n 'canvas',\n 'radius',\n 'font',\n] as const;\n\n/** A token's name: `surface` is the CSS variable `--epdf-surface`. */\nexport type ThemeToken = (typeof THEME_TOKENS)[number];\n\n/** Token values by name, each a CSS value: `{ surface: '#fbfaf7', radius: '2px' }`. */\nexport type ThemeTokens = { readonly [Name in ThemeToken]?: string };\n\nexport interface ThemeConfig {\n /** 'system' (default) follows the OS. */\n preference?: ThemePreference;\n /** The accent color in both modes: the same as `tokens.accent`, which wins when both are set. */\n accent?: string;\n /** Token values for both modes, over the viewer's defaults. */\n tokens?: ThemeTokens;\n /** Token values for dark mode only, over `tokens`. */\n dark?: ThemeTokens;\n}\n\n/** Normalize the shorthand — deliveries use this to read one shape. */\nexport const themeConfigOf = (theme: ThemePreference | ThemeConfig | undefined): ThemeConfig =>\n typeof theme === 'string' ? { preference: theme } : (theme ?? {});\n\nconst isThemeToken = (name: string): name is ThemeToken =>\n (THEME_TOKENS as readonly string[]).includes(name);\n\n/** The declarations of `tokens` that are tokens with a CSS value; each other entry warns. */\nfunction tokenDeclarations(tokens: ThemeTokens): string {\n return Object.entries(tokens)\n .filter(([name, value]) => {\n if (value === undefined) return false;\n if (!isThemeToken(name)) {\n console.warn(`[embedpdf] theme: \"${name}\" isn't a token, ignored`);\n return false;\n }\n if (typeof value !== 'string' || /[{};]/.test(value)) {\n console.warn(`[embedpdf] theme: ignoring the invalid value of \"${name}\"`);\n return false;\n }\n return true;\n })\n .map(([name, value]) => `--epdf-${name}:var(--embedpdf-host-${name},${value});`)\n .join('');\n}\n\n/**\n * The CSS that applies a theme's tokens on the viewer's root (`root`, a selector), for a sheet\n * after the chrome's: its tokens win over the defaults in both modes by coming later, and its\n * dark ones win in dark by naming the class too. A value is a default only: the page's own\n * `--epdf-*` variable still wins, read on the host as the chrome's stylesheet does. Empty when\n * the theme sets no token.\n */\nexport function themeTokenCss(theme: ThemePreference | ThemeConfig | undefined, root: string) {\n const { accent, tokens, dark } = themeConfigOf(theme);\n const both = tokenDeclarations({ ...(accent === undefined ? null : { accent }), ...tokens });\n const darkOnly = dark ? tokenDeclarations(dark) : '';\n return (both ? `${root}{${both}}` : '') + (darkOnly ? `${root}.dark{${darkOnly}}` : '');\n}\n\nconst ThemeCtx = createContext<{ mode: ThemeMode } | null>(null);\n\nconst DARK_QUERY = '(prefers-color-scheme: dark)';\n\nconst systemMode = (): ThemeMode =>\n typeof window !== 'undefined' && window.matchMedia?.(DARK_QUERY).matches ? 'dark' : 'light';\n\nexport function ThemeProvider({\n children,\n preference = 'system',\n target,\n}: {\n children: React.ReactNode;\n /** The mode, or 'system' (default) to follow the OS setting. */\n preference?: ThemePreference;\n /** Where the `.dark` class goes. Default: document.documentElement. */\n target?: HTMLElement | null;\n}) {\n const [system, setSystem] = useState<ThemeMode>(systemMode);\n useEffect(() => {\n if (preference !== 'system' || typeof window === 'undefined' || !window.matchMedia) return;\n const query = window.matchMedia(DARK_QUERY);\n const follow = () => setSystem(query.matches ? 'dark' : 'light');\n follow();\n query.addEventListener('change', follow);\n return () => query.removeEventListener('change', follow);\n }, [preference]);\n const mode = preference === 'system' ? system : preference;\n // Before the paint, so the viewer never shows a frame in the other mode.\n useLayoutEffect(() => {\n (target ?? document.documentElement).classList.toggle('dark', mode === 'dark');\n }, [mode, target]);\n const value = useMemo(() => ({ mode }), [mode]);\n return <ThemeCtx.Provider value={value}>{children}</ThemeCtx.Provider>;\n}\n\n/** The mode the viewer shows now. */\nexport function useTheme() {\n const ctx = useContext(ThemeCtx);\n if (!ctx) throw new Error('useTheme must be used within <ThemeProvider>');\n return ctx;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAqBA,MAAa,eAAe;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAoBA,MAAa,iBAAiB,UAC5B,OAAO,UAAU,WAAW,EAAE,YAAY,MAAM,IAAK,SAAS,CAAC;AAEjE,MAAM,gBAAgB,SACnB,aAAmC,SAAS,IAAI;;AAGnD,SAAS,kBAAkB,QAA6B;CACtD,OAAO,OAAO,QAAQ,MAAM,CAAC,CAC1B,QAAQ,CAAC,MAAM,WAAW;EACzB,IAAI,UAAU,KAAA,GAAW,OAAO;EAChC,IAAI,CAAC,aAAa,IAAI,GAAG;GACvB,QAAQ,KAAK,sBAAsB,KAAK,yBAAyB;GACjE,OAAO;EACT;EACA,IAAI,OAAO,UAAU,YAAY,QAAQ,KAAK,KAAK,GAAG;GACpD,QAAQ,KAAK,oDAAoD,KAAK,EAAE;GACxE,OAAO;EACT;EACA,OAAO;CACT,CAAC,CAAC,CACD,KAAK,CAAC,MAAM,WAAW,UAAU,KAAK,uBAAuB,KAAK,GAAG,MAAM,GAAG,CAAC,CAC/E,KAAK,EAAE;AACZ;;;;;;;;AASA,SAAgB,cAAc,OAAkD,MAAc;CAC5F,MAAM,EAAE,QAAQ,QAAQ,SAAS,cAAc,KAAK;CACpD,MAAM,OAAO,kBAAkB;EAAE,GAAI,WAAW,KAAA,IAAY,OAAO,EAAE,OAAO;EAAI,GAAG;CAAO,CAAC;CAC3F,MAAM,WAAW,OAAO,kBAAkB,IAAI,IAAI;CAClD,QAAQ,OAAO,GAAG,KAAK,GAAG,KAAK,KAAK,OAAO,WAAW,GAAG,KAAK,QAAQ,SAAS,KAAK;AACtF;AAEA,MAAM,YAAA,GAAA,MAAA,cAAA,CAAqD,IAAI;AAE/D,MAAM,aAAa;AAEnB,MAAM,mBACJ,OAAO,WAAW,eAAe,OAAO,aAAa,UAAU,CAAC,CAAC,UAAU,SAAS;AAEtF,SAAgB,cAAc,EAC5B,UACA,aAAa,UACb,UAOC;CACD,MAAM,CAAC,QAAQ,cAAA,GAAA,MAAA,SAAA,CAAiC,UAAU;CAC1D,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,IAAI,eAAe,YAAY,OAAO,WAAW,eAAe,CAAC,OAAO,YAAY;EACpF,MAAM,QAAQ,OAAO,WAAW,UAAU;EAC1C,MAAM,eAAe,UAAU,MAAM,UAAU,SAAS,OAAO;EAC/D,OAAO;EACP,MAAM,iBAAiB,UAAU,MAAM;EACvC,aAAa,MAAM,oBAAoB,UAAU,MAAM;CACzD,GAAG,CAAC,UAAU,CAAC;CACf,MAAM,OAAO,eAAe,WAAW,SAAS;CAEhD,CAAA,GAAA,MAAA,gBAAA,OAAsB;EACpB,CAAC,UAAU,SAAS,gBAAA,CAAiB,UAAU,OAAO,QAAQ,SAAS,MAAM;CAC/E,GAAG,CAAC,MAAM,MAAM,CAAC;CACjB,MAAM,SAAA,GAAA,MAAA,QAAA,QAAuB,EAAE,KAAK,IAAI,CAAC,IAAI,CAAC;CAC9C,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAS,UAAV;EAA0B;EAAQ;CAA4B,CAAA;AACvE;;AAGA,SAAgB,WAAW;CACzB,MAAM,OAAA,GAAA,MAAA,WAAA,CAAiB,QAAQ;CAC/B,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,8CAA8C;CACxE,OAAO;AACT"}
@@ -1,5 +1,5 @@
1
- import { _ as useStampSettings, d as useLayoutEnv, n as Icon, p as useMenu } from "./icons-BrK5iVL8.js";
2
- import { r as Sheet } from "./sheet-R6XDgyEf.js";
1
+ import { _ as useStampSettings, d as useLayoutEnv, n as Icon, p as useMenu } from "./icons-7dB0Y1ct.js";
2
+ import { r as Sheet } from "./sheet-DyjKfAq0.js";
3
3
  import { a as quickStampAssetIdOf, i as ensureDefaultLibrary, n as restoreStampLibrariesOnce, o as resolveStampsLocale, r as DEFAULT_LIBRARY_ID } from "./stamp-store-WuF-L3Jj.js";
4
4
  import { createContext, useContext, useEffect, useId, useLayoutEffect, useReducer, useRef, useState } from "react";
5
5
  import { useDocumentId, useKernelValue, useOptionalCapability, useOptionalSelector, useSelector } from "@embedpdf/react/runtime";
@@ -42,7 +42,7 @@ const FEATURE_PARTS = {
42
42
  text: ["selection", "copy"],
43
43
  search: [],
44
44
  thumbnails: [],
45
- outline: [],
45
+ outline: ["editing"],
46
46
  documents: [
47
47
  "open",
48
48
  "download",
@@ -61,7 +61,8 @@ const READ_ONLY_FEATURES = [
61
61
  "redaction",
62
62
  "measurement",
63
63
  "pages",
64
- "attachments.adding"
64
+ "attachments.adding",
65
+ "outline.editing"
65
66
  ];
66
67
  const isInside = (feature, outer) => feature === outer || feature.startsWith(`${outer}.`);
67
68
  /**
@@ -247,7 +248,7 @@ function PageNumber() {
247
248
  /** Whether the field closed from the keyboard, so focus goes back to the number. */
248
249
  const refocus = useRef(false);
249
250
  const editing = draft !== null;
250
- useEffect(() => {
251
+ useLayoutEffect(() => {
251
252
  if (editing) {
252
253
  field.current?.focus();
253
254
  field.current?.select();
@@ -1561,4 +1562,4 @@ function AppToolbar({ bar, orientation = "horizontal", className }) {
1561
1562
  //#endregion
1562
1563
  export { MenuAnchor as a, SlottedEdgesProvider as c, TOOLBAR_ITEM_CONTEXT_ATTRIBUTES as d, BarEdgeProvider as f, sameByHand as g, disabledSettingsOf as h, buttonPart as i, createSlottedEdges as l, byHandSettingsOf as m, CommandButton as n, MenuItem as o, bothAllow as p, buttonClass as r, MenuPopover as s, AppToolbar as t, useSlottedEdges as u };
1563
1564
 
1564
- //# sourceMappingURL=toolbar-z9od3tKl.js.map
1565
+ //# sourceMappingURL=toolbar-DF361xWY.js.map