@arbidocs/blocks 0.5.122 → 0.5.124

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 (124) 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/{ConnectedPresentation-AU25OW25.cjs → ConnectedPresentation-OV2KBOLK.cjs} +27 -153
  6. package/dist/ConnectedPresentation-OV2KBOLK.cjs.map +1 -0
  7. package/dist/{ConnectedSlidesTab-I75LKKN7.cjs → ConnectedSlidesTab-LUAGZ6FD.cjs} +60 -36
  8. package/dist/ConnectedSlidesTab-LUAGZ6FD.cjs.map +1 -0
  9. package/dist/{FilesViewerDialog-4352KIOG.cjs → FilesViewerDialog-JWKNJLWG.cjs} +10 -7
  10. package/dist/FilesViewerDialog-JWKNJLWG.cjs.map +1 -0
  11. package/dist/SpotlightStrip-ED22UYTM.cjs +398 -0
  12. package/dist/SpotlightStrip-ED22UYTM.cjs.map +1 -0
  13. package/dist/{chunk-LHWOKOMP.cjs → chunk-3IH55CDE.cjs} +4 -4
  14. package/dist/chunk-3IH55CDE.cjs.map +1 -0
  15. package/dist/chunk-3ZZZO4F7.cjs +145 -0
  16. package/dist/chunk-3ZZZO4F7.cjs.map +1 -0
  17. package/dist/{chunk-WFMWKPGY.cjs → chunk-ADPRIBSH.cjs} +9 -33
  18. package/dist/chunk-ADPRIBSH.cjs.map +1 -0
  19. package/dist/{chunk-UTJ223TI.cjs → chunk-BX6G2ZCI.cjs} +138 -146
  20. package/dist/chunk-BX6G2ZCI.cjs.map +1 -0
  21. package/dist/{chunk-WRLGLZIA.cjs → chunk-EMRY62HS.cjs} +2 -2
  22. package/dist/{chunk-WRLGLZIA.cjs.map → chunk-EMRY62HS.cjs.map} +1 -1
  23. package/dist/{chunk-USNTRL22.cjs → chunk-H236SNEV.cjs} +199 -1616
  24. package/dist/chunk-H236SNEV.cjs.map +1 -0
  25. package/dist/chunk-JITYC4OS.cjs +66 -0
  26. package/dist/chunk-JITYC4OS.cjs.map +1 -0
  27. package/dist/chunk-JY7UUZQG.cjs +1513 -0
  28. package/dist/chunk-JY7UUZQG.cjs.map +1 -0
  29. package/dist/chunk-MVXHTAJ4.cjs +111 -0
  30. package/dist/chunk-MVXHTAJ4.cjs.map +1 -0
  31. package/dist/{chunk-4TTX6ZNS.cjs → chunk-ORNLCBNE.cjs} +24 -2
  32. package/dist/chunk-ORNLCBNE.cjs.map +1 -0
  33. package/dist/chunk-WVZLAAIZ.cjs +31 -0
  34. package/dist/chunk-WVZLAAIZ.cjs.map +1 -0
  35. package/dist/chunk-ZZZITHGK.cjs +119 -0
  36. package/dist/chunk-ZZZITHGK.cjs.map +1 -0
  37. package/dist/connect/index.cjs +52 -52
  38. package/dist/connect/viewer.cjs +8 -5
  39. package/dist/connection/presentation/ClippingMediaViewer.js +3 -3
  40. package/dist/connection/presentation/ClippingMediaViewer.js.map +2 -2
  41. package/dist/connection/presentation/ClippingPdfViewer.d.ts +4 -3
  42. package/dist/connection/presentation/ClippingPdfViewer.js +48 -9
  43. package/dist/connection/presentation/ClippingPdfViewer.js.map +2 -2
  44. package/dist/connection/presentation/ConnectedSlidesTab.js +35 -13
  45. package/dist/connection/presentation/ConnectedSlidesTab.js.map +2 -2
  46. package/dist/connection/presentation/SpotlightLayer.d.ts +5 -0
  47. package/dist/connection/presentation/SpotlightLayer.js +19 -0
  48. package/dist/connection/presentation/SpotlightLayer.js.map +7 -0
  49. package/dist/connection/presentation/SpotlightStrip.d.ts +10 -0
  50. package/dist/connection/presentation/SpotlightStrip.js +237 -0
  51. package/dist/connection/presentation/SpotlightStrip.js.map +7 -0
  52. package/dist/connection/presentation/useViewerClipping.d.ts +4 -3
  53. package/dist/connection/presentation/useViewerClipping.js +8 -4
  54. package/dist/connection/presentation/useViewerClipping.js.map +2 -2
  55. package/dist/connection/viewer/ConnectedDocumentViewer.js +52 -61
  56. package/dist/connection/viewer/ConnectedDocumentViewer.js.map +2 -2
  57. package/dist/connection/viewer/ViewerMoreMenu.d.ts +18 -0
  58. package/dist/connection/viewer/ViewerMoreMenu.js +45 -0
  59. package/dist/connection/viewer/ViewerMoreMenu.js.map +7 -0
  60. package/dist/connection/viewer/pdf/PdfPassageHighlights.js +3 -2
  61. package/dist/connection/viewer/pdf/PdfPassageHighlights.js.map +2 -2
  62. package/dist/connection/viewer/pdf/passageHighlights.d.ts +5 -0
  63. package/dist/connection/viewer/pdf/passageHighlights.js +14 -1
  64. package/dist/connection/viewer/pdf/passageHighlights.js.map +2 -2
  65. package/dist/connection/viewer/useCleanView.d.ts +3 -1
  66. package/dist/connection/viewer/useCleanView.js +6 -3
  67. package/dist/connection/viewer/useCleanView.js.map +2 -2
  68. package/dist/document-tools/DocumentToolButtons.js +3 -3
  69. package/dist/document-tools/DocumentToolButtons.js.map +2 -2
  70. package/dist/document-tools/index.cjs +13 -13
  71. package/dist/index.cjs +53 -53
  72. package/dist/presentation/BoxActionBar.d.ts +2 -2
  73. package/dist/presentation/BoxActionBar.js +62 -30
  74. package/dist/presentation/BoxActionBar.js.map +2 -2
  75. package/dist/presentation/ClipActionBar.js +60 -7
  76. package/dist/presentation/ClipActionBar.js.map +2 -2
  77. package/dist/presentation/ClipCaptureOverlay.d.ts +7 -3
  78. package/dist/presentation/ClipCaptureOverlay.js +43 -14
  79. package/dist/presentation/ClipCaptureOverlay.js.map +2 -2
  80. package/dist/presentation/ClipViewControls.d.ts +3 -3
  81. package/dist/presentation/ClipViewControls.js +59 -64
  82. package/dist/presentation/ClipViewControls.js.map +2 -2
  83. package/dist/presentation/PresentControls.d.ts +8 -0
  84. package/dist/presentation/PresentControls.js +1 -0
  85. package/dist/presentation/PresentControls.js.map +2 -2
  86. package/dist/presentation/PresentationStage.d.ts +10 -2
  87. package/dist/presentation/PresentationStage.js +6 -3
  88. package/dist/presentation/PresentationStage.js.map +2 -2
  89. package/dist/presentation/PresenterView.js +1 -22
  90. package/dist/presentation/PresenterView.js.map +2 -2
  91. package/dist/presentation/SlidesEditor.js +56 -42
  92. package/dist/presentation/SlidesEditor.js.map +2 -2
  93. package/dist/presentation/SpotlightView.d.ts +19 -0
  94. package/dist/presentation/SpotlightView.js +180 -0
  95. package/dist/presentation/SpotlightView.js.map +7 -0
  96. package/dist/presentation/StageItem.js +0 -5
  97. package/dist/presentation/StageItem.js.map +2 -2
  98. package/dist/presentation/passage-clip.d.ts +17 -0
  99. package/dist/presentation/passage-clip.js +25 -0
  100. package/dist/presentation/passage-clip.js.map +7 -0
  101. package/dist/presentation/spotlight.d.ts +58 -0
  102. package/dist/presentation/spotlight.js +110 -0
  103. package/dist/presentation/spotlight.js.map +7 -0
  104. package/dist/presentation/store.d.ts +5 -0
  105. package/dist/presentation/store.js +19 -0
  106. package/dist/presentation/store.js.map +2 -2
  107. package/dist/presentation/usePointerActive.d.ts +2 -0
  108. package/dist/presentation/usePointerActive.js +28 -0
  109. package/dist/presentation/usePointerActive.js.map +7 -0
  110. package/dist/styles.css +1 -1
  111. package/node_modules/@arbidocs/coedit/package.json +1 -1
  112. package/package.json +5 -5
  113. package/dist/ClippingMediaViewer-IEIBT74X.cjs.map +0 -1
  114. package/dist/ClippingPdfViewer-OGYLMVCE.cjs.map +0 -1
  115. package/dist/ConnectedPresentation-AU25OW25.cjs.map +0 -1
  116. package/dist/ConnectedSlidesTab-I75LKKN7.cjs.map +0 -1
  117. package/dist/FilesViewerDialog-4352KIOG.cjs.map +0 -1
  118. package/dist/chunk-4TTX6ZNS.cjs.map +0 -1
  119. package/dist/chunk-LHWOKOMP.cjs.map +0 -1
  120. package/dist/chunk-USNTRL22.cjs.map +0 -1
  121. package/dist/chunk-UTJ223TI.cjs.map +0 -1
  122. package/dist/chunk-WFMWKPGY.cjs.map +0 -1
  123. package/dist/chunk-XK4TVJKD.cjs +0 -73
  124. package/dist/chunk-XK4TVJKD.cjs.map +0 -1
@@ -1,12 +1,13 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
+ var chunkJY7UUZQG_cjs = require('./chunk-JY7UUZQG.cjs');
4
5
  var chunkWOOOMTTA_cjs = require('./chunk-WOOOMTTA.cjs');
5
- var chunk5GCCUXMT_cjs = require('./chunk-5GCCUXMT.cjs');
6
6
  var chunk2F57IO7S_cjs = require('./chunk-2F57IO7S.cjs');
7
7
  var chunkUFT22LAB_cjs = require('./chunk-UFT22LAB.cjs');
8
- var chunkWFMWKPGY_cjs = require('./chunk-WFMWKPGY.cjs');
9
- var chunk4TTX6ZNS_cjs = require('./chunk-4TTX6ZNS.cjs');
8
+ var chunkWVZLAAIZ_cjs = require('./chunk-WVZLAAIZ.cjs');
9
+ var chunkADPRIBSH_cjs = require('./chunk-ADPRIBSH.cjs');
10
+ var chunkORNLCBNE_cjs = require('./chunk-ORNLCBNE.cjs');
10
11
  var chunk7JLJH5CW_cjs = require('./chunk-7JLJH5CW.cjs');
11
12
  var chunkVZOOGA47_cjs = require('./chunk-VZOOGA47.cjs');
12
13
  var chunkTKHCIHE2_cjs = require('./chunk-TKHCIHE2.cjs');
@@ -15,234 +16,11 @@ var react = require('react');
15
16
  var lucideReact = require('lucide-react');
16
17
  var ui = require('@arbidocs/react/ui');
17
18
  var reactDom = require('react-dom');
18
- var viewers = require('@arbidocs/react/viewers');
19
19
  var jsxRuntime = require('react/jsx-runtime');
20
20
  var react$1 = require('@arbidocs/react');
21
21
  var documentTools = require('@arbidocs/react/document-tools');
22
+ var viewers = require('@arbidocs/react/viewers');
22
23
 
23
- function cropStyle(rect) {
24
- return {
25
- position: "absolute",
26
- width: `${100 / rect.w}%`,
27
- height: `${100 / rect.h}%`,
28
- left: `${-rect.x / rect.w * 100}%`,
29
- top: `${-rect.y / rect.h * 100}%`,
30
- maxWidth: "none"
31
- };
32
- }
33
- function MediaClip({
34
- clip,
35
- className,
36
- live
37
- }) {
38
- const url = chunkWOOOMTTA_cjs.useObjectUrl(clip.source);
39
- const videoRef = react.useRef(null);
40
- react.useEffect(() => {
41
- const video = videoRef.current;
42
- if (!video) return;
43
- const toStart = () => {
44
- video.currentTime = clip.start ?? 0;
45
- };
46
- if (video.readyState >= 1) toStart();
47
- else video.addEventListener("loadedmetadata", toStart, { once: true });
48
- return () => video.removeEventListener("loadedmetadata", toStart);
49
- }, [clip.start, url]);
50
- return /* @__PURE__ */ jsxRuntime.jsx(
51
- "div",
52
- {
53
- className: ui.cn("relative h-full w-full overflow-hidden bg-black", className),
54
- "data-testid": `clip-image-${clip.id}`,
55
- children: clip.kind === "video" ? /* @__PURE__ */ jsxRuntime.jsx(
56
- "video",
57
- {
58
- ref: videoRef,
59
- src: url,
60
- muted: !live,
61
- playsInline: true,
62
- preload: "auto",
63
- className: "pointer-events-none block select-none",
64
- style: cropStyle(clip.rect),
65
- ...live ? { [chunkWFMWKPGY_cjs.STAGE_VIDEO_ATTRIBUTE]: "" } : {}
66
- }
67
- ) : /* @__PURE__ */ jsxRuntime.jsx(
68
- "img",
69
- {
70
- src: url,
71
- alt: clip.caption,
72
- draggable: false,
73
- className: "pointer-events-none block select-none",
74
- style: cropStyle(clip.rect)
75
- }
76
- )
77
- }
78
- );
79
- }
80
- var WIDTH_STEP = 160;
81
- var SETTLE_MS = 150;
82
- var ClipImage = react.memo(function ClipImage2({
83
- clip,
84
- className,
85
- live = false
86
- }) {
87
- return clip.kind === "pdf" ? /* @__PURE__ */ jsxRuntime.jsx(PdfClip, { clip, className }) : /* @__PURE__ */ jsxRuntime.jsx(MediaClip, { clip, className, live });
88
- });
89
- var sameRect = (a, b) => a.x === b.x && a.y === b.y && a.w === b.w && a.h === b.h;
90
- function PdfClip({ clip, className }) {
91
- const canvasRef = react.useRef(null);
92
- const [size, setSize] = react.useState({ width: 0, height: 0 });
93
- const [rendered, setRendered] = react.useState(null);
94
- const [failed, setFailed] = react.useState(false);
95
- react.useEffect(() => {
96
- const canvas = canvasRef.current;
97
- const view = canvas?.ownerDocument.defaultView;
98
- if (!canvas || !view) return;
99
- const measure = () => {
100
- const box2 = canvas.getBoundingClientRect();
101
- const dpr = view.devicePixelRatio || 1;
102
- const width = Math.max(1, Math.round(box2.width * dpr));
103
- const height = Math.max(1, Math.round(box2.height * dpr));
104
- setSize((s) => s.width === width && s.height === height ? s : { width, height });
105
- };
106
- measure();
107
- const Observer = view.ResizeObserver ?? ResizeObserver;
108
- const observer = new Observer(measure);
109
- observer.observe(canvas);
110
- return () => observer.disconnect();
111
- }, []);
112
- react.useLayoutEffect(() => {
113
- const canvas = canvasRef.current;
114
- const context = canvas?.getContext("2d");
115
- if (!canvas || !context || !size.width) return;
116
- if (canvas.width !== size.width) canvas.width = size.width;
117
- if (canvas.height !== size.height) canvas.height = size.height;
118
- context.fillStyle = "#fff";
119
- context.fillRect(0, 0, size.width, size.height);
120
- if (!rendered) return;
121
- const { rect } = clip;
122
- const sx = size.width / rect.w;
123
- const sy = size.height / rect.h;
124
- try {
125
- context.drawImage(
126
- rendered.image,
127
- (rendered.rect.x - rect.x) * sx,
128
- (rendered.rect.y - rect.y) * sy,
129
- rendered.rect.w * sx,
130
- rendered.rect.h * sy
131
- );
132
- } catch {
133
- setRendered(null);
134
- }
135
- }, [size, rendered, clip]);
136
- const wanted = Math.ceil(size.width / WIDTH_STEP) * WIDTH_STEP;
137
- const stale = wanted > 0 && (!rendered || !sameRect(rendered.rect, clip.rect) || wanted > rendered.width || wanted < rendered.width / 2);
138
- react.useEffect(() => {
139
- if (!stale) return;
140
- const controller = new AbortController();
141
- const rect = clip.rect;
142
- const timer = setTimeout(() => {
143
- viewers.renderPdfRegion({
144
- file: clip.source,
145
- page: clip.page,
146
- rect,
147
- masks: clip.masks,
148
- width: wanted,
149
- signal: controller.signal
150
- }).then((image) => {
151
- if (controller.signal.aborted) return viewers.closePdfRegionImage(image);
152
- setFailed(false);
153
- setRendered({ image, rect, width: wanted });
154
- }).catch(() => !controller.signal.aborted && setFailed(true));
155
- }, SETTLE_MS);
156
- return () => {
157
- clearTimeout(timer);
158
- controller.abort();
159
- };
160
- }, [stale, wanted, clip.source, clip.page, clip.rect, clip.masks]);
161
- const previous = react.useRef(null);
162
- react.useEffect(() => {
163
- if (previous.current && previous.current !== rendered) {
164
- viewers.closePdfRegionImage(previous.current.image);
165
- }
166
- previous.current = rendered;
167
- }, [rendered]);
168
- return /* @__PURE__ */ jsxRuntime.jsxs(
169
- "div",
170
- {
171
- className: ui.cn("relative h-full w-full overflow-hidden bg-white", className),
172
- "data-testid": `clip-image-${clip.id}`,
173
- children: [
174
- /* @__PURE__ */ jsxRuntime.jsx(
175
- "canvas",
176
- {
177
- ref: canvasRef,
178
- className: "pointer-events-none block h-full w-full",
179
- role: "img",
180
- "aria-label": clip.caption,
181
- "aria-busy": !rendered
182
- }
183
- ),
184
- failed && !rendered && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center justify-center p-2 text-center text-xs text-neutral-500", children: "Couldn't draw this clip" })
185
- ]
186
- }
187
- );
188
- }
189
- var DRAG_THRESHOLD = 6;
190
- var DROP_ATTRIBUTE = "data-presentation-drop";
191
- function dropAt(doc, clipId, x, y) {
192
- const target = doc.elementFromPoint(x, y)?.closest(`[${DROP_ATTRIBUTE}]`);
193
- if (!target) return false;
194
- const state = chunk4TTX6ZNS_cjs.usePresentation.getState();
195
- if (target.getAttribute(DROP_ATTRIBUTE) === "slide") {
196
- const index2 = Number(target.getAttribute("data-slide-index"));
197
- if (!Number.isInteger(index2)) return false;
198
- state.goTo(index2);
199
- state.place(clipId);
200
- return true;
201
- }
202
- const index = Number(target.getAttribute("data-slide-index"));
203
- if (target.hasAttribute("data-slide-index") && Number.isInteger(index)) state.goTo(index);
204
- const box2 = target.getBoundingClientRect();
205
- state.place(clipId, { x: (x - box2.left) / box2.width, y: (y - box2.top) / box2.height });
206
- return true;
207
- }
208
- function useClipDrag(clipId, onTap) {
209
- const press = react.useRef(null);
210
- const [ghost, setGhost] = react.useState(null);
211
- const end = () => {
212
- press.current = null;
213
- setGhost(null);
214
- chunk4TTX6ZNS_cjs.usePresentation.getState().setDragging(null);
215
- };
216
- return {
217
- ghost,
218
- handlers: {
219
- onPointerDown: (event) => {
220
- if (event.button !== 0) return;
221
- press.current = { x: event.clientX, y: event.clientY, dragging: false };
222
- },
223
- onPointerMove: (event) => {
224
- const p = press.current;
225
- if (!p) return;
226
- if (!p.dragging) {
227
- if (Math.hypot(event.clientX - p.x, event.clientY - p.y) < DRAG_THRESHOLD) return;
228
- p.dragging = true;
229
- event.currentTarget.setPointerCapture(event.pointerId);
230
- chunk4TTX6ZNS_cjs.usePresentation.getState().setDragging(clipId);
231
- }
232
- event.preventDefault();
233
- setGhost({ x: event.clientX, y: event.clientY });
234
- },
235
- onPointerUp: (event) => {
236
- const p = press.current;
237
- if (p?.dragging)
238
- dropAt(event.currentTarget.ownerDocument, clipId, event.clientX, event.clientY);
239
- else if (p) onTap();
240
- end();
241
- },
242
- onPointerCancel: end
243
- }
244
- };
245
- }
246
24
  var TILE_HEIGHT = 72;
