@june-ai/june-ui 0.2.4 → 0.2.5

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.cjs CHANGED
@@ -58,30 +58,6 @@ var init_errors = __esm({
58
58
  }
59
59
  });
60
60
 
61
- // src/components/document-editor/document-extensions.ts
62
- function createDocumentExtensions() {
63
- return [
64
- import_starter_kit.default.configure({
65
- heading: { levels: [1, 2, 3] },
66
- // Tiptap v3 StarterKit already includes Link and Underline
67
- link: { openOnClick: false, autolink: true, defaultProtocol: "https" }
68
- }),
69
- import_extension_text_align.default.configure({ types: ["heading", "paragraph"] }),
70
- import_extension_table.TableKit,
71
- import_markdown.Markdown
72
- ];
73
- }
74
- var import_extension_table, import_extension_text_align, import_markdown, import_starter_kit;
75
- var init_document_extensions = __esm({
76
- "src/components/document-editor/document-extensions.ts"() {
77
- "use strict";
78
- import_extension_table = require("@tiptap/extension-table");
79
- import_extension_text_align = __toESM(require("@tiptap/extension-text-align"), 1);
80
- import_markdown = require("@tiptap/markdown");
81
- import_starter_kit = __toESM(require("@tiptap/starter-kit"), 1);
82
- }
83
- });
84
-
85
61
  // src/components/document-editor/document-utils.ts
86
62
  function isDocJSON(value) {
87
63
  if (!value || typeof value !== "object") return false;
@@ -169,6 +145,199 @@ var init_document_utils = __esm({
169
145
  }
170
146
  });
171
147
 
148
+ // src/components/document-editor/document-search.ts
149
+ function findMatches(doc, term, caseSensitive) {
150
+ if (!term) return [];
151
+ const needle = caseSensitive ? term : term.toLowerCase();
152
+ const out = [];
153
+ doc.descendants((node, pos) => {
154
+ if (!node.isTextblock) return true;
155
+ let text = "";
156
+ const map = [];
157
+ node.forEach((child, offset) => {
158
+ const start = pos + 1 + offset;
159
+ if (child.isText && child.text) {
160
+ for (let i = 0; i < child.text.length; i++) map.push(start + i);
161
+ text += child.text;
162
+ } else {
163
+ map.push(start);
164
+ text += "\uFFFC";
165
+ }
166
+ });
167
+ const hay = caseSensitive ? text : text.toLowerCase();
168
+ let idx = hay.indexOf(needle);
169
+ while (idx !== -1) {
170
+ out.push({ from: map[idx], to: map[idx + needle.length - 1] + 1 });
171
+ idx = hay.indexOf(needle, idx + needle.length);
172
+ }
173
+ return false;
174
+ });
175
+ return out;
176
+ }
177
+ function build(doc, term, caseSensitive, current) {
178
+ const matches = findMatches(doc, term, caseSensitive);
179
+ const active = matches.length ? Math.min(Math.max(current, 0), matches.length - 1) : -1;
180
+ const decorations = import_view.DecorationSet.create(
181
+ doc,
182
+ matches.map(
183
+ (m, i) => import_view.Decoration.inline(m.from, m.to, {
184
+ class: i === active ? "june-doc__match june-doc__match--active" : "june-doc__match"
185
+ })
186
+ )
187
+ );
188
+ return { term, caseSensitive, current: active, matches, decorations };
189
+ }
190
+ function getSearchState(editor) {
191
+ return editor ? searchKey.getState(editor.state) : void 0;
192
+ }
193
+ function setSearch(editor, meta) {
194
+ editor.view.dispatch(editor.state.tr.setMeta(searchKey, meta));
195
+ }
196
+ function gotoMatch(editor, step) {
197
+ const s = getSearchState(editor);
198
+ if (!s || !s.matches.length) return;
199
+ const n = s.matches.length;
200
+ const current = s.current < 0 ? 0 : (s.current + step + n) % n;
201
+ setSearch(editor, { current });
202
+ const m = s.matches[current];
203
+ editor.chain().setTextSelection(m).scrollIntoView().run();
204
+ }
205
+ function replaceCurrent(editor, replacement) {
206
+ const s = getSearchState(editor);
207
+ if (!s || s.current < 0) return;
208
+ const m = s.matches[s.current];
209
+ editor.chain().command(({ tr }) => {
210
+ if (replacement) tr.insertText(replacement, m.from, m.to);
211
+ else tr.delete(m.from, m.to);
212
+ return true;
213
+ }).run();
214
+ gotoMatch(editor, 0);
215
+ }
216
+ function replaceAll(editor, replacement) {
217
+ const s = getSearchState(editor);
218
+ if (!s || !s.matches.length) return 0;
219
+ const matches = [...s.matches].reverse();
220
+ editor.chain().command(({ tr }) => {
221
+ for (const m of matches) {
222
+ if (replacement) tr.insertText(replacement, m.from, m.to);
223
+ else tr.delete(m.from, m.to);
224
+ }
225
+ return true;
226
+ }).run();
227
+ return matches.length;
228
+ }
229
+ var import_core, import_state, import_view, searchKey, DocumentSearch;
230
+ var init_document_search = __esm({
231
+ "src/components/document-editor/document-search.ts"() {
232
+ "use strict";
233
+ import_core = require("@tiptap/core");
234
+ import_state = require("@tiptap/pm/state");
235
+ import_view = require("@tiptap/pm/view");
236
+ searchKey = new import_state.PluginKey("juneDocSearch");
237
+ DocumentSearch = import_core.Extension.create({
238
+ name: "juneDocSearch",
239
+ addProseMirrorPlugins() {
240
+ return [
241
+ new import_state.Plugin({
242
+ key: searchKey,
243
+ state: {
244
+ init: () => ({ term: "", caseSensitive: false, current: -1, matches: [], decorations: import_view.DecorationSet.empty }),
245
+ apply(tr, prev, _old, state) {
246
+ const meta = tr.getMeta(searchKey);
247
+ if (!meta && !tr.docChanged) return prev;
248
+ if (!meta && !prev.term) return prev;
249
+ return build(
250
+ state.doc,
251
+ meta?.term ?? prev.term,
252
+ meta?.caseSensitive ?? prev.caseSensitive,
253
+ meta?.current ?? prev.current
254
+ );
255
+ }
256
+ },
257
+ props: {
258
+ decorations: (state) => searchKey.getState(state)?.decorations
259
+ }
260
+ })
261
+ ];
262
+ }
263
+ });
264
+ }
265
+ });
266
+
267
+ // src/components/document-editor/document-extensions.ts
268
+ function createDocumentExtensions() {
269
+ return [
270
+ import_starter_kit.default.configure({
271
+ heading: { levels: [1, 2, 3] },
272
+ // Tiptap v3 StarterKit already includes Link and Underline
273
+ link: { openOnClick: false, autolink: true, defaultProtocol: "https" }
274
+ }),
275
+ import_extension_text_align.default.configure({ types: ["heading", "paragraph"] }),
276
+ import_extension_table.TableKit,
277
+ import_extension_text_style.TextStyle,
278
+ import_extension_text_style.Color,
279
+ import_extension_text_style.FontFamily,
280
+ import_extension_text_style.FontSize,
281
+ import_extension_highlight.default.configure({ multicolor: true }),
282
+ import_extension_subscript.default,
283
+ import_extension_superscript.default,
284
+ import_extension_image.default.configure({
285
+ inline: false,
286
+ allowBase64: true,
287
+ resize: { enabled: true, minWidth: 48, minHeight: 32, alwaysPreserveAspectRatio: true }
288
+ }),
289
+ PageBreak,
290
+ DocumentSearch,
291
+ import_markdown.Markdown
292
+ ];
293
+ }
294
+ var import_core2, import_extension_highlight, import_extension_image, import_extension_subscript, import_extension_superscript, import_extension_table, import_extension_text_align, import_extension_text_style, import_markdown, import_starter_kit, PageBreak;
295
+ var init_document_extensions = __esm({
296
+ "src/components/document-editor/document-extensions.ts"() {
297
+ "use strict";
298
+ import_core2 = require("@tiptap/core");
299
+ import_extension_highlight = __toESM(require("@tiptap/extension-highlight"), 1);
300
+ import_extension_image = __toESM(require("@tiptap/extension-image"), 1);
301
+ import_extension_subscript = __toESM(require("@tiptap/extension-subscript"), 1);
302
+ import_extension_superscript = __toESM(require("@tiptap/extension-superscript"), 1);
303
+ import_extension_table = require("@tiptap/extension-table");
304
+ import_extension_text_align = __toESM(require("@tiptap/extension-text-align"), 1);
305
+ import_extension_text_style = require("@tiptap/extension-text-style");
306
+ import_markdown = require("@tiptap/markdown");
307
+ import_starter_kit = __toESM(require("@tiptap/starter-kit"), 1);
308
+ init_document_search();
309
+ PageBreak = import_core2.Node.create({
310
+ name: "pageBreak",
311
+ group: "block",
312
+ atom: true,
313
+ selectable: true,
314
+ parseHTML() {
315
+ return [{ tag: "div[data-page-break]" }];
316
+ },
317
+ renderHTML({ HTMLAttributes }) {
318
+ return [
319
+ "div",
320
+ (0, import_core2.mergeAttributes)(HTMLAttributes, {
321
+ "data-page-break": "true",
322
+ class: "june-doc__page-break",
323
+ style: "break-after: page; page-break-after: always;"
324
+ })
325
+ ];
326
+ },
327
+ // Markdown has no page break; a thematic break is the closest stable equivalent.
328
+ renderMarkdown: () => "---",
329
+ addCommands() {
330
+ return {
331
+ setPageBreak: () => ({ chain }) => chain().insertContent([{ type: this.name }, { type: "paragraph" }]).run()
332
+ };
333
+ },
334
+ addKeyboardShortcuts() {
335
+ return { "Mod-Enter": () => this.editor.commands.setPageBreak() };
336
+ }
337
+ });
338
+ }
339
+ });
340
+
172
341
  // src/components/document-editor/document-engine.ts
173
342
  var document_engine_exports = {};
