@arbidocs/blocks 0.5.123 → 0.5.125

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 (192) hide show
  1. package/dist/{ClippingMediaViewer-IEIBT74X.cjs → ClippingMediaViewer-ZFEX5A3U.cjs} +11 -10
  2. package/dist/ClippingMediaViewer-ZFEX5A3U.cjs.map +1 -0
  3. package/dist/{ClippingPdfViewer-OGYLMVCE.cjs → ClippingPdfViewer-3LRTEPHV.cjs} +45 -11
  4. package/dist/ClippingPdfViewer-3LRTEPHV.cjs.map +1 -0
  5. package/dist/ConnectedCallDock-XJOYVVAH.cjs +6 -6
  6. package/dist/ConnectedCallRoom-CUDYAPQK.cjs +6 -6
  7. package/dist/{ConnectedNativeDocxComparison-QKHCYD6W.cjs → ConnectedNativeDocxComparison-7QQ55JIO.cjs} +13 -13
  8. package/dist/{ConnectedNativeDocxComparison-QKHCYD6W.cjs.map → ConnectedNativeDocxComparison-7QQ55JIO.cjs.map} +1 -1
  9. package/dist/{ConnectedPresentation-5DOJ35XL.cjs → ConnectedPresentation-L32JPRFI.cjs} +30 -156
  10. package/dist/ConnectedPresentation-L32JPRFI.cjs.map +1 -0
  11. package/dist/{ConnectedProductionSetDialog-LHB4VQWC.cjs → ConnectedProductionSetDialog-4EAY6KAZ.cjs} +3 -3
  12. package/dist/{ConnectedProductionSetDialog-LHB4VQWC.cjs.map → ConnectedProductionSetDialog-4EAY6KAZ.cjs.map} +1 -1
  13. package/dist/{ConnectedSlidesTab-7YMEDGUU.cjs → ConnectedSlidesTab-P7GGNUTO.cjs} +31 -29
  14. package/dist/ConnectedSlidesTab-P7GGNUTO.cjs.map +1 -0
  15. package/dist/{ConnectedStreamedWordArtifact-AG62232A.cjs → ConnectedStreamedWordArtifact-7NJ3N52V.cjs} +13 -13
  16. package/dist/{ConnectedStreamedWordArtifact-AG62232A.cjs.map → ConnectedStreamedWordArtifact-7NJ3N52V.cjs.map} +1 -1
  17. package/dist/{DocumentReviewCard-M53XFLI2.cjs → DocumentReviewCard-BFPOFQXI.cjs} +16 -16
  18. package/dist/{DocumentReviewCard-M53XFLI2.cjs.map → DocumentReviewCard-BFPOFQXI.cjs.map} +1 -1
  19. package/dist/{FilesViewerDialog-2QCCRWF2.cjs → FilesViewerDialog-MHUVEZ7M.cjs} +35 -32
  20. package/dist/FilesViewerDialog-MHUVEZ7M.cjs.map +1 -0
  21. package/dist/{NativeDocxEditor-2LQY2CTV.cjs → NativeDocxEditor-SIRYPMBN.cjs} +6 -6
  22. package/dist/{NativeDocxEditor-2LQY2CTV.cjs.map → NativeDocxEditor-SIRYPMBN.cjs.map} +1 -1
  23. package/dist/SpotlightStrip-ED22UYTM.cjs +398 -0
  24. package/dist/SpotlightStrip-ED22UYTM.cjs.map +1 -0
  25. package/dist/{WorkspaceTableView-3XYAV4BV.cjs → WorkspaceTableView-MIFYXV3G.cjs} +8 -8
  26. package/dist/{WorkspaceTableView-3XYAV4BV.cjs.map → WorkspaceTableView-MIFYXV3G.cjs.map} +1 -1
  27. package/dist/agents/index.cjs +216 -216
  28. package/dist/ai-IEIR7SC2.cjs +3 -3
  29. package/dist/auth/index.cjs +1 -1
  30. package/dist/calls/index.cjs +2 -2
  31. package/dist/chat/index.cjs +6 -6
  32. package/dist/{chunk-GNZAH6UI.cjs → chunk-2K6IMIVL.cjs} +3 -3
  33. package/dist/{chunk-GNZAH6UI.cjs.map → chunk-2K6IMIVL.cjs.map} +1 -1
  34. package/dist/{chunk-NQML7IUC.cjs → chunk-3UP32FM3.cjs} +6 -6
  35. package/dist/{chunk-NQML7IUC.cjs.map → chunk-3UP32FM3.cjs.map} +1 -1
  36. package/dist/chunk-3ZZZO4F7.cjs +145 -0
  37. package/dist/chunk-3ZZZO4F7.cjs.map +1 -0
  38. package/dist/{chunk-L4CIFLCU.cjs → chunk-4LP5MJGQ.cjs} +4 -4
  39. package/dist/{chunk-L4CIFLCU.cjs.map → chunk-4LP5MJGQ.cjs.map} +1 -1
  40. package/dist/{chunk-JD2HX2BR.cjs → chunk-6JMW3IJ2.cjs} +152 -155
  41. package/dist/chunk-6JMW3IJ2.cjs.map +1 -0
  42. package/dist/{chunk-WV7BCGCK.cjs → chunk-7RJZIPLE.cjs} +33 -33
  43. package/dist/{chunk-WV7BCGCK.cjs.map → chunk-7RJZIPLE.cjs.map} +1 -1
  44. package/dist/{chunk-WFMWKPGY.cjs → chunk-ADPRIBSH.cjs} +9 -33
  45. package/dist/chunk-ADPRIBSH.cjs.map +1 -0
  46. package/dist/{chunk-7NLO7ASW.cjs → chunk-AISYXX4M.cjs} +4 -4
  47. package/dist/{chunk-7NLO7ASW.cjs.map → chunk-AISYXX4M.cjs.map} +1 -1
  48. package/dist/{chunk-5QERK4PK.cjs → chunk-AS6QZETU.cjs} +35 -35
  49. package/dist/{chunk-5QERK4PK.cjs.map → chunk-AS6QZETU.cjs.map} +1 -1
  50. package/dist/{chunk-V6MW7B4B.cjs → chunk-B3R62764.cjs} +6 -6
  51. package/dist/{chunk-V6MW7B4B.cjs.map → chunk-B3R62764.cjs.map} +1 -1
  52. package/dist/{chunk-VKH3BEZE.cjs → chunk-BLIO3B7Z.cjs} +3 -3
  53. package/dist/{chunk-VKH3BEZE.cjs.map → chunk-BLIO3B7Z.cjs.map} +1 -1
  54. package/dist/{chunk-46P7IDBX.cjs → chunk-CQ2RJYE2.cjs} +4 -4
  55. package/dist/chunk-CQ2RJYE2.cjs.map +1 -0
  56. package/dist/{chunk-MXBXZXXQ.cjs → chunk-ENOPKX7E.cjs} +3 -3
  57. package/dist/{chunk-MXBXZXXQ.cjs.map → chunk-ENOPKX7E.cjs.map} +1 -1
  58. package/dist/{chunk-2CSLFAGF.cjs → chunk-GAMRVB3I.cjs} +4 -3
  59. package/dist/chunk-GAMRVB3I.cjs.map +1 -0
  60. package/dist/chunk-IRGRMJPP.cjs +18 -0
  61. package/dist/{chunk-SDRYSLOX.cjs.map → chunk-IRGRMJPP.cjs.map} +1 -1
  62. package/dist/{chunk-ADDQKZ5I.cjs → chunk-J3FFSEKO.cjs} +4 -4
  63. package/dist/{chunk-ADDQKZ5I.cjs.map → chunk-J3FFSEKO.cjs.map} +1 -1
  64. package/dist/chunk-JITYC4OS.cjs +66 -0
  65. package/dist/chunk-JITYC4OS.cjs.map +1 -0
  66. package/dist/chunk-JY7UUZQG.cjs +1513 -0
  67. package/dist/chunk-JY7UUZQG.cjs.map +1 -0
  68. package/dist/{chunk-ALK3PUUB.cjs → chunk-L6HTZIBD.cjs} +3 -3
  69. package/dist/{chunk-ALK3PUUB.cjs.map → chunk-L6HTZIBD.cjs.map} +1 -1
  70. package/dist/chunk-MVXHTAJ4.cjs +111 -0
  71. package/dist/chunk-MVXHTAJ4.cjs.map +1 -0
  72. package/dist/{chunk-OHHKBURG.cjs → chunk-OGK377NL.cjs} +33 -33
  73. package/dist/{chunk-OHHKBURG.cjs.map → chunk-OGK377NL.cjs.map} +1 -1
  74. package/dist/{chunk-T73BHNQX.cjs → chunk-OHWHYVKG.cjs} +3 -3
  75. package/dist/{chunk-T73BHNQX.cjs.map → chunk-OHWHYVKG.cjs.map} +1 -1
  76. package/dist/{chunk-4TTX6ZNS.cjs → chunk-ORNLCBNE.cjs} +24 -2
  77. package/dist/chunk-ORNLCBNE.cjs.map +1 -0
  78. package/dist/{chunk-MLA2BJ2Y.cjs → chunk-PSB64T43.cjs} +28 -28
  79. package/dist/{chunk-MLA2BJ2Y.cjs.map → chunk-PSB64T43.cjs.map} +1 -1
  80. package/dist/{chunk-COD5ENHK.cjs → chunk-PVJ5ODDB.cjs} +4 -4
  81. package/dist/{chunk-COD5ENHK.cjs.map → chunk-PVJ5ODDB.cjs.map} +1 -1
  82. package/dist/{chunk-7557LDAN.cjs → chunk-PWBRE7JA.cjs} +5 -5
  83. package/dist/{chunk-7557LDAN.cjs.map → chunk-PWBRE7JA.cjs.map} +1 -1
  84. package/dist/{chunk-7PN3YENO.cjs → chunk-QIK7E6VF.cjs} +4 -4
  85. package/dist/{chunk-7PN3YENO.cjs.map → chunk-QIK7E6VF.cjs.map} +1 -1
  86. package/dist/{chunk-DWMWEALB.cjs → chunk-TSFNLY3K.cjs} +143 -1634
  87. package/dist/chunk-TSFNLY3K.cjs.map +1 -0
  88. package/dist/{chunk-YGBHY67W.cjs → chunk-UA7HOLAZ.cjs} +5 -5
  89. package/dist/{chunk-YGBHY67W.cjs.map → chunk-UA7HOLAZ.cjs.map} +1 -1
  90. package/dist/{chunk-KXIRVKCJ.cjs → chunk-UUENH4BJ.cjs} +3 -3
  91. package/dist/{chunk-KXIRVKCJ.cjs.map → chunk-UUENH4BJ.cjs.map} +1 -1
  92. package/dist/chunk-WVZLAAIZ.cjs +31 -0
  93. package/dist/chunk-WVZLAAIZ.cjs.map +1 -0
  94. package/dist/{chunk-E3L5DB5F.cjs → chunk-YOEP3I4V.cjs} +5 -5
  95. package/dist/{chunk-E3L5DB5F.cjs.map → chunk-YOEP3I4V.cjs.map} +1 -1
  96. package/dist/{chunk-SNPK3R3O.cjs → chunk-YVO6Z5BS.cjs} +10 -10
  97. package/dist/{chunk-SNPK3R3O.cjs.map → chunk-YVO6Z5BS.cjs.map} +1 -1
  98. package/dist/chunk-ZZZITHGK.cjs +119 -0
  99. package/dist/chunk-ZZZITHGK.cjs.map +1 -0
  100. package/dist/connect/docx.cjs +17 -17
  101. package/dist/connect/index.cjs +994 -994
  102. package/dist/connect/viewer.cjs +28 -25
  103. package/dist/connection/presentation/ClippingMediaViewer.js +3 -3
  104. package/dist/connection/presentation/ClippingMediaViewer.js.map +2 -2
  105. package/dist/connection/presentation/ClippingPdfViewer.d.ts +4 -3
  106. package/dist/connection/presentation/ClippingPdfViewer.js +48 -9
  107. package/dist/connection/presentation/ClippingPdfViewer.js.map +2 -2
  108. package/dist/connection/presentation/SpotlightLayer.d.ts +5 -0
  109. package/dist/connection/presentation/SpotlightLayer.js +19 -0
  110. package/dist/connection/presentation/SpotlightLayer.js.map +7 -0
  111. package/dist/connection/presentation/SpotlightStrip.d.ts +10 -0
  112. package/dist/connection/presentation/SpotlightStrip.js +237 -0
  113. package/dist/connection/presentation/SpotlightStrip.js.map +7 -0
  114. package/dist/connection/presentation/useViewerClipping.d.ts +4 -3
  115. package/dist/connection/presentation/useViewerClipping.js +8 -4
  116. package/dist/connection/presentation/useViewerClipping.js.map +2 -2
  117. package/dist/connection/viewer/ConnectedDocumentViewer.js +1 -1
  118. package/dist/connection/viewer/ConnectedDocumentViewer.js.map +2 -2
  119. package/dist/connection/viewer/VersionDropdown.js +1 -1
  120. package/dist/connection/viewer/VersionDropdown.js.map +1 -1
  121. package/dist/connection/viewer/ViewerPdfPane.js +2 -0
  122. package/dist/connection/viewer/ViewerPdfPane.js.map +2 -2
  123. package/dist/connection/viewer/pdf/passageHighlights.d.ts +5 -0
  124. package/dist/connection/viewer/pdf/passageHighlights.js +14 -1
  125. package/dist/connection/viewer/pdf/passageHighlights.js.map +2 -2
  126. package/dist/connection/viewer/pdf/usePassageTextFallback.d.ts +12 -0
  127. package/dist/connection/viewer/pdf/usePassageTextFallback.js +30 -0
  128. package/dist/connection/viewer/pdf/usePassageTextFallback.js.map +7 -0
  129. package/dist/connection/viewer/pdf/usePdfPassageHighlights.js +2 -11
  130. package/dist/connection/viewer/pdf/usePdfPassageHighlights.js.map +2 -2
  131. package/dist/connection/viewer/useCleanView.d.ts +3 -1
  132. package/dist/connection/viewer/useCleanView.js +6 -3
  133. package/dist/connection/viewer/useCleanView.js.map +2 -2
  134. package/dist/connection/viewer/useViewerTabs.js +13 -1
  135. package/dist/connection/viewer/useViewerTabs.js.map +2 -2
  136. package/dist/document-tools/DocumentToolButtons.js +1 -1
  137. package/dist/document-tools/DocumentToolButtons.js.map +1 -1
  138. package/dist/document-tools/index.cjs +20 -20
  139. package/dist/docx/DocxCommandMenu.js +2 -1
  140. package/dist/docx/DocxCommandMenu.js.map +2 -2
  141. package/dist/docx/index.cjs +38 -38
  142. package/dist/embed/index.cjs +20 -20
  143. package/dist/facts/index.cjs +64 -64
  144. package/dist/files/index.cjs +223 -223
  145. package/dist/index.cjs +521 -521
  146. package/dist/presentation/ClipCaptureOverlay.d.ts +7 -3
  147. package/dist/presentation/ClipCaptureOverlay.js +43 -14
  148. package/dist/presentation/ClipCaptureOverlay.js.map +2 -2
  149. package/dist/presentation/PresentControls.d.ts +8 -0
  150. package/dist/presentation/PresentControls.js +1 -0
  151. package/dist/presentation/PresentControls.js.map +2 -2
  152. package/dist/presentation/PresentationStage.d.ts +10 -2
  153. package/dist/presentation/PresentationStage.js +6 -3
  154. package/dist/presentation/PresentationStage.js.map +2 -2
  155. package/dist/presentation/PresenterView.js +1 -22
  156. package/dist/presentation/PresenterView.js.map +2 -2
  157. package/dist/presentation/SpotlightView.d.ts +19 -0
  158. package/dist/presentation/SpotlightView.js +180 -0
  159. package/dist/presentation/SpotlightView.js.map +7 -0
  160. package/dist/presentation/passage-clip.d.ts +17 -0
  161. package/dist/presentation/passage-clip.js +25 -0
  162. package/dist/presentation/passage-clip.js.map +7 -0
  163. package/dist/presentation/spotlight.d.ts +58 -0
  164. package/dist/presentation/spotlight.js +110 -0
  165. package/dist/presentation/spotlight.js.map +7 -0
  166. package/dist/presentation/store.d.ts +5 -0
  167. package/dist/presentation/store.js +19 -0
  168. package/dist/presentation/store.js.map +2 -2
  169. package/dist/presentation/usePointerActive.d.ts +2 -0
  170. package/dist/presentation/usePointerActive.js +28 -0
  171. package/dist/presentation/usePointerActive.js.map +7 -0
  172. package/dist/settings/index.cjs +146 -146
  173. package/dist/site/index.cjs +6 -6
  174. package/dist/studio/index.cjs +9 -9
  175. package/dist/styles.css +1 -1
  176. package/dist/workflow-canvas/index.cjs +35 -35
  177. package/node_modules/@arbidocs/coedit/package.json +1 -1
  178. package/package.json +5 -5
  179. package/dist/ClippingMediaViewer-IEIBT74X.cjs.map +0 -1
  180. package/dist/ClippingPdfViewer-OGYLMVCE.cjs.map +0 -1
  181. package/dist/ConnectedPresentation-5DOJ35XL.cjs.map +0 -1
  182. package/dist/ConnectedSlidesTab-7YMEDGUU.cjs.map +0 -1
  183. package/dist/FilesViewerDialog-2QCCRWF2.cjs.map +0 -1
  184. package/dist/chunk-2CSLFAGF.cjs.map +0 -1
  185. package/dist/chunk-46P7IDBX.cjs.map +0 -1
  186. package/dist/chunk-4TTX6ZNS.cjs.map +0 -1
  187. package/dist/chunk-DWMWEALB.cjs.map +0 -1
  188. package/dist/chunk-JD2HX2BR.cjs.map +0 -1
  189. package/dist/chunk-SDRYSLOX.cjs +0 -18
  190. package/dist/chunk-WFMWKPGY.cjs.map +0 -1
  191. package/dist/chunk-XK4TVJKD.cjs +0 -73
  192. package/dist/chunk-XK4TVJKD.cjs.map +0 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/presentation/store.ts"],