247
25
  var TILE_WIDTH = { min: 56, max: 168 };
248
26
  function tileSize(aspect, height = TILE_HEIGHT) {
@@ -252,7 +30,7 @@ function tileSize(aspect, height = TILE_HEIGHT) {
252
30
  function Fitted({ clip, box: box2 }) {
253
31
  const wide = clip.aspect > box2.width / box2.height;
254
32
  const size = wide ? { width: box2.width, height: box2.width / clip.aspect } : { width: box2.height * clip.aspect, height: box2.height };
255
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none", style: size, children: /* @__PURE__ */ jsxRuntime.jsx(ClipImage, { clip }) });
33
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none", style: size, children: /* @__PURE__ */ jsxRuntime.jsx(chunkJY7UUZQG_cjs.ClipImage, { clip }) });
256
34
  }
257
35
  function Label({ clip }) {
258
36
  const [editing, setEditing] = react.useState(false);
@@ -265,7 +43,7 @@ function Label({ clip }) {
265
43
  "aria-label": "Clip label",
266
44
  className: "w-full rounded border border-input bg-background px-1 text-[11px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
267
45
  onBlur: (event) => {
268
- chunk4TTX6ZNS_cjs.usePresentation.getState().setCaption(clip.id, event.target.value);
46
+ chunkORNLCBNE_cjs.usePresentation.getState().setCaption(clip.id, event.target.value);
269
47
  setEditing(false);
270
48
  },
271
49
  onKeyDown: (event) => {
@@ -287,8 +65,8 @@ function Label({ clip }) {
287
65
  );
288
66
  }
289
67
  function TrayTile({ clip, onSlide }) {
290
- const { place, removeClip } = chunk4TTX6ZNS_cjs.usePresentation.getState();
291
- const drag = useClipDrag(clip.id, () => !onSlide && place(clip.id));
68
+ const { place, removeClip } = chunkORNLCBNE_cjs.usePresentation.getState();
69
+ const drag = chunkJY7UUZQG_cjs.useClipDrag(clip.id, () => !onSlide && place(clip.id));
292
70
  const itemRef = react.useRef(null);
293
71
  const size = tileSize(clip.aspect);
294
72
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -354,9 +132,9 @@ function TrayTile({ clip, onSlide }) {
354
132
  );
355
133
  }
356
134
  function ClipTray({ start }) {
357
- const all = chunk4TTX6ZNS_cjs.usePresentation((s) => s.clips);
135
+ const all = chunkORNLCBNE_cjs.usePresentation((s) => s.clips);
358
136
  const clips = react.useMemo(() => all.filter((clip) => !clip.plain), [all]);
359
- const slide = chunk4TTX6ZNS_cjs.usePresentation(chunk4TTX6ZNS_cjs.currentSlide);
137
+ const slide = chunkORNLCBNE_cjs.usePresentation(chunkORNLCBNE_cjs.currentSlide);
360
138
  const onSlide = new Set(slide?.items.map((item) => item.clipId));
361
139
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 border-t border-border bg-background", "data-testid": "clip-tray-bar", children: clips.length || start ? /* @__PURE__ */ jsxRuntime.jsxs(
362
140
  "ul",
@@ -411,7 +189,7 @@ function CustomColor({
411
189
  "input",
412
190
  {
413
191
  type: "color",
414
- value: chunk4TTX6ZNS_cjs.isHexColor(value) ? value : "#1f2937",
192
+ value: chunkORNLCBNE_cjs.isHexColor(value) ? value : "#1f2937",
415
193
  onChange: (event) => onChange(event.target.value),
416
194
  "aria-label": label,
417
195
  className: "absolute inset-0 cursor-pointer opacity-0"
@@ -422,10 +200,10 @@ function CustomColor({
422
200
  );
423
201
  }
424
202
  function DesignMenu({ onChooseLogo }) {
425
- const theme = chunk4TTX6ZNS_cjs.usePresentation((s) => s.theme);
426
- const setTheme = chunk4TTX6ZNS_cjs.usePresentation((s) => s.setTheme);
427
- const customBackground = chunk4TTX6ZNS_cjs.isHexColor(theme.background);
428
- const customAccent = !chunk4TTX6ZNS_cjs.ACCENTS.some((accent) => accent.color === theme.accent);
203
+ const theme = chunkORNLCBNE_cjs.usePresentation((s) => s.theme);
204
+ const setTheme = chunkORNLCBNE_cjs.usePresentation((s) => s.setTheme);
205
+ const customBackground = chunkORNLCBNE_cjs.isHexColor(theme.background);
206
+ const customAccent = !chunkORNLCBNE_cjs.ACCENTS.some((accent) => accent.color === theme.accent);
429
207
  return /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover, { children: [
430
208
  /* @__PURE__ */ jsxRuntime.jsx(ui.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
431
209
  ui.Button,
@@ -442,7 +220,7 @@ function DesignMenu({ onChooseLogo }) {
442
220
  ) }),
443
221
  /* @__PURE__ */ jsxRuntime.jsxs(ui.PopoverContent, { align: "end", className: "flex w-[21.5rem] flex-col gap-4 overflow-x-hidden p-4", children: [
444
222
  /* @__PURE__ */ jsxRuntime.jsx(Section, { title: "Background", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-7 gap-2", children: [
445
- chunk4TTX6ZNS_cjs.BACKGROUNDS.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
223
+ chunkORNLCBNE_cjs.BACKGROUNDS.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
446
224
  "button",
447
225
  {
448
226
  type: "button",
@@ -454,7 +232,7 @@ function DesignMenu({ onChooseLogo }) {
454
232
  "size-8 rounded-md border border-border shadow-sm",
455
233
  theme.background === preset.id && "ring-2 ring-primary ring-offset-1 ring-offset-background"
456
234
  ),
457
- style: { background: chunk4TTX6ZNS_cjs.backgroundCss(preset.id), containerType: "inline-size" },
235
+ style: { background: chunkORNLCBNE_cjs.backgroundCss(preset.id), containerType: "inline-size" },
458
236
  "data-testid": `design-background-${preset.id}`
459
237
  },
460
238
  preset.id
@@ -469,7 +247,7 @@ function DesignMenu({ onChooseLogo }) {
469
247
  }
470
248
  )
471
249
  ] }) }),
472
- /* @__PURE__ */ jsxRuntime.jsx(Section, { title: "Typeface", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-3 gap-2", children: Object.keys(chunk4TTX6ZNS_cjs.FONTS).map((font) => /* @__PURE__ */ jsxRuntime.jsxs(
250
+ /* @__PURE__ */ jsxRuntime.jsx(Section, { title: "Typeface", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-3 gap-2", children: Object.keys(chunkORNLCBNE_cjs.FONTS).map((font) => /* @__PURE__ */ jsxRuntime.jsxs(
473
251
  "button",
474
252
  {
475
253
  type: "button",
@@ -481,14 +259,14 @@ function DesignMenu({ onChooseLogo }) {
481
259
  ),
482
260
  "data-testid": `design-font-${font}`,
483
261
  children: [
484
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xl leading-tight", style: { fontFamily: chunk4TTX6ZNS_cjs.FONTS[font].css }, children: "Aa" }),
485
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] text-muted-foreground", children: chunk4TTX6ZNS_cjs.FONTS[font].label })
262
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xl leading-tight", style: { fontFamily: chunkORNLCBNE_cjs.FONTS[font].css }, children: "Aa" }),
263
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] text-muted-foreground", children: chunkORNLCBNE_cjs.FONTS[font].label })
486
264
  ]
487
265
  },
488
266
  font
489
267
  )) }) }),
490
268
  /* @__PURE__ */ jsxRuntime.jsx(Section, { title: "Accent", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
491
- chunk4TTX6ZNS_cjs.ACCENTS.map((accent) => /* @__PURE__ */ jsxRuntime.jsx(
269
+ chunkORNLCBNE_cjs.ACCENTS.map((accent) => /* @__PURE__ */ jsxRuntime.jsx(
492
270
  "button",
493
271
  {
494
272
  type: "button",
@@ -500,7 +278,7 @@ function DesignMenu({ onChooseLogo }) {
500
278
  "flex size-8 items-center justify-center rounded-full border border-black/10 shadow-sm",
501
279
  theme.accent === accent.color && "ring-2 ring-primary ring-offset-1 ring-offset-background"
502
280
  ),
503
- style: { background: chunk4TTX6ZNS_cjs.accentColor(accent.color) },
281
+ style: { background: chunkORNLCBNE_cjs.accentColor(accent.color) },
504
282
  children: theme.accent === accent.color && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "size-3.5 text-black/70" })
505
283
  },
506
284
  accent.color
@@ -508,7 +286,7 @@ function DesignMenu({ onChooseLogo }) {
508
286
  /* @__PURE__ */ jsxRuntime.jsx(
509
287
  CustomColor,
510
288
  {
511
- value: chunk4TTX6ZNS_cjs.accentColor(theme.accent),
289
+ value: chunkORNLCBNE_cjs.accentColor(theme.accent),
512
290
  selected: customAccent,
513
291
  label: "Your own accent colour",
514
292
  round: true,
@@ -571,13 +349,13 @@ var at = (box2) => ({
571
349
  height: `${box2.h * 100}%`
572
350
  });
573
351
  function LayoutThumb({ layout, className }) {
574
- const geometry = chunk4TTX6ZNS_cjs.slideGeometry({ layout, caption: "Title" }, { labels: false, logo: null });
352
+ const geometry = chunkORNLCBNE_cjs.slideGeometry({ layout, caption: "Title" }, { labels: false, logo: null });
575
353
  const { top, right = 0, bottom = 0, columns } = geometry.reserve;
576
354
  const room = {
577
- x: chunk4TTX6ZNS_cjs.STAGE_MARGIN,
578
- y: chunk4TTX6ZNS_cjs.STAGE_MARGIN + top,
579
- w: 1 - 2 * chunk4TTX6ZNS_cjs.STAGE_MARGIN - right,
580
- h: 1 - 2 * chunk4TTX6ZNS_cjs.STAGE_MARGIN - top - bottom
355
+ x: chunkORNLCBNE_cjs.STAGE_MARGIN,
356
+ y: chunkORNLCBNE_cjs.STAGE_MARGIN + top,
357
+ w: 1 - 2 * chunkORNLCBNE_cjs.STAGE_MARGIN - right,
358
+ h: 1 - 2 * chunkORNLCBNE_cjs.STAGE_MARGIN - top - bottom
581
359
  };
582
360
  const blocks = layout === "title" || layout === "section" || layout === "free" ? [] : columns === 2 ? [
583
361
  { ...room, w: room.w / 2 - 0.02 },
@@ -628,10 +406,10 @@ function LayoutMenu({
628
406
  className,
629
407
  compact = false
630
408
  }) {
631
- const layout = chunk4TTX6ZNS_cjs.usePresentation(
632
- (s) => (index === void 0 ? chunk4TTX6ZNS_cjs.currentSlide(s) : s.slides[index])?.layout ?? "clips"
409
+ const layout = chunkORNLCBNE_cjs.usePresentation(
410
+ (s) => (index === void 0 ? chunkORNLCBNE_cjs.currentSlide(s) : s.slides[index])?.layout ?? "clips"
633
411
  );
634
- const setSlideLayout = chunk4TTX6ZNS_cjs.usePresentation((s) => s.setSlideLayout);
412
+ const setSlideLayout = chunkORNLCBNE_cjs.usePresentation((s) => s.setSlideLayout);
635
413
  return /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
636
414
  /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
637
415
  ui.Button,
@@ -644,7 +422,7 @@ function LayoutMenu({
644
422
  className
645
423
  ),
646
424
  title: "Slide layout",
647
- "aria-label": `Slide layout: ${chunk4TTX6ZNS_cjs.LAYOUT_INFO[layout].label}`,
425
+ "aria-label": `Slide layout: ${chunkORNLCBNE_cjs.LAYOUT_INFO[layout].label}`,
648
426
  "data-testid": "presentation-layout",
649
427
  children: [
650
428
  /* @__PURE__ */ jsxRuntime.jsx(LayoutThumb, { layout, className: compact ? "w-6" : "w-7" }),
@@ -652,7 +430,7 @@ function LayoutMenu({
652
430
  ]
653
431
  }
654
432
  ) }),
655
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuContent, { align: "start", className: "w-56", children: chunk4TTX6ZNS_cjs.SLIDE_LAYOUTS.map((option) => /* @__PURE__ */ jsxRuntime.jsxs(
433
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuContent, { align: "start", className: "w-56", children: chunkORNLCBNE_cjs.SLIDE_LAYOUTS.map((option) => /* @__PURE__ */ jsxRuntime.jsxs(
656
434
  ui.DropdownMenuItem,
657
435
  {
658
436
  onSelect: () => setSlideLayout(option, index),
@@ -660,7 +438,7 @@ function LayoutMenu({
660
438
  "data-testid": `presentation-layout-${option}`,
661
439
  children: [
662
440
  /* @__PURE__ */ jsxRuntime.jsx(LayoutThumb, { layout: option, className: "w-12" }),
663
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: chunk4TTX6ZNS_cjs.LAYOUT_INFO[option].label })
441
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: chunkORNLCBNE_cjs.LAYOUT_INFO[option].label })
664
442
  ]
665
443
  },
666
444
  option
@@ -668,11 +446,11 @@ function LayoutMenu({
668
446
  ] });
669
447
  }
670
448
  function Notice() {
671
- const notice = chunk4TTX6ZNS_cjs.usePresentation((s) => s.notice);
449
+ const notice = chunkORNLCBNE_cjs.usePresentation((s) => s.notice);
672
450
  react.useEffect(() => {
673
451
  if (!notice) return;
674
452
  const timer = setTimeout(
675
- () => chunk4TTX6ZNS_cjs.usePresentation.getState().clearNotice(notice.id),
453
+ () => chunkORNLCBNE_cjs.usePresentation.getState().clearNotice(notice.id),
676
454
  notice.kind === "error" ? 8e3 : 3e3
677
455
  );
678
456
  return () => clearTimeout(timer);
@@ -693,7 +471,7 @@ function Notice() {
693
471
  type: "button",
694
472
  className: "ml-1 rounded p-0.5 text-muted-foreground hover:text-foreground",
695
473
  "aria-label": "Dismiss",
696
- onClick: () => chunk4TTX6ZNS_cjs.usePresentation.getState().clearNotice(notice.id),
474
+ onClick: () => chunkORNLCBNE_cjs.usePresentation.getState().clearNotice(notice.id),
697
475
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-3.5" })
698
476
  }
699
477
  )
@@ -701,1235 +479,6 @@ function Notice() {
701
479
  }
702
480
  );
703
481
  }
704
- var ACTION = "inline-flex size-7 items-center justify-center rounded text-foreground hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:size-11";
705
- var SIZES = [
706
- { command: "fit", label: "Fit the slide", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize2, { className: "size-4" }) },
707
- { command: "fullWidth", label: "Full width", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoveHorizontal, { className: "size-4" }) },
708
- { command: "fullHeight", label: "Full height", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoveVertical, { className: "size-4" }) }
709
- ];
710
- var ALIGNMENTS = [
711
- { alignment: "left", label: "Left", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignStartVertical, { className: "size-4" }) },
712
- { alignment: "centre", label: "Centre", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignCenterVertical, { className: "size-4" }) },
713
- { alignment: "right", label: "Right", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignEndVertical, { className: "size-4" }) },
714
- { alignment: "top", label: "Top", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignStartHorizontal, { className: "size-4" }) },
715
- { alignment: "middle", label: "Middle", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignCenterHorizontal, { className: "size-4" }) },
716
- { alignment: "bottom", label: "Bottom", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignEndHorizontal, { className: "size-4" }) }
717
- ];
718
- function Action({
719
- label,
720
- onClick,
721
- children
722
- }) {
723
- return /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: ACTION, title: label, "aria-label": label, onClick, children });
724
- }
725
- function ClipActionBar({
726
- clipId,
727
- at: at2,
728
- onRemoved,
729
- onEditImage,
730
- onCropImage
731
- }) {
732
- const actions = chunk4TTX6ZNS_cjs.usePresentation.getState();
733
- return /* @__PURE__ */ jsxRuntime.jsxs(
734
- "div",
735
- {
736
- role: "toolbar",
737
- "aria-label": "Clip",
738
- className: "absolute z-20 flex items-center gap-0.5 rounded-md border border-border bg-background p-0.5 shadow-md",
739
- style: { left: `${at2.x * 100}%`, top: `calc(${at2.y * 100}% - 40px)` },
740
- onPointerDown: (event) => event.stopPropagation(),
741
- "data-testid": "clip-action-bar",
742
- children: [
743
- SIZES.map(({ command, label, icon }) => /* @__PURE__ */ jsxRuntime.jsx(Action, { label, onClick: () => actions.applyFrame(clipId, command), children: icon }, command)),
744
- /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
745
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: ACTION, title: "Align", "aria-label": "Align", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignCenterHorizontal, { className: "size-4" }) }) }),
746
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuContent, { align: "start", children: ALIGNMENTS.map(({ alignment, label, icon }) => /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: () => actions.align(clipId, alignment), children: [
747
- icon,
748
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: label })
749
- ] }, alignment)) })
750
- ] }),
751
- onCropImage && /* @__PURE__ */ jsxRuntime.jsx(Action, { label: "Crop", onClick: onCropImage, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Crop, { className: "size-4" }) }),
752
- onEditImage && /* @__PURE__ */ jsxRuntime.jsx(Action, { label: "Edit image", onClick: onEditImage, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "size-4" }) }),
753
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-0.5 h-5 w-px bg-border" }),
754
- /* @__PURE__ */ jsxRuntime.jsx(Action, { label: "Bring to front", onClick: () => actions.bringToFront(clipId), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BringToFront, { className: "size-4" }) }),
755
- /* @__PURE__ */ jsxRuntime.jsx(Action, { label: "Send to back", onClick: () => actions.sendToBack(clipId), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SendToBack, { className: "size-4" }) }),
756
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-0.5 h-5 w-px bg-border" }),
757
- /* @__PURE__ */ jsxRuntime.jsx(
758
- "button",
759
- {
760
- type: "button",
761
- className: ui.cn(ACTION, "text-destructive hover:bg-destructive/10"),
762
- title: "Remove from slide (Delete)",
763
- "aria-label": "Remove from slide",
764
- onClick: () => {
765
- actions.unplace(clipId);
766
- onRemoved();
767
- },
768
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "size-4" })
769
- }
770
- )
771
- ]
772
- }
773
- );
774
- }
775
- var boxStyle = (box2) => ({
776
- left: `${box2.x * 100}%`,
777
- top: `${box2.y * 100}%`,
778
- width: `${box2.w * 100}%`,
779
- height: `${box2.h * 100}%`
780
- });
781
- var textStyle = (box2, color) => ({
782
- ...boxStyle(box2),
783
- fontSize: `${box2.size * 100}cqw`,
784
- fontWeight: box2.weight,
785
- lineHeight: box2.leading,
786
- color,
787
- letterSpacing: box2.tone === "title" ? "-0.01em" : void 0
788
- });
789
- var PLACEHOLDER_COLOR = "rgba(255,255,255,0.32)";
790
- function Text({
791
- box: box2,
792
- lines,
793
- accent,
794
- placeholder,
795
- onEdit,
796
- testId
797
- }) {
798
- const empty = lines.length === 0;
799
- if (empty && !placeholder) return null;
800
- return /* @__PURE__ */ jsxRuntime.jsx(
801
- "div",
802
- {
803
- className: ui.cn(
804
- "absolute flex flex-col overflow-hidden",
805
- onEdit ? "pointer-events-auto cursor-text rounded-[0.3cqw] hover:outline hover:outline-1 hover:outline-white/25" : "pointer-events-none",
806
- box2.align === "center" && "text-center",
807
- box2.bullets && "gap-[0.6cqw]",
808
- box2.anchor === "middle" && "justify-center",
809
- box2.anchor === "bottom" && "justify-end"
810
- ),
811
- style: textStyle(box2, empty ? PLACEHOLDER_COLOR : chunk4TTX6ZNS_cjs.TEXT_COLORS[box2.tone]),
812
- onPointerDown: onEdit ? (event) => event.stopPropagation() : void 0,
813
- onClick: onEdit,
814
- "data-testid": testId,
815
- children: (empty ? [placeholder] : lines).map(
816
- (line, index) => box2.bullets ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-[0.8em]", children: [
817
- /* @__PURE__ */ jsxRuntime.jsx(
818
- "span",
819
- {
820
- "aria-hidden": true,
821
- className: "inline-block size-[0.42em] shrink-0 -translate-y-[0.12em]",
822
- style: { background: empty ? "currentColor" : accent }
823
- }
824
- ),
825
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: line })
826
- ] }, index) : /* @__PURE__ */ jsxRuntime.jsx("div", { children: line }, index)
827
- )
828
- }
829
- );
830
- }
831
- function TextField({
832
- box: box2,
833
- value,
834
- placeholder,
835
- multiline,
836
- onChange,
837
- onDone,
838
- testId
839
- }) {
840
- return /* @__PURE__ */ jsxRuntime.jsx(
841
- "textarea",
842
- {
843
- autoFocus: true,
844
- value,
845
- placeholder,
846
- onChange: (event) => onChange(multiline ? event.target.value : event.target.value.replace(/\n/g, " ")),
847
- onBlur: onDone,
848
- onPointerDown: (event) => event.stopPropagation(),
849
- onKeyDown: (event) => {
850
- if (event.key === "Escape" || !multiline && event.key === "Enter") {
851
- event.preventDefault();
852
- event.currentTarget.blur();
853
- }
854
- },
855
- className: ui.cn(
856
- "pointer-events-auto absolute resize-none overflow-hidden rounded-[0.3cqw] bg-white/5 p-0 outline outline-1 outline-white/40 placeholder:text-white/30 focus:outline-white/60",
857
- box2.align === "center" && "text-center"
858
- ),
859
- style: {
860
- ...textStyle(box2, chunk4TTX6ZNS_cjs.TEXT_COLORS[box2.tone]),
861
- fontFamily: "inherit",
862
- // Bulleted lines keep their indent while typed.
863
- paddingLeft: box2.bullets ? "1.22em" : void 0
864
- },
865
- "aria-label": placeholder,
866
- "data-testid": testId
867
- }
868
- );
869
- }
870
- function Logo({ image, box: box2 }) {
871
- const url = chunkWOOOMTTA_cjs.useObjectUrl(image);
872
- if (!url) return null;
873
- return /* @__PURE__ */ jsxRuntime.jsx(
874
- "img",
875
- {
876
- src: url,
877
- alt: "",
878
- className: "pointer-events-none absolute object-contain opacity-90",
879
- style: { ...boxStyle(box2), objectPosition: box2.x < 0.5 ? "left bottom" : "right bottom" },
880
- "data-testid": "stage-logo"
881
- }
882
- );
883
- }
884
- var SlideDecor = react.memo(function SlideDecor2({
885
- slide,
886
- theme,
887
- labels,
888
- logoImage,
889
- editable,
890
- editing,
891
- dim
892
- }) {
893
- const [typing, setTyping] = react.useState(null);
894
- const geometry = chunk4TTX6ZNS_cjs.slideGeometry(slide, { labels, logo: theme.logo?.corner ?? null });
895
- const title = slide.caption.trim();
896
- const titled = slide.layout === "title" || slide.layout === "section";
897
- const info = chunk4TTX6ZNS_cjs.LAYOUT_INFO[slide.layout];
898
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("pointer-events-none absolute inset-0", dim && "opacity-30"), children: [
899
- !geometry.title ? null : editing && typing === "title" ? /* @__PURE__ */ jsxRuntime.jsx(
900
- TextField,
901
- {
902
- box: geometry.title,
903
- value: slide.caption,
904
- placeholder: "Title",
905
- multiline: false,
906
- onChange: editing.onTitle,
907
- onDone: () => setTyping(null),
908
- testId: "stage-slide-caption-input"
909
- }
910
- ) : /* @__PURE__ */ jsxRuntime.jsx(
911
- Text,
912
- {
913
- box: geometry.title,
914
- lines: title ? [title] : [],
915
- accent: chunk4TTX6ZNS_cjs.accentColor(theme.accent),
916
- placeholder: editable && (titled || editing) ? "Click to add a title" : void 0,
917
- onEdit: editing ? () => setTyping("title") : void 0,
918
- testId: "stage-slide-caption"
919
- }
920
- ),
921
- geometry.rule && (title || editable && titled) && /* @__PURE__ */ jsxRuntime.jsx(
922
- "div",
923
- {
924
- className: "absolute",
925
- style: { ...boxStyle(geometry.rule), background: chunk4TTX6ZNS_cjs.accentColor(theme.accent) }
926
- }
927
- ),
928
- geometry.text && (editing && typing === "text" ? /* @__PURE__ */ jsxRuntime.jsx(
929
- TextField,
930
- {
931
- box: geometry.text,
932
- value: slide.points,
933
- placeholder: info.text ?? "",
934
- multiline: true,
935
- onChange: editing.onPoints,
936
- onDone: () => setTyping(null),
937
- testId: "stage-slide-points-input"
938
- }
939
- ) : /* @__PURE__ */ jsxRuntime.jsx(
940
- Text,
941
- {
942
- box: geometry.text,
943
- lines: chunk4TTX6ZNS_cjs.textLines(slide.points),
944
- accent: chunk4TTX6ZNS_cjs.accentColor(theme.accent),
945
- placeholder: editable ? info.text : void 0,
946
- onEdit: editing ? () => setTyping("text") : void 0,
947
- testId: "stage-slide-points"
948
- }
949
- )),
950
- geometry.logo && logoImage && /* @__PURE__ */ jsxRuntime.jsx(Logo, { image: logoImage, box: geometry.logo })
951
- ] });
952
- });
953
- var PAN_STEP = 0.1;
954
- var MAX_ZOOM = 800;
955
- var HOLD_DELAY = 350;
956
- var HOLD_EVERY = 90;
957
- var BUTTON = "pointer-events-auto flex size-7 items-center justify-center rounded-full border border-border bg-background/90 text-foreground shadow-sm backdrop-blur-sm hover:bg-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-30 pointer-coarse:size-11";
958
- function HoldButton({
959
- label,
960
- disabled,
961
- onStep,
962
- className,
963
- children
964
- }) {
965
- const timer = react.useRef(null);
966
- const stop = () => {
967
- if (timer.current) clearTimeout(timer.current);
968
- timer.current = null;
969
- };
970
- react.useEffect(() => stop, []);
971
- react.useEffect(() => {
972
- if (disabled) stop();
973
- }, [disabled]);
974
- const start = (event) => {
975
- event.stopPropagation();
976
- if (disabled || event.button !== 0) return;
977
- onStep();
978
- const repeat = () => {
979
- onStep();
980
- timer.current = setTimeout(repeat, HOLD_EVERY);
981
- };
982
- timer.current = setTimeout(repeat, HOLD_DELAY);
983
- };
984
- return /* @__PURE__ */ jsxRuntime.jsx(
985
- "button",
986
- {
987
- type: "button",
988
- className: ui.cn(BUTTON, className),
989
- title: label,
990
- "aria-label": label,
991
- disabled,
992
- onPointerDown: start,
993
- onPointerUp: stop,
994
- onPointerLeave: stop,
995
- onPointerCancel: stop,
996
- onClick: (event) => event.detail === 0 && onStep(),
997
- children
998
- }
999
- );
1000
- }
1001
- function ClipViewControls({ clip }) {
1002
- const { panClip, setClipZoom } = chunk4TTX6ZNS_cjs.usePresentation.getState();
1003
- const { rect } = clip;
1004
- const zoomBase = clip.zoomBase ?? rect.w;
1005
- const minZoom = Math.min(100, Math.floor(zoomBase / Math.min(1, rect.w / rect.h) * 100));
1006
- const pan = (dx, dy) => () => panClip(clip.id, dx * rect.w, dy * rect.h);
1007
- const zoom = Math.round(zoomBase / rect.w * 100);
1008
- const edge = 1e-6;
1009
- return /* @__PURE__ */ jsxRuntime.jsxs(
1010
- "div",
1011
- {
1012
- className: "pointer-events-none absolute inset-0 z-10",
1013
- onPointerDown: (event) => event.stopPropagation(),
1014
- "data-testid": "clip-view-controls",
1015
- children: [
1016
- /* @__PURE__ */ jsxRuntime.jsx(
1017
- HoldButton,
1018
- {
1019
- label: "Show more above",
1020
- disabled: rect.y <= edge,
1021
- onStep: pan(0, -PAN_STEP),
1022
- className: "absolute left-1/2 top-4 -translate-x-1/2 pointer-coarse:top-7",
1023
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "size-4" })
1024
- }
1025
- ),
1026
- /* @__PURE__ */ jsxRuntime.jsx(
1027
- HoldButton,
1028
- {
1029
- label: "Show more below",
1030
- disabled: rect.y + rect.h >= 1 - edge,
1031
- onStep: pan(0, PAN_STEP),
1032
- className: "absolute bottom-10 left-1/2 -translate-x-1/2 pointer-coarse:bottom-14",
1033
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "size-4" })
1034
- }
1035
- ),
1036
- /* @__PURE__ */ jsxRuntime.jsx(
1037
- HoldButton,
1038
- {
1039
- label: "Show more on the left",
1040
- disabled: rect.x <= edge,
1041
- onStep: pan(-PAN_STEP, 0),
1042
- className: "absolute left-4 top-1/2 -translate-y-1/2 pointer-coarse:left-7",
1043
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "size-4" })
1044
- }
1045
- ),
1046
- /* @__PURE__ */ jsxRuntime.jsx(
1047
- HoldButton,
1048
- {
1049
- label: "Show more on the right",
1050
- disabled: rect.x + rect.w >= 1 - edge,
1051
- onStep: pan(PAN_STEP, 0),
1052
- className: "absolute right-4 top-1/2 -translate-y-1/2 pointer-coarse:right-7",
1053
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "size-4" })
1054
- }
1055
- ),
1056
- /* @__PURE__ */ jsxRuntime.jsx(
1057
- "div",
1058
- {
1059
- className: "pointer-events-auto absolute bottom-1.5 left-1/2 -translate-x-1/2",
1060
- "data-testid": "clip-zoom-control",
1061
- children: /* @__PURE__ */ jsxRuntime.jsx(
1062
- chunk5GCCUXMT_cjs.ZoomSlider,
1063
- {
1064
- value: zoom,
1065
- min: minZoom,
1066
- max: Math.max(MAX_ZOOM, zoom),
1067
- zoomOutStep: 25,
1068
- onChange: (value) => setClipZoom(clip.id, value),
1069
- label: "Zoom",
1070
- valueLabel: /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-testid": "clip-zoom", children: [
1071
- zoom,
1072
- "%"
1073
- ] }),
1074
- className: "bg-background/95 shadow-sm backdrop-blur-sm pointer-coarse:h-11",
1075
- sliderClassName: "w-24"
1076
- }
1077
- )
1078
- }
1079
- )
1080
- ]
1081
- }
1082
- );
1083
- }
1084
- var isEdge = (kind) => kind === "n" || kind === "e" || kind === "s" || kind === "w";
1085
- var EDGES = [
1086
- { edge: "n", left: "50%", top: "0%", cursor: "ns-resize", label: "top" },
1087
- { edge: "e", left: "100%", top: "50%", cursor: "ew-resize", label: "right" },
1088
- { edge: "s", left: "50%", top: "100%", cursor: "ns-resize", label: "bottom" },
1089
- { edge: "w", left: "0%", top: "50%", cursor: "ew-resize", label: "left" }
1090
- ];
1091
- var CORNERS = [
1092
- { corner: "nw", left: "0%", top: "0%", cursor: "nwse-resize" },
1093
- { corner: "ne", left: "100%", top: "0%", cursor: "nesw-resize" },
1094
- { corner: "sw", left: "0%", top: "100%", cursor: "nesw-resize" },
1095
- { corner: "se", left: "100%", top: "100%", cursor: "nwse-resize" }
1096
- ];
1097
- var EDGE_CSS = chunk4TTX6ZNS_cjs.clipEdgeCss();
1098
- var StageItem = react.memo(function StageItem2({
1099
- clip,
1100
- frame,
1101
- editable,
1102
- selected,
1103
- dim,
1104
- label,
1105
- host
1106
- }) {
1107
- const element = react.useRef(null);
1108
- const gesture = react.useRef(null);
1109
- const [dragging, setDragging] = react.useState(false);
1110
- const [reshape, setReshape] = react.useState(null);
1111
- const shown = reshape ? { ...clip, ...reshape.shape } : clip;
1112
- const box2 = reshape?.frame ?? frame;
1113
- const view = () => element.current?.ownerDocument.defaultView ?? window;
1114
- const apply = () => {
1115
- const g = gesture.current;
1116
- const el = element.current;
1117
- if (!g) return;
1118
- g.request = null;
1119
- const next = g.next;
1120
- if (!next || !el) return;
1121
- if (next.shape) {
1122
- setReshape({ frame: next.frame, shape: next.shape });
1123
- } else {
1124
- const dx = (next.frame.x - g.frame.x) * g.stage.width;
1125
- const dy = (next.frame.y - g.frame.y) * g.stage.height;
1126
- const scale = next.frame.w / g.frame.w;
1127
- el.style.transform = `translate3d(${dx}px, ${dy}px, 0) scale(${scale})`;
1128
- }
1129
- const key = next.guides.map((guide) => `${guide.axis}${guide.at}`).join();
1130
- if (key !== g.guidesKey) {
1131
- g.guidesKey = key;
1132
- host.guides(next.guides);
1133
- }
1134
- };
1135
- const start = (event, kind) => {
1136
- if (!editable || event.button !== 0) return;
1137
- const stage = host.stageBox();
1138
- if (!stage) return;
1139
- event.preventDefault();
1140
- event.stopPropagation();
1141
- host.select(clip.id);
1142
- event.currentTarget.setPointerCapture(event.pointerId);
1143
- gesture.current = {
1144
- kind,
1145
- pointer: { x: event.clientX, y: event.clientY },
1146
- frame,
1147
- shape: { rect: clip.rect, aspect: clip.aspect },
1148
- stage,
1149
- others: host.others(clip.id),
1150
- next: null,
1151
- request: null,
1152
- guidesKey: ""
1153
- };
1154
- };
1155
- const move = (event) => {
1156
- const g = gesture.current;
1157
- if (!g) return;
1158
- if (!g.next) {
1159
- setDragging(true);
1160
- host.dragging(true);
1161
- if (element.current) element.current.style.willChange = "transform";
1162
- }
1163
- const dx = (event.clientX - g.pointer.x) / g.stage.width;
1164
- const dy = (event.clientY - g.pointer.y) / g.stage.height;
1165
- const free = event.altKey;
1166
- if (isEdge(g.kind)) {
1167
- const result = chunk4TTX6ZNS_cjs.reshapeFrame(g.frame, g.shape, g.kind, dx, dy, g.others, free);
1168
- g.next = {
1169
- frame: result.frame,
1170
- shape: { rect: result.rect, aspect: result.aspect },
1171
- guides: result.guides
1172
- };
1173
- } else {
1174
- g.next = g.kind === "move" ? chunk4TTX6ZNS_cjs.moveFrame(g.frame, g.shape.aspect, dx, dy, g.others, free) : chunk4TTX6ZNS_cjs.resizeFrame(g.frame, g.shape.aspect, g.kind, dx, dy, g.others, free);
1175
- }
1176
- g.request ??= view().requestAnimationFrame(apply);
1177
- };
1178
- const end = () => {
1179
- const g = gesture.current;
1180
- gesture.current = null;
1181
- if (!g) return;
1182
- if (g.request !== null) view().cancelAnimationFrame(g.request);
1183
- const el = element.current;
1184
- if (el) {
1185
- el.style.transform = "";
1186
- el.style.willChange = "";
1187
- }
1188
- if (!g.next) return;
1189
- setReshape(null);
1190
- setDragging(false);
1191
- host.dragging(false);
1192
- host.guides([]);
1193
- host.commit(clip.id, g.next.frame, g.next.shape);
1194
- };
1195
- return /* @__PURE__ */ jsxRuntime.jsxs(
1196
- "div",
1197
- {
1198
- ref: element,
1199
- className: ui.cn(
1200
- "absolute origin-top-left",
1201
- // Lifted off the background (a picture that is part of the slide's design is not).
1202
- !clip.plain && "rounded-[0.6cqw] shadow-[0_0.5cqw_1.6cqw_rgba(0,0,0,0.5)]",
1203
- editable && "cursor-move touch-none",
1204
- selected && "outline outline-2 outline-offset-2 outline-primary",
1205
- dim && "opacity-30"
1206
- ),
1207
- style: {
1208
- left: `${box2.x * 100}%`,
1209
- top: `${box2.y * 100}%`,
1210
- width: `${box2.w * 100}%`,
1211
- height: `${chunk4TTX6ZNS_cjs.frameHeight(box2, shown.aspect) * 100}%`
1212
- },
1213
- onPointerDown: (event) => start(event, "move"),
1214
- onPointerMove: move,
1215
- onPointerUp: end,
1216
- onPointerCancel: end,
1217
- "data-testid": `stage-item-${clip.id}`,
1218
- children: [
1219
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("absolute inset-0 overflow-hidden", !clip.plain && "rounded-[0.6cqw]"), children: [
1220
- /* @__PURE__ */ jsxRuntime.jsx(ClipImage, { clip: shown, live: !editable }),
1221
- clip.kind === "pdf" && !clip.plain && /* @__PURE__ */ jsxRuntime.jsx(
1222
- "div",
1223
- {
1224
- className: "pointer-events-none absolute inset-0",
1225
- style: { background: EDGE_CSS },
1226
- "data-testid": "stage-clip-edge"
1227
- }
1228
- ),
1229
- !clip.plain && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none absolute inset-0 rounded-[0.6cqw] ring-1 ring-inset ring-white/15" })
1230
- ] }),
1231
- label && !clip.plain && // Under the clip, in the room the layout keeps (CAPTION_SPACE): never over it.
1232
- /* @__PURE__ */ jsxRuntime.jsx(
1233
- "div",
1234
- {
1235
- className: "pointer-events-none absolute left-0 top-full mt-[0.5cqw] max-w-full truncate text-[1.7cqw] leading-tight",
1236
- style: { color: chunk4TTX6ZNS_cjs.TEXT_COLORS.muted },
1237
- children: label
1238
- }
1239
- ),
1240
- selected && !dragging && /* @__PURE__ */ jsxRuntime.jsx(ClipViewControls, { clip }),
1241
- selected && CORNERS.map(({ corner, left, top, cursor }) => /* @__PURE__ */ jsxRuntime.jsx(
1242
- "div",
1243
- {
1244
- className: "absolute flex size-6 -translate-x-1/2 -translate-y-1/2 items-center justify-center pointer-coarse:size-11",
1245
- style: { left, top, cursor, touchAction: "none" },
1246
- onPointerDown: (event) => start(event, corner),
1247
- "aria-label": `Resize from the ${corner} corner`,
1248
- "data-testid": `stage-item-resize-${corner}`,
1249
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none size-3 rounded-full border-2 border-primary bg-background" })
1250
- },
1251
- corner
1252
- )),
1253
- selected && EDGES.map(({ edge, left, top, cursor, label: side }) => /* @__PURE__ */ jsxRuntime.jsx(
1254
- "div",
1255
- {
1256
- className: "absolute flex size-6 -translate-x-1/2 -translate-y-1/2 items-center justify-center pointer-coarse:size-11",
1257
- style: { left, top, cursor, touchAction: "none" },
1258
- onPointerDown: (event) => start(event, edge),
1259
- "aria-label": `Show more or less at the ${side}`,
1260
- title: "Drag to show more or less of the page",
1261
- "data-testid": `stage-item-reshape-${edge}`,
1262
- children: /* @__PURE__ */ jsxRuntime.jsx(
1263
- "span",
1264
- {
1265
- className: ui.cn(
1266
- "pointer-events-none rounded-full border-2 border-primary bg-background",
1267
- edge === "n" || edge === "s" ? "h-2 w-4" : "h-4 w-2"
1268
- )
1269
- }
1270
- )
1271
- },
1272
- edge
1273
- ))
1274
- ]
1275
- }
1276
- );
1277
- });
1278
-
1279
- // src/presentation/box-style.ts
1280
- var cqw = (points) => `${chunk4TTX6ZNS_cjs.pointsToStage(points) * 100}cqw`;
1281
- function runStyle(run, font) {
1282
- return {
1283
- fontSize: cqw(run.size ?? chunk4TTX6ZNS_cjs.DEFAULT_TEXT_SIZE),
1284
- fontWeight: run.bold ? 700 : 400,
1285
- fontStyle: run.italic ? "italic" : void 0,
1286
- textDecoration: run.underline ? "underline" : void 0,
1287
- color: run.color ?? chunk4TTX6ZNS_cjs.TEXT_COLORS.body,
1288
- fontFamily: run.font ? `"${run.font}", ${font}` : font
1289
- };
1290
- }
1291
- var HANDLES = [
1292
- { handle: "nw", left: "0%", top: "0%", cursor: "nwse-resize" },
1293
- { handle: "n", left: "50%", top: "0%", cursor: "ns-resize" },
1294
- { handle: "ne", left: "100%", top: "0%", cursor: "nesw-resize" },
1295
- { handle: "e", left: "100%", top: "50%", cursor: "ew-resize" },
1296
- { handle: "se", left: "100%", top: "100%", cursor: "nwse-resize" },
1297
- { handle: "s", left: "50%", top: "100%", cursor: "ns-resize" },
1298
- { handle: "sw", left: "0%", top: "100%", cursor: "nesw-resize" },
1299
- { handle: "w", left: "0%", top: "50%", cursor: "ew-resize" }
1300
- ];
1301
- var withAlpha = (hex3, alpha = 1) => {
1302
- if (alpha >= 1) return hex3;
1303
- const n = parseInt(hex3.slice(1), 16);
1304
- return `rgba(${n >> 16 & 255}, ${n >> 8 & 255}, ${n & 255}, ${alpha})`;
1305
- };
1306
- function shapeStyle(box2) {
1307
- const { frame } = box2;
1308
- const line = box2.line;
1309
- const shorter = Math.min(frame.w, frame.h * 1 / chunk4TTX6ZNS_cjs.STAGE_ASPECT);
1310
- return {
1311
- background: box2.fill && box2.shape !== "line" ? withAlpha(box2.fill, box2.fillAlpha) : void 0,
1312
- border: line && box2.shape !== "line" ? `${cqw(line.width)} ${line.dash ? "dashed" : "solid"} ${line.color}` : void 0,
1313
- borderRadius: box2.shape === "ellipse" ? "50%" : box2.shape === "roundRect" ? `${shorter * 16.67}cqw` : void 0
1314
- };
1315
- }
1316
- function Paragraphs({
1317
- paragraphs,
1318
- font
1319
- }) {
1320
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: paragraphs.map((paragraph, index) => {
1321
- const first = paragraph.runs[0];
1322
- const size = first?.size ?? chunk4TTX6ZNS_cjs.DEFAULT_TEXT_SIZE;
1323
- const indent = (paragraph.level ?? 0) * 0.5 * size;
1324
- const empty = !paragraph.runs.some((run) => run.text);
1325
- return /* @__PURE__ */ jsxRuntime.jsxs(
1326
- "div",
1327
- {
1328
- className: "whitespace-pre-wrap break-words",
1329
- style: {
1330
- textAlign: paragraph.align ?? "left",
1331
- lineHeight: 1.2,
1332
- paddingLeft: cqw(indent + (paragraph.bullet ? size * 0.9 : 0)),
1333
- textIndent: paragraph.bullet ? cqw(-size * 0.9) : void 0,
1334
- // An empty line keeps its height.
1335
- fontSize: cqw(size)
1336
- },
1337
- children: [
1338
- paragraph.bullet && /* @__PURE__ */ jsxRuntime.jsx(
1339
- "span",
1340
- {
1341
- style: {
1342
- ...runStyle(first ?? { }, font),
1343
- display: "inline-block",
1344
- width: cqw(size * 0.9),
1345
- textIndent: 0
1346
- },
1347
- children: "\u2022"
1348
- }
1349
- ),
1350
- empty ? "\u200B" : paragraph.runs.map((run, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: runStyle(run, font), children: run.text }, i))
1351
- ]
1352
- },
1353
- index
1354
- );
1355
- }) });
1356
- }
1357
- var StageBox = react.memo(function StageBox2({
1358
- box: box2,
1359
- font,
1360
- editable,
1361
- selected,
1362
- host
1363
- }) {
1364
- const element = react.useRef(null);
1365
- const gesture = react.useRef(null);
1366
- const [typing, setTyping] = react.useState(false);
1367
- const [dragging, setDragging] = react.useState(false);
1368
- const { frame } = box2;
1369
- const view = () => element.current?.ownerDocument.defaultView ?? window;
1370
- const apply = () => {
1371
- const g = gesture.current;
1372
- const el = element.current;
1373
- if (!g || !el) return;
1374
- g.request = null;
1375
- if (!g.next) return;
1376
- if (g.handle === "move") {
1377
- el.style.translate = `${(g.next.x - g.frame.x) * g.stage.width}px ${(g.next.y - g.frame.y) * g.stage.height}px`;
1378
- } else {
1379
- el.style.left = `${g.next.x * 100}%`;
1380
- el.style.top = `${g.next.y * 100}%`;
1381
- el.style.width = `${g.next.w * 100}%`;
1382
- el.style.height = `${g.next.h * 100}%`;
1383
- }
1384
- };
1385
- const start = (event, handle) => {
1386
- if (!editable || typing || event.button !== 0) return;
1387
- const stage = host.stageBox();
1388
- if (!stage) return;
1389
- event.preventDefault();
1390
- event.stopPropagation();
1391
- host.select(box2.id);
1392
- event.currentTarget.setPointerCapture(event.pointerId);
1393
- gesture.current = {
1394
- handle,
1395
- pointer: { x: event.clientX, y: event.clientY },
1396
- frame,
1397
- stage,
1398
- next: null,
1399
- request: null,
1400
- wasSelected: selected
1401
- };
1402
- };
1403
- const move = (event) => {
1404
- const g = gesture.current;
1405
- if (!g) return;
1406
- const dx = (event.clientX - g.pointer.x) / g.stage.width;
1407
- const dy = (event.clientY - g.pointer.y) / g.stage.height;
1408
- if (!g.next) setDragging(true);
1409
- g.next = g.handle === "move" ? chunk4TTX6ZNS_cjs.moveBox(g.frame, dx, dy) : chunk4TTX6ZNS_cjs.stretchBox(g.frame, g.handle, dx, dy);
1410
- g.request ??= view().requestAnimationFrame(apply);
1411
- };
1412
- const end = () => {
1413
- const g = gesture.current;
1414
- gesture.current = null;
1415
- if (!g) return;
1416
- if (g.request !== null) view().cancelAnimationFrame(g.request);
1417
- if (!g.next) {
1418
- if (g.wasSelected && g.handle === "move" && hasText) setTyping(true);
1419
- return;
1420
- }
1421
- const el = element.current;
1422
- if (el) {
1423
- el.style.translate = "";
1424
- el.style.left = `${g.frame.x * 100}%`;
1425
- el.style.top = `${g.frame.y * 100}%`;
1426
- el.style.width = `${g.frame.w * 100}%`;
1427
- el.style.height = `${g.frame.h * 100}%`;
1428
- }
1429
- setDragging(false);
1430
- host.commit(box2.id, g.next);
1431
- };
1432
- const hasText = box2.shape !== "line";
1433
- const inset = cqw(box2.inset ?? chunk4TTX6ZNS_cjs.DEFAULT_INSET);
1434
- const run = chunk4TTX6ZNS_cjs.firstRun(box2);
1435
- const transform = box2.rotation ? `rotate(${box2.rotation}deg)` : void 0;
1436
- return /* @__PURE__ */ jsxRuntime.jsxs(
1437
- "div",
1438
- {
1439
- ref: element,
1440
- className: ui.cn(
1441
- "absolute",
1442
- editable ? "pointer-events-auto" : "pointer-events-none",
1443
- editable && !typing && "cursor-move touch-none",
1444
- editable && !selected && "hover:outline hover:outline-1 hover:outline-white/30",
1445
- selected && "outline outline-2 outline-offset-1 outline-primary"
1446
- ),
1447
- style: {
1448
- left: `${frame.x * 100}%`,
1449
- top: `${frame.y * 100}%`,
1450
- width: `${frame.w * 100}%`,
1451
- height: `${frame.h * 100}%`,
1452
- transform,
1453
- willChange: dragging ? "translate" : void 0
1454
- },
1455
- onPointerDown: (event) => start(event, "move"),
1456
- onPointerMove: move,
1457
- onPointerUp: end,
1458
- onPointerCancel: end,
1459
- onDoubleClick: () => editable && hasText && setTyping(true),
1460
- onKeyDown: (event) => {
1461
- if (selected && !typing && event.key === "Enter" && hasText) {
1462
- event.preventDefault();
1463
- setTyping(true);
1464
- }
1465
- },
1466
- tabIndex: editable ? 0 : void 0,
1467
- "data-testid": `stage-box-${box2.id}`,
1468
- children: [
1469
- box2.shape === "line" ? /* @__PURE__ */ jsxRuntime.jsx(
1470
- "svg",
1471
- {
1472
- className: "absolute inset-0 size-full overflow-visible",
1473
- preserveAspectRatio: "none",
1474
- "aria-hidden": true,
1475
- children: /* @__PURE__ */ jsxRuntime.jsx(
1476
- "line",
1477
- {
1478
- x1: "0%",
1479
- y1: box2.flipV ? "100%" : "0%",
1480
- x2: "100%",
1481
- y2: box2.flipV ? "0%" : "100%",
1482
- stroke: box2.line?.color ?? chunk4TTX6ZNS_cjs.TEXT_COLORS.body,
1483
- style: { strokeWidth: cqw(box2.line?.width ?? 1) },
1484
- strokeDasharray: box2.line?.dash ? "6 4" : void 0
1485
- }
1486
- )
1487
- }
1488
- ) : /* @__PURE__ */ jsxRuntime.jsx(
1489
- "div",
1490
- {
1491
- className: ui.cn(
1492
- "absolute inset-0 box-border flex flex-col overflow-hidden",
1493
- box2.anchor === "middle" && "justify-center",
1494
- box2.anchor === "bottom" && "justify-end"
1495
- ),
1496
- style: { ...shapeStyle(box2), padding: inset },
1497
- children: typing ? /* @__PURE__ */ jsxRuntime.jsx(
1498
- "textarea",
1499
- {
1500
- autoFocus: true,
1501
- defaultValue: chunk4TTX6ZNS_cjs.boxText(box2),
1502
- className: "pointer-events-auto w-full flex-1 resize-none bg-transparent p-0 outline-none",
1503
- style: {
1504
- ...runStyle(run ?? { }, font),
1505
- lineHeight: 1.2,
1506
- textAlign: box2.paragraphs[0]?.align ?? "left"
1507
- },
1508
- onPointerDown: (event) => event.stopPropagation(),
1509
- onBlur: (event) => {
1510
- host.setText(box2.id, event.currentTarget.value);
1511
- setTyping(false);
1512
- },
1513
- onKeyDown: (event) => {
1514
- event.stopPropagation();
1515
- if (event.key === "Escape") event.currentTarget.blur();
1516
- },
1517
- "aria-label": "Text",
1518
- "data-testid": "stage-box-text-input"
1519
- }
1520
- ) : chunk4TTX6ZNS_cjs.boxText(box2) || !editable ? /* @__PURE__ */ jsxRuntime.jsx(Paragraphs, { paragraphs: box2.paragraphs, font }) : box2.shape === "text" && /* @__PURE__ */ jsxRuntime.jsx(
1521
- "span",
1522
- {
1523
- className: "text-white/40",
1524
- style: { fontSize: cqw(run?.size ?? chunk4TTX6ZNS_cjs.DEFAULT_TEXT_SIZE) },
1525
- children: "Double-click to type"
1526
- }
1527
- )
1528
- }
1529
- ),
1530
- selected && !typing && !dragging && HANDLES.filter(
1531
- ({ handle }) => box2.shape !== "line" || handle === "e" || handle === "w" || handle === "n" || handle === "s"
1532
- ).map(({ handle, left, top, cursor }) => /* @__PURE__ */ jsxRuntime.jsx(
1533
- "div",
1534
- {
1535
- className: "absolute flex size-5 -translate-x-1/2 -translate-y-1/2 items-center justify-center pointer-coarse:size-11",
1536
- style: { left, top, cursor, touchAction: "none" },
1537
- onPointerDown: (event) => start(event, handle),
1538
- "aria-label": `Resize from ${handle}`,
1539
- "data-testid": `stage-box-resize-${handle}`,
1540
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none size-2.5 rounded-full border-2 border-primary bg-background" })
1541
- },
1542
- handle
1543
- ))
1544
- ]
1545
- }
1546
- );
1547
- });
1548
- var SIZE_STEPS = [8, 10, 12, 14, 16, 18, 20, 24, 28, 32, 36, 44, 54, 66, 80, 96];
1549
- var nextSize = (size, up) => up ? SIZE_STEPS.find((step) => step > size + 0.5) ?? size : [...SIZE_STEPS].reverse().find((step) => step < size - 0.5) ?? size;
1550
- var ALIGN_NEXT = {
1551
- left: "center",
1552
- center: "right",
1553
- right: "left",
1554
- justify: "left"
1555
- };
1556
- var ALIGN_ICON = {
1557
- left: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignLeft, { className: "size-4" }),
1558
- center: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignCenter, { className: "size-4" }),
1559
- right: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignRight, { className: "size-4" }),
1560
- justify: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignLeft, { className: "size-4" })
1561
- };
1562
- function ColorAction({
1563
- label,
1564
- value,
1565
- onChange,
1566
- children
1567
- }) {
1568
- return /* @__PURE__ */ jsxRuntime.jsxs("label", { className: ui.cn(ACTION, "relative cursor-pointer"), title: label, "aria-label": label, children: [
1569
- children,
1570
- /* @__PURE__ */ jsxRuntime.jsx(
1571
- "span",
1572
- {
1573
- className: "pointer-events-none absolute inset-x-1.5 bottom-0.5 h-0.5 rounded-full",
1574
- style: { background: value }
1575
- }
1576
- ),
1577
- /* @__PURE__ */ jsxRuntime.jsx(
1578
- "input",
1579
- {
1580
- type: "color",
1581
- value,
1582
- onChange: (event) => onChange(event.target.value),
1583
- className: "absolute inset-0 size-full cursor-pointer opacity-0",
1584
- "aria-label": label
1585
- }
1586
- )
1587
- ] });
1588
- }
1589
- function BoxActionBar({ box: box2, onRemoved }) {
1590
- const actions = chunk4TTX6ZNS_cjs.usePresentation.getState();
1591
- const run = chunk4TTX6ZNS_cjs.firstRun(box2);
1592
- const size = run?.size ?? chunk4TTX6ZNS_cjs.DEFAULT_TEXT_SIZE;
1593
- const align = box2.paragraphs[0]?.align ?? "left";
1594
- const update = (change) => actions.updateBox(box2.id, change);
1595
- const text = box2.shape !== "line";
1596
- const top = Math.max(0, box2.frame.y);
1597
- return /* @__PURE__ */ jsxRuntime.jsxs(
1598
- "div",
1599
- {
1600
- role: "toolbar",
1601
- "aria-label": "Text box",
1602
- className: "absolute z-20 flex items-center gap-0.5 rounded-md border border-border bg-background p-0.5 shadow-md",
1603
- style: {
1604
- left: `${Math.min(Math.max(0, box2.frame.x), 0.6) * 100}%`,
1605
- top: `calc(${top * 100}% - 40px)`
1606
- },
1607
- onPointerDown: (event) => event.stopPropagation(),
1608
- "data-testid": "box-action-bar",
1609
- children: [
1610
- text && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1611
- /* @__PURE__ */ jsxRuntime.jsx(
1612
- Action,
1613
- {
1614
- label: "Smaller",
1615
- onClick: () => update((b) => chunk4TTX6ZNS_cjs.styleRuns(b, (r) => ({ ...r, size: nextSize(r.size ?? size, false) }))),
1616
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AArrowDown, { className: "size-4" })
1617
- }
1618
- ),
1619
- /* @__PURE__ */ jsxRuntime.jsx(
1620
- "span",
1621
- {
1622
- className: "w-7 text-center text-xs tabular-nums text-muted-foreground",
1623
- "data-testid": "box-text-size",
1624
- children: Math.round(size)
1625
- }
1626
- ),
1627
- /* @__PURE__ */ jsxRuntime.jsx(
1628
- Action,
1629
- {
1630
- label: "Larger",
1631
- onClick: () => update((b) => chunk4TTX6ZNS_cjs.styleRuns(b, (r) => ({ ...r, size: nextSize(r.size ?? size, true) }))),
1632
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AArrowUp, { className: "size-4" })
1633
- }
1634
- ),
1635
- /* @__PURE__ */ jsxRuntime.jsx(
1636
- Action,
1637
- {
1638
- label: "Bold",
1639
- onClick: () => update((b) => chunk4TTX6ZNS_cjs.styleRuns(b, (r) => ({ ...r, bold: !run?.bold }))),
1640
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bold, { className: ui.cn("size-4", run?.bold && "text-primary") })
1641
- }
1642
- ),
1643
- /* @__PURE__ */ jsxRuntime.jsx(
1644
- Action,
1645
- {
1646
- label: "Italic",
1647
- onClick: () => update((b) => chunk4TTX6ZNS_cjs.styleRuns(b, (r) => ({ ...r, italic: !run?.italic }))),
1648
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Italic, { className: ui.cn("size-4", run?.italic && "text-primary") })
1649
- }
1650
- ),
1651
- /* @__PURE__ */ jsxRuntime.jsx(
1652
- Action,
1653
- {
1654
- label: "Align",
1655
- onClick: () => update((b) => ({
1656
- ...b,
1657
- paragraphs: b.paragraphs.map((p) => ({ ...p, align: ALIGN_NEXT[align] }))
1658
- })),
1659
- children: ALIGN_ICON[align]
1660
- }
1661
- ),
1662
- /* @__PURE__ */ jsxRuntime.jsx(
1663
- ColorAction,
1664
- {
1665
- label: "Text colour",
1666
- value: run?.color ?? chunk4TTX6ZNS_cjs.TEXT_COLORS.body,
1667
- onChange: (color) => update((b) => chunk4TTX6ZNS_cjs.styleRuns(b, (r) => ({ ...r, color }))),
1668
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Baseline, { className: "size-4" })
1669
- }
1670
- )
1671
- ] }),
1672
- /* @__PURE__ */ jsxRuntime.jsx(
1673
- ColorAction,
1674
- {
1675
- label: box2.shape === "line" ? "Line colour" : "Fill",
1676
- value: (box2.shape === "line" ? box2.line?.color : box2.fill) ?? "#ffffff",
1677
- onChange: (color) => update(
1678
- (b) => b.shape === "line" ? { ...b, line: { width: b.line?.width ?? 2, ...b.line, color } } : { ...b, fill: color, shape: b.shape === "text" ? "rect" : b.shape }
1679
- ),
1680
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PaintBucket, { className: "size-4" })
1681
- }
1682
- ),
1683
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-0.5 h-5 w-px bg-border" }),
1684
- /* @__PURE__ */ jsxRuntime.jsx(Action, { label: "In front of the clips", onClick: () => actions.restackBox(box2.id, "front"), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BringToFront, { className: "size-4" }) }),
1685
- /* @__PURE__ */ jsxRuntime.jsx(Action, { label: "Behind the clips", onClick: () => actions.restackBox(box2.id, "back"), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SendToBack, { className: "size-4" }) }),
1686
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-0.5 h-5 w-px bg-border" }),
1687
- /* @__PURE__ */ jsxRuntime.jsx(
1688
- "button",
1689
- {
1690
- type: "button",
1691
- className: ui.cn(ACTION, "text-destructive hover:bg-destructive/10"),
1692
- title: "Delete (Delete)",
1693
- "aria-label": "Delete",
1694
- onClick: () => {
1695
- actions.removeBox(box2.id);
1696
- onRemoved();
1697
- },
1698
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "size-4" })
1699
- }
1700
- )
1701
- ]
1702
- }
1703
- );
1704
- }
1705
- var GuideLayer = react.memo(
1706
- react.forwardRef(function GuideLayer2(_, ref) {
1707
- const [guides, setGuides] = react.useState([]);
1708
- react.useImperativeHandle(ref, () => ({ set: setGuides }), []);
1709
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: guides.map((guide) => /* @__PURE__ */ jsxRuntime.jsx(
1710
- "div",
1711
- {
1712
- className: "pointer-events-none absolute z-10 bg-primary",
1713
- style: guide.axis === "x" ? { left: `${guide.at * 100}%`, top: 0, bottom: 0, width: 1 } : { top: `${guide.at * 100}%`, left: 0, right: 0, height: 1 },
1714
- "data-testid": `stage-guide-${guide.axis}`
1715
- },
1716
- `${guide.axis}-${guide.at}`
1717
- )) });
1718
- })
1719
- );
1720
- function PresentationStage({
1721
- editable = false,
1722
- slideIndex,
1723
- selected = null,
1724
- onSelect,
1725
- onEditImage,
1726
- onCropImage,
1727
- textEditing,
1728
- overlay,
1729
- className
1730
- }) {
1731
- const index = chunk4TTX6ZNS_cjs.usePresentation((s) => slideIndex ?? s.current);
1732
- const slide = chunk4TTX6ZNS_cjs.usePresentation((s) => s.slides[index]);
1733
- const clips = chunk4TTX6ZNS_cjs.usePresentation((s) => s.clips);
1734
- const blank = chunk4TTX6ZNS_cjs.usePresentation((s) => s.blank && !editable);
1735
- const captions = chunk4TTX6ZNS_cjs.usePresentation((s) => s.captions);
1736
- const columnValues = chunk4TTX6ZNS_cjs.usePresentation((s) => s.columnValues);
1737
- const theme = chunk4TTX6ZNS_cjs.usePresentation((s) => s.theme);
1738
- const logoImage = chunk4TTX6ZNS_cjs.usePresentation((s) => s.logoImage);
1739
- const media = chunk4TTX6ZNS_cjs.usePresentation((s) => s.media);
1740
- const stageRef = react.useRef(null);
1741
- const guideLayer = react.useRef(null);
1742
- const dropping = chunk4TTX6ZNS_cjs.usePresentation((s) => editable && s.dragging !== null);
1743
- const [dragging, setDragging] = react.useState(false);
1744
- const latest = react.useRef({ slide, clips, index, onSelect });
1745
- latest.current = { slide, clips, index, onSelect };
1746
- const host = react.useMemo(
1747
- () => ({
1748
- stageBox: () => stageRef.current?.getBoundingClientRect() ?? null,
1749
- others: (clipId) => {
1750
- const { slide: current2, clips: all } = latest.current;
1751
- return (current2?.items ?? []).filter((item) => item.clipId !== clipId).map((item) => ({
1752
- frame: item.frame,
1753
- aspect: all.find((clip) => clip.id === item.clipId)?.aspect ?? 1
1754
- }));
1755
- },
1756
- select: (clipId) => {
1757
- chunk4TTX6ZNS_cjs.usePresentation.getState().goTo(latest.current.index);
1758
- latest.current.onSelect?.(clipId);
1759
- },
1760
- guides: (guides) => guideLayer.current?.set(guides),
1761
- dragging: setDragging,
1762
- commit: (clipId, frame, shape) => {
1763
- const state = chunk4TTX6ZNS_cjs.usePresentation.getState();
1764
- state.goTo(latest.current.index);
1765
- if (shape) state.reshapeClip(clipId, frame, shape.rect, shape.aspect);
1766
- else state.setFrame(clipId, frame);
1767
- }
1768
- }),
1769
- []
1770
- );
1771
- const boxHost = react.useMemo(
1772
- () => ({
1773
- stageBox: () => stageRef.current?.getBoundingClientRect() ?? null,
1774
- select: (boxId) => {
1775
- chunk4TTX6ZNS_cjs.usePresentation.getState().goTo(latest.current.index);
1776
- latest.current.onSelect?.(boxId);
1777
- },
1778
- commit: (boxId, frame) => chunk4TTX6ZNS_cjs.usePresentation.getState().updateBox(boxId, (box2) => ({ ...box2, frame })),
1779
- setText: (boxId, text) => chunk4TTX6ZNS_cjs.usePresentation.getState().setBoxText(boxId, text)
1780
- }),
1781
- []
1782
- );
1783
- const font = chunk4TTX6ZNS_cjs.FONTS[theme.font].css;
1784
- const boxes = slide?.boxes ?? [];
1785
- const selectedBox = selected ? boxes.find((box2) => box2.id === selected) : void 0;
1786
- const renderBoxes = (front) => boxes.filter((box2) => !!box2.front === front).map((box2) => /* @__PURE__ */ jsxRuntime.jsx(
1787
- StageBox,
1788
- {
1789
- box: box2,
1790
- font,
1791
- editable,
1792
- selected: editable && selected === box2.id,
1793
- host: boxHost
1794
- },
1795
- box2.id
1796
- ));
1797
- const clipOf = (id) => clips.find((clip) => clip.id === id);
1798
- const selectedFrame = selected ? slide?.items.find((item) => item.clipId === selected)?.frame : void 0;
1799
- react.useEffect(() => {
1800
- const stage = stageRef.current;
1801
- const view = stage?.ownerDocument.defaultView;
1802
- if (!editable || !selected || !stage || !view) return;
1803
- let sum = { x: 0, y: 0 };
1804
- let request = null;
1805
- const onWheel = (event) => {
1806
- const item = event.target?.closest?.(
1807
- `[data-testid="stage-item-${selected}"]`
1808
- );
1809
- const clip = chunk4TTX6ZNS_cjs.usePresentation.getState().clips.find((entry) => entry.id === selected);
1810
- if (!item || !clip) return;
1811
- event.preventDefault();
1812
- const box2 = item.getBoundingClientRect();
1813
- const horizontal = event.shiftKey && !event.deltaX;
1814
- const deltaX = horizontal ? event.deltaY : event.deltaX;
1815
- const deltaY = horizontal ? 0 : event.deltaY;
1816
- sum = {
1817
- x: sum.x + deltaX / box2.width * clip.rect.w,
1818
- y: sum.y + deltaY / box2.height * clip.rect.h
1819
- };
1820
- request ??= view.requestAnimationFrame(() => {
1821
- request = null;
1822
- chunk4TTX6ZNS_cjs.usePresentation.getState().panClip(selected, sum.x, sum.y);
1823
- sum = { x: 0, y: 0 };
1824
- });
1825
- };
1826
- stage.addEventListener("wheel", onWheel, { passive: false });
1827
- return () => {
1828
- stage.removeEventListener("wheel", onWheel);
1829
- if (request !== null) view.cancelAnimationFrame(request);
1830
- };
1831
- }, [editable, selected]);
1832
- return /* @__PURE__ */ jsxRuntime.jsx(
1833
- "div",
1834
- {
1835
- className: ui.cn("relative h-full w-full", !editable && "overflow-hidden bg-black", className),
1836
- style: { containerType: "size" },
1837
- "data-testid": editable ? "presentation-stage-editor" : "presentation-stage",
1838
- children: /* @__PURE__ */ jsxRuntime.jsxs(
1839
- "div",
1840
- {
1841
- ref: stageRef,
1842
- className: ui.cn(
1843
- "absolute inset-0 m-auto",
1844
- editable ? "shadow-md" : "overflow-hidden",
1845
- dropping && "outline outline-2 outline-offset-2 outline-primary"
1846
- ),
1847
- style: {
1848
- width: "min(100cqw, calc(100cqh * 16 / 9))",
1849
- height: "min(100cqh, calc(100cqw * 9 / 16))",
1850
- containerType: "inline-size",
1851
- background: slide?.background ? chunk4TTX6ZNS_cjs.slideBackgroundCss(slide.background, media) : chunk4TTX6ZNS_cjs.backgroundCss(theme.background),
1852
- fontFamily: chunk4TTX6ZNS_cjs.FONTS[theme.font].css
1853
- },
1854
- onPointerDown: () => {
1855
- if (!editable) return;
1856
- chunk4TTX6ZNS_cjs.usePresentation.getState().goTo(index);
1857
- onSelect?.(null);
1858
- },
1859
- ...editable ? { [DROP_ATTRIBUTE]: "stage", "data-slide-index": index } : {},
1860
- "aria-label": `Slide ${index + 1}`,
1861
- children: [
1862
- blank && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-20 bg-black" }),
1863
- slide && /* @__PURE__ */ jsxRuntime.jsx(
1864
- SlideDecor,
1865
- {
1866
- slide,
1867
- theme,
1868
- labels: captions,
1869
- logoImage,
1870
- editable,
1871
- editing: textEditing
1872
- }
1873
- ),
1874
- renderBoxes(false),
1875
- slide?.items.map((item) => {
1876
- const clip = clipOf(item.clipId);
1877
- if (!clip) return null;
1878
- return /* @__PURE__ */ jsxRuntime.jsx(
1879
- StageItem,
1880
- {
1881
- clip,
1882
- frame: item.frame,
1883
- editable,
1884
- selected: editable && selected === clip.id,
1885
- dim: false,
1886
- label: captions ? chunk4TTX6ZNS_cjs.clipLabel(clip, columnValues) : "",
1887
- host
1888
- },
1889
- clip.id
1890
- );
1891
- }),
1892
- renderBoxes(true),
1893
- editable && /* @__PURE__ */ jsxRuntime.jsx(GuideLayer, { ref: guideLayer }),
1894
- editable && selectedFrame && selected && !dragging && /* @__PURE__ */ jsxRuntime.jsx(
1895
- ClipActionBar,
1896
- {
1897
- clipId: selected,
1898
- at: selectedFrame,
1899
- onRemoved: () => onSelect?.(null),
1900
- onEditImage: onEditImage && clipOf(selected)?.kind === "image" ? () => onEditImage(selected) : void 0,
1901
- onCropImage: onCropImage && clipOf(selected)?.kind === "image" ? () => onCropImage(selected) : void 0
1902
- }
1903
- ),
1904
- editable && selectedBox && /* @__PURE__ */ jsxRuntime.jsx(BoxActionBar, { box: selectedBox, onRemoved: () => onSelect?.(null) }),
1905
- overlay
1906
- ]
1907
- }
1908
- )
1909
- }
1910
- );
1911
- }
1912
- function SlideAction({
1913
- label,
1914
- onClick,
1915
- disabled,
1916
- children
1917
- }) {
1918
- return /* @__PURE__ */ jsxRuntime.jsx(
1919
- ui.Button,
1920
- {
1921
- type: "button",
1922
- size: "icon",
1923
- variant: "ghost",
1924
- className: "size-7 text-muted-foreground hover:text-foreground pointer-coarse:size-10",
1925
- title: label,
1926
- "aria-label": label,
1927
- disabled,
1928
- onClick,
1929
- children
1930
- }
1931
- );
1932
- }
1933
482
  var SlideCard = react.memo(function SlideCard2({
1934
483
  index,
1935
484
  count,
@@ -1939,20 +488,20 @@ var SlideCard = react.memo(function SlideCard2({
1939
488
  onEditImage,
1940
489
  onCropImage
1941
490
  }) {
1942
- const empty = chunk4TTX6ZNS_cjs.usePresentation((s) => {
491
+ const empty = chunkORNLCBNE_cjs.usePresentation((s) => {
1943
492
  const slide = s.slides[index];
1944
- return !!slide && !slide.items.length && !slide.boxes.length && slide.layout !== "title" && slide.layout !== "section";
493
+ return !!slide && !slide.items.length && !slide.boxes.length && !slide.points.trim() && slide.layout !== "title" && slide.layout !== "section";
1945
494
  });
1946
- const notes = chunk4TTX6ZNS_cjs.usePresentation((s) => s.slides[index]?.notes ?? "");
495
+ const notes = chunkORNLCBNE_cjs.usePresentation((s) => s.slides[index]?.notes ?? "");
1947
496
  const textEditing = react.useMemo(
1948
497
  () => ({
1949
- onTitle: (title) => chunk4TTX6ZNS_cjs.usePresentation.getState().setSlideCaption(title, index),
1950
- onPoints: (points) => chunk4TTX6ZNS_cjs.usePresentation.getState().setSlidePoints(points, index)
498
+ onTitle: (title) => chunkORNLCBNE_cjs.usePresentation.getState().setSlideCaption(title, index),
499
+ onPoints: (points) => chunkORNLCBNE_cjs.usePresentation.getState().setSlidePoints(points, index)
1951
500
  }),
1952
501
  [index]
1953
502
  );
1954
503
  const select = react.useCallback((clipId) => onSelect(index, clipId), [onSelect, index]);
1955
- const actions = chunk4TTX6ZNS_cjs.usePresentation.getState();
504
+ const actions = chunkORNLCBNE_cjs.usePresentation.getState();
1956
505
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group relative flex gap-2", "data-testid": `slide-${index}`, children: [
1957
506
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-9 shrink-0 flex-col items-center gap-0.5", children: [
1958
507
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -1976,26 +525,61 @@ var SlideCard = react.memo(function SlideCard2({
1976
525
  "data-testid": `slide-actions-${index}`,
1977
526
  children: [
1978
527
  /* @__PURE__ */ jsxRuntime.jsx(LayoutMenu, { index, compact: true }),
1979
- /* @__PURE__ */ jsxRuntime.jsx(
1980
- SlideAction,
1981
- {
1982
- label: "Move up",
1983
- disabled: index === 0,
1984
- onClick: () => actions.moveSlide(index, index - 1),
1985
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "size-3.5" })
1986
- }
1987
- ),
1988
- /* @__PURE__ */ jsxRuntime.jsx(
1989
- SlideAction,
1990
- {
1991
- label: "Move down",
1992
- disabled: index === count - 1,
1993
- onClick: () => actions.moveSlide(index, index + 1),
1994
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "size-3.5" })
1995
- }
1996
- ),
1997
- /* @__PURE__ */ jsxRuntime.jsx(SlideAction, { label: "Duplicate", onClick: () => actions.duplicateSlide(index), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "size-3.5" }) }),
1998
- /* @__PURE__ */ jsxRuntime.jsx(SlideAction, { label: "Delete slide", onClick: () => actions.removeSlide(index), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "size-3.5" }) })
528
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
529
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
530
+ ui.Button,
531
+ {
532
+ type: "button",
533
+ size: "icon",
534
+ variant: "ghost",
535
+ className: "size-7 text-muted-foreground hover:text-foreground pointer-coarse:size-11",
536
+ title: "Slide actions",
537
+ "aria-label": `Slide ${index + 1} actions`,
538
+ "data-testid": `slide-menu-${index}`,
539
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { className: "size-3.5" })
540
+ }
541
+ ) }),
542
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuContent, { align: "start", children: [
543
+ /* @__PURE__ */ jsxRuntime.jsxs(
544
+ ui.DropdownMenuItem,
545
+ {
546
+ disabled: index === 0,
547
+ onSelect: () => actions.moveSlide(index, index - 1),
548
+ children: [
549
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "size-4" }),
550
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "Move up" })
551
+ ]
552
+ }
553
+ ),
554
+ /* @__PURE__ */ jsxRuntime.jsxs(
555
+ ui.DropdownMenuItem,
556
+ {
557
+ disabled: index === count - 1,
558
+ onSelect: () => actions.moveSlide(index, index + 1),
559
+ children: [
560
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "size-4" }),
561
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "Move down" })
562
+ ]
563
+ }
564
+ ),
565
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: () => actions.duplicateSlide(index), children: [
566
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "size-4" }),
567
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "Duplicate" })
568
+ ] }),
569
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuSeparator, {}),
570
+ /* @__PURE__ */ jsxRuntime.jsxs(
571
+ ui.DropdownMenuItem,
572
+ {
573
+ className: "text-destructive",
574
+ onSelect: () => actions.removeSlide(index),
575
+ children: [
576
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "size-4" }),
577
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "Delete slide" })
578
+ ]
579
+ }
580
+ )
581
+ ] })
582
+ ] })
1999
583
  ]
