@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
package/dist/index.js CHANGED
@@ -1,17 +1,20 @@
1
- import { _ as openModeSurfaceOf, c as defaultCommands, d as toolCommandsFor, f as OPEN_COMMAND_ID, g as modeSpecsOf, h as modeCommandsFor, m as mayCarryPdf, o as SHORTCUTS_DIALOG, p as isPdfFile, r as GO_TO_PAGE_DIALOG, s as TOOL_ICONS, v as sameModeSpecs } from "./commands-BmgxhJ8B.js";
2
- import { a as DEFAULT_ENV, b as resolveViewerCommands, c as stripOf, d as useLayoutEnv, f as useLayoutOption, h as useResolvedLayout, i as iconPathsOf, m as usePanelResize, n as Icon, o as ResolvedLayoutProvider, r as hasIcon, s as ViewerConfigProvider, t as ICON_PATHS, u as useCustomIcons, v as useStripSchema, y as useViewerCommands } from "./icons-BrK5iVL8.js";
1
+ import { _ as mayCarryPdf, b as openModeSurfaceOf, c as TOOL_ICONS, f as toolCommandsFor, g as isPdfFile, h as OPEN_COMMAND_ID, l as defaultCommands, p as OUTLINE_PROPERTIES_DIALOG, r as GO_TO_PAGE_DIALOG, s as SHORTCUTS_DIALOG, v as modeCommandsFor, x as sameModeSpecs, y as modeSpecsOf } from "./commands-BkgLP3Om.js";
2
+ import { a as DEFAULT_ENV, b as resolveViewerCommands, c as stripOf, d as useLayoutEnv, f as useLayoutOption, h as useResolvedLayout, i as iconPathsOf, m as usePanelResize, n as Icon, o as ResolvedLayoutProvider, r as hasIcon, s as ViewerConfigProvider, t as ICON_PATHS, u as useCustomIcons, v as useStripSchema, y as useViewerCommands } from "./icons-7dB0Y1ct.js";
3
3
  import { defaultLayout } from "./chrome.js";
4
- import { a as MenuAnchor, c as SlottedEdgesProvider, d as TOOLBAR_ITEM_CONTEXT_ATTRIBUTES, f as BarEdgeProvider, g as sameByHand, h as disabledSettingsOf, i as buttonPart, l as createSlottedEdges, m as byHandSettingsOf, n as CommandButton, o as MenuItem, p as bothAllow, r as buttonClass, s as MenuPopover, t as AppToolbar, u as useSlottedEdges } from "./toolbar-z9od3tKl.js";
5
- import { a as FOCUS_ROOT_ATTRIBUTE, c as holdFocus, d as sameScreenEdges, f as screenEdgesOf, i as useCloseOnPick, l as NO_SCREEN_EDGES, n as SCRIM_CLASS, p as windowSizeOf, r as Sheet, t as CloseOnPickProvider, u as safeAreaPaddingOf } from "./sheet-R6XDgyEf.js";
4
+ import { a as MenuAnchor, c as SlottedEdgesProvider, d as TOOLBAR_ITEM_CONTEXT_ATTRIBUTES, f as BarEdgeProvider, g as sameByHand, h as disabledSettingsOf, i as buttonPart, l as createSlottedEdges, m as byHandSettingsOf, n as CommandButton, o as MenuItem, p as bothAllow, r as buttonClass, s as MenuPopover, t as AppToolbar, u as useSlottedEdges } from "./toolbar-DF361xWY.js";
5
+ import { i as themeTokenCss, n as ThemeProvider, r as themeConfigOf, t as THEME_TOKENS } from "./theme-Be0OZokZ.js";
6
+ import { a as FOCUS_ROOT_ATTRIBUTE, d as safeAreaPaddingOf, f as sameScreenEdges, i as useCloseOnPick, l as holdFocus, m as windowSizeOf, n as SCRIM_CLASS, p as screenEdgesOf, r as Sheet, t as CloseOnPickProvider, u as NO_SCREEN_EDGES } from "./sheet-DyjKfAq0.js";
6
7
  import { t as StampLibraryStore } from "./stamp-store-WuF-L3Jj.js";