174
343
  __export(document_engine_exports, {
@@ -179,7 +348,7 @@ __export(document_engine_exports, {
179
348
  });
180
349
  function scratchEditor() {
181
350
  if (!scratch || scratch.isDestroyed) {
182
- scratch = new import_core.Editor({ extensions: createDocumentExtensions(), content: "" });
351
+ scratch = new import_core3.Editor({ extensions: createDocumentExtensions(), content: "" });
183
352
  }
184
353
  return scratch;
185
354
  }
@@ -205,11 +374,11 @@ function load(doc) {
205
374
  editor.commands.setContent(doc, { emitUpdate: false });
206
375
  return editor;
207
376
  }
208
- var import_core, scratch, docToHtml, docToMarkdown, docToText;
377
+ var import_core3, scratch, docToHtml, docToMarkdown, docToText;
209
378
  var init_document_engine = __esm({
210
379
  "src/components/document-editor/document-engine.ts"() {
211
380
  "use strict";
212
- import_core = require("@tiptap/core");
381
+ import_core3 = require("@tiptap/core");
213
382
  init_errors();
214
383
  init_document_extensions();
215
384
  init_document_utils();
@@ -1353,15 +1522,1163 @@ function DocumentDraft({ title, words, state }) {
1353
1522
  }
1354
1523
 
1355
1524
  // src/components/document-editor/document-editor.tsx
1356
- var import_react10 = require("@tiptap/react");
1357
- var import_react11 = require("react");
1525
+ var import_react15 = require("@tiptap/react");
1526
+ var import_react16 = require("react");
1358
1527
  init_errors();
1359
1528
 
1360
- // src/components/document-editor/document-content.tsx
1361
- var import_react7 = require("@tiptap/react");
1529
+ // src/components/document-editor/document-bubble.tsx
1530
+ var import_react10 = require("@tiptap/react");
1531
+ var import_menus = require("@tiptap/react/menus");
1532
+
1533
+ // src/components/document-editor/document-toolbar.tsx
1534
+ var import_react8 = require("@tiptap/react");
1535
+ var import_react9 = require("react");
1536
+
1537
+ // src/components/document-editor/document-icons.tsx
1362
1538
  var import_jsx_runtime5 = require("react/jsx-runtime");
1363
- function DocumentContent({ editor }) {
1364
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "june-doc__content", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react7.EditorContent, { editor }) });
1539
+ var PATHS = {
1540
+ undo: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1541
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M9 14 4 9l5-5" }),
1542
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M4 9h10.5a5.5 5.5 0 0 1 0 11H11" })
1543
+ ] }),
1544
+ redo: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1545
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m15 14 5-5-5-5" }),
1546
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M20 9H9.5a5.5 5.5 0 0 0 0 11H13" })
1547
+ ] }),
1548
+ bold: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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" }),
1549
+ italic: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1550
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "19", x2: "10", y1: "4", y2: "4" }),
1551
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "14", x2: "5", y1: "20", y2: "20" }),
1552
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "15", x2: "9", y1: "4", y2: "20" })
1553
+ ] }),
1554
+ underline: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1555
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M6 4v6a6 6 0 0 0 12 0V4" }),
1556
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "4", x2: "20", y1: "20", y2: "20" })
1557
+ ] }),
1558
+ strike: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1559
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M16 4H9a3 3 0 0 0-2.83 4" }),
1560
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M14 12a4 4 0 0 1 0 8H6" }),
1561
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "4", x2: "20", y1: "12", y2: "12" })
1562
+ ] }),
1563
+ code: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1564
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m16 18 6-6-6-6" }),
1565
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m8 6-6 6 6 6" })
1566
+ ] }),
1567
+ codeBlock: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1568
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
1569
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m10 9-3 3 3 3" }),
1570
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m14 15 3-3-3-3" })
1571
+ ] }),
1572
+ superscript: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1573
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m4 19 8-8" }),
1574
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m12 19-8-8" }),
1575
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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" })
1576
+ ] }),
1577
+ subscript: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1578
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m4 5 8 8" }),
1579
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m12 5-8 8" }),
1580
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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" })
1581
+ ] }),
1582
+ alignLeft: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1583
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M15 12H3" }),
1584
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M17 18H3" }),
1585
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M21 6H3" })
1586
+ ] }),
1587
+ alignCenter: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1588
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M17 12H7" }),
1589
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M19 18H5" }),
1590
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M21 6H3" })
1591
+ ] }),
1592
+ alignRight: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1593
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M21 12H9" }),
1594
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M21 18H7" }),
1595
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M21 6H3" })
1596
+ ] }),
1597
+ alignJustify: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1598
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M3 12h18" }),
1599
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M3 18h18" }),
1600
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M3 6h18" })
1601
+ ] }),
1602
+ list: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1603
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M3 12h.01" }),
1604
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M3 18h.01" }),
1605
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M3 6h.01" }),
1606
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M8 12h13" }),
1607
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M8 18h13" }),
1608
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M8 6h13" })
1609
+ ] }),
1610
+ listOrdered: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1611
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M10 12h11" }),
1612
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M10 18h11" }),
1613
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M10 6h11" }),
1614
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M4 10h2" }),
1615
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M4 6h1v4" }),
1616
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M6 18H4c0-1 2-2 2-3s-1-1.5-2-1" })
1617
+ ] }),
1618
+ outdent: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1619
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M21 12H11" }),
1620
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M21 18H11" }),
1621
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M21 6H11" }),
1622
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m7 8-4 4 4 4" })
1623
+ ] }),
1624
+ indent: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1625
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M21 12H11" }),
1626
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M21 18H11" }),
1627
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M21 6H11" }),
1628
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m3 8 4 4-4 4" })
1629
+ ] }),
1630
+ quote: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1631
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M17 6H3" }),
1632
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M21 12H8" }),
1633
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M21 18H8" }),
1634
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M3 12v6" })
1635
+ ] }),
1636
+ pilcrow: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1637
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M13 4v16" }),
1638
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M17 4v16" }),
1639
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M19 4H9.5a4.5 4.5 0 0 0 0 9H13" })
1640
+ ] }),
1641
+ pageBreak: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1642
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "3", x2: "21", y1: "12", y2: "12" }),
1643
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polyline", { points: "8 8 12 4 16 8" }),
1644
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polyline", { points: "16 16 12 20 8 16" })
1645
+ ] }),
1646
+ divider: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1647
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M3 12h18" }),
1648
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M8 6h8", opacity: ".45" }),
1649
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M8 18h8", opacity: ".45" })
1650
+ ] }),
1651
+ layout: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1652
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { width: "18", height: "7", x: "3", y: "3", rx: "1" }),
1653
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { width: "9", height: "7", x: "3", y: "14", rx: "1" }),
1654
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { width: "5", height: "7", x: "16", y: "14", rx: "1" })
1655
+ ] }),
1656
+ search: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1657
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("circle", { cx: "11", cy: "11", r: "8" }),
1658
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m21 21-4.3-4.3" })
1659
+ ] }),
1660
+ palette: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1661
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("circle", { cx: "13.5", cy: "6.5", r: ".5", fill: "currentColor" }),
1662
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("circle", { cx: "17.5", cy: "10.5", r: ".5", fill: "currentColor" }),
1663
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("circle", { cx: "8.5", cy: "7.5", r: ".5", fill: "currentColor" }),
1664
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("circle", { cx: "6.5", cy: "12.5", r: ".5", fill: "currentColor" }),
1665
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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" })
1666
+ ] }),
1667
+ highlighter: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1668
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m9 11-6 6v3h9l3-3" }),
1669
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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" })
1670
+ ] }),
1671
+ link: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1672
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
1673
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
1674
+ ] }),
1675
+ image: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1676
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }),
1677
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("circle", { cx: "9", cy: "9", r: "2" }),
1678
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m21 15-3.09-3.09a2 2 0 0 0-2.82 0L6 21" })
1679
+ ] }),
1680
+ table: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1681
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 3v18" }),
1682
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }),
1683
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M3 9h18" }),
1684
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M3 15h18" })
1685
+ ] }),
1686
+ eraser: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1687
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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" }),
1688
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M22 21H7" }),
1689
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m5 11 9 9" })
1690
+ ] }),
1691
+ save: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1692
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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" }),
1693
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7" }),
1694
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M7 3v4a1 1 0 0 0 1 1h7" })
1695
+ ] }),
1696
+ download: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1697
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
1698
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polyline", { points: "7 10 12 15 17 10" }),
1699
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "12", x2: "12", y1: "15", y2: "3" })
1700
+ ] }),
1701
+ chevronDown: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m6 9 6 6 6-6" }),
1702
+ chevronUp: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m18 15-6-6-6 6" }),
1703
+ close: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1704
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M18 6 6 18" }),
1705
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m6 6 12 12" })
1706
+ ] }),
1707
+ maximize: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1708
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M8 3H5a2 2 0 0 0-2 2v3" }),
1709
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M21 8V5a2 2 0 0 0-2-2h-3" }),
1710
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M3 16v3a2 2 0 0 0 2 2h3" }),
1711
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M16 21h3a2 2 0 0 0 2-2v-3" })
1712
+ ] }),
1713
+ copy: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1714
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { width: "14", height: "14", x: "8", y: "8", rx: "2" }),
1715
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })
1716
+ ] }),
1717
+ file: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1718
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" }),
1719
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" })
1720
+ ] }),
1721
+ plus: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1722
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M5 12h14" }),
1723
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 5v14" })
1724
+ ] }),
1725
+ minus: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M5 12h14" }),
1726
+ check: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M20 6 9 17l-5-5" }),
1727
+ sparkles: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1728
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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)" }),
1729
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M20 3v4" }),
1730
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M22 5h-4" })
1731
+ ] }),
1732
+ upload: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1733
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
1734
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("polyline", { points: "17 8 12 3 7 8" }),
1735
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: "12", x2: "12", y1: "3", y2: "15" })
1736
+ ] })
1737
+ };
1738
+ function Icon({ name, size = 16 }) {
1739
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1740
+ "svg",
1741
+ {
1742
+ className: "june-doc__icon",
1743
+ width: size,
1744
+ height: size,
1745
+ viewBox: "0 0 24 24",
1746
+ fill: "none",
1747
+ stroke: "currentColor",
1748
+ strokeWidth: 2,
1749
+ strokeLinecap: "round",
1750
+ strokeLinejoin: "round",
1751
+ "aria-hidden": "true",
1752
+ focusable: "false",
1753
+ children: PATHS[name]
1754
+ }
1755
+ );
1756
+ }
1757
+
1758
+ // src/components/document-editor/document-popover.tsx
1759
+ var import_react7 = require("react");
1760
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1761
+ function Dropdown({ trigger, children, align = "start", className, onOpen }) {
1762
+ const [open, setOpen] = (0, import_react7.useState)(false);
1763
+ const anchor = (0, import_react7.useRef)(null);
1764
+ (0, import_react7.useEffect)(() => {
1765
+ if (!open) return;
1766
+ const onDown = (e) => {
1767
+ if (anchor.current && !anchor.current.contains(e.target)) setOpen(false);
1768
+ };
1769
+ document.addEventListener("mousedown", onDown);
1770
+ return () => document.removeEventListener("mousedown", onDown);
1771
+ }, [open]);
1772
+ const toggle = () => setOpen((v) => {
1773
+ if (!v) onOpen?.();
1774
+ return !v;
1775
+ });
1776
+ const close = () => setOpen(false);
1777
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1778
+ "div",
1779
+ {
1780
+ ref: anchor,
1781
+ className: "june-doc__anchor",
1782
+ onKeyDown: (e) => {
1783
+ if (e.key === "Escape" && open) {
1784
+ e.stopPropagation();
1785
+ close();
1786
+ }
1787
+ },
1788
+ children: [
1789
+ trigger({ open, toggle }),
1790
+ open ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: `june-doc__pop june-doc__pop--${align}${className ? ` ${className}` : ""}`, children: children(close) }) : null
1791
+ ]
1792
+ }
1793
+ );
1794
+ }
1795
+
1796
+ // src/components/document-editor/document-toolbar.tsx
1797
+ init_document_utils();
1798
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1799
+ var FONT_FAMILIES = [
1800
+ { label: "Default", value: "" },
1801
+ { label: "Arial", value: "Arial, Helvetica, sans-serif" },
1802
+ { label: "Calibri", value: "Calibri, Carlito, sans-serif" },
1803
+ { label: "Georgia", value: "Georgia, serif" },
1804
+ { label: "Garamond", value: "Garamond, 'EB Garamond', serif" },
1805
+ { label: "Times New Roman", value: "'Times New Roman', Times, serif" },
1806
+ { label: "Verdana", value: "Verdana, Geneva, sans-serif" },
1807
+ { label: "Trebuchet MS", value: "'Trebuchet MS', sans-serif" },
1808
+ { label: "Courier New", value: "'Courier New', Courier, monospace" }
1809
+ ];
1810
+ var FONT_SIZES = [8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 24, 28, 32, 36, 48, 60, 72];
1811
+ var TEXT_COLORS = [
1812
+ "#111827",
1813
+ "#374151",
1814
+ "#6b7280",
1815
+ "#9ca3af",
1816
+ "#dc2626",
1817
+ "#ea580c",
1818
+ "#ca8a04",
1819
+ "#16a34a",
1820
+ "#0d9488",
1821
+ "#0284c7",
1822
+ "#2563eb",
1823
+ "#4f46e5",
1824
+ "#9333ea",
1825
+ "#db2777",
1826
+ "#7f1d1d",
1827
+ "#1e3a8a"
1828
+ ];
1829
+ var HIGHLIGHT_COLORS = [
1830
+ "#fef08a",
1831
+ "#fde68a",
1832
+ "#fed7aa",
1833
+ "#fecaca",
1834
+ "#fbcfe8",
1835
+ "#e9d5ff",
1836
+ "#c7d2fe",
1837
+ "#bfdbfe",
1838
+ "#a5f3fc",
1839
+ "#bbf7d0",
1840
+ "#d9f99d",
1841
+ "#e5e7eb"
1842
+ ];
1843
+ var MAX_IMAGE_BYTES = 8 * 1024 * 1024;
1844
+ function Btn({ label, icon, active, disabled, toggle, onClick, children, className, text }) {
1845
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1846
+ "button",
1847
+ {
1848
+ type: "button",
1849
+ className: `june-doc__btn${icon && !text && !children ? " june-doc__btn--icon" : ""}${className ? ` ${className}` : ""}`,
1850
+ "aria-label": label,
1851
+ title: label,
1852
+ "aria-pressed": toggle ? !!active : void 0,
1853
+ "data-active": active || void 0,
1854
+ disabled,
1855
+ onMouseDown: (e) => e.preventDefault(),
1856
+ onClick,
1857
+ children: [
1858
+ icon ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { name: icon }) : null,
1859
+ children ?? (text ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: label }) : null)
1860
+ ]
1861
+ }
1862
+ );
1863
+ }
1864
+ function Group({ label, children }) {
1865
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__group", role: "group", "aria-label": label, children: [
1866
+ label ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "june-doc__group-label", "aria-hidden": "true", children: label }) : null,
1867
+ children
1868
+ ] });
1869
+ }
1870
+ function Field({ label, children }) {
1871
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "june-doc__field", children: [
1872
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "june-doc__field-label", children: label }),
1873
+ children
1874
+ ] });
1875
+ }
1876
+ function ColorPicker({ label, icon, colors, current, disabled, resetLabel, onPick, onReset }) {
1877
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1878
+ Dropdown,
1879
+ {
1880
+ trigger: ({ open, toggle }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1881
+ "button",
1882
+ {
1883
+ type: "button",
1884
+ className: "june-doc__btn june-doc__btn--icon june-doc__btn--color",
1885
+ "aria-label": label,
1886
+ title: label,
1887
+ "aria-expanded": open,
1888
+ "aria-haspopup": "dialog",
1889
+ disabled,
1890
+ onMouseDown: (e) => e.preventDefault(),
1891
+ onClick: toggle,
1892
+ children: [
1893
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { name: icon }),
1894
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "june-doc__color-bar", style: { background: current ?? "transparent" } })
1895
+ ]
1896
+ }
1897
+ ),
1898
+ children: (close) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__swatches-wrap", role: "dialog", "aria-label": label, children: [
1899
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "june-doc__pop-title", children: label }),
1900
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "june-doc__swatches", children: colors.map((c) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1901
+ "button",
1902
+ {
1903
+ type: "button",
1904
+ className: "june-doc__swatch",
1905
+ style: { background: c },
1906
+ "aria-label": c,
1907
+ title: c,
1908
+ "data-active": current?.toLowerCase() === c ? true : void 0,
1909
+ onMouseDown: (e) => e.preventDefault(),
1910
+ onClick: () => {
1911
+ onPick(c);
1912
+ close();
1913
+ }
1914
+ },
1915
+ c
1916
+ )) }),
1917
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__pop-row", children: [
1918
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1919
+ "button",
1920
+ {
1921
+ type: "button",
1922
+ className: "june-doc__btn june-doc__btn--ghost",
1923
+ onMouseDown: (e) => e.preventDefault(),
1924
+ onClick: () => {
1925
+ onReset();
1926
+ close();
1927
+ },
1928
+ children: resetLabel
1929
+ }
1930
+ ),
1931
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "june-doc__custom-color", title: "Custom color", children: [
1932
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Custom" }),
1933
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1934
+ "input",
1935
+ {
1936
+ type: "color",
1937
+ "aria-label": `${label}: custom`,
1938
+ defaultValue: current && /^#[0-9a-f]{6}$/i.test(current) ? current : "#000000",
1939
+ onChange: (e) => onPick(e.target.value)
1940
+ }
1941
+ )
1942
+ ] })
1943
+ ] })
1944
+ ] })
1945
+ }
1946
+ );
1947
+ }
1948
+ function LinkPanel({
1949
+ editor,
1950
+ href,
1951
+ isLink,
1952
+ close
1953
+ }) {
1954
+ const [value, setValue] = (0, import_react9.useState)(href);
1955
+ const apply = () => {
1956
+ const safe = sanitizeHref(value);
1957
+ if (safe) editor.chain().focus().extendMarkRange("link").setLink({ href: safe }).run();
1958
+ close();
1959
+ };
1960
+ const remove = () => {
1961
+ editor.chain().focus().extendMarkRange("link").unsetLink().run();
1962
+ close();
1963
+ };
1964
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__form", role: "dialog", "aria-label": "Edit link", children: [
1965
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "june-doc__pop-title", children: "Link" }),
1966
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1967
+ "input",
1968
+ {
1969
+ "aria-label": "Link address",
1970
+ className: "june-doc__input",
1971
+ placeholder: "https://example.com",
1972
+ value,
1973
+ autoFocus: true,
1974
+ onChange: (e) => setValue(e.target.value),
1975
+ onKeyDown: (e) => {
1976
+ if (e.key === "Enter") {
1977
+ e.preventDefault();
1978
+ apply();
1979
+ }
1980
+ }
1981
+ }
1982
+ ),
1983
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__pop-row june-doc__pop-row--end", children: [
1984
+ isLink ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "june-doc__btn june-doc__btn--ghost", onClick: remove, children: "Remove" }) : null,
1985
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "june-doc__btn", onClick: close, children: "Cancel" }),
1986
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "june-doc__btn june-doc__btn--primary", onClick: apply, children: "Apply" })
1987
+ ] })
1988
+ ] });
1989
+ }
1990
+ function ImagePanel({ editor, close, onNotice }) {
1991
+ const [url, setUrl] = (0, import_react9.useState)("");
1992
+ const [alt, setAlt] = (0, import_react9.useState)("");
1993
+ const file = (0, import_react9.useRef)(null);
1994
+ const insert = (src) => {
1995
+ editor.chain().focus().setImage({ src, alt: alt || void 0 }).run();
1996
+ close();
1997
+ };
1998
+ const fromUrl = () => {
1999
+ const safe = sanitizeHref(url);
2000
+ if (!safe || !/^https?:/i.test(safe)) {
2001
+ onNotice("Enter an http(s) image address");
2002
+ return;
2003
+ }
2004
+ insert(safe);
2005
+ };
2006
+ const fromFile = (f) => {
2007
+ if (!f) return;
2008
+ if (!f.type.startsWith("image/")) return onNotice("That file is not an image");
2009
+ if (f.size > MAX_IMAGE_BYTES) return onNotice("Images must be 8 MB or smaller");
2010
+ const reader = new FileReader();
2011
+ reader.onload = () => typeof reader.result === "string" && insert(reader.result);
2012
+ reader.onerror = () => onNotice("The image could not be read");
2013
+ reader.readAsDataURL(f);
2014
+ };
2015
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__form", role: "dialog", "aria-label": "Insert image", children: [
2016
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "june-doc__pop-title", children: "Image" }),
2017
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2018
+ "button",
2019
+ {
2020
+ type: "button",
2021
+ className: "june-doc__dropzone",
2022
+ onClick: () => file.current?.click(),
2023
+ onDragOver: (e) => e.preventDefault(),
2024
+ onDrop: (e) => {
2025
+ e.preventDefault();
2026
+ fromFile(e.dataTransfer.files[0]);
2027
+ },
2028
+ children: [
2029
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { name: "upload", size: 18 }),
2030
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Upload or drop an image" })
2031
+ ]
2032
+ }
2033
+ ),
2034
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2035
+ "input",
2036
+ {
2037
+ ref: file,
2038
+ type: "file",
2039
+ accept: "image/*",
2040
+ hidden: true,
2041
+ onChange: (e) => fromFile(e.target.files?.[0])
2042
+ }
2043
+ ),
2044
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "june-doc__or", children: "or" }),
2045
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2046
+ "input",
2047
+ {
2048
+ "aria-label": "Image address",
2049
+ className: "june-doc__input",
2050
+ placeholder: "https://example.com/image.png",
2051
+ value: url,
2052
+ onChange: (e) => setUrl(e.target.value),
2053
+ onKeyDown: (e) => e.key === "Enter" && fromUrl()
2054
+ }
2055
+ ),
2056
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2057
+ "input",
2058
+ {
2059
+ "aria-label": "Alternative text",
2060
+ className: "june-doc__input",
2061
+ placeholder: "Alt text (optional)",
2062
+ value: alt,
2063
+ onChange: (e) => setAlt(e.target.value)
2064
+ }
2065
+ ),
2066
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__pop-row june-doc__pop-row--end", children: [
2067
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "june-doc__btn", onClick: close, children: "Cancel" }),
2068
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "june-doc__btn june-doc__btn--primary", disabled: !url.trim(), onClick: fromUrl, children: "Insert" })
2069
+ ] })
2070
+ ] });
2071
+ }
2072
+ function TablePanel({ editor, close }) {
2073
+ const [hover, setHover] = (0, import_react9.useState)([0, 0]);
2074
+ const N = 8;
2075
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__form", role: "dialog", "aria-label": "Insert table", children: [
2076
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__pop-title", children: [
2077
+ "Table ",
2078
+ hover[0] ? `${hover[0]} \xD7 ${hover[1]}` : ""
2079
+ ] }),
2080
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "june-doc__grid", onMouseLeave: () => setHover([0, 0]), children: Array.from({ length: N * N }, (_, i) => {
2081
+ const r = Math.floor(i / N) + 1;
2082
+ const c = i % N + 1;
2083
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2084
+ "button",
2085
+ {
2086
+ type: "button",
2087
+ className: "june-doc__cell",
2088
+ "aria-label": `${r} by ${c} table`,
2089
+ "data-active": r <= hover[0] && c <= hover[1] ? true : void 0,
2090
+ onMouseEnter: () => setHover([r, c]),
2091
+ onFocus: () => setHover([r, c]),
2092
+ onMouseDown: (e) => e.preventDefault(),
2093
+ onClick: () => {
2094
+ editor.chain().focus().insertTable({ rows: r, cols: c, withHeaderRow: true }).run();
2095
+ close();
2096
+ }
2097
+ },
2098
+ i
2099
+ );
2100
+ }) })
2101
+ ] });
2102
+ }
2103
+ var px = (v) => typeof v === "string" ? v.replace(/px$/, "") : "";
2104
+ function DocumentToolbar(props) {
2105
+ const { editor, editable, expanded, onToggleExpanded, showMarks, onToggleMarks, layout, onToggleLayout, findOpen, onToggleFind, onNotice } = props;
2106
+ const s = (0, import_react8.useEditorState)({
2107
+ editor,
2108
+ selector: ({ editor: ed }) => {
2109
+ if (!ed) return null;
2110
+ const ts = ed.getAttributes("textStyle");
2111
+ return {
2112
+ bold: ed.isActive("bold"),
2113
+ italic: ed.isActive("italic"),
2114
+ underline: ed.isActive("underline"),
2115
+ strike: ed.isActive("strike"),
2116
+ code: ed.isActive("code"),
2117
+ sup: ed.isActive("superscript"),
2118
+ sub: ed.isActive("subscript"),
2119
+ bullet: ed.isActive("bulletList"),
2120
+ ordered: ed.isActive("orderedList"),
2121
+ quote: ed.isActive("blockquote"),
2122
+ codeBlock: ed.isActive("codeBlock"),
2123
+ link: ed.isActive("link"),
2124
+ linkHref: ed.getAttributes("link").href ?? "",
2125
+ h1: ed.isActive("heading", { level: 1 }),
2126
+ h2: ed.isActive("heading", { level: 2 }),
2127
+ h3: ed.isActive("heading", { level: 3 }),
2128
+ left: ed.isActive({ textAlign: "left" }),
2129
+ center: ed.isActive({ textAlign: "center" }),
2130
+ right: ed.isActive({ textAlign: "right" }),
2131
+ justify: ed.isActive({ textAlign: "justify" }),
2132
+ inTable: ed.isActive("table"),
2133
+ color: ts.color ?? null,
2134
+ fontFamily: ts.fontFamily ?? "",
2135
+ fontSize: px(ts.fontSize),
2136
+ highlight: ed.isActive("highlight") ? ed.getAttributes("highlight").color ?? "#fef08a" : null,
2137
+ canUndo: ed.can().undo(),
2138
+ canRedo: ed.can().redo(),
2139
+ canSink: ed.can().sinkListItem("listItem"),
2140
+ canLift: ed.can().liftListItem("listItem"),
2141
+ canMerge: ed.can().mergeCells(),
2142
+ canSplit: ed.can().splitCell()
2143
+ };
2144
+ }
2145
+ });
2146
+ const run = () => editor?.chain().focus();
2147
+ const off = !editor || !editable;
2148
+ const style = s?.codeBlock ? "code" : s?.h1 ? "1" : s?.h2 ? "2" : s?.h3 ? "3" : s?.quote ? "quote" : "p";
2149
+ const setStyle = (v) => {
2150
+ if (!editor || !s) return;
2151
+ let c = editor.chain().focus();
2152
+ if (v === "quote") {
2153
+ if (!s.quote) c = c.setParagraph().toggleBlockquote();
2154
+ } else if (v === "code") {
2155
+ if (!s.codeBlock) c = c.toggleCodeBlock();
2156
+ } else {
2157
+ if (s.quote) c = c.lift("blockquote");
2158
+ c = v === "p" ? c.setParagraph() : c.setHeading({ level: Number(v) });
2159
+ }
2160
+ c.run();
2161
+ };
2162
+ const fontKnown = FONT_FAMILIES.some((f) => f.value === s?.fontFamily);
2163
+ const sizes = s?.fontSize && !FONT_SIZES.includes(Number(s.fontSize)) ? [...FONT_SIZES, Number(s.fontSize)].sort((a, b) => a - b) : FONT_SIZES;
2164
+ if (!editable) return null;
2165
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__ribbon", role: "toolbar", "aria-label": "Document formatting", children: [
2166
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__row", children: [
2167
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Group, { label: "History", children: [
2168
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Undo", icon: "undo", disabled: off || !s?.canUndo, onClick: () => run()?.undo().run() }),
2169
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Redo", icon: "redo", disabled: off || !s?.canRedo, onClick: () => run()?.redo().run() })
2170
+ ] }),
2171
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Group, { label: "Format", children: [
2172
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Bold", icon: "bold", toggle: true, active: s?.bold, disabled: off, onClick: () => run()?.toggleBold().run() }),
2173
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Italic", icon: "italic", toggle: true, active: s?.italic, disabled: off, onClick: () => run()?.toggleItalic().run() }),
2174
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Underline", icon: "underline", toggle: true, active: s?.underline, disabled: off, onClick: () => run()?.toggleUnderline().run() }),
2175
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Strikethrough", icon: "strike", toggle: true, active: s?.strike, disabled: off, onClick: () => run()?.toggleStrike().run() }),
2176
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Inline code", icon: "code", toggle: true, active: s?.code, disabled: off, onClick: () => run()?.toggleCode().run() }),
2177
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Superscript", icon: "superscript", toggle: true, active: s?.sup, disabled: off, onClick: () => run()?.toggleSuperscript().run() }),
2178
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Subscript", icon: "subscript", toggle: true, active: s?.sub, disabled: off, onClick: () => run()?.toggleSubscript().run() })
2179
+ ] }),
2180
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Group, { label: "Align", children: [
2181
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Align left", icon: "alignLeft", toggle: true, active: s?.left, disabled: off, onClick: () => run()?.setTextAlign("left").run() }),
2182
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Align center", icon: "alignCenter", toggle: true, active: s?.center, disabled: off, onClick: () => run()?.setTextAlign("center").run() }),
2183
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Align right", icon: "alignRight", toggle: true, active: s?.right, disabled: off, onClick: () => run()?.setTextAlign("right").run() }),
2184
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Justify", icon: "alignJustify", toggle: true, active: s?.justify, disabled: off, onClick: () => run()?.setTextAlign("justify").run() })
2185
+ ] }),
2186
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Group, { label: "Lists", children: [
2187
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Bullet list", icon: "list", toggle: true, active: s?.bullet, disabled: off, onClick: () => run()?.toggleBulletList().run() }),
2188
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Numbered list", icon: "listOrdered", toggle: true, active: s?.ordered, disabled: off, onClick: () => run()?.toggleOrderedList().run() }),
2189
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Decrease indent", icon: "outdent", disabled: off || !s?.canLift, onClick: () => run()?.liftListItem("listItem").run() }),
2190
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Increase indent", icon: "indent", disabled: off || !s?.canSink, onClick: () => run()?.sinkListItem("listItem").run() })
2191
+ ] }),
2192
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2193
+ "button",
2194
+ {
2195
+ type: "button",
2196
+ className: "june-doc__btn june-doc__more",
2197
+ "aria-expanded": expanded,
2198
+ "aria-label": expanded ? "Show fewer tools" : "Show more tools",
2199
+ onMouseDown: (e) => e.preventDefault(),
2200
+ onClick: onToggleExpanded,
2201
+ children: [
2202
+ expanded ? "Less" : "More",
2203
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { name: expanded ? "chevronUp" : "chevronDown", size: 14 })
2204
+ ]
2205
+ }
2206
+ )
2207
+ ] }),
2208
+ expanded ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__row june-doc__row--secondary", children: [
2209
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Group, { label: "Style", children: [
2210
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Field, { label: "Style", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("select", { className: "june-doc__select", "aria-label": "Text style", disabled: off, value: style, onChange: (e) => setStyle(e.target.value), children: [
2211
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "p", children: "Paragraph" }),
2212
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "1", children: "Heading 1" }),
2213
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "2", children: "Heading 2" }),
2214
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "3", children: "Heading 3" }),
2215
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "quote", children: "Quote" }),
2216
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "code", children: "Code block" })
2217
+ ] }) }),
2218
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Field, { label: "Font", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2219
+ "select",
2220
+ {
2221
+ className: "june-doc__select june-doc__select--font",
2222
+ "aria-label": "Font family",
2223
+ disabled: off,
2224
+ value: s?.fontFamily ?? "",
2225
+ onChange: (e) => {
2226
+ const v = e.target.value;
2227
+ if (v) run()?.setFontFamily(v).run();
2228
+ else run()?.unsetFontFamily().run();
2229
+ },
2230
+ children: [
2231
+ FONT_FAMILIES.map((f) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: f.value, style: { fontFamily: f.value || void 0 }, children: f.label }, f.label)),
2232
+ !fontKnown && s?.fontFamily ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: s.fontFamily, children: s.fontFamily.split(",")[0].replace(/['"]/g, "") }) : null
2233
+ ]
2234
+ }
2235
+ ) }),
2236
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Field, { label: "Size", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2237
+ "select",
2238
+ {
2239
+ className: "june-doc__select june-doc__select--size",
2240
+ "aria-label": "Font size",
2241
+ disabled: off,
2242
+ value: s?.fontSize ?? "",
2243
+ onChange: (e) => {
2244
+ const v = e.target.value;
2245
+ if (v) run()?.setFontSize(`${v}px`).run();
2246
+ else run()?.unsetFontSize().run();
2247
+ },
2248
+ children: [
2249
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "", children: "Auto" }),
2250
+ sizes.map((n) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: String(n), children: n }, n))
2251
+ ]
2252
+ }
2253
+ ) })
2254
+ ] }),
2255
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Show formatting marks", icon: "pilcrow", toggle: true, active: showMarks, onClick: onToggleMarks, text: true, className: "june-doc__btn--marks", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "Paragraph" }) }),
2256
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Group, { label: "Document", children: [
2257
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Insert page break", icon: "pageBreak", disabled: off, onClick: () => run()?.setPageBreak().run() }),
2258
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Insert divider", icon: "divider", disabled: off, onClick: () => run()?.setHorizontalRule().run() }),
2259
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: layout === "page" ? "Switch to full-width layout" : "Switch to page layout", icon: "layout", toggle: true, active: layout === "fluid", onClick: onToggleLayout }),
2260
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Find and replace", icon: "search", toggle: true, active: findOpen, onClick: onToggleFind })
2261
+ ] }),
2262
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Group, { label: "Color", children: [
2263
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2264
+ ColorPicker,
2265
+ {
2266
+ label: "Text color",
2267
+ icon: "palette",
2268
+ colors: TEXT_COLORS,
2269
+ current: s?.color ?? null,
2270
+ disabled: off,
2271
+ resetLabel: "Default color",
2272
+ onPick: (c) => run()?.setColor(c).run(),
2273
+ onReset: () => run()?.unsetColor().run()
2274
+ }
2275
+ ),
2276
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2277
+ ColorPicker,
2278
+ {
2279
+ label: "Highlight",
2280
+ icon: "highlighter",
2281
+ colors: HIGHLIGHT_COLORS,
2282
+ current: s?.highlight ?? null,
2283
+ disabled: off,
2284
+ resetLabel: "No highlight",
2285
+ onPick: (c) => run()?.setHighlight({ color: c }).run(),
2286
+ onReset: () => run()?.unsetHighlight().run()
2287
+ }
2288
+ )
2289
+ ] }),
2290
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Group, { label: "Insert", children: [
2291
+ editor ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2292
+ Dropdown,
2293
+ {
2294
+ trigger: ({ open, toggle }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Link", icon: "link", toggle: true, active: s?.link || open, disabled: off, onClick: toggle }),
2295
+ children: (close) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(LinkPanel, { editor, href: s?.linkHref ?? "", isLink: !!s?.link, close })
2296
+ }
2297
+ ) : null,
2298
+ editor ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Dropdown, { trigger: ({ open, toggle }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Insert image", icon: "image", active: open, disabled: off, onClick: toggle }), children: (close) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ImagePanel, { editor, close, onNotice }) }) : null,
2299
+ editor ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Dropdown, { trigger: ({ open, toggle }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Insert table", icon: "table", active: open, disabled: off, onClick: toggle }), children: (close) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TablePanel, { editor, close }) }) : null
2300
+ ] }),
2301
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Group, { label: "Actions", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Clear formatting", icon: "eraser", disabled: off, onClick: () => run()?.unsetAllMarks().clearNodes().run() }) })
2302
+ ] }) : null,
2303
+ s?.inTable ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "june-doc__row june-doc__row--context", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Group, { label: "Table", children: [
2304
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Add row below", disabled: off, onClick: () => run()?.addRowAfter().run(), children: "+ Row" }),
2305
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Add column right", disabled: off, onClick: () => run()?.addColumnAfter().run(), children: "+ Column" }),
2306
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Delete row", disabled: off, onClick: () => run()?.deleteRow().run(), children: "\u2212 Row" }),
2307
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Delete column", disabled: off, onClick: () => run()?.deleteColumn().run(), children: "\u2212 Column" }),
2308
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Merge cells", disabled: off || !s?.canMerge, onClick: () => run()?.mergeCells().run(), children: "Merge" }),
2309
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Split cell", disabled: off || !s?.canSplit, onClick: () => run()?.splitCell().run(), children: "Split" }),
2310
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Toggle header row", disabled: off, onClick: () => run()?.toggleHeaderRow().run(), children: "Header row" }),
2311
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Delete table", disabled: off, onClick: () => run()?.deleteTable().run(), className: "june-doc__btn--danger", children: "Delete table" })
2312
+ ] }) }) : null
2313
+ ] });
2314
+ }
2315
+
2316
+ // src/components/document-editor/document-bubble.tsx
2317
+ var import_jsx_runtime8 = require("react/jsx-runtime");
2318
+ function DocumentBubbleMenu({ editor }) {
2319
+ const s = (0, import_react10.useEditorState)({
2320
+ editor,
2321
+ selector: ({ editor: ed }) => ({
2322
+ bold: ed.isActive("bold"),
2323
+ italic: ed.isActive("italic"),
2324
+ underline: ed.isActive("underline"),
2325
+ strike: ed.isActive("strike"),
2326
+ link: ed.isActive("link"),
2327
+ linkHref: ed.getAttributes("link").href ?? "",
2328
+ color: ed.getAttributes("textStyle").color ?? null,
2329
+ highlight: ed.isActive("highlight") ? ed.getAttributes("highlight").color ?? "#fef08a" : null
2330
+ })
2331
+ });
2332
+ const run = () => editor.chain().focus();
2333
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2334
+ import_menus.BubbleMenu,
2335
+ {
2336
+ editor,
2337
+ className: "june-doc__bubble",
2338
+ options: { placement: "top", offset: 8 },
2339
+ shouldShow: ({ editor: ed, state }) => {
2340
+ const { empty } = state.selection;
2341
+ if (empty || !ed.isEditable) return false;
2342
+ if (ed.isActive("image") || ed.isActive("pageBreak") || ed.isActive("codeBlock")) return false;
2343
+ return state.doc.textBetween(state.selection.from, state.selection.to).trim().length > 0;
2344
+ },
2345
+ children: [
2346
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Bold", icon: "bold", toggle: true, active: s.bold, onClick: () => run().toggleBold().run() }),
2347
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Italic", icon: "italic", toggle: true, active: s.italic, onClick: () => run().toggleItalic().run() }),
2348
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Underline", icon: "underline", toggle: true, active: s.underline, onClick: () => run().toggleUnderline().run() }),
2349
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Strikethrough", icon: "strike", toggle: true, active: s.strike, onClick: () => run().toggleStrike().run() }),
2350
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "june-doc__bubble-sep", "aria-hidden": "true" }),
2351
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Dropdown, { trigger: ({ open, toggle }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Link", icon: "link", toggle: true, active: s.link || open, onClick: toggle }), children: (close) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(LinkPanel, { editor, href: s.linkHref, isLink: s.link, close }) }),
2352
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2353
+ ColorPicker,
2354
+ {
2355
+ label: "Text color",
2356
+ icon: "palette",
2357
+ colors: TEXT_COLORS,
2358
+ current: s.color,
2359
+ resetLabel: "Default color",
2360
+ onPick: (c) => run().setColor(c).run(),
2361
+ onReset: () => run().unsetColor().run()
2362
+ }
2363
+ ),
2364
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2365
+ ColorPicker,
2366
+ {
2367
+ label: "Highlight",
2368
+ icon: "highlighter",
2369
+ colors: HIGHLIGHT_COLORS,
2370
+ current: s.highlight,
2371
+ resetLabel: "No highlight",
2372
+ onPick: (c) => run().setHighlight({ color: c }).run(),
2373
+ onReset: () => run().unsetHighlight().run()
2374
+ }
2375
+ ),
2376
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "june-doc__bubble-sep", "aria-hidden": "true" }),
2377
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Btn, { label: "Clear formatting", icon: "eraser", onClick: () => run().unsetAllMarks().run() })
2378
+ ]
2379
+ }
2380
+ );
2381
+ }
2382
+
2383
+ // src/components/document-editor/document-content.tsx
2384
+ var import_react11 = require("@tiptap/react");
2385
+ var import_react12 = require("react");
2386
+ var import_jsx_runtime9 = require("react/jsx-runtime");
2387
+ var PAGE_HEIGHT = 1123;
2388
+ var PAGE_PAD_Y = 96;
2389
+ function DocumentContent({ editor, layout = "page", zoom = 1, showMarks = false, onMetrics }) {
2390
+ const canvas = (0, import_react12.useRef)(null);
2391
+ const sheet = (0, import_react12.useRef)(null);
2392
+ const [pages, setPages] = (0, import_react12.useState)(1);
2393
+ const metricsRef = (0, import_react12.useRef)(onMetrics);
2394
+ metricsRef.current = onMetrics;
2395
+ const last = (0, import_react12.useRef)({ page: 0, pages: 0 });
2396
+ (0, import_react12.useEffect)(() => {
2397
+ const c = canvas.current;
2398
+ const p = sheet.current;
2399
+ const prose = editor?.view.dom;
2400
+ if (!c || !p || !prose) return;
2401
+ const measure = () => {
2402
+ const contentH = prose.getBoundingClientRect().height / zoom;
2403
+ const total = layout === "page" ? Math.max(1, Math.ceil((contentH + PAGE_PAD_Y * 2) / PAGE_HEIGHT)) : 1;
2404
+ const cRect = c.getBoundingClientRect();
2405
+ const pRect = p.getBoundingClientRect();
2406
+ const y = cRect.top + c.clientHeight * 0.35 - pRect.top;
2407
+ const page = Math.min(total, Math.max(1, Math.floor(y / (PAGE_HEIGHT * zoom)) + 1));
2408
+ setPages(total);
2409
+ if (last.current.page !== page || last.current.pages !== total) {
2410
+ last.current = { page, pages: total };
2411
+ metricsRef.current?.({ page, pages: total });
2412
+ }
2413
+ };
2414
+ measure();
2415
+ c.addEventListener("scroll", measure, { passive: true });
2416
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(measure) : null;
2417
+ ro?.observe(prose);
2418
+ ro?.observe(c);
2419
+ editor?.on("update", measure);
2420
+ return () => {
2421
+ c.removeEventListener("scroll", measure);
2422
+ ro?.disconnect();
2423
+ editor?.off("update", measure);
2424
+ };
2425
+ }, [editor, layout, zoom]);
2426
+ const sheetStyle = layout === "page" ? {
2427
+ zoom,
2428
+ minHeight: pages * PAGE_HEIGHT,
2429
+ maxWidth: `calc(100% / ${zoom})`,
2430
+ "--jd-page-h": `${PAGE_HEIGHT}px`
2431
+ } : { zoom };
2432
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { ref: canvas, className: "june-doc__content june-doc__canvas", "data-layout": layout, "data-marks": showMarks || void 0, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { ref: sheet, className: "june-doc__sheet", style: sheetStyle, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react11.EditorContent, { editor }) }) });
2433
+ }
2434
+
2435
+ // src/components/document-editor/document-findbar.tsx
2436
+ var import_react13 = require("@tiptap/react");
2437
+ var import_react14 = require("react");
2438
+ init_document_search();
2439
+ var import_jsx_runtime10 = require("react/jsx-runtime");
2440
+ function DocumentFindBar({ editor, editable, onClose, onNotice }) {
2441
+ const [term, setTerm] = (0, import_react14.useState)(() => {
2442
+ const { from, to, empty } = editor.state.selection;
2443
+ return empty ? "" : editor.state.doc.textBetween(from, to, " ").slice(0, 100);
2444
+ });
2445
+ const [replacement, setReplacement] = (0, import_react14.useState)("");
2446
+ const [caseSensitive, setCaseSensitive] = (0, import_react14.useState)(false);
2447
+ const input = (0, import_react14.useRef)(null);
2448
+ const info = (0, import_react13.useEditorState)({
2449
+ editor,
2450
+ selector: ({ editor: ed }) => {
2451
+ const s = getSearchState(ed);
2452
+ return { count: s?.matches.length ?? 0, current: s?.current ?? -1 };
2453
+ }
2454
+ });
2455
+ (0, import_react14.useEffect)(() => {
2456
+ input.current?.focus();
2457
+ input.current?.select();
2458
+ }, []);
2459
+ (0, import_react14.useEffect)(() => {
2460
+ setSearch(editor, { term, caseSensitive, current: 0 });
2461
+ }, [editor, term, caseSensitive]);
2462
+ (0, import_react14.useEffect)(() => () => {
2463
+ if (!editor.isDestroyed) setSearch(editor, { term: "" });
2464
+ }, [editor]);
2465
+ const count = info?.count ?? 0;
2466
+ const current = info?.current ?? -1;
2467
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2468
+ "div",
2469
+ {
2470
+ className: "june-doc__findbar",
2471
+ role: "search",
2472
+ onKeyDown: (e) => {
2473
+ if (e.key === "Escape") {
2474
+ e.stopPropagation();
2475
+ onClose();
2476
+ editor.commands.focus();
2477
+ }
2478
+ },
2479
+ children: [
2480
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "june-doc__find-field", children: [
2481
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Icon, { name: "search", size: 14 }),
2482
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2483
+ "input",
2484
+ {
2485
+ ref: input,
2486
+ className: "june-doc__find-input",
2487
+ "aria-label": "Find in document",
2488
+ placeholder: "Find in document",
2489
+ value: term,
2490
+ onChange: (e) => setTerm(e.target.value),
2491
+ onKeyDown: (e) => {
2492
+ if (e.key === "Enter") {
2493
+ e.preventDefault();
2494
+ gotoMatch(editor, e.shiftKey ? -1 : 1);
2495
+ }
2496
+ }
2497
+ }
2498
+ ),
2499
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "june-doc__find-count", "aria-live": "polite", children: term ? count ? `${current + 1} of ${count}` : "No results" : "" })
2500
+ ] }),
2501
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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__ */ (0, import_jsx_runtime10.jsx)(Icon, { name: "chevronUp" }) }),
2502
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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__ */ (0, import_jsx_runtime10.jsx)(Icon, { name: "chevronDown" }) }),
2503
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2504
+ "button",
2505
+ {
2506
+ type: "button",
2507
+ className: "june-doc__btn june-doc__btn--icon june-doc__btn--case",
2508
+ "aria-label": "Match case",
2509
+ title: "Match case",
2510
+ "aria-pressed": caseSensitive,
2511
+ "data-active": caseSensitive || void 0,
2512
+ onClick: () => setCaseSensitive((v) => !v),
2513
+ children: "Aa"
2514
+ }
2515
+ ),
2516
+ editable ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
2517
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "june-doc__find-sep", "aria-hidden": "true" }),
2518
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2519
+ "input",
2520
+ {
2521
+ className: "june-doc__input june-doc__replace-input",
2522
+ "aria-label": "Replace with",
2523
+ placeholder: "Replace with",
2524
+ value: replacement,
2525
+ onChange: (e) => setReplacement(e.target.value),
2526
+ onKeyDown: (e) => {
2527
+ if (e.key === "Enter") {
2528
+ e.preventDefault();
2529
+ replaceCurrent(editor, replacement);
2530
+ }
2531
+ }
2532
+ }
2533
+ ),
2534
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "june-doc__btn", disabled: !count, onClick: () => replaceCurrent(editor, replacement), children: "Replace" }),
2535
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2536
+ "button",
2537
+ {
2538
+ type: "button",
2539
+ className: "june-doc__btn",
2540
+ disabled: !count,
2541
+ onClick: () => {
2542
+ const n = replaceAll(editor, replacement);
2543
+ onNotice(`Replaced ${n} ${n === 1 ? "match" : "matches"}`);
2544
+ },
2545
+ children: "Replace all"
2546
+ }
2547
+ )
2548
+ ] }) : null,
2549
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("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__ */ (0, import_jsx_runtime10.jsx)(Icon, { name: "close" }) })
2550
+ ]
2551
+ }
2552
+ );
2553
+ }
2554
+
2555
+ // src/components/document-editor/document-title.tsx
2556
+ var import_jsx_runtime11 = require("react/jsx-runtime");
2557
+ function DocumentTitle({ value, disabled, onChange }) {
2558
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2559
+ "input",
2560
+ {
2561
+ className: "june-doc__title",
2562
+ "aria-label": "Document title",
2563
+ value,
2564
+ disabled,
2565
+ placeholder: "Untitled document",
2566
+ onChange: (e) => onChange(e.target.value)
2567
+ }
2568
+ );
2569
+ }
2570
+
2571
+ // src/components/document-editor/document-header.tsx
2572
+ var import_jsx_runtime12 = require("react/jsx-runtime");
2573
+ var FORMATS = {
2574
+ docx: { label: "Word document", hint: ".docx", icon: "file" },
2575
+ pdf: { label: "PDF", hint: "Print / Save as PDF", icon: "file" },
2576
+ html: { label: "Web page", hint: ".html", icon: "code" },
2577
+ markdown: { label: "Markdown", hint: ".md", icon: "file" },
2578
+ txt: { label: "Plain text", hint: ".txt", icon: "file" }
2579
+ };
2580
+ function DocumentHeader(props) {
2581
+ const { title, editable, isDraft, fullscreen, onToggleFullscreen, onTitle, exportFormats, canSave, saveState, onExport, onCopy, onSave } = props;
2582
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "june-doc__header", children: [
2583
+ fullscreen ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("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__ */ (0, import_jsx_runtime12.jsx)(Icon, { name: "close", size: 18 }) }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "june-doc__doc-icon", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Icon, { name: "file", size: 16 }) }),
2584
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(DocumentTitle, { value: title, disabled: !editable, onChange: onTitle }),
2585
+ isDraft ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "june-doc__badge", children: [
2586
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Icon, { name: "sparkles", size: 12 }),
2587
+ "AI draft"
2588
+ ] }) : null,
2589
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "june-doc__header-actions", children: [
2590
+ canSave ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2591
+ "button",
2592
+ {
2593
+ type: "button",
2594
+ className: "june-doc__btn june-doc__btn--outline",
2595
+ "aria-label": "Save",
2596
+ title: "Save (Ctrl+S)",
2597
+ disabled: saveState === "saving" || saveState === "saved" || saveState === "idle",
2598
+ onClick: onSave,
2599
+ children: [
2600
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Icon, { name: saveState === "saved" ? "check" : "save" }),
2601
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: saveState === "saving" ? "Saving\u2026" : saveState === "saved" ? "Saved" : "Save" })
2602
+ ]
2603
+ }
2604
+ ) : null,
2605
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2606
+ Dropdown,
2607
+ {
2608
+ align: "end",
2609
+ className: "june-doc__menu",
2610
+ trigger: ({ open, toggle }) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2611
+ "button",
2612
+ {
2613
+ type: "button",
2614
+ className: "june-doc__btn june-doc__btn--solid",
2615
+ "aria-label": "Download",
2616
+ "aria-haspopup": "menu",
2617
+ "aria-expanded": open,
2618
+ onClick: toggle,
2619
+ children: [
2620
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: "Download" }),
2621
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Icon, { name: "chevronDown", size: 14 })
2622
+ ]
2623
+ }
2624
+ ),
2625
+ children: (close) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { role: "menu", "aria-label": "Download options", children: [
2626
+ exportFormats.map((f) => {
2627
+ const meta = FORMATS[f] ?? { label: f.toUpperCase(), hint: "", icon: "file" };
2628
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2629
+ "button",
2630
+ {
2631
+ type: "button",
2632
+ role: "menuitem",
2633
+ className: "june-doc__menu-item",
2634
+ onClick: () => {
2635
+ close();
2636
+ onExport(f);
2637
+ },
2638
+ children: [
2639
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Icon, { name: meta.icon }),
2640
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "june-doc__menu-label", children: meta.label }),
2641
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "june-doc__menu-hint", children: meta.hint })
2642
+ ]
2643
+ },
2644
+ f
2645
+ );
2646
+ }),
2647
+ exportFormats.length ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "june-doc__menu-sep", role: "separator" }) : null,
2648
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2649
+ "button",
2650
+ {
2651
+ type: "button",
2652
+ role: "menuitem",
2653
+ className: "june-doc__menu-item",
2654
+ "aria-label": "Copy document",
2655
+ onClick: () => {
2656
+ close();
2657
+ onCopy();
2658
+ },
2659
+ children: [
2660
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Icon, { name: "copy" }),
2661
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "june-doc__menu-label", children: "Copy to clipboard" })
2662
+ ]
2663
+ }
2664
+ )
2665
+ ] })
2666
+ }
2667
+ ),
2668
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2669
+ "button",
2670
+ {
2671
+ type: "button",
2672
+ className: "june-doc__btn june-doc__btn--icon june-doc__btn--ghost",
2673
+ "aria-label": fullscreen ? "Exit full screen" : "Open full screen",
2674
+ title: fullscreen ? "Exit full screen" : "Open full screen",
2675
+ "aria-pressed": fullscreen,
2676
+ onClick: onToggleFullscreen,
2677
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Icon, { name: "maximize" })
2678
+ }
2679
+ )
2680
+ ] })
2681
+ ] });
1365
2682
  }