4
- "sourcesContent": ["/**\n * The presentation of this session: the clips taken, the slides they are arranged on, the slide on\n * the stage, whether the stage is blanked and whether the presentation window presents (shows only\n * the stage, for sharing) or edits. Clips taken in the app's viewer land in it at once.\n *\n * Kept in memory only: a clip holds the decrypted PDF it is drawn from, so nothing is written to\n * storage, and everything is cleared when the session signs out (`ConnectedPresentation`).\n */\n\nimport { create } from 'zustand'\nimport { releasePdfRegionSource } from '@arbidocs/react/viewers'\nimport {\n alignFrame,\n autoLayout,\n defaultCaption,\n dropFrame,\n fitFrame,\n fullHeightFrame,\n fullWidthFrame,\n moveFrame,\n type Alignment,\n type Clip,\n type Rect,\n type Reserve,\n type Frame,\n type Slide,\n type SlideLayout,\n} from './model'\nimport { slideGeometry } from './slide-layout'\nimport { DEFAULT_THEME, type Theme } from './theme'\nimport { serializePresentation } from './persistence'\nimport { nextBoxId, withText, type SlideBackground, type SlideBox } from './boxes'\nimport type { SavedBox } from './saved-boxes'\n\n/** The smallest a clip's area can be zoomed to (a fraction of its source, either side). */\nconst MIN_CLIP_AREA = 0.02\n\n/** A slide holds a handful of clips: more would be too small to read on a shared screen. */\nexport const MAX_ITEMS_PER_SLIDE = 6\n/** A new clip goes on the slide by itself while the slide has fewer than this. */\nconst AUTO_PLACE_BELOW = 2\n\nexport type NewClip = Omit<Clip, 'id' | 'caption'> & { caption?: string }\nexport type FrameCommand = 'fullWidth' | 'fullHeight' | 'fit'\n\ninterface PresentationState {\n clips: Clip[]\n slides: Slide[]\n /** Index of the slide on the stage. */\n current: number\n /** The stage shows nothing (black) while true. */\n blank: boolean\n captions: boolean\n /** One look for every slide: background, typeface, accent, logo. Saved. */\n theme: Theme\n /** The theme's logo image (this session only; fetched by the host from `theme.logo`). */\n logoImage: Blob | null\n /**\n * The annotation column (a tag's id) whose value for each clip's document leads its label: an\n * Exhibit column's \"R-100\". Saved with the presentation.\n */\n labelColumn: string | null\n /** Each clip document's value in `labelColumn`, kept current by the host (not saved). */\n columnValues: Readonly<Record<string, string>>\n /** Present mode: the presentation window shows only the stage (what is shared). */\n presenting: boolean\n /** The presentation's name (its file's, once saved). */\n title: string\n /** The document it is saved as, once saved: saving again adds a version to it. */\n savedId: string | null\n /** Which version of that document this is (as opened or saved), when known. */\n version: number | null\n /**\n * The document (or draft) this presentation is edited as, in the viewer: its slides tab shows\n * it. Null: clips gathered with no presentation open yet (a new one takes them).\n */\n boundTo: string | null\n /** The presentation as last opened or saved (serialised), to tell unsaved changes; null: never. */\n clean: string | null\n /**\n * A message for the presentation window itself (saved, failed\u2026): the app's notifications show in\n * the app's window, out of sight behind a popped-out presentation.\n */\n notice: { text: string; kind: 'success' | 'error'; id: number } | null\n /** The clip being dragged from the tray, while it is (the drop targets light up). */\n dragging: string | null\n /** Images embedded in the presentation (an imported deck's pictures), as data URLs, by key. */\n media: Readonly<Record<string, string>>\n}\n\ninterface PresentationActions {\n /** Add a clip; it is placed on the current slide while that has fewer than two. */\n addClip(clip: NewClip): string\n removeClip(clipId: string): void\n setCaption(clipId: string, caption: string): void\n /** Put a clip on the current slide (at a point, when dropped there). */\n place(clipId: string, at?: { x: number; y: number }): void\n unplace(clipId: string): void\n /** Move or resize a clip by hand: the slide stops arranging itself. */\n setFrame(clipId: string, frame: Frame): void\n applyFrame(clipId: string, command: FrameCommand): void\n /** Overlapping clips: this one on top of the others (later items are drawn over earlier ones). */\n bringToFront(clipId: string): void\n /** Overlapping clips: this one under the others. */\n sendToBack(clipId: string): void\n /**\n * Scroll what a clip shows over its page, image or video by `dx, dy` (fractions of the source),\n * its size kept and kept within the source: e.g. to show the lines above or below a passage.\n */\n panClip(clipId: string, dx: number, dy: number): void\n /**\n * Zoom what a clip shows by `factor` (2: twice as close) about its centre: its area over the\n * source shrinks or grows, its shape kept, never past the source's edges.\n */\n zoomClip(clipId: string, factor: number): void\n /** Zoom a clip to `percent` of how close it was cut (100: as cut), about its centre. */\n setClipZoom(clipId: string, percent: number): void\n /** Align a clip on the stage (inside the margins and the slide's reserved room). */\n align(clipId: string, alignment: Alignment): void\n /** Nudge a clip by `dx, dy` (stage fractions), kept on the stage, not snapped. */\n nudge(clipId: string, dx: number, dy: number): void\n /** The current slide's caption (shown across its top; empty for none). */\n /** A slide's title (default the current slide's). */\n setSlideCaption(caption: string, index?: number): void\n /** The current slide's layout: it is arranged for it again. */\n setSlideLayout(layout: SlideLayout, index?: number): void\n /** The current slide's text (its points, or subtitle). */\n setSlidePoints(points: string, index?: number): void\n /** Change the theme; slides arranging themselves make room for a logo (or give it back). */\n setTheme(change: Partial<Theme>): void\n setLogoImage(image: Blob | null): void\n /** Arrange the current slide automatically again. */\n arrange(): void\n /** A new slide after the current one (by default with the current slide's layout). */\n addSlide(layout?: SlideLayout, after?: number): void\n /** Remove a slide (default the current one); the last one left is emptied instead. */\n removeSlide(index?: number): void\n /** A copy of a slide (its title, points and clips), right after it. */\n duplicateSlide(index: number): void\n /** Move a slide to `to` (the others shift up or down). */\n moveSlide(index: number, to: number): void\n goTo(index: number): void\n setBlank(blank: boolean): void\n setCaptions(captions: boolean): void\n setLabelColumn(tagId: string | null): void\n setColumnValues(values: Readonly<Record<string, string>>): void\n setPresenting(presenting: boolean): void\n setDragging(clipId: string | null): void\n setTitle(title: string): void\n notify(text: string, kind: 'success' | 'error'): void\n clearNotice(id: number): void\n /** Show another part of an image or video clip's source (a new crop): its area and shape. */\n cropClip(clipId: string, rect: Rect, aspect: number): void\n /**\n * A clip reshaped on the current slide (`reshapeFrame`): it shows `rect` of its source, in\n * `frame`, at the same scale and zoom. Slides arranging themselves arrange around its new shape.\n */\n reshapeClip(clipId: string, frame: Frame, rect: Rect, aspect: number): void\n /** A text box or shape on a slide (default the current one), on top; resolves with its id. */\n addBox(box: Omit<SlideBox, 'id'>, index?: number): string\n /** Change a box (wherever it is). */\n updateBox(boxId: string, change: (box: SlideBox) => SlideBox): void\n /** Type a box's text (one paragraph per line, each keeping its style). */\n setBoxText(boxId: string, text: string): void\n removeBox(boxId: string): void\n /** A box over the slide's clips and other boxes, or under them all. */\n restackBox(boxId: string, to: 'front' | 'back'): void\n /** A slide's speaker notes (default the current slide's). */\n setSlideNotes(notes: string, index?: number): void\n /** A slide's own background (none: the theme's). */\n setSlideBackground(background: SlideBackground | undefined, index?: number): void\n /** Saved as this document (under this title), as its `version`. */\n setSaved(savedId: string, title: string, version?: number | null): void\n /** Edited as this document or draft (see `boundTo`). */\n bind(boundTo: string | null): void\n /** Clips gathered before (with no presentation open), added to the tray, not placed. */\n adoptClips(clips: readonly Clip[]): void\n /** Replace the presentation with one opened from a file (its clips' sources fetched). */\n load(opened: {\n title: string\n /** The document it is saved as; null for a new one (from a template). */\n savedId: string | null\n /** Its version, when known. */\n version?: number | null\n /** Edited as (default `savedId`): an older file opened unsaved is still its own. */\n boundTo?: string | null\n captions: boolean\n labelColumn?: string | null\n theme?: Theme\n clips: Omit<Clip, 'id'>[]\n slides: {\n caption: string\n auto: boolean\n layout?: SlideLayout\n points?: string\n items: { clip: number; frame: Frame }[]\n boxes?: readonly SavedBox[]\n background?: SlideBackground\n notes?: string\n }[]\n media?: Readonly<Record<string, string>>\n }): void\n reset(): void\n}\n\nexport type PresentationStore = PresentationState & PresentationActions\n\nlet sequence = 0\nconst nextId = (kind: string) => `${kind}-${Date.now().toString(36)}-${++sequence}`\n\nconst emptySlide = (layout: SlideLayout = 'clips'): Slide => ({\n id: nextId('slide'),\n items: [],\n auto: true,\n caption: '',\n layout,\n points: '',\n boxes: [],\n})\n\nconst initialState = (): PresentationState => ({\n clips: [],\n slides: [emptySlide()],\n current: 0,\n blank: false,\n captions: true,\n theme: DEFAULT_THEME,\n logoImage: null,\n labelColumn: null,\n columnValues: {},\n presenting: false,\n dragging: null,\n notice: null,\n title: 'Untitled presentation',\n savedId: null,\n version: null,\n boundTo: null,\n clean: null,\n media: {},\n})\n\n/** What arranging a slide depends on besides its clips: labels shown, a logo in the footer. */\ntype Look = Pick<PresentationState, 'captions' | 'theme'>\n\n/** The slide arranged again from its clips' aspects, in the room its layout leaves them. */\nfunction arranged(slide: Slide, clips: readonly Clip[], look: Look): Slide {\n const aspects = slide.items.map((item) => aspectOf(clips, item.clipId))\n const frames = autoLayout(aspects, reserveOf(slide, look))\n return {\n ...slide,\n auto: true,\n items: slide.items.map((item, i) => ({ ...item, frame: frames[i] })),\n }\n}\n\n/**\n * The room a slide keeps free of clips: its title and text (by its layout), each clip's label\n * under it, the footer while a logo shows.\n */\nexport const reserveOf = (slide: Pick<Slide, 'caption' | 'layout'>, look: Look): Reserve =>\n slideGeometry(slide, { labels: look.captions, logo: look.theme.logo?.corner ?? null }).reserve\n\nfunction aspectOf(clips: readonly Clip[], clipId: string): number {\n return clips.find((clip) => clip.id === clipId)?.aspect ?? 1\n}\n\nexport const usePresentation = create<PresentationStore>()((set, get) => {\n /** Change the current slide; an auto slide is arranged again after the change. */\n const updateSlide = (change: (slide: Slide, clips: readonly Clip[]) => Slide, at?: number) =>\n set((state) => {\n const index = at ?? state.current\n const slide = state.slides[index]\n if (!slide) return state\n const next = change(slide, state.clips)\n if (next === slide) return state\n const slides = state.slides.slice()\n slides[index] = next.auto ? arranged(next, state.clips, state) : next\n return { slides }\n })\n\n /** Change the boxes of the slide holding `boxId` (`at`: the box's index there). */\n const updateBoxes = (\n boxId: string,\n change: (boxes: readonly SlideBox[], at: number) => SlideBox[]\n ) =>\n set((state) => {\n const index = state.slides.findIndex((slide) => slide.boxes.some((box) => box.id === boxId))\n if (index < 0) return state\n const slide = state.slides[index]\n const slides = state.slides.slice()\n slides[index] = {\n ...slide,\n boxes: change(\n slide.boxes,\n slide.boxes.findIndex((box) => box.id === boxId)\n ),\n }\n return { slides }\n })\n\n /** Restack a clip on the current slide: only the drawing order changes, never a position. */\n const restack = (clipId: string, to: 'front' | 'back') =>\n set((state) => {\n const slide = state.slides[state.current]\n const item = slide?.items.find((entry) => entry.clipId === clipId)\n if (!slide || !item) return state\n const rest = slide.items.filter((entry) => entry !== item)\n const items = to === 'front' ? [...rest, item] : [item, ...rest]\n if (items.every((entry, i) => entry === slide.items[i])) return state\n const slides = state.slides.slice()\n slides[state.current] = { ...slide, items }\n return { slides }\n })\n\n return {\n ...initialState(),\n\n addClip(clip) {\n const id = nextId('clip')\n const full: Clip = {\n ...clip,\n id,\n caption: clip.caption ?? defaultCaption(clip.fileName, clip.page),\n zoomBase: clip.zoomBase ?? clip.rect.w,\n }\n set((state) => ({ clips: [...state.clips, full] }))\n const slide = get().slides[get().current]\n if (slide && slide.items.length < AUTO_PLACE_BELOW) get().place(id)\n return id\n },\n\n removeClip(clipId) {\n const { clips, slides } = get()\n const removed = clips.find((clip) => clip.id === clipId)\n if (!removed) return\n const rest = clips.filter((clip) => clip.id !== clipId)\n set({\n clips: rest,\n slides: slides.map((slide) => {\n if (!slide.items.some((item) => item.clipId === clipId)) return slide\n const next = { ...slide, items: slide.items.filter((item) => item.clipId !== clipId) }\n return next.auto ? arranged(next, rest, get()) : next\n }),\n })\n // The PDF engine's copy of the file goes once no clip is drawn from it.\n if (!rest.some((clip) => clip.source === removed.source))\n releasePdfRegionSource(removed.source)\n },\n\n setCaption: (clipId, caption) =>\n set((state) => ({\n clips: state.clips.map((clip) => (clip.id === clipId ? { ...clip, caption } : clip)),\n })),\n\n place: (clipId, at) =>\n updateSlide((slide, clips) => {\n if (!clips.some((clip) => clip.id === clipId)) return slide\n const others = slide.items.filter((item) => item.clipId !== clipId)\n if (!at && others.length < slide.items.length) return slide\n if (others.length >= MAX_ITEMS_PER_SLIDE) return slide\n const aspect = aspectOf(clips, clipId)\n // An auto slide arranges it with the rest. A slide arranged by hand stays so: the clip goes\n // where it was dropped, or in the middle.\n const frame = slide.auto ? fitFrame(aspect) : dropFrame(aspect, at ?? { x: 0.5, y: 0.5 })\n return { ...slide, items: [...others, { clipId, frame }] }\n }),\n\n unplace: (clipId) =>\n updateSlide((slide) =>\n slide.items.some((item) => item.clipId === clipId)\n ? { ...slide, items: slide.items.filter((item) => item.clipId !== clipId) }\n : slide\n ),\n\n setFrame: (clipId, frame) =>\n updateSlide((slide) => ({\n ...slide,\n auto: false,\n items: slide.items.map((item) => (item.clipId === clipId ? { ...item, frame } : item)),\n })),\n\n applyFrame(clipId, command) {\n const slide = get().slides[get().current]\n const item = slide?.items.find((entry) => entry.clipId === clipId)\n if (!item) return\n const aspect = aspectOf(get().clips, clipId)\n const reserve = reserveOf(slide, get())\n const frame =\n command === 'fullWidth'\n ? fullWidthFrame(item.frame, aspect, reserve)\n : command === 'fullHeight'\n ? fullHeightFrame(item.frame, aspect, reserve)\n : fitFrame(aspect, reserve)\n get().setFrame(clipId, frame)\n // Made the size of the stage, it goes on top of the others.\n get().bringToFront(clipId)\n },\n\n bringToFront: (clipId) => restack(clipId, 'front'),\n sendToBack: (clipId) => restack(clipId, 'back'),\n\n panClip: (clipId, dx, dy) =>\n set((state) => {\n const clip = state.clips.find((entry) => entry.id === clipId)\n if (!clip) return state\n const { rect } = clip\n const x = Math.min(Math.max(rect.x + dx, 0), 1 - rect.w)\n const y = Math.min(Math.max(rect.y + dy, 0), 1 - rect.h)\n if (x === rect.x && y === rect.y) return state\n return {\n clips: state.clips.map((entry) =>\n entry === clip ? { ...clip, rect: { ...rect, x, y } } : entry\n ),\n }\n }),\n\n zoomClip: (clipId, factor) =>\n set((state) => {\n const clip = state.clips.find((entry) => entry.id === clipId)\n if (!clip || !(factor > 0)) return state\n const { rect } = clip\n // Its area scales by 1/factor; never larger than the source, nor smaller than a sliver.\n const largest = Math.min(1 / rect.w, 1 / rect.h)\n const smallest = Math.max(MIN_CLIP_AREA / rect.w, MIN_CLIP_AREA / rect.h)\n const scale = Math.min(Math.max(1 / factor, smallest), largest)\n if (scale === 1) return state\n const w = rect.w * scale\n const h = rect.h * scale\n const x = Math.min(Math.max(rect.x + (rect.w - w) / 2, 0), 1 - w)\n const y = Math.min(Math.max(rect.y + (rect.h - h) / 2, 0), 1 - h)\n return {\n clips: state.clips.map((entry) =>\n entry === clip ? { ...clip, rect: { x, y, w, h } } : entry\n ),\n }\n }),\n\n setClipZoom(clipId, percent) {\n const clip = get().clips.find((entry) => entry.id === clipId)\n if (!clip || !(percent > 0)) return\n const width = (clip.zoomBase ?? clip.rect.w) / (percent / 100)\n get().zoomClip(clipId, clip.rect.w / width)\n },\n\n align(clipId, alignment) {\n const slide = get().slides[get().current]\n const item = slide?.items.find((entry) => entry.clipId === clipId)\n if (!slide || !item) return\n const aspect = aspectOf(get().clips, clipId)\n get().setFrame(clipId, alignFrame(item.frame, aspect, alignment, reserveOf(slide, get())))\n },\n\n nudge(clipId, dx, dy) {\n const slide = get().slides[get().current]\n const item = slide?.items.find((entry) => entry.clipId === clipId)\n if (!item) return\n const aspect = aspectOf(get().clips, clipId)\n get().setFrame(clipId, moveFrame(item.frame, aspect, dx, dy, [], true).frame)\n },\n\n // An auto slide makes (or gives back) the caption's room; one arranged by hand keeps its places.\n // A blank slide's title is its title box's text.\n setSlideCaption: (caption, index) =>\n updateSlide(\n (slide) => ({\n ...slide,\n caption,\n boxes: slide.boxes.map((box) => (box.role === 'title' ? withText(box, caption) : box)),\n }),\n index\n ),\n setSlideLayout: (layout, index) =>\n updateSlide((slide) => ({ ...slide, layout, auto: true }), index),\n setSlidePoints: (points, index) => updateSlide((slide) => ({ ...slide, points }), index),\n\n setTheme: (change) =>\n set((state) => {\n const theme = { ...state.theme, ...change }\n const logoMoved = (theme.logo?.corner ?? null) !== (state.theme.logo?.corner ?? null)\n return {\n theme,\n ...(theme.logo?.documentId !== state.theme.logo?.documentId ? { logoImage: null } : {}),\n slides: logoMoved\n ? state.slides.map((slide) =>\n slide.auto ? arranged(slide, state.clips, { ...state, theme }) : slide\n )\n : state.slides,\n }\n }),\n setLogoImage: (logoImage) => set({ logoImage }),\n\n arrange: () => updateSlide((slide) => ({ ...slide, auto: true })),\n\n addSlide: (layout, after) =>\n set((state) => {\n const at = (after ?? state.current) + 1\n const slides = state.slides.slice()\n const before = state.slides[at - 1]\n const slide = emptySlide(layout ?? before?.layout ?? 'clips')\n // The slide it follows keeps its look (an imported deck's background).\n slides.splice(\n at,\n 0,\n before?.background ? { ...slide, background: before.background } : slide\n )\n return { slides, current: at }\n }),\n\n removeSlide: (index) =>\n set((state) => {\n const target = index ?? state.current\n if (state.slides.length <= 1) return { slides: [emptySlide()], current: 0 }\n const slides = state.slides.filter((_, i) => i !== target)\n const current = state.current > target ? state.current - 1 : state.current\n return { slides, current: Math.min(current, slides.length - 1) }\n }),\n\n duplicateSlide: (index) =>\n set((state) => {\n const slide = state.slides[index]\n if (!slide) return state\n const slides = state.slides.slice()\n slides.splice(index + 1, 0, {\n ...slide,\n id: nextId('slide'),\n items: slide.items.map((item) => ({ ...item, frame: { ...item.frame } })),\n boxes: slide.boxes.map((box) => ({ ...box, id: nextBoxId() })),\n })\n return { slides, current: index + 1 }\n }),\n\n moveSlide: (index, to) =>\n set((state) => {\n if (to < 0 || to >= state.slides.length || index === to || !state.slides[index]) {\n return state\n }\n const slides = state.slides.slice()\n const [slide] = slides.splice(index, 1)\n slides.splice(to, 0, slide)\n return { slides, current: to }\n }),\n\n goTo: (index) =>\n set((state) =>\n index < 0 || index >= state.slides.length || index === state.current\n ? state\n : { current: index }\n ),\n\n setBlank: (blank) => set({ blank }),\n // Slides arranged automatically make (or give back) the captions' room.\n setCaptions: (captions) =>\n set((state) => ({\n captions,\n slides: state.slides.map((slide) =>\n slide.auto ? arranged(slide, state.clips, { ...state, captions }) : slide\n ),\n })),\n setLabelColumn: (labelColumn) => set({ labelColumn }),\n setColumnValues: (columnValues) => set({ columnValues }),\n setPresenting: (presenting) => set({ presenting }),\n setDragging: (dragging) => set({ dragging }),\n setTitle: (title) => set({ title }),\n notify: (text, kind) => set({ notice: { text, kind, id: ++sequence } }),\n clearNotice: (id) => set((state) => (state.notice?.id === id ? { notice: null } : state)),\n\n cropClip: (clipId, rect, aspect) =>\n set((state) => {\n const clips = state.clips.map((clip) =>\n clip.id === clipId ? { ...clip, rect, aspect } : clip\n )\n return {\n clips,\n // Its shape changed: slides arranged automatically arrange again around it.\n slides: state.slides.map((slide) =>\n slide.auto && slide.items.some((item) => item.clipId === clipId)\n ? arranged(slide, clips, state)\n : slide\n ),\n }\n }),\n reshapeClip: (clipId, frame, rect, aspect) =>\n set((state) => {\n const clip = state.clips.find((entry) => entry.id === clipId)\n if (!clip) return state\n // Its zoom reads against its width when cut: that scales with the width it now shows.\n const zoomBase = ((clip.zoomBase ?? clip.rect.w) * rect.w) / clip.rect.w\n const clips = state.clips.map((entry) =>\n entry === clip ? { ...clip, rect, aspect, zoomBase } : entry\n )\n return {\n clips,\n slides: state.slides.map((slide, index) => {\n if (index === state.current) {\n return {\n ...slide,\n auto: false,\n items: slide.items.map((item) =>\n item.clipId === clipId ? { ...item, frame } : item\n ),\n }\n }\n return slide.auto && slide.items.some((item) => item.clipId === clipId)\n ? arranged(slide, clips, state)\n : slide\n }),\n }\n }),\n addBox(box, index) {\n const id = nextBoxId()\n updateSlide((slide) => ({ ...slide, boxes: [...slide.boxes, { ...box, id }] }), index)\n return id\n },\n updateBox: (boxId, change) =>\n updateBoxes(boxId, (boxes, at) => {\n const next = boxes.slice()\n next[at] = change(boxes[at])\n return next\n }),\n setBoxText(boxId, text) {\n get().updateBox(boxId, (box) => withText(box, text))\n // A blank slide's title box is its title too (what an outline reads).\n set((state) => ({\n slides: state.slides.map((slide) =>\n slide.boxes.some((box) => box.id === boxId && box.role === 'title')\n ? { ...slide, caption: text.replace(/\\s*\\n\\s*/g, ' ').trim() }\n : slide\n ),\n }))\n },\n removeBox: (boxId) => updateBoxes(boxId, (boxes, at) => boxes.filter((_, i) => i !== at)),\n restackBox: (boxId, to) =>\n updateBoxes(boxId, (boxes, at) => {\n const box = { ...boxes[at], front: to === 'front' }\n const rest = boxes.filter((_, i) => i !== at)\n return to === 'front' ? [...rest, box] : [box, ...rest]\n }),\n setSlideNotes: (notes, index) => updateSlide((slide) => ({ ...slide, notes }), index),\n setSlideBackground: (background, index) =>\n updateSlide((slide) => {\n const { background: _old, ...rest } = slide\n void _old\n return background ? { ...rest, background } : rest\n }, index),\n setSaved: (savedId, title, version = null) => {\n set({ savedId, title, boundTo: savedId, version })\n set({ clean: snapshotOf(get()) })\n },\n bind: (boundTo) => set({ boundTo }),\n adoptClips: (adopted) =>\n set((state) => ({\n clips: [\n ...state.clips,\n ...adopted.filter((clip) => !state.clips.some((entry) => entry.id === clip.id)),\n ],\n })),\n\n load(opened) {\n get().reset()\n const clips: Clip[] = opened.clips.map((clip) => ({ ...clip, id: nextId('clip') }))\n const slides: Slide[] = opened.slides.map((slide) => ({\n id: nextId('slide'),\n caption: slide.caption,\n auto: slide.auto,\n layout: slide.layout ?? 'clips',\n points: slide.points ?? '',\n // Items whose clip could not be opened are left out.\n items: slide.items\n .filter((item) => clips[item.clip])\n .map((item) => ({ clipId: clips[item.clip].id, frame: item.frame })),\n boxes: (slide.boxes ?? []).map((box) => ({ ...box, id: nextBoxId() })),\n ...(slide.background ? { background: slide.background } : {}),\n ...(slide.notes ? { notes: slide.notes } : {}),\n }))\n set({\n title: opened.title,\n savedId: opened.savedId,\n version: opened.version ?? null,\n boundTo: opened.boundTo ?? opened.savedId,\n captions: opened.captions,\n labelColumn: opened.labelColumn ?? null,\n theme: opened.theme ?? DEFAULT_THEME,\n clips,\n slides: slides.length ? slides : [emptySlide()],\n current: 0,\n media: opened.media ?? {},\n })\n set({ clean: opened.savedId ? snapshotOf(get()) : null })\n },\n\n reset() {\n for (const source of new Set(get().clips.map((clip) => clip.source))) {\n releasePdfRegionSource(source)\n }\n set(initialState())\n },\n }\n})\n\n/** The slide on the stage. */\nexport const currentSlide = (state: PresentationState): Slide | undefined =>\n state.slides[state.current]\n\n/** What is saved of a presentation, as text (to compare). */\nfunction snapshotOf(state: PresentationState): string {\n // Embedded images change only with the clips that show them: left out, so comparing stays cheap.\n return JSON.stringify(serializePresentation({ ...state, media: undefined }))\n}\n\n/**\n * The presentation has changes not saved: since it was opened or saved; or, never saved, anything\n * in it at all (a clip, a title, a point).\n */\nexport function hasUnsavedChanges(state: PresentationState): boolean {\n if (state.clean !== null) return snapshotOf(state) !== state.clean\n return (\n state.clips.length > 0 ||\n state.slides.some(\n (slide) =>\n slide.items.length || slide.boxes.length || slide.caption.trim() || slide.points.trim()\n )\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * The presentation of this session: the clips taken, the slides they are arranged on, the slide on\n * the stage, whether the stage is blanked and whether the presentation window presents (shows only\n * the stage, for sharing) or edits. Clips taken in the app's viewer land in it at once.\n *\n * Kept in memory only: a clip holds the decrypted PDF it is drawn from, so nothing is written to\n * storage, and everything is cleared when the session signs out (`ConnectedPresentation`).\n */\n\nimport { create } from 'zustand'\nimport { releasePdfRegionSource } from '@arbidocs/react/viewers'\nimport {\n alignFrame,\n autoLayout,\n defaultCaption,\n dropFrame,\n fitFrame,\n fullHeightFrame,\n fullWidthFrame,\n moveFrame,\n type Alignment,\n type Clip,\n type Rect,\n type Reserve,\n type Frame,\n type Slide,\n type SlideLayout,\n} from './model'\nimport { slideGeometry } from './slide-layout'\nimport { DEFAULT_THEME, type Theme } from './theme'\nimport { serializePresentation } from './persistence'\nimport { nextBoxId, withText, type SlideBackground, type SlideBox } from './boxes'\nimport type { SavedBox } from './saved-boxes'\n\n/** The smallest a clip's area can be zoomed to (a fraction of its source, either side). */\nconst MIN_CLIP_AREA = 0.02\n\n/** A slide holds a handful of clips: more would be too small to read on a shared screen. */\nexport const MAX_ITEMS_PER_SLIDE = 6\n/** A new clip goes on the slide by itself while the slide has fewer than this. */\nconst AUTO_PLACE_BELOW = 2\n\nexport type NewClip = Omit<Clip, 'id' | 'caption'> & { caption?: string }\nexport type FrameCommand = 'fullWidth' | 'fullHeight' | 'fit'\n\ninterface PresentationState {\n clips: Clip[]\n slides: Slide[]\n /** Index of the slide on the stage. */\n current: number\n /** The stage shows nothing (black) while true. */\n blank: boolean\n captions: boolean\n /** One look for every slide: background, typeface, accent, logo. Saved. */\n theme: Theme\n /** The theme's logo image (this session only; fetched by the host from `theme.logo`). */\n logoImage: Blob | null\n /**\n * The annotation column (a tag's id) whose value for each clip's document leads its label: an\n * Exhibit column's \"R-100\". Saved with the presentation.\n */\n labelColumn: string | null\n /** Each clip document's value in `labelColumn`, kept current by the host (not saved). */\n columnValues: Readonly<Record<string, string>>\n /** Present mode: the presentation window shows only the stage (what is shared). */\n presenting: boolean\n /** The presentation's name (its file's, once saved). */\n title: string\n /** The document it is saved as, once saved: saving again adds a version to it. */\n savedId: string | null\n /** Which version of that document this is (as opened or saved), when known. */\n version: number | null\n /**\n * The document (or draft) this presentation is edited as, in the viewer: its slides tab shows\n * it. Null: clips gathered with no presentation open yet (a new one takes them).\n */\n boundTo: string | null\n /** The presentation as last opened or saved (serialised), to tell unsaved changes; null: never. */\n clean: string | null\n /**\n * A message for the presentation window itself (saved, failed\u2026): the app's notifications show in\n * the app's window, out of sight behind a popped-out presentation.\n */\n notice: { text: string; kind: 'success' | 'error'; id: number } | null\n /** The clip being dragged from the tray, while it is (the drop targets light up). */\n dragging: string | null\n /** Images embedded in the presentation (an imported deck's pictures), as data URLs, by key. */\n media: Readonly<Record<string, string>>\n}\n\ninterface PresentationActions {\n /** Add a clip; it is placed on the current slide while that has fewer than two. */\n addClip(clip: NewClip): string\n removeClip(clipId: string): void\n setCaption(clipId: string, caption: string): void\n /** Put a clip on the current slide (at a point, when dropped there). */\n place(clipId: string, at?: { x: number; y: number }): void\n unplace(clipId: string): void\n /** Move or resize a clip by hand: the slide stops arranging itself. */\n setFrame(clipId: string, frame: Frame): void\n applyFrame(clipId: string, command: FrameCommand): void\n /** Overlapping clips: this one on top of the others (later items are drawn over earlier ones). */\n bringToFront(clipId: string): void\n /** Overlapping clips: this one under the others. */\n sendToBack(clipId: string): void\n /**\n * Scroll what a clip shows over its page, image or video by `dx, dy` (fractions of the source),\n * its size kept and kept within the source: e.g. to show the lines above or below a passage.\n */\n panClip(clipId: string, dx: number, dy: number): void\n /**\n * Zoom what a clip shows by `factor` (2: twice as close) about its centre: its area over the\n * source shrinks or grows, its shape kept, never past the source's edges.\n */\n zoomClip(clipId: string, factor: number): void\n /** Zoom a clip to `percent` of how close it was cut (100: as cut), about its centre. */\n setClipZoom(clipId: string, percent: number): void\n /** Align a clip on the stage (inside the margins and the slide's reserved room). */\n align(clipId: string, alignment: Alignment): void\n /** Nudge a clip by `dx, dy` (stage fractions), kept on the stage, not snapped. */\n nudge(clipId: string, dx: number, dy: number): void\n /** The current slide's caption (shown across its top; empty for none). */\n /** A slide's title (default the current slide's). */\n setSlideCaption(caption: string, index?: number): void\n /** The current slide's layout: it is arranged for it again. */\n setSlideLayout(layout: SlideLayout, index?: number): void\n /** The current slide's text (its points, or subtitle). */\n setSlidePoints(points: string, index?: number): void\n /** Change the theme; slides arranging themselves make room for a logo (or give it back). */\n setTheme(change: Partial<Theme>): void\n setLogoImage(image: Blob | null): void\n /** Arrange the current slide automatically again. */\n arrange(): void\n /** A new slide after the current one (by default with the current slide's layout). */\n addSlide(layout?: SlideLayout, after?: number): void\n /** Remove a slide (default the current one); the last one left is emptied instead. */\n removeSlide(index?: number): void\n /** A copy of a slide (its title, points and clips), right after it. */\n duplicateSlide(index: number): void\n /** Move a slide to `to` (the others shift up or down). */\n moveSlide(index: number, to: number): void\n goTo(index: number): void\n setBlank(blank: boolean): void\n setCaptions(captions: boolean): void\n setLabelColumn(tagId: string | null): void\n setColumnValues(values: Readonly<Record<string, string>>): void\n setPresenting(presenting: boolean): void\n setDragging(clipId: string | null): void\n setTitle(title: string): void\n notify(text: string, kind: 'success' | 'error'): void\n clearNotice(id: number): void\n /** Show another part of an image or video clip's source (a new crop): its area and shape. */\n cropClip(clipId: string, rect: Rect, aspect: number): void\n /**\n * A clip reshaped on the current slide (`reshapeFrame`): it shows `rect` of its source, in\n * `frame`, at the same scale and zoom. Slides arranging themselves arrange around its new shape.\n */\n reshapeClip(clipId: string, frame: Frame, rect: Rect, aspect: number): void\n /** A text box or shape on a slide (default the current one), on top; resolves with its id. */\n addBox(box: Omit<SlideBox, 'id'>, index?: number): string\n /** Change a box (wherever it is). */\n updateBox(boxId: string, change: (box: SlideBox) => SlideBox): void\n /** Type a box's text (one paragraph per line, each keeping its style). */\n setBoxText(boxId: string, text: string): void\n removeBox(boxId: string): void\n /** A box over the slide's clips and other boxes, or under them all. */\n restackBox(boxId: string, to: 'front' | 'back'): void\n /** A slide's speaker notes (default the current slide's). */\n setSlideNotes(notes: string, index?: number): void\n /** A slide's own background (none: the theme's). */\n setSlideBackground(background: SlideBackground | undefined, index?: number): void\n /** Saved as this document (under this title), as its `version`. */\n setSaved(savedId: string, title: string, version?: number | null): void\n /** Edited as this document or draft (see `boundTo`). */\n bind(boundTo: string | null): void\n /** Clips gathered before (with no presentation open), added to the tray, not placed. */\n adoptClips(clips: readonly Clip[]): void\n /**\n * A slide of these clips (added to the tray too), arranged, with `caption` as its title: after\n * the current slide, or in its place while that is empty. It becomes the current slide.\n */\n addSlideOf(clips: readonly Clip[], caption?: string): void\n /** Replace the presentation with one opened from a file (its clips' sources fetched). */\n load(opened: {\n title: string\n /** The document it is saved as; null for a new one (from a template). */\n savedId: string | null\n /** Its version, when known. */\n version?: number | null\n /** Edited as (default `savedId`): an older file opened unsaved is still its own. */\n boundTo?: string | null\n captions: boolean\n labelColumn?: string | null\n theme?: Theme\n clips: Omit<Clip, 'id'>[]\n slides: {\n caption: string\n auto: boolean\n layout?: SlideLayout\n points?: string\n items: { clip: number; frame: Frame }[]\n boxes?: readonly SavedBox[]\n background?: SlideBackground\n notes?: string\n }[]\n media?: Readonly<Record<string, string>>\n }): void\n reset(): void\n}\n\nexport type PresentationStore = PresentationState & PresentationActions\n\nlet sequence = 0\nconst nextId = (kind: string) => `${kind}-${Date.now().toString(36)}-${++sequence}`\n\nconst emptySlide = (layout: SlideLayout = 'clips'): Slide => ({\n id: nextId('slide'),\n items: [],\n auto: true,\n caption: '',\n layout,\n points: '',\n boxes: [],\n})\n\nconst initialState = (): PresentationState => ({\n clips: [],\n slides: [emptySlide()],\n current: 0,\n blank: false,\n captions: true,\n theme: DEFAULT_THEME,\n logoImage: null,\n labelColumn: null,\n columnValues: {},\n presenting: false,\n dragging: null,\n notice: null,\n title: 'Untitled presentation',\n savedId: null,\n version: null,\n boundTo: null,\n clean: null,\n media: {},\n})\n\n/** What arranging a slide depends on besides its clips: labels shown, a logo in the footer. */\ntype Look = Pick<PresentationState, 'captions' | 'theme'>\n\n/** The slide arranged again from its clips' aspects, in the room its layout leaves them. */\nfunction arranged(slide: Slide, clips: readonly Clip[], look: Look): Slide {\n const aspects = slide.items.map((item) => aspectOf(clips, item.clipId))\n const frames = autoLayout(aspects, reserveOf(slide, look))\n return {\n ...slide,\n auto: true,\n items: slide.items.map((item, i) => ({ ...item, frame: frames[i] })),\n }\n}\n\n/**\n * The room a slide keeps free of clips: its title and text (by its layout), each clip's label\n * under it, the footer while a logo shows.\n */\nexport const reserveOf = (slide: Pick<Slide, 'caption' | 'layout'>, look: Look): Reserve =>\n slideGeometry(slide, { labels: look.captions, logo: look.theme.logo?.corner ?? null }).reserve\n\nfunction aspectOf(clips: readonly Clip[], clipId: string): number {\n return clips.find((clip) => clip.id === clipId)?.aspect ?? 1\n}\n\nexport const usePresentation = create<PresentationStore>()((set, get) => {\n /** Change the current slide; an auto slide is arranged again after the change. */\n const updateSlide = (change: (slide: Slide, clips: readonly Clip[]) => Slide, at?: number) =>\n set((state) => {\n const index = at ?? state.current\n const slide = state.slides[index]\n if (!slide) return state\n const next = change(slide, state.clips)\n if (next === slide) return state\n const slides = state.slides.slice()\n slides[index] = next.auto ? arranged(next, state.clips, state) : next\n return { slides }\n })\n\n /** Change the boxes of the slide holding `boxId` (`at`: the box's index there). */\n const updateBoxes = (\n boxId: string,\n change: (boxes: readonly SlideBox[], at: number) => SlideBox[]\n ) =>\n set((state) => {\n const index = state.slides.findIndex((slide) => slide.boxes.some((box) => box.id === boxId))\n if (index < 0) return state\n const slide = state.slides[index]\n const slides = state.slides.slice()\n slides[index] = {\n ...slide,\n boxes: change(\n slide.boxes,\n slide.boxes.findIndex((box) => box.id === boxId)\n ),\n }\n return { slides }\n })\n\n /** Restack a clip on the current slide: only the drawing order changes, never a position. */\n const restack = (clipId: string, to: 'front' | 'back') =>\n set((state) => {\n const slide = state.slides[state.current]\n const item = slide?.items.find((entry) => entry.clipId === clipId)\n if (!slide || !item) return state\n const rest = slide.items.filter((entry) => entry !== item)\n const items = to === 'front' ? [...rest, item] : [item, ...rest]\n if (items.every((entry, i) => entry === slide.items[i])) return state\n const slides = state.slides.slice()\n slides[state.current] = { ...slide, items }\n return { slides }\n })\n\n return {\n ...initialState(),\n\n addClip(clip) {\n const id = nextId('clip')\n const full: Clip = {\n ...clip,\n id,\n caption: clip.caption ?? defaultCaption(clip.fileName, clip.page),\n zoomBase: clip.zoomBase ?? clip.rect.w,\n }\n set((state) => ({ clips: [...state.clips, full] }))\n const slide = get().slides[get().current]\n if (slide && slide.items.length < AUTO_PLACE_BELOW) get().place(id)\n return id\n },\n\n removeClip(clipId) {\n const { clips, slides } = get()\n const removed = clips.find((clip) => clip.id === clipId)\n if (!removed) return\n const rest = clips.filter((clip) => clip.id !== clipId)\n set({\n clips: rest,\n slides: slides.map((slide) => {\n if (!slide.items.some((item) => item.clipId === clipId)) return slide\n const next = { ...slide, items: slide.items.filter((item) => item.clipId !== clipId) }\n return next.auto ? arranged(next, rest, get()) : next\n }),\n })\n // The PDF engine's copy of the file goes once no clip is drawn from it.\n if (!rest.some((clip) => clip.source === removed.source))\n releasePdfRegionSource(removed.source)\n },\n\n setCaption: (clipId, caption) =>\n set((state) => ({\n clips: state.clips.map((clip) => (clip.id === clipId ? { ...clip, caption } : clip)),\n })),\n\n place: (clipId, at) =>\n updateSlide((slide, clips) => {\n if (!clips.some((clip) => clip.id === clipId)) return slide\n const others = slide.items.filter((item) => item.clipId !== clipId)\n if (!at && others.length < slide.items.length) return slide\n if (others.length >= MAX_ITEMS_PER_SLIDE) return slide\n const aspect = aspectOf(clips, clipId)\n // An auto slide arranges it with the rest. A slide arranged by hand stays so: the clip goes\n // where it was dropped, or in the middle.\n const frame = slide.auto ? fitFrame(aspect) : dropFrame(aspect, at ?? { x: 0.5, y: 0.5 })\n return { ...slide, items: [...others, { clipId, frame }] }\n }),\n\n unplace: (clipId) =>\n updateSlide((slide) =>\n slide.items.some((item) => item.clipId === clipId)\n ? { ...slide, items: slide.items.filter((item) => item.clipId !== clipId) }\n : slide\n ),\n\n setFrame: (clipId, frame) =>\n updateSlide((slide) => ({\n ...slide,\n auto: false,\n items: slide.items.map((item) => (item.clipId === clipId ? { ...item, frame } : item)),\n })),\n\n applyFrame(clipId, command) {\n const slide = get().slides[get().current]\n const item = slide?.items.find((entry) => entry.clipId === clipId)\n if (!item) return\n const aspect = aspectOf(get().clips, clipId)\n const reserve = reserveOf(slide, get())\n const frame =\n command === 'fullWidth'\n ? fullWidthFrame(item.frame, aspect, reserve)\n : command === 'fullHeight'\n ? fullHeightFrame(item.frame, aspect, reserve)\n : fitFrame(aspect, reserve)\n get().setFrame(clipId, frame)\n // Made the size of the stage, it goes on top of the others.\n get().bringToFront(clipId)\n },\n\n bringToFront: (clipId) => restack(clipId, 'front'),\n sendToBack: (clipId) => restack(clipId, 'back'),\n\n panClip: (clipId, dx, dy) =>\n set((state) => {\n const clip = state.clips.find((entry) => entry.id === clipId)\n if (!clip) return state\n const { rect } = clip\n const x = Math.min(Math.max(rect.x + dx, 0), 1 - rect.w)\n const y = Math.min(Math.max(rect.y + dy, 0), 1 - rect.h)\n if (x === rect.x && y === rect.y) return state\n return {\n clips: state.clips.map((entry) =>\n entry === clip ? { ...clip, rect: { ...rect, x, y } } : entry\n ),\n }\n }),\n\n zoomClip: (clipId, factor) =>\n set((state) => {\n const clip = state.clips.find((entry) => entry.id === clipId)\n if (!clip || !(factor > 0)) return state\n const { rect } = clip\n // Its area scales by 1/factor; never larger than the source, nor smaller than a sliver.\n const largest = Math.min(1 / rect.w, 1 / rect.h)\n const smallest = Math.max(MIN_CLIP_AREA / rect.w, MIN_CLIP_AREA / rect.h)\n const scale = Math.min(Math.max(1 / factor, smallest), largest)\n if (scale === 1) return state\n const w = rect.w * scale\n const h = rect.h * scale\n const x = Math.min(Math.max(rect.x + (rect.w - w) / 2, 0), 1 - w)\n const y = Math.min(Math.max(rect.y + (rect.h - h) / 2, 0), 1 - h)\n return {\n clips: state.clips.map((entry) =>\n entry === clip ? { ...clip, rect: { x, y, w, h } } : entry\n ),\n }\n }),\n\n setClipZoom(clipId, percent) {\n const clip = get().clips.find((entry) => entry.id === clipId)\n if (!clip || !(percent > 0)) return\n const width = (clip.zoomBase ?? clip.rect.w) / (percent / 100)\n get().zoomClip(clipId, clip.rect.w / width)\n },\n\n align(clipId, alignment) {\n const slide = get().slides[get().current]\n const item = slide?.items.find((entry) => entry.clipId === clipId)\n if (!slide || !item) return\n const aspect = aspectOf(get().clips, clipId)\n get().setFrame(clipId, alignFrame(item.frame, aspect, alignment, reserveOf(slide, get())))\n },\n\n nudge(clipId, dx, dy) {\n const slide = get().slides[get().current]\n const item = slide?.items.find((entry) => entry.clipId === clipId)\n if (!item) return\n const aspect = aspectOf(get().clips, clipId)\n get().setFrame(clipId, moveFrame(item.frame, aspect, dx, dy, [], true).frame)\n },\n\n // An auto slide makes (or gives back) the caption's room; one arranged by hand keeps its places.\n // A blank slide's title is its title box's text.\n setSlideCaption: (caption, index) =>\n updateSlide(\n (slide) => ({\n ...slide,\n caption,\n boxes: slide.boxes.map((box) => (box.role === 'title' ? withText(box, caption) : box)),\n }),\n index\n ),\n setSlideLayout: (layout, index) =>\n updateSlide((slide) => ({ ...slide, layout, auto: true }), index),\n setSlidePoints: (points, index) => updateSlide((slide) => ({ ...slide, points }), index),\n\n setTheme: (change) =>\n set((state) => {\n const theme = { ...state.theme, ...change }\n const logoMoved = (theme.logo?.corner ?? null) !== (state.theme.logo?.corner ?? null)\n return {\n theme,\n ...(theme.logo?.documentId !== state.theme.logo?.documentId ? { logoImage: null } : {}),\n slides: logoMoved\n ? state.slides.map((slide) =>\n slide.auto ? arranged(slide, state.clips, { ...state, theme }) : slide\n )\n : state.slides,\n }\n }),\n setLogoImage: (logoImage) => set({ logoImage }),\n\n arrange: () => updateSlide((slide) => ({ ...slide, auto: true })),\n\n addSlide: (layout, after) =>\n set((state) => {\n const at = (after ?? state.current) + 1\n const slides = state.slides.slice()\n const before = state.slides[at - 1]\n const slide = emptySlide(layout ?? before?.layout ?? 'clips')\n // The slide it follows keeps its look (an imported deck's background).\n slides.splice(\n at,\n 0,\n before?.background ? { ...slide, background: before.background } : slide\n )\n return { slides, current: at }\n }),\n\n removeSlide: (index) =>\n set((state) => {\n const target = index ?? state.current\n if (state.slides.length <= 1) return { slides: [emptySlide()], current: 0 }\n const slides = state.slides.filter((_, i) => i !== target)\n const current = state.current > target ? state.current - 1 : state.current\n return { slides, current: Math.min(current, slides.length - 1) }\n }),\n\n duplicateSlide: (index) =>\n set((state) => {\n const slide = state.slides[index]\n if (!slide) return state\n const slides = state.slides.slice()\n slides.splice(index + 1, 0, {\n ...slide,\n id: nextId('slide'),\n items: slide.items.map((item) => ({ ...item, frame: { ...item.frame } })),\n boxes: slide.boxes.map((box) => ({ ...box, id: nextBoxId() })),\n })\n return { slides, current: index + 1 }\n }),\n\n moveSlide: (index, to) =>\n set((state) => {\n if (to < 0 || to >= state.slides.length || index === to || !state.slides[index]) {\n return state\n }\n const slides = state.slides.slice()\n const [slide] = slides.splice(index, 1)\n slides.splice(to, 0, slide)\n return { slides, current: to }\n }),\n\n goTo: (index) =>\n set((state) =>\n index < 0 || index >= state.slides.length || index === state.current\n ? state\n : { current: index }\n ),\n\n setBlank: (blank) => set({ blank }),\n // Slides arranged automatically make (or give back) the captions' room.\n setCaptions: (captions) =>\n set((state) => ({\n captions,\n slides: state.slides.map((slide) =>\n slide.auto ? arranged(slide, state.clips, { ...state, captions }) : slide\n ),\n })),\n setLabelColumn: (labelColumn) => set({ labelColumn }),\n setColumnValues: (columnValues) => set({ columnValues }),\n setPresenting: (presenting) => set({ presenting }),\n setDragging: (dragging) => set({ dragging }),\n setTitle: (title) => set({ title }),\n notify: (text, kind) => set({ notice: { text, kind, id: ++sequence } }),\n clearNotice: (id) => set((state) => (state.notice?.id === id ? { notice: null } : state)),\n\n cropClip: (clipId, rect, aspect) =>\n set((state) => {\n const clips = state.clips.map((clip) =>\n clip.id === clipId ? { ...clip, rect, aspect } : clip\n )\n return {\n clips,\n // Its shape changed: slides arranged automatically arrange again around it.\n slides: state.slides.map((slide) =>\n slide.auto && slide.items.some((item) => item.clipId === clipId)\n ? arranged(slide, clips, state)\n : slide\n ),\n }\n }),\n reshapeClip: (clipId, frame, rect, aspect) =>\n set((state) => {\n const clip = state.clips.find((entry) => entry.id === clipId)\n if (!clip) return state\n // Its zoom reads against its width when cut: that scales with the width it now shows.\n const zoomBase = ((clip.zoomBase ?? clip.rect.w) * rect.w) / clip.rect.w\n const clips = state.clips.map((entry) =>\n entry === clip ? { ...clip, rect, aspect, zoomBase } : entry\n )\n return {\n clips,\n slides: state.slides.map((slide, index) => {\n if (index === state.current) {\n return {\n ...slide,\n auto: false,\n items: slide.items.map((item) =>\n item.clipId === clipId ? { ...item, frame } : item\n ),\n }\n }\n return slide.auto && slide.items.some((item) => item.clipId === clipId)\n ? arranged(slide, clips, state)\n : slide\n }),\n }\n }),\n addBox(box, index) {\n const id = nextBoxId()\n updateSlide((slide) => ({ ...slide, boxes: [...slide.boxes, { ...box, id }] }), index)\n return id\n },\n updateBox: (boxId, change) =>\n updateBoxes(boxId, (boxes, at) => {\n const next = boxes.slice()\n next[at] = change(boxes[at])\n return next\n }),\n setBoxText(boxId, text) {\n get().updateBox(boxId, (box) => withText(box, text))\n // A blank slide's title box is its title too (what an outline reads).\n set((state) => ({\n slides: state.slides.map((slide) =>\n slide.boxes.some((box) => box.id === boxId && box.role === 'title')\n ? { ...slide, caption: text.replace(/\\s*\\n\\s*/g, ' ').trim() }\n : slide\n ),\n }))\n },\n removeBox: (boxId) => updateBoxes(boxId, (boxes, at) => boxes.filter((_, i) => i !== at)),\n restackBox: (boxId, to) =>\n updateBoxes(boxId, (boxes, at) => {\n const box = { ...boxes[at], front: to === 'front' }\n const rest = boxes.filter((_, i) => i !== at)\n return to === 'front' ? [...rest, box] : [box, ...rest]\n }),\n setSlideNotes: (notes, index) => updateSlide((slide) => ({ ...slide, notes }), index),\n setSlideBackground: (background, index) =>\n updateSlide((slide) => {\n const { background: _old, ...rest } = slide\n void _old\n return background ? { ...rest, background } : rest\n }, index),\n setSaved: (savedId, title, version = null) => {\n set({ savedId, title, boundTo: savedId, version })\n set({ clean: snapshotOf(get()) })\n },\n bind: (boundTo) => set({ boundTo }),\n adoptClips: (adopted) =>\n set((state) => ({\n clips: [\n ...state.clips,\n ...adopted.filter((clip) => !state.clips.some((entry) => entry.id === clip.id)),\n ],\n })),\n\n addSlideOf: (added, caption = '') =>\n set((state) => {\n const fresh = added.map((clip) => ({ ...clip, id: nextId('clip') }))\n const clips = [...state.clips, ...fresh]\n const slide = arranged(\n {\n ...emptySlide('clips'),\n caption,\n items: fresh.map((clip) => ({ clipId: clip.id, frame: fitFrame(clip.aspect) })),\n },\n clips,\n state\n )\n const here = state.slides[state.current]\n const empty =\n !!here &&\n !here.items.length &&\n !here.boxes.length &&\n !here.caption.trim() &&\n !here.points.trim()\n const at = empty ? state.current : state.current + 1\n const slides = state.slides.slice()\n slides.splice(at, empty ? 1 : 0, slide)\n return { clips, slides, current: at }\n }),\n\n load(opened) {\n get().reset()\n const clips: Clip[] = opened.clips.map((clip) => ({ ...clip, id: nextId('clip') }))\n const slides: Slide[] = opened.slides.map((slide) => ({\n id: nextId('slide'),\n caption: slide.caption,\n auto: slide.auto,\n layout: slide.layout ?? 'clips',\n points: slide.points ?? '',\n // Items whose clip could not be opened are left out.\n items: slide.items\n .filter((item) => clips[item.clip])\n .map((item) => ({ clipId: clips[item.clip].id, frame: item.frame })),\n boxes: (slide.boxes ?? []).map((box) => ({ ...box, id: nextBoxId() })),\n ...(slide.background ? { background: slide.background } : {}),\n ...(slide.notes ? { notes: slide.notes } : {}),\n }))\n set({\n title: opened.title,\n savedId: opened.savedId,\n version: opened.version ?? null,\n boundTo: opened.boundTo ?? opened.savedId,\n captions: opened.captions,\n labelColumn: opened.labelColumn ?? null,\n theme: opened.theme ?? DEFAULT_THEME,\n clips,\n slides: slides.length ? slides : [emptySlide()],\n current: 0,\n media: opened.media ?? {},\n })\n set({ clean: opened.savedId ? snapshotOf(get()) : null })\n },\n\n reset() {\n for (const source of new Set(get().clips.map((clip) => clip.source))) {\n releasePdfRegionSource(source)\n }\n set(initialState())\n },\n }\n})\n\n/** The slide on the stage. */\nexport const currentSlide = (state: PresentationState): Slide | undefined =>\n state.slides[state.current]\n\n/** What is saved of a presentation, as text (to compare). */\nfunction snapshotOf(state: PresentationState): string {\n // Embedded images change only with the clips that show them: left out, so comparing stays cheap.\n return JSON.stringify(serializePresentation({ ...state, media: undefined }))\n}\n\n/**\n * The presentation has changes not saved: since it was opened or saved; or, never saved, anything\n * in it at all (a clip, a title, a point).\n */\nexport function hasUnsavedChanges(state: PresentationState): boolean {\n if (state.clean !== null) return snapshotOf(state) !== state.clean\n return (\n state.clips.length > 0 ||\n state.slides.some(\n (slide) =>\n slide.items.length || slide.boxes.length || slide.caption.trim() || slide.points.trim()\n )\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["slide"]
7
7
  }
