@june-ai/june-ui 0.2.5 → 0.2.7

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.
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import "./block-automount.js";
1
2
  import {
2
3
  JuneError,
3
4
  createDocumentExtensions,
@@ -6,24 +7,75 @@ import {
6
7
  docToHtml,
7
8
  docToMarkdown,
8
9
  emptyDoc,
10
+ getPageCount,
9
11
  getSearchState,
10
12
  gotoMatch,
11
13
  isJuneError,
12
14
  parseDocumentContent,
15
+ remeasurePagination,
13
16
  replaceAll,
14
17
  replaceCurrent,
15
18
  sanitizeHref,
19
+ setPaginationConfig,
16
20
  setSearch,
17
21
  slugify,
18
22
  toJuneError,
19
23
  wordCountOf
20
- } from "./chunk-CZE533PM.js";
24
+ } from "./chunk-VFZI3SEL.js";
25
+
26
+ // src/openui/disable-devtools.tsx
27
+ import { OpenUIDevtools } from "@openuidev/devtools";
28
+ import { jsx } from "react/jsx-runtime";
29
+ var AUTO_MOUNT_FLAG = /* @__PURE__ */ Symbol.for("openui.devtools.autoMount");
30
+ var BLOCKED_BY_JUNE = /* @__PURE__ */ Symbol.for("openui.devtools.blockedByJune");
31
+ var flags = globalThis;
32
+ var scheduledByOpenUI = flags[AUTO_MOUNT_FLAG] === true && flags[BLOCKED_BY_JUNE] !== true;
33
+ flags[AUTO_MOUNT_FLAG] = true;
34
+ flags[BLOCKED_BY_JUNE] = true;
35
+ var DEVTOOLS_BUNDLE = "https://cdn.jsdelivr.net/npm/@openuidev/devtools@0/dist/devtools.browser.js";
36
+ var ALIAS_CACHE_MS = 5 * 60 * 1e3;
37
+ function claimDisabledDevtools() {
38
+ if (typeof document === "undefined") return () => {
39
+ };
40
+ const url = `${DEVTOOLS_BUNDLE}?t=${Math.floor(Date.now() / ALIAS_CACHE_MS)}`;
41
+ let cancelled = false;
42
+ let unmount = () => {
43
+ cancelled = true;
44
+ };
45
+ void Promise.all([
46
+ import(
47
+ /* @vite-ignore */
48
+ url
49
+ ),
50
+ import("react"),
51
+ import("react-dom"),
52
+ import("react-dom/client")
53
+ ]).then(([devtools, react, reactDom, reactDomClient]) => {
54
+ if (cancelled) return;
55
+ unmount = devtools.mountOpenUIDevtools({
56
+ React: react,
57
+ ReactDOM: reactDom,
58
+ ReactDOMClient: reactDomClient,
59
+ loadReactLang: () => import("@openuidev/react-lang"),
60
+ props: { enabled: false }
61
+ });
62
+ }).catch(() => {
63
+ });
64
+ return () => unmount();
65
+ }
66
+ if (scheduledByOpenUI && process.env.NODE_ENV === "development" && process.env.VITEST !== "true" && typeof document !== "undefined") {
67
+ claimDisabledDevtools();
68
+ }
69
+ function OpenUIDevtoolsGate() {
70
+ return /* @__PURE__ */ jsx(OpenUIDevtools, { enabled: false });
71
+ }
21
72
 
22
73
  // src/renderer/renderer.tsx
23
74
  import { Renderer } from "@openuidev/react-lang";
24
75
  import {
25
76
  Fragment,
26
77
  useCallback,
78
+ useEffect,
27
79
  useMemo as useMemo2,
28
80
  useRef
29
81
  } from "react";
@@ -101,6 +153,316 @@ function useDocumentValue(store, id, selector) {
101
153
  return useSyncExternalStore(store.subscribe, read, read);
102
154
  }
103
155
 
156
+ // src/components/document-editor/document-merge.ts
157
+ var MAX_CELLS = 4e6;
158
+ function matchIndices(a, b) {
159
+ const n = a.length;
160
+ const m = b.length;
161
+ if (n * m > MAX_CELLS) return null;
162
+ const dp = Array.from({ length: n + 1 }, () => new Uint32Array(m + 1));
163
+ for (let i2 = n - 1; i2 >= 0; i2--) {
164
+ for (let j2 = m - 1; j2 >= 0; j2--) {
165
+ dp[i2][j2] = a[i2] === b[j2] ? dp[i2 + 1][j2 + 1] + 1 : Math.max(dp[i2 + 1][j2], dp[i2][j2 + 1]);
166
+ }
167
+ }
168
+ const matches = /* @__PURE__ */ new Map();
169
+ let i = 0;
170
+ let j = 0;
171
+ while (i < n && j < m) {
172
+ if (a[i] === b[j]) {
173
+ matches.set(i, j);
174
+ i++;
175
+ j++;
176
+ } else if (dp[i + 1][j] >= dp[i][j + 1]) i++;
177
+ else j++;
178
+ }
179
+ return matches;
180
+ }
181
+ var same = (x, y) => x.length === y.length && x.every((v, i) => v === y[i]);
182
+ function mergeBlocks(base, local, incoming) {
183
+ if (same(local, base)) return { blocks: incoming, conflicts: 0 };
184
+ if (same(incoming, base) || same(local, incoming)) return { blocks: local, conflicts: 0 };
185
+ const ml = matchIndices(base, local);
186
+ const mn = matchIndices(base, incoming);
187
+ if (!ml || !mn) return { blocks: null, conflicts: 1 };
188
+ const anchors = [...ml.keys()].filter((i) => mn.has(i)).sort((x, y) => x - y);
189
+ const out = [];
190
+ let conflicts = 0;
191
+ let pb = -1;
192
+ let pl = -1;
193
+ let pn = -1;
194
+ const region = (bEnd, lEnd, nEnd) => {
195
+ const B = base.slice(pb + 1, bEnd);
196
+ const L = local.slice(pl + 1, lEnd);
197
+ const N = incoming.slice(pn + 1, nEnd);
198
+ if (B.length === L.length && L.length === N.length) {
199
+ for (let k = 0; k < B.length; k++) {
200
+ if (L[k] === B[k]) out.push(N[k]);
201
+ else if (N[k] === B[k] || N[k] === L[k]) out.push(L[k]);
202
+ else {
203
+ conflicts++;
204
+ out.push(L[k]);
205
+ }
206
+ }
207
+ return;
208
+ }
209
+ if (same(L, B)) out.push(...N);
210
+ else if (same(N, B) || same(L, N)) out.push(...L);
211
+ else {
212
+ conflicts++;
213
+ out.push(...L);
214
+ }
215
+ };
216
+ for (const a of anchors) {
217
+ const la = ml.get(a);
218
+ const na = mn.get(a);
219
+ region(a, la, na);
220
+ out.push(local[la]);
221
+ pb = a;
222
+ pl = la;
223
+ pn = na;
224
+ }
225
+ region(base.length, local.length, incoming.length);
226
+ return { blocks: out, conflicts };
227
+ }
228
+ function mergeDocuments(base, local, incoming) {
229
+ const toBlocks = (d) => (d.content ?? []).map((node) => JSON.stringify(node));
230
+ const { blocks: blocks2, conflicts } = mergeBlocks(toBlocks(base), toBlocks(local), toBlocks(incoming));
231
+ if (!blocks2) return { doc: local, conflicts: Math.max(1, conflicts) };
232
+ if (blocks2.length === 0) return { doc: emptyDoc(), conflicts };
233
+ return { doc: { type: "doc", content: blocks2.map((b) => JSON.parse(b)) }, conflicts };
234
+ }
235
+
236
+ // src/components/document-editor/document-store.ts
237
+ var incomingKey = (doc) => JSON.stringify([doc.title, docKey(doc.json)]);
238
+ function createDocumentStore() {
239
+ const records = /* @__PURE__ */ new Map();
240
+ const listeners = /* @__PURE__ */ new Set();
241
+ const emit = () => listeners.forEach((listener) => listener());
242
+ const put = (record) => {
243
+ records.set(record.id, record);
244
+ emit();
245
+ };
246
+ const fresh2 = (doc) => ({
247
+ id: doc.id,
248
+ title: doc.title,
249
+ documentType: doc.documentType,
250
+ status: doc.status,
251
+ json: doc.json,
252
+ baseJson: doc.json,
253
+ baseTitle: doc.title,
254
+ lastIncomingKey: incomingKey(doc),
255
+ revision: 0,
256
+ origin: "external",
257
+ pending: null,
258
+ updatedAt: Date.now()
259
+ });
260
+ return {
261
+ get: (id) => records.get(id),
262
+ list: () => [...records.values()],
263
+ subscribe: (listener) => {
264
+ listeners.add(listener);
265
+ return () => {
266
+ listeners.delete(listener);
267
+ };
268
+ },
269
+ receive(incoming) {
270
+ const current = records.get(incoming.id);
271
+ if (!current) {
272
+ put(fresh2(incoming));
273
+ return "created";
274
+ }
275
+ const key = incomingKey(incoming);
276
+ if (current.lastIncomingKey === key) return "unchanged";
277
+ const userEditedBody = docKey(current.json) !== docKey(current.baseJson);
278
+ const userEditedTitle = current.title !== current.baseTitle;
279
+ const title = userEditedTitle ? current.title : incoming.title;
280
+ const meta = {
281
+ documentType: incoming.documentType ?? current.documentType,
282
+ status: incoming.status ?? current.status
283
+ };
284
+ if (!userEditedBody) {
285
+ put({
286
+ ...current,
287
+ ...meta,
288
+ title,
289
+ baseTitle: incoming.title,
290
+ json: incoming.json,
291
+ baseJson: incoming.json,
292
+ lastIncomingKey: key,
293
+ revision: current.revision + 1,
294
+ origin: "external",
295
+ pending: null,
296
+ updatedAt: Date.now()
297
+ });
298
+ return "applied";
299
+ }
300
+ const { doc, conflicts } = mergeDocuments(current.baseJson, current.json, incoming.json);
301
+ if (conflicts === 0) {
302
+ put({
303
+ ...current,
304
+ ...meta,
305
+ title,
306
+ baseTitle: incoming.title,
307
+ json: doc,
308
+ baseJson: incoming.json,
309
+ lastIncomingKey: key,
310
+ revision: current.revision + 1,
311
+ origin: "external",
312
+ pending: null,
313
+ updatedAt: Date.now()
314
+ });
315
+ return "merged";
316
+ }
317
+ put({
318
+ ...current,
319
+ ...meta,
320
+ lastIncomingKey: key,
321
+ pending: { json: incoming.json, title: incoming.title, merged: doc, conflicts }
322
+ });
323
+ return "conflict";
324
+ },
325
+ hydrate(doc) {
326
+ put(fresh2(doc));
327
+ },
328
+ edit(id, json, origin) {
329
+ const current = records.get(id);
330
+ if (!current || docKey(current.json) === docKey(json)) return;
331
+ put({ ...current, json, origin, revision: current.revision + 1, updatedAt: Date.now() });
332
+ },
333
+ setTitle(id, title) {
334
+ const current = records.get(id);
335
+ if (!current || current.title === title) return;
336
+ put({ ...current, title, updatedAt: Date.now() });
337
+ },
338
+ resolve(id, choice) {
339
+ const current = records.get(id);
340
+ const pending = current?.pending;
341
+ if (!current || !pending) return;
342
+ if (choice === "keep") {
343
+ put({ ...current, baseJson: pending.json, baseTitle: pending.title, pending: null });
344
+ return;
345
+ }
346
+ const json = choice === "merge" ? pending.merged : pending.json;
347
+ const title = choice === "merge" ? current.title : pending.title;
348
+ put({
349
+ ...current,
350
+ title,
351
+ json,
352
+ baseJson: pending.json,
353
+ baseTitle: pending.title,
354
+ revision: current.revision + 1,
355
+ origin: "external",
356
+ pending: null,
357
+ updatedAt: Date.now()
358
+ });
359
+ },
360
+ remove(id) {
361
+ if (records.delete(id)) emit();
362
+ }
363
+ };
364
+ }
365
+ var echoes = /* @__PURE__ */ new WeakMap();
366
+ var ECHO_MEMORY = 8;
367
+ function rememberDocumentEcho(store, id, content) {
368
+ let byId = echoes.get(store);
369
+ if (!byId) echoes.set(store, byId = /* @__PURE__ */ new Map());
370
+ const list2 = byId.get(id) ?? [];
371
+ list2.push(content);
372
+ if (list2.length > ECHO_MEMORY) list2.shift();
373
+ byId.set(id, list2);
374
+ }
375
+ function isDocumentEcho(store, id, content) {
376
+ return !!content && !!echoes.get(store)?.get(id)?.includes(content);
377
+ }
378
+ var defaultStore = null;
379
+ function getDefaultDocumentStore() {
380
+ if (!defaultStore) defaultStore = createDocumentStore();
381
+ return defaultStore;
382
+ }
383
+
384
+ // src/utils/update-document-program.ts
385
+ function readString(src, i) {
386
+ if (src[i] !== '"') return null;
387
+ let j = i + 1;
388
+ let value = "";
389
+ while (j < src.length) {
390
+ const ch = src[j];
391
+ if (ch === '"') return { start: i, end: j + 1, value };
392
+ if (ch === "\\") {
393
+ const next = src[j + 1];
394
+ if (next === void 0) return null;
395
+ if (next === "u" && /^[0-9a-fA-F]{4}$/.test(src.slice(j + 2, j + 6))) {
396
+ value += String.fromCharCode(parseInt(src.slice(j + 2, j + 6), 16));
397
+ j += 6;
398
+ continue;
399
+ }
400
+ value += next === "n" ? "\n" : next === "t" ? " " : next === "r" ? "\r" : next === "b" ? "\b" : next === "f" ? "\f" : next;
401
+ j += 2;
402
+ continue;
403
+ }
404
+ value += ch;
405
+ j++;
406
+ }
407
+ return null;
408
+ }
409
+ var skipSpace = (src, i) => {
410
+ while (i < src.length && /\s/.test(src[i])) i++;
411
+ return i;
412
+ };
413
+ var toLangString = (value) => JSON.stringify(value);
414
+ function updateDocumentInProgram(program, documentId, update, componentName = "DocumentEditor") {
415
+ const re = new RegExp(`\\b${componentName}\\s*\\(`, "g");
416
+ let match;
417
+ while (match = re.exec(program)) {
418
+ const args = [];
419
+ let i = match.index + match[0].length;
420
+ for (let n = 0; n < 3; n++) {
421
+ i = skipSpace(program, i);
422
+ const tok = readString(program, i);
423
+ if (!tok) break;
424
+ args.push(tok);
425
+ i = skipSpace(program, tok.end);
426
+ if (program[i] === ",") i++;
427
+ else break;
428
+ }
429
+ if (args[0]?.value !== documentId) continue;
430
+ const edits = [];
431
+ if (update.title !== void 0 && args[1] && args[1].value !== update.title) {
432
+ edits.push({ start: args[1].start, end: args[1].end, text: toLangString(update.title) });
433
+ }
434
+ if (update.content !== void 0 && args[2] && args[2].value !== update.content) {
435
+ edits.push({ start: args[2].start, end: args[2].end, text: toLangString(update.content) });
436
+ }
437
+ if (!args[2] && update.content !== void 0) return null;
438
+ let out = program;
439
+ for (const e of edits.sort((a, b) => b.start - a.start)) {
440
+ out = out.slice(0, e.start) + e.text + out.slice(e.end);
441
+ }
442
+ return out;
443
+ }
444
+ return null;
445
+ }
446
+ function readDocumentFromProgram(program, documentId, componentName = "DocumentEditor") {
447
+ const re = new RegExp(`\\b${componentName}\\s*\\(`, "g");
448
+ let match;
449
+ while (match = re.exec(program)) {
450
+ const args = [];
451
+ let i = match.index + match[0].length;
452
+ for (let n = 0; n < 3; n++) {
453
+ i = skipSpace(program, i);
454
+ const tok = readString(program, i);
455
+ if (!tok) break;
456
+ args.push(tok);
457
+ i = skipSpace(program, tok.end);
458
+ if (program[i] === ",") i++;
459
+ else break;
460
+ }
461
+ if (args[0]?.value === documentId && args[1] && args[2]) return { title: args[1].value, content: args[2].value };
462
+ }
463
+ return null;
464
+ }
465
+
104
466
  // src/core/context.ts
105
467
  import { createContext as createContext2, useContext as useContext2 } from "react";