7
- import { t as AnnotationFontsProvider } from "./annotation-fonts-BqoLZ4Mp.js";
8
- import { t as Dialog } from "./dialog-B5GBisKv.js";
9
- import { Fragment, Suspense, createContext, lazy, useCallback, useEffect, useId, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
10
- import { DocumentGate, DocumentsToken, DocumentsToken as DocumentsToken$1, PluginError, Viewer, createCapabilityToken, isReadMember, mergeSettings, useDocument, useDocumentId, useDocuments, useDocumentsState, useKernel, useKernelValue, useOptionalCapability, useOptionalSelector } from "@embedpdf/react/runtime";
8
+ import { t as AnnotationFontsProvider } from "./annotation-fonts-DWjVOTP0.js";
9
+ import { t as Dialog } from "./dialog-BIb373cg.js";
10
+ import { Fragment, Suspense, lazy, useCallback, useEffect, useId, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
11
+ import { DocumentGate, DocumentsToken, DocumentsToken as DocumentsToken$1, PluginError, Viewer, createCapabilityToken, isReadMember, mergeSettings, toPageRef, useDocument, useDocumentId, useDocuments, useDocumentsState, useKernel, useKernelValue, useOptionalCapability, useOptionalSelector, usePageList } from "@embedpdf/react/runtime";
11
12
  import { Scrollbar, Stage, StageToken, StageToken as StageToken$1, stagePlugin, useStage, useStageState } from "@embedpdf/react/stage";
12
13
  import { RenderLayer, RenderToken, RenderToken as RenderToken$1, renderPlugin } from "@embedpdf/react/render";
13
- import { PageEditToken, PageEditToken as PageEditToken$1, pageEditPlugin } from "@embedpdf/react/page-edit";
14
+ import { PageEditToken, PageEditToken as PageEditToken$1, pageEditPlugin, usePageEdit, usePageEditState } from "@embedpdf/react/page-edit";
14
15
  import { MetadataToken, MetadataToken as MetadataToken$1, metadataPlugin } from "@embedpdf/react/metadata";
16
+ import { OutlineToken, OutlineToken as OutlineToken$1, outlinePlugin, useOutlineState } from "@embedpdf/react/outline";
17
+ import { AttachmentToken, AttachmentToken as AttachmentToken$1, attachmentPlugin, useAttachmentState } from "@embedpdf/react/attachment";
15
18
  import { InteractionToken, InteractionToken as InteractionToken$1, feedbackPlugin, interactionPlugin, useInteractionState, useToolCursor, vibrationFeedback } from "@embedpdf/react/interaction";
16
19
  import { SelectionClipboard, SelectionHandles, SelectionLayer, SelectionMenu, SelectionToken, SelectionToken as SelectionToken$1, selectionPlugin } from "@embedpdf/react/selection";
17
20
  import { AnnotationLayer, AnnotationMenu, AnnotationRotationBadge, AnnotationToken, AnnotationToken as AnnotationToken$1, annotationPlugin, useAnnotation, useAnnotationDefaults, useAnnotationState, useFilePickerProvider } from "@embedpdf/react/annotation";
@@ -149,6 +152,7 @@ const en = {
149
152
  note: "Comment",
150
153
  link: "Link",
151
154
  gotoLink: "Go to link",
155
+ saveFile: "Save file",
152
156
  removeLink: "Remove link",
153
157
  delete: "Delete",
154
158
  group: "Group",
@@ -205,12 +209,44 @@ const en = {
205
209
  "annotations-create": "Adding annotations isn't allowed",
206
210
  "doc-annotate-modify": "Changing annotations isn't allowed",
207
211
  "doc-annotate-read": "Viewing annotations isn't allowed",
212
+ "doc-attachments-modify": "Adding files isn’t allowed",
208
213
  "doc-download": "Downloading isn't allowed",
209
214
  "doc-forms-modify": "Editing form fields isn't allowed",
215
+ "doc-outline-modify": "Changing the outline isn’t allowed",
216
+ "doc-pages-assemble": "Changing pages isn’t allowed",
210
217
  "doc-print": "Printing isn't allowed",
211
218
  "doc-text-copy": "Copying isn't allowed",
212
219
  "doc-text-search": "Searching isn't allowed"
213
220
  },
221
+ attachment: {
222
+ add: "Add file",
223
+ save: "Save",
224
+ goTo: "Go to page",
225
+ delete: "Delete",
226
+ more: "More options"
227
+ },
228
+ outline: {
229
+ add: "Add item",
230
+ addChild: "Add child item",
231
+ rename: "Rename",
232
+ setDestination: "Set destination to current view",
233
+ properties: "Properties…",
234
+ delete: "Delete",
235
+ expandAll: "Expand all",
236
+ collapseAll: "Collapse all",
237
+ more: "More options"
238
+ },
239
+ pages: {
240
+ rotateClockwise: "Rotate Page Clockwise",
241
+ rotateCounterclockwise: "Rotate Page Counter-Clockwise",
242
+ delete: "Delete Pages",
243
+ duplicate: "Duplicate Pages",
244
+ insertBlank: "Insert Blank Page",
245
+ insertFile: "Insert from File…",
246
+ extract: "Extract Pages",
247
+ selectAll: "Select All Pages",
248
+ more: "Page Options"
249
+ },
214
250
  turnedOff: "{label} isn't available"
215
251
  },
216
252
  passwordPrompt: {
@@ -263,6 +299,25 @@ const en = {
263
299
  other: "Other"
264
300
  },
265
301
  goToPage: { go: "Go" },
302
+ print: {
303
+ title: "Print",
304
+ pages: "Pages",
305
+ allPages: "All pages",
306
+ currentPage: "Current page",
307
+ range: "Custom",
308
+ rangeLabel: "Pages to print",
309
+ rangePlaceholder: "e.g. 1-3, 5",
310
+ rangeInvalid: "Use page numbers from 1 to {total}, such as 1-3, 5",
311
+ annotations: "Print annotations",
312
+ preparing: "Preparing…",
313
+ preparingPage: "Preparing page {page} of {total}…",
314
+ ready: "Ready to print.",
315
+ images: "Pages print as images at {dpi} DPI.",
316
+ lowResolution: "This document allows only low-resolution printing ({dpi} DPI).",
317
+ failed: "The printout couldn’t be prepared.",
318
+ cancel: "Cancel",
319
+ print: "Print"
320
+ },
266
321
  panels: {
267
322
  thumbnails: "Thumbnails",
268
323
  outline: "Outline",
@@ -458,6 +513,46 @@ const en = {
458
513
  noRotate: "Stays upright when the page rotates",
459
514
  invisible: "Legacy: hide unknown subtypes"
460
515
  },
516
+ attachments: {
517
+ loading: "Loading attachments…",
518
+ failed: "The attachments couldn’t be read.",
519
+ empty: "This document has no attached files",
520
+ drop: "Drop files to attach them",
521
+ dropHint: "Or drop files here",
522
+ adding: "Adding…",
523
+ onPage: "Page {page}",
524
+ count: "{count} file",
525
+ countPlural: "{count} files"
526
+ },
527
+ outline: {
528
+ filter: "Filter outline",
529
+ loading: "Loading outline…",
530
+ failed: "The outline couldn’t be read.",
531
+ empty: "This document has no outline",
532
+ noMatches: "No items match",
533
+ incomplete: "Part of the outline couldn’t be read.",
534
+ untitled: "Untitled",
535
+ properties: {
536
+ title: "Item properties",
537
+ name: "Title",
538
+ color: "Color",
539
+ noColor: "None",
540
+ customColor: "Custom color",
541
+ bold: "Bold",
542
+ italic: "Italic",
543
+ open: "Expanded when the document opens",
544
+ target: "Destination",
545
+ targetNone: "None",
546
+ targetView: "Current view",
547
+ targetNamed: "Page action",
548
+ targetKept: "Kept as it is",
549
+ keptNote: "This item runs a script or opens another file. It can’t be changed here.",
550
+ fit: "Fit",
551
+ fitKept: "As it is",
552
+ save: "Save",
553
+ cancel: "Cancel"
554
+ }
555
+ },
461
556
  linkEditor: {
462
557
  toUrl: "Link to a URL",
463
558
  url: "URL",
@@ -620,18 +715,18 @@ const en = {
620
715
  */
621
716
  /** The viewer's languages besides English, by code. */
622
717
  const LOCALE_LOADERS = {
623
- de: () => import("./de-Bdr4aWzm.js").then((module) => module.de),
624
- fr: () => import("./fr-Ckn3K9v1.js").then((module) => module.fr),
625
- es: () => import("./es-BSXz5tBv.js").then((module) => module.es),
626
- it: () => import("./it-Us-VmvIu.js").then((module) => module.it),
627
- nl: () => import("./nl-0aF7M_0h.js").then((module) => module.nl),
628
- pt: () => import("./pt-DIhpU5pT.js").then((module) => module.pt),
629
- pl: () => import("./pl-BW--AaCI.js").then((module) => module.pl),
630
- ja: () => import("./ja-Cizj0-5O.js").then((module) => module.ja),
631
- "zh-CN": () => import("./zh-cn-CxkUUBct.js").then((module) => module.zhCN),
632
- ko: () => import("./ko-DlrXliE1.js").then((module) => module.ko),
633
- ar: () => import("./ar-D9XKAmDx.js").then((module) => module.ar),
634
- he: () => import("./he-wdGU5PkU.js").then((module) => module.he)
718
+ de: () => import("./de-BUhwc9-x.js").then((module) => module.de),
719
+ fr: () => import("./fr-B-8NDhBA.js").then((module) => module.fr),
720
+ es: () => import("./es-DoXTqFoO.js").then((module) => module.es),
721
+ it: () => import("./it-BkirG7ol.js").then((module) => module.it),
722
+ nl: () => import("./nl-Dya4sR8_.js").then((module) => module.nl),
723
+ pt: () => import("./pt-Nm8yyjbX.js").then((module) => module.pt),
724
+ pl: () => import("./pl-DA9b5NVg.js").then((module) => module.pl),
725
+ ja: () => import("./ja-CGEjCE-s.js").then((module) => module.ja),
726
+ "zh-CN": () => import("./zh-cn-BMPPkLpL.js").then((module) => module.zhCN),
727
+ ko: () => import("./ko-CTkl5vMh.js").then((module) => module.ko),
728
+ ar: () => import("./ar-BLWFJoA_.js").then((module) => module.ar),
729
+ he: () => import("./he-Dlh0fNXM.js").then((module) => module.he)
635
730
  };
636
731
  /**
637
732
  * The language a `locale` value shows, among `codes`: the browser's languages for `'auto'`,
@@ -769,6 +864,8 @@ const VIEWER_PLUGINS = {
769
864
  signature: SignatureToken$1,
770
865
  pageEdit: PageEditToken$1,
771
866
  metadata: MetadataToken$1,
867
+ outline: OutlineToken$1,
868
+ attachment: AttachmentToken$1,
772
869
  actions: ActionsToken$1,
773
870
  documents: DocumentsToken$1,
774
871
  interaction: InteractionToken$1,
@@ -958,6 +1055,8 @@ const WITHOUT_SETTINGS = /* @__PURE__ */ new Set([
958
1055
  "link",
959
1056
  "pageEdit",
960
1057
  "metadata",
1058
+ "outline",
1059
+ "attachment",
961
1060
  "documents",
962
1061
  "shell"
963
1062
  ]);
@@ -1014,92 +1113,6 @@ function settingsOver(viewerSettings, settings) {
1014
1113
  return mergeSettings(viewerSettings, settings);
1015
1114
  }
1016
1115
  //#endregion
1017
- //#region src/ui/theme.tsx
1018
- /**
1019
- * Light/dark theme — one class, and the CSS variables in styles.css do the
1020
- * rest (both toolbars, sidebars, popovers, and the canvas re-theme from it).
1021
- * The mode follows the embedder's `theme` preference while the viewer runs;
1022
- * `'system'` follows the OS setting, and switches when the user changes it.
1023
- * The class lands on <html> by default; a delivery that must not touch the
1024
- * page (the <embedpdf-viewer> shadow root) passes `target` and the class stays
1025
- * inside its own subtree. The theme's tokens are CSS variables too: a delivery
1026
- * applies {@link themeTokenCss} on the viewer's root.
1027
- */
1028
- /**
1029
- * The viewer's look, by name: each is the CSS variable `--epdf-<name>`, which the chrome's
1030
- * stylesheet declares with a default for each mode and mixes every other shade from.
1031
- */
1032
- const THEME_TOKENS = [
1033
- "accent",
1034
- "background",
1035
- "surface",
1036
- "surface-raised",
1037
- "text",
1038
- "text-muted",
1039
- "border",
1040
- "hover",
1041
- "canvas",
1042
- "radius",
1043
- "font"
1044
- ];
1045
- /** Normalize the shorthand — deliveries use this to read one shape. */
1046
- const themeConfigOf = (theme) => typeof theme === "string" ? { preference: theme } : theme ?? {};
1047
- const isThemeToken = (name) => THEME_TOKENS.includes(name);
1048
- /** The declarations of `tokens` that are tokens with a CSS value; each other entry warns. */
1049
- function tokenDeclarations(tokens) {
1050
- return Object.entries(tokens).filter(([name, value]) => {
1051
- if (value === void 0) return false;
1052
- if (!isThemeToken(name)) {
1053
- console.warn(`[embedpdf] theme: "${name}" isn't a token, ignored`);
1054
- return false;
1055
- }
1056
- if (typeof value !== "string" || /[{};]/.test(value)) {
1057
- console.warn(`[embedpdf] theme: ignoring the invalid value of "${name}"`);
1058
- return false;
1059
- }
1060
- return true;
1061
- }).map(([name, value]) => `--epdf-${name}:var(--embedpdf-host-${name},${value});`).join("");
1062
- }
1063
- /**
1064
- * The CSS that applies a theme's tokens on the viewer's root (`root`, a selector), for a sheet
1065
- * after the chrome's: its tokens win over the defaults in both modes by coming later, and its
1066
- * dark ones win in dark by naming the class too. A value is a default only: the page's own
1067
- * `--epdf-*` variable still wins, read on the host as the chrome's stylesheet does. Empty when
1068
- * the theme sets no token.
1069
- */
1070
- function themeTokenCss(theme, root) {
1071
- const { accent, tokens, dark } = themeConfigOf(theme);
1072
- const both = tokenDeclarations({
1073
- ...accent === void 0 ? null : { accent },
1074
- ...tokens
1075
- });
1076
- const darkOnly = dark ? tokenDeclarations(dark) : "";
1077
- return (both ? `${root}{${both}}` : "") + (darkOnly ? `${root}.dark{${darkOnly}}` : "");
1078
- }
1079
- const ThemeCtx = createContext(null);
1080
- const DARK_QUERY = "(prefers-color-scheme: dark)";
1081
- const systemMode = () => typeof window !== "undefined" && window.matchMedia?.(DARK_QUERY).matches ? "dark" : "light";
1082
- function ThemeProvider({ children, preference = "system", target }) {
1083
- const [system, setSystem] = useState(systemMode);
1084
- useEffect(() => {
1085
- if (preference !== "system" || typeof window === "undefined" || !window.matchMedia) return;
1086
- const query = window.matchMedia(DARK_QUERY);
1087
- const follow = () => setSystem(query.matches ? "dark" : "light");
1088
- follow();
1089
- query.addEventListener("change", follow);
1090
- return () => query.removeEventListener("change", follow);
1091
- }, [preference]);
1092
- const mode = preference === "system" ? system : preference;
1093
- useLayoutEffect(() => {
1094
- (target ?? document.documentElement).classList.toggle("dark", mode === "dark");
1095
- }, [mode, target]);
1096
- const value = useMemo(() => ({ mode }), [mode]);
1097
- return /* @__PURE__ */ jsx(ThemeCtx.Provider, {
1098
- value,
1099
- children
1100
- });
1101
- }
1102
- //#endregion
1103
1116
  //#region src/config/panels.ts
1104
1117
  /**
1105
1118
  * The panels a layout brings, as commands. Every panel gets `panel:<id>`, which
@@ -1119,6 +1132,12 @@ const panelSideOf = (panel) => panel.side === "start" ? "start" : "end";
1119
1132
  function panelsOnSide(data, side) {
1120
1133
  return Object.entries(data.panels ?? {}).filter(([, panel]) => isPanel(panel) && panelSideOf(panel) === side).map(([id]) => id);
1121
1134
  }
1135
+ /**
1136
+ * Whether a list panel has a job: its list holds entries, or the session may add some (the
1137
+ * right, and `adding`, the feature that turns adding off, on). A document without an outline
1138
+ * shows no outline button to a session that can't add items; the same for attachments.
1139
+ */
1140
+ const hasJob = (commandContext, entries, mayAdd, adding) => entries > 0 || mayAdd && !(commandContext.tryGet(CommandsToken$1)?.isCategoryDisabled(adding) ?? false);
1122
1141
  /** The search panel's id in the layout. */
1123
1142
  const SEARCH_PANEL = "search";
1124
1143
  /** Searching, which the search panel and Find need: without it every query is refused. */
@@ -1145,11 +1164,17 @@ const BUILT_IN_PANELS = /* @__PURE__ */ new Map([
1145
1164
  ["thumbnails", { categories: ["thumbnails"] }],
1146
1165
  ["outline", {
1147
1166
  categories: ["outline"],
1148
- visible: () => false
1167
+ visible: (commandContext) => {
1168
+ const outline = commandContext.tryGet(OutlineToken$1);
1169
+ return outline != null && hasJob(commandContext, outline.list().length, outline.canEdit(), "outline.editing");
1170
+ }
1149
1171
  }],
1150
1172
  ["attachments", {
1151
1173
  categories: ["attachments"],
1152
- visible: () => false
1174
+ visible: (commandContext) => {
1175
+ const attachment = commandContext.tryGet(AttachmentToken$1);
1176
+ return attachment != null && hasJob(commandContext, attachment.list().length, attachment.canAdd(), "attachments.adding");
1177
+ }
1153
1178
  }],
1154
1179
  [SEARCH_PANEL, {
1155
1180
  ...SEARCHES,
@@ -1816,7 +1841,7 @@ function StripBar({ view, label }) {
1816
1841
  * groups vanish, null when nothing applies. Mounted in the Stage `overlay`
1817
1842
  * slot. The pixels are the shared <StripBar>.
1818
1843
  */
1819
- const LinkEditorCard = lazyComponent(() => import("./link-editor-SxM1nnJU.js").then((ui) => ui.LinkEditorCard));
1844
+ const LinkEditorCard = lazyComponent(() => import("./link-editor-CkwtqRvb.js").then((ui) => ui.LinkEditorCard));
1820
1845
  function AnnotationStrip() {
1821
1846
  const t = useT();
1822
1847
  const view = useStripView(useStripSchema("annotation"));
@@ -2516,6 +2541,551 @@ function PanelRow({ panel, current, onPicked }) {
2516
2541
  });
2517
2542
  }
2518
2543
  //#endregion
2544
+ //#region src/ui/thumbnail-drop.ts
2545
+ /** How thick the drop line is drawn, in px. */
2546
+ const LINE = 2;
2547
+ /** How many thumbnails share the first row on screen: 1 for a single column. */
2548
+ function columnsOf(boxes) {
2549
+ const first = boxes[0];
2550
+ if (!first) return 1;
2551
+ return Math.max(1, boxes.filter((box) => Math.abs(box.y - first.y) < 1).length);
2552
+ }
2553
+ /** How far a point is from a box: 0 inside it. */
2554
+ function distance(box, x, y) {
2555
+ const dx = Math.max(box.x - x, 0, x - (box.x + box.width));
2556
+ const dy = Math.max(box.y - y, 0, y - (box.y + box.height));
2557
+ return Math.hypot(dx, dy);
2558
+ }
2559
+ /**
2560
+ * The order of the document's pages once `moving` go to `position`, together in the order they
2561
+ * have now: what a reorder answers.
2562
+ */
2563
+ function orderAfter(order, moving, position) {
2564
+ const staying = order.filter((page) => !moving.has(page));
2565
+ const anchor = "before" in position ? position.before : position.after;
2566
+ const at = staying.indexOf(anchor) + ("after" in position ? 1 : 0);
2567
+ const moved = order.filter((page) => moving.has(page));
2568
+ return [
2569
+ ...staying.slice(0, at),
2570
+ ...moved,
2571
+ ...staying.slice(at)
2572
+ ];
2573
+ }
2574
+ /**
2575
+ * Where pages dropped at `point` land, or `null` when nothing would change: over a page that
2576
+ * moves, or in the place the pages already are. `order` is every page of the document in display
2577
+ * order; `moving` the pages dragged, empty for files dropped from outside.
2578
+ */
2579
+ function thumbDropAt(boxes, point, spacing, order, moving) {
2580
+ let nearest = null;
2581
+ for (const box of boxes) if (!nearest || distance(box, point.x, point.y) < distance(nearest, point.x, point.y)) nearest = box;
2582
+ if (!nearest || moving.has(nearest.page)) return null;
2583
+ const across = columnsOf(boxes) > 1;
2584
+ const before = across ? point.x < nearest.x + nearest.width / 2 : point.y < nearest.y + nearest.height / 2;
2585
+ const position = before ? { before: nearest.page } : { after: nearest.page };
2586
+ if (moving.size > 0) {
2587
+ if (orderAfter(order, moving, position).every((page, i) => page === order[i])) return null;
2588
+ }
2589
+ const half = spacing.gap / 2;
2590
+ return {
2591
+ position,
2592
+ line: across ? {
2593
+ x: (before ? nearest.x - half : nearest.x + nearest.width + half) - LINE / 2,
2594
+ y: nearest.y,
2595
+ width: LINE,
2596
+ height: nearest.height
2597
+ } : {
2598
+ x: nearest.x,
2599
+ y: (before ? nearest.y - half : nearest.y + nearest.height + spacing.band + half) - LINE / 2,
2600
+ width: nearest.width,
2601
+ height: LINE
2602
+ }
2603
+ };
2604
+ }
2605
+ /**
2606
+ * The page a move of one slot puts the selection next to, keys up or down: past the nearest page
2607
+ * that isn't selected, on that side. `null` at the start or the end.
2608
+ */
2609
+ function slotMove(order, selected, direction) {
2610
+ const indexes = order.flatMap((page, i) => selected.has(page) ? [i] : []);
2611
+ if (indexes.length === 0) return null;
2612
+ if (direction < 0) {
2613
+ for (let i = indexes[0] - 1; i >= 0; i -= 1) if (!selected.has(order[i])) return { before: order[i] };
2614
+ return null;
2615
+ }
2616
+ for (let i = indexes[indexes.length - 1] + 1; i < order.length; i += 1) if (!selected.has(order[i])) return { after: order[i] };
2617
+ return null;
2618
+ }
2619
+ //#endregion
2620
+ //#region src/ui/thumbnail-list.tsx
2621
+ /**
2622
+ * The thumbnails panel: the same document through the thumbnail Stage lens (a fixed-zoom grid
2623
+ * that wraps into as many columns as the panel's width fits; see the viewer's `thumbnails`
2624
+ * plugin). A click goes to the page, and the panel follows the main view.
2625
+ *
2626
+ * A session that may change the pages (`page:insert-blank` shows and is enabled, the outline
2627
+ * panel's rule) organizes them here too:
2628
+ * - a click selects the page, Ctrl/Cmd+click adds or removes one, Shift+click selects a range;
2629
+ * - each page has a menu: its button, a right-click, or a long press;
2630
+ * - dragging moves the selection if the page is in it, else that page, with a line where they
2631
+ * land; a pen or a finger holds the page first, so a swipe still scrolls;
2632
+ * - PDFs dropped between pages are inserted there, not opened as a tab;
2633
+ * - the header has insert, rotate, delete, the selection's menu, and undo and redo;
2634
+ * - the list is one tab stop: arrows go through the pages, Shift extends, Space adds or removes,
2635
+ * Alt+arrows move the selection one place, Delete deletes and Ctrl/Cmd+A selects every page.
2636
+ */
2637
+ /** How far the pointer moves before a press on a page becomes a drag, in px (the outline's). */
2638
+ const DRAG_SLOP_PX = 4;
2639
+ /** How long a pen or a finger holds a page before it drags it, or opens its menu, in ms. */
2640
+ const HOLD_MS = 450;
2641
+ /** Within this many px of the list's top or bottom, a drag scrolls the list. */
2642
+ const EDGE_PX = 28;
2643
+ /** The lens's spacing when its settings don't say it in px. */
2644
+ const DEFAULT_GAP_PX = 16;
2645
+ /** The header's commands: insert and rotate, delete, the menu of the rest, then the history. */
2646
+ const HEADER_EDITS = [
2647
+ "page:insert-blank",
2648
+ "page:rotate-counterclockwise",
2649
+ "page:rotate-clockwise",
2650
+ "page:delete",
2651
+ "menu:page"
2652
+ ];
2653
+ const HEADER_HISTORY = ["history:undo", "history:redo"];
2654
+ /** The thumbnails on screen, as boxes in the lens's viewport. */
2655
+ function boxesOf(thumbs) {
2656
+ return thumbs.listVisiblePages().map((page) => ({
2657
+ page: page.ref.objectNumber,
2658
+ x: page.screenX,
2659
+ y: page.screenY,
2660
+ width: page.transform.viewWidth,
2661
+ height: page.transform.viewHeight
2662
+ }));
2663
+ }
2664
+ const positionOf = (position) => "before" in position ? { before: toPageRef(position.before) } : { after: toPageRef(position.after) };
2665
+ function ThumbnailList() {
2666
+ const t = useT();
2667
+ const idPrefix = useId();
2668
+ const main = useStage();
2669
+ const thumbs = useStage(ThumbsStageToken);
2670
+ const currentPage = useStageState((state) => state.currentPageIndex);
2671
+ const pages = usePageList();
2672
+ const pageEdit = usePageEdit();
2673
+ const selected = usePageEditState((state) => state.selected);
2674
+ const commands = useCommands();
2675
+ const insertFile = useCommand("page:insert-file");
2676
+ const insertBlank = useCommand("page:insert-blank");
2677
+ const editable = insertBlank.visible && insertBlank.enabled;
2678
+ const closeOnPick = useCloseOnPick();
2679
+ const host = useRef(null);
2680
+ const [focusedPage, setFocusedPage] = useState(null);
2681
+ const [anchorPage, setAnchorPage] = useState(null);
2682
+ const [listFocused, setListFocused] = useState(false);
2683
+ const [drag, setDrag] = useState(null);
2684
+ const dragRef = useRef(null);
2685
+ dragRef.current = drag;
2686
+ const [fileDrop, setFileDrop] = useState(null);
2687
+ const holdTimer = useRef(null);
2688
+ const suppressClick = useRef(false);
2689
+ const order = pages.map((page) => page.ref.objectNumber);
2690
+ const indexOf = (page) => page === null ? -1 : order.indexOf(page);
2691
+ const selectedPages = new Set(selected.map((ref) => ref.objectNumber));
2692
+ const focusedIndex = indexOf(focusedPage) >= 0 ? indexOf(focusedPage) : currentPage;
2693
+ useEffect(() => thumbs.reveal(currentPage), [currentPage, thumbs]);
2694
+ const laidOut = useStageState((state) => state.pageCount, ThumbsStageToken);
2695
+ const lastSelected = selected[selected.length - 1]?.objectNumber ?? null;
2696
+ const lastSelectedIndex = lastSelected === null ? -1 : order.indexOf(lastSelected);
2697
+ useEffect(() => {
2698
+ if (lastSelectedIndex >= 0 && lastSelectedIndex < laidOut) thumbs.reveal(lastSelectedIndex);
2699
+ }, [
2700
+ lastSelectedIndex,
2701
+ laidOut,
2702
+ thumbs
2703
+ ]);
2704
+ const spacing = () => {
2705
+ const { gap, pageFrame } = thumbs.getSettings();
2706
+ return {
2707
+ gap: typeof gap === "object" && gap !== null && "px" in gap ? gap.px : DEFAULT_GAP_PX,
2708
+ band: pageFrame.bottom
2709
+ };
2710
+ };
2711
+ /** A pointer's place in the lens's viewport. */
2712
+ const pointOf = (clientX, clientY) => {
2713
+ const box = host.current?.getBoundingClientRect();
2714
+ return box ? {
2715
+ x: clientX - box.left,
2716
+ y: clientY - box.top
2717
+ } : null;
2718
+ };
2719
+ const dropAt = (clientX, clientY, moving) => {
2720
+ const point = pointOf(clientX, clientY);
2721
+ return point ? thumbDropAt(boxesOf(thumbs), point, spacing(), order, moving) : null;
2722
+ };
2723
+ const go = (index) => {
2724
+ main.goToPage(index);
2725
+ closeOnPick();
2726
+ };
2727
+ const select = (refs) => pageEdit.select(refs);
2728
+ const onPageClick = (ref, index, event) => {
2729
+ if (suppressClick.current) {
2730
+ suppressClick.current = false;
2731
+ return;
2732
+ }
2733
+ const page = ref.objectNumber;
2734
+ setFocusedPage(page);
2735
+ if (editable && (event.metaKey || event.ctrlKey)) {
2736
+ select(selectedPages.has(page) ? selected.filter((each) => each.objectNumber !== page) : [...selected, ref]);
2737
+ setAnchorPage(page);
2738
+ return;
2739
+ }
2740
+ if (editable && event.shiftKey && indexOf(anchorPage) >= 0) {
2741
+ const from = indexOf(anchorPage);
2742
+ const [low, high] = from < index ? [from, index] : [index, from];
2743
+ select(pages.slice(low, high + 1).map((each) => each.ref));
2744
+ return;
2745
+ }
2746
+ setAnchorPage(page);
2747
+ if (editable) select([ref]);
2748
+ go(index);
2749
+ };
2750
+ /** A page's menu is about to open: an unselected page becomes the selection. */
2751
+ const onMenu = (ref) => {
2752
+ setFocusedPage(ref.objectNumber);
2753
+ if (!selectedPages.has(ref.objectNumber)) select([ref]);
2754
+ };
2755
+ const openMenuOf = (page) => host.current?.querySelector(`[data-epdf-page-menu="${page}"] button`)?.click();
2756
+ const stopHold = () => {
2757
+ if (holdTimer.current !== null) clearTimeout(holdTimer.current);
2758
+ holdTimer.current = null;
2759
+ };
2760
+ const onPagePointerDown = (ref, event) => {
2761
+ if (!editable || event.button !== 0) return;
2762
+ if (event.target.closest("[data-epdf-page-menu]")) return;
2763
+ const page = ref.objectNumber;
2764
+ const moving = selectedPages.has(page) ? selectedPages : /* @__PURE__ */ new Set([page]);
2765
+ setDrag({
2766
+ pointerId: event.pointerId,
2767
+ startX: event.clientX,
2768
+ startY: event.clientY,
2769
+ page,
2770
+ moving,
2771
+ held: false,
2772
+ active: false,
2773
+ drop: null
2774
+ });
2775
+ if (event.pointerType !== "mouse") holdTimer.current = setTimeout(() => {
2776
+ const current = dragRef.current;
2777
+ if (current && !current.active) setDrag({
2778
+ ...current,
2779
+ held: true
2780
+ });
2781
+ }, HOLD_MS);
2782
+ };
2783
+ const dragging = drag?.active === true;
2784
+ const pressed = drag !== null;
2785
+ useEffect(() => {
2786
+ if (!pressed) return void 0;
2787
+ const move = (event) => {
2788
+ const current = dragRef.current;
2789
+ if (!current || event.pointerId !== current.pointerId) return;
2790
+ if (!current.active) {
2791
+ if (Math.hypot(event.clientX - current.startX, event.clientY - current.startY) <= DRAG_SLOP_PX) return;
2792
+ if (event.pointerType !== "mouse" && !current.held) {
2793
+ stopHold();
2794
+ setDrag(null);
2795
+ return;
2796
+ }
2797
+ }
2798
+ const box = host.current?.getBoundingClientRect();
2799
+ if (box && event.clientY < box.top + EDGE_PX) thumbs.scrollBy({ top: -8 });
2800
+ else if (box && event.clientY > box.bottom - EDGE_PX) thumbs.scrollBy({ top: 8 });
2801
+ setDrag({
2802
+ ...current,
2803
+ active: true,
2804
+ drop: dropAt(event.clientX, event.clientY, current.moving)
2805
+ });
2806
+ };
2807
+ const end = (event, commit) => {
2808
+ stopHold();
2809
+ const current = dragRef.current;
2810
+ if (!current || event.pointerId !== current.pointerId) return;
2811
+ setDrag(null);
2812
+ if (!current.active) {
2813
+ if (current.held && commit) {
2814
+ suppressClick.current = true;
2815
+ onMenu(toPageRef(current.page));
2816
+ openMenuOf(current.page);
2817
+ }
2818
+ return;
2819
+ }
2820
+ suppressClick.current = true;
2821
+ setTimeout(() => {
2822
+ suppressClick.current = false;
2823
+ }, 0);
2824
+ if (!commit || !current.drop) return;
2825
+ const moving = pages.filter((page) => current.moving.has(page.ref.objectNumber));
2826
+ pageEdit.reorder(moving.map((page) => page.ref), positionOf(current.drop.position)).catch(() => {});
2827
+ };
2828
+ const up = (event) => end(event, true);
2829
+ const cancel = (event) => end(event, false);
2830
+ window.addEventListener("pointermove", move);
2831
+ window.addEventListener("pointerup", up);
2832
+ window.addEventListener("pointercancel", cancel);
2833
+ return () => {
2834
+ window.removeEventListener("pointermove", move);
2835
+ window.removeEventListener("pointerup", up);
2836
+ window.removeEventListener("pointercancel", cancel);
2837
+ };
2838
+ });
2839
+ useEffect(() => {
2840
+ if (!dragging) return void 0;
2841
+ const prevent = (event) => event.preventDefault();
2842
+ document.addEventListener("touchmove", prevent, { passive: false });
2843
+ return () => document.removeEventListener("touchmove", prevent);
2844
+ }, [dragging]);
2845
+ useEffect(() => stopHold, []);
2846
+ const takesFiles = (event) => editable && insertFile.visible && insertFile.enabled && mayCarryPdf(event.dataTransfer);
2847
+ const onDragOver = (event) => {
2848
+ if (!takesFiles(event)) return;
2849
+ event.preventDefault();
2850
+ event.stopPropagation();
2851
+ event.dataTransfer.dropEffect = "copy";
2852
+ setFileDrop(dropAt(event.clientX, event.clientY, /* @__PURE__ */ new Set()));
2853
+ };
2854
+ const onDragLeave = (event) => {
2855
+ if (!takesFiles(event)) return;
2856
+ event.stopPropagation();
2857
+ const next = event.relatedTarget;
2858
+ if (!next || !host.current?.contains(next)) setFileDrop(null);
2859
+ };
2860
+ const onDrop = (event) => {
2861
+ if (!takesFiles(event)) return;
2862
+ event.preventDefault();
2863
+ event.stopPropagation();
2864
+ const drop = dropAt(event.clientX, event.clientY, /* @__PURE__ */ new Set());
2865
+ setFileDrop(null);
2866
+ const files = Array.from(event.dataTransfer.files).filter(isPdfFile);
2867
+ if (files.length === 0) return;
2868
+ const args = {
2869
+ files,
2870
+ ...drop ? { position: positionOf(drop.position) } : {}
2871
+ };
2872
+ commands.execute("page:insert-file", { args }).catch(() => {});
2873
+ };
2874
+ const focusIndex = (index, extend) => {
2875
+ const page = pages[index];
2876
+ if (!page) return;
2877
+ setFocusedPage(page.ref.objectNumber);
2878
+ thumbs.reveal(index);
2879
+ if (!editable) {
2880
+ main.goToPage(index);
2881
+ return;
2882
+ }
2883
+ if (extend && indexOf(anchorPage) >= 0) {
2884
+ const from = indexOf(anchorPage);
2885
+ const [low, high] = from < index ? [from, index] : [index, from];
2886
+ select(pages.slice(low, high + 1).map((each) => each.ref));
2887
+ return;
2888
+ }
2889
+ setAnchorPage(page.ref.objectNumber);
2890
+ select([page.ref]);
2891
+ main.goToPage(index);
2892
+ };
2893
+ const onKeyDown = (event) => {
2894
+ if (event.target !== event.currentTarget || pages.length === 0) return;
2895
+ setListFocused(true);
2896
+ const columns = columnsOf(boxesOf(thumbs));
2897
+ const step = {
2898
+ ArrowLeft: -1,
2899
+ ArrowRight: 1,
2900
+ ArrowUp: -columns,
2901
+ ArrowDown: columns
2902
+ }[event.key];
2903
+ const mod = event.metaKey || event.ctrlKey;
2904
+ if (step !== void 0 && event.altKey && editable) {
2905
+ event.preventDefault();
2906
+ const position = slotMove(order, selectedPages, step < 0 ? -1 : 1);
2907
+ const moving = pages.filter((page) => selectedPages.has(page.ref.objectNumber));
2908
+ if (position && moving.length > 0) pageEdit.reorder(moving.map((page) => page.ref), positionOf(position)).catch(() => {});
2909
+ return;
2910
+ }
2911
+ if (step !== void 0) {
2912
+ event.preventDefault();
2913
+ focusIndex(Math.max(0, Math.min(pages.length - 1, focusedIndex + step)), event.shiftKey);
2914
+ return;
2915
+ }
2916
+ switch (event.key) {
2917
+ case "Home":
2918
+ case "End":
2919
+ event.preventDefault();
2920
+ focusIndex(event.key === "Home" ? 0 : pages.length - 1, event.shiftKey);
2921
+ return;
2922
+ case "Enter":
2923
+ event.preventDefault();
2924
+ go(focusedIndex);
2925
+ return;
2926
+ case " ": {
2927
+ if (!editable) return;
2928
+ event.preventDefault();
2929
+ const page = pages[focusedIndex];
2930
+ if (!page) return;
2931
+ const number = page.ref.objectNumber;
2932
+ setAnchorPage(number);
2933
+ select(selectedPages.has(number) ? selected.filter((each) => each.objectNumber !== number) : [...selected, page.ref]);
2934
+ return;
2935
+ }
2936
+ case "Delete":
2937
+ case "Backspace":
2938
+ if (!editable) return;
2939
+ event.preventDefault();
2940
+ commands.execute("page:delete").catch(() => {});
2941
+ return;
2942
+ case "a":
2943
+ case "A":
2944
+ if (!mod || !editable) return;
2945
+ event.preventDefault();
2946
+ commands.execute("page:select-all").catch(() => {});
2947
+ return;
2948
+ }
2949
+ };
2950
+ const focusedRef = pages[focusedIndex]?.ref ?? null;
2951
+ const shownDrop = dragging ? drag.drop : fileDrop;
2952
+ return /* @__PURE__ */ jsxs("div", {
2953
+ className: "flex min-h-0 flex-1 flex-col",
2954
+ children: [editable && /* @__PURE__ */ jsx(PageHeader, {}), /* @__PURE__ */ jsx("div", {
2955
+ ref: host,
2956
+ role: "listbox",
2957
+ "aria-label": t("panels.thumbnails"),
2958
+ "aria-multiselectable": editable || void 0,
2959
+ tabIndex: 0,
2960
+ "aria-activedescendant": listFocused && focusedRef ? `${idPrefix}-${focusedRef.objectNumber}` : void 0,
2961
+ onKeyDown,
2962
+ onFocus: (event) => event.target === event.currentTarget && setListFocused(event.currentTarget.matches(":focus-visible")),
2963
+ onBlur: (event) => event.target === event.currentTarget && setListFocused(false),
2964
+ onDragEnter: onDragOver,
2965
+ onDragOver,
2966
+ onDragLeave,
2967
+ onDrop,
2968
+ className: "focus-visible:ring-accent relative flex min-h-0 flex-1 flex-col outline-none focus-visible:ring-2 focus-visible:ring-inset",
2969
+ children: /* @__PURE__ */ jsx(Stage, {
2970
+ token: ThumbsStageToken,
2971
+ className: "flex-1",
2972
+ style: { position: "relative" },
2973
+ overlay: shownDrop ? /* @__PURE__ */ jsx("div", {
2974
+ "aria-hidden": true,
2975
+ className: "bg-accent pointer-events-none absolute rounded-full",
2976
+ style: {
2977
+ left: shownDrop.line.x,
2978
+ top: shownDrop.line.y,
2979
+ width: shownDrop.line.width,
2980
+ height: shownDrop.line.height
2981
+ }
2982
+ }) : null,
2983
+ pageChrome: (page) => {
2984
+ const number = page.ref.objectNumber;
2985
+ const isSelected = editable && selectedPages.has(number);
2986
+ const isCurrent = page.pageIndex === currentPage;
2987
+ const isFocused = listFocused && focusedRef?.objectNumber === number;
2988
+ const isMoving = dragging && drag.moving.has(number);
2989
+ const label = t("thumbnails.page", { params: { page: page.pageIndex + 1 } });
2990
+ return /* @__PURE__ */ jsxs("div", {
2991
+ className: "group",
2992
+ style: {
2993
+ position: "absolute",
2994
+ inset: 0
2995
+ },
2996
+ children: [
2997
+ /* @__PURE__ */ jsx("button", {
2998
+ type: "button",
2999
+ id: `${idPrefix}-${number}`,
3000
+ role: "option",
3001
+ "aria-selected": editable ? isSelected : isCurrent,
3002
+ "aria-current": isCurrent ? "page" : void 0,
3003
+ "aria-label": label,
3004
+ tabIndex: -1,
3005
+ title: label,
3006
+ onClick: (event) => onPageClick(page.ref, page.pageIndex, event),
3007
+ onPointerDown: (event) => onPagePointerDown(page.ref, event),
3008
+ onContextMenu: (event) => {
3009
+ if (!editable) return;
3010
+ event.preventDefault();
3011
+ onMenu(page.ref);
3012
+ openMenuOf(number);
3013
+ },
3014
+ className: `box-border cursor-pointer touch-manipulation rounded ${isSelected || isCurrent ? "border-accent border-2" : "border-border-subtle border"} ${isCurrent ? "ring-accent-light ring-2" : ""} ${isSelected ? "bg-accent/10" : ""} ${isFocused ? "outline-accent outline outline-2 outline-offset-2" : ""} ${isMoving ? "bg-surface/60" : ""}`,
3015
+ style: {
3016
+ position: "absolute",
3017
+ top: page.frame.top,
3018
+ left: page.frame.left,
3019
+ right: page.frame.right,
3020
+ bottom: page.frame.bottom
3021
+ }
3022
+ }),
3023
+ editable && /* @__PURE__ */ jsx("span", {
3024
+ "data-epdf-page-menu": number,
3025
+ onClick: (event) => event.stopPropagation(),
3026
+ onPointerDownCapture: () => onMenu(page.ref),
3027
+ className: `bg-elevated absolute rounded shadow-sm ${isSelected || isFocused ? "" : "opacity-0 focus-within:opacity-100 group-hover:opacity-100"}`,
3028
+ style: {
3029
+ top: page.frame.top + 4,
3030
+ right: page.frame.right + 4
3031
+ },
3032
+ children: /* @__PURE__ */ jsx(PageMenuButton, {})
3033
+ }),
3034
+ /* @__PURE__ */ jsx("div", {
3035
+ style: {
3036
+ position: "absolute",
3037
+ bottom: 0,
3038
+ left: 0,
3039
+ right: 0,
3040
+ height: page.frame.bottom,
3041
+ display: "flex",
3042
+ alignItems: "center",
3043
+ justifyContent: "center",
3044
+ fontSize: 11,
3045
+ color: "var(--epdf-text-muted)",
3046
+ pointerEvents: "none"
3047
+ },
3048
+ children: page.pageIndex + 1
3049
+ })
3050
+ ]
3051
+ });
3052
+ },
3053
+ children: () => /* @__PURE__ */ jsx(RenderLayer, {})
3054
+ })
3055
+ })]
3056
+ });
3057
+ }
3058
+ /** A page's menu button: the page commands for the selected pages. */
3059
+ function PageMenuButton() {
3060
+ const more = useCommand("menu:page");
3061
+ if (!more.visible) return null;
3062
+ return /* @__PURE__ */ jsx(CommandButton, {
3063
+ cmd: more,
3064
+ variant: "icon",
3065
+ run: () => void more.run()
3066
+ });
3067
+ }
3068
+ /** The header over the thumbnails while the pages can be changed: the edits, then the history. */
3069
+ function PageHeader() {
3070
+ return /* @__PURE__ */ jsxs("div", {
3071
+ className: "border-border-subtle flex items-center gap-1 border-b p-2",
3072
+ children: [
3073
+ HEADER_EDITS.map((id) => /* @__PURE__ */ jsx(HeaderButton, { id }, id)),
3074
+ /* @__PURE__ */ jsx("span", { className: "flex-1" }),
3075
+ HEADER_HISTORY.map((id) => /* @__PURE__ */ jsx(HeaderButton, { id }, id))
3076
+ ]
3077
+ });
3078
+ }
3079
+ function HeaderButton({ id }) {
3080
+ const command = useCommand(id);
3081
+ if (!command.visible) return null;
3082
+ return /* @__PURE__ */ jsx(CommandButton, {
3083
+ cmd: command,
3084
+ variant: "icon",
3085
+ run: () => void command.run()
3086
+ });
3087
+ }
3088
+ //#endregion
2519
3089
  //#region src/ui/panels.tsx
2520
3090
  /**
2521
3091
  * The layout's panels, drawn: on each side of the pages, the panel open on
@@ -2531,19 +3101,29 @@ function PanelRow({ panel, current, onPicked }) {
2531
3101
  * A panel whose button no longer shows (its feature turned off, or not
2532
3102
  * allowed) closes.
2533
3103
  */
2534
- const SearchPanel = lazyComponent(() => import("./search-panel-HfIhJm1M.js").then((ui) => ui.SearchPanel));
2535
- const CommentsPanel = lazyComponent(() => import("./comments-panel-MUVgLCBI.js").then((ui) => ui.CommentsPanel));
2536
- const MeasurementSection = lazyComponent(() => import("./measurement-Bs61XWbJ.js").then((ui) => ui.MeasurementSection));
2537
- const AnnotationStylePanel = lazyComponent(() => import("./annotation-style--rPIZsuP.js").then((ui) => ui.AnnotationStylePanel));
2538
- const StampsPanel = lazyComponent(() => import("./stamps-panel-CDO0FPyK.js").then((ui) => ui.StampsPanel));
2539
- const SignaturesPanel = lazyComponent(() => import("./signatures-panel-CgnFfhFm.js").then((ui) => ui.SignaturesPanel));
2540
- const RedactionPanel = lazyComponent(() => import("./redaction-panel-IJDshSJI.js").then((ui) => ui.RedactionPanel));
2541
- const FormDesignPanel = lazyComponent(() => import("./form-design-panel-vWWU9uB-.js").then((ui) => ui.FormDesignPanel));
3104
+ const SearchPanel = lazyComponent(() => import("./search-panel-BE4xzWlm.js").then((ui) => ui.SearchPanel));
3105
+ const CommentsPanel = lazyComponent(() => import("./comments-panel-D7Eadws9.js").then((ui) => ui.CommentsPanel));
3106
+ const MeasurementSection = lazyComponent(() => import("./measurement-CQdbnIrn.js").then((ui) => ui.MeasurementSection));
3107
+ const AnnotationStylePanel = lazyComponent(() => import("./annotation-style-CXF3X47Z.js").then((ui) => ui.AnnotationStylePanel));
3108
+ const StampsPanel = lazyComponent(() => import("./stamps-panel-BrczStaz.js").then((ui) => ui.StampsPanel));
3109
+ const SignaturesPanel = lazyComponent(() => import("./signatures-panel-DZ9ywrjz.js").then((ui) => ui.SignaturesPanel));
3110
+ const RedactionPanel = lazyComponent(() => import("./redaction-panel-CgNZ-pQk.js").then((ui) => ui.RedactionPanel));
3111
+ const OutlinePanel = lazyComponent(() => import("./outline-panel-DO5_REYw.js").then((ui) => ui.OutlinePanel));
3112
+ const AttachmentsPanel = lazyComponent(() => import("./attachments-panel-H1ucRbwo.js").then((ui) => ui.AttachmentsPanel));
3113
+ const FormDesignPanel = lazyComponent(() => import("./form-design-panel-CgV_5YWC.js").then((ui) => ui.FormDesignPanel));
2542
3114
  const BUILT_IN_CONTENT = /* @__PURE__ */ new Map([
2543
3115
  ["thumbnails", {
2544
3116
  draw: () => /* @__PURE__ */ jsx(ThumbnailList, {}),
2545
3117
  list: true
2546
3118
  }],
3119
+ ["outline", {
3120
+ draw: (documentId) => /* @__PURE__ */ jsx(OutlinePanel, {}, documentId ?? "none"),
3121
+ list: true
3122
+ }],
3123
+ ["attachments", {
3124
+ draw: (documentId) => /* @__PURE__ */ jsx(AttachmentsPanel, {}, documentId ?? "none"),
3125
+ list: true
3126
+ }],
2547
3127
  ["search", {
2548
3128
  draw: (documentId) => /* @__PURE__ */ jsx(SearchPanel, {}, documentId ?? "none"),
2549
3129
  list: true
@@ -2624,51 +3204,6 @@ function OpenPanel({ id, side, siblings }) {
2624
3204
  })
2625
3205
  });
2626
3206
  }
2627
- function ThumbnailList() {
2628
- const t = useT();
2629
- const main = useStage();
2630
- const thumbs = useStage(ThumbsStageToken);
2631
- const currentPage = useStageState((state) => state.currentPageIndex);
2632
- const closeOnPick = useCloseOnPick();
2633
- useEffect(() => thumbs.reveal(currentPage), [currentPage, thumbs]);
2634
- return /* @__PURE__ */ jsx(Stage, {
2635
- token: ThumbsStageToken,
2636
- className: "flex-1",
2637
- style: { position: "relative" },
2638
- pageChrome: (page) => /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
2639
- type: "button",
2640
- onClick: () => {
2641
- main.goToPage(page.pageIndex);
2642
- closeOnPick();
2643
- },
2644
- title: t("thumbnails.page", { params: { page: page.pageIndex + 1 } }),
2645
- className: `box-border cursor-pointer rounded ${page.pageIndex === currentPage ? "border-accent ring-accent-light border-2 ring-2" : "border-border-subtle border"}`,
2646
- style: {
2647
- position: "absolute",
2648
- top: page.frame.top,
2649
- left: page.frame.left,
2650
- right: page.frame.right,
2651
- bottom: page.frame.bottom
2652
- }
2653
- }), /* @__PURE__ */ jsx("div", {
2654
- style: {
2655
- position: "absolute",
2656
- bottom: 0,
2657
- left: 0,
2658
- right: 0,
2659
- height: page.frame.bottom,
2660
- display: "flex",
2661
- alignItems: "center",
2662
- justifyContent: "center",
2663
- fontSize: 11,
2664
- color: "var(--epdf-text-muted)",
2665
- pointerEvents: "none"
2666
- },
2667
- children: page.pageIndex + 1
2668
- })] }),
2669
- children: () => /* @__PURE__ */ jsx(RenderLayer, {})
2670
- });
2671
- }
2672
3207
  //#endregion
2673
3208
  //#region src/ui/placed-components.tsx
2674
3209
  /**
@@ -2991,7 +3526,8 @@ const GROUPS = [
2991
3526
  "selection",
2992
3527
  "annotation",
2993
3528
  "redaction",
2994
- "measurement"
3529
+ "measurement",
3530
+ "outline"
2995
3531
  ]
2996
3532
  }
2997
3533
  ];
@@ -3081,6 +3617,18 @@ function ShortcutsList({ onClose }) {
3081
3617
  });
3082
3618
  }
3083
3619
  //#endregion
3620
+ //#region src/ui/sidebar-reads.tsx
3621
+ /**
3622
+ * Once a document shows: read its outline and its attachments, so their panels' buttons know
3623
+ * whether the panels have a job (`config/panels.ts`). Reading a plugin's state is what reads it;
3624
+ * a viewer without the plugin reads nothing. Mounted once per document view; renders nothing.
3625
+ */
3626
+ function SidebarReads() {
3627
+ useOutlineState((state) => state.status);
3628
+ useAttachmentState((state) => state.status);
3629
+ return null;
3630
+ }
3631
+ //#endregion
3084
3632
  //#region src/ui/signature-bridge.tsx
3085
3633
  /**
3086
3634
  * The signature plugin's UI intents → shell surfaces. The plugin owns the
@@ -3408,11 +3956,15 @@ const useCalibrating = () => useMeasurementState((state) => state.calibrationReq
3408
3956
  const useSignDialogOpen = () => useSurface("signature-sign").isOpen;
3409
3957
  const useSignatureMakerOpen = () => useSurface("signature-maker").isOpen;
3410
3958
  const useSignatureInspectorOpen = () => useSurface("signature-inspector").isOpen;
3411
- const RedactConfirmModal = lazyComponent(() => import("./redact-confirm-B6j36TPw.js").then((ui) => ui.RedactConfirmModal), { shownWhile: useRedactConfirmOpen });
3412
- const CalibrationDialog = lazyComponent(() => import("./measurement-Bs61XWbJ.js").then((ui) => ui.CalibrationDialog), { shownWhile: useCalibrating });
3413
- const SignDialog = lazyComponent(() => import("./sign-dialog-GDqCoQhA.js").then((ui) => ui.SignDialog), { shownWhile: useSignDialogOpen });
3414
- const SignatureMakerModal = lazyComponent(() => import("./signature-maker-BhCmYyHD.js").then((ui) => ui.SignatureMakerModal), { shownWhile: useSignatureMakerOpen });
3415
- const SignatureInspector = lazyComponent(() => import("./signature-inspector-okFz8do6.js").then((ui) => ui.SignatureInspector), { shownWhile: useSignatureInspectorOpen });
3959
+ const usePrintDialogOpen = () => useSurface("print").isOpen;
3960
+ const RedactConfirmModal = lazyComponent(() => import("./redact-confirm-CKuv9iN_.js").then((ui) => ui.RedactConfirmModal), { shownWhile: useRedactConfirmOpen });
3961
+ const CalibrationDialog = lazyComponent(() => import("./measurement-CQdbnIrn.js").then((ui) => ui.CalibrationDialog), { shownWhile: useCalibrating });
3962
+ const SignDialog = lazyComponent(() => import("./sign-dialog-DerNe8qT.js").then((ui) => ui.SignDialog), { shownWhile: useSignDialogOpen });
3963
+ const SignatureMakerModal = lazyComponent(() => import("./signature-maker-Dnth4rV4.js").then((ui) => ui.SignatureMakerModal), { shownWhile: useSignatureMakerOpen });
3964
+ const SignatureInspector = lazyComponent(() => import("./signature-inspector-CsGr9EBk.js").then((ui) => ui.SignatureInspector), { shownWhile: useSignatureInspectorOpen });
3965
+ const PrintDialog = lazyComponent(() => import("./print-dialog-DvcI2m2_.js").then((ui) => ui.PrintDialog), { shownWhile: usePrintDialogOpen });
3966
+ const useOutlinePropertiesOpen = () => useSurface(OUTLINE_PROPERTIES_DIALOG).isOpen;
3967
+ const OutlinePropertiesDialog = lazyComponent(() => import("./outline-properties-BCa2cc0t.js").then((ui) => ui.OutlinePropertiesDialog), { shownWhile: useOutlinePropertiesOpen });
3416
3968
  /** The document tabs, as the layout says: always, while more than one document is open, or never. */
3417
3969
  function DocumentTabs() {
3418
3970
  const visibility = tabsOf(useResolvedLayout().data);
@@ -3537,8 +4089,11 @@ function Shell({ components }) {
3537
4089
  /* @__PURE__ */ jsx(RedactConfirmModal, {}),
3538
4090
  /* @__PURE__ */ jsx(CalibrationDialog, {}),
3539
4091
  /* @__PURE__ */ jsx(GoToPageDialog, {}),
4092
+ /* @__PURE__ */ jsx(PrintDialog, {}),
4093
+ /* @__PURE__ */ jsx(OutlinePropertiesDialog, {}),
3540
4094
  /* @__PURE__ */ jsx(ShortcutsSheet, {}),
3541
4095
  /* @__PURE__ */ jsx(SignatureBridge, {}),
4096
+ /* @__PURE__ */ jsx(SidebarReads, {}),
3542
4097
  /* @__PURE__ */ jsx(FeaturePrefetch, {}),
3543
4098
  /* @__PURE__ */ jsx(SignDialog, {}),
3544
4099
  /* @__PURE__ */ jsx(SignatureMakerModal, {})
@@ -3716,6 +4271,8 @@ function FullViewer({ engine, initialDocuments, fallback, commands, icons, strin
3716
4271
  renderPlugin(settings.render),
3717
4272
  pageEditPlugin(),
3718
4273
  metadataPlugin(),
4274
+ outlinePlugin(),
4275
+ attachmentPlugin(),
3719
4276
  interactionPlugin(settings.interaction),
3720
4277
  feedbackPlugin({ provider: vibrationFeedback }),
3721
4278
  selectionPlugin(settings.selection),
@@ -3826,6 +4383,6 @@ function FullViewer({ engine, initialDocuments, fallback, commands, icons, strin
3826
4383
  });
3827
4384
  }
3828
4385
  //#endregion
3829
- export { ActionsToken, AnnotationToken, CommandsToken, DocumentsToken, FormToken, FullViewer, I18nToken, InteractionToken, LinkToken, MeasurementToken, MetadataToken, PageEditToken, RedactionToken, RenderToken, SearchToken, SelectionToken, ShellToken, SignatureToken, StageToken, StampToken, THEME_TOKENS, TOOLBAR_ITEM_CONTEXT_ATTRIBUTES, VIEWER_PLUGINS, createLayout, createPlacedComponents, createTestSigner, createViewer, defaultCommands, ICON_PATHS as defaultIcons, defaultLayout, indexedDbKeyStore, memoryKeyStore, personalSigner, remoteSigner, themeConfigOf, themeTokenCss, webCryptoSigner };
4386
+ export { ActionsToken, AnnotationToken, AttachmentToken, CommandsToken, DocumentsToken, FormToken, FullViewer, I18nToken, InteractionToken, LinkToken, MeasurementToken, MetadataToken, OutlineToken, PageEditToken, RedactionToken, RenderToken, SearchToken, SelectionToken, ShellToken, SignatureToken, StageToken, StampToken, THEME_TOKENS, TOOLBAR_ITEM_CONTEXT_ATTRIBUTES, VIEWER_PLUGINS, createLayout, createPlacedComponents, createTestSigner, createViewer, defaultCommands, ICON_PATHS as defaultIcons, defaultLayout, indexedDbKeyStore, memoryKeyStore, personalSigner, remoteSigner, themeConfigOf, themeTokenCss, webCryptoSigner };
3830
4387
 
3831
4388
  //# sourceMappingURL=index.js.map