@@ -0,0 +1,2 @@
1
+ /** The pointer has moved (or a key was pressed) in `view` within the last moment. */
2
+ export declare function usePointerActive(view: Window | null): boolean;
@@ -0,0 +1,28 @@
1
+ "use client";
2
+ import { useEffect, useState } from "react";
3
+ const IDLE_MS = 2200;
4
+ function usePointerActive(view) {
5
+ const [active, setActive] = useState(true);
6
+ useEffect(() => {
7
+ if (!view) return;
8
+ setActive(true);
9
+ let timer = view.setTimeout(() => setActive(false), IDLE_MS);
10
+ const wake = () => {
11
+ setActive(true);
12
+ view.clearTimeout(timer);
13
+ timer = view.setTimeout(() => setActive(false), IDLE_MS);
14
+ };
15
+ view.addEventListener("pointermove", wake);
16
+ view.addEventListener("keydown", wake);
17
+ return () => {
18
+ view.clearTimeout(timer);
19
+ view.removeEventListener("pointermove", wake);
20
+ view.removeEventListener("keydown", wake);
21
+ };
22
+ }, [view]);
23
+ return active;
24
+ }
25
+ export {
26
+ usePointerActive
27
+ };
28
+ //# sourceMappingURL=usePointerActive.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/presentation/usePointerActive.ts"],
4
+ "sourcesContent": ["import { useEffect, useState } from 'react'\n\n/** How long the pointer (or a key) has to rest before the controls fade. */\nconst IDLE_MS = 2200\n\n/** The pointer has moved (or a key was pressed) in `view` within the last moment. */\nexport function usePointerActive(view: Window | null): boolean {\n const [active, setActive] = useState(true)\n useEffect(() => {\n if (!view) return\n setActive(true)\n let timer = view.setTimeout(() => setActive(false), IDLE_MS)\n const wake = () => {\n setActive(true)\n view.clearTimeout(timer)\n timer = view.setTimeout(() => setActive(false), IDLE_MS)\n }\n view.addEventListener('pointermove', wake)\n view.addEventListener('keydown', wake)\n return () => {\n view.clearTimeout(timer)\n view.removeEventListener('pointermove', wake)\n view.removeEventListener('keydown', wake)\n }\n }, [view])\n return active\n}\n"],
5
+ "mappings": ";AAAA,SAAS,WAAW,gBAAgB;AAGpC,MAAM,UAAU;AAGT,SAAS,iBAAiB,MAA8B;AAC7D,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,IAAI;AACzC,YAAU,MAAM;AACd,QAAI,CAAC,KAAM;AACX,cAAU,IAAI;AACd,QAAI,QAAQ,KAAK,WAAW,MAAM,UAAU,KAAK,GAAG,OAAO;AAC3D,UAAM,OAAO,MAAM;AACjB,gBAAU,IAAI;AACd,WAAK,aAAa,KAAK;AACvB,cAAQ,KAAK,WAAW,MAAM,UAAU,KAAK,GAAG,OAAO;AAAA,IACzD;AACA,SAAK,iBAAiB,eAAe,IAAI;AACzC,SAAK,iBAAiB,WAAW,IAAI;AACrC,WAAO,MAAM;AACX,WAAK,aAAa,KAAK;AACvB,WAAK,oBAAoB,eAAe,IAAI;AAC5C,WAAK,oBAAoB,WAAW,IAAI;AAAA,IAC1C;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AACT,SAAO;AACT;",
6
+ "names": []
7
+ }