106
468
  var JuneContext = createContext2({
@@ -140,7 +502,7 @@ var lightTheme = {
140
502
  };
141
503
 
142
504
  // src/themes/theme-provider.tsx
143
- import { jsx } from "react/jsx-runtime";
505
+ import { jsx as jsx2 } from "react/jsx-runtime";
144
506
  var QUERY = "(prefers-color-scheme: dark)";
145
507
  function subscribe(onChange) {
146
508
  if (typeof window === "undefined" || !window.matchMedia) return () => {
@@ -183,7 +545,7 @@ function JuneThemeProvider({
183
545
  () => ({ mode: mode ?? "system", theme: resolved }),
184
546
  [mode, resolved]
185
547
  );
186
- return /* @__PURE__ */ jsx(JuneContext.Provider, { value: context, children: /* @__PURE__ */ jsx(
548
+ return /* @__PURE__ */ jsx2(JuneContext.Provider, { value: context, children: /* @__PURE__ */ jsx2(
187
549
  "div",
188
550
  {
189
551
  className: className ? `june-ui-root ${className}` : "june-ui-root",
@@ -605,7 +967,7 @@ function splitResponse(source, options = {}) {
605
967
 
606
968
  // src/renderer/error-boundary.tsx
607
969
  import { Component } from "react";
608
- import { jsx as jsx2 } from "react/jsx-runtime";
970
+ import { jsx as jsx3 } from "react/jsx-runtime";
609
971
  function keysChanged(a = [], b = []) {
610
972
  return a.length !== b.length || a.some((v, i) => !Object.is(v, b[i]));
611
973
  }
@@ -634,12 +996,12 @@ var JuneErrorBoundary = class extends Component {
634
996
  const { fallback } = this.props;
635
997
  if (typeof fallback === "function") return fallback({ error, reset: this.reset });
636
998
  if (fallback !== void 0) return fallback;
637
- return /* @__PURE__ */ jsx2("div", { role: "alert", "data-june-error": "", children: "Something went wrong while rendering this UI." });
999
+ return /* @__PURE__ */ jsx3("div", { role: "alert", "data-june-error": "", children: "Something went wrong while rendering this UI." });
638
1000
  }
639
1001
  };
640
1002
 
641
1003
  // src/renderer/renderer.tsx
642
- import { jsx as jsx3, jsxs } from "react/jsx-runtime";
1004
+ import { jsx as jsx4, jsxs } from "react/jsx-runtime";
643
1005
  function JuneRenderer(props) {
644
1006
  const {
645
1007
  library,
@@ -659,14 +1021,43 @@ function JuneRenderer(props) {
659
1021
  onError,
660
1022
  onJuneError,
661
1023
  documents,
1024
+ onResponseChange,
1025
+ responseChangeDelay = 300,
662
1026
  loadingFallback = null,
663
1027
  emptyFallback = null,
664
1028
  errorFallback,
665
1029
  resetKeys,
666
1030
  ...rendererProps
667
1031
  } = props;
668
- const latest = useRef({ actions, confirmAction, parseActionEvent, onAction, onError, onJuneError });
669
- latest.current = { actions, confirmAction, parseActionEvent, onAction, onError, onJuneError };
1032
+ const latest = useRef({ actions, confirmAction, parseActionEvent, onAction, onError, onJuneError, onResponseChange, responseChangeDelay, response });
1033
+ latest.current = { actions, confirmAction, parseActionEvent, onAction, onError, onJuneError, onResponseChange, responseChangeDelay, response };
1034
+ const syncTimers = useRef(/* @__PURE__ */ new Map());
1035
+ useEffect(() => {
1036
+ const timers = syncTimers.current;
1037
+ return () => {
1038
+ timers.forEach(clearTimeout);
1039
+ timers.clear();
1040
+ };
1041
+ }, []);
1042
+ const syncProgram = useCallback(async (change, store) => {
1043
+ const l = latest.current;
1044
+ if (!l.onResponseChange || typeof l.response !== "string") return;
1045
+ const record = store.get(change.documentId);
1046
+ const title = record?.title ?? change.title;
1047
+ const json = record?.json ?? change.json;
1048
+ try {
1049
+ const { docToMarkdown: docToMarkdown2 } = await import("./document-engine-RKD5SLXR.js");
1050
+ const markdown = docToMarkdown2(json);
1051
+ const program = latest.current.response;
1052
+ if (typeof program !== "string") return;
1053
+ const next = updateDocumentInProgram(program, change.documentId, { title, content: markdown });
1054
+ if (next === null || next === program) return;
1055
+ rememberDocumentEcho(store, change.documentId, markdown);
1056
+ latest.current.onResponseChange?.(next, { documentId: change.documentId, title, markdown, source: change.source });
1057
+ } catch (error) {
1058
+ latest.current.onJuneError?.(toJuneError(error, "DOCUMENT_ERROR", "Updating the program failed"));
1059
+ }
1060
+ }, []);
670
1061
  const handleAction = useCallback((event) => {
671
1062
  const l = latest.current;
672
1063
  l.onAction?.(event);
@@ -705,12 +1096,27 @@ function JuneRenderer(props) {
705
1096
  const documentOptions = useMemo2(
706
1097
  () => ({
707
1098
  ...documents,
1099
+ onDocumentChange: (change) => {
1100
+ documents?.onDocumentChange?.(change);
1101
+ if (!latest.current.onResponseChange || change.source === "ai") return;
1102
+ const store = documents?.store ?? getDefaultDocumentStore();
1103
+ const timers = syncTimers.current;
1104
+ const prev = timers.get(change.documentId);
1105
+ if (prev) clearTimeout(prev);
1106
+ timers.set(
1107
+ change.documentId,
1108
+ setTimeout(() => {
1109
+ timers.delete(change.documentId);
1110
+ void syncProgram(change, store);
1111
+ }, Math.max(0, latest.current.responseChangeDelay))
1112
+ );
1113
+ },
708
1114
  onError: (error) => {
709
1115
  documents?.onError?.(error);
710
1116
  latest.current.onJuneError?.(error);
711
1117
  }
712
1118
  }),
713
- [documents]
1119
+ [documents, syncProgram]
714
1120
  );
715
1121
  const parts = useMemo2(
716
1122
  () => mixedContent && response ? splitResponse(response, { streaming: isStreaming }) : null,
@@ -725,31 +1131,34 @@ function JuneRenderer(props) {
725
1131
  const before = parts?.before ?? [];
726
1132
  const after = parts?.after ?? [];
727
1133
  const hasText = before.length + after.length > 0;
728
- const text = (value, index, key) => /* @__PURE__ */ jsx3(Fragment, { children: renderText ? renderText(value, index) : /* @__PURE__ */ jsx3("p", { className: "june-text", children: value }) }, key);
729
- return /* @__PURE__ */ jsx3(JuneThemeProvider, { mode: theme, vars: themeVars, className, style, children: /* @__PURE__ */ jsx3(JuneRuntimeContext.Provider, { value: runtime, children: /* @__PURE__ */ jsx3(JuneDocumentContext.Provider, { value: documentOptions, children: /* @__PURE__ */ jsxs(
730
- JuneErrorBoundary,
731
- {
732
- fallback: errorFallback,
733
- onError: handleBoundaryError,
734
- resetKeys: resetKeys ?? [response],
735
- children: [
736
- before.map((t, i) => text(t, i, `b${i}`)),
737
- hasUi && /* @__PURE__ */ jsx3(
738
- Renderer,
739
- {
740
- ...rendererProps,
741
- library,
742
- response: uiText,
743
- isStreaming,
744
- onAction: handleAction,
745
- onError: handleParserErrors
746
- }
747
- ),
748
- after.map((t, i) => text(t, before.length + i, `a${i}`)),
749
- !hasUi && !hasText && (isStreaming ? loadingFallback : emptyFallback)
750
- ]
751
- }
752
- ) }) }) });
1134
+ const text = (value, index, key) => /* @__PURE__ */ jsx4(Fragment, { children: renderText ? renderText(value, index) : /* @__PURE__ */ jsx4("p", { className: "june-text", children: value }) }, key);
1135
+ return /* @__PURE__ */ jsxs(JuneThemeProvider, { mode: theme, vars: themeVars, className, style, children: [
1136
+ /* @__PURE__ */ jsx4(OpenUIDevtoolsGate, {}),
1137
+ /* @__PURE__ */ jsx4(JuneRuntimeContext.Provider, { value: runtime, children: /* @__PURE__ */ jsx4(JuneDocumentContext.Provider, { value: documentOptions, children: /* @__PURE__ */ jsxs(
1138
+ JuneErrorBoundary,
1139
+ {
1140
+ fallback: errorFallback,
1141
+ onError: handleBoundaryError,
1142
+ resetKeys: resetKeys ?? [response],
1143
+ children: [
1144
+ before.map((t, i) => text(t, i, `b${i}`)),
1145
+ hasUi && /* @__PURE__ */ jsx4(
1146
+ Renderer,
1147
+ {
1148
+ ...rendererProps,
1149
+ library,
1150
+ response: uiText,
1151
+ isStreaming,
1152
+ onAction: handleAction,
1153
+ onError: handleParserErrors
1154
+ }
1155
+ ),
1156
+ after.map((t, i) => text(t, before.length + i, `a${i}`)),
1157
+ !hasUi && !hasText && (isStreaming ? loadingFallback : emptyFallback)
1158
+ ]
1159
+ }
1160
+ ) }) })
1161
+ ] });
753
1162
  }
754
1163
 
755
1164
  // src/components/library.ts
@@ -803,7 +1212,7 @@ function defineJuneAction(definition) {
803
1212
  }
804
1213
 
805
1214
  // src/streaming/use-june-stream.ts
806
- import { useCallback as useCallback2, useEffect, useMemo as useMemo3, useRef as useRef2, useState } from "react";
1215
+ import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo3, useRef as useRef2, useState } from "react";
807
1216
 
808
1217
  // src/streaming/stream-handler.ts
809
1218
  function isReadableStream(source) {
@@ -1058,7 +1467,7 @@ function useJuneStream(options = {}) {
1058
1467
  clearTimer();
1059
1468
  setState(INITIAL);
1060
1469
  }, [clearTimer]);
1061
- useEffect(
1470
+ useEffect2(
1062
1471
  () => () => {
1063
1472
  runIdRef.current++;
1064
1473
  controllerRef.current?.abort();
@@ -1077,25 +1486,25 @@ import { defineComponent as defineComponent2 } from "@openuidev/react-lang";
1077
1486
  import { z } from "zod/v4";
1078
1487
 
1079
1488
  // src/components/document-editor/document-draft.tsx
1080
- import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1489
+ import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
1081
1490
  function DocumentDraft({ title, words, state }) {
1082
1491
  if (state === "empty") {
1083
- return /* @__PURE__ */ jsx4("div", { className: "june-doc june-doc--draft", role: "alert", children: /* @__PURE__ */ jsx4("p", { className: "june-doc__draft-text", children: "No document content was received." }) });
1492
+ return /* @__PURE__ */ jsx5("div", { className: "june-doc june-doc--draft", role: "alert", children: /* @__PURE__ */ jsx5("p", { className: "june-doc__draft-text", children: "No document content was received." }) });
1084
1493
  }
1085
1494
  return /* @__PURE__ */ jsxs2("div", { className: "june-doc june-doc--draft", role: "status", "aria-live": "polite", children: [
1086
- title ? /* @__PURE__ */ jsx4("p", { className: "june-doc__draft-title", children: title }) : null,
1087
- /* @__PURE__ */ jsx4("p", { className: "june-doc__draft-text", children: state === "drafting" ? `Drafting document\u2026${words ? ` ${words} words so far` : ""}` : "Loading editor\u2026" }),
1495
+ title ? /* @__PURE__ */ jsx5("p", { className: "june-doc__draft-title", children: title }) : null,
1496
+ /* @__PURE__ */ jsx5("p", { className: "june-doc__draft-text", children: state === "drafting" ? `Drafting document\u2026${words ? ` ${words} words so far` : ""}` : "Loading editor\u2026" }),
1088
1497
  /* @__PURE__ */ jsxs2("div", { className: "june-doc__pulse", "aria-hidden": "true", children: [
1089
- /* @__PURE__ */ jsx4("span", {}),
1090
- /* @__PURE__ */ jsx4("span", {}),
1091
- /* @__PURE__ */ jsx4("span", {})
1498
+ /* @__PURE__ */ jsx5("span", {}),
1499
+ /* @__PURE__ */ jsx5("span", {}),
1500
+ /* @__PURE__ */ jsx5("span", {})
1092
1501
  ] })
1093
1502
  ] });
1094
1503
  }
1095
1504
 
1096
1505
  // src/components/document-editor/document-editor.tsx
1097
1506
  import { useEditor } from "@tiptap/react";
1098
- import { useCallback as useCallback3, useEffect as useEffect5, useId, useMemo as useMemo4, useRef as useRef7, useState as useState6 } from "react";
1507
+ import { useCallback as useCallback3, useEffect as useEffect6, useId, useMemo as useMemo4, useRef as useRef7, useState as useState6 } from "react";
1099
1508
 
1100
1509
  // src/components/document-editor/document-bubble.tsx
1101
1510
  import { useEditorState as useEditorState2 } from "@tiptap/react";
@@ -1106,208 +1515,208 @@ import { useEditorState } from "@tiptap/react";
1106
1515
  import { useRef as useRef4, useState as useState3 } from "react";
1107
1516
 
1108
1517
  // src/components/document-editor/document-icons.tsx
1109
- import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1518
+ import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
1110
1519
  var PATHS = {
1111
1520
  undo: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1112
- /* @__PURE__ */ jsx5("path", { d: "M9 14 4 9l5-5" }),
1113
- /* @__PURE__ */ jsx5("path", { d: "M4 9h10.5a5.5 5.5 0 0 1 0 11H11" })
1521
+ /* @__PURE__ */ jsx6("path", { d: "M9 14 4 9l5-5" }),
1522
+ /* @__PURE__ */ jsx6("path", { d: "M4 9h10.5a5.5 5.5 0 0 1 0 11H11" })
1114
1523
  ] }),
1115
1524
  redo: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1116
- /* @__PURE__ */ jsx5("path", { d: "m15 14 5-5-5-5" }),
1117
- /* @__PURE__ */ jsx5("path", { d: "M20 9H9.5a5.5 5.5 0 0 0 0 11H13" })
1525
+ /* @__PURE__ */ jsx6("path", { d: "m15 14 5-5-5-5" }),
1526
+ /* @__PURE__ */ jsx6("path", { d: "M20 9H9.5a5.5 5.5 0 0 0 0 11H13" })
1118
1527
  ] }),
1119
- bold: /* @__PURE__ */ jsx5("path", { d: "M6 12h9a4 4 0 0 1 0 8H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h7a4 4 0 0 1 0 8" }),
1528
+ bold: /* @__PURE__ */ jsx6("path", { d: "M6 12h9a4 4 0 0 1 0 8H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h7a4 4 0 0 1 0 8" }),
1120
1529
  italic: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1121
- /* @__PURE__ */ jsx5("line", { x1: "19", x2: "10", y1: "4", y2: "4" }),
1122
- /* @__PURE__ */ jsx5("line", { x1: "14", x2: "5", y1: "20", y2: "20" }),
1123
- /* @__PURE__ */ jsx5("line", { x1: "15", x2: "9", y1: "4", y2: "20" })
1530
+ /* @__PURE__ */ jsx6("line", { x1: "19", x2: "10", y1: "4", y2: "4" }),
1531
+ /* @__PURE__ */ jsx6("line", { x1: "14", x2: "5", y1: "20", y2: "20" }),
1532
+ /* @__PURE__ */ jsx6("line", { x1: "15", x2: "9", y1: "4", y2: "20" })
1124
1533
  ] }),
1125
1534
  underline: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1126
- /* @__PURE__ */ jsx5("path", { d: "M6 4v6a6 6 0 0 0 12 0V4" }),
1127
- /* @__PURE__ */ jsx5("line", { x1: "4", x2: "20", y1: "20", y2: "20" })
1535
+ /* @__PURE__ */ jsx6("path", { d: "M6 4v6a6 6 0 0 0 12 0V4" }),
1536
+ /* @__PURE__ */ jsx6("line", { x1: "4", x2: "20", y1: "20", y2: "20" })
1128
1537
  ] }),
1129
1538
  strike: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1130
- /* @__PURE__ */ jsx5("path", { d: "M16 4H9a3 3 0 0 0-2.83 4" }),
1131
- /* @__PURE__ */ jsx5("path", { d: "M14 12a4 4 0 0 1 0 8H6" }),
1132
- /* @__PURE__ */ jsx5("line", { x1: "4", x2: "20", y1: "12", y2: "12" })
1539
+ /* @__PURE__ */ jsx6("path", { d: "M16 4H9a3 3 0 0 0-2.83 4" }),
1540
+ /* @__PURE__ */ jsx6("path", { d: "M14 12a4 4 0 0 1 0 8H6" }),
1541
+ /* @__PURE__ */ jsx6("line", { x1: "4", x2: "20", y1: "12", y2: "12" })
1133
1542
  ] }),
1134
1543
  code: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1135
- /* @__PURE__ */ jsx5("path", { d: "m16 18 6-6-6-6" }),
1136
- /* @__PURE__ */ jsx5("path", { d: "m8 6-6 6 6 6" })
1544
+ /* @__PURE__ */ jsx6("path", { d: "m16 18 6-6-6-6" }),
1545
+ /* @__PURE__ */ jsx6("path", { d: "m8 6-6 6 6 6" })
1137
1546
  ] }),
1138
1547
  codeBlock: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1139
- /* @__PURE__ */ jsx5("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
1140
- /* @__PURE__ */ jsx5("path", { d: "m10 9-3 3 3 3" }),
1141
- /* @__PURE__ */ jsx5("path", { d: "m14 15 3-3-3-3" })
1548
+ /* @__PURE__ */ jsx6("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
1549
+ /* @__PURE__ */ jsx6("path", { d: "m10 9-3 3 3 3" }),
1550
+ /* @__PURE__ */ jsx6("path", { d: "m14 15 3-3-3-3" })
1142
1551
  ] }),
1143
1552
  superscript: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1144
- /* @__PURE__ */ jsx5("path", { d: "m4 19 8-8" }),
1145
- /* @__PURE__ */ jsx5("path", { d: "m12 19-8-8" }),
1146
- /* @__PURE__ */ jsx5("path", { d: "M20 12h-4c0-1.5.44-2 1.5-2.5S20 8.33 20 7c0-.47-.17-.93-.48-1.29a2.11 2.11 0 0 0-2.62-.44c-.42.24-.74.62-.9 1.07" })
1553
+ /* @__PURE__ */ jsx6("path", { d: "m4 19 8-8" }),
1554
+ /* @__PURE__ */ jsx6("path", { d: "m12 19-8-8" }),
1555
+ /* @__PURE__ */ jsx6("path", { d: "M20 12h-4c0-1.5.44-2 1.5-2.5S20 8.33 20 7c0-.47-.17-.93-.48-1.29a2.11 2.11 0 0 0-2.62-.44c-.42.24-.74.62-.9 1.07" })
1147
1556
  ] }),
1148
1557
  subscript: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1149
- /* @__PURE__ */ jsx5("path", { d: "m4 5 8 8" }),
1150
- /* @__PURE__ */ jsx5("path", { d: "m12 5-8 8" }),
1151
- /* @__PURE__ */ jsx5("path", { d: "M20 19h-4c0-1.5.44-2 1.5-2.5S20 15.33 20 14c0-.47-.17-.93-.48-1.29a2.11 2.11 0 0 0-2.62-.44c-.42.24-.74.62-.9 1.07" })
1558
+ /* @__PURE__ */ jsx6("path", { d: "m4 5 8 8" }),
1559
+ /* @__PURE__ */ jsx6("path", { d: "m12 5-8 8" }),
1560
+ /* @__PURE__ */ jsx6("path", { d: "M20 19h-4c0-1.5.44-2 1.5-2.5S20 15.33 20 14c0-.47-.17-.93-.48-1.29a2.11 2.11 0 0 0-2.62-.44c-.42.24-.74.62-.9 1.07" })
1152
1561
  ] }),
1153
1562
  alignLeft: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1154
- /* @__PURE__ */ jsx5("path", { d: "M15 12H3" }),
1155
- /* @__PURE__ */ jsx5("path", { d: "M17 18H3" }),
1156
- /* @__PURE__ */ jsx5("path", { d: "M21 6H3" })
1563
+ /* @__PURE__ */ jsx6("path", { d: "M15 12H3" }),
1564
+ /* @__PURE__ */ jsx6("path", { d: "M17 18H3" }),
1565
+ /* @__PURE__ */ jsx6("path", { d: "M21 6H3" })
1157
1566
  ] }),
1158
1567
  alignCenter: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1159
- /* @__PURE__ */ jsx5("path", { d: "M17 12H7" }),
1160
- /* @__PURE__ */ jsx5("path", { d: "M19 18H5" }),
1161
- /* @__PURE__ */ jsx5("path", { d: "M21 6H3" })
1568
+ /* @__PURE__ */ jsx6("path", { d: "M17 12H7" }),
1569
+ /* @__PURE__ */ jsx6("path", { d: "M19 18H5" }),
1570
+ /* @__PURE__ */ jsx6("path", { d: "M21 6H3" })
1162
1571
  ] }),
1163
1572
  alignRight: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1164
- /* @__PURE__ */ jsx5("path", { d: "M21 12H9" }),
1165
- /* @__PURE__ */ jsx5("path", { d: "M21 18H7" }),
1166
- /* @__PURE__ */ jsx5("path", { d: "M21 6H3" })
1573
+ /* @__PURE__ */ jsx6("path", { d: "M21 12H9" }),
1574
+ /* @__PURE__ */ jsx6("path", { d: "M21 18H7" }),
1575
+ /* @__PURE__ */ jsx6("path", { d: "M21 6H3" })
1167
1576
  ] }),
1168
1577
  alignJustify: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1169
- /* @__PURE__ */ jsx5("path", { d: "M3 12h18" }),
1170
- /* @__PURE__ */ jsx5("path", { d: "M3 18h18" }),
1171
- /* @__PURE__ */ jsx5("path", { d: "M3 6h18" })
1578
+ /* @__PURE__ */ jsx6("path", { d: "M3 12h18" }),
1579
+ /* @__PURE__ */ jsx6("path", { d: "M3 18h18" }),
1580
+ /* @__PURE__ */ jsx6("path", { d: "M3 6h18" })
1172
1581
  ] }),
1173
1582
  list: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1174