2000
584
  }
2001
585
  )
@@ -2009,7 +593,7 @@ var SlideCard = react.memo(function SlideCard2({
2009
593
  ),
2010
594
  children: [
2011
595
  /* @__PURE__ */ jsxRuntime.jsx(
2012
- PresentationStage,
596
+ chunkJY7UUZQG_cjs.PresentationStage,
2013
597
  {
2014
598
  editable: true,
2015
599
  slideIndex: index,
@@ -2027,7 +611,7 @@ var SlideCard = react.memo(function SlideCard2({
2027
611
  value: notes,
2028
612
  rows: notes.split("\n").length,
2029
613
  placeholder: "Speaker notes",
2030
- onChange: (event) => chunk4TTX6ZNS_cjs.usePresentation.getState().setSlideNotes(event.target.value, index),
614
+ onChange: (event) => chunkORNLCBNE_cjs.usePresentation.getState().setSlideNotes(event.target.value, index),
2031
615
  className: "mt-2 block w-full resize-none rounded-sm border-0 bg-transparent px-1 py-0.5 text-xs text-muted-foreground placeholder:text-muted-foreground/50 focus:bg-background focus:text-foreground focus:outline-none focus:ring-1 focus:ring-ring",
2032
616
  "aria-label": `Speaker notes for slide ${index + 1}`,
2033
617
  "data-testid": `slide-notes-${index}`
@@ -2051,10 +635,10 @@ var INSERTS = [
2051
635
  ];
2052
636
  function InsertMenu({ onInserted }) {
2053
637
  const insert = (shape) => {
2054
- const state = chunk4TTX6ZNS_cjs.usePresentation.getState();
638
+ const state = chunkORNLCBNE_cjs.usePresentation.getState();
2055
639
  const slide = state.slides[state.current];
2056
- const box2 = chunk4TTX6ZNS_cjs.newBox(shape, chunk4TTX6ZNS_cjs.accentColor(state.theme.accent));
2057
- const dark = chunk4TTX6ZNS_cjs.isLightBackground(slide?.background);
640
+ const box2 = chunkORNLCBNE_cjs.newBox(shape, chunkORNLCBNE_cjs.accentColor(state.theme.accent));
641
+ const dark = chunkORNLCBNE_cjs.isLightBackground(slide?.background);
2058
642
  const { id, ...rest } = dark ? {
2059
643
  ...box2,
2060
644
  paragraphs: box2.paragraphs.map((p) => ({
@@ -2097,7 +681,7 @@ function InsertSlide({ after, always }) {
2097
681
  "button",
2098
682
  {
2099
683
  type: "button",
2100
- onClick: () => chunk4TTX6ZNS_cjs.usePresentation.getState().addSlide(void 0, after),
684
+ onClick: () => chunkORNLCBNE_cjs.usePresentation.getState().addSlide(void 0, after),
2101
685
  className: ui.cn(
2102
686
  "flex items-center gap-1 rounded-full border border-dashed border-border bg-background px-2.5 py-0.5 text-xs text-muted-foreground transition-opacity hover:border-solid hover:text-foreground focus-visible:opacity-100",
2103
687
  !always && "opacity-0 group-hover/insert:opacity-100 pointer-coarse:opacity-100"
@@ -2120,11 +704,11 @@ function SlidesEditor({
2120
704
  onEditImage,
2121
705
  onCropImage
2122
706
  }) {
2123
- const ids = chunk4TTX6ZNS_cjs.usePresentation((s) => s.slides.map((slide) => slide.id).join(" "));
707
+ const ids = chunkORNLCBNE_cjs.usePresentation((s) => s.slides.map((slide) => slide.id).join(" "));
2124
708
  const slideIds = react.useMemo(() => ids.split(" "), [ids]);
2125
- const current2 = chunk4TTX6ZNS_cjs.usePresentation((s) => s.current);
2126
- const captions = chunk4TTX6ZNS_cjs.usePresentation((s) => s.captions);
2127
- const presenting = chunk4TTX6ZNS_cjs.usePresentation((s) => s.presenting);
709
+ const current2 = chunkORNLCBNE_cjs.usePresentation((s) => s.current);
710
+ const captions = chunkORNLCBNE_cjs.usePresentation((s) => s.captions);
711
+ const presenting = chunkORNLCBNE_cjs.usePresentation((s) => s.presenting);
2128
712
  const [selection, setSelection] = react.useState(null);
2129
713
  const [view, setView] = react.useState(null);
2130
714
  const list = react.useRef(null);
@@ -2138,7 +722,7 @@ function SlidesEditor({
2138
722
  () => ({ clipId: selection?.clipId ?? null, clear: () => setSelection(null) }),
2139
723
  [selection]
2140
724
  );
2141
- chunkWFMWKPGY_cjs.usePresenterKeys(view, false, keySelection);
725
+ chunkADPRIBSH_cjs.usePresenterKeys(view, false, keySelection);
2142
726
  react.useEffect(() => {
2143
727
  const card = list.current?.querySelector(`[data-testid="slide-${current2}"]`);
2144
728
  card?.scrollIntoView?.({ block: "nearest", behavior: "smooth" });
@@ -2194,7 +778,7 @@ function SlidesEditor({
2194
778
  ui.DropdownMenuCheckboxItem,
2195
779
  {
2196
780
  checked: captions,
2197
- onCheckedChange: (on) => chunk4TTX6ZNS_cjs.usePresentation.getState().setCaptions(!!on),
781
+ onCheckedChange: (on) => chunkORNLCBNE_cjs.usePresentation.getState().setCaptions(!!on),
2198
782
  children: "Show source labels"
2199
783
  }
2200
784
  )
@@ -2207,7 +791,7 @@ function SlidesEditor({
2207
791
  size: "sm",
2208
792
  variant: "destructive",
2209
793
  className: "ml-0.5 h-8 rounded-full",
2210
- onClick: () => chunk4TTX6ZNS_cjs.usePresentation.getState().setPresenting(false),
794
+ onClick: () => chunkORNLCBNE_cjs.usePresentation.getState().setPresenting(false),
2211
795
  title: "Stop presenting (the presentation window closes)",
2212
796
  "data-testid": "presentation-stop-button",
2213
797
  children: [
@@ -2246,7 +830,7 @@ function SlidesEditor({
2246
830
  // src/presentation/draw-boxes.ts
2247
831
  var LINE_HEIGHT = 1.2;
2248
832
  function fontOf(run, themeFont, width) {
2249
- const size = chunk4TTX6ZNS_cjs.pointsToStage(run.size ?? chunk4TTX6ZNS_cjs.DEFAULT_TEXT_SIZE) * width;
833
+ const size = chunkORNLCBNE_cjs.pointsToStage(run.size ?? chunkORNLCBNE_cjs.DEFAULT_TEXT_SIZE) * width;
2250
834
  const family = run.font ? `"${run.font}", ${themeFont}` : themeFont;
2251
835
  return `${run.italic ? "italic " : ""}${run.bold ? 700 : 400} ${size}px ${family}`;
2252
836
  }
@@ -2264,9 +848,9 @@ function drawBox(context, box2, width, height, themeFont) {
2264
848
  context.translate(frame.x * width + w / 2, frame.y * height + h / 2);
2265
849
  if (box2.rotation) context.rotate(box2.rotation * Math.PI / 180);
2266
850
  context.translate(-w / 2, -h / 2);
2267
- const lineWidth = box2.line ? Math.max(1, chunk4TTX6ZNS_cjs.pointsToStage(box2.line.width) * width) : 0;
851
+ const lineWidth = box2.line ? Math.max(1, chunkORNLCBNE_cjs.pointsToStage(box2.line.width) * width) : 0;
2268
852
  if (box2.shape === "line") {
2269
- context.strokeStyle = box2.line?.color ?? chunk4TTX6ZNS_cjs.TEXT_COLORS.body;
853
+ context.strokeStyle = box2.line?.color ?? chunkORNLCBNE_cjs.TEXT_COLORS.body;
2270
854
  context.lineWidth = lineWidth || 1;
2271
855
  if (box2.line?.dash) context.setLineDash([lineWidth * 3, lineWidth * 2]);
2272
856
  context.beginPath();
@@ -2291,12 +875,12 @@ function drawBox(context, box2, width, height, themeFont) {
2291
875
  context.stroke();
2292
876
  context.setLineDash([]);
2293
877
  }
2294
- const inset = chunk4TTX6ZNS_cjs.pointsToStage(box2.inset ?? chunk4TTX6ZNS_cjs.DEFAULT_INSET) * width;
878
+ const inset = chunkORNLCBNE_cjs.pointsToStage(box2.inset ?? chunkORNLCBNE_cjs.DEFAULT_INSET) * width;
2295
879
  const room = w - 2 * inset;
2296
880
  context.textBaseline = "alphabetic";
2297
881
  const lines = [];
2298
882
  for (const paragraph of box2.paragraphs) {
2299
- const size = chunk4TTX6ZNS_cjs.pointsToStage(paragraph.runs[0]?.size ?? chunk4TTX6ZNS_cjs.DEFAULT_TEXT_SIZE) * width;
883
+ const size = chunkORNLCBNE_cjs.pointsToStage(paragraph.runs[0]?.size ?? chunkORNLCBNE_cjs.DEFAULT_TEXT_SIZE) * width;
2300
884
  const indent = (paragraph.level ?? 0) * 0.5 * size + (paragraph.bullet ? size * 0.9 : 0);
2301
885
  const words = [];
2302
886
  for (const run of paragraph.runs) {
@@ -2342,12 +926,12 @@ function drawBox(context, box2, width, height, themeFont) {
2342
926
  const baseline = y + line.size * (LINE_HEIGHT - 0.2);
2343
927
  if (line.bullet) {
2344
928
  context.font = fontOf(line.bullet, themeFont, width);
2345
- context.fillStyle = line.bullet.color ?? chunk4TTX6ZNS_cjs.TEXT_COLORS.body;
929
+ context.fillStyle = line.bullet.color ?? chunkORNLCBNE_cjs.TEXT_COLORS.body;
2346
930
  context.fillText("\u2022", inset + line.indent - line.size * 0.9, baseline);
2347
931
  }
2348
932
  for (const piece of line.pieces) {
2349
933
  context.font = fontOf(piece.run, themeFont, width);
2350
- context.fillStyle = piece.run.color ?? chunk4TTX6ZNS_cjs.TEXT_COLORS.body;
934
+ context.fillStyle = piece.run.color ?? chunkORNLCBNE_cjs.TEXT_COLORS.body;
2351
935
  context.fillText(piece.text, x, baseline);
2352
936
  if (piece.run.underline) {
2353
937
  context.fillRect(x, baseline + line.size * 0.08, piece.width, Math.max(1, line.size * 0.05));
@@ -2364,7 +948,7 @@ var boxWords = (box2) => box2.paragraphs.map(
2364
948
  ).filter(Boolean);
2365
949
 
2366
950
  // src/presentation/render-slides.ts
2367
- var SLIDE_PIXELS = { width: 1920, height: Math.round(1920 / chunk4TTX6ZNS_cjs.STAGE_ASPECT) };
951
+ var SLIDE_PIXELS = { width: 1920, height: Math.round(1920 / chunkORNLCBNE_cjs.STAGE_ASPECT) };
2368
952
  async function videoFrame(source, seconds) {
2369
953
  const video = document.createElement("video");
2370
954
  video.muted = true;
@@ -2476,7 +1060,7 @@ async function drawRoundedClip(context, clip, box2, stageWidth, shadow = true) {
2476
1060
  outline2();
2477
1061
  context.clip();
2478
1062
  await drawClip(context, clip, box2);
2479
- if (clip.kind === "pdf") chunk4TTX6ZNS_cjs.paintClipEdge(context, box2, stageWidth);
1063
+ if (clip.kind === "pdf") chunkORNLCBNE_cjs.paintClipEdge(context, box2, stageWidth);
2480
1064
  context.restore();
2481
1065
  context.save();
2482
1066
  context.strokeStyle = "rgba(255,255,255,0.15)";
@@ -2508,7 +1092,7 @@ function wrapLines(context, text, width, max) {
2508
1092
  function drawText(context, box2, lines, theme, width, height) {
2509
1093
  const size = box2.size * width;
2510
1094
  const lineHeight = size * box2.leading;
2511
- context.font = `${box2.weight} ${size}px ${chunk4TTX6ZNS_cjs.FONTS[theme.font].css}`;
1095
+ context.font = `${box2.weight} ${size}px ${chunkORNLCBNE_cjs.FONTS[theme.font].css}`;
2512
1096
  context.textBaseline = "top";
2513
1097
  const indent = box2.bullets ? size * 1.22 : 0;
2514
1098
  const left = box2.x * width;
@@ -2530,10 +1114,10 @@ function drawText(context, box2, lines, theme, width, height) {
2530
1114
  for (const wrapped of paragraphs) {
2531
1115
  if (box2.bullets) {
2532
1116
  const square = size * 0.42;
2533
- context.fillStyle = chunk4TTX6ZNS_cjs.accentColor(theme.accent);
1117
+ context.fillStyle = chunkORNLCBNE_cjs.accentColor(theme.accent);
2534
1118
  context.fillRect(left, y + size * 0.5 - square / 2, square, square);
2535
1119
  }
2536
- context.fillStyle = chunk4TTX6ZNS_cjs.TEXT_COLORS[box2.tone];
1120
+ context.fillStyle = chunkORNLCBNE_cjs.TEXT_COLORS[box2.tone];
2537
1121
  context.textAlign = box2.align === "center" ? "center" : "left";
2538
1122
  for (const line of wrapped) {
2539
1123
  const x = box2.align === "center" ? left + box2.w * width / 2 : left + indent;
@@ -2569,11 +1153,11 @@ async function loadImage(file) {
2569
1153
  }
2570
1154
  }
2571
1155
  function slideWords(slide) {
2572
- const own = slide.layout === "free" ? [] : [slide.caption.trim(), ...chunk4TTX6ZNS_cjs.textLines(slide.points)];
1156
+ const own = slide.layout === "free" ? [] : [slide.caption.trim(), ...chunkORNLCBNE_cjs.textLines(slide.points)];
2573
1157
  return [...own, ...slide.boxes.flatMap(boxWords)].filter(Boolean);
2574
1158
  }
2575
1159
  function drawSlideText(context, slide, look, width, height) {
2576
- const geometry = chunk4TTX6ZNS_cjs.slideGeometry(slide, {
1160
+ const geometry = chunkORNLCBNE_cjs.slideGeometry(slide, {
2577
1161
  labels: look.labels,
2578
1162
  logo: look.theme.logo?.corner ?? null
2579
1163
  });
@@ -2581,13 +1165,13 @@ function drawSlideText(context, slide, look, width, height) {
2581
1165
  if (title && geometry.title) {
2582
1166
  drawText(context, geometry.title, [title], look.theme, width, height);
2583
1167
  if (geometry.rule) {
2584
- context.fillStyle = chunk4TTX6ZNS_cjs.accentColor(look.theme.accent);
1168
+ context.fillStyle = chunkORNLCBNE_cjs.accentColor(look.theme.accent);
2585
1169
  const r = geometry.rule;
2586
1170
  context.fillRect(r.x * width, r.y * height, r.w * width, r.h * height);
2587
1171
  }
2588
1172
  }
2589
1173
  if (geometry.text) {
2590
- drawText(context, geometry.text, chunk4TTX6ZNS_cjs.textLines(slide.points), look.theme, width, height);
1174
+ drawText(context, geometry.text, chunkORNLCBNE_cjs.textLines(slide.points), look.theme, width, height);
2591
1175
  }
2592
1176
  return geometry;
2593
1177
  }
@@ -2599,13 +1183,13 @@ async function renderSlide(slide, clips, look) {
2599
1183
  const context = canvas.getContext("2d");
2600
1184
  if (!context) throw new Error("Could not draw the slides");
2601
1185
  if (slide.background) {
2602
- await chunk4TTX6ZNS_cjs.paintSlideBackground(context, width, height, slide.background, look.media);
1186
+ await chunkORNLCBNE_cjs.paintSlideBackground(context, width, height, slide.background, look.media);
2603
1187
  } else {
2604
- chunk4TTX6ZNS_cjs.paintBackground(context, width, height, look.theme.background);
1188
+ chunkORNLCBNE_cjs.paintBackground(context, width, height, look.theme.background);
2605
1189
  }
2606
1190
  const geometry = drawSlideText(context, slide, look, width, height);
2607
1191
  const text = slideWords(slide);
2608
- const font = chunk4TTX6ZNS_cjs.FONTS[look.theme.font].css;
1192
+ const font = chunkORNLCBNE_cjs.FONTS[look.theme.font].css;
2609
1193
  const drawBoxes = (front) => {
2610
1194
  for (const box2 of slide.boxes) {
2611
1195
  if (!!box2.front === front) drawBox(context, box2, width, height, font);
@@ -2619,16 +1203,16 @@ async function renderSlide(slide, clips, look) {
2619
1203
  x: item.frame.x * width,
2620
1204
  y: item.frame.y * height,
2621
1205
  width: item.frame.w * width,
2622
- height: chunk4TTX6ZNS_cjs.frameHeight(item.frame, clip.aspect) * height
1206
+ height: chunkORNLCBNE_cjs.frameHeight(item.frame, clip.aspect) * height
2623
1207
  };
2624
1208
  if (clip.plain) {
2625
1209
  await drawClip(context, clip, box2);
2626
1210
  continue;
2627
1211
  }
2628
1212
  await drawRoundedClip(context, clip, box2, width);
2629
- const label = chunk4TTX6ZNS_cjs.clipLabel(clip, look.columnValues);
1213
+ const label = chunkORNLCBNE_cjs.clipLabel(clip, look.columnValues);
2630
1214
  if (look.labels && label) {
2631
- context.fillStyle = chunk4TTX6ZNS_cjs.TEXT_COLORS.muted;
1215
+ context.fillStyle = chunkORNLCBNE_cjs.TEXT_COLORS.muted;
2632
1216
  context.font = `${Math.round(width * 0.017)}px ${font}`;
2633
1217
  context.textAlign = "left";
2634
1218
  context.textBaseline = "top";
@@ -2671,7 +1255,7 @@ function addBox(pptx, page, box2, themeFont) {
2671
1255
  if (box2.shape === "line") {
2672
1256
  page.addShape(pptx.ShapeType.line, {
2673
1257
  ...place,
2674
- line: line ?? { color: hex(chunk4TTX6ZNS_cjs.TEXT_COLORS.body), width: 1 }
1258
+ line: line ?? { color: hex(chunkORNLCBNE_cjs.TEXT_COLORS.body), width: 1 }
2675
1259
  });
2676
1260
  return;
2677
1261
  }
@@ -2688,9 +1272,9 @@ function addBox(pptx, page, box2, themeFont) {
2688
1272
  runs.push({
2689
1273
  text: run.text,
2690
1274
  options: {
2691
- fontSize: run.size ?? chunk4TTX6ZNS_cjs.DEFAULT_TEXT_SIZE,
1275
+ fontSize: run.size ?? chunkORNLCBNE_cjs.DEFAULT_TEXT_SIZE,
2692
1276
  fontFace: run.font ?? themeFont,
2693
- color: hex(run.color ?? chunk4TTX6ZNS_cjs.TEXT_COLORS.body),
1277
+ color: hex(run.color ?? chunkORNLCBNE_cjs.TEXT_COLORS.body),
2694
1278
  ...run.bold ? { bold: true } : {},
2695
1279
  ...run.italic ? { italic: true } : {},
2696
1280
  ...run.underline ? { underline: { style: "sng" } } : {},
@@ -2712,7 +1296,7 @@ function addBox(pptx, page, box2, themeFont) {
2712
1296
  // Its part in the slide (its title, its body), kept by name: read back when imported.
2713
1297
  ...box2.role ? { objectName: `ARBI ${box2.role}` } : {},
2714
1298
  valign: box2.anchor ?? "top",
2715
- margin: box2.inset ?? chunk4TTX6ZNS_cjs.DEFAULT_INSET,
1299
+ margin: box2.inset ?? chunkORNLCBNE_cjs.DEFAULT_INSET,
2716
1300
  lineSpacingMultiple: 1,
2717
1301
  fit: "none"
2718
1302
  });
@@ -2742,10 +1326,10 @@ var box = (b) => ({
2742
1326
  function textOptions(text, look) {
2743
1327
  return {
2744
1328
  ...box(text),
2745
- fontFace: chunk4TTX6ZNS_cjs.FONTS[look.theme.font].pptx,
1329
+ fontFace: chunkORNLCBNE_cjs.FONTS[look.theme.font].pptx,
2746
1330
  fontSize: toPoints(text.size),
2747
1331
  bold: text.weight >= 600,
2748
- color: hex2(chunk4TTX6ZNS_cjs.TEXT_COLORS[text.tone]),
1332
+ color: hex2(chunkORNLCBNE_cjs.TEXT_COLORS[text.tone]),
2749
1333
  align: text.align,
2750
1334
  valign: text.anchor ?? "top",
2751
1335
  lineSpacingMultiple: text.leading,
@@ -2758,18 +1342,18 @@ async function buildPptx(deck, look) {
2758
1342
  pptx.layout = "LAYOUT_WIDE";
2759
1343
  pptx.title = deck.title;
2760
1344
  pptx.theme = {
2761
- headFontFace: chunk4TTX6ZNS_cjs.FONTS[look.theme.font].pptx,
2762
- bodyFontFace: chunk4TTX6ZNS_cjs.FONTS[look.theme.font].pptx
1345
+ headFontFace: chunkORNLCBNE_cjs.FONTS[look.theme.font].pptx,
1346
+ bodyFontFace: chunkORNLCBNE_cjs.FONTS[look.theme.font].pptx
2763
1347
  };
2764
1348
  const { width, height } = SLIDE_PIXELS;
2765
1349
  const background = await canvasImage(
2766
1350
  width,
2767
1351
  height,
2768
- (context) => chunk4TTX6ZNS_cjs.paintBackground(context, width, height, look.theme.background)
1352
+ (context) => chunkORNLCBNE_cjs.paintBackground(context, width, height, look.theme.background)
2769
1353
  );
2770
1354
  const logo = look.logo ? await loadImage(look.logo) : null;
2771
1355
  const logoData = logo ? await canvasImage(logo.width, logo.height, (context) => context.drawImage(logo, 0, 0)) : null;
2772
- const themeFont = chunk4TTX6ZNS_cjs.FONTS[look.theme.font].pptx;
1356
+ const themeFont = chunkORNLCBNE_cjs.FONTS[look.theme.font].pptx;
2773
1357
  for (const slide of deck.slides) {
2774
1358
  const page = pptx.addSlide();
2775
1359
  if (slide.background?.color && !slide.background.gradient && !slide.background.image) {
@@ -2780,14 +1364,14 @@ async function buildPptx(deck, look) {
2780
1364
  data: await canvasImage(
2781
1365
  width,
2782
1366
  height,
2783
- (context) => chunk4TTX6ZNS_cjs.paintSlideBackground(context, width, height, own, look.media)
1367
+ (context) => chunkORNLCBNE_cjs.paintSlideBackground(context, width, height, own, look.media)
2784
1368
  )
2785
1369
  };
2786
1370
  } else {
2787
1371
  page.background = { data: background };
2788
1372
  }
2789
1373
  if (slide.notes?.trim()) page.addNotes(slide.notes);
2790
- const geometry = chunk4TTX6ZNS_cjs.slideGeometry(slide, {
1374
+ const geometry = chunkORNLCBNE_cjs.slideGeometry(slide, {
2791
1375
  labels: look.labels,
2792
1376
  logo: look.theme.logo?.corner ?? null
2793
1377
  });
@@ -2795,7 +1379,7 @@ async function buildPptx(deck, look) {
2795
1379
  for (const item of slide.items) {
2796
1380
  const clip = deck.clips.find((entry) => entry.id === item.clipId);
2797
1381
  if (!clip) continue;
2798
- const frame = { ...item.frame, h: chunk4TTX6ZNS_cjs.frameHeight(item.frame, clip.aspect) };
1382
+ const frame = { ...item.frame, h: chunkORNLCBNE_cjs.frameHeight(item.frame, clip.aspect) };
2799
1383
  if (clip.plain) {
2800
1384
  const source = clip.kind === "image" ? await createImageBitmap(clip.source) : null;
2801
1385
  const scale = source ? Math.min(1, 2400 / Math.max(1, clip.rect.w * source.width)) : 1.5;
@@ -2827,13 +1411,13 @@ async function buildPptx(deck, look) {
2827
1411
  altText: clip.caption,
2828
1412
  shadow: { type: "outer", blur: 10, offset: 3, angle: 90, color: "000000", opacity: 0.45 }
2829
1413
  });
2830
- const label = chunk4TTX6ZNS_cjs.clipLabel(clip, look.columnValues);
1414
+ const label = chunkORNLCBNE_cjs.clipLabel(clip, look.columnValues);
2831
1415
  if (look.labels && label) {
2832
1416
  page.addText(label, {
2833
1417
  ...box({ x: frame.x, y: frame.y + frame.h + 8e-3, w: frame.w, h: 0.045 }),
2834
- fontFace: chunk4TTX6ZNS_cjs.FONTS[look.theme.font].pptx,
1418
+ fontFace: chunkORNLCBNE_cjs.FONTS[look.theme.font].pptx,
2835
1419
  fontSize: toPoints(0.017),
2836
- color: hex2(chunk4TTX6ZNS_cjs.TEXT_COLORS.muted),
1420
+ color: hex2(chunkORNLCBNE_cjs.TEXT_COLORS.muted),
2837
1421
  margin: 0,
2838
1422
  valign: "top",
2839
1423
  fit: "shrink"
@@ -2846,12 +1430,12 @@ async function buildPptx(deck, look) {
2846
1430
  if (geometry.rule) {
2847
1431
  page.addShape(pptx.ShapeType.rect, {
2848
1432
  ...box(geometry.rule),
2849
- fill: { color: hex2(chunk4TTX6ZNS_cjs.accentColor(look.theme.accent)) },
2850
- line: { color: hex2(chunk4TTX6ZNS_cjs.accentColor(look.theme.accent)), width: 0 }
1433
+ fill: { color: hex2(chunkORNLCBNE_cjs.accentColor(look.theme.accent)) },
1434
+ line: { color: hex2(chunkORNLCBNE_cjs.accentColor(look.theme.accent)), width: 0 }
2851
1435
  });
2852
1436
  }
2853
1437
  }
2854
- const lines = chunk4TTX6ZNS_cjs.textLines(slide.points);
1438
+ const lines = chunkORNLCBNE_cjs.textLines(slide.points);
2855
1439
  if (geometry.text && lines.length) {
2856
1440
  const text = geometry.text;
2857
1441
  page.addText(
@@ -2885,7 +1469,7 @@ async function buildPptx(deck, look) {
2885
1469
  }
2886
1470
  }
2887
1471
  const deckFile = await pptx.write({ outputType: "blob" });
2888
- return accentBullets(deckFile, chunk4TTX6ZNS_cjs.accentColor(look.theme.accent));
1472
+ return accentBullets(deckFile, chunkORNLCBNE_cjs.accentColor(look.theme.accent));
2889
1473
  }
2890
1474
  async function accentBullets(deck, accent) {
2891
1475
  const { default: JSZip } = await import('jszip');
@@ -3416,7 +2000,7 @@ function renditionClip(deck, part, area, what) {
3416
2000
  fileName: fileName ?? "Presentation.pptx",
3417
2001
  page: part.page,
3418
2002
  rect,
3419
- aspect: frame.w * chunk4TTX6ZNS_cjs.STAGE_ASPECT / Math.max(frame.h, 1e-6),
2003
+ aspect: frame.w * chunkORNLCBNE_cjs.STAGE_ASPECT / Math.max(frame.h, 1e-6),
3420
2004
  caption: "",
3421
2005
  plain: true
3422
2006
  });
@@ -3435,7 +2019,7 @@ function readParagraphs(body, chain, deck, defaults, fontScale, fallback = []) {
3435
2019
  defaults.color ? { color: defaults.color } : {},
3436
2020
  levelStyle(fallback, level, theme)
3437
2021
  ]);
3438
- const runStyle2 = (rPr) => {
2022
+ const runStyle = (rPr) => {
3439
2023
  const s = merge([readRunProps(rPr, theme), style]);
3440
2024
  const color = s.color ?? defaults.base;
3441
2025
  return {
@@ -3458,13 +2042,13 @@ function readParagraphs(body, chain, deck, defaults, fontScale, fallback = []) {
3458
2042
  for (const child of kids(p)) {
3459
2043
  if (child.localName === "r" || child.localName === "fld") {
3460
2044
  const text = kid(child, "t")?.textContent ?? "";
3461
- runs.push({ ...runStyle2(kid(child, "rPr")), text });
2045
+ runs.push({ ...runStyle(kid(child, "rPr")), text });
3462
2046
  } else if (child.localName === "br") {
3463
- paragraphs.push(shape(runs.length ? runs : [{ ...runStyle2(kid(child, "rPr")), text: "" }]));
2047
+ paragraphs.push(shape(runs.length ? runs : [{ ...runStyle(kid(child, "rPr")), text: "" }]));
3464
2048
  runs = [];
3465
2049
  }
3466
2050
  }
3467
- if (!runs.length) runs = [{ ...runStyle2(kid(p, "endParaRPr")), text: "" }];
2051
+ if (!runs.length) runs = [{ ...runStyle(kid(p, "endParaRPr")), text: "" }];
3468
2052
  paragraphs.push(shape(runs));
3469
2053
  }
3470
2054
  while (paragraphs.length > 1 && !paragraphs[paragraphs.length - 1].runs.some((run) => run.text.trim())) {
@@ -3555,7 +2139,7 @@ async function readShape(shape, transform, deck, part, inherit, built) {
3555
2139
  fileName: target?.target.split("/").pop() ?? "Picture",
3556
2140
  page: 1,
3557
2141
  rect,
3558
- aspect: frame.w * chunk4TTX6ZNS_cjs.STAGE_ASPECT / Math.max(frame.h, 1e-6),
2142
+ aspect: frame.w * chunkORNLCBNE_cjs.STAGE_ASPECT / Math.max(frame.h, 1e-6),
3559
2143
  caption: "",
3560
2144
  media: key,
3561
2145
  plain: true
@@ -3778,7 +2362,7 @@ async function importPptx(bytes, options = {}) {
3778
2362
  const cx = numAttr(size, "cx", 12192e3);
3779
2363
  const cy = numAttr(size, "cy", 6858e3);
3780
2364
  const deckAspect = cx / cy;
3781
- const place = deckAspect < chunk4TTX6ZNS_cjs.STAGE_ASPECT ? { w: deckAspect / chunk4TTX6ZNS_cjs.STAGE_ASPECT, h: 1, x: (1 - deckAspect / chunk4TTX6ZNS_cjs.STAGE_ASPECT) / 2, y: 0 } : { w: 1, h: chunk4TTX6ZNS_cjs.STAGE_ASPECT / deckAspect, x: 0, y: (1 - chunk4TTX6ZNS_cjs.STAGE_ASPECT / deckAspect) / 2 };
2365
+ const place = deckAspect < chunkORNLCBNE_cjs.STAGE_ASPECT ? { w: deckAspect / chunkORNLCBNE_cjs.STAGE_ASPECT, h: 1, x: (1 - deckAspect / chunkORNLCBNE_cjs.STAGE_ASPECT) / 2, y: 0 } : { w: 1, h: chunkORNLCBNE_cjs.STAGE_ASPECT / deckAspect, x: 0, y: (1 - chunkORNLCBNE_cjs.STAGE_ASPECT / deckAspect) / 2 };
3782
2366
  const slides = await slideParts(pkg);
3783
2367
  const firstLayout = slides.length ? await pkg.related(slides[0].part, "/slideLayout") : null;
3784
2368
  const firstMaster = firstLayout ? await pkg.related(firstLayout, "/slideMaster") : null;
@@ -3787,7 +2371,7 @@ async function importPptx(bytes, options = {}) {
3787
2371
  theme: firstMaster ? await readTheme(pkg, firstMaster) : { scheme: {}, map: {}, majorFont: "Calibri", minorFont: "Calibri", lineWidths: [] },
3788
2372
  slideSize: { cx, cy },
3789
2373
  place,
3790
- pointScale: chunk4TTX6ZNS_cjs.SLIDE_POINTS.h * place.h / (cy / EMU_PER_POINT),
2374
+ pointScale: chunkORNLCBNE_cjs.SLIDE_POINTS.h * place.h / (cy / EMU_PER_POINT),
3791
2375
  defaultText: kid(pres.documentElement, "defaultTextStyle"),
3792
2376
  options,
3793
2377
  clips: [],
@@ -3883,7 +2467,7 @@ async function importPptx(bytes, options = {}) {
3883
2467
  version: 1,
3884
2468
  title: options.title ?? (coreTitle?.trim() || "Presentation"),
3885
2469
  captions: false,
3886
- theme: chunk4TTX6ZNS_cjs.DEFAULT_THEME,
2470
+ theme: chunkORNLCBNE_cjs.DEFAULT_THEME,
3887
2471
  clips: deck.clips,
3888
2472
  slides: saved,
3889
2473
  ...Object.keys(deck.media).length ? { media: deck.media } : {}
@@ -3971,7 +2555,7 @@ async function presentationData(bytes) {
3971
2555
  if (isZipBytes(bytes)) return readPptxPresentationData(bytes);
3972
2556
  const isPdf = bytes[0] === 37 && bytes[1] === 80 && bytes[2] === 68 && bytes[3] === 70;
3973
2557
  if (!isPdf) return new TextDecoder().decode(bytes);
3974
- const data = await documentTools.readPdfAttachment(bytes, chunk4TTX6ZNS_cjs.PRESENTATION_ATTACHMENT);
2558
+ const data = await documentTools.readPdfAttachment(bytes, chunkORNLCBNE_cjs.PRESENTATION_ATTACHMENT);
3975
2559
  if (!data) {
3976
2560
  throw new Error(
3977
2561
  "This PDF has no editable presentation in it (it may have been changed outside ARBI)."
@@ -3980,7 +2564,7 @@ async function presentationData(bytes) {
3980
2564
  return new TextDecoder().decode(data);
3981
2565
  }
3982
2566
  function current(withoutClips) {
3983
- const state = chunk4TTX6ZNS_cjs.usePresentation.getState();
2567
+ const state = chunkORNLCBNE_cjs.usePresentation.getState();
3984
2568
  return withoutClips ? {
3985
2569
  ...state,
3986
2570
  clips: [],
@@ -4002,18 +2586,18 @@ function usePresentationFiles() {
4002
2586
  const state = current(withoutClips);
4003
2587
  const deck = await buildPptx({ title, slides: state.slides, clips: state.clips }, lookOf(state));
4004
2588
  const fingerprints = await slideFingerprints(deck);
4005
- const data = chunk4TTX6ZNS_cjs.serializePresentation({ ...state, title, fingerprints });
2589
+ const data = chunkORNLCBNE_cjs.serializePresentation({ ...state, title, fingerprints });
4006
2590
  return writePptxPresentationData(deck, JSON.stringify(data, null, 2));
4007
2591
  }, []);
4008
2592
  const save = react.useCallback(
4009
2593
  async (title, { asNew = false, template = false } = {}) => {
4010
2594
  if (!arbi || !workspaceId) throw new Error("Open a workspace to save the presentation.");
4011
- const state = chunk4TTX6ZNS_cjs.usePresentation.getState();
2595
+ const state = chunkORNLCBNE_cjs.usePresentation.getState();
4012
2596
  const versionOf = asNew || template ? null : state.savedId;
4013
2597
  const deck = await buildFile(title, template);
4014
- const file = new File([deck], chunk4TTX6ZNS_cjs.presentationFileName(title), { type: PPTX_TYPE });
2598
+ const file = new File([deck], chunkORNLCBNE_cjs.presentationFileName(title), { type: PPTX_TYPE });
4015
2599
  const result = await arbi.documents.upload([file], {
4016
- folder: template ? chunk4TTX6ZNS_cjs.TEMPLATES_FOLDER : chunk4TTX6ZNS_cjs.PRESENTATIONS_FOLDER,
2600
+ folder: template ? chunkORNLCBNE_cjs.TEMPLATES_FOLDER : chunkORNLCBNE_cjs.PRESENTATIONS_FOLDER,
4017
2601
  workspaceExtId: workspaceId,
4018
2602
  ...versionOf ? { versionOf } : {}
4019
2603
  });
@@ -4038,8 +2622,8 @@ function usePresentationFiles() {
4038
2622
  }
4039
2623
  const pdf = await documentTools.imagesToPdf(pages, { title });
4040
2624
  const result = await arbi.documents.upload(
4041
- [new File([pdf], `${chunk4TTX6ZNS_cjs.safeFileStem(title)}.pdf`, { type: "application/pdf" })],
4042
- { folder: chunk4TTX6ZNS_cjs.EXPORTS_FOLDER, workspaceExtId: workspaceId }
2625
+ [new File([pdf], `${chunkORNLCBNE_cjs.safeFileStem(title)}.pdf`, { type: "application/pdf" })],
2626
+ { folder: chunkORNLCBNE_cjs.EXPORTS_FOLDER, workspaceExtId: workspaceId }
4043
2627
  );
4044
2628
  const id = result.doc_ext_ids?.[0];
4045
2629
  if (!id) throw new Error("The PDF could not be saved.");
@@ -4054,10 +2638,10 @@ function usePresentationFiles() {
4054
2638
  return docs.filter((doc) => {
4055
2639
  const folder = doc.folder ?? "";
4056
2640
  if (!ui.isPresentationFileName(doc.file_name, folder)) return false;
4057
- return scope === "templates" ? folder === chunk4TTX6ZNS_cjs.TEMPLATES_FOLDER : folder.startsWith(chunk4TTX6ZNS_cjs.PRESENTATIONS_FOLDER) && folder !== chunk4TTX6ZNS_cjs.TEMPLATES_FOLDER && !folder.startsWith(chunk4TTX6ZNS_cjs.EXPORTS_FOLDER);
2641
+ return scope === "templates" ? folder === chunkORNLCBNE_cjs.TEMPLATES_FOLDER : folder.startsWith(chunkORNLCBNE_cjs.PRESENTATIONS_FOLDER) && folder !== chunkORNLCBNE_cjs.TEMPLATES_FOLDER && !folder.startsWith(chunkORNLCBNE_cjs.EXPORTS_FOLDER);
4058
2642
  }).map((doc) => ({
4059
2643
  id: doc.external_id,
4060
- title: chunk4TTX6ZNS_cjs.presentationTitle(doc.file_name ?? ""),
2644
+ title: chunkORNLCBNE_cjs.presentationTitle(doc.file_name ?? ""),
4061
2645
  updatedAt: doc.updated_at ?? doc.created_at ?? null
4062
2646
  })).sort((a, b) => (a.updatedAt ?? "") < (b.updatedAt ?? "") ? 1 : -1);
4063
2647
  },
@@ -4073,7 +2657,7 @@ function usePresentationFiles() {
4073
2657
  const openedVersion = version ?? doc?.current_version ?? null;
4074
2658
  if (text === null) {
4075
2659
  const imported = await importPptx(bytes, {
4076
- title: chunk4TTX6ZNS_cjs.presentationTitle(doc?.file_name ?? "Presentation.pptx"),
2660
+ title: chunkORNLCBNE_cjs.presentationTitle(doc?.file_name ?? "Presentation.pptx"),
4077
2661
  documentId: id,
4078
2662
  version: version ?? doc?.current_version,
4079
2663
  fileName: doc?.file_name ?? void 0
@@ -4085,7 +2669,7 @@ function usePresentationFiles() {
4085
2669
  openedVersion
4086
2670
  };
4087
2671
  }
4088
- let saved = chunk4TTX6ZNS_cjs.parsePresentation(text);
2672
+ let saved = chunkORNLCBNE_cjs.parsePresentation(text);
4089
2673
  let changedOutside;
4090
2674
  if (isZipBytes(bytes) && saved.slides.some((slide) => slide.fingerprint)) {
4091
2675
  const now = await slideFingerprints(bytes);
@@ -4116,7 +2700,7 @@ function usePresentationFiles() {
4116
2700
  const startFromTemplate = react.useCallback(
4117
2701
  async (id) => {
4118
2702
  const { saved } = await readSaved(id);
4119
- chunk4TTX6ZNS_cjs.usePresentation.getState().load({
2703
+ chunkORNLCBNE_cjs.usePresentation.getState().load({
4120
2704
  title: "Untitled presentation",
4121
2705
  savedId: null,
4122
2706
  captions: saved.captions,
@@ -4193,7 +2777,7 @@ function usePresentationFiles() {
4193
2777
  );
4194
2778
  const kept = [];
4195
2779
  const newIndex = opened.map((clip) => clip ? kept.push(clip) - 1 : -1);
4196
- chunk4TTX6ZNS_cjs.usePresentation.getState().load({
2780
+ chunkORNLCBNE_cjs.usePresentation.getState().load({
4197
2781
  title: saved.title,
4198
2782
  savedId: legacy ? null : id,
4199
2783
  version: legacy ? null : openedVersion,
@@ -4267,7 +2851,7 @@ function useGenerateImageLaunch() {
4267
2851
  throw new Error(failure || answer.trim() || "The image could not be generated.");
4268
2852
  const source = await (await arbi.documents.download(documentId)).blob();
4269
2853
  const fileName = `${prompt.split("\n")[0].slice(0, 60)}.png`;
4270
- chunk4TTX6ZNS_cjs.usePresentation.getState().addClip({
2854
+ chunkORNLCBNE_cjs.usePresentation.getState().addClip({
4271
2855
  kind: "image",
4272
2856
  documentId,
4273
2857
  fileName,
@@ -4276,7 +2860,7 @@ function useGenerateImageLaunch() {
4276
2860
  aspect: await aspectOf(source),
4277
2861
  masks: [],
4278
2862
  source,
4279
- caption: chunk4TTX6ZNS_cjs.mediaCaption(fileName)
2863
+ caption: chunkORNLCBNE_cjs.mediaCaption(fileName)
4280
2864
  });
4281
2865
  },
4282
2866
  [arbi, workspaceId]
@@ -4287,7 +2871,7 @@ function GenerateImageDialog({
4287
2871
  onOpenChange,
4288
2872
  referenceId
4289
2873
  }) {
4290
- const notify = chunk4TTX6ZNS_cjs.usePresentation((s) => s.notify);
2874
+ const notify = chunkORNLCBNE_cjs.usePresentation((s) => s.notify);
4291
2875
  const { skills } = chunkUFT22LAB_cjs.useWorkflowDefinitions();
4292
2876
  const run = useGenerateImageLaunch();
4293
2877
  const workflows = react.useMemo(
@@ -4347,9 +2931,9 @@ function SavePresentationDialog({
4347
2931
  onOpenChange,
4348
2932
  mode = "save"
4349
2933
  }) {
4350
- const notify = chunk4TTX6ZNS_cjs.usePresentation((s) => s.notify);
2934
+ const notify = chunkORNLCBNE_cjs.usePresentation((s) => s.notify);
4351
2935
  const { save, exportPdf } = usePresentationFiles();
4352
- const current2 = chunk4TTX6ZNS_cjs.usePresentation((s) => s.title);
2936
+ const current2 = chunkORNLCBNE_cjs.usePresentation((s) => s.title);
4353
2937
  const [title, setTitle] = react.useState(current2);
4354
2938
  const [busy, setBusy] = react.useState(false);
4355
2939
  const text = SAVE_TEXT[mode];
@@ -4419,7 +3003,7 @@ function OpenPresentationDialog({
4419
3003
  templates = false
4420
3004
  }) {
4421
3005
  const { confirm } = chunkTKHCIHE2_cjs.useBlocksEnvironment();
4422
- const notify = chunk4TTX6ZNS_cjs.usePresentation((s) => s.notify);
3006
+ const notify = chunkORNLCBNE_cjs.usePresentation((s) => s.notify);
4423
3007
  const { list, startFromTemplate } = usePresentationFiles();
4424
3008
  const [entries, setEntries] = react.useState(null);
4425
3009
  const [opening, setOpening] = react.useState(null);
@@ -4434,7 +3018,7 @@ function OpenPresentationDialog({
4434
3018
  onOpened(entry.id);
4435
3019
  return;
4436
3020
  }
4437
- if (chunk4TTX6ZNS_cjs.usePresentation.getState().clips.length) {
3021
+ if (chunkORNLCBNE_cjs.usePresentation.getState().clips.length) {
4438
3022
  const ok = await confirm({
4439
3023
  title: "New from template",
4440
3024
  message: "Replace the presentation that is open? Save it first to keep it.",
@@ -4485,8 +3069,8 @@ function OpenPresentationDialog({
4485
3069
  }
4486
3070
  var IMAGE_FILE = /\.(png|jpe?g|gif|webp|svg)$/i;
4487
3071
  function ChooseLogoDialog({ open, onOpenChange }) {
4488
- const setTheme = chunk4TTX6ZNS_cjs.usePresentation((s) => s.setTheme);
4489
- const corner = chunk4TTX6ZNS_cjs.usePresentation((s) => s.theme.logo?.corner ?? "br");
3072
+ const setTheme = chunkORNLCBNE_cjs.usePresentation((s) => s.setTheme);
3073
+ const corner = chunkORNLCBNE_cjs.usePresentation((s) => s.theme.logo?.corner ?? "br");
4490
3074
  const { data: documents } = react$1.useDocuments(void 0, { enabled: open });
4491
3075
  const [picked, setPicked] = react.useState("");
4492
3076
  const groups = react.useMemo(
@@ -4573,7 +3157,7 @@ function CropClipDialog({ clip, onOpenChange }) {
4573
3157
  w: Math.min(1, area.width / natural.width),
4574
3158
  h: Math.min(1, area.height / natural.height)
4575
3159
  };
4576
- chunk4TTX6ZNS_cjs.usePresentation.getState().cropClip(clip.id, rect, area.width / area.height);
3160
+ chunkORNLCBNE_cjs.usePresentation.getState().cropClip(clip.id, rect, area.width / area.height);
4577
3161
  onOpenChange(false);
4578
3162
  };
4579
3163
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -4622,8 +3206,8 @@ function CropClipDialog({ clip, onOpenChange }) {
4622
3206
  var EMPTY = new Blob();
4623
3207
  var NONE = "none";
4624
3208
  function LabelColumnMenu({ columns }) {
4625
- const labelColumn = chunk4TTX6ZNS_cjs.usePresentation((s) => s.labelColumn);
4626
- const setLabelColumn = chunk4TTX6ZNS_cjs.usePresentation((s) => s.setLabelColumn);
3209
+ const labelColumn = chunkORNLCBNE_cjs.usePresentation((s) => s.labelColumn);
3210
+ const setLabelColumn = chunkORNLCBNE_cjs.usePresentation((s) => s.setLabelColumn);
4627
3211
  if (!columns.length) return null;
4628
3212
  const chosen = columns.find((column) => column.id === labelColumn);
4629
3213
  return /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuSub, { children: [
@@ -4666,8 +3250,8 @@ function useLabelColumns(active) {
4666
3250
  const workspaceId = react$1.useArbiSessionState((s) => s.workspaceId);
4667
3251
  const { data: tags } = react$1.useTags(workspaceId, { enabled: active });
4668
3252
  const { data: documents } = react$1.useDocuments(workspaceId, { enabled: active });
4669
- const labelColumn = chunk4TTX6ZNS_cjs.usePresentation((s) => s.labelColumn);
4670
- const documentIds = chunk4TTX6ZNS_cjs.usePresentation((s) => s.clips.map((clip) => clip.documentId).join(" "));
3253
+ const labelColumn = chunkORNLCBNE_cjs.usePresentation((s) => s.labelColumn);
3254
+ const documentIds = chunkORNLCBNE_cjs.usePresentation((s) => s.clips.map((clip) => clip.documentId).join(" "));
4671
3255
  const columns = react.useMemo(
4672
3256
  () => (tags ?? []).filter((tag) => tag.kind !== "search" && VALUE_FORMATS.has(tag.tag_type.type)).map((tag) => ({ id: tag.external_id, name: tag.name })).sort((a, b) => a.name.localeCompare(b.name)),
4673
3257
  [tags]
@@ -4682,23 +3266,23 @@ function useLabelColumns(active) {
4682
3266
  if (note2) values[doc.external_id] = note2;
4683
3267
  }
4684
3268
  }
4685
- chunk4TTX6ZNS_cjs.usePresentation.getState().setColumnValues(values);
3269
+ chunkORNLCBNE_cjs.usePresentation.getState().setColumnValues(values);
4686
3270
  }, [labelColumn, documentIds, documents]);
4687
3271
  return columns;
4688
3272
  }
4689
3273
  function usePresentationController(active) {
4690
3274
  const session = react$1.useArbiSessionStore();
4691
- const notify = chunk4TTX6ZNS_cjs.usePresentation((s) => s.notify);
3275
+ const notify = chunkORNLCBNE_cjs.usePresentation((s) => s.notify);
4692
3276
  const { save, canSave } = usePresentationFiles();
4693
3277
  const labelColumns = useLabelColumns(active);
4694
3278
  const [dialog, setDialog] = react.useState(null);
4695
3279
  const [reference, setReference] = react.useState(null);
4696
3280
  const [cropping, setCropping] = react.useState(null);
4697
- const cropClip = chunk4TTX6ZNS_cjs.usePresentation((s) => s.clips.find((c) => c.id === cropping) ?? null);
3281
+ const cropClip = chunkORNLCBNE_cjs.usePresentation((s) => s.clips.find((c) => c.id === cropping) ?? null);
4698
3282
  const [saving, setSaving] = react.useState(false);
4699
3283
  const close = (open) => !open && setDialog(null);
4700
3284
  const quickSave = react.useCallback(async () => {
4701
- const { savedId, title } = chunk4TTX6ZNS_cjs.usePresentation.getState();
3285
+ const { savedId, title } = chunkORNLCBNE_cjs.usePresentation.getState();
4702
3286
  if (!savedId) return setDialog("save");
4703
3287
  setSaving(true);
4704
3288
  try {
@@ -4732,7 +3316,7 @@ function usePresentationController(active) {
4732
3316
  {
4733
3317
  open: dialog === "open" || dialog === "fromTemplate",
4734
3318
  templates: dialog === "fromTemplate",
4735
- onOpened: (id) => chunkWFMWKPGY_cjs.editPresentation(session, id ? { kind: "open", documentId: id } : { kind: "new" }),
3319
+ onOpened: (id) => chunkWVZLAAIZ_cjs.editPresentation(session, id ? { kind: "open", documentId: id } : { kind: "new" }),
4736
3320
  onOpenChange: close
4737
3321
  }
4738
3322
  ),
@@ -4774,7 +3358,7 @@ function usePresentationController(active) {
4774
3358
  trayStart: canSave && /* @__PURE__ */ jsxRuntime.jsx(GenerateTile, { onClick: () => generate(null) }),
4775
3359
  onChooseLogo: canSave ? () => setDialog("logo") : void 0,
4776
3360
  onEditImage: (clipId) => {
4777
- const clip = chunk4TTX6ZNS_cjs.usePresentation.getState().clips.find((c) => c.id === clipId);
3361
+ const clip = chunkORNLCBNE_cjs.usePresentation.getState().clips.find((c) => c.id === clipId);
4778
3362
  if (clip) generate(clip.documentId);
4779
3363
  },
4780
3364
  onCropImage: setCropping
@@ -4782,9 +3366,8 @@ function usePresentationController(active) {
4782
3366
  return { editor, dialogs };
4783
3367
  }
4784
3368
 
4785
- exports.PresentationStage = PresentationStage;
4786
3369
  exports.SlidesEditor = SlidesEditor;
4787
3370
  exports.usePresentationController = usePresentationController;
4788
3371
  exports.usePresentationFiles = usePresentationFiles;
4789
- //# sourceMappingURL=chunk-USNTRL22.cjs.map
4790
- //# sourceMappingURL=chunk-USNTRL22.cjs.map
3372
+ //# sourceMappingURL=chunk-H236SNEV.cjs.map
3373
+ //# sourceMappingURL=chunk-H236SNEV.cjs.map