@june-ai/june-ui 0.2.3 → 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();
@@ -454,6 +623,7 @@ var ATTACHABLE = /* @__PURE__ */ new Set([
454
623
  "CodeBlock",
455
624
  "CompositeCardBlock",
456
625
  "ContextCardBlock",
626
+ "DocumentEditor",
457
627
  "EditableTable",
458
628
  "EntityList",
459
629
  "Form",
@@ -1352,15 +1522,1163 @@ function DocumentDraft({ title, words, state }) {
1352
1522
  }
1353
1523
 
1354
1524
  // src/components/document-editor/document-editor.tsx
1355
- var import_react10 = require("@tiptap/react");
1356
- var import_react11 = require("react");
1525
+ var import_react15 = require("@tiptap/react");
1526
+ var import_react16 = require("react");
1357
1527
  init_errors();
1358
1528
 
1359
- // src/components/document-editor/document-content.tsx
1360
- 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
1361
1538
  var import_jsx_runtime5 = require("react/jsx-runtime");
1362
- function DocumentContent({ editor }) {
1363
- 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
+ ] });
1364
2682
  }
1365
2683
 
1366
2684
  // src/components/document-editor/document-editor.tsx
@@ -1370,7 +2688,7 @@ init_document_engine();
1370
2688
  init_errors();
1371
2689
  init_document_utils();
1372
2690
  var escapeHtml = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
1373
- 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}}';
1374
2692
  function buildHtmlDocument(title, bodyHtml) {
1375
2693
  return `<!doctype html><html lang="en"><head><meta charset="utf-8"><title>${escapeHtml(
1376
2694
  title
@@ -1408,6 +2726,33 @@ var exportTxt = async (ctx) => {
1408
2726
  ${docToText2(ctx.json)}
1409
2727
  `, `${ctx.basename}.txt`, "text/plain");
1410
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
+ }
1411
2756
  var ORDERED_REF = "june-ordered";
1412
2757
  var DOCX_MIME = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