- /* @__PURE__ */ jsx5("path", { d: "M3 12h.01" }),
1175
- /* @__PURE__ */ jsx5("path", { d: "M3 18h.01" }),
1176
- /* @__PURE__ */ jsx5("path", { d: "M3 6h.01" }),
1177
- /* @__PURE__ */ jsx5("path", { d: "M8 12h13" }),
1178
- /* @__PURE__ */ jsx5("path", { d: "M8 18h13" }),
1179
- /* @__PURE__ */ jsx5("path", { d: "M8 6h13" })
1583
+ /* @__PURE__ */ jsx6("path", { d: "M3 12h.01" }),
1584
+ /* @__PURE__ */ jsx6("path", { d: "M3 18h.01" }),
1585
+ /* @__PURE__ */ jsx6("path", { d: "M3 6h.01" }),
1586
+ /* @__PURE__ */ jsx6("path", { d: "M8 12h13" }),
1587
+ /* @__PURE__ */ jsx6("path", { d: "M8 18h13" }),
1588
+ /* @__PURE__ */ jsx6("path", { d: "M8 6h13" })
1180
1589
  ] }),
1181
1590
  listOrdered: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1182
- /* @__PURE__ */ jsx5("path", { d: "M10 12h11" }),
1183
- /* @__PURE__ */ jsx5("path", { d: "M10 18h11" }),
1184
- /* @__PURE__ */ jsx5("path", { d: "M10 6h11" }),
1185
- /* @__PURE__ */ jsx5("path", { d: "M4 10h2" }),
1186
- /* @__PURE__ */ jsx5("path", { d: "M4 6h1v4" }),
1187
- /* @__PURE__ */ jsx5("path", { d: "M6 18H4c0-1 2-2 2-3s-1-1.5-2-1" })
1591
+ /* @__PURE__ */ jsx6("path", { d: "M10 12h11" }),
1592
+ /* @__PURE__ */ jsx6("path", { d: "M10 18h11" }),
1593
+ /* @__PURE__ */ jsx6("path", { d: "M10 6h11" }),
1594
+ /* @__PURE__ */ jsx6("path", { d: "M4 10h2" }),
1595
+ /* @__PURE__ */ jsx6("path", { d: "M4 6h1v4" }),
1596
+ /* @__PURE__ */ jsx6("path", { d: "M6 18H4c0-1 2-2 2-3s-1-1.5-2-1" })
1188
1597
  ] }),
1189
1598
  outdent: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1190
- /* @__PURE__ */ jsx5("path", { d: "M21 12H11" }),
1191
- /* @__PURE__ */ jsx5("path", { d: "M21 18H11" }),
1192
- /* @__PURE__ */ jsx5("path", { d: "M21 6H11" }),
1193
- /* @__PURE__ */ jsx5("path", { d: "m7 8-4 4 4 4" })
1599
+ /* @__PURE__ */ jsx6("path", { d: "M21 12H11" }),
1600
+ /* @__PURE__ */ jsx6("path", { d: "M21 18H11" }),
1601
+ /* @__PURE__ */ jsx6("path", { d: "M21 6H11" }),
1602
+ /* @__PURE__ */ jsx6("path", { d: "m7 8-4 4 4 4" })
1194
1603
  ] }),
1195
1604
  indent: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1196
- /* @__PURE__ */ jsx5("path", { d: "M21 12H11" }),
1197
- /* @__PURE__ */ jsx5("path", { d: "M21 18H11" }),
1198
- /* @__PURE__ */ jsx5("path", { d: "M21 6H11" }),
1199
- /* @__PURE__ */ jsx5("path", { d: "m3 8 4 4-4 4" })
1605
+ /* @__PURE__ */ jsx6("path", { d: "M21 12H11" }),
1606
+ /* @__PURE__ */ jsx6("path", { d: "M21 18H11" }),
1607
+ /* @__PURE__ */ jsx6("path", { d: "M21 6H11" }),
1608
+ /* @__PURE__ */ jsx6("path", { d: "m3 8 4 4-4 4" })
1200
1609
  ] }),
1201
1610
  quote: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1202
- /* @__PURE__ */ jsx5("path", { d: "M17 6H3" }),
1203
- /* @__PURE__ */ jsx5("path", { d: "M21 12H8" }),
1204
- /* @__PURE__ */ jsx5("path", { d: "M21 18H8" }),
1205
- /* @__PURE__ */ jsx5("path", { d: "M3 12v6" })
1611
+ /* @__PURE__ */ jsx6("path", { d: "M17 6H3" }),
1612
+ /* @__PURE__ */ jsx6("path", { d: "M21 12H8" }),
1613
+ /* @__PURE__ */ jsx6("path", { d: "M21 18H8" }),
1614
+ /* @__PURE__ */ jsx6("path", { d: "M3 12v6" })
1206
1615
  ] }),
1207
1616
  pilcrow: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1208
- /* @__PURE__ */ jsx5("path", { d: "M13 4v16" }),
1209
- /* @__PURE__ */ jsx5("path", { d: "M17 4v16" }),
1210
- /* @__PURE__ */ jsx5("path", { d: "M19 4H9.5a4.5 4.5 0 0 0 0 9H13" })
1617
+ /* @__PURE__ */ jsx6("path", { d: "M13 4v16" }),
1618
+ /* @__PURE__ */ jsx6("path", { d: "M17 4v16" }),
1619
+ /* @__PURE__ */ jsx6("path", { d: "M19 4H9.5a4.5 4.5 0 0 0 0 9H13" })
1211
1620
  ] }),
1212
1621
  pageBreak: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1213
- /* @__PURE__ */ jsx5("line", { x1: "3", x2: "21", y1: "12", y2: "12" }),
1214
- /* @__PURE__ */ jsx5("polyline", { points: "8 8 12 4 16 8" }),
1215
- /* @__PURE__ */ jsx5("polyline", { points: "16 16 12 20 8 16" })
1622
+ /* @__PURE__ */ jsx6("line", { x1: "3", x2: "21", y1: "12", y2: "12" }),
1623
+ /* @__PURE__ */ jsx6("polyline", { points: "8 8 12 4 16 8" }),
1624
+ /* @__PURE__ */ jsx6("polyline", { points: "16 16 12 20 8 16" })
1216
1625
  ] }),
1217
1626
  divider: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1218
- /* @__PURE__ */ jsx5("path", { d: "M3 12h18" }),
1219
- /* @__PURE__ */ jsx5("path", { d: "M8 6h8", opacity: ".45" }),
1220
- /* @__PURE__ */ jsx5("path", { d: "M8 18h8", opacity: ".45" })
1627
+ /* @__PURE__ */ jsx6("path", { d: "M3 12h18" }),
1628
+ /* @__PURE__ */ jsx6("path", { d: "M8 6h8", opacity: ".45" }),
1629
+ /* @__PURE__ */ jsx6("path", { d: "M8 18h8", opacity: ".45" })
1221
1630
  ] }),
1222
1631
  layout: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1223
- /* @__PURE__ */ jsx5("rect", { width: "18", height: "7", x: "3", y: "3", rx: "1" }),
1224
- /* @__PURE__ */ jsx5("rect", { width: "9", height: "7", x: "3", y: "14", rx: "1" }),
1225
- /* @__PURE__ */ jsx5("rect", { width: "5", height: "7", x: "16", y: "14", rx: "1" })
1632
+ /* @__PURE__ */ jsx6("rect", { width: "18", height: "7", x: "3", y: "3", rx: "1" }),
1633
+ /* @__PURE__ */ jsx6("rect", { width: "9", height: "7", x: "3", y: "14", rx: "1" }),
1634
+ /* @__PURE__ */ jsx6("rect", { width: "5", height: "7", x: "16", y: "14", rx: "1" })
1226
1635
  ] }),
1227
1636
  search: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1228
- /* @__PURE__ */ jsx5("circle", { cx: "11", cy: "11", r: "8" }),
1229
- /* @__PURE__ */ jsx5("path", { d: "m21 21-4.3-4.3" })
1637
+ /* @__PURE__ */ jsx6("circle", { cx: "11", cy: "11", r: "8" }),
1638
+ /* @__PURE__ */ jsx6("path", { d: "m21 21-4.3-4.3" })
1230
1639
  ] }),
1231
1640
  palette: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1232
- /* @__PURE__ */ jsx5("circle", { cx: "13.5", cy: "6.5", r: ".5", fill: "currentColor" }),
1233
- /* @__PURE__ */ jsx5("circle", { cx: "17.5", cy: "10.5", r: ".5", fill: "currentColor" }),
1234
- /* @__PURE__ */ jsx5("circle", { cx: "8.5", cy: "7.5", r: ".5", fill: "currentColor" }),
1235
- /* @__PURE__ */ jsx5("circle", { cx: "6.5", cy: "12.5", r: ".5", fill: "currentColor" }),
1236
- /* @__PURE__ */ jsx5("path", { d: "M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.93 0 1.65-.75 1.65-1.69 0-.44-.18-.84-.44-1.13-.29-.29-.44-.65-.44-1.13a1.64 1.64 0 0 1 1.67-1.67h2c3.05 0 5.55-2.5 5.55-5.55C21.97 6.01 17.46 2 12 2z" })
1641
+ /* @__PURE__ */ jsx6("circle", { cx: "13.5", cy: "6.5", r: ".5", fill: "currentColor" }),
1642
+ /* @__PURE__ */ jsx6("circle", { cx: "17.5", cy: "10.5", r: ".5", fill: "currentColor" }),
1643
+ /* @__PURE__ */ jsx6("circle", { cx: "8.5", cy: "7.5", r: ".5", fill: "currentColor" }),
1644
+ /* @__PURE__ */ jsx6("circle", { cx: "6.5", cy: "12.5", r: ".5", fill: "currentColor" }),
1645
+ /* @__PURE__ */ jsx6("path", { d: "M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.93 0 1.65-.75 1.65-1.69 0-.44-.18-.84-.44-1.13-.29-.29-.44-.65-.44-1.13a1.64 1.64 0 0 1 1.67-1.67h2c3.05 0 5.55-2.5 5.55-5.55C21.97 6.01 17.46 2 12 2z" })
1237
1646
  ] }),
1238
1647
  highlighter: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1239
- /* @__PURE__ */ jsx5("path", { d: "m9 11-6 6v3h9l3-3" }),
1240
- /* @__PURE__ */ jsx5("path", { d: "m22 12-4.6 4.6a2 2 0 0 1-2.8 0l-5.2-5.2a2 2 0 0 1 0-2.8L14 4" })
1648
+ /* @__PURE__ */ jsx6("path", { d: "m9 11-6 6v3h9l3-3" }),
1649
+ /* @__PURE__ */ jsx6("path", { d: "m22 12-4.6 4.6a2 2 0 0 1-2.8 0l-5.2-5.2a2 2 0 0 1 0-2.8L14 4" })
1241
1650
  ] }),
1242
1651
  link: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1243
- /* @__PURE__ */ jsx5("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
1244
- /* @__PURE__ */ jsx5("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
1652
+ /* @__PURE__ */ jsx6("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
1653
+ /* @__PURE__ */ jsx6("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
1245
1654
  ] }),
1246
1655
  image: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1247
- /* @__PURE__ */ jsx5("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }),
1248
- /* @__PURE__ */ jsx5("circle", { cx: "9", cy: "9", r: "2" }),
1249
- /* @__PURE__ */ jsx5("path", { d: "m21 15-3.09-3.09a2 2 0 0 0-2.82 0L6 21" })
1656
+ /* @__PURE__ */ jsx6("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }),
1657
+ /* @__PURE__ */ jsx6("circle", { cx: "9", cy: "9", r: "2" }),
1658
+ /* @__PURE__ */ jsx6("path", { d: "m21 15-3.09-3.09a2 2 0 0 0-2.82 0L6 21" })
1250
1659
  ] }),
1251
1660
  table: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1252
- /* @__PURE__ */ jsx5("path", { d: "M12 3v18" }),
1253
- /* @__PURE__ */ jsx5("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }),
1254
- /* @__PURE__ */ jsx5("path", { d: "M3 9h18" }),
1255
- /* @__PURE__ */ jsx5("path", { d: "M3 15h18" })
1661
+ /* @__PURE__ */ jsx6("path", { d: "M12 3v18" }),
1662
+ /* @__PURE__ */ jsx6("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }),
1663
+ /* @__PURE__ */ jsx6("path", { d: "M3 9h18" }),
1664
+ /* @__PURE__ */ jsx6("path", { d: "M3 15h18" })
1256
1665
  ] }),
1257
1666
  eraser: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1258
- /* @__PURE__ */ jsx5("path", { d: "m7 21-4.3-4.3c-1-1-1-2.5 0-3.4l9.6-9.6c1-1 2.5-1 3.4 0l5.6 5.6c1 1 1 2.5 0 3.4L13 21" }),
1259
- /* @__PURE__ */ jsx5("path", { d: "M22 21H7" }),
1260
- /* @__PURE__ */ jsx5("path", { d: "m5 11 9 9" })
1667
+ /* @__PURE__ */ jsx6("path", { d: "m7 21-4.3-4.3c-1-1-1-2.5 0-3.4l9.6-9.6c1-1 2.5-1 3.4 0l5.6 5.6c1 1 1 2.5 0 3.4L13 21" }),
1668
+ /* @__PURE__ */ jsx6("path", { d: "M22 21H7" }),
1669
+ /* @__PURE__ */ jsx6("path", { d: "m5 11 9 9" })
1261
1670
  ] }),
1262
1671
  save: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1263
- /* @__PURE__ */ jsx5("path", { d: "M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z" }),
1264
- /* @__PURE__ */ jsx5("path", { d: "M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7" }),
1265
- /* @__PURE__ */ jsx5("path", { d: "M7 3v4a1 1 0 0 0 1 1h7" })
1672
+ /* @__PURE__ */ jsx6("path", { d: "M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z" }),
1673
+ /* @__PURE__ */ jsx6("path", { d: "M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7" }),
1674
+ /* @__PURE__ */ jsx6("path", { d: "M7 3v4a1 1 0 0 0 1 1h7" })
1266
1675
  ] }),
1267
1676
  download: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1268
- /* @__PURE__ */ jsx5("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
1269
- /* @__PURE__ */ jsx5("polyline", { points: "7 10 12 15 17 10" }),
1270
- /* @__PURE__ */ jsx5("line", { x1: "12", x2: "12", y1: "15", y2: "3" })
1677
+ /* @__PURE__ */ jsx6("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
1678
+ /* @__PURE__ */ jsx6("polyline", { points: "7 10 12 15 17 10" }),
1679
+ /* @__PURE__ */ jsx6("line", { x1: "12", x2: "12", y1: "15", y2: "3" })
1271
1680
  ] }),
1272
- chevronDown: /* @__PURE__ */ jsx5("path", { d: "m6 9 6 6 6-6" }),
1273
- chevronUp: /* @__PURE__ */ jsx5("path", { d: "m18 15-6-6-6 6" }),
1681
+ chevronDown: /* @__PURE__ */ jsx6("path", { d: "m6 9 6 6 6-6" }),
1682
+ chevronUp: /* @__PURE__ */ jsx6("path", { d: "m18 15-6-6-6 6" }),
1274
1683
  close: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1275
- /* @__PURE__ */ jsx5("path", { d: "M18 6 6 18" }),
1276
- /* @__PURE__ */ jsx5("path", { d: "m6 6 12 12" })
1684
+ /* @__PURE__ */ jsx6("path", { d: "M18 6 6 18" }),
1685
+ /* @__PURE__ */ jsx6("path", { d: "m6 6 12 12" })
1277
1686
  ] }),
1278
1687
  maximize: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1279
- /* @__PURE__ */ jsx5("path", { d: "M8 3H5a2 2 0 0 0-2 2v3" }),
1280
- /* @__PURE__ */ jsx5("path", { d: "M21 8V5a2 2 0 0 0-2-2h-3" }),
1281
- /* @__PURE__ */ jsx5("path", { d: "M3 16v3a2 2 0 0 0 2 2h3" }),
1282
- /* @__PURE__ */ jsx5("path", { d: "M16 21h3a2 2 0 0 0 2-2v-3" })
1688
+ /* @__PURE__ */ jsx6("path", { d: "M8 3H5a2 2 0 0 0-2 2v3" }),
1689
+ /* @__PURE__ */ jsx6("path", { d: "M21 8V5a2 2 0 0 0-2-2h-3" }),
1690
+ /* @__PURE__ */ jsx6("path", { d: "M3 16v3a2 2 0 0 0 2 2h3" }),
1691
+ /* @__PURE__ */ jsx6("path", { d: "M16 21h3a2 2 0 0 0 2-2v-3" })
1283
1692
  ] }),
1284
1693
  copy: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1285
- /* @__PURE__ */ jsx5("rect", { width: "14", height: "14", x: "8", y: "8", rx: "2" }),
1286
- /* @__PURE__ */ jsx5("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })
1694
+ /* @__PURE__ */ jsx6("rect", { width: "14", height: "14", x: "8", y: "8", rx: "2" }),
1695
+ /* @__PURE__ */ jsx6("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })
1287
1696
  ] }),
1288
1697
  file: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1289
- /* @__PURE__ */ jsx5("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
1290
- /* @__PURE__ */ jsx5("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
1698
+ /* @__PURE__ */ jsx6("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
1699
+ /* @__PURE__ */ jsx6("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
1291
1700
  ] }),
1292
1701
  plus: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1293
- /* @__PURE__ */ jsx5("path", { d: "M5 12h14" }),
1294
- /* @__PURE__ */ jsx5("path", { d: "M12 5v14" })
1702
+ /* @__PURE__ */ jsx6("path", { d: "M5 12h14" }),
1703
+ /* @__PURE__ */ jsx6("path", { d: "M12 5v14" })
1295
1704
  ] }),
1296
- minus: /* @__PURE__ */ jsx5("path", { d: "M5 12h14" }),
1297
- check: /* @__PURE__ */ jsx5("path", { d: "M20 6 9 17l-5-5" }),
1705
+ minus: /* @__PURE__ */ jsx6("path", { d: "M5 12h14" }),
1706
+ check: /* @__PURE__ */ jsx6("path", { d: "M20 6 9 17l-5-5" }),
1298
1707
  sparkles: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1299
- /* @__PURE__ */ jsx5("path", { d: "M9.94 14.06 8 20l-1.94-5.94L0 12l6.06-1.94L8 4l1.94 6.06L16 12z", transform: "translate(3 -1) scale(.85)" }),
1300
- /* @__PURE__ */ jsx5("path", { d: "M20 3v4" }),
1301
- /* @__PURE__ */ jsx5("path", { d: "M22 5h-4" })
1708
+ /* @__PURE__ */ jsx6("path", { d: "M9.94 14.06 8 20l-1.94-5.94L0 12l6.06-1.94L8 4l1.94 6.06L16 12z", transform: "translate(3 -1) scale(.85)" }),
1709
+ /* @__PURE__ */ jsx6("path", { d: "M20 3v4" }),
1710
+ /* @__PURE__ */ jsx6("path", { d: "M22 5h-4" })
1302
1711
  ] }),