1366
2683
 
1367
2684
  // src/components/document-editor/document-editor.tsx
@@ -1371,7 +2688,7 @@ init_document_engine();
1371
2688
  init_errors();
1372
2689
  init_document_utils();
1373
2690
  var escapeHtml = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
1374
- var PRINT_CSS = 'body{font-family:system-ui,-apple-system,"Segoe UI",sans-serif;line-height:1.6;color:#111827;max-width:780px;margin:32px auto;padding:0 20px}h1,h2,h3{line-height:1.25}table{border-collapse:collapse;width:100%}th,td{border:1px solid #d1d5db;padding:6px 10px;text-align:left}blockquote{border-left:4px solid #d1d5db;margin:1em 0;padding-left:1em;color:#4b5563}pre,code{font-family:ui-monospace,Menlo,monospace;background:#f3f4f6}pre{padding:12px;overflow:auto}@media print{body{margin:0;max-width:none}}';
2691
+ var PRINT_CSS = 'body{font-family:system-ui,-apple-system,"Segoe UI",sans-serif;line-height:1.6;color:#111827;max-width:780px;margin:32px auto;padding:0 20px}h1,h2,h3{line-height:1.25}table{border-collapse:collapse;width:100%}th,td{border:1px solid #d1d5db;padding:6px 10px;text-align:left}blockquote{border-left:4px solid #d1d5db;margin:1em 0;padding-left:1em;color:#4b5563}pre,code{font-family:ui-monospace,Menlo,monospace;background:#f3f4f6}pre{padding:12px;overflow:auto}img{max-width:100%;height:auto}mark{padding:0 .1em;border-radius:2px}div[data-page-break]{break-after:page;page-break-after:always;height:0}@media screen{div[data-page-break]{border-top:1px dashed #d1d5db;margin:24px 0}}@media print{body{margin:0;max-width:none}}';
1375
2692
  function buildHtmlDocument(title, bodyHtml) {
1376
2693
  return `<!doctype html><html lang="en"><head><meta charset="utf-8"><title>${escapeHtml(
1377
2694
  title
@@ -1409,6 +2726,33 @@ var exportTxt = async (ctx) => {
1409
2726
  ${docToText2(ctx.json)}
1410
2727
  `, `${ctx.basename}.txt`, "text/plain");