1413
2758
  function runs(d, node, fmt) {
@@ -1421,14 +2766,21 @@ function runs(d, node, fmt) {
1421
2766
  const marks = child.marks ?? [];
1422
2767
  const has = (type) => marks.some((m) => m.type === type);
1423
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;
1424
2772
  const run = new d.TextRun({
1425
2773
  text: child.text,
1426
2774
  bold: fmt.bold || has("bold") || void 0,
1427
2775
  italics: has("italic") || void 0,
1428
2776
  underline: has("underline") || link ? {} : void 0,
1429
2777
  strike: has("strike") || void 0,
1430
- font: has("code") ? "Courier New" : void 0,
1431
- 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
1432
2784
  });
1433
2785
  const href = typeof link?.attrs?.href === "string" ? sanitizeHref(link.attrs.href) : null;
1434
2786
  out.push(href ? new d.ExternalHyperlink({ link: href, children: [run] }) : run);
@@ -1497,6 +2849,100 @@ function table(d, node, state) {
1497
2849
  if (rows.length === 0) return new d.Paragraph("");
1498
2850
  return new d.Table({ rows, width: { size: 100, type: d.WidthType.PERCENTAGE } });
1499
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
+ }
1500
2946
  function blocks(d, nodes, fmt, state) {
1501
2947
  const headings = [d.HeadingLevel.HEADING_1, d.HeadingLevel.HEADING_2, d.HeadingLevel.HEADING_3];
1502
2948
  const out = [];
@@ -1531,6 +2977,12 @@ function blocks(d, nodes, fmt, state) {
1531
2977
  case "table":
1532
2978
  out.push(table(d, node, state));
1533
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;
1534
2986
  default:
1535
2987
  if (node.content) out.push(...blocks(d, node.content, fmt, state));
1536
2988
  }
@@ -1539,7 +2991,7 @@ function blocks(d, nodes, fmt, state) {
1539
2991
  }
1540
2992
  var exportDocx = async (ctx) => {
1541
2993
  const d = await import("docx");
1542
- const state = { instance: 0 };
2994
+ const state = { instance: 0, images: await resolveImages(ctx.json) };
1543
2995
  const children = [
1544
2996
  new d.Paragraph({ text: ctx.title, heading: d.HeadingLevel.TITLE }),
1545
2997
  ...blocks(d, ctx.json.content, {}, state)
@@ -1870,190 +3322,6 @@ function getDefaultDocumentStore() {
1870
3322
  return defaultStore;
1871
3323
  }
1872
3324
 
1873
- // src/components/document-editor/document-title.tsx
1874
- var import_jsx_runtime6 = require("react/jsx-runtime");
1875
- function DocumentTitle({ value, disabled, onChange }) {
1876
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1877
- "input",
1878
- {
1879
- className: "june-doc__title",
1880
- "aria-label": "Document title",
1881
- value,
1882
- disabled,
1883
- placeholder: "Untitled document",
1884
- onChange: (e) => onChange(e.target.value)
1885
- }
1886
- );
1887
- }
1888
-
1889
- // src/components/document-editor/document-toolbar.tsx
1890
- var import_react8 = require("@tiptap/react");
1891
- var import_react9 = require("react");
1892
- init_document_utils();
1893
- var import_jsx_runtime7 = require("react/jsx-runtime");
1894
- var FORMAT_LABELS = {
1895
- html: "HTML",
1896
- markdown: "Markdown",
1897
- txt: "Plain text",
1898
- docx: "Word (.docx)",
1899
- pdf: "PDF (print)"
1900
- };
1901
- function Btn({ label, active, disabled, toggle, onClick, children }) {
1902
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1903
- "button",
1904
- {
1905
- type: "button",
1906
- className: "june-doc__btn",
1907
- "aria-label": label,
1908
- title: label,
1909
- "aria-pressed": toggle ? !!active : void 0,
1910
- "data-active": active || void 0,
1911
- disabled,
1912
- onMouseDown: (e) => e.preventDefault(),
1913
- onClick,
1914
- children
1915
- }
1916
- );
1917
- }
1918
- function DocumentToolbar(props) {
1919
- const { editor, editable, exportFormats, canSave, saveState, onExport, onCopy, onSave } = props;
1920
- const [linkOpen, setLinkOpen] = (0, import_react9.useState)(false);
1921
- const [linkValue, setLinkValue] = (0, import_react9.useState)("");
1922
- const s = (0, import_react8.useEditorState)({
1923
- editor,
1924
- selector: ({ editor: ed }) => ed ? {
1925
- bold: ed.isActive("bold"),
1926
- italic: ed.isActive("italic"),
1927
- underline: ed.isActive("underline"),
1928
- strike: ed.isActive("strike"),
1929
- bullet: ed.isActive("bulletList"),
1930
- ordered: ed.isActive("orderedList"),
1931
- quote: ed.isActive("blockquote"),
1932
- link: ed.isActive("link"),
1933
- linkHref: ed.getAttributes("link").href ?? "",
1934
- h1: ed.isActive("heading", { level: 1 }),
1935
- h2: ed.isActive("heading", { level: 2 }),
1936
- h3: ed.isActive("heading", { level: 3 }),
1937
- left: ed.isActive({ textAlign: "left" }),
1938
- center: ed.isActive({ textAlign: "center" }),
1939
- right: ed.isActive({ textAlign: "right" }),
1940
- justify: ed.isActive({ textAlign: "justify" }),
1941
- inTable: ed.isActive("table"),
1942
- canUndo: ed.can().undo(),
1943
- canRedo: ed.can().redo()
1944
- } : null
1945
- });
1946
- const run = () => editor?.chain().focus();
1947
- const off = !editor || !editable;
1948
- const heading = s?.h1 ? "1" : s?.h2 ? "2" : s?.h3 ? "3" : "p";
1949
- const openLink = () => {
1950
- setLinkValue(s?.linkHref ?? "");
1951
- setLinkOpen(true);
1952
- };
1953
- const applyLink = () => {
1954
- const href = sanitizeHref(linkValue);
1955
- if (href) run()?.extendMarkRange("link").setLink({ href }).run();
1956
- setLinkOpen(false);
1957
- };
1958
- const removeLink = () => {
1959
- run()?.extendMarkRange("link").unsetLink().run();
1960
- setLinkOpen(false);
1961
- };
1962
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__toolbar", role: "toolbar", "aria-label": "Document formatting", children: [
1963
- editable ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1964
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__group", children: [
1965
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Undo", disabled: off || !s?.canUndo, onClick: () => run()?.undo().run(), children: "\u21B6" }),
1966
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Redo", disabled: off || !s?.canRedo, onClick: () => run()?.redo().run(), children: "\u21B7" })
1967
- ] }),
1968
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "june-doc__group", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1969
- "select",
1970
- {
1971
- className: "june-doc__select",
1972
- "aria-label": "Text style",
1973
- disabled: off,
1974
- value: heading,
1975
- onChange: (e) => {
1976
- const v = e.target.value;
1977
- if (v === "p") run()?.setParagraph().run();
1978
- else run()?.toggleHeading({ level: Number(v) }).run();
1979
- },
1980
- children: [
1981
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "p", children: "Paragraph" }),
1982
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "1", children: "Heading 1" }),
1983
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "2", children: "Heading 2" }),
1984
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "3", children: "Heading 3" })
1985
- ]
1986
- }
1987
- ) }),
1988
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__group", children: [
1989
- /* @__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" }) }),
1990
- /* @__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" }) }),
1991
- /* @__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" }) }),
1992
- /* @__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" }) })
1993
- ] }),
1994
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__group", children: [
1995
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Bullet list", toggle: true, active: s?.bullet, disabled: off, onClick: () => run()?.toggleBulletList().run(), children: "\u2022 List" }),
1996
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Numbered list", toggle: true, active: s?.ordered, disabled: off, onClick: () => run()?.toggleOrderedList().run(), children: "1. List" }),
1997
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Blockquote", toggle: true, active: s?.quote, disabled: off, onClick: () => run()?.toggleBlockquote().run(), children: "Quote" }),
1998
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Link", toggle: true, active: s?.link, disabled: off, onClick: openLink, children: "Link" })
1999
- ] }),
2000
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__group", children: [
2001
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Align left", toggle: true, active: s?.left, disabled: off, onClick: () => run()?.setTextAlign("left").run(), children: "L" }),
2002
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Align center", toggle: true, active: s?.center, disabled: off, onClick: () => run()?.setTextAlign("center").run(), children: "C" }),
2003
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Align right", toggle: true, active: s?.right, disabled: off, onClick: () => run()?.setTextAlign("right").run(), children: "R" }),
2004
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Justify", toggle: true, active: s?.justify, disabled: off, onClick: () => run()?.setTextAlign("justify").run(), children: "J" })
2005
- ] }),
2006
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__group", children: [
2007
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Insert table", disabled: off, onClick: () => run()?.insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run(), children: "Table" }),
2008
- s?.inTable ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
2009
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Add row below", disabled: off, onClick: () => run()?.addRowAfter().run(), children: "+Row" }),
2010
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Add column right", disabled: off, onClick: () => run()?.addColumnAfter().run(), children: "+Col" }),
2011
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Delete row", disabled: off, onClick: () => run()?.deleteRow().run(), children: "\u2212Row" }),
2012
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Delete column", disabled: off, onClick: () => run()?.deleteColumn().run(), children: "\u2212Col" }),
2013
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Delete table", disabled: off, onClick: () => run()?.deleteTable().run(), children: "Del table" })
2014
- ] }) : null
2015
- ] })
2016
- ] }) : null,
2017
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__group june-doc__group--end", children: [
2018
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Copy document", onClick: onCopy, children: "Copy" }),
2019
- exportFormats.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2020
- "select",
2021
- {
2022
- className: "june-doc__select",
2023
- "aria-label": "Export document",
2024
- value: "",
2025
- onChange: (e) => e.target.value && onExport(e.target.value),
2026
- children: [
2027
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "", children: "Export\u2026" }),
2028
- exportFormats.map((f) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: f, children: FORMAT_LABELS[f] ?? f }, f))
2029
- ]
2030
- }
2031
- ) : null,
2032
- canSave ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Btn, { label: "Save", disabled: saveState === "saving" || saveState === "saved" || saveState === "idle", onClick: onSave, children: "Save" }) : null
2033
- ] }),
2034
- linkOpen ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "june-doc__linkbar", children: [
2035
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2036
- "input",
2037
- {
2038
- "aria-label": "Link address",
2039
- className: "june-doc__input",
2040
- placeholder: "https://example.com",
2041
- value: linkValue,
2042
- autoFocus: true,
2043
- onChange: (e) => setLinkValue(e.target.value),
2044
- onKeyDown: (e) => {
2045
- if (e.key === "Enter") applyLink();
2046
- if (e.key === "Escape") setLinkOpen(false);
2047
- }
2048
- }
2049
- ),
2050
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "june-doc__btn", onClick: applyLink, children: "Apply" }),
2051
- s?.link ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "june-doc__btn", onClick: removeLink, children: "Remove" }) : null,
2052
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "june-doc__btn", onClick: () => setLinkOpen(false), children: "Cancel" })
2053
- ] }) : null
2054
- ] });
2055
- }
2056
-
2057
3325
  // src/components/document-editor/document-types.ts
2058
3326
  var ALL_EXPORT_FORMATS = [
2059
3327
  "html",
@@ -2065,7 +3333,7 @@ var ALL_EXPORT_FORMATS = [
2065
3333
 
2066
3334
  // src/components/document-editor/document-editor.tsx
2067
3335
  init_document_utils();
2068
- var import_jsx_runtime8 = require("react/jsx-runtime");
3336
+ var import_jsx_runtime13 = require("react/jsx-runtime");
2069
3337
  var snapshotOf = (r) => ({
2070
3338
  documentId: r.id,
2071
3339
  title: r.title,
@@ -2080,6 +3348,8 @@ var SAVE_LABEL = {
2080
3348
  saved: "Saved",
2081
3349
  error: "Save failed"
2082
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;
2083
3353
  function DocumentEditorImpl(props) {
2084
3354
  const {
2085
3355
  documentId,
@@ -2093,15 +3363,15 @@ function DocumentEditorImpl(props) {
2093
3363
  className
2094
3364
  } = props;
2095
3365
  const ctxOptions = useDocumentOptions();
2096
- const options = (0, import_react11.useMemo)(() => ({ ...ctxOptions, ...props.options }), [ctxOptions, props.options]);
2097
- 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);
2098
3368
  optionsRef.current = options;
2099
- const store = (0, import_react11.useMemo)(() => options.store ?? getDefaultDocumentStore(), [options.store]);
2100
- 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)();
2101
3371
  const { theme: contextTheme } = useJuneTheme();
2102
3372
  const resolvedTheme = theme === "auto" ? contextTheme : theme;
2103
3373
  const contentKey = typeof content === "string" ? content : content ? JSON.stringify(content) : "";
2104
- const parsed = (0, import_react11.useMemo)(() => {
3374
+ const parsed = (0, import_react16.useMemo)(() => {
2105
3375
  if (!contentKey) return { json: null, error: null };
2106
3376
  try {
2107
3377
  return { json: parseDocumentContent(contentKey), error: null };
@@ -2109,40 +3379,55 @@ function DocumentEditorImpl(props) {
2109
3379
  return { json: null, error: toJuneError(e, "DOCUMENT_ERROR") };
2110
3380
  }
2111
3381
  }, [contentKey]);
2112
- (0, import_react11.useEffect)(() => {
3382
+ (0, import_react16.useEffect)(() => {
2113
3383
  if (parsed.error) optionsRef.current.onError?.(parsed.error);
2114
3384
  }, [parsed.error]);
2115
3385
  const title = useDocumentValue(store, documentId, (r) => r?.title ?? titleProp);
2116
3386
  const pending = useDocumentValue(store, documentId, (r) => r?.pending ?? null);
2117
3387
  const words = useDocumentValue(store, documentId, (r) => r ? wordCountOf(r.json) : 0);
2118
3388
  const recordStatus = useDocumentValue(store, documentId, (r) => r?.status ?? status);
2119
- const [saveState, setSaveState] = (0, import_react11.useState)("idle");
2120
- const [notice, setNotice] = (0, import_react11.useState)(null);
2121
- const lastSavedKey = (0, import_react11.useRef)("");
2122
- const seenRevision = (0, import_react11.useRef)(store.get(documentId)?.revision ?? 0);
2123
- const readyRef = (0, import_react11.useRef)(false);
2124
- 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) => {
2125
3410
  setNotice(message);
2126
3411
  }, []);
2127
- (0, import_react11.useEffect)(() => {
3412
+ (0, import_react16.useEffect)(() => {
2128
3413
  if (!notice) return;
2129
3414
  const t = setTimeout(() => setNotice(null), 3e3);
2130
3415
  return () => clearTimeout(t);
2131
3416
  }, [notice]);
2132
- const emitChange = (0, import_react11.useCallback)(
3417
+ const emitChange = (0, import_react16.useCallback)(
2133
3418
  (source) => {
2134
3419
  const record = store.get(documentId);
2135
3420
  if (record) optionsRef.current.onDocumentChange?.({ ...snapshotOf(record), source });
2136
3421
  },
2137
3422
  [store, documentId]
2138
3423
  );
2139
- const saveRef = (0, import_react11.useRef)(async () => {
3424
+ const saveRef = (0, import_react16.useRef)(async () => {
2140
3425
  });
2141
- const autosave = (0, import_react11.useMemo)(() => {
3426
+ const autosave = (0, import_react16.useMemo)(() => {
2142
3427
  const delay = options.autosaveDelay ?? 1500;
2143
3428
  return delay > 0 ? debounce(() => void saveRef.current(), delay) : null;
2144
3429
  }, [options.autosaveDelay]);
2145
- (0, import_react11.useEffect)(() => () => autosave?.flush(), [autosave]);
3430
+ (0, import_react16.useEffect)(() => () => autosave?.flush(), [autosave]);
2146
3431
  saveRef.current = async () => {
2147
3432
  const record = store.get(documentId);
2148
3433
  const onSave = optionsRef.current.onSave;
@@ -2168,21 +3453,21 @@ function DocumentEditorImpl(props) {
2168
3453
  optionsRef.current.onError?.(toJuneError(error, "DOCUMENT_ERROR", "Saving the document failed"));
2169
3454
  }
2170
3455
  };
2171
- const markDirty = (0, import_react11.useCallback)(() => {
3456
+ const markDirty = (0, import_react16.useCallback)(() => {
2172
3457
  if (!optionsRef.current.onSave) return;
2173
3458
  setSaveState("dirty");
2174
3459
  autosave?.();
2175
3460
  }, [autosave]);
2176
- const [initialJson] = (0, import_react11.useState)(() => store.get(documentId)?.json ?? parsed.json ?? emptyDoc());
2177
- const extensions = (0, import_react11.useMemo)(() => createDocumentExtensions(), []);
2178
- 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)(() => {
2179
3464
  });
2180
3465
  onUpdateRef.current = (json) => {
2181
3466
  store.edit(documentId, json, instanceId);
2182
3467
  emitChange("user");
2183
3468
  markDirty();
2184
3469
  };
2185
- const editor = (0, import_react10.useEditor)({
3470
+ const editor = (0, import_react15.useEditor)({
2186
3471
  extensions,
2187
3472
  content: initialJson,
2188
3473
  editable,
@@ -2197,10 +3482,10 @@ function DocumentEditorImpl(props) {
2197
3482
  },
2198
3483
  onUpdate: ({ editor: ed }) => onUpdateRef.current(ed.getJSON())
2199
3484
  });
2200
- (0, import_react11.useEffect)(() => {
3485
+ (0, import_react16.useEffect)(() => {
2201
3486
  editor?.setEditable(editable);
2202
3487
  }, [editor, editable]);
2203
- (0, import_react11.useEffect)(() => {
3488
+ (0, import_react16.useEffect)(() => {
2204
3489
  if (!parsed.json) return;
2205
3490
  const outcome = store.receive({
2206
3491
  id: documentId,
@@ -2221,7 +3506,7 @@ function DocumentEditorImpl(props) {
2221
3506
  });
2222
3507
  }
2223
3508
  }, [store, documentId, titleProp, parsed.json, documentType, status, emitChange, markDirty]);
2224
- (0, import_react11.useEffect)(() => {
3509
+ (0, import_react16.useEffect)(() => {
2225
3510
  if (!editor) return;
2226
3511
  const apply = () => {
2227
3512
  const record = store.get(documentId);
@@ -2238,7 +3523,7 @@ function DocumentEditorImpl(props) {
2238
3523
  apply();
2239
3524
  return store.subscribe(apply);
2240
3525
  }, [editor, store, documentId, instanceId]);
2241
- (0, import_react11.useEffect)(() => {
3526
+ (0, import_react16.useEffect)(() => {
2242
3527
  if (!editor || readyRef.current) return;
2243
3528
  const record = store.get(documentId);
2244
3529
  if (!record) return;
@@ -2282,67 +3567,114 @@ function DocumentEditorImpl(props) {
2282
3567
  };
2283
3568
  const formats = (exportFormats ?? [...ALL_EXPORT_FORMATS]).filter((f) => listDocumentExporters().includes(f));
2284
3569
  if (parsed.error && !store.get(documentId)) {
2285
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "june-doc june-doc--error", "data-theme": resolvedTheme, role: "alert", children: [
2286
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "june-doc__draft-text", children: "This document could not be displayed." }),
2287
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("details", { children: [
2288
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("summary", { children: "Show raw content" }),
2289
- /* @__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 })
2290
3575
  ] })
2291
3576
  ] });
2292
3577
  }
2293
- 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" });
2294
3579
  const isDraft = recordStatus === "draft";
2295
- 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)(
2296
3582
  "div",
2297
3583
  {
2298
- className: className ? `june-doc ${className}` : "june-doc",
3584
+ className: classes,
2299
3585
  "data-theme": resolvedTheme,
2300
3586
  "data-status": recordStatus,
3587
+ role: fullscreen ? "dialog" : void 0,
3588
+ "aria-modal": fullscreen || void 0,
3589
+ "aria-label": fullscreen ? title : void 0,
2301
3590
  onKeyDown: (e) => {
2302
- 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) {
2303
3593
  e.preventDefault();
2304
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);
2305
3600
  }
2306
3601
  },
2307
3602
  children: [
2308
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "june-doc__header", children: [
2309
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DocumentTitle, { value: title, disabled: !editable, onChange: handleTitle }),
2310
- isDraft ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "june-doc__badge", children: "AI draft" }) : null
2311
- ] }),
2312
- pending ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "june-doc__banner", role: "status", children: [
2313
- /* @__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: [
2314
3622
  "The assistant suggested changes that overlap your edits (",
2315
3623
  pending.conflicts,
2316
3624
  " ",
2317
3625
  pending.conflicts === 1 ? "section" : "sections",
2318
3626
  ")."
2319
3627
  ] }),
2320
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "june-doc__banner-actions", children: [
2321
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "june-doc__btn", onClick: () => resolve("merge"), children: "Merge, keep my edits" }),
2322
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "june-doc__btn", onClick: () => resolve("replace"), children: "Use AI version" }),
2323
- /* @__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" })
2324
3632
  ] })
2325
3633
  ] }) : null,
2326
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3634
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2327
3635
  DocumentToolbar,
2328
3636
  {
2329
3637
  editor,
2330
3638
  editable,
2331
- exportFormats: formats,
2332
- canSave: !!options.onSave,
2333
- saveState,
2334
- onExport: (f) => void handleExport(f),
2335
- onCopy: () => void handleCopy(),
2336
- 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
2337
3648
  }
2338
3649
  ),
2339
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DocumentContent, { editor }),
2340
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "june-doc__footer", "aria-live": "polite", children: [
2341
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
2342
- words,
2343
- " 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
+ ] })
2344
3668
  ] }),
2345
- /* @__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
+ ] })
2346
3678
  ] })
2347
3679
  ]
2348
3680
  }
@@ -2350,8 +3682,8 @@ function DocumentEditorImpl(props) {
2350
3682
  }
2351
3683
 
2352
3684
  // src/components/document-editor/document-component.tsx
2353
- var import_jsx_runtime9 = require("react/jsx-runtime");
2354
- var DOCUMENT_COMPONENT_DESCRIPTION = 'An editable document. DocumentEditor(documentId, title, content, documentType?, status?, editable?, exportFormats?). "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.';
3685
+ var import_jsx_runtime14 = require("react/jsx-runtime");
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.';
2355
3687
  var documentProps = import_v4.z.object({
2356
3688
  documentId: import_v4.z.string().describe("Stable id. Reuse it when revising the same document."),
2357
3689
  title: import_v4.z.string().describe("Document title. Do not repeat it as a heading in content."),
@@ -2364,12 +3696,12 @@ var documentProps = import_v4.z.object({
2364
3696
  function DocumentEditor(props) {
2365
3697
  const { isStreaming } = useJuneRuntime();
2366
3698
  if (props.generating || isStreaming) {
2367
- 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" });
2368
3700
  }
2369
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DocumentEditorImpl, { ...props });
3701
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DocumentEditorImpl, { ...props });
2370
3702
  }
2371
3703
  function OpenUIDocument({ props }) {
2372
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
3704
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2373
3705
  DocumentEditor,
2374
3706
  {
2375
3707
  documentId: props.documentId,
@@ -2389,7 +3721,15 @@ var JuneDocumentEditorComponent = (0, import_react_lang3.defineComponent)({
2389
3721
  component: OpenUIDocument
2390
3722
  });
2391
3723
  function withDocumentEditor(library) {
2392
- return library.extend({ components: { add: [JuneDocumentEditorComponent] } });
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
+ }
2393
3733
  }
2394
3734
 
2395
3735
  // src/components/document-editor/document-instructions.ts
@@ -2449,9 +3789,9 @@ var import_react_ui = require("@openuidev/react-ui");
2449
3789
  var juneLibrary = withDocumentEditor(import_react_ui.openuiLibrary);
2450
3790
 
2451
3791
  // src/core/JuneUI.tsx
2452
- var import_jsx_runtime10 = require("react/jsx-runtime");
3792
+ var import_jsx_runtime15 = require("react/jsx-runtime");
2453
3793
  function JuneUI({ library = juneLibrary, ...props }) {
2454
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(JuneRenderer, { library, ...props });
3794
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(JuneRenderer, { library, ...props });
2455
3795
  }
2456
3796
  // Annotate the CommonJS export names for ESM import in node:
2457
3797
  0 && (module.exports = {