1303
1712
  upload: /* @__PURE__ */ jsxs3(Fragment2, { children: [
1304
- /* @__PURE__ */ jsx5("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
1305
- /* @__PURE__ */ jsx5("polyline", { points: "17 8 12 3 7 8" }),
1306
- /* @__PURE__ */ jsx5("line", { x1: "12", x2: "12", y1: "3", y2: "15" })
1713
+ /* @__PURE__ */ jsx6("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
1714
+ /* @__PURE__ */ jsx6("polyline", { points: "17 8 12 3 7 8" }),
1715
+ /* @__PURE__ */ jsx6("line", { x1: "12", x2: "12", y1: "3", y2: "15" })
1307
1716
  ] })
1308
1717
  };
1309
1718
  function Icon({ name, size = 16 }) {
1310
- return /* @__PURE__ */ jsx5(
1719
+ return /* @__PURE__ */ jsx6(
1311
1720
  "svg",
1312
1721
  {
1313
1722
  className: "june-doc__icon",
@@ -1327,12 +1736,12 @@ function Icon({ name, size = 16 }) {
1327
1736
  }
1328
1737
 
1329
1738
  // src/components/document-editor/document-popover.tsx
1330
- import { useEffect as useEffect2, useRef as useRef3, useState as useState2 } from "react";
1331
- import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1739
+ import { useEffect as useEffect3, useRef as useRef3, useState as useState2 } from "react";
1740
+ import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
1332
1741
  function Dropdown({ trigger, children, align = "start", className, onOpen }) {
1333
1742
  const [open, setOpen] = useState2(false);
1334
1743
  const anchor = useRef3(null);
1335
- useEffect2(() => {
1744
+ useEffect3(() => {
1336
1745
  if (!open) return;
1337
1746
  const onDown = (e) => {
1338
1747
  if (anchor.current && !anchor.current.contains(e.target)) setOpen(false);
@@ -1358,14 +1767,14 @@ function Dropdown({ trigger, children, align = "start", className, onOpen }) {
1358
1767
  },
1359
1768
  children: [
1360
1769
  trigger({ open, toggle }),
1361
- open ? /* @__PURE__ */ jsx6("div", { className: `june-doc__pop june-doc__pop--${align}${className ? ` ${className}` : ""}`, children: children(close) }) : null
1770
+ open ? /* @__PURE__ */ jsx7("div", { className: `june-doc__pop june-doc__pop--${align}${className ? ` ${className}` : ""}`, children: children(close) }) : null
1362
1771
  ]
1363
1772
  }
1364
1773
  );
1365
1774
  }
1366
1775
 
1367
1776
  // src/components/document-editor/document-toolbar.tsx
1368
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
1777
+ import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
1369
1778
  var FONT_FAMILIES = [
1370
1779
  { label: "Default", value: "" },
1371
1780
  { label: "Arial", value: "Arial, Helvetica, sans-serif" },
@@ -1425,26 +1834,26 @@ function Btn({ label, icon, active, disabled, toggle, onClick, children, classNa
1425
1834
  onMouseDown: (e) => e.preventDefault(),
1426
1835
  onClick,
1427
1836
  children: [
1428
- icon ? /* @__PURE__ */ jsx7(Icon, { name: icon }) : null,
1429
- children ?? (text ? /* @__PURE__ */ jsx7("span", { children: label }) : null)
1837
+ icon ? /* @__PURE__ */ jsx8(Icon, { name: icon }) : null,
1838
+ children ?? (text ? /* @__PURE__ */ jsx8("span", { children: label }) : null)
1430
1839
  ]
1431
1840
  }
1432
1841
  );
1433
1842
  }
1434
1843
  function Group({ label, children }) {
1435
1844
  return /* @__PURE__ */ jsxs5("div", { className: "june-doc__group", role: "group", "aria-label": label, children: [
1436
- label ? /* @__PURE__ */ jsx7("span", { className: "june-doc__group-label", "aria-hidden": "true", children: label }) : null,
1845
+ label ? /* @__PURE__ */ jsx8("span", { className: "june-doc__group-label", "aria-hidden": "true", children: label }) : null,
1437
1846
  children
1438
1847
  ] });
1439
1848
  }
1440
1849
  function Field({ label, children }) {
1441
1850
  return /* @__PURE__ */ jsxs5("label", { className: "june-doc__field", children: [
1442
- /* @__PURE__ */ jsx7("span", { className: "june-doc__field-label", children: label }),
1851
+ /* @__PURE__ */ jsx8("span", { className: "june-doc__field-label", children: label }),
1443
1852
  children
1444
1853
  ] });
1445
1854
  }
1446
1855
  function ColorPicker({ label, icon, colors, current, disabled, resetLabel, onPick, onReset }) {
1447
- return /* @__PURE__ */ jsx7(
1856
+ return /* @__PURE__ */ jsx8(
1448
1857
  Dropdown,
1449
1858
  {
1450
1859
  trigger: ({ open, toggle }) => /* @__PURE__ */ jsxs5(
@@ -1460,14 +1869,14 @@ function ColorPicker({ label, icon, colors, current, disabled, resetLabel, onPic
1460
1869
  onMouseDown: (e) => e.preventDefault(),
1461
1870
  onClick: toggle,
1462
1871
  children: [
1463
- /* @__PURE__ */ jsx7(Icon, { name: icon }),
1464
- /* @__PURE__ */ jsx7("span", { className: "june-doc__color-bar", style: { background: current ?? "transparent" } })
1872
+ /* @__PURE__ */ jsx8(Icon, { name: icon }),
1873
+ /* @__PURE__ */ jsx8("span", { className: "june-doc__color-bar", style: { background: current ?? "transparent" } })
1465
1874
  ]
1466
1875
  }
1467
1876
  ),
1468
1877
  children: (close) => /* @__PURE__ */ jsxs5("div", { className: "june-doc__swatches-wrap", role: "dialog", "aria-label": label, children: [
1469
- /* @__PURE__ */ jsx7("div", { className: "june-doc__pop-title", children: label }),
1470
- /* @__PURE__ */ jsx7("div", { className: "june-doc__swatches", children: colors.map((c) => /* @__PURE__ */ jsx7(
1878
+ /* @__PURE__ */ jsx8("div", { className: "june-doc__pop-title", children: label }),
1879
+ /* @__PURE__ */ jsx8("div", { className: "june-doc__swatches", children: colors.map((c) => /* @__PURE__ */ jsx8(
1471
1880
  "button",
1472
1881
  {
1473
1882
  type: "button",
@@ -1485,7 +1894,7 @@ function ColorPicker({ label, icon, colors, current, disabled, resetLabel, onPic
1485
1894
  c
1486
1895
  )) }),
1487
1896
  /* @__PURE__ */ jsxs5("div", { className: "june-doc__pop-row", children: [
1488
- /* @__PURE__ */ jsx7(
1897
+ /* @__PURE__ */ jsx8(
1489
1898
  "button",
1490
1899
  {
1491
1900
  type: "button",
@@ -1499,8 +1908,8 @@ function ColorPicker({ label, icon, colors, current, disabled, resetLabel, onPic
1499
1908
  }
1500
1909
  ),
1501
1910
  /* @__PURE__ */ jsxs5("label", { className: "june-doc__custom-color", title: "Custom color", children: [
1502
- /* @__PURE__ */ jsx7("span", { children: "Custom" }),
1503
- /* @__PURE__ */ jsx7(
1911
+ /* @__PURE__ */ jsx8("span", { children: "Custom" }),
1912
+ /* @__PURE__ */ jsx8(
1504
1913
  "input",
1505
1914
  {
1506
1915
  type: "color",
@@ -1532,8 +1941,8 @@ function LinkPanel({
1532
1941
  close();
1533
1942
  };
1534
1943
  return /* @__PURE__ */ jsxs5("div", { className: "june-doc__form", role: "dialog", "aria-label": "Edit link", children: [
1535
- /* @__PURE__ */ jsx7("div", { className: "june-doc__pop-title", children: "Link" }),
1536
- /* @__PURE__ */ jsx7(
1944
+ /* @__PURE__ */ jsx8("div", { className: "june-doc__pop-title", children: "Link" }),
1945
+ /* @__PURE__ */ jsx8(
1537
1946
  "input",
1538
1947
  {
1539
1948
  "aria-label": "Link address",
@@ -1551,9 +1960,9 @@ function LinkPanel({
1551
1960
  }
1552
1961
  ),
1553
1962
  /* @__PURE__ */ jsxs5("div", { className: "june-doc__pop-row june-doc__pop-row--end", children: [
1554
- isLink ? /* @__PURE__ */ jsx7("button", { type: "button", className: "june-doc__btn june-doc__btn--ghost", onClick: remove, children: "Remove" }) : null,
1555
- /* @__PURE__ */ jsx7("button", { type: "button", className: "june-doc__btn", onClick: close, children: "Cancel" }),
1556
- /* @__PURE__ */ jsx7("button", { type: "button", className: "june-doc__btn june-doc__btn--primary", onClick: apply, children: "Apply" })
1963
+ isLink ? /* @__PURE__ */ jsx8("button", { type: "button", className: "june-doc__btn june-doc__btn--ghost", onClick: remove, children: "Remove" }) : null,
1964
+ /* @__PURE__ */ jsx8("button", { type: "button", className: "june-doc__btn", onClick: close, children: "Cancel" }),
1965
+ /* @__PURE__ */ jsx8("button", { type: "button", className: "june-doc__btn june-doc__btn--primary", onClick: apply, children: "Apply" })
1557
1966
  ] })
1558
1967
  ] });
1559
1968
  }
@@ -1583,7 +1992,7 @@ function ImagePanel({ editor, close, onNotice }) {
1583
1992
  reader.readAsDataURL(f);
1584
1993
  };
1585
1994
  return /* @__PURE__ */ jsxs5("div", { className: "june-doc__form", role: "dialog", "aria-label": "Insert image", children: [
1586
- /* @__PURE__ */ jsx7("div", { className: "june-doc__pop-title", children: "Image" }),
1995
+ /* @__PURE__ */ jsx8("div", { className: "june-doc__pop-title", children: "Image" }),
1587
1996
  /* @__PURE__ */ jsxs5(
1588
1997
  "button",
1589
1998
  {
@@ -1596,12 +2005,12 @@ function ImagePanel({ editor, close, onNotice }) {
1596
2005
  fromFile(e.dataTransfer.files[0]);
1597
2006
  },
1598
2007
  children: [
1599
- /* @__PURE__ */ jsx7(Icon, { name: "upload", size: 18 }),
1600
- /* @__PURE__ */ jsx7("span", { children: "Upload or drop an image" })
2008
+ /* @__PURE__ */ jsx8(Icon, { name: "upload", size: 18 }),
2009
+ /* @__PURE__ */ jsx8("span", { children: "Upload or drop an image" })
1601
2010
  ]
1602
2011
  }
1603
2012
  ),
1604
- /* @__PURE__ */ jsx7(
2013
+ /* @__PURE__ */ jsx8(
1605
2014
  "input",
1606
2015
  {
1607
2016
  ref: file,
@@ -1611,8 +2020,8 @@ function ImagePanel({ editor, close, onNotice }) {
1611
2020
  onChange: (e) => fromFile(e.target.files?.[0])
1612
2021
  }
1613
2022
  ),
1614
- /* @__PURE__ */ jsx7("div", { className: "june-doc__or", children: "or" }),
1615
- /* @__PURE__ */ jsx7(
2023
+ /* @__PURE__ */ jsx8("div", { className: "june-doc__or", children: "or" }),
2024
+ /* @__PURE__ */ jsx8(
1616
2025
  "input",
1617
2026
  {
1618
2027
  "aria-label": "Image address",
@@ -1623,7 +2032,7 @@ function ImagePanel({ editor, close, onNotice }) {
1623
2032
  onKeyDown: (e) => e.key === "Enter" && fromUrl()
1624
2033
  }
1625
2034
  ),
1626
- /* @__PURE__ */ jsx7(
2035
+ /* @__PURE__ */ jsx8(
1627
2036
  "input",
1628
2037
  {
1629
2038
  "aria-label": "Alternative text",
@@ -1634,8 +2043,8 @@ function ImagePanel({ editor, close, onNotice }) {
1634
2043
  }
1635
2044
  ),
1636
2045
  /* @__PURE__ */ jsxs5("div", { className: "june-doc__pop-row june-doc__pop-row--end", children: [
1637
- /* @__PURE__ */ jsx7("button", { type: "button", className: "june-doc__btn", onClick: close, children: "Cancel" }),
1638
- /* @__PURE__ */ jsx7("button", { type: "button", className: "june-doc__btn june-doc__btn--primary", disabled: !url.trim(), onClick: fromUrl, children: "Insert" })
2046
+ /* @__PURE__ */ jsx8("button", { type: "button", className: "june-doc__btn", onClick: close, children: "Cancel" }),
2047
+ /* @__PURE__ */ jsx8("button", { type: "button", className: "june-doc__btn june-doc__btn--primary", disabled: !url.trim(), onClick: fromUrl, children: "Insert" })
1639
2048
  ] })
1640
2049
  ] });
1641
2050
  }
@@ -1647,10 +2056,10 @@ function TablePanel({ editor, close }) {
1647
2056
  "Table ",
1648
2057
  hover[0] ? `${hover[0]} \xD7 ${hover[1]}` : ""
1649
2058
  ] }),
1650
- /* @__PURE__ */ jsx7("div", { className: "june-doc__grid", onMouseLeave: () => setHover([0, 0]), children: Array.from({ length: N * N }, (_, i) => {
2059
+ /* @__PURE__ */ jsx8("div", { className: "june-doc__grid", onMouseLeave: () => setHover([0, 0]), children: Array.from({ length: N * N }, (_, i) => {
1651
2060
  const r = Math.floor(i / N) + 1;
1652
2061
  const c = i % N + 1;
1653
- return /* @__PURE__ */ jsx7(
2062
+ return /* @__PURE__ */ jsx8(
1654
2063
  "button",
1655
2064
  {
1656
2065
  type: "button",
@@ -1735,29 +2144,29 @@ function DocumentToolbar(props) {
1735
2144
  return /* @__PURE__ */ jsxs5("div", { className: "june-doc__ribbon", role: "toolbar", "aria-label": "Document formatting", children: [
1736
2145
  /* @__PURE__ */ jsxs5("div", { className: "june-doc__row", children: [
1737
2146
  /* @__PURE__ */ jsxs5(Group, { label: "History", children: [
1738
- /* @__PURE__ */ jsx7(Btn, { label: "Undo", icon: "undo", disabled: off || !s?.canUndo, onClick: () => run()?.undo().run() }),
1739
- /* @__PURE__ */ jsx7(Btn, { label: "Redo", icon: "redo", disabled: off || !s?.canRedo, onClick: () => run()?.redo().run() })
2147
+ /* @__PURE__ */ jsx8(Btn, { label: "Undo", icon: "undo", disabled: off || !s?.canUndo, onClick: () => run()?.undo().run() }),
2148
+ /* @__PURE__ */ jsx8(Btn, { label: "Redo", icon: "redo", disabled: off || !s?.canRedo, onClick: () => run()?.redo().run() })
1740
2149
  ] }),
1741
2150
  /* @__PURE__ */ jsxs5(Group, { label: "Format", children: [
1742
- /* @__PURE__ */ jsx7(Btn, { label: "Bold", icon: "bold", toggle: true, active: s?.bold, disabled: off, onClick: () => run()?.toggleBold().run() }),
1743
- /* @__PURE__ */ jsx7(Btn, { label: "Italic", icon: "italic", toggle: true, active: s?.italic, disabled: off, onClick: () => run()?.toggleItalic().run() }),
1744
- /* @__PURE__ */ jsx7(Btn, { label: "Underline", icon: "underline", toggle: true, active: s?.underline, disabled: off, onClick: () => run()?.toggleUnderline().run() }),
1745
- /* @__PURE__ */ jsx7(Btn, { label: "Strikethrough", icon: "strike", toggle: true, active: s?.strike, disabled: off, onClick: () => run()?.toggleStrike().run() }),
1746
- /* @__PURE__ */ jsx7(Btn, { label: "Inline code", icon: "code", toggle: true, active: s?.code, disabled: off, onClick: () => run()?.toggleCode().run() }),
1747
- /* @__PURE__ */ jsx7(Btn, { label: "Superscript", icon: "superscript", toggle: true, active: s?.sup, disabled: off, onClick: () => run()?.toggleSuperscript().run() }),
1748
- /* @__PURE__ */ jsx7(Btn, { label: "Subscript", icon: "subscript", toggle: true, active: s?.sub, disabled: off, onClick: () => run()?.toggleSubscript().run() })
2151
+ /* @__PURE__ */ jsx8(Btn, { label: "Bold", icon: "bold", toggle: true, active: s?.bold, disabled: off, onClick: () => run()?.toggleBold().run() }),
2152
+ /* @__PURE__ */ jsx8(Btn, { label: "Italic", icon: "italic", toggle: true, active: s?.italic, disabled: off, onClick: () => run()?.toggleItalic().run() }),
2153
+ /* @__PURE__ */ jsx8(Btn, { label: "Underline", icon: "underline", toggle: true, active: s?.underline, disabled: off, onClick: () => run()?.toggleUnderline().run() }),
2154
+ /* @__PURE__ */ jsx8(Btn, { label: "Strikethrough", icon: "strike", toggle: true, active: s?.strike, disabled: off, onClick: () => run()?.toggleStrike().run() }),
2155
+ /* @__PURE__ */ jsx8(Btn, { label: "Inline code", icon: "code", toggle: true, active: s?.code, disabled: off, onClick: () => run()?.toggleCode().run() }),
2156
+ /* @__PURE__ */ jsx8(Btn, { label: "Superscript", icon: "superscript", toggle: true, active: s?.sup, disabled: off, onClick: () => run()?.toggleSuperscript().run() }),
2157
+ /* @__PURE__ */ jsx8(Btn, { label: "Subscript", icon: "subscript", toggle: true, active: s?.sub, disabled: off, onClick: () => run()?.toggleSubscript().run() })
1749
2158
  ] }),
1750
2159
  /* @__PURE__ */ jsxs5(Group, { label: "Align", children: [
1751
- /* @__PURE__ */ jsx7(Btn, { label: "Align left", icon: "alignLeft", toggle: true, active: s?.left, disabled: off, onClick: () => run()?.setTextAlign("left").run() }),
1752
- /* @__PURE__ */ jsx7(Btn, { label: "Align center", icon: "alignCenter", toggle: true, active: s?.center, disabled: off, onClick: () => run()?.setTextAlign("center").run() }),
1753
- /* @__PURE__ */ jsx7(Btn, { label: "Align right", icon: "alignRight", toggle: true, active: s?.right, disabled: off, onClick: () => run()?.setTextAlign("right").run() }),
1754
- /* @__PURE__ */ jsx7(Btn, { label: "Justify", icon: "alignJustify", toggle: true, active: s?.justify, disabled: off, onClick: () => run()?.setTextAlign("justify").run() })
2160
+ /* @__PURE__ */ jsx8(Btn, { label: "Align left", icon: "alignLeft", toggle: true, active: s?.left, disabled: off, onClick: () => run()?.setTextAlign("left").run() }),
2161
+ /* @__PURE__ */ jsx8(Btn, { label: "Align center", icon: "alignCenter", toggle: true, active: s?.center, disabled: off, onClick: () => run()?.setTextAlign("center").run() }),
2162
+ /* @__PURE__ */ jsx8(Btn, { label: "Align right", icon: "alignRight", toggle: true, active: s?.right, disabled: off, onClick: () => run()?.setTextAlign("right").run() }),
2163
+ /* @__PURE__ */ jsx8(Btn, { label: "Justify", icon: "alignJustify", toggle: true, active: s?.justify, disabled: off, onClick: () => run()?.setTextAlign("justify").run() })
1755
2164
  ] }),
1756
2165
  /* @__PURE__ */ jsxs5(Group, { label: "Lists", children: [
1757
- /* @__PURE__ */ jsx7(Btn, { label: "Bullet list", icon: "list", toggle: true, active: s?.bullet, disabled: off, onClick: () => run()?.toggleBulletList().run() }),
1758
- /* @__PURE__ */ jsx7(Btn, { label: "Numbered list", icon: "listOrdered", toggle: true, active: s?.ordered, disabled: off, onClick: () => run()?.toggleOrderedList().run() }),
1759
- /* @__PURE__ */ jsx7(Btn, { label: "Decrease indent", icon: "outdent", disabled: off || !s?.canLift, onClick: () => run()?.liftListItem("listItem").run() }),
1760
- /* @__PURE__ */ jsx7(Btn, { label: "Increase indent", icon: "indent", disabled: off || !s?.canSink, onClick: () => run()?.sinkListItem("listItem").run() })
2166
+ /* @__PURE__ */ jsx8(Btn, { label: "Bullet list", icon: "list", toggle: true, active: s?.bullet, disabled: off, onClick: () => run()?.toggleBulletList().run() }),
2167
+ /* @__PURE__ */ jsx8(Btn, { label: "Numbered list", icon: "listOrdered", toggle: true, active: s?.ordered, disabled: off, onClick: () => run()?.toggleOrderedList().run() }),
2168
+ /* @__PURE__ */ jsx8(Btn, { label: "Decrease indent", icon: "outdent", disabled: off || !s?.canLift, onClick: () => run()?.liftListItem("listItem").run() }),
2169
+ /* @__PURE__ */ jsx8(Btn, { label: "Increase indent", icon: "indent", disabled: off || !s?.canSink, onClick: () => run()?.sinkListItem("listItem").run() })
1761
2170
  ] }),
1762
2171
  /* @__PURE__ */ jsxs5(
1763
2172
  "button",
@@ -1770,22 +2179,22 @@ function DocumentToolbar(props) {
1770
2179
  onClick: onToggleExpanded,
1771
2180
  children: [
1772
2181
  expanded ? "Less" : "More",
1773
- /* @__PURE__ */ jsx7(Icon, { name: expanded ? "chevronUp" : "chevronDown", size: 14 })
2182
+ /* @__PURE__ */ jsx8(Icon, { name: expanded ? "chevronUp" : "chevronDown", size: 14 })
1774
2183
  ]
1775
2184
  }
1776
2185
  )
1777
2186
  ] }),
1778
2187
  expanded ? /* @__PURE__ */ jsxs5("div", { className: "june-doc__row june-doc__row--secondary", children: [
1779
2188
  /* @__PURE__ */ jsxs5(Group, { label: "Style", children: [
1780
- /* @__PURE__ */ jsx7(Field, { label: "Style", children: /* @__PURE__ */ jsxs5("select", { className: "june-doc__select", "aria-label": "Text style", disabled: off, value: style, onChange: (e) => setStyle(e.target.value), children: [
1781
- /* @__PURE__ */ jsx7("option", { value: "p", children: "Paragraph" }),
1782
- /* @__PURE__ */ jsx7("option", { value: "1", children: "Heading 1" }),
1783
- /* @__PURE__ */ jsx7("option", { value: "2", children: "Heading 2" }),
1784
- /* @__PURE__ */ jsx7("option", { value: "3", children: "Heading 3" }),
1785
- /* @__PURE__ */ jsx7("option", { value: "quote", children: "Quote" }),
1786
- /* @__PURE__ */ jsx7("option", { value: "code", children: "Code block" })
2189
+ /* @__PURE__ */ jsx8(Field, { label: "Style", children: /* @__PURE__ */ jsxs5("select", { className: "june-doc__select", "aria-label": "Text style", disabled: off, value: style, onChange: (e) => setStyle(e.target.value), children: [
2190
+ /* @__PURE__ */ jsx8("option", { value: "p", children: "Paragraph" }),
2191
+ /* @__PURE__ */ jsx8("option", { value: "1", children: "Heading 1" }),
2192
+ /* @__PURE__ */ jsx8("option", { value: "2", children: "Heading 2" }),
2193
+ /* @__PURE__ */ jsx8("option", { value: "3", children: "Heading 3" }),
2194
+ /* @__PURE__ */ jsx8("option", { value: "quote", children: "Quote" }),
2195
+ /* @__PURE__ */ jsx8("option", { value: "code", children: "Code block" })
1787
2196
  ] }) }),
1788
- /* @__PURE__ */ jsx7(Field, { label: "Font", children: /* @__PURE__ */ jsxs5(
2197
+ /* @__PURE__ */ jsx8(Field, { label: "Font", children: /* @__PURE__ */ jsxs5(
1789
2198
  "select",
1790
2199
  {
1791
2200
  className: "june-doc__select june-doc__select--font",
@@ -1798,12 +2207,12 @@ function DocumentToolbar(props) {
1798
2207
  else run()?.unsetFontFamily().run();
1799
2208
  },
1800
2209
  children: [
1801
- FONT_FAMILIES.map((f) => /* @__PURE__ */ jsx7("option", { value: f.value, style: { fontFamily: f.value || void 0 }, children: f.label }, f.label)),
1802
- !fontKnown && s?.fontFamily ? /* @__PURE__ */ jsx7("option", { value: s.fontFamily, children: s.fontFamily.split(",")[0].replace(/['"]/g, "") }) : null
2210
+ FONT_FAMILIES.map((f) => /* @__PURE__ */ jsx8("option", { value: f.value, style: { fontFamily: f.value || void 0 }, children: f.label }, f.label)),
2211
+ !fontKnown && s?.fontFamily ? /* @__PURE__ */ jsx8("option", { value: s.fontFamily, children: s.fontFamily.split(",")[0].replace(/['"]/g, "") }) : null
1803
2212
  ]
1804
2213
  }
1805
2214
  ) }),
1806
- /* @__PURE__ */ jsx7(Field, { label: "Size", children: /* @__PURE__ */ jsxs5(
2215
+ /* @__PURE__ */ jsx8(Field, { label: "Size", children: /* @__PURE__ */ jsxs5(
1807
2216
  "select",
1808
2217
  {
1809
2218
  className: "june-doc__select june-doc__select--size",
@@ -1816,21 +2225,21 @@ function DocumentToolbar(props) {
1816
2225
  else run()?.unsetFontSize().run();
1817
2226
  },
1818
2227
  children: [
1819
- /* @__PURE__ */ jsx7("option", { value: "", children: "Auto" }),
1820
- sizes.map((n) => /* @__PURE__ */ jsx7("option", { value: String(n), children: n }, n))
2228
+ /* @__PURE__ */ jsx8("option", { value: "", children: "Auto" }),
2229
+ sizes.map((n) => /* @__PURE__ */ jsx8("option", { value: String(n), children: n }, n))
1821
2230
  ]
1822
2231
  }
1823
2232
  ) })
1824
2233
  ] }),
1825
- /* @__PURE__ */ jsx7(Btn, { label: "Show formatting marks", icon: "pilcrow", toggle: true, active: showMarks, onClick: onToggleMarks, text: true, className: "june-doc__btn--marks", children: /* @__PURE__ */ jsx7("span", { children: "Paragraph" }) }),
2234
+ /* @__PURE__ */ jsx8(Btn, { label: "Show formatting marks", icon: "pilcrow", toggle: true, active: showMarks, onClick: onToggleMarks, text: true, className: "june-doc__btn--marks", children: /* @__PURE__ */ jsx8("span", { children: "Paragraph" }) }),
1826
2235
  /* @__PURE__ */ jsxs5(Group, { label: "Document", children: [
1827
- /* @__PURE__ */ jsx7(Btn, { label: "Insert page break", icon: "pageBreak", disabled: off, onClick: () => run()?.setPageBreak().run() }),
1828
- /* @__PURE__ */ jsx7(Btn, { label: "Insert divider", icon: "divider", disabled: off, onClick: () => run()?.setHorizontalRule().run() }),
1829
- /* @__PURE__ */ jsx7(Btn, { label: layout === "page" ? "Switch to full-width layout" : "Switch to page layout", icon: "layout", toggle: true, active: layout === "fluid", onClick: onToggleLayout }),
1830
- /* @__PURE__ */ jsx7(Btn, { label: "Find and replace", icon: "search", toggle: true, active: findOpen, onClick: onToggleFind })
2236
+ /* @__PURE__ */ jsx8(Btn, { label: "Insert page break", icon: "pageBreak", disabled: off, onClick: () => run()?.setPageBreak().run() }),
2237
+ /* @__PURE__ */ jsx8(Btn, { label: "Insert divider", icon: "divider", disabled: off, onClick: () => run()?.setHorizontalRule().run() }),
2238
+ /* @__PURE__ */ jsx8(Btn, { label: layout === "page" ? "Switch to full-width layout" : "Switch to page layout", icon: "layout", toggle: true, active: layout === "fluid", onClick: onToggleLayout }),
2239
+ /* @__PURE__ */ jsx8(Btn, { label: "Find and replace", icon: "search", toggle: true, active: findOpen, onClick: onToggleFind })
1831
2240
  ] }),
1832
2241
  /* @__PURE__ */ jsxs5(Group, { label: "Color", children: [
1833
- /* @__PURE__ */ jsx7(
2242
+ /* @__PURE__ */ jsx8(
1834
2243
  ColorPicker,
1835
2244
  {
1836
2245
  label: "Text color",
@@ -1843,7 +2252,7 @@ function DocumentToolbar(props) {
1843
2252
  onReset: () => run()?.unsetColor().run()
1844
2253
  }
1845
2254
  ),
1846
- /* @__PURE__ */ jsx7(
2255
+ /* @__PURE__ */ jsx8(
1847
2256
  ColorPicker,
1848
2257
  {
1849
2258
  label: "Highlight",
@@ -1858,33 +2267,33 @@ function DocumentToolbar(props) {
1858
2267
  )
1859
2268
  ] }),
1860
2269
  /* @__PURE__ */ jsxs5(Group, { label: "Insert", children: [
1861
- editor ? /* @__PURE__ */ jsx7(
2270
+ editor ? /* @__PURE__ */ jsx8(
1862
2271
  Dropdown,
1863
2272
  {
1864
- trigger: ({ open, toggle }) => /* @__PURE__ */ jsx7(Btn, { label: "Link", icon: "link", toggle: true, active: s?.link || open, disabled: off, onClick: toggle }),
1865
- children: (close) => /* @__PURE__ */ jsx7(LinkPanel, { editor, href: s?.linkHref ?? "", isLink: !!s?.link, close })
2273
+ trigger: ({ open, toggle }) => /* @__PURE__ */ jsx8(Btn, { label: "Link", icon: "link", toggle: true, active: s?.link || open, disabled: off, onClick: toggle }),
2274
+ children: (close) => /* @__PURE__ */ jsx8(LinkPanel, { editor, href: s?.linkHref ?? "", isLink: !!s?.link, close })
1866
2275
  }
1867
2276
  ) : null,
1868
- editor ? /* @__PURE__ */ jsx7(Dropdown, { trigger: ({ open, toggle }) => /* @__PURE__ */ jsx7(Btn, { label: "Insert image", icon: "image", active: open, disabled: off, onClick: toggle }), children: (close) => /* @__PURE__ */ jsx7(ImagePanel, { editor, close, onNotice }) }) : null,
1869
- editor ? /* @__PURE__ */ jsx7(Dropdown, { trigger: ({ open, toggle }) => /* @__PURE__ */ jsx7(Btn, { label: "Insert table", icon: "table", active: open, disabled: off, onClick: toggle }), children: (close) => /* @__PURE__ */ jsx7(TablePanel, { editor, close }) }) : null
2277
+ editor ? /* @__PURE__ */ jsx8(Dropdown, { trigger: ({ open, toggle }) => /* @__PURE__ */ jsx8(Btn, { label: "Insert image", icon: "image", active: open, disabled: off, onClick: toggle }), children: (close) => /* @__PURE__ */ jsx8(ImagePanel, { editor, close, onNotice }) }) : null,
2278
+ editor ? /* @__PURE__ */ jsx8(Dropdown, { trigger: ({ open, toggle }) => /* @__PURE__ */ jsx8(Btn, { label: "Insert table", icon: "table", active: open, disabled: off, onClick: toggle }), children: (close) => /* @__PURE__ */ jsx8(TablePanel, { editor, close }) }) : null
1870
2279
  ] }),
1871
- /* @__PURE__ */ jsx7(Group, { label: "Actions", children: /* @__PURE__ */ jsx7(Btn, { label: "Clear formatting", icon: "eraser", disabled: off, onClick: () => run()?.unsetAllMarks().clearNodes().run() }) })
2280
+ /* @__PURE__ */ jsx8(Group, { label: "Actions", children: /* @__PURE__ */ jsx8(Btn, { label: "Clear formatting", icon: "eraser", disabled: off, onClick: () => run()?.unsetAllMarks().clearNodes().run() }) })
1872
2281
  ] }) : null,
1873
- s?.inTable ? /* @__PURE__ */ jsx7("div", { className: "june-doc__row june-doc__row--context", children: /* @__PURE__ */ jsxs5(Group, { label: "Table", children: [
1874
- /* @__PURE__ */ jsx7(Btn, { label: "Add row below", disabled: off, onClick: () => run()?.addRowAfter().run(), children: "+ Row" }),
1875
- /* @__PURE__ */ jsx7(Btn, { label: "Add column right", disabled: off, onClick: () => run()?.addColumnAfter().run(), children: "+ Column" }),
1876
- /* @__PURE__ */ jsx7(Btn, { label: "Delete row", disabled: off, onClick: () => run()?.deleteRow().run(), children: "\u2212 Row" }),
1877
- /* @__PURE__ */ jsx7(Btn, { label: "Delete column", disabled: off, onClick: () => run()?.deleteColumn().run(), children: "\u2212 Column" }),
1878
- /* @__PURE__ */ jsx7(Btn, { label: "Merge cells", disabled: off || !s?.canMerge, onClick: () => run()?.mergeCells().run(), children: "Merge" }),
1879
- /* @__PURE__ */ jsx7(Btn, { label: "Split cell", disabled: off || !s?.canSplit, onClick: () => run()?.splitCell().run(), children: "Split" }),
1880
- /* @__PURE__ */ jsx7(Btn, { label: "Toggle header row", disabled: off, onClick: () => run()?.toggleHeaderRow().run(), children: "Header row" }),
1881
- /* @__PURE__ */ jsx7(Btn, { label: "Delete table", disabled: off, onClick: () => run()?.deleteTable().run(), className: "june-doc__btn--danger", children: "Delete table" })
2282
+ s?.inTable ? /* @__PURE__ */ jsx8("div", { className: "june-doc__row june-doc__row--context", children: /* @__PURE__ */ jsxs5(Group, { label: "Table", children: [
2283
+ /* @__PURE__ */ jsx8(Btn, { label: "Add row below", disabled: off, onClick: () => run()?.addRowAfter().run(), children: "+ Row" }),
2284
+ /* @__PURE__ */ jsx8(Btn, { label: "Add column right", disabled: off, onClick: () => run()?.addColumnAfter().run(), children: "+ Column" }),
2285
+ /* @__PURE__ */ jsx8(Btn, { label: "Delete row", disabled: off, onClick: () => run()?.deleteRow().run(), children: "\u2212 Row" }),
2286
+ /* @__PURE__ */ jsx8(Btn, { label: "Delete column", disabled: off, onClick: () => run()?.deleteColumn().run(), children: "\u2212 Column" }),
2287
+ /* @__PURE__ */ jsx8(Btn, { label: "Merge cells", disabled: off || !s?.canMerge, onClick: () => run()?.mergeCells().run(), children: "Merge" }),
2288
+ /* @__PURE__ */ jsx8(Btn, { label: "Split cell", disabled: off || !s?.canSplit, onClick: () => run()?.splitCell().run(), children: "Split" }),
2289
+ /* @__PURE__ */ jsx8(Btn, { label: "Toggle header row", disabled: off, onClick: () => run()?.toggleHeaderRow().run(), children: "Header row" }),
2290
+ /* @__PURE__ */ jsx8(Btn, { label: "Delete table", disabled: off, onClick: () => run()?.deleteTable().run(), className: "june-doc__btn--danger", children: "Delete table" })
1882
2291
  ] }) }) : null
1883
2292
  ] });
1884
2293
  }
1885
2294
 
1886
2295
  // src/components/document-editor/document-bubble.tsx
1887
- import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
2296
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
1888
2297
  function DocumentBubbleMenu({ editor }) {
1889
2298
  const s = useEditorState2({
1890
2299
  editor,
@@ -1913,13 +2322,13 @@ function DocumentBubbleMenu({ editor }) {
1913
2322
  return state.doc.textBetween(state.selection.from, state.selection.to).trim().length > 0;
1914
2323
  },
1915
2324
  children: [
1916
- /* @__PURE__ */ jsx8(Btn, { label: "Bold", icon: "bold", toggle: true, active: s.bold, onClick: () => run().toggleBold().run() }),
1917
- /* @__PURE__ */ jsx8(Btn, { label: "Italic", icon: "italic", toggle: true, active: s.italic, onClick: () => run().toggleItalic().run() }),
1918
- /* @__PURE__ */ jsx8(Btn, { label: "Underline", icon: "underline", toggle: true, active: s.underline, onClick: () => run().toggleUnderline().run() }),
1919
- /* @__PURE__ */ jsx8(Btn, { label: "Strikethrough", icon: "strike", toggle: true, active: s.strike, onClick: () => run().toggleStrike().run() }),
1920
- /* @__PURE__ */ jsx8("span", { className: "june-doc__bubble-sep", "aria-hidden": "true" }),
1921
- /* @__PURE__ */ jsx8(Dropdown, { trigger: ({ open, toggle }) => /* @__PURE__ */ jsx8(Btn, { label: "Link", icon: "link", toggle: true, active: s.link || open, onClick: toggle }), children: (close) => /* @__PURE__ */ jsx8(LinkPanel, { editor, href: s.linkHref, isLink: s.link, close }) }),
1922
- /* @__PURE__ */ jsx8(
2325
+ /* @__PURE__ */ jsx9(Btn, { label: "Bold", icon: "bold", toggle: true, active: s.bold, onClick: () => run().toggleBold().run() }),
2326
+ /* @__PURE__ */ jsx9(Btn, { label: "Italic", icon: "italic", toggle: true, active: s.italic, onClick: () => run().toggleItalic().run() }),
2327
+ /* @__PURE__ */ jsx9(Btn, { label: "Underline", icon: "underline", toggle: true, active: s.underline, onClick: () => run().toggleUnderline().run() }),
2328
+ /* @__PURE__ */ jsx9(Btn, { label: "Strikethrough", icon: "strike", toggle: true, active: s.strike, onClick: () => run().toggleStrike().run() }),
2329
+ /* @__PURE__ */ jsx9("span", { className: "june-doc__bubble-sep", "aria-hidden": "true" }),
2330
+ /* @__PURE__ */ jsx9(Dropdown, { trigger: ({ open, toggle }) => /* @__PURE__ */ jsx9(Btn, { label: "Link", icon: "link", toggle: true, active: s.link || open, onClick: toggle }), children: (close) => /* @__PURE__ */ jsx9(LinkPanel, { editor, href: s.linkHref, isLink: s.link, close }) }),
2331
+ /* @__PURE__ */ jsx9(
1923
2332
  ColorPicker,
1924
2333
  {
1925
2334
  label: "Text color",
@@ -1931,7 +2340,7 @@ function DocumentBubbleMenu({ editor }) {
1931
2340
  onReset: () => run().unsetColor().run()
1932
2341
  }
1933
2342
  ),
1934
- /* @__PURE__ */ jsx8(
2343
+ /* @__PURE__ */ jsx9(
1935
2344
  ColorPicker,
1936
2345
  {
1937
2346
  label: "Highlight",
@@ -1943,8 +2352,8 @@ function DocumentBubbleMenu({ editor }) {
1943
2352
  onReset: () => run().unsetHighlight().run()
1944
2353
  }
1945
2354
  ),
1946
- /* @__PURE__ */ jsx8("span", { className: "june-doc__bubble-sep", "aria-hidden": "true" }),
1947
- /* @__PURE__ */ jsx8(Btn, { label: "Clear formatting", icon: "eraser", onClick: () => run().unsetAllMarks().run() })
2355
+ /* @__PURE__ */ jsx9("span", { className: "june-doc__bubble-sep", "aria-hidden": "true" }),
2356
+ /* @__PURE__ */ jsx9(Btn, { label: "Clear formatting", icon: "eraser", onClick: () => run().unsetAllMarks().run() })
1948
2357
  ]
1949
2358
  }
1950
2359
  );
@@ -1952,60 +2361,116 @@ function DocumentBubbleMenu({ editor }) {
1952
2361
 
1953
2362
  // src/components/document-editor/document-content.tsx
1954
2363
  import { EditorContent } from "@tiptap/react";
1955
- import { useEffect as useEffect3, useRef as useRef5, useState as useState4 } from "react";
1956
- import { jsx as jsx9 } from "react/jsx-runtime";
2364
+ import { useEffect as useEffect4, useLayoutEffect, useRef as useRef5, useState as useState4 } from "react";
2365
+ import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
2366
+ var PAGE_WIDTH = 794;
1957
2367
  var PAGE_HEIGHT = 1123;
1958
- var PAGE_PAD_Y = 96;
2368
+ var PAGE_GAP = 28;
2369
+ var CANVAS_PAD_X = 24;
2370
+ var useIsoLayoutEffect = typeof window === "undefined" ? useEffect4 : useLayoutEffect;
2371
+ function geometry(width) {
2372
+ const ratio = width / PAGE_WIDTH;
2373
+ const height = Math.round(PAGE_HEIGHT * ratio);
2374
+ const padX = Math.round(Math.min(96, Math.max(20, width * 0.12)));
2375
+ const padY = Math.round(Math.min(96, Math.max(36, 96 * ratio)));
2376
+ return { width, height, padX, padY };
2377
+ }
1959
2378
  function DocumentContent({ editor, layout = "page", zoom = 1, showMarks = false, onMetrics }) {
1960
2379
  const canvas = useRef5(null);
1961
2380
  const sheet = useRef5(null);
2381
+ const [avail, setAvail] = useState4(PAGE_WIDTH);
2382
+ const [sheetH, setSheetH] = useState4(0);
1962
2383
  const [pages, setPages] = useState4(1);
1963
2384
  const metricsRef = useRef5(onMetrics);
1964
2385
  metricsRef.current = onMetrics;
1965
2386
  const last = useRef5({ page: 0, pages: 0 });
1966
- useEffect3(() => {
2387
+ const paged = layout === "page";
2388
+ const width = paged ? Math.max(260, Math.min(PAGE_WIDTH, Math.floor(avail / zoom))) : Math.max(260, Math.floor(avail / zoom));
2389
+ const g = geometry(width);
2390
+ const stride = g.height + PAGE_GAP;
2391
+ useIsoLayoutEffect(() => {
1967
2392
  const c = canvas.current;
1968
- const p = sheet.current;
1969
- const prose = editor?.view.dom;
1970
- if (!c || !p || !prose) return;
1971
- const measure = () => {
1972
- const contentH = prose.getBoundingClientRect().height / zoom;
1973
- const total = layout === "page" ? Math.max(1, Math.ceil((contentH + PAGE_PAD_Y * 2) / PAGE_HEIGHT)) : 1;
1974
- const cRect = c.getBoundingClientRect();
1975
- const pRect = p.getBoundingClientRect();
1976
- const y = cRect.top + c.clientHeight * 0.35 - pRect.top;
1977
- const page = Math.min(total, Math.max(1, Math.floor(y / (PAGE_HEIGHT * zoom)) + 1));
2393
+ if (!c) return;
2394
+ const read = () => {
2395
+ const cs = typeof getComputedStyle === "function" ? getComputedStyle(c) : null;
2396
+ const padX = cs ? (parseFloat(cs.paddingLeft) || 0) + (parseFloat(cs.paddingRight) || 0) : CANVAS_PAD_X * 2;
2397
+ const w = c.clientWidth - padX;
2398
+ if (w > 0) setAvail(w);
2399
+ };
2400
+ read();
2401
+ if (typeof ResizeObserver === "undefined") return;
2402
+ const ro = new ResizeObserver(read);
2403
+ ro.observe(c);
2404
+ return () => ro.disconnect();
2405
+ }, []);
2406
+ useEffect4(() => {
2407
+ if (!editor) return;
2408
+ setPaginationConfig(editor, {
2409
+ enabled: paged,
2410
+ pageHeight: g.height,
2411
+ gap: PAGE_GAP,
2412
+ padTop: g.padY,
2413
+ padBottom: g.padY
2414
+ });
2415
+ }, [editor, paged, g.height, g.padY, width]);
2416
+ useEffect4(() => {
2417
+ const c = canvas.current;
2418
+ const s = sheet.current;
2419
+ if (!editor || !c || !s) return;
2420
+ const prose = editor.view.dom;
2421
+ const report = () => {
2422
+ const total = paged ? getPageCount(editor) : 1;
1978
2423
  setPages(total);
2424
+ setSheetH(s.offsetHeight);
2425
+ const cRect = c.getBoundingClientRect();
2426
+ const sRect = s.getBoundingClientRect();
2427
+ const y = (cRect.top + c.clientHeight * 0.35 - sRect.top) / zoom;
2428
+ const page = paged ? Math.min(total, Math.max(1, Math.floor(y / stride) + 1)) : 1;
1979
2429
  if (last.current.page !== page || last.current.pages !== total) {
1980
2430
  last.current = { page, pages: total };
1981
2431
  metricsRef.current?.({ page, pages: total });
1982
2432
  }
1983
2433
  };
1984
- measure();
1985
- c.addEventListener("scroll", measure, { passive: true });
1986
- const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(measure) : null;
1987
- ro?.observe(prose);
1988
- ro?.observe(c);
1989
- editor?.on("update", measure);
2434
+ report();
2435
+ editor.on("transaction", report);
2436
+ c.addEventListener("scroll", report, { passive: true });
2437
+ const onLoad = () => remeasurePagination(editor);
2438
+ prose.addEventListener("load", onLoad, true);
2439
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(report) : null;
2440
+ ro?.observe(s);
1990
2441
  return () => {
1991
- c.removeEventListener("scroll", measure);
2442
+ editor.off("transaction", report);
2443
+ c.removeEventListener("scroll", report);
2444
+ prose.removeEventListener("load", onLoad, true);
1992
2445
  ro?.disconnect();
1993
- editor?.off("update", measure);
1994
2446
  };
1995
- }, [editor, layout, zoom]);
1996
- const sheetStyle = layout === "page" ? {
1997
- zoom,
1998
- minHeight: pages * PAGE_HEIGHT,
1999
- maxWidth: `calc(100% / ${zoom})`,
2000
- "--jd-page-h": `${PAGE_HEIGHT}px`
2001
- } : { zoom };
2002
- return /* @__PURE__ */ jsx9("div", { ref: canvas, className: "june-doc__content june-doc__canvas", "data-layout": layout, "data-marks": showMarks || void 0, children: /* @__PURE__ */ jsx9("div", { ref: sheet, className: "june-doc__sheet", style: sheetStyle, children: /* @__PURE__ */ jsx9(EditorContent, { editor }) }) });
2447
+ }, [editor, paged, zoom, stride]);
2448
+ const minHeight = paged ? pages * g.height + (pages - 1) * PAGE_GAP : void 0;
2449
+ const sheetStyle = {
2450
+ width,
2451
+ minHeight,
2452
+ transform: zoom === 1 ? void 0 : `scale(${zoom})`,
2453
+ "--jd-pad-x": `${g.padX}px`,
2454
+ "--jd-pad-y": `${g.padY}px`
2455
+ };
2456
+ const zoomerStyle = {
2457
+ width: width * zoom,
2458
+ height: zoom === 1 ? void 0 : Math.max(sheetH, minHeight ?? 0) * zoom
2459
+ };
2460
+ return /* @__PURE__ */ jsx10("div", { ref: canvas, className: "june-doc__content june-doc__canvas", "data-layout": layout, "data-marks": showMarks || void 0, children: /* @__PURE__ */ jsx10("div", { className: "june-doc__zoomer", style: zoomerStyle, children: /* @__PURE__ */ jsxs7("div", { ref: sheet, className: "june-doc__sheet", style: sheetStyle, children: [
2461
+ paged ? /* @__PURE__ */ jsx10("div", { className: "june-doc__pages", "aria-hidden": "true", children: Array.from({ length: pages }, (_, i) => /* @__PURE__ */ jsx10("div", { className: "june-doc__page", style: { top: i * stride, height: g.height }, children: /* @__PURE__ */ jsxs7("span", { className: "june-doc__page-num", children: [
2462
+ i + 1,
2463
+ " / ",
2464
+ pages
2465
+ ] }) }, i)) }) : null,
2466
+ /* @__PURE__ */ jsx10(EditorContent, { editor })
2467
+ ] }) }) });
2003
2468
  }
2004
2469
 
2005
2470
  // src/components/document-editor/document-findbar.tsx
2006
2471
  import { useEditorState as useEditorState3 } from "@tiptap/react";
2007
- import { useEffect as useEffect4, useRef as useRef6, useState as useState5 } from "react";
2008
- import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
2472
+ import { useEffect as useEffect5, useRef as useRef6, useState as useState5 } from "react";
2473
+ import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
2009
2474
  function DocumentFindBar({ editor, editable, onClose, onNotice }) {
2010
2475
  const [term, setTerm] = useState5(() => {
2011
2476
  const { from, to, empty } = editor.state.selection;
@@ -2021,19 +2486,19 @@ function DocumentFindBar({ editor, editable, onClose, onNotice }) {
2021
2486
  return { count: s?.matches.length ?? 0, current: s?.current ?? -1 };
2022
2487
  }
2023
2488
  });
2024
- useEffect4(() => {
2489
+ useEffect5(() => {
2025
2490
  input.current?.focus();
2026
2491
  input.current?.select();
2027
2492
  }, []);
2028
- useEffect4(() => {
2493
+ useEffect5(() => {
2029
2494
  setSearch(editor, { term, caseSensitive, current: 0 });
2030
2495
  }, [editor, term, caseSensitive]);
2031
- useEffect4(() => () => {
2496
+ useEffect5(() => () => {
2032
2497
  if (!editor.isDestroyed) setSearch(editor, { term: "" });
2033
2498
  }, [editor]);
2034
2499
  const count = info?.count ?? 0;
2035
2500
  const current = info?.current ?? -1;
2036
- return /* @__PURE__ */ jsxs7(
2501
+ return /* @__PURE__ */ jsxs8(
2037
2502
  "div",
2038
2503
  {
2039
2504
  className: "june-doc__findbar",
@@ -2046,9 +2511,9 @@ function DocumentFindBar({ editor, editable, onClose, onNotice }) {
2046
2511
  }
2047
2512
  },
2048
2513
  children: [
2049
- /* @__PURE__ */ jsxs7("div", { className: "june-doc__find-field", children: [
2050
- /* @__PURE__ */ jsx10(Icon, { name: "search", size: 14 }),
2051
- /* @__PURE__ */ jsx10(
2514
+ /* @__PURE__ */ jsxs8("div", { className: "june-doc__find-field", children: [
2515
+ /* @__PURE__ */ jsx11(Icon, { name: "search", size: 14 }),
2516
+ /* @__PURE__ */ jsx11(
2052
2517
  "input",
2053
2518
  {
2054
2519
  ref: input,
@@ -2065,11 +2530,11 @@ function DocumentFindBar({ editor, editable, onClose, onNotice }) {
2065
2530
  }
2066
2531
  }
2067
2532
  ),
2068
- /* @__PURE__ */ jsx10("span", { className: "june-doc__find-count", "aria-live": "polite", children: term ? count ? `${current + 1} of ${count}` : "No results" : "" })
2533
+ /* @__PURE__ */ jsx11("span", { className: "june-doc__find-count", "aria-live": "polite", children: term ? count ? `${current + 1} of ${count}` : "No results" : "" })
2069
2534
  ] }),
2070
- /* @__PURE__ */ jsx10("button", { type: "button", className: "june-doc__btn june-doc__btn--icon", "aria-label": "Previous match", title: "Previous (Shift+Enter)", disabled: !count, onClick: () => gotoMatch(editor, -1), children: /* @__PURE__ */ jsx10(Icon, { name: "chevronUp" }) }),
2071
- /* @__PURE__ */ jsx10("button", { type: "button", className: "june-doc__btn june-doc__btn--icon", "aria-label": "Next match", title: "Next (Enter)", disabled: !count, onClick: () => gotoMatch(editor, 1), children: /* @__PURE__ */ jsx10(Icon, { name: "chevronDown" }) }),
2072
- /* @__PURE__ */ jsx10(
2535
+ /* @__PURE__ */ jsx11("button", { type: "button", className: "june-doc__btn june-doc__btn--icon", "aria-label": "Previous match", title: "Previous (Shift+Enter)", disabled: !count, onClick: () => gotoMatch(editor, -1), children: /* @__PURE__ */ jsx11(Icon, { name: "chevronUp" }) }),
2536
+ /* @__PURE__ */ jsx11("button", { type: "button", className: "june-doc__btn june-doc__btn--icon", "aria-label": "Next match", title: "Next (Enter)", disabled: !count, onClick: () => gotoMatch(editor, 1), children: /* @__PURE__ */ jsx11(Icon, { name: "chevronDown" }) }),
2537
+ /* @__PURE__ */ jsx11(
2073
2538
  "button",
2074
2539
  {
2075
2540
  type: "button",
@@ -2082,9 +2547,9 @@ function DocumentFindBar({ editor, editable, onClose, onNotice }) {
2082
2547
  children: "Aa"
2083
2548
  }
2084
2549
  ),
2085
- editable ? /* @__PURE__ */ jsxs7(Fragment3, { children: [
2086
- /* @__PURE__ */ jsx10("span", { className: "june-doc__find-sep", "aria-hidden": "true" }),
2087
- /* @__PURE__ */ jsx10(
2550
+ editable ? /* @__PURE__ */ jsxs8(Fragment3, { children: [
2551
+ /* @__PURE__ */ jsx11("span", { className: "june-doc__find-sep", "aria-hidden": "true" }),
2552
+ /* @__PURE__ */ jsx11(
2088
2553
  "input",
2089
2554
  {
2090
2555
  className: "june-doc__input june-doc__replace-input",
@@ -2100,8 +2565,8 @@ function DocumentFindBar({ editor, editable, onClose, onNotice }) {
2100
2565
  }
2101
2566
  }
2102
2567
  ),
2103
- /* @__PURE__ */ jsx10("button", { type: "button", className: "june-doc__btn", disabled: !count, onClick: () => replaceCurrent(editor, replacement), children: "Replace" }),
2104
- /* @__PURE__ */ jsx10(
2568
+ /* @__PURE__ */ jsx11("button", { type: "button", className: "june-doc__btn", disabled: !count, onClick: () => replaceCurrent(editor, replacement), children: "Replace" }),
2569
+ /* @__PURE__ */ jsx11(
2105
2570
  "button",
2106
2571
  {
2107
2572
  type: "button",
@@ -2115,16 +2580,16 @@ function DocumentFindBar({ editor, editable, onClose, onNotice }) {
2115
2580
  }
2116
2581
  )
2117
2582
  ] }) : null,
2118
- /* @__PURE__ */ jsx10("button", { type: "button", className: "june-doc__btn june-doc__btn--icon june-doc__btn--ghost june-doc__find-close", "aria-label": "Close find", onClick: onClose, children: /* @__PURE__ */ jsx10(Icon, { name: "close" }) })
2583
+ /* @__PURE__ */ jsx11("button", { type: "button", className: "june-doc__btn june-doc__btn--icon june-doc__btn--ghost june-doc__find-close", "aria-label": "Close find", onClick: onClose, children: /* @__PURE__ */ jsx11(Icon, { name: "close" }) })
2119
2584
  ]
2120
2585
  }
2121
2586
  );
2122
2587
  }
2123
2588
 
2124
2589
  // src/components/document-editor/document-title.tsx
2125
- import { jsx as jsx11 } from "react/jsx-runtime";
2590
+ import { jsx as jsx12 } from "react/jsx-runtime";
2126
2591
  function DocumentTitle({ value, disabled, onChange }) {
2127
- return /* @__PURE__ */ jsx11(
2592
+ return /* @__PURE__ */ jsx12(
2128
2593
  "input",
2129
2594
  {
2130
2595
  className: "june-doc__title",
@@ -2138,7 +2603,7 @@ function DocumentTitle({ value, disabled, onChange }) {
2138
2603
  }
2139
2604
 
2140
2605
  // src/components/document-editor/document-header.tsx
2141
- import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
2606
+ import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
2142
2607
  var FORMATS = {
2143
2608
  docx: { label: "Word document", hint: ".docx", icon: "file" },
2144
2609
  pdf: { label: "PDF", hint: "Print / Save as PDF", icon: "file" },
@@ -2147,36 +2612,37 @@ var FORMATS = {
2147
2612
  txt: { label: "Plain text", hint: ".txt", icon: "file" }
2148
2613
  };
2149
2614
  function DocumentHeader(props) {
2150
- const { title, editable, isDraft, fullscreen, onToggleFullscreen, onTitle, exportFormats, canSave, saveState, onExport, onCopy, onSave } = props;
2151
- return /* @__PURE__ */ jsxs8("div", { className: "june-doc__header", children: [
2152
- fullscreen ? /* @__PURE__ */ jsx12("button", { type: "button", className: "june-doc__btn june-doc__btn--icon june-doc__btn--ghost", "aria-label": "Close full screen", title: "Close (Esc)", onClick: onToggleFullscreen, children: /* @__PURE__ */ jsx12(Icon, { name: "close", size: 18 }) }) : /* @__PURE__ */ jsx12("span", { className: "june-doc__doc-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx12(Icon, { name: "file", size: 16 }) }),
2153
- /* @__PURE__ */ jsx12(DocumentTitle, { value: title, disabled: !editable, onChange: onTitle }),
2154
- isDraft ? /* @__PURE__ */ jsxs8("span", { className: "june-doc__badge", children: [
2155
- /* @__PURE__ */ jsx12(Icon, { name: "sparkles", size: 12 }),
2615
+ const { title, editable, isDraft, fullscreen, onToggleFullscreen, onTitle, exportFormats, canSave, showSave = canSave, saveState, onExport, onCopy, onSave } = props;
2616
+ return /* @__PURE__ */ jsxs9("div", { className: "june-doc__header", children: [
2617
+ fullscreen ? /* @__PURE__ */ jsx13("button", { type: "button", className: "june-doc__btn june-doc__btn--icon june-doc__btn--ghost", "aria-label": "Close full screen", title: "Close (Esc)", onClick: onToggleFullscreen, children: /* @__PURE__ */ jsx13(Icon, { name: "close", size: 18 }) }) : /* @__PURE__ */ jsx13("span", { className: "june-doc__doc-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx13(Icon, { name: "file", size: 16 }) }),
2618
+ /* @__PURE__ */ jsx13(DocumentTitle, { value: title, disabled: !editable, onChange: onTitle }),
2619
+ isDraft ? /* @__PURE__ */ jsxs9("span", { className: "june-doc__badge", children: [
2620
+ /* @__PURE__ */ jsx13(Icon, { name: "sparkles", size: 12 }),
2156
2621
  "AI draft"
2157
2622
  ] }) : null,
2158
- /* @__PURE__ */ jsxs8("div", { className: "june-doc__header-actions", children: [
2159
- canSave ? /* @__PURE__ */ jsxs8(
2623
+ /* @__PURE__ */ jsxs9("div", { className: "june-doc__header-actions", children: [
2624
+ showSave ? /* @__PURE__ */ jsxs9(
2160
2625
  "button",
2161
2626
  {
2162
2627
  type: "button",
2163
- className: "june-doc__btn june-doc__btn--outline",
2628
+ className: "june-doc__btn june-doc__btn--outline june-doc__save",
2629
+ "data-state": saveState,
2164
2630
  "aria-label": "Save",
2165
2631
  title: "Save (Ctrl+S)",
2166
2632
  disabled: saveState === "saving" || saveState === "saved" || saveState === "idle",
2167
2633
  onClick: onSave,
2168
2634
  children: [
2169
- /* @__PURE__ */ jsx12(Icon, { name: saveState === "saved" ? "check" : "save" }),
2170
- /* @__PURE__ */ jsx12("span", { children: saveState === "saving" ? "Saving\u2026" : saveState === "saved" ? "Saved" : "Save" })
2635
+ /* @__PURE__ */ jsx13(Icon, { name: saveState === "saved" ? "check" : "save" }),
2636
+ /* @__PURE__ */ jsx13("span", { children: saveState === "saving" ? "Saving\u2026" : saveState === "saved" ? "Saved" : "Save" })
2171
2637
  ]
2172
2638
  }
2173
2639
  ) : null,
2174
- /* @__PURE__ */ jsx12(
2640
+ /* @__PURE__ */ jsx13(
2175
2641
  Dropdown,
2176
2642
  {
2177
2643
  align: "end",
2178
2644
  className: "june-doc__menu",
2179
- trigger: ({ open, toggle }) => /* @__PURE__ */ jsxs8(
2645
+ trigger: ({ open, toggle }) => /* @__PURE__ */ jsxs9(
2180
2646
  "button",
2181
2647
  {
2182
2648
  type: "button",
@@ -2186,15 +2652,15 @@ function DocumentHeader(props) {
2186
2652
  "aria-expanded": open,
2187
2653
  onClick: toggle,
2188
2654
  children: [
2189
- /* @__PURE__ */ jsx12("span", { children: "Download" }),
2190
- /* @__PURE__ */ jsx12(Icon, { name: "chevronDown", size: 14 })
2655
+ /* @__PURE__ */ jsx13("span", { children: "Download" }),
2656
+ /* @__PURE__ */ jsx13(Icon, { name: "chevronDown", size: 14 })
2191
2657
  ]
2192
2658
  }
2193
2659
  ),
2194
- children: (close) => /* @__PURE__ */ jsxs8("div", { role: "menu", "aria-label": "Download options", children: [
2660
+ children: (close) => /* @__PURE__ */ jsxs9("div", { role: "menu", "aria-label": "Download options", children: [
2195
2661
  exportFormats.map((f) => {
2196
2662
  const meta = FORMATS[f] ?? { label: f.toUpperCase(), hint: "", icon: "file" };
2197
- return /* @__PURE__ */ jsxs8(
2663
+ return /* @__PURE__ */ jsxs9(
2198
2664
  "button",
2199
2665
  {
2200
2666
  type: "button",
@@ -2205,16 +2671,16 @@ function DocumentHeader(props) {
2205
2671
  onExport(f);
2206
2672
  },
2207
2673
  children: [
2208
- /* @__PURE__ */ jsx12(Icon, { name: meta.icon }),
2209
- /* @__PURE__ */ jsx12("span", { className: "june-doc__menu-label", children: meta.label }),
2210
- /* @__PURE__ */ jsx12("span", { className: "june-doc__menu-hint", children: meta.hint })
2674
+ /* @__PURE__ */ jsx13(Icon, { name: meta.icon }),
2675
+ /* @__PURE__ */ jsx13("span", { className: "june-doc__menu-label", children: meta.label }),
2676
+ /* @__PURE__ */ jsx13("span", { className: "june-doc__menu-hint", children: meta.hint })
2211
2677
  ]
2212
2678
  },
2213
2679
  f
2214
2680
  );
2215
2681
  }),
2216
- exportFormats.length ? /* @__PURE__ */ jsx12("div", { className: "june-doc__menu-sep", role: "separator" }) : null,
2217
- /* @__PURE__ */ jsxs8(
2682
+ exportFormats.length ? /* @__PURE__ */ jsx13("div", { className: "june-doc__menu-sep", role: "separator" }) : null,
2683
+ /* @__PURE__ */ jsxs9(
2218
2684
  "button",
2219
2685
  {
2220
2686
  type: "button",
@@ -2226,15 +2692,15 @@ function DocumentHeader(props) {
2226
2692
  onCopy();
2227
2693
  },
2228
2694
  children: [
2229
- /* @__PURE__ */ jsx12(Icon, { name: "copy" }),
2230
- /* @__PURE__ */ jsx12("span", { className: "june-doc__menu-label", children: "Copy to clipboard" })
2695
+ /* @__PURE__ */ jsx13(Icon, { name: "copy" }),
2696
+ /* @__PURE__ */ jsx13("span", { className: "june-doc__menu-label", children: "Copy to clipboard" })
2231
2697
  ]
2232
2698
  }
2233
2699
  )
2234
2700
  ] })
2235
2701
  }
2236
2702
  ),
2237
- /* @__PURE__ */ jsx12(
2703
+ /* @__PURE__ */ jsx13(
2238
2704
  "button",
2239
2705
  {
2240
2706
  type: "button",
@@ -2243,7 +2709,7 @@ function DocumentHeader(props) {
2243
2709
  title: fullscreen ? "Exit full screen" : "Open full screen",
2244
2710
  "aria-pressed": fullscreen,
2245
2711
  onClick: onToggleFullscreen,
2246
- children: /* @__PURE__ */ jsx12(Icon, { name: "maximize" })
2712
+ children: /* @__PURE__ */ jsx13(Icon, { name: "maximize" })
2247
2713
  }
2248
2714
  )
2249
2715
  ] })
@@ -2265,7 +2731,7 @@ var textResult = (text, filename, mimeType) => ({
2265
2731
  blob: new Blob([text], { type: `${mimeType};charset=utf-8` })
2266
2732
  });
2267
2733
  var exportHtml = async (ctx) => {
2268
- const { docToHtml: docToHtml2 } = await import("./document-engine-IAY2T6B3.js");
2734
+ const { docToHtml: docToHtml2 } = await import("./document-engine-RKD5SLXR.js");
2269
2735
  return textResult(
2270
2736
  buildHtmlDocument(ctx.title, docToHtml2(ctx.json)),
2271
2737
  `${ctx.basename}.html`,
@@ -2273,7 +2739,7 @@ var exportHtml = async (ctx) => {
2273
2739
  );
2274
2740
  };
2275
2741
  var exportMarkdown = async (ctx) => {
2276
- const { docToMarkdown: docToMarkdown2 } = await import("./document-engine-IAY2T6B3.js");
2742
+ const { docToMarkdown: docToMarkdown2 } = await import("./document-engine-RKD5SLXR.js");
2277
2743
  return textResult(
2278
2744
  `# ${ctx.title}
2279
2745
 
@@ -2284,7 +2750,7 @@ ${docToMarkdown2(ctx.json)}
2284
2750
  );
2285
2751
  };
2286
2752
  var exportTxt = async (ctx) => {
2287
- const { docToText } = await import("./document-engine-IAY2T6B3.js");
2753
+ const { docToText } = await import("./document-engine-RKD5SLXR.js");
2288
2754
  return textResult(`${ctx.title}
2289
2755
 
2290
2756
  ${docToText(ctx.json)}
@@ -2606,7 +3072,7 @@ function printHtml(html) {
2606
3072
  });
2607
3073
  }
2608
3074
  var exportPdf = async (ctx) => {
2609
- const { docToHtml: docToHtml2 } = await import("./document-engine-IAY2T6B3.js");
3075
+ const { docToHtml: docToHtml2 } = await import("./document-engine-RKD5SLXR.js");
2610
3076
  await printHtml(buildHtmlDocument(ctx.title, docToHtml2(ctx.json)));
2611
3077
  return { filename: `${ctx.basename}.pdf`, mimeType: "application/pdf", handled: true };
2612
3078
  };
@@ -2644,7 +3110,7 @@ function downloadResult(result) {
2644
3110
  setTimeout(() => URL.revokeObjectURL(url), 1e3);
2645
3111
  }
2646
3112
  async function copyDocumentToClipboard(doc) {
2647
- const { docToHtml: docToHtml2, docToText } = await import("./document-engine-IAY2T6B3.js");
3113
+ const { docToHtml: docToHtml2, docToText } = await import("./document-engine-RKD5SLXR.js");
2648
3114
  const html = docToHtml2(doc.json);
2649
3115
  const text = `${doc.title}
2650
3116
 
@@ -2666,221 +3132,6 @@ ${docToText(doc.json)}`;
2666
3132
  }
2667
3133
  }
2668
3134
 
2669
- // src/components/document-editor/document-merge.ts
2670
- var MAX_CELLS = 4e6;
2671
- function matchIndices(a, b) {
2672
- const n = a.length;
2673
- const m = b.length;
2674
- if (n * m > MAX_CELLS) return null;
2675
- const dp = Array.from({ length: n + 1 }, () => new Uint32Array(m + 1));
2676
- for (let i2 = n - 1; i2 >= 0; i2--) {
2677
- for (let j2 = m - 1; j2 >= 0; j2--) {
2678
- dp[i2][j2] = a[i2] === b[j2] ? dp[i2 + 1][j2 + 1] + 1 : Math.max(dp[i2 + 1][j2], dp[i2][j2 + 1]);
2679
- }
2680
- }
2681
- const matches = /* @__PURE__ */ new Map();
2682
- let i = 0;
2683
- let j = 0;
2684
- while (i < n && j < m) {
2685
- if (a[i] === b[j]) {
2686
- matches.set(i, j);
2687
- i++;
2688
- j++;
2689
- } else if (dp[i + 1][j] >= dp[i][j + 1]) i++;
2690
- else j++;
2691
- }
2692
- return matches;
2693
- }
2694
- var same = (x, y) => x.length === y.length && x.every((v, i) => v === y[i]);
2695
- function mergeBlocks(base, local, incoming) {
2696
- if (same(local, base)) return { blocks: incoming, conflicts: 0 };
2697
- if (same(incoming, base) || same(local, incoming)) return { blocks: local, conflicts: 0 };
2698
- const ml = matchIndices(base, local);
2699
- const mn = matchIndices(base, incoming);
2700
- if (!ml || !mn) return { blocks: null, conflicts: 1 };
2701
- const anchors = [...ml.keys()].filter((i) => mn.has(i)).sort((x, y) => x - y);
2702
- const out = [];
2703
- let conflicts = 0;
2704
- let pb = -1;
2705
- let pl = -1;
2706
- let pn = -1;
2707
- const region = (bEnd, lEnd, nEnd) => {
2708
- const B = base.slice(pb + 1, bEnd);
2709
- const L = local.slice(pl + 1, lEnd);
2710
- const N = incoming.slice(pn + 1, nEnd);
2711
- if (B.length === L.length && L.length === N.length) {
2712
- for (let k = 0; k < B.length; k++) {
2713
- if (L[k] === B[k]) out.push(N[k]);
2714
- else if (N[k] === B[k] || N[k] === L[k]) out.push(L[k]);
2715
- else {
2716
- conflicts++;
2717
- out.push(L[k]);
2718
- }
2719
- }
2720
- return;
2721
- }
2722
- if (same(L, B)) out.push(...N);
2723
- else if (same(N, B) || same(L, N)) out.push(...L);
2724
- else {
2725
- conflicts++;
2726
- out.push(...L);
2727
- }
2728
- };
2729
- for (const a of anchors) {
2730
- const la = ml.get(a);
2731
- const na = mn.get(a);
2732
- region(a, la, na);
2733
- out.push(local[la]);
2734
- pb = a;
2735
- pl = la;
2736
- pn = na;
2737
- }
2738
- region(base.length, local.length, incoming.length);
2739
- return { blocks: out, conflicts };
2740
- }
2741
- function mergeDocuments(base, local, incoming) {
2742
- const toBlocks = (d) => (d.content ?? []).map((node) => JSON.stringify(node));
2743
- const { blocks: blocks2, conflicts } = mergeBlocks(toBlocks(base), toBlocks(local), toBlocks(incoming));
2744
- if (!blocks2) return { doc: local, conflicts: Math.max(1, conflicts) };
2745
- if (blocks2.length === 0) return { doc: emptyDoc(), conflicts };
2746
- return { doc: { type: "doc", content: blocks2.map((b) => JSON.parse(b)) }, conflicts };
2747
- }
2748
-
2749
- // src/components/document-editor/document-store.ts
2750
- var incomingKey = (doc) => JSON.stringify([doc.title, docKey(doc.json)]);
2751
- function createDocumentStore() {
2752
- const records = /* @__PURE__ */ new Map();
2753
- const listeners = /* @__PURE__ */ new Set();
2754
- const emit = () => listeners.forEach((listener) => listener());
2755
- const put = (record) => {
2756
- records.set(record.id, record);
2757
- emit();
2758
- };
2759
- const fresh2 = (doc) => ({
2760
- id: doc.id,
2761
- title: doc.title,
2762
- documentType: doc.documentType,
2763
- status: doc.status,
2764
- json: doc.json,
2765
- baseJson: doc.json,
2766
- baseTitle: doc.title,
2767
- lastIncomingKey: incomingKey(doc),
2768
- revision: 0,
2769
- origin: "external",
2770
- pending: null,
2771
- updatedAt: Date.now()
2772
- });
2773
- return {
2774
- get: (id) => records.get(id),
2775
- list: () => [...records.values()],
2776
- subscribe: (listener) => {
2777
- listeners.add(listener);
2778
- return () => {
2779
- listeners.delete(listener);
2780
- };
2781
- },
2782
- receive(incoming) {
2783
- const current = records.get(incoming.id);
2784
- if (!current) {
2785
- put(fresh2(incoming));
2786
- return "created";
2787
- }
2788
- const key = incomingKey(incoming);
2789
- if (current.lastIncomingKey === key) return "unchanged";
2790
- const userEditedBody = docKey(current.json) !== docKey(current.baseJson);
2791
- const userEditedTitle = current.title !== current.baseTitle;
2792
- const title = userEditedTitle ? current.title : incoming.title;
2793
- const meta = {
2794
- documentType: incoming.documentType ?? current.documentType,
2795
- status: incoming.status ?? current.status
2796
- };
2797
- if (!userEditedBody) {
2798
- put({
2799
- ...current,
2800
- ...meta,
2801
- title,
2802
- baseTitle: incoming.title,
2803
- json: incoming.json,
2804
- baseJson: incoming.json,
2805
- lastIncomingKey: key,
2806
- revision: current.revision + 1,
2807
- origin: "external",
2808
- pending: null,
2809
- updatedAt: Date.now()
2810
- });
2811
- return "applied";
2812
- }
2813
- const { doc, conflicts } = mergeDocuments(current.baseJson, current.json, incoming.json);
2814
- if (conflicts === 0) {
2815
- put({
2816
- ...current,
2817
- ...meta,
2818
- title,
2819
- baseTitle: incoming.title,
2820
- json: doc,
2821
- baseJson: incoming.json,
2822
- lastIncomingKey: key,
2823
- revision: current.revision + 1,
2824
- origin: "external",
2825
- pending: null,
2826
- updatedAt: Date.now()
2827
- });
2828
- return "merged";
2829
- }
2830
- put({
2831
- ...current,
2832
- ...meta,
2833
- lastIncomingKey: key,
2834
- pending: { json: incoming.json, title: incoming.title, merged: doc, conflicts }
2835
- });
2836
- return "conflict";
2837
- },
2838
- hydrate(doc) {
2839
- put(fresh2(doc));
2840
- },
2841
- edit(id, json, origin) {
2842
- const current = records.get(id);
2843
- if (!current || docKey(current.json) === docKey(json)) return;
2844
- put({ ...current, json, origin, revision: current.revision + 1, updatedAt: Date.now() });
2845
- },
2846
- setTitle(id, title) {
2847
- const current = records.get(id);
2848
- if (!current || current.title === title) return;
2849
- put({ ...current, title, updatedAt: Date.now() });
2850
- },
2851
- resolve(id, choice) {
2852
- const current = records.get(id);
2853
- const pending = current?.pending;
2854
- if (!current || !pending) return;
2855
- if (choice === "keep") {
2856
- put({ ...current, baseJson: pending.json, baseTitle: pending.title, pending: null });
2857
- return;
2858
- }
2859
- const json = choice === "merge" ? pending.merged : pending.json;
2860
- const title = choice === "merge" ? current.title : pending.title;
2861
- put({
2862
- ...current,
2863
- title,
2864
- json,
2865
- baseJson: pending.json,
2866
- baseTitle: pending.title,
2867
- revision: current.revision + 1,
2868
- origin: "external",
2869
- pending: null,
2870
- updatedAt: Date.now()
2871
- });
2872
- },
2873
- remove(id) {
2874
- if (records.delete(id)) emit();
2875
- }
2876
- };
2877
- }
2878
- var defaultStore = null;
2879
- function getDefaultDocumentStore() {
2880
- if (!defaultStore) defaultStore = createDocumentStore();
2881
- return defaultStore;
2882
- }
2883
-
2884
3135
  // src/components/document-editor/document-types.ts
2885
3136
  var ALL_EXPORT_FORMATS = [
2886
3137
  "html",
@@ -2891,7 +3142,7 @@ var ALL_EXPORT_FORMATS = [
2891
3142
  ];
2892
3143
 
2893
3144
  // src/components/document-editor/document-editor.tsx
2894
- import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
3145
+ import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
2895
3146
  var snapshotOf = (r) => ({
2896
3147
  documentId: r.id,
2897
3148
  title: r.title,
@@ -2937,7 +3188,7 @@ function DocumentEditorImpl(props) {
2937
3188
  return { json: null, error: toJuneError(e, "DOCUMENT_ERROR") };
2938
3189
  }
2939
3190
  }, [contentKey]);
2940
- useEffect5(() => {
3191
+ useEffect6(() => {
2941
3192
  if (parsed.error) optionsRef.current.onError?.(parsed.error);
2942
3193
  }, [parsed.error]);
2943
3194
  const title = useDocumentValue(store, documentId, (r) => r?.title ?? titleProp);
@@ -2953,7 +3204,7 @@ function DocumentEditorImpl(props) {
2953
3204
  const [findOpen, setFindOpen] = useState6(false);
2954
3205
  const [zoom, setZoom] = useState6(1);
2955
3206
  const [metrics, setMetrics] = useState6({ page: 1, pages: 1 });
2956
- useEffect5(() => {
3207
+ useEffect6(() => {
2957
3208
  if (!fullscreen || typeof document === "undefined") return;
2958
3209
  const prev = document.body.style.overflow;
2959
3210
  document.body.style.overflow = "hidden";
@@ -2967,7 +3218,7 @@ function DocumentEditorImpl(props) {
2967
3218
  const flash = useCallback3((message) => {
2968
3219
  setNotice(message);
2969
3220
  }, []);
2970
- useEffect5(() => {
3221
+ useEffect6(() => {
2971
3222
  if (!notice) return;
2972
3223
  const t = setTimeout(() => setNotice(null), 3e3);
2973
3224
  return () => clearTimeout(t);
@@ -2985,12 +3236,17 @@ function DocumentEditorImpl(props) {
2985
3236
  const delay = options.autosaveDelay ?? 1500;
2986
3237
  return delay > 0 ? debounce(() => void saveRef.current(), delay) : null;
2987
3238
  }, [options.autosaveDelay]);
2988
- useEffect5(() => () => autosave?.flush(), [autosave]);
3239
+ useEffect6(() => () => autosave?.flush(), [autosave]);
2989
3240
  saveRef.current = async () => {
2990
3241
  const record = store.get(documentId);
2991
3242
  const onSave = optionsRef.current.onSave;
2992
- if (!record || !onSave) return;
3243
+ if (!record) return;
2993
3244
  const key = JSON.stringify([record.title, docKey(record.json)]);
3245
+ if (!onSave) {
3246
+ lastSavedKey.current = key;
3247
+ setSaveState("saved");
3248
+ return;
3249
+ }
2994
3250
  if (key === lastSavedKey.current) {
2995
3251
  setSaveState("saved");
2996
3252
  return;
@@ -3011,11 +3267,22 @@ function DocumentEditorImpl(props) {
3011
3267
  optionsRef.current.onError?.(toJuneError(error, "DOCUMENT_ERROR", "Saving the document failed"));
3012
3268
  }
3013
3269
  };
3014
- const markDirty = useCallback3(() => {
3015
- if (!optionsRef.current.onSave) return;
3016
- setSaveState("dirty");
3017
- autosave?.();
3018
- }, [autosave]);
3270
+ const markDirty = useCallback3(
3271
+ (userEdit = true) => {
3272
+ if (!optionsRef.current.onSave) {
3273
+ if (userEdit) setSaveState("dirty");
3274
+ return;
3275
+ }
3276
+ setSaveState("dirty");
3277
+ autosave?.();
3278
+ },
3279
+ [autosave]
3280
+ );
3281
+ useEffect6(() => {
3282
+ if (saveState !== "saved" || options.onSave) return;
3283
+ const t = setTimeout(() => setSaveState((s) => s === "saved" ? "idle" : s), 2500);
3284
+ return () => clearTimeout(t);
3285
+ }, [saveState, options.onSave]);
3019
3286
  const [initialJson] = useState6(() => store.get(documentId)?.json ?? parsed.json ?? emptyDoc());
3020
3287
  const extensions = useMemo4(() => createDocumentExtensions(), []);
3021
3288
  const onUpdateRef = useRef7(() => {
@@ -3040,11 +3307,13 @@ function DocumentEditorImpl(props) {
3040
3307
  },
3041
3308
  onUpdate: ({ editor: ed }) => onUpdateRef.current(ed.getJSON())
3042
3309
  });
3043
- useEffect5(() => {
3044
- editor?.setEditable(editable);
3310
+ useEffect6(() => {
3311
+ if (!editor || editor.isEditable === editable) return;
3312
+ editor.setEditable(editable);
3045
3313
  }, [editor, editable]);
3046
- useEffect5(() => {
3314
+ useEffect6(() => {
3047
3315
  if (!parsed.json) return;
3316
+ if (isDocumentEcho(store, documentId, contentKey)) return;
3048
3317
  const outcome = store.receive({
3049
3318
  id: documentId,
3050
3319
  title: titleProp,
@@ -3054,7 +3323,7 @@ function DocumentEditorImpl(props) {
3054
3323
  });
3055
3324
  if (outcome === "applied" || outcome === "merged") {
3056
3325
  emitChange(outcome === "applied" ? "ai" : "merge");
3057
- markDirty();
3326
+ markDirty(false);
3058
3327
  } else if (outcome === "conflict") {
3059
3328
  const record = store.get(documentId);
3060
3329
  optionsRef.current.onConflict?.({
@@ -3064,7 +3333,7 @@ function DocumentEditorImpl(props) {
3064
3333
  });
3065
3334
  }
3066
3335
  }, [store, documentId, titleProp, parsed.json, documentType, status, emitChange, markDirty]);
3067
- useEffect5(() => {
3336
+ useEffect6(() => {
3068
3337
  if (!editor) return;
3069
3338
  const apply = () => {
3070
3339
  const record = store.get(documentId);
@@ -3081,7 +3350,7 @@ function DocumentEditorImpl(props) {
3081
3350
  apply();
3082
3351
  return store.subscribe(apply);
3083
3352
  }, [editor, store, documentId, instanceId]);
3084
- useEffect5(() => {
3353
+ useEffect6(() => {
3085
3354
  if (!editor || readyRef.current) return;
3086
3355
  const record = store.get(documentId);
3087
3356
  if (!record) return;
@@ -3125,18 +3394,18 @@ function DocumentEditorImpl(props) {
3125
3394
  };
3126
3395
  const formats = (exportFormats ?? [...ALL_EXPORT_FORMATS]).filter((f) => listDocumentExporters().includes(f));
3127
3396
  if (parsed.error && !store.get(documentId)) {
3128
- return /* @__PURE__ */ jsxs9("div", { className: "june-doc june-doc--error", "data-theme": resolvedTheme, role: "alert", children: [
3129
- /* @__PURE__ */ jsx13("p", { className: "june-doc__draft-text", children: "This document could not be displayed." }),
3130
- /* @__PURE__ */ jsxs9("details", { children: [
3131
- /* @__PURE__ */ jsx13("summary", { children: "Show raw content" }),
3132
- /* @__PURE__ */ jsx13("pre", { className: "june-doc__raw", children: contentKey })
3397
+ return /* @__PURE__ */ jsxs10("div", { className: "june-doc june-doc--error", "data-theme": resolvedTheme, role: "alert", children: [
3398
+ /* @__PURE__ */ jsx14("p", { className: "june-doc__draft-text", children: "This document could not be displayed." }),
3399
+ /* @__PURE__ */ jsxs10("details", { children: [
3400
+ /* @__PURE__ */ jsx14("summary", { children: "Show raw content" }),
3401
+ /* @__PURE__ */ jsx14("pre", { className: "june-doc__raw", children: contentKey })
3133
3402
  ] })
3134
3403
  ] });
3135
3404
  }
3136
- if (!editor) return /* @__PURE__ */ jsx13(DocumentDraft, { title, state: "loading" });
3405
+ if (!editor) return /* @__PURE__ */ jsx14(DocumentDraft, { title, state: "loading" });
3137
3406
  const isDraft = recordStatus === "draft";
3138
3407
  const classes = ["june-doc", fullscreen ? "june-doc--fullscreen" : "", className ?? ""].filter(Boolean).join(" ");
3139
- return /* @__PURE__ */ jsxs9(
3408
+ return /* @__PURE__ */ jsxs10(
3140
3409
  "div",
3141
3410
  {
3142
3411
  className: classes,
@@ -3158,7 +3427,7 @@ function DocumentEditorImpl(props) {
3158
3427
  }
3159
3428
  },
3160
3429
  children: [
3161
- /* @__PURE__ */ jsx13(
3430
+ /* @__PURE__ */ jsx14(
3162
3431
  DocumentHeader,
3163
3432
  {
3164
3433
  title,
@@ -3169,27 +3438,28 @@ function DocumentEditorImpl(props) {
3169
3438
  onTitle: handleTitle,
3170
3439
  exportFormats: formats,
3171
3440
  canSave: !!options.onSave,
3441
+ showSave: !!options.onSave || editable && saveState !== "idle",
3172
3442
  saveState,
3173
3443
  onExport: (f) => void handleExport(f),
3174
3444
  onCopy: () => void handleCopy(),
3175
3445
  onSave: () => void saveRef.current()
3176
3446
  }
3177
3447
  ),
3178
- pending ? /* @__PURE__ */ jsxs9("div", { className: "june-doc__banner", role: "status", children: [
3179
- /* @__PURE__ */ jsxs9("span", { children: [
3448
+ pending ? /* @__PURE__ */ jsxs10("div", { className: "june-doc__banner", role: "status", children: [
3449
+ /* @__PURE__ */ jsxs10("span", { children: [
3180
3450
  "The assistant suggested changes that overlap your edits (",
3181
3451
  pending.conflicts,
3182
3452
  " ",
3183
3453
  pending.conflicts === 1 ? "section" : "sections",
3184
3454
  ")."
3185
3455
  ] }),
3186
- /* @__PURE__ */ jsxs9("span", { className: "june-doc__banner-actions", children: [
3187
- /* @__PURE__ */ jsx13("button", { type: "button", className: "june-doc__btn", onClick: () => resolve("merge"), children: "Merge, keep my edits" }),
3188
- /* @__PURE__ */ jsx13("button", { type: "button", className: "june-doc__btn", onClick: () => resolve("replace"), children: "Use AI version" }),
3189
- /* @__PURE__ */ jsx13("button", { type: "button", className: "june-doc__btn", onClick: () => resolve("keep"), children: "Keep mine" })
3456
+ /* @__PURE__ */ jsxs10("span", { className: "june-doc__banner-actions", children: [
3457
+ /* @__PURE__ */ jsx14("button", { type: "button", className: "june-doc__btn", onClick: () => resolve("merge"), children: "Merge, keep my edits" }),
3458
+ /* @__PURE__ */ jsx14("button", { type: "button", className: "june-doc__btn", onClick: () => resolve("replace"), children: "Use AI version" }),
3459
+ /* @__PURE__ */ jsx14("button", { type: "button", className: "june-doc__btn", onClick: () => resolve("keep"), children: "Keep mine" })
3190
3460
  ] })
3191
3461
  ] }) : null,
3192
- /* @__PURE__ */ jsx13(
3462
+ /* @__PURE__ */ jsx14(
3193
3463
  DocumentToolbar,
3194
3464
  {
3195
3465
  editor,
@@ -3205,33 +3475,33 @@ function DocumentEditorImpl(props) {
3205
3475
  onNotice: flash
3206
3476
  }
3207
3477
  ),
3208
- findOpen ? /* @__PURE__ */ jsx13(DocumentFindBar, { editor, editable, onClose: () => setFindOpen(false), onNotice: flash }) : null,
3209
- editable ? /* @__PURE__ */ jsx13(DocumentBubbleMenu, { editor }) : null,
3210
- /* @__PURE__ */ jsx13(DocumentContent, { editor, layout, zoom, showMarks, onMetrics: setMetrics }),
3211
- /* @__PURE__ */ jsxs9("div", { className: "june-doc__footer", children: [
3212
- /* @__PURE__ */ jsxs9("div", { className: "june-doc__stats", children: [
3213
- layout === "page" ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
3214
- /* @__PURE__ */ jsxs9("span", { children: [
3478
+ findOpen ? /* @__PURE__ */ jsx14(DocumentFindBar, { editor, editable, onClose: () => setFindOpen(false), onNotice: flash }) : null,
3479
+ editable ? /* @__PURE__ */ jsx14(DocumentBubbleMenu, { editor }) : null,
3480
+ /* @__PURE__ */ jsx14(DocumentContent, { editor, layout, zoom, showMarks, onMetrics: setMetrics }),
3481
+ /* @__PURE__ */ jsxs10("div", { className: "june-doc__footer", children: [
3482
+ /* @__PURE__ */ jsxs10("div", { className: "june-doc__stats", children: [
3483
+ layout === "page" ? /* @__PURE__ */ jsxs10(Fragment4, { children: [
3484
+ /* @__PURE__ */ jsxs10("span", { children: [
3215
3485
  "Page ",
3216
3486
  metrics.page,
3217
3487
  " of ",
3218
3488
  metrics.pages
3219
3489
  ] }),
3220
- /* @__PURE__ */ jsx13("span", { className: "june-doc__stats-sep", "aria-hidden": "true" })
3490
+ /* @__PURE__ */ jsx14("span", { className: "june-doc__stats-sep", "aria-hidden": "true" })
3221
3491
  ] }) : null,
3222
- /* @__PURE__ */ jsxs9("span", { children: [
3492
+ /* @__PURE__ */ jsxs10("span", { children: [
3223
3493
  words,
3224
3494
  " words"
3225
3495
  ] })
3226
3496
  ] }),
3227
- /* @__PURE__ */ jsx13("span", { className: "june-doc__status", "aria-live": "polite", "data-state": notice ? "notice" : saveState, children: notice ?? SAVE_LABEL[saveState] }),
3228
- /* @__PURE__ */ jsxs9("div", { className: "june-doc__zoom", role: "group", "aria-label": "Zoom", children: [
3229
- /* @__PURE__ */ jsx13("button", { type: "button", className: "june-doc__btn june-doc__btn--icon june-doc__btn--ghost", "aria-label": "Zoom out", disabled: zoom <= ZOOM_STEPS[0], onClick: () => setZoom(stepZoom(zoom, -1)), children: /* @__PURE__ */ jsx13(Icon, { name: "minus", size: 14 }) }),
3230
- /* @__PURE__ */ jsxs9("button", { type: "button", className: "june-doc__zoom-value", "aria-label": "Reset zoom", title: "Reset zoom", onClick: () => setZoom(1), children: [
3497
+ /* @__PURE__ */ jsx14("span", { className: "june-doc__status", "aria-live": "polite", "data-state": notice ? "notice" : saveState, children: notice ?? SAVE_LABEL[saveState] }),
3498
+ /* @__PURE__ */ jsxs10("div", { className: "june-doc__zoom", role: "group", "aria-label": "Zoom", children: [
3499
+ /* @__PURE__ */ jsx14("button", { type: "button", className: "june-doc__btn june-doc__btn--icon june-doc__btn--ghost", "aria-label": "Zoom out", disabled: zoom <= ZOOM_STEPS[0], onClick: () => setZoom(stepZoom(zoom, -1)), children: /* @__PURE__ */ jsx14(Icon, { name: "minus", size: 14 }) }),
3500
+ /* @__PURE__ */ jsxs10("button", { type: "button", className: "june-doc__zoom-value", "aria-label": "Reset zoom", title: "Reset zoom", onClick: () => setZoom(1), children: [
3231
3501
  Math.round(zoom * 100),
3232
3502
  "%"
3233
3503
  ] }),
3234
- /* @__PURE__ */ jsx13("button", { type: "button", className: "june-doc__btn june-doc__btn--icon june-doc__btn--ghost", "aria-label": "Zoom in", disabled: zoom >= ZOOM_STEPS[ZOOM_STEPS.length - 1], onClick: () => setZoom(stepZoom(zoom, 1)), children: /* @__PURE__ */ jsx13(Icon, { name: "plus", size: 14 }) })
3504
+ /* @__PURE__ */ jsx14("button", { type: "button", className: "june-doc__btn june-doc__btn--icon june-doc__btn--ghost", "aria-label": "Zoom in", disabled: zoom >= ZOOM_STEPS[ZOOM_STEPS.length - 1], onClick: () => setZoom(stepZoom(zoom, 1)), children: /* @__PURE__ */ jsx14(Icon, { name: "plus", size: 14 }) })
3235
3505
  ] })
3236
3506
  ] })
3237
3507
  ]
@@ -3240,7 +3510,7 @@ function DocumentEditorImpl(props) {
3240
3510
  }
3241
3511
 
3242
3512
  // src/components/document-editor/document-component.tsx
3243
- import { jsx as jsx14 } from "react/jsx-runtime";
3513
+ import { jsx as jsx15 } from "react/jsx-runtime";
3244
3514
  var DOCUMENT_COMPONENT_DESCRIPTION = 'Custom component. An editable document. DocumentEditor(documentId, title, content, documentType?, status?, editable?, exportFormats?). Place it in the root container (Card or Stack). "content" is the full document body as one Markdown string. Reuse documentId when revising the same document. Use it only when the user asks to create or revise a document.';
3245
3515
  var documentProps = z.object({
3246
3516
  documentId: z.string().describe("Stable id. Reuse it when revising the same document."),
@@ -3254,12 +3524,12 @@ var documentProps = z.object({
3254
3524
  function DocumentEditor(props) {
3255
3525
  const { isStreaming } = useJuneRuntime();
3256
3526
  if (props.generating || isStreaming) {
3257
- return /* @__PURE__ */ jsx14(DocumentDraft, { title: props.title, state: "drafting" });
3527
+ return /* @__PURE__ */ jsx15(DocumentDraft, { title: props.title, state: "drafting" });
3258
3528
  }
3259
- return /* @__PURE__ */ jsx14(DocumentEditorImpl, { ...props });
3529
+ return /* @__PURE__ */ jsx15(DocumentEditorImpl, { ...props });
3260
3530
  }
3261
3531
  function OpenUIDocument({ props }) {
3262
- return /* @__PURE__ */ jsx14(
3532
+ return /* @__PURE__ */ jsx15(
3263
3533
  DocumentEditor,
3264
3534
  {
3265
3535
  documentId: props.documentId,
@@ -3334,7 +3604,7 @@ function documentPromptOptions(options = {}) {
3334
3604
  var attr = (value) => value.replace(/"/g, "&quot;");
3335
3605
  async function serializeDocumentsForAgent(options = {}) {
3336
3606
  const store = options.store ?? getDefaultDocumentStore();
3337
- const { docToMarkdown: docToMarkdown2 } = await import("./document-engine-IAY2T6B3.js");
3607
+ const { docToMarkdown: docToMarkdown2 } = await import("./document-engine-RKD5SLXR.js");
3338
3608
  return store.list().filter((r) => !options.ids || options.ids.includes(r.id)).map(
3339
3609
  (r) => `<document id="${attr(r.id)}" title="${attr(r.title)}"${r.documentType ? ` type="${attr(r.documentType)}"` : ""}>
3340
3610
  ${docToMarkdown2(r.json)}
@@ -3347,9 +3617,9 @@ import { openuiLibrary } from "@openuidev/react-ui";
3347
3617
  var juneLibrary = withDocumentEditor(openuiLibrary);
3348
3618
 
3349
3619
  // src/core/JuneUI.tsx
3350
- import { jsx as jsx15 } from "react/jsx-runtime";
3620
+ import { jsx as jsx16 } from "react/jsx-runtime";
3351
3621
  function JuneUI({ library = juneLibrary, ...props }) {
3352
- return /* @__PURE__ */ jsx15(JuneRenderer, { library, ...props });
3622
+ return /* @__PURE__ */ jsx16(JuneRenderer, { library, ...props });
3353
3623
  }
3354
3624
  export {
3355
3625
  ALL_EXPORT_FORMATS,
@@ -3378,17 +3648,21 @@ export {
3378
3648
  getDefaultDocumentStore,
3379
3649
  getDocumentEditorInstructions,
3380
3650
  getDocumentEditorRules,
3651
+ isDocumentEcho,
3381
3652
  isJuneError,
3382
3653
  jsonFieldExtractor,
3383
3654
  juneLibrary,
3384
3655
  lightTheme,
3385
3656
  listDocumentExporters,
3386
3657
  mergeDocuments,
3658
+ readDocumentFromProgram,
3387
3659
  registerDocumentExporter,
3660
+ rememberDocumentEcho,
3388
3661
  runAction,
3389
3662
  serializeDocumentsForAgent,
3390
3663
  sseToText,
3391
3664
  toJuneError,
3665
+ updateDocumentInProgram,
3392
3666
  useDocumentOptions,
3393
3667
  useJuneRuntime,
3394
3668
  useJuneStream,