1411
2728
  };
2729
+ function toDocxColor(value) {
2730
+ if (typeof value !== "string") return void 0;
2731
+ const v = value.trim();
2732
+ let m = /^#([0-9a-f]{3})$/i.exec(v);
2733
+ if (m) return m[1].split("").map((c) => c + c).join("").toUpperCase();
2734
+ m = /^#([0-9a-f]{6})$/i.exec(v);
2735
+ if (m) return m[1].toUpperCase();
2736
+ m = /^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/i.exec(v);
2737
+ if (m) {
2738
+ return [m[1], m[2], m[3]].map((n) => Math.min(255, Number(n)).toString(16).padStart(2, "0")).join("").toUpperCase();
2739
+ }
2740
+ return void 0;
2741
+ }
2742
+ function toHalfPoints(value) {
2743
+ if (typeof value !== "string") return void 0;
2744
+ const m = /^([\d.]+)\s*(px|pt)?$/i.exec(value.trim());
2745
+ if (!m) return void 0;
2746
+ const n = Number(m[1]);
2747
+ if (!Number.isFinite(n) || n <= 0) return void 0;
2748
+ const pt = m[2]?.toLowerCase() === "pt" ? n : n * 0.75;
2749
+ return Math.round(pt * 2);
2750
+ }
2751
+ function firstFontFamily(value) {
2752
+ if (typeof value !== "string") return void 0;
2753
+ const first = value.split(",")[0]?.trim().replace(/^['"]|['"]$/g, "");
2754
+ return first || void 0;
2755
+ }
1412
2756
  var ORDERED_REF = "june-ordered";
1413
2757
  var DOCX_MIME = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
1414
2758
  function runs(d, node, fmt) {
@@ -1422,14 +2766,21 @@ function runs(d, node, fmt) {
1422
2766
  const marks = child.marks ?? [];
1423
2767
  const has = (type) => marks.some((m) => m.type === type);
1424
2768
  const link = marks.find((m) => m.type === "link");
2769
+ const style = marks.find((m) => m.type === "textStyle")?.attrs ?? {};
2770
+ const highlight = marks.find((m) => m.type === "highlight");
2771
+ const fill = highlight ? toDocxColor(highlight.attrs?.color) ?? "FFF59D" : void 0;
1425
2772
  const run = new d.TextRun({
1426
2773
  text: child.text,
1427
2774
  bold: fmt.bold || has("bold") || void 0,
1428
2775
  italics: has("italic") || void 0,
1429
2776
  underline: has("underline") || link ? {} : void 0,
1430
2777
  strike: has("strike") || void 0,
1431
- font: has("code") ? "Courier New" : void 0,
1432
- color: link ? "0563C1" : void 0
2778
+ superScript: has("superscript") || void 0,
2779
+ subScript: has("subscript") || void 0,
2780
+ font: has("code") ? "Courier New" : firstFontFamily(style.fontFamily),
2781
+ size: toHalfPoints(style.fontSize),
2782
+ color: toDocxColor(style.color) ?? (link ? "0563C1" : void 0),
2783
+ shading: fill ? { type: d.ShadingType.CLEAR, fill, color: "auto" } : void 0
1433
2784
  });
1434
2785
  const href = typeof link?.attrs?.href === "string" ? sanitizeHref(link.attrs.href) : null;
1435
2786
  out.push(href ? new d.ExternalHyperlink({ link: href, children: [run] }) : run);
@@ -1498,6 +2849,100 @@ function table(d, node, state) {
1498
2849
  if (rows.length === 0) return new d.Paragraph("");
1499
2850
  return new d.Table({ rows, width: { size: 100, type: d.WidthType.PERCENTAGE } });
1500
2851
  }
2852
+ function image(d, node, state) {
2853
+ const src = typeof node.attrs?.src === "string" ? node.attrs.src : "";
2854
+ const alt = typeof node.attrs?.alt === "string" ? node.attrs.alt : "";
2855
+ const img = state.images.get(src);
2856
+ if (img) {
2857
+ return [
2858
+ new d.Paragraph({
2859
+ children: [
2860
+ new d.ImageRun({
2861
+ type: img.type,
2862
+ data: img.data,
2863
+ transformation: { width: img.width, height: img.height },
2864
+ altText: alt ? { name: alt, description: alt, title: alt } : void 0
2865
+ })
2866
+ ],
2867
+ spacing: { after: 120 }
2868
+ })
2869
+ ];
2870
+ }
2871
+ const href = src && !src.startsWith("data:") ? sanitizeHref(src) : null;
2872
+ if (!href) return [];
2873
+ return [
2874
+ new d.Paragraph({
2875
+ children: [
2876
+ new d.ExternalHyperlink({
2877
+ link: href,
2878
+ children: [new d.TextRun({ text: alt || href, color: "0563C1", underline: {} })]
2879
+ })
2880
+ ]
2881
+ })
2882
+ ];
2883
+ }
2884
+ function collectImages(nodes, out) {
2885
+ for (const node of nodes ?? []) {
2886
+ const src = node.attrs?.src;
2887
+ if (node.type === "image" && typeof src === "string" && src && !out.has(src)) out.set(src, node.attrs);
2888
+ if (node.content) collectImages(node.content, out);
2889
+ }
2890
+ return out;
2891
+ }
2892
+ var IMAGE_TYPES = {
2893
+ "image/png": "png",
2894
+ "image/jpeg": "jpg",
2895
+ "image/jpg": "jpg",
2896
+ "image/gif": "gif",
2897
+ "image/bmp": "bmp"
2898
+ };
2899
+ var MAX_IMAGE_WIDTH = 600;
2900
+ function naturalSize(blob) {
2901
+ const fallback = { width: 400, height: 300 };
2902
+ return new Promise((resolve) => {
2903
+ if (typeof Image === "undefined" || typeof URL.createObjectURL !== "function") return resolve(fallback);
2904
+ const url = URL.createObjectURL(blob);
2905
+ const img = new Image();
2906
+ const done = (size) => {
2907
+ URL.revokeObjectURL(url);
2908
+ resolve(size);
2909
+ };
2910
+ img.onload = () => done({ width: img.naturalWidth || 400, height: img.naturalHeight || 300 });
2911
+ img.onerror = () => done(fallback);
2912
+ img.src = url;
2913
+ });
2914
+ }
2915
+ async function loadImage(src, attrs) {
2916
+ try {
2917
+ const res = await fetch(src);
2918
+ if (!res.ok) return null;
2919
+ const blob = await res.blob();
2920
+ const type = IMAGE_TYPES[blob.type.toLowerCase()];
2921
+ if (!type) return null;
2922
+ const natural = await naturalSize(blob);
2923
+ let width = Number(attrs?.width) || natural.width;
2924
+ let height = Number(attrs?.height) || natural.height * width / natural.width;
2925
+ if (width > MAX_IMAGE_WIDTH) {
2926
+ height = height * MAX_IMAGE_WIDTH / width;
2927
+ width = MAX_IMAGE_WIDTH;
2928
+ }
2929
+ return { data: new Uint8Array(await blob.arrayBuffer()), type, width: Math.round(width), height: Math.round(height) };
2930
+ } catch {
2931
+ return null;
2932
+ }
2933
+ }
2934
+ async function resolveImages(doc) {
2935
+ const map = /* @__PURE__ */ new Map();
2936
+ if (typeof fetch !== "function") return map;
2937
+ const found = collectImages(doc.content, /* @__PURE__ */ new Map());
2938
+ await Promise.all(
2939
+ [...found].map(async ([src, attrs]) => {
2940
+ const info = await loadImage(src, attrs);
2941
+ if (info) map.set(src, info);
2942
+ })
2943
+ );
2944
+ return map;
2945
+ }
1501
2946
  function blocks(d, nodes, fmt, state) {
1502
2947
  const headings = [d.HeadingLevel.HEADING_1, d.HeadingLevel.HEADING_2, d.HeadingLevel.HEADING_3];
1503
2948
  const out = [];
@@ -1532,6 +2977,12 @@ function blocks(d, nodes, fmt, state) {
1532
2977
  case "table":
1533
2978
  out.push(table(d, node, state));
1534
2979
  break;
2980
+ case "pageBreak":
2981
+ out.push(new d.Paragraph({ children: [new d.PageBreak()] }));
2982
+ break;
2983
+ case "image":
2984
+ out.push(...image(d, node, state));
2985
+ break;
1535
2986
  default:
1536
2987
  if (node.content) out.push(...blocks(d, node.content, fmt, state));
1537
2988
  }
@@ -1540,7 +2991,7 @@ function blocks(d, nodes, fmt, state) {
1540
2991
  }
1541
2992
  var exportDocx = async (ctx) => {
1542
2993
  const d = await import("docx");
1543
- const state = { instance: 0 };
2994
+ const state = { instance: 0, images: await resolveImages(ctx.json) };
1544
2995
  const children = [
1545
2996
  new d.Paragraph({ text: ctx.title, heading: d.HeadingLevel.TITLE }),
1546
2997
  ...blocks(d, ctx.json.content, {}, state)
@@ -1871,190 +3322,6 @@ function getDefaultDocumentStore() {
1871
3322
  return defaultStore;
1872
3323
  }
1873
3324
 
1874
- // src/components/document-editor/document-title.tsx
1875
- var import_jsx_runtime6 = require("react/jsx-runtime");
1876
- function DocumentTitle({ value, disabled, onChange }) {
1877
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1878
- "input",
1879
- {
1880
- className: "june-doc__title",
1881
- "aria-label": "Document title",
1882
- value,
1883
- disabled,
1884
- placeholder: "Untitled document",
1885
- onChange: (e) => onChange(e.target.value)
1886
- }
1887
- );
1888
- }
1889
-
1890
- // src/components/document-editor/document-toolbar.tsx
1891
- var import_react8 = require("@tiptap/react");
1892
- var import_react9 = require("react");
1893
- init_document_utils();
1894
- var import_jsx_runtime7 = require("react/jsx-runtime");
1895
- var FORMAT_LABELS = {
1896
- html: "HTML",
1897
- markdown: "Markdown",
1898
- txt: "Plain text",
1899
- docx: "Word (.docx)",
1900
- pdf: "PDF (print)"
1901
- };
1902
- function Btn({ label, active, disabled, toggle, onClick, children }) {
1903
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1904
- "button",
1905
- {
1906
- type: "button",
1907
- className: "june-doc__btn",
1908
- "aria-label": label,
1909
- title: label,
1910
- "aria-pressed": toggle ? !!active : void 0,
1911
- "data-active": active || void 0,
1912
- disabled,
1913
- onMouseDown: (e) => e.preventDefault(),
1914
- onClick,
1915
- children
1916
- }
1917
- );
1918
- }
1919
- function DocumentToolbar(props) {
1920
- const { editor, editable, exportFormats, canSave, saveState, onExport, onCopy, onSave } = props;
1921
- const [linkOpen, setLinkOpen] = (0, import_react9.useState)(false);
1922
- const [linkValue, setLinkValue] = (0, import_react9.useState)("");
1923
- const s = (0, import_react8.useEditorState)({
1924
- editor,
1925
- selector: ({ editor: ed }) => ed ? {
1926
- bold: ed.isActive("bold"),
1927
- italic: ed.isActive("italic"),
1928
- underline: ed.isActive("underline"),
1929
- strike: ed.isActive("strike"),
1930
- bullet: ed.isActive("bulletList"),
1931
- ordered: ed.isActive("orderedList"),
1932
- quote: ed.isActive("blockquote"),
1933
- link: ed.isActive("link"),
1934
- linkHref: ed.getAttributes("link").href ?? "",
1935
- h1: ed.isActive("heading", { level: 1 }),
1936
- h2: ed.isActive("heading", { level: 2 }),
1937
- h3: ed.isActive("heading", { level: 3 }),
1938
- left: ed.isActive({ textAlign: "left" }),
1939
- center: ed.isActive({ textAlign: "center" }),
1940
- right: ed.isActive({ textAlign: "right" }),
1941
- justify: ed.isActive({ textAlign: "justify" }),
1942
- inTable: ed.isActive("table"),
1943
- canUndo: ed.can().undo(),
1944
- canRedo: ed.can().redo()
1945
- } : null
1946
- });
1947
- const run = () => editor?.chain().focus();
1948
- const off = !editor || !editable;
1949
- const heading = s?.h1 ? "1" : s?.h2 ? "2" : s?.h3 ? "3" : "p";
1950
- const openLink = () => {
1951
- setLinkValue(s?.linkHref ?? "");
1952
- setLinkOpen(true);
1953
- };
1954
- const applyLink = () => {
1955
- const href = sanitizeHref(linkValue);
1956
- if (href) run()?.extendMarkRange("link").setLink({ href }).run();
1957
- setLinkOpen(false);
1958
- };
1959
- const removeLink = () => {
1960
- run()?.extendMarkRange("link").unsetLink().run();
1961
- setLinkOpen(false);
1962
- };
1963
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__toolbar", role: "toolbar", "aria-label": "Document formatting", children: [
1964
- editable ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1965
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__group", children: [
1966
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Undo", disabled: off || !s?.canUndo, onClick: () => run()?.undo().run(), children: "\u21B6" }),
1967
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Redo", disabled: off || !s?.canRedo, onClick: () => run()?.redo().run(), children: "\u21B7" })
1968
- ] }),
1969
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "june-doc__group", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1970
- "select",
1971
- {
1972
- className: "june-doc__select",
1973
- "aria-label": "Text style",
1974
- disabled: off,
1975
- value: heading,
1976
- onChange: (e) => {
1977
- const v = e.target.value;
1978
- if (v === "p") run()?.setParagraph().run();
1979
- else run()?.toggleHeading({ level: Number(v) }).run();
1980
- },
1981
- children: [
1982
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "p", children: "Paragraph" }),
1983
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "1", children: "Heading 1" }),
1984
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "2", children: "Heading 2" }),
1985
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "3", children: "Heading 3" })
1986
- ]
1987
- }
1988
- ) }),
1989
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__group", children: [
1990
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Bold", toggle: true, active: s?.bold, disabled: off, onClick: () => run()?.toggleBold().run(), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("b", { children: "B" }) }),
1991
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Italic", toggle: true, active: s?.italic, disabled: off, onClick: () => run()?.toggleItalic().run(), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("i", { children: "I" }) }),
1992
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Underline", toggle: true, active: s?.underline, disabled: off, onClick: () => run()?.toggleUnderline().run(), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("u", { children: "U" }) }),
1993
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Strikethrough", toggle: true, active: s?.strike, disabled: off, onClick: () => run()?.toggleStrike().run(), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("s", { children: "S" }) })
1994
- ] }),
1995
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__group", children: [
1996
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Bullet list", toggle: true, active: s?.bullet, disabled: off, onClick: () => run()?.toggleBulletList().run(), children: "\u2022 List" }),
1997
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Numbered list", toggle: true, active: s?.ordered, disabled: off, onClick: () => run()?.toggleOrderedList().run(), children: "1. List" }),
1998
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Blockquote", toggle: true, active: s?.quote, disabled: off, onClick: () => run()?.toggleBlockquote().run(), children: "Quote" }),
1999
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Link", toggle: true, active: s?.link, disabled: off, onClick: openLink, children: "Link" })
2000
- ] }),
2001
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__group", children: [
2002
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Align left", toggle: true, active: s?.left, disabled: off, onClick: () => run()?.setTextAlign("left").run(), children: "L" }),
2003
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Align center", toggle: true, active: s?.center, disabled: off, onClick: () => run()?.setTextAlign("center").run(), children: "C" }),
2004
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Align right", toggle: true, active: s?.right, disabled: off, onClick: () => run()?.setTextAlign("right").run(), children: "R" }),
2005
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Justify", toggle: true, active: s?.justify, disabled: off, onClick: () => run()?.setTextAlign("justify").run(), children: "J" })
2006
- ] }),
2007
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__group", children: [
2008
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Insert table", disabled: off, onClick: () => run()?.insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run(), children: "Table" }),
2009
- s?.inTable ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
2010
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Add row below", disabled: off, onClick: () => run()?.addRowAfter().run(), children: "+Row" }),
2011
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Add column right", disabled: off, onClick: () => run()?.addColumnAfter().run(), children: "+Col" }),
2012
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Delete row", disabled: off, onClick: () => run()?.deleteRow().run(), children: "\u2212Row" }),
2013
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Delete column", disabled: off, onClick: () => run()?.deleteColumn().run(), children: "\u2212Col" }),
2014
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Delete table", disabled: off, onClick: () => run()?.deleteTable().run(), children: "Del table" })
2015
- ] }) : null
2016
- ] })
2017
- ] }) : null,
2018
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__group june-doc__group--end", children: [
2019
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Copy document", onClick: onCopy, children: "Copy" }),
2020
- exportFormats.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2021
- "select",
2022
- {
2023
- className: "june-doc__select",
2024
- "aria-label": "Export document",
2025
- value: "",
2026
- onChange: (e) => e.target.value && onExport(e.target.value),
2027
- children: [
2028
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "", children: "Export\u2026" }),
2029
- exportFormats.map((f) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: f, children: FORMAT_LABELS[f] ?? f }, f))
2030
- ]
2031
- }
2032
- ) : null,
2033
- canSave ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Save", disabled: saveState === "saving" || saveState === "saved" || saveState === "idle", onClick: onSave, children: "Save" }) : null
2034
- ] }),
2035
- linkOpen ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__linkbar", children: [
2036
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2037
- "input",
2038
- {
2039
- "aria-label": "Link address",
2040
- className: "june-doc__input",
2041
- placeholder: "https://example.com",
2042
- value: linkValue,
2043
- autoFocus: true,
2044
- onChange: (e) => setLinkValue(e.target.value),
2045
- onKeyDown: (e) => {
2046
- if (e.key === "Enter") applyLink();
2047
- if (e.key === "Escape") setLinkOpen(false);
2048
- }
2049
- }
2050
- ),
2051
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "june-doc__btn", onClick: applyLink, children: "Apply" }),
2052
- s?.link ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "june-doc__btn", onClick: removeLink, children: "Remove" }) : null,
2053
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "june-doc__btn", onClick: () => setLinkOpen(false), children: "Cancel" })
2054
- ] }) : null
2055
- ] });
2056
- }
2057
-
2058
3325
  // src/components/document-editor/document-types.ts
2059
3326
  var ALL_EXPORT_FORMATS = [
2060
3327
  "html",
@@ -2066,7 +3333,7 @@ var ALL_EXPORT_FORMATS = [
2066
3333
 
2067
3334
  // src/components/document-editor/document-editor.tsx
2068
3335
  init_document_utils();
2069
- var import_jsx_runtime8 = require("react/jsx-runtime");
3336
+ var import_jsx_runtime13 = require("react/jsx-runtime");
2070
3337
  var snapshotOf = (r) => ({
2071
3338
  documentId: r.id,
2072
3339
  title: r.title,
@@ -2081,6 +3348,8 @@ var SAVE_LABEL = {
2081
3348
  saved: "Saved",
2082
3349
  error: "Save failed"
2083
3350
  };
3351
+ var ZOOM_STEPS = [0.5, 0.67, 0.75, 0.9, 1, 1.1, 1.25, 1.5, 1.75, 2];
3352
+ var stepZoom = (z2, dir) => dir > 0 ? ZOOM_STEPS.find((s) => s > z2 + 1e-3) ?? z2 : [...ZOOM_STEPS].reverse().find((s) => s < z2 - 1e-3) ?? z2;
2084
3353
  function DocumentEditorImpl(props) {
2085
3354
  const {
2086
3355
  documentId,
@@ -2094,15 +3363,15 @@ function DocumentEditorImpl(props) {
2094
3363
  className
2095
3364
  } = props;
2096
3365
  const ctxOptions = useDocumentOptions();
2097
- const options = (0, import_react11.useMemo)(() => ({ ...ctxOptions, ...props.options }), [ctxOptions, props.options]);
2098
- const optionsRef = (0, import_react11.useRef)(options);
3366
+ const options = (0, import_react16.useMemo)(() => ({ ...ctxOptions, ...props.options }), [ctxOptions, props.options]);
3367
+ const optionsRef = (0, import_react16.useRef)(options);
2099
3368
  optionsRef.current = options;
2100
- const store = (0, import_react11.useMemo)(() => options.store ?? getDefaultDocumentStore(), [options.store]);
2101
- const instanceId = (0, import_react11.useId)();
3369
+ const store = (0, import_react16.useMemo)(() => options.store ?? getDefaultDocumentStore(), [options.store]);
3370
+ const instanceId = (0, import_react16.useId)();
2102
3371
  const { theme: contextTheme } = useJuneTheme();
2103
3372
  const resolvedTheme = theme === "auto" ? contextTheme : theme;
2104
3373
  const contentKey = typeof content === "string" ? content : content ? JSON.stringify(content) : "";
2105
- const parsed = (0, import_react11.useMemo)(() => {
3374
+ const parsed = (0, import_react16.useMemo)(() => {
2106
3375
  if (!contentKey) return { json: null, error: null };
2107
3376
  try {
2108
3377
  return { json: parseDocumentContent(contentKey), error: null };
@@ -2110,40 +3379,55 @@ function DocumentEditorImpl(props) {
2110
3379
  return { json: null, error: toJuneError(e, "DOCUMENT_ERROR") };
2111
3380
  }
2112
3381
  }, [contentKey]);
2113
- (0, import_react11.useEffect)(() => {
3382
+ (0, import_react16.useEffect)(() => {
2114
3383
  if (parsed.error) optionsRef.current.onError?.(parsed.error);
2115
3384
  }, [parsed.error]);
2116
3385
  const title = useDocumentValue(store, documentId, (r) => r?.title ?? titleProp);
2117
3386
  const pending = useDocumentValue(store, documentId, (r) => r?.pending ?? null);
2118
3387
  const words = useDocumentValue(store, documentId, (r) => r ? wordCountOf(r.json) : 0);
2119
3388
  const recordStatus = useDocumentValue(store, documentId, (r) => r?.status ?? status);
2120
- const [saveState, setSaveState] = (0, import_react11.useState)("idle");
2121
- const [notice, setNotice] = (0, import_react11.useState)(null);
2122
- const lastSavedKey = (0, import_react11.useRef)("");
2123
- const seenRevision = (0, import_react11.useRef)(store.get(documentId)?.revision ?? 0);
2124
- const readyRef = (0, import_react11.useRef)(false);
2125
- const flash = (0, import_react11.useCallback)((message) => {
3389
+ const [saveState, setSaveState] = (0, import_react16.useState)("idle");
3390
+ const [notice, setNotice] = (0, import_react16.useState)(null);
3391
+ const [fullscreen, setFullscreen] = (0, import_react16.useState)(false);
3392
+ const [expanded, setExpanded] = (0, import_react16.useState)(true);
3393
+ const [showMarks, setShowMarks] = (0, import_react16.useState)(false);
3394
+ const [layout, setLayout] = (0, import_react16.useState)("page");
3395
+ const [findOpen, setFindOpen] = (0, import_react16.useState)(false);
3396
+ const [zoom, setZoom] = (0, import_react16.useState)(1);
3397
+ const [metrics, setMetrics] = (0, import_react16.useState)({ page: 1, pages: 1 });
3398
+ (0, import_react16.useEffect)(() => {
3399
+ if (!fullscreen || typeof document === "undefined") return;
3400
+ const prev = document.body.style.overflow;
3401
+ document.body.style.overflow = "hidden";
3402
+ return () => {
3403
+ document.body.style.overflow = prev;
3404
+ };
3405
+ }, [fullscreen]);
3406
+ const lastSavedKey = (0, import_react16.useRef)("");
3407
+ const seenRevision = (0, import_react16.useRef)(store.get(documentId)?.revision ?? 0);
3408
+ const readyRef = (0, import_react16.useRef)(false);
3409
+ const flash = (0, import_react16.useCallback)((message) => {
2126
3410
  setNotice(message);
2127
3411
  }, []);
2128
- (0, import_react11.useEffect)(() => {
3412
+ (0, import_react16.useEffect)(() => {
2129
3413
  if (!notice) return;
2130
3414
  const t = setTimeout(() => setNotice(null), 3e3);
2131
3415
  return () => clearTimeout(t);
2132
3416
  }, [notice]);
2133
- const emitChange = (0, import_react11.useCallback)(
3417
+ const emitChange = (0, import_react16.useCallback)(
2134
3418
  (source) => {
2135
3419
  const record = store.get(documentId);
2136
3420
  if (record) optionsRef.current.onDocumentChange?.({ ...snapshotOf(record), source });
2137
3421
  },
2138
3422
  [store, documentId]
2139
3423
  );
2140
- const saveRef = (0, import_react11.useRef)(async () => {
3424
+ const saveRef = (0, import_react16.useRef)(async () => {
2141
3425
  });
2142
- const autosave = (0, import_react11.useMemo)(() => {
3426
+ const autosave = (0, import_react16.useMemo)(() => {
2143
3427
  const delay = options.autosaveDelay ?? 1500;
2144
3428
  return delay > 0 ? debounce(() => void saveRef.current(), delay) : null;
2145
3429
  }, [options.autosaveDelay]);
2146
- (0, import_react11.useEffect)(() => () => autosave?.flush(), [autosave]);
3430
+ (0, import_react16.useEffect)(() => () => autosave?.flush(), [autosave]);
2147
3431
  saveRef.current = async () => {
2148
3432
  const record = store.get(documentId);
2149
3433
  const onSave = optionsRef.current.onSave;
@@ -2169,21 +3453,21 @@ function DocumentEditorImpl(props) {
2169
3453
  optionsRef.current.onError?.(toJuneError(error, "DOCUMENT_ERROR", "Saving the document failed"));
2170
3454
  }
2171
3455
  };
2172
- const markDirty = (0, import_react11.useCallback)(() => {
3456
+ const markDirty = (0, import_react16.useCallback)(() => {
2173
3457
  if (!optionsRef.current.onSave) return;
2174
3458
  setSaveState("dirty");
2175
3459
  autosave?.();
2176
3460
  }, [autosave]);
2177
- const [initialJson] = (0, import_react11.useState)(() => store.get(documentId)?.json ?? parsed.json ?? emptyDoc());
2178
- const extensions = (0, import_react11.useMemo)(() => createDocumentExtensions(), []);
2179
- const onUpdateRef = (0, import_react11.useRef)(() => {
3461
+ const [initialJson] = (0, import_react16.useState)(() => store.get(documentId)?.json ?? parsed.json ?? emptyDoc());
3462
+ const extensions = (0, import_react16.useMemo)(() => createDocumentExtensions(), []);
3463
+ const onUpdateRef = (0, import_react16.useRef)(() => {
2180
3464
  });
2181
3465
  onUpdateRef.current = (json) => {
2182
3466
  store.edit(documentId, json, instanceId);
2183
3467
  emitChange("user");
2184
3468
  markDirty();
2185
3469
  };
2186
- const editor = (0, import_react10.useEditor)({
3470
+ const editor = (0, import_react15.useEditor)({
2187
3471
  extensions,
2188
3472
  content: initialJson,
2189
3473
  editable,
@@ -2198,10 +3482,10 @@ function DocumentEditorImpl(props) {
2198
3482
  },
2199
3483
  onUpdate: ({ editor: ed }) => onUpdateRef.current(ed.getJSON())
2200
3484
  });
2201
- (0, import_react11.useEffect)(() => {
3485
+ (0, import_react16.useEffect)(() => {
2202
3486
  editor?.setEditable(editable);
2203
3487
  }, [editor, editable]);
2204
- (0, import_react11.useEffect)(() => {
3488
+ (0, import_react16.useEffect)(() => {
2205
3489
  if (!parsed.json) return;
2206
3490
  const outcome = store.receive({
2207
3491
  id: documentId,
@@ -2222,7 +3506,7 @@ function DocumentEditorImpl(props) {
2222
3506
  });
2223
3507
  }
2224
3508
  }, [store, documentId, titleProp, parsed.json, documentType, status, emitChange, markDirty]);
2225
- (0, import_react11.useEffect)(() => {
3509
+ (0, import_react16.useEffect)(() => {
2226
3510
  if (!editor) return;
2227
3511
  const apply = () => {
2228
3512
  const record = store.get(documentId);
@@ -2239,7 +3523,7 @@ function DocumentEditorImpl(props) {
2239
3523
  apply();
2240
3524
  return store.subscribe(apply);
2241
3525
  }, [editor, store, documentId, instanceId]);
2242
- (0, import_react11.useEffect)(() => {
3526
+ (0, import_react16.useEffect)(() => {
2243
3527
  if (!editor || readyRef.current) return;
2244
3528
  const record = store.get(documentId);
2245
3529
  if (!record) return;
@@ -2283,67 +3567,114 @@ function DocumentEditorImpl(props) {
2283
3567
  };
2284
3568
  const formats = (exportFormats ?? [...ALL_EXPORT_FORMATS]).filter((f) => listDocumentExporters().includes(f));
2285
3569
  if (parsed.error && !store.get(documentId)) {
2286
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "june-doc june-doc--error", "data-theme": resolvedTheme, role: "alert", children: [
2287
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "june-doc__draft-text", children: "This document could not be displayed." }),
2288
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("details", { children: [
2289
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("summary", { children: "Show raw content" }),
2290
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("pre", { className: "june-doc__raw", children: contentKey })
3570
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "june-doc june-doc--error", "data-theme": resolvedTheme, role: "alert", children: [
3571
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "june-doc__draft-text", children: "This document could not be displayed." }),
3572
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("details", { children: [
3573
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("summary", { children: "Show raw content" }),
3574
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("pre", { className: "june-doc__raw", children: contentKey })
2291
3575
  ] })
2292
3576
  ] });
2293
3577
  }
2294
- if (!editor) return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DocumentDraft, { title, state: "loading" });
3578
+ if (!editor) return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DocumentDraft, { title, state: "loading" });
2295
3579
  const isDraft = recordStatus === "draft";
2296
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
3580
+ const classes = ["june-doc", fullscreen ? "june-doc--fullscreen" : "", className ?? ""].filter(Boolean).join(" ");
3581
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2297
3582
  "div",
2298
3583
  {
2299
- className: className ? `june-doc ${className}` : "june-doc",
3584
+ className: classes,
2300
3585
  "data-theme": resolvedTheme,
2301
3586
  "data-status": recordStatus,
3587
+ role: fullscreen ? "dialog" : void 0,
3588
+ "aria-modal": fullscreen || void 0,
3589
+ "aria-label": fullscreen ? title : void 0,
2302
3590
  onKeyDown: (e) => {
2303
- if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "s" && options.onSave) {
3591
+ const mod = e.ctrlKey || e.metaKey;
3592
+ if (mod && e.key.toLowerCase() === "s" && options.onSave) {
2304
3593
  e.preventDefault();
2305
3594
  void saveRef.current();
3595
+ } else if (mod && e.key.toLowerCase() === "f") {
3596
+ e.preventDefault();
3597
+ setFindOpen(true);
3598
+ } else if (e.key === "Escape" && fullscreen && !e.defaultPrevented) {
3599
+ setFullscreen(false);
2306
3600
  }
2307
3601
  },
2308
3602
  children: [
2309
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "june-doc__header", children: [
2310
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DocumentTitle, { value: title, disabled: !editable, onChange: handleTitle }),
2311
- isDraft ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "june-doc__badge", children: "AI draft" }) : null
2312
- ] }),
2313
- pending ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "june-doc__banner", role: "status", children: [
2314
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
3603
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3604
+ DocumentHeader,
3605
+ {
3606
+ title,
3607
+ editable,
3608
+ isDraft,
3609
+ fullscreen,
3610
+ onToggleFullscreen: () => setFullscreen((v) => !v),
3611
+ onTitle: handleTitle,
3612
+ exportFormats: formats,
3613
+ canSave: !!options.onSave,
3614
+ saveState,
3615
+ onExport: (f) => void handleExport(f),
3616
+ onCopy: () => void handleCopy(),
3617
+ onSave: () => void saveRef.current()
3618
+ }
3619
+ ),
3620
+ pending ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "june-doc__banner", role: "status", children: [
3621
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { children: [
2315
3622
  "The assistant suggested changes that overlap your edits (",
2316
3623
  pending.conflicts,
2317
3624
  " ",
2318
3625
  pending.conflicts === 1 ? "section" : "sections",
2319
3626
  ")."
2320
3627
  ] }),
2321
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "june-doc__banner-actions", children: [
2322
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "june-doc__btn", onClick: () => resolve("merge"), children: "Merge, keep my edits" }),
2323
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "june-doc__btn", onClick: () => resolve("replace"), children: "Use AI version" }),
2324
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "june-doc__btn", onClick: () => resolve("keep"), children: "Keep mine" })
3628
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "june-doc__banner-actions", children: [
3629
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", className: "june-doc__btn", onClick: () => resolve("merge"), children: "Merge, keep my edits" }),
3630
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", className: "june-doc__btn", onClick: () => resolve("replace"), children: "Use AI version" }),
3631
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", className: "june-doc__btn", onClick: () => resolve("keep"), children: "Keep mine" })
2325
3632
  ] })
2326
3633
  ] }) : null,
2327
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3634
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2328
3635
  DocumentToolbar,
2329
3636
  {
2330
3637
  editor,
2331
3638
  editable,
2332
- exportFormats: formats,
2333
- canSave: !!options.onSave,
2334
- saveState,
2335
- onExport: (f) => void handleExport(f),
2336
- onCopy: () => void handleCopy(),
2337
- onSave: () => void saveRef.current()
3639
+ expanded,
3640
+ onToggleExpanded: () => setExpanded((v) => !v),
3641
+ showMarks,
3642
+ onToggleMarks: () => setShowMarks((v) => !v),
3643
+ layout,
3644
+ onToggleLayout: () => setLayout((v) => v === "page" ? "fluid" : "page"),
3645
+ findOpen,
3646
+ onToggleFind: () => setFindOpen((v) => !v),
3647
+ onNotice: flash
2338
3648
  }
2339
3649
  ),
2340
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DocumentContent, { editor }),
2341
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "june-doc__footer", "aria-live": "polite", children: [
2342
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
2343
- words,
2344
- " words"
3650
+ findOpen ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DocumentFindBar, { editor, editable, onClose: () => setFindOpen(false), onNotice: flash }) : null,
3651
+ editable ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DocumentBubbleMenu, { editor }) : null,
3652
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DocumentContent, { editor, layout, zoom, showMarks, onMetrics: setMetrics }),
3653
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "june-doc__footer", children: [
3654
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "june-doc__stats", children: [
3655
+ layout === "page" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
3656
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { children: [
3657
+ "Page ",
3658
+ metrics.page,
3659
+ " of ",
3660
+ metrics.pages
3661
+ ] }),
3662
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "june-doc__stats-sep", "aria-hidden": "true" })
3663
+ ] }) : null,
3664
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { children: [
3665
+ words,
3666
+ " words"
3667
+ ] })
2345
3668
  ] }),
2346
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: notice ?? SAVE_LABEL[saveState] })
3669
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "june-doc__status", "aria-live": "polite", "data-state": notice ? "notice" : saveState, children: notice ?? SAVE_LABEL[saveState] }),
3670
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "june-doc__zoom", role: "group", "aria-label": "Zoom", children: [
3671
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("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__ */ (0, import_jsx_runtime13.jsx)(Icon, { name: "minus", size: 14 }) }),
3672
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { type: "button", className: "june-doc__zoom-value", "aria-label": "Reset zoom", title: "Reset zoom", onClick: () => setZoom(1), children: [
3673
+ Math.round(zoom * 100),
3674
+ "%"
3675
+ ] }),
3676
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("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__ */ (0, import_jsx_runtime13.jsx)(Icon, { name: "plus", size: 14 }) })
3677
+ ] })
2347
3678
  ] })
2348
3679
  ]
2349
3680
  }
@@ -2351,7 +3682,7 @@ function DocumentEditorImpl(props) {
2351
3682
  }
2352
3683
 
2353
3684
  // src/components/document-editor/document-component.tsx
2354
- var import_jsx_runtime9 = require("react/jsx-runtime");
3685
+ var import_jsx_runtime14 = require("react/jsx-runtime");
2355
3686
  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.';
2356
3687
  var documentProps = import_v4.z.object({
2357
3688
  documentId: import_v4.z.string().describe("Stable id. Reuse it when revising the same document."),
@@ -2365,12 +3696,12 @@ var documentProps = import_v4.z.object({
2365
3696
  function DocumentEditor(props) {
2366
3697
  const { isStreaming } = useJuneRuntime();
2367
3698
  if (props.generating || isStreaming) {
2368
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DocumentDraft, { title: props.title, state: "drafting" });
3699
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocumentDraft, { title: props.title, state: "drafting" });
2369
3700
  }
2370
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DocumentEditorImpl, { ...props });
3701
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocumentEditorImpl, { ...props });
2371
3702
  }
2372
3703
  function OpenUIDocument({ props }) {
2373
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
3704
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2374
3705
  DocumentEditor,
2375
3706
  {
2376
3707
  documentId: props.documentId,
@@ -2390,11 +3721,15 @@ var JuneDocumentEditorComponent = (0, import_react_lang3.defineComponent)({
2390
3721
  component: OpenUIDocument
2391
3722
  });
2392
3723
  function withDocumentEditor(library) {
2393
- return library.extend({
2394
- components: {
2395
- add: [{ component: JuneDocumentEditorComponent, slots: ["Card"] }]
2396
- }
2397
- });
3724
+ try {
3725
+ return library.extend({
3726
+ components: {
3727
+ add: [{ component: JuneDocumentEditorComponent, slots: ["Card"] }]
3728
+ }
3729
+ });
3730
+ } catch {
3731
+ return library.extend({ components: { add: [JuneDocumentEditorComponent] } });
3732
+ }
2398
3733
  }
2399
3734
 
2400
3735
  // src/components/document-editor/document-instructions.ts
@@ -2454,9 +3789,9 @@ var import_react_ui = require("@openuidev/react-ui");
2454
3789
  var juneLibrary = withDocumentEditor(import_react_ui.openuiLibrary);
2455
3790
 
2456
3791
  // src/core/JuneUI.tsx
2457
- var import_jsx_runtime10 = require("react/jsx-runtime");
3792
+ var import_jsx_runtime15 = require("react/jsx-runtime");
2458
3793
  function JuneUI({ library = juneLibrary, ...props }) {
2459
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(JuneRenderer, { library, ...props });
3794
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(JuneRenderer, { library, ...props });
2460
3795
  }
2461
3796
  // Annotate the CommonJS export names for ESM import in node:
2462
3797
  0 && (module.exports = {