@arbidocs/blocks 0.4.99 → 0.4.101

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/{chunk-44TPPPRJ.cjs → chunk-FAGQTB3D.cjs} +958 -272
  2. package/dist/chunk-FAGQTB3D.cjs.map +1 -0
  3. package/dist/{chunk-C5RF47LD.js → chunk-G5JH2YMQ.js} +3 -3
  4. package/dist/{chunk-C5RF47LD.js.map → chunk-G5JH2YMQ.js.map} +1 -1
  5. package/dist/{chunk-4ZTIMQ7Z.js → chunk-MYALCKDR.js} +963 -277
  6. package/dist/chunk-MYALCKDR.js.map +1 -0
  7. package/dist/{chunk-MABEOI4S.cjs → chunk-Y5XW57U4.cjs} +5 -5
  8. package/dist/{chunk-MABEOI4S.cjs.map → chunk-Y5XW57U4.cjs.map} +1 -1
  9. package/dist/{chunk-3ICWR3BK.js → chunk-YGREW5TZ.js} +3 -3
  10. package/dist/{chunk-3ICWR3BK.js.map → chunk-YGREW5TZ.js.map} +1 -1
  11. package/dist/{chunk-QBEUCOC7.cjs → chunk-ZT2EBBSC.cjs} +5 -5
  12. package/dist/{chunk-QBEUCOC7.cjs.map → chunk-ZT2EBBSC.cjs.map} +1 -1
  13. package/dist/connect/docx.cjs +6 -6
  14. package/dist/connect/docx.js +4 -4
  15. package/dist/connect/index.cjs +3 -3
  16. package/dist/connect/index.js +2 -2
  17. package/dist/docx/NativeDocxEditor.d.ts +7 -2
  18. package/dist/docx/definitions/DefinedTerms.d.ts +1 -12
  19. package/dist/docx/definitions/commands.d.ts +3 -27
  20. package/dist/docx/index.cjs +38 -38
  21. package/dist/docx/index.d.ts +2 -1
  22. package/dist/docx/index.js +3 -3
  23. package/dist/docx/layout/GenerateImage.d.ts +50 -0
  24. package/dist/docx/layout/LayoutRibbon.d.ts +32 -0
  25. package/dist/docx/layout/LayoutTabs.d.ts +20 -0
  26. package/dist/docx/layout/PictureRibbon.d.ts +23 -0
  27. package/dist/docx/layout/TableKeys.d.ts +25 -0
  28. package/dist/docx/layout/TableRibbon.d.ts +11 -0
  29. package/dist/docx/layout/caption.d.ts +38 -0
  30. package/dist/docx/layout/presets.d.ts +40 -0
  31. package/dist/index.cjs +5 -5
  32. package/dist/index.js +1 -1
  33. package/package.json +5 -4
  34. package/src/docx/README.md +24 -3
  35. package/src/docx/layout/layout.css +120 -0
  36. package/src/docx/styles.css +2 -0
  37. package/dist/chunk-44TPPPRJ.cjs.map +0 -1
  38. package/dist/chunk-4ZTIMQ7Z.js.map +0 -1
@@ -1,15 +1,16 @@
1
1
  "use client";
2
- import { stylesXml, definitionBookmark, DEFINITION_BOOKMARK_PREFIX, compareTerms, groupDefinitions, definitionLabels, filterTermGroups, toDefinition, definitionIdOfBookmark, esc, parseDefinition, docxPackage, documentXml } from './chunk-D3QPYKZG.js';
2
+ import { stylesXml, definitionBookmark, groupDefinitions, definitionLabels, filterTermGroups, esc, docxPackage, documentXml, definitionIdOfBookmark, compareTerms, parseDefinition } from './chunk-D3QPYKZG.js';
3
3
  import { filterMentionCandidates, MentionMenu, findMentionQuery, listOptionId, extractMentions, useListKeyNav } from './chunk-AA3PT6KR.js';
4
4
  import { unzipSync, strFromU8, strToU8, zipSync } from 'fflate';
5
5
  import { collectReviewItems, revisionItemsOf } from '@docx-editor.dev/core/store';
6
- import React3, { createContext, useContext, useState, useRef, useCallback, useEffect, useLayoutEffect, useMemo } from 'react';
7
- import { useDocxEditor, ReviewRailContext, useEditorSnapshot, useChromeTranslate, DocxEditor, createFontSource, useParagraphStyle, useEditorCommand } from '@docx-editor.dev/react';
8
- import { AiMarkdown, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, Button, DialogFooter, cn, splitMarkdownBlocks } from '@arbidocs/react/ui';
9
- import { MessageSquarePlus, MessageSquare, PencilLine, ChevronLeft, ChevronRight, X, ChevronUp, ChevronDown, CheckCheck, RotateCcw, CircleCheck, Trash2, Check, SendHorizontal, Type, Ellipsis, RefreshCw, WifiOff, Download, Save, BookA, ListRestart, Blocks, Superscript, NotebookText } from 'lucide-react';
6
+ import React3, { createContext, useContext, useState, useRef, useCallback, useEffect, useLayoutEffect, useMemo, useSyncExternalStore } from 'react';
7
+ import { useDocxEditor, ReviewRailContext, useEditorSnapshot, useEditorState, useChromeTranslate, DocxEditor, createFontSource, useParagraphStyle, normalizeImageBytes, usePageSetup, useEditorCommand } from '@docx-editor.dev/react';
8
+ import { AiMarkdown, Dialog, DialogContent, DialogHeader, DialogTitle, cn, splitMarkdownBlocks } from '@arbidocs/react/ui';
9
+ import { MessageSquarePlus, MessageSquare, PencilLine, ChevronLeft, ChevronRight, X, ChevronUp, ChevronDown, CheckCheck, RotateCcw, CircleCheck, Trash2, Check, SendHorizontal, Loader2, Sparkles, Type, Ellipsis, RefreshCw, WifiOff, Download, Save, BookA, Blocks, Superscript, NotebookText, Columns2, Settings2, BetweenHorizontalStart, BetweenHorizontalEnd, BetweenVerticalStart, BetweenVerticalEnd, Merge, Split, Heading, AlignVerticalJustifyStart, AlignVerticalJustifyCenter, AlignVerticalJustifyEnd, RotateCw, FlipHorizontal2, FlipVertical2, Scaling, RectangleVertical, RectangleHorizontal, FileText, SeparatorHorizontal, Captions } from 'lucide-react';
10
10
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
11
11
  import { createPortal } from 'react-dom';
12
12
  import { defaultLegalTemplate, listBuildingBlocks, attachedTemplateOf, linkedLevelStyles, styleDivergence, buildingBlockFragment, fragmentClipboardHtml, trackInsertion, newFromTemplate } from '@arbidocs/coedit/template';
13
+ import { executeImageCommand } from '@docx-editor.dev/core/editor';
13
14
  import { renderToStaticMarkup } from 'react-dom/server';
14
15
  import * as Y from 'yjs';
15
16
  import { DOCUMENT_COLLABORATION_VERSIONS, collaborationModule } from '@arbidocs/coedit';
@@ -871,18 +872,18 @@ function ReviewCardSlot({ children }) {
871
872
  var DocxEditorReview = Object.assign(DocxEditorReviewRail, { Card: ReviewCardSlot });
872
873
 
873
874
  // src/docx/mentions.ts
874
- function mentionCandidates(mentions2) {
875
+ function mentionCandidates(mentions) {
875
876
  return [
876
877
  { id: "arbi", label: "ARBI", kind: "assistant" },
877
- ...mentions2.filter((person) => person.name.trim()).map((person) => ({
878
+ ...mentions.filter((person) => person.name.trim()).map((person) => ({
878
879
  id: person.id,
879
880
  label: person.name,
880
881
  kind: person.kind === "agent" ? "assistant" : "user"
881
882
  }))
882
883
  ];
883
884
  }
884
- function mentionedDocxRecipients(text, mentions2) {
885
- return extractMentions(text, mentionCandidates(mentions2)).map((person) => person.id);
885
+ function mentionedDocxRecipients(text, mentions) {
886
+ return extractMentions(text, mentionCandidates(mentions)).map((person) => person.id);
886
887
  }
887
888
  var ActivityContext = createContext({});
888
889
  function DocxCommentActivity() {
@@ -958,7 +959,7 @@ function DocxCommentActivity() {
958
959
  }
959
960
  function DocxMentions({
960
961
  children,
961
- mentions: mentions2 = [],
962
+ mentions = [],
962
963
  initialCommentId,
963
964
  requestAgent,
964
965
  getAgentStatus,
@@ -1017,7 +1018,7 @@ function DocxMentions({
1017
1018
  const [suggestions, setSuggestions] = useState(null);
1018
1019
  const [selected, setSelected] = useState(0);
1019
1020
  const candidates = filterMentionCandidates(
1020
- mentionCandidates(mentions2),
1021
+ mentionCandidates(mentions),
1021
1022
  suggestions?.query || ""
1022
1023
  ).slice(0, 8);
1023
1024
  useEffect(() => {
@@ -1038,7 +1039,7 @@ function DocxMentions({
1038
1039
  }));
1039
1040
  };
1040
1041
  const hasAgent = submission.recipientIds.some(
1041
- (id) => id === "arbi" || mentions2.some((person) => person.id === id && person.kind === "agent")
1042
+ (id) => id === "arbi" || mentions.some((person) => person.id === id && person.kind === "agent")
1042
1043
  );
1043
1044
  if (hasAgent) update("delivering");
1044
1045
  void requestAgent({
@@ -1072,7 +1073,7 @@ function DocxMentions({
1072
1073
  "error"
1073
1074
  );
1074
1075
  });
1075
- }, [review.items, requestAgent, getAgentStatus, mentions2, notify]);
1076
+ }, [review.items, requestAgent, getAgentStatus, mentions, notify]);
1076
1077
  const choose = (name) => {
1077
1078
  const field = input.current;
1078
1079
  if (!field || !suggestions) return;
@@ -1090,7 +1091,7 @@ function DocxMentions({
1090
1091
  '[data-testid="review-draft-input"], [data-testid="review-reply-input"]'
1091
1092
  );
1092
1093
  if (!field || field.readOnly || !requestAgent) return false;
1093
- const recipientIds = mentionedDocxRecipients(field.value, mentions2);
1094
+ const recipientIds = mentionedDocxRecipients(field.value, mentions);
1094
1095
  if (!recipientIds.length) return false;
1095
1096
  pending.current = {
1096
1097
  ids: new Set(review.items.filter((i) => i.kind === "comment").map((i) => i.item.id)),
@@ -1137,7 +1138,7 @@ function DocxMentions({
1137
1138
  (entry) => entry.kind === "comment" && entry.parentId === commentId
1138
1139
  );
1139
1140
  const author = replies.at(-1)?.author || target.author;
1140
- const agent = mentions2.find((person) => person.kind === "agent" && person.name === author);
1141
+ const agent = mentions.find((person) => person.kind === "agent" && person.name === author);
1141
1142
  if (agent || author === "ARBI" || author === "Assistant")
1142
1143
  prefixMention(
1143
1144
  field,
@@ -1215,7 +1216,7 @@ function DocxMentions({
1215
1216
  onMouseDown: (event) => event.preventDefault(),
1216
1217
  onClick: (event) => {
1217
1218
  event.stopPropagation();
1218
- if (!mentionedDocxRecipients(field.value, mentions2).includes("arbi"))
1219
+ if (!mentionedDocxRecipients(field.value, mentions).includes("arbi"))
1219
1220
  prefixMention(field);
1220
1221
  else field.focus();
1221
1222
  },
@@ -1270,7 +1271,6 @@ function definitionTooltip(definition) {
1270
1271
  const line = `\u201C${definition.term}\u201D${definition.rest}`.replace(/\s+/g, " ").trim();
1271
1272
  return line.length > 255 ? `${line.slice(0, 254)}\u2026` : line;
1272
1273
  }
1273
- var definitionParagraphText = (definition) => `\u201C${definition.term}\u201D${definition.rest}`;
1274
1274
  function definitionParagraphXml(definition, bookmark, id = 0) {
1275
1275
  return `<w:p><w:bookmarkStart w:id="${id}" w:name="${esc(bookmark)}"/>${textRun("\u201C")}${textRun(
1276
1276
  definition.term,
@@ -1391,95 +1391,6 @@ function insertDefinedTerm(port, definition, options = {}) {
1391
1391
  port.setCaret({ paragraphId: caret.paragraphId, offset: caret.offset + definition.term.length });
1392
1392
  return { addedDefinition };
1393
1393
  }
1394
- var escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1395
- var mentions = (text, term) => new RegExp(`(^|[^\\p{L}\\p{N}])${escapeRegExp(term)}($|[^\\p{L}\\p{N}])`, "iu").test(text);
1396
- function updateDefinitions(port, definitions) {
1397
- const result = {
1398
- added: [],
1399
- refreshed: [],
1400
- reordered: [],
1401
- unused: [],
1402
- unknown: []
1403
- };
1404
- let paragraphs = port.paragraphs();
1405
- const linked = new Set(
1406
- paragraphs.flatMap(
1407
- (p) => p.links.map((l) => l.anchor).filter((a) => a.startsWith(DEFINITION_BOOKMARK_PREFIX))
1408
- )
1409
- );
1410
- const declared = /* @__PURE__ */ new Map();
1411
- for (const p of paragraphs)
1412
- for (const b of p.bookmarks)
1413
- if (b.startsWith(DEFINITION_BOOKMARK_PREFIX) && !declared.has(b)) declared.set(b, p);
1414
- const factOf = (bookmark) => {
1415
- const id = definitionIdOfBookmark(bookmark);
1416
- return id ? definitions.get(id) : void 0;
1417
- };
1418
- for (const bookmark of [...linked, ...declared.keys()])
1419
- if (!factOf(bookmark) && !result.unknown.includes(bookmark)) result.unknown.push(bookmark);
1420
- const section = findDefinitionsSection(paragraphs);
1421
- const rewrite = /* @__PURE__ */ new Map();
1422
- for (const [bookmark, paragraph] of declared) {
1423
- const fact = factOf(bookmark);
1424
- if (fact && paragraph.text !== definitionParagraphText(fact)) {
1425
- rewrite.set(paragraph.id, fact);
1426
- result.refreshed.push(fact.term);
1427
- }
1428
- }
1429
- if (section) {
1430
- let previous = null;
1431
- for (let i = section.start; i < section.end; i++) {
1432
- const p = paragraphs[i];
1433
- const term = termOf(p);
1434
- if (term === null) continue;
1435
- const bookmark = p.bookmarks.find((b) => b.startsWith(DEFINITION_BOOKMARK_PREFIX));
1436
- const fact = bookmark ? factOf(bookmark) : void 0;
1437
- if (previous !== null && compareTerms(term, previous) < 0 && fact) {
1438
- if (!rewrite.has(p.id)) result.reordered.push(fact.term);
1439
- rewrite.set(p.id, fact);
1440
- continue;
1441
- }
1442
- previous = term;
1443
- }
1444
- }
1445
- for (const id of [...rewrite.keys()].reverse()) {
1446
- const index = paragraphs.findIndex((p) => p.id === id);
1447
- const previous = paragraphs[index - 1];
1448
- const target = paragraphs[index];
1449
- if (!previous) continue;
1450
- port.deleteRange(
1451
- { paragraphId: previous.id, offset: previous.text.length },
1452
- { paragraphId: target.id, offset: target.text.length }
1453
- );
1454
- paragraphs = port.paragraphs();
1455
- }
1456
- const toAdd = [...rewrite.values()];
1457
- for (const bookmark of linked) {
1458
- const fact = factOf(bookmark);
1459
- if (fact && !declared.has(bookmark) && !toAdd.some((d) => d.id === fact.id)) {
1460
- toAdd.push(fact);
1461
- result.added.push(fact.term);
1462
- }
1463
- }
1464
- toAdd.sort((a, b) => compareTerms(a.term, b.term));
1465
- for (const definition of toAdd) addDefinition(port, definition);
1466
- paragraphs = port.paragraphs();
1467
- const after = findDefinitionsSection(paragraphs);
1468
- if (after) {
1469
- const inSection = (i) => i >= after.title && i < after.end;
1470
- const outside = paragraphs.filter((_, i) => !inSection(i));
1471
- const linkedNow = new Set(outside.flatMap((p) => p.links.map((l) => l.anchor)));
1472
- const outsideText = outside.map((p) => p.text).join("\n");
1473
- for (let i = after.start; i < after.end; i++) {
1474
- const p = paragraphs[i];
1475
- const term = termOf(p);
1476
- if (term === null) continue;
1477
- const used = p.bookmarks.some((b) => linkedNow.has(b)) || mentions(outsideText, term);
1478
- if (!used) result.unused.push({ term, paragraphId: p.id });
1479
- }
1480
- }
1481
- return result;
1482
- }
1483
1394
  function definitionOfAnchor(anchor, definitions) {
1484
1395
  const id = definitionIdOfBookmark(anchor.replace(/^#/, ""));
1485
1396
  return id ? definitions.get(id) : void 0;
@@ -1687,7 +1598,6 @@ var MAX_GROUPS = 8;
1687
1598
  var STALE_AFTER_MS = 3e4;
1688
1599
  var DEFAULT_DEFINED_TERMS_LABELS = {
1689
1600
  insert: "Defined term",
1690
- update: "Update definitions",
1691
1601
  search: "Search defined terms",
1692
1602
  allAgreements: "All definitions",
1693
1603
  loading: "Loading definitions\u2026",
@@ -1695,18 +1605,7 @@ var DEFAULT_DEFINED_TERMS_LABELS = {
1695
1605
  noMatch: "No defined term matches.",
1696
1606
  hint: "Enter to insert \xB7 Esc to close",
1697
1607
  preferred: "Preferred",
1698
- alsoIn: (source) => `Also defined${source ? ` in ${source}` : ""}`,
1699
- updated: "Definitions updated",
1700
- updateSummary: (r) => [
1701
- r.added.length ? `${r.added.length} added` : "",
1702
- r.refreshed.length ? `${r.refreshed.length} reworded` : "",
1703
- r.reordered.length ? `${r.reordered.length} reordered` : ""
1704
- ].filter(Boolean).join(" \xB7 ") || "The Definitions section is up to date.",
1705
- unusedTitle: "Defined but never used",
1706
- unusedNone: "Every definition in the section is used.",
1707
- unknownTitle: "Links to definitions that no longer exist",
1708
- show: "Show",
1709
- close: "Close"
1608
+ alsoIn: (source) => `Also defined${source ? ` in ${source}` : ""}`
1710
1609
  };
1711
1610
  var DefinedTermsContext = createContext(null);
1712
1611
  var useDefinedTerms = () => useContext(DefinedTermsContext);
@@ -1732,7 +1631,6 @@ function DefinedTermsProvider({
1732
1631
  const [labelId, setLabelId] = useState(null);
1733
1632
  const [picker, setPicker] = useState(null);
1734
1633
  const [selected, setSelected] = useState(0);
1735
- const [report, setReport] = useState(null);
1736
1634
  const marker = useRef(null);
1737
1635
  const dismissedAt = useRef(null);
1738
1636
  const refresh = useCallback(
@@ -1891,31 +1789,9 @@ function DefinedTermsProvider({
1891
1789
  window.addEventListener("keydown", keys, true);
1892
1790
  return () => window.removeEventListener("keydown", keys, true);
1893
1791
  }, [picker, rows, selected, pick]);
1894
- const update = useCallback(() => {
1895
- if (!editor || !editable) return;
1896
- void refresh(true).then((list) => {
1897
- const definitions = new Map(
1898
- list.flatMap((s) => {
1899
- const d = toDefinition(s);
1900
- return d ? [[d.id, d]] : [];
1901
- })
1902
- );
1903
- const surface = editor.surface;
1904
- const before = surface?.state().selection?.head;
1905
- const paraId = before && surface?.session.paraIdOf(before.paragraphId);
1906
- const result = run(() => updateDefinitions(editorPort(editor), definitions));
1907
- const node = paraId && surface?.session.nodeIdOf(paraId);
1908
- if (result && before && node) {
1909
- const point = { paragraphId: node, offset: before.offset };
1910
- surface.setSelection({ anchor: point, head: point });
1911
- holdCaret(editor);
1912
- }
1913
- if (result) setReport(result);
1914
- });
1915
- }, [editor, editable, refresh, run]);
1916
1792
  const value = useMemo(
1917
- () => load && editable ? { openPicker, update, labels: l } : null,
1918
- [load, editable, openPicker, update, l]
1793
+ () => load && editable ? { openPicker, labels: l } : null,
1794
+ [load, editable, openPicker, l]
1919
1795
  );
1920
1796
  return /* @__PURE__ */ jsxs(DefinedTermsContext.Provider, { value, children: [
1921
1797
  /* @__PURE__ */ jsx("span", { ref: marker, hidden: true }),
@@ -1950,50 +1826,7 @@ function DefinedTermsProvider({
1950
1826
  }
1951
1827
  ),
1952
1828
  document.body
1953
- ),
1954
- /* @__PURE__ */ jsx(Dialog, { open: !!report, onOpenChange: (open) => !open && setReport(null), children: /* @__PURE__ */ jsxs(
1955
- DialogContent,
1956
- {
1957
- className: "max-h-[85dvh] overflow-y-auto",
1958
- "data-testid": "docx-definitions-report",
1959
- children: [
1960
- /* @__PURE__ */ jsxs(DialogHeader, { children: [
1961
- /* @__PURE__ */ jsx(DialogTitle, { children: l.updated }),
1962
- /* @__PURE__ */ jsx(DialogDescription, { children: report && l.updateSummary(report) })
1963
- ] }),
1964
- report && /* @__PURE__ */ jsxs("div", { className: "space-y-4 text-sm", children: [
1965
- /* @__PURE__ */ jsxs("section", { children: [
1966
- /* @__PURE__ */ jsx("h3", { className: "mb-1 font-medium", children: l.unusedTitle }),
1967
- report.unused.length ? /* @__PURE__ */ jsx("ul", { className: "space-y-1", "data-testid": "docx-definitions-unused", children: report.unused.map((u) => /* @__PURE__ */ jsxs("li", { className: "flex items-center justify-between gap-2", children: [
1968
- /* @__PURE__ */ jsx("span", { children: u.term }),
1969
- /* @__PURE__ */ jsx(
1970
- Button,
1971
- {
1972
- size: "sm",
1973
- variant: "ghost",
1974
- onClick: () => {
1975
- const surface = editor?.surface;
1976
- surface?.setSelection({
1977
- anchor: { paragraphId: u.paragraphId, offset: 0 },
1978
- head: { paragraphId: u.paragraphId, offset: 0 }
1979
- });
1980
- surface?.revealParagraph(u.paragraphId);
1981
- setReport(null);
1982
- },
1983
- children: l.show
1984
- }
1985
- )
1986
- ] }, u.paragraphId)) }) : /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: l.unusedNone })
1987
- ] }),
1988
- report.unknown.length > 0 && /* @__PURE__ */ jsxs("section", { children: [
1989
- /* @__PURE__ */ jsx("h3", { className: "mb-1 font-medium", children: l.unknownTitle }),
1990
- /* @__PURE__ */ jsx("ul", { className: "list-disc pl-5 text-muted-foreground", children: report.unknown.map((name) => /* @__PURE__ */ jsx("li", { children: name }, name)) })
1991
- ] })
1992
- ] }),
1993
- /* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => setReport(null), children: l.close }) })
1994
- ]
1995
- }
1996
- ) })
1829
+ )
1997
1830
  ] });
1998
1831
  }
1999
1832
  function DefinedTermMenu({
@@ -2330,6 +2163,241 @@ function HouseTemplateProvider({
2330
2163
  );
2331
2164
  return /* @__PURE__ */ jsx(HouseTemplateContext.Provider, { value: enabled ? value : null, children });
2332
2165
  }
2166
+ function RibbonMenu({
2167
+ label,
2168
+ icon,
2169
+ children,
2170
+ className,
2171
+ testId,
2172
+ title
2173
+ }) {
2174
+ const [open, setOpen] = useState(false);
2175
+ const element = useRef(null);
2176
+ useEffect(() => {
2177
+ if (!open) return;
2178
+ const dismiss = (event) => {
2179
+ if (!element.current?.contains(event.target)) setOpen(false);
2180
+ };
2181
+ const escape = (event) => {
2182
+ if (event.key === "Escape") setOpen(false);
2183
+ };
2184
+ document.addEventListener("pointerdown", dismiss);
2185
+ document.addEventListener("keydown", escape);
2186
+ return () => {
2187
+ document.removeEventListener("pointerdown", dismiss);
2188
+ document.removeEventListener("keydown", escape);
2189
+ };
2190
+ }, [open]);
2191
+ return /* @__PURE__ */ jsxs("div", { className: "native-docx-ribbon-menu", ref: element, children: [
2192
+ /* @__PURE__ */ jsx(
2193
+ "button",
2194
+ {
2195
+ type: "button",
2196
+ className: ["native-docx-ribbon-trigger", className].filter(Boolean).join(" "),
2197
+ "aria-label": label,
2198
+ title: title ?? label,
2199
+ "aria-expanded": open,
2200
+ "data-testid": testId,
2201
+ onMouseDown: (event) => event.preventDefault(),
2202
+ onClick: () => setOpen((value) => !value),
2203
+ children: icon
2204
+ }
2205
+ ),
2206
+ open && /* @__PURE__ */ jsx(
2207
+ "div",
2208
+ {
2209
+ className: "native-docx-ribbon-popover",
2210
+ role: "group",
2211
+ "aria-label": label,
2212
+ onMouseDown: (event) => {
2213
+ if (!(event.target instanceof HTMLInputElement || event.target instanceof HTMLSelectElement))
2214
+ event.preventDefault();
2215
+ },
2216
+ children: typeof children === "function" ? children(() => setOpen(false)) : children
2217
+ }
2218
+ )
2219
+ ] });
2220
+ }
2221
+ var titleOf = (prompt) => {
2222
+ const line = prompt.trim().split("\n")[0];
2223
+ return line.length > 80 ? `${line.slice(0, 79)}\u2026` : line;
2224
+ };
2225
+ function rememberCaret(editor) {
2226
+ const surface = editor.surface;
2227
+ const head = surface?.state().selection?.head;
2228
+ if (!surface || !head) return null;
2229
+ return { paraId: surface.session.paraIdOf(head.paragraphId), ...head };
2230
+ }
2231
+ var mounted = [];
2232
+ var running = 0;
2233
+ var listeners = /* @__PURE__ */ new Set();
2234
+ var setRunning = (delta) => {
2235
+ running += delta;
2236
+ listeners.forEach((listener) => listener());
2237
+ };
2238
+ var subscribe = (listener) => {
2239
+ listeners.add(listener);
2240
+ return () => void listeners.delete(listener);
2241
+ };
2242
+ function insertionTarget(origin, caret, editors = mounted) {
2243
+ if (editors.includes(origin) && origin.surface) return origin;
2244
+ const paraId = caret?.paraId;
2245
+ if (!paraId) return null;
2246
+ for (let i = editors.length - 1; i >= 0; i--) {
2247
+ const session = editors[i].surface?.session;
2248
+ if (session?.nodeIdOf(paraId)) return editors[i];
2249
+ }
2250
+ return null;
2251
+ }
2252
+ function restoreCaret(editor, caret) {
2253
+ const surface = editor.surface;
2254
+ if (!surface || !caret) return;
2255
+ const paragraphId = caret.paraId && surface.session.nodeIdOf(caret.paraId) || caret.paragraphId;
2256
+ if (!surface.session.paragraphIds().includes(paragraphId)) return;
2257
+ const point = { paragraphId, offset: caret.offset };
2258
+ surface.setSelection({ anchor: point, head: point });
2259
+ }
2260
+ async function insertGeneratedImage(editor, bytes, prompt, caret) {
2261
+ const image = normalizeImageBytes(bytes);
2262
+ if (!image.ok) throw new Error("The generated image is not in a format Word can embed.");
2263
+ let result;
2264
+ for (let attempt = 0; attempt < 3 && !result?.ok; attempt++) {
2265
+ editor.focus();
2266
+ restoreCaret(editor, caret);
2267
+ result = await executeImageCommand(editor, {
2268
+ type: "insertImage",
2269
+ data: image.bytes,
2270
+ mime: image.mime,
2271
+ widthPoints: image.widthPoints,
2272
+ heightPoints: image.heightPoints,
2273
+ description: prompt.trim(),
2274
+ title: titleOf(prompt)
2275
+ });
2276
+ if (!result.ok && result.reason !== "stale drawing selection") break;
2277
+ }
2278
+ if (!result?.ok) throw new Error(result?.reason || "The picture could not be inserted here.");
2279
+ }
2280
+ var AUTO = "";
2281
+ function useGenerateImageTarget() {
2282
+ const editor = useDocxEditor();
2283
+ const loaded2 = useEditorState((snapshot) => !snapshot.isLoading);
2284
+ useEffect(() => {
2285
+ if (!editor || !loaded2) return;
2286
+ mounted.push(editor);
2287
+ return () => void mounted.splice(mounted.indexOf(editor), 1);
2288
+ }, [editor, loaded2]);
2289
+ }
2290
+ function GenerateImageButton({ generation }) {
2291
+ const editor = useDocxEditor();
2292
+ const [prompt, setPrompt] = useState("");
2293
+ const [aspectRatio, setAspectRatio] = useState(AUTO);
2294
+ const [busy, setBusy] = useState(false);
2295
+ const [error, setError] = useState("");
2296
+ const abort = useRef(null);
2297
+ const close = useRef(() => {
2298
+ });
2299
+ const editable = useEditorState((snapshot) => snapshot.editable);
2300
+ const generating = useSyncExternalStore(subscribe, () => running > 0);
2301
+ async function run() {
2302
+ if (!editor || !prompt.trim() || busy) return;
2303
+ const caret = rememberCaret(editor);
2304
+ const controller = new AbortController();
2305
+ abort.current = controller;
2306
+ setBusy(true);
2307
+ setRunning(1);
2308
+ setError("");
2309
+ try {
2310
+ const bytes = await generation.generate(prompt.trim(), {
2311
+ aspectRatio: aspectRatio || void 0,
2312
+ signal: controller.signal
2313
+ });
2314
+ if (controller.signal.aborted) return;
2315
+ const target = insertionTarget(editor, caret);
2316
+ if (!target) throw new Error("The document was closed before the generated image was ready.");
2317
+ await insertGeneratedImage(target, bytes, prompt, caret);
2318
+ setPrompt("");
2319
+ close.current();
2320
+ generation.notify?.("Generated image inserted", "success");
2321
+ } catch (failure) {
2322
+ if (controller.signal.aborted) return;
2323
+ const message = failure instanceof Error ? failure.message : String(failure);
2324
+ setError(message);
2325
+ generation.notify?.(message, "error");
2326
+ } finally {
2327
+ abort.current = null;
2328
+ setRunning(-1);
2329
+ setBusy(false);
2330
+ }
2331
+ }
2332
+ if (!editable && !generating) return null;
2333
+ return /* @__PURE__ */ jsx(
2334
+ RibbonMenu,
2335
+ {
2336
+ label: generating ? "Generating image\u2026" : "Generate image",
2337
+ icon: generating ? /* @__PURE__ */ jsx(Loader2, { size: 16, className: "native-docx-spin" }) : /* @__PURE__ */ jsx(Sparkles, { size: 16 }),
2338
+ testId: "docx-generate-image",
2339
+ children: (dismiss) => {
2340
+ close.current = dismiss;
2341
+ return /* @__PURE__ */ jsxs(
2342
+ "form",
2343
+ {
2344
+ className: "native-docx-form native-docx-generate-image",
2345
+ onSubmit: (event) => {
2346
+ event.preventDefault();
2347
+ void run();
2348
+ },
2349
+ children: [
2350
+ /* @__PURE__ */ jsxs("label", { children: [
2351
+ "Describe the image",
2352
+ /* @__PURE__ */ jsx(
2353
+ "textarea",
2354
+ {
2355
+ autoFocus: true,
2356
+ rows: 3,
2357
+ value: prompt,
2358
+ disabled: busy,
2359
+ placeholder: "A watercolour of a lighthouse at dawn",
2360
+ "data-testid": "docx-generate-image-prompt",
2361
+ onChange: (event) => setPrompt(event.target.value),
2362
+ onKeyDown: (event) => {
2363
+ if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) void run();
2364
+ }
2365
+ }
2366
+ )
2367
+ ] }),
2368
+ generation.aspectRatios && generation.aspectRatios.length > 0 && /* @__PURE__ */ jsxs("label", { children: [
2369
+ "Aspect ratio",
2370
+ /* @__PURE__ */ jsxs(
2371
+ "select",
2372
+ {
2373
+ value: aspectRatio,
2374
+ disabled: busy,
2375
+ onChange: (event) => setAspectRatio(event.target.value),
2376
+ children: [
2377
+ /* @__PURE__ */ jsx("option", { value: AUTO, children: "Auto" }),
2378
+ generation.aspectRatios.map((ratio) => /* @__PURE__ */ jsx("option", { value: ratio.value, children: ratio.label }, ratio.value))
2379
+ ]
2380
+ }
2381
+ )
2382
+ ] }),
2383
+ busy && /* @__PURE__ */ jsx("p", { role: "status", "data-testid": "docx-generate-image-status", children: "Generating\u2026 the picture is inserted where your cursor was. You can keep writing." }),
2384
+ error && /* @__PURE__ */ jsx("p", { role: "alert", children: error }),
2385
+ /* @__PURE__ */ jsx("div", { className: "native-docx-form-actions", children: busy ? /* @__PURE__ */ jsx("button", { type: "button", onClick: () => abort.current?.abort(), children: "Cancel" }) : /* @__PURE__ */ jsx(
2386
+ "button",
2387
+ {
2388
+ type: "submit",
2389
+ disabled: !prompt.trim(),
2390
+ "data-testid": "docx-generate-image-submit",
2391
+ children: "Generate"
2392
+ }
2393
+ ) })
2394
+ ]
2395
+ }
2396
+ );
2397
+ }
2398
+ }
2399
+ );
2400
+ }
2333
2401
  function wordDraftHtml(markdown) {
2334
2402
  const template = document.createElement("template");
2335
2403
  template.innerHTML = renderToStaticMarkup(/* @__PURE__ */ jsx(AiMarkdown, { children: markdown }));
@@ -2417,61 +2485,6 @@ var WordDraftStream = class {
2417
2485
  }
2418
2486
  }
2419
2487
  };
2420
- function RibbonMenu({
2421
- label,
2422
- icon,
2423
- children,
2424
- className,
2425
- testId,
2426
- title
2427
- }) {
2428
- const [open, setOpen] = useState(false);
2429
- const element = useRef(null);
2430
- useEffect(() => {
2431
- if (!open) return;
2432
- const dismiss = (event) => {
2433
- if (!element.current?.contains(event.target)) setOpen(false);
2434
- };
2435
- const escape = (event) => {
2436
- if (event.key === "Escape") setOpen(false);
2437
- };
2438
- document.addEventListener("pointerdown", dismiss);
2439
- document.addEventListener("keydown", escape);
2440
- return () => {
2441
- document.removeEventListener("pointerdown", dismiss);
2442
- document.removeEventListener("keydown", escape);
2443
- };
2444
- }, [open]);
2445
- return /* @__PURE__ */ jsxs("div", { className: "native-docx-ribbon-menu", ref: element, children: [
2446
- /* @__PURE__ */ jsx(
2447
- "button",
2448
- {
2449
- type: "button",
2450
- className: ["native-docx-ribbon-trigger", className].filter(Boolean).join(" "),
2451
- "aria-label": label,
2452
- title: title ?? label,
2453
- "aria-expanded": open,
2454
- "data-testid": testId,
2455
- onMouseDown: (event) => event.preventDefault(),
2456
- onClick: () => setOpen((value) => !value),
2457
- children: icon
2458
- }
2459
- ),
2460
- open && /* @__PURE__ */ jsx(
2461
- "div",
2462
- {
2463
- className: "native-docx-ribbon-popover",
2464
- role: "group",
2465
- "aria-label": label,
2466
- onMouseDown: (event) => {
2467
- if (!(event.target instanceof HTMLInputElement || event.target instanceof HTMLSelectElement))
2468
- event.preventDefault();
2469
- },
2470
- children: typeof children === "function" ? children(() => setOpen(false)) : children
2471
- }
2472
- )
2473
- ] });
2474
- }
2475
2488
 
2476
2489
  // src/docx/wordStyles.ts
2477
2490
  var QUICK_STYLES = ["Normal", "Title", "heading 1", "heading 2", "heading 3"];
@@ -2761,6 +2774,679 @@ function WordShortcuts({ scope }) {
2761
2774
  }, [scope]);
2762
2775
  return null;
2763
2776
  }
2777
+
2778
+ // src/docx/layout/presets.ts
2779
+ var TWIPS_PER_INCH = 1440;
2780
+ var MARGIN_PRESETS = [
2781
+ { id: "normal", label: "Normal", top: 1440, right: 1440, bottom: 1440, left: 1440 },
2782
+ { id: "narrow", label: "Narrow", top: 720, right: 720, bottom: 720, left: 720 },
2783
+ { id: "moderate", label: "Moderate", top: 1440, right: 1080, bottom: 1440, left: 1080 },
2784
+ { id: "wide", label: "Wide", top: 1440, right: 2880, bottom: 1440, left: 2880 }
2785
+ ];
2786
+ var PAPER_SIZES = [
2787
+ { id: "letter", label: "Letter", width: 12240, height: 15840 },
2788
+ { id: "legal", label: "Legal", width: 12240, height: 20160 },
2789
+ { id: "a4", label: "A4", width: 11906, height: 16838 },
2790
+ { id: "a5", label: "A5", width: 8391, height: 11906 },
2791
+ { id: "executive", label: "Executive", width: 10440, height: 15120 }
2792
+ ];
2793
+ var TOLERANCE = 20;
2794
+ var near = (a, b) => Math.abs(a - b) <= TOLERANCE;
2795
+ function matchMargins(setup) {
2796
+ if (!setup) return null;
2797
+ const m = setup.marginsTwips;
2798
+ return MARGIN_PRESETS.find(
2799
+ (p) => near(p.top, m.top) && near(p.right, m.right) && near(p.bottom, m.bottom) && near(p.left, m.left)
2800
+ )?.id ?? null;
2801
+ }
2802
+ function matchPaper(setup) {
2803
+ if (!setup) return null;
2804
+ const short = Math.min(setup.pageWidthTwips, setup.pageHeightTwips);
2805
+ const long = Math.max(setup.pageWidthTwips, setup.pageHeightTwips);
2806
+ return PAPER_SIZES.find((p) => near(p.width, short) && near(p.height, long))?.id ?? null;
2807
+ }
2808
+ function orientedSize(paper, orientation) {
2809
+ return orientation === "landscape" ? { pageWidthTwips: paper.height, pageHeightTwips: paper.width } : { pageWidthTwips: paper.width, pageHeightTwips: paper.height };
2810
+ }
2811
+ function inches(twips) {
2812
+ return `${Number((twips / TWIPS_PER_INCH).toFixed(2))}"`;
2813
+ }
2814
+ function paperDescription(paper) {
2815
+ return `${inches(paper.width)} \xD7 ${inches(paper.height)}`;
2816
+ }
2817
+ var COLUMNS_UNSUPPORTED = "Text columns are not available in this editor yet. Documents that already use columns display and save them unchanged.";
2818
+ function RibbonGallery({
2819
+ label,
2820
+ choices,
2821
+ current,
2822
+ onPick,
2823
+ close,
2824
+ testId
2825
+ }) {
2826
+ return /* @__PURE__ */ jsx("div", { className: "native-docx-gallery", role: "menu", "aria-label": label, "data-testid": testId, children: choices.map((choice) => /* @__PURE__ */ jsxs(
2827
+ "button",
2828
+ {
2829
+ type: "button",
2830
+ role: "menuitemradio",
2831
+ "aria-checked": current === choice.id,
2832
+ disabled: choice.disabled,
2833
+ title: choice.title,
2834
+ "data-choice": choice.id,
2835
+ onClick: () => {
2836
+ onPick(choice.id);
2837
+ close();
2838
+ },
2839
+ children: [
2840
+ choice.icon,
2841
+ /* @__PURE__ */ jsxs("span", { className: "native-docx-gallery-text", children: [
2842
+ /* @__PURE__ */ jsx("span", { className: "native-docx-gallery-label", children: choice.label }),
2843
+ choice.detail && /* @__PURE__ */ jsx("span", { className: "native-docx-gallery-detail", children: choice.detail })
2844
+ ] })
2845
+ ]
2846
+ },
2847
+ choice.id
2848
+ )) });
2849
+ }
2850
+ var marginDetail = (p) => `Top ${inches(p.top)} \xB7 Bottom ${inches(p.bottom)} \xB7 Left ${inches(p.left)} \xB7 Right ${inches(p.right)}`;
2851
+ function Margins({ setup, apply, openDialog }) {
2852
+ return /* @__PURE__ */ jsx(RibbonMenu, { label: "Margins", icon: /* @__PURE__ */ jsx(Scaling, { size: 16 }), testId: "docx-layout-margins", children: (close) => /* @__PURE__ */ jsxs(Fragment, { children: [
2853
+ /* @__PURE__ */ jsx(
2854
+ RibbonGallery,
2855
+ {
2856
+ label: "Margins",
2857
+ current: matchMargins(setup),
2858
+ close,
2859
+ choices: MARGIN_PRESETS.map((p) => ({
2860
+ id: p.id,
2861
+ label: p.label,
2862
+ detail: marginDetail(p)
2863
+ })),
2864
+ onPick: (id) => {
2865
+ const p = MARGIN_PRESETS.find((m) => m.id === id);
2866
+ apply({
2867
+ marginTopTwips: p.top,
2868
+ marginRightTwips: p.right,
2869
+ marginBottomTwips: p.bottom,
2870
+ marginLeftTwips: p.left,
2871
+ scope: "section"
2872
+ });
2873
+ }
2874
+ }
2875
+ ),
2876
+ /* @__PURE__ */ jsx(
2877
+ "button",
2878
+ {
2879
+ type: "button",
2880
+ className: "native-docx-gallery-more",
2881
+ onClick: () => {
2882
+ close();
2883
+ openDialog();
2884
+ },
2885
+ children: "Custom margins\u2026"
2886
+ }
2887
+ )
2888
+ ] }) });
2889
+ }
2890
+ function Orientation({ setup, apply }) {
2891
+ return /* @__PURE__ */ jsx(
2892
+ RibbonMenu,
2893
+ {
2894
+ label: "Orientation",
2895
+ icon: setup?.orientation === "landscape" ? /* @__PURE__ */ jsx(RectangleHorizontal, { size: 16 }) : /* @__PURE__ */ jsx(RectangleVertical, { size: 16 }),
2896
+ testId: "docx-layout-orientation",
2897
+ children: (close) => /* @__PURE__ */ jsx(
2898
+ RibbonGallery,
2899
+ {
2900
+ label: "Orientation",
2901
+ current: setup?.orientation,
2902
+ close,
2903
+ choices: [
2904
+ { id: "portrait", label: "Portrait", icon: /* @__PURE__ */ jsx(RectangleVertical, { size: 16 }) },
2905
+ { id: "landscape", label: "Landscape", icon: /* @__PURE__ */ jsx(RectangleHorizontal, { size: 16 }) }
2906
+ ],
2907
+ onPick: (id) => apply({ orientation: id, scope: "section" })
2908
+ }
2909
+ )
2910
+ }
2911
+ );
2912
+ }
2913
+ function Size({ setup, apply, openDialog }) {
2914
+ return /* @__PURE__ */ jsx(RibbonMenu, { label: "Size", icon: /* @__PURE__ */ jsx(FileText, { size: 16 }), testId: "docx-layout-size", children: (close) => /* @__PURE__ */ jsxs(Fragment, { children: [
2915
+ /* @__PURE__ */ jsx(
2916
+ RibbonGallery,
2917
+ {
2918
+ label: "Size",
2919
+ current: matchPaper(setup),
2920
+ close,
2921
+ choices: PAPER_SIZES.map((p) => ({
2922
+ id: p.id,
2923
+ label: p.label,
2924
+ detail: paperDescription(p)
2925
+ })),
2926
+ onPick: (id) => apply({
2927
+ ...orientedSize(
2928
+ PAPER_SIZES.find((p) => p.id === id),
2929
+ setup?.orientation
2930
+ ),
2931
+ scope: "section"
2932
+ })
2933
+ }
2934
+ ),
2935
+ /* @__PURE__ */ jsx(
2936
+ "button",
2937
+ {
2938
+ type: "button",
2939
+ className: "native-docx-gallery-more",
2940
+ onClick: () => {
2941
+ close();
2942
+ openDialog();
2943
+ },
2944
+ children: "More paper sizes\u2026"
2945
+ }
2946
+ )
2947
+ ] }) });
2948
+ }
2949
+ var COLUMN_BREAK = { type: "insertBreak", kind: "column" };
2950
+ function Breaks() {
2951
+ const page = useEditorCommand("insert.pageBreak");
2952
+ const nextPage = useEditorCommand("insert.sectionBreakNextPage");
2953
+ const continuous = useEditorCommand("insert.sectionBreakContinuous");
2954
+ const column = useEditorCommand(COLUMN_BREAK);
2955
+ const rows = [
2956
+ { id: "page", label: "Page", detail: "Start the next page here", command: page },
2957
+ { id: "column", label: "Column", detail: "Start the next column here", command: column },
2958
+ {
2959
+ id: "nextPage",
2960
+ label: "Next Page",
2961
+ detail: "Section break: new section on the next page",
2962
+ command: nextPage
2963
+ },
2964
+ {
2965
+ id: "continuous",
2966
+ label: "Continuous",
2967
+ detail: "Section break: new section on the same page",
2968
+ command: continuous
2969
+ }
2970
+ ];
2971
+ return /* @__PURE__ */ jsx(RibbonMenu, { label: "Breaks", icon: /* @__PURE__ */ jsx(SeparatorHorizontal, { size: 16 }), testId: "docx-layout-breaks", children: (close) => /* @__PURE__ */ jsx(
2972
+ RibbonGallery,
2973
+ {
2974
+ label: "Breaks",
2975
+ close,
2976
+ choices: rows.map((row) => ({
2977
+ id: row.id,
2978
+ label: row.label,
2979
+ detail: row.detail,
2980
+ disabled: !row.command.isEnabled,
2981
+ title: row.command.disabledReason ?? void 0
2982
+ })),
2983
+ onPick: (id) => void rows.find((row) => row.id === id)?.command.execute()
2984
+ }
2985
+ ) });
2986
+ }
2987
+ function LayoutButtons() {
2988
+ const { pageSetup, apply } = usePageSetup();
2989
+ const [dialog, setDialog] = useState(false);
2990
+ const props = { setup: pageSetup, apply, openDialog: () => setDialog(true) };
2991
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
2992
+ /* @__PURE__ */ jsx(Margins, { ...props }),
2993
+ /* @__PURE__ */ jsx(Orientation, { ...props }),
2994
+ /* @__PURE__ */ jsx(Size, { ...props }),
2995
+ /* @__PURE__ */ jsx(
2996
+ DocxEditor.Toolbar.Action,
2997
+ {
2998
+ label: "Columns",
2999
+ icon: /* @__PURE__ */ jsx(Columns2, { size: 16 }),
3000
+ disabled: true,
3001
+ disabledReason: COLUMNS_UNSUPPORTED,
3002
+ className: "native-docx-layout-columns"
3003
+ }
3004
+ ),
3005
+ /* @__PURE__ */ jsx(Breaks, {}),
3006
+ /* @__PURE__ */ jsx(
3007
+ DocxEditor.Toolbar.Action,
3008
+ {
3009
+ label: "Page Setup\u2026",
3010
+ icon: /* @__PURE__ */ jsx(Settings2, { size: 16 }),
3011
+ onSelect: () => setDialog(true),
3012
+ className: "native-docx-layout-page-setup"
3013
+ }
3014
+ ),
3015
+ /* @__PURE__ */ jsx(DocxEditor.PageSetupDialog, { open: dialog, onClose: () => setDialog(false) })
3016
+ ] });
3017
+ }
3018
+ var ROW_ABOVE = { type: "insertRow", where: "above" };
3019
+ var ROW_BELOW = { type: "insertRow", where: "below" };
3020
+ var COLUMN_LEFT = { type: "insertColumn", where: "left" };
3021
+ var COLUMN_RIGHT = { type: "insertColumn", where: "right" };
3022
+ var MERGE = { type: "mergeCells" };
3023
+ var SPLIT = { type: "splitCell", rows: 1, cols: 2 };
3024
+ var HEADER_ROW = { type: "toggleHeaderRow" };
3025
+ var DELETE_ROW = { type: "deleteRow" };
3026
+ var DELETE_COLUMN = { type: "deleteColumn" };
3027
+ var DELETE_TABLE = { type: "deleteTable" };
3028
+ var ALIGN_TOP = { type: "setTableCellVerticalAlignment", alignment: "top" };
3029
+ var ALIGN_CENTER = { type: "setTableCellVerticalAlignment", alignment: "center" };
3030
+ var ALIGN_BOTTOM = { type: "setTableCellVerticalAlignment", alignment: "bottom" };
3031
+ function useRows(rows) {
3032
+ return rows.map((row) => ({ ...row, state: useEditorCommand(row.command) }));
3033
+ }
3034
+ function CommandGallery({
3035
+ label,
3036
+ icon,
3037
+ testId,
3038
+ rows
3039
+ }) {
3040
+ const bound = useRows(rows);
3041
+ return /* @__PURE__ */ jsx(RibbonMenu, { label, icon, testId, children: (close) => /* @__PURE__ */ jsx(
3042
+ RibbonGallery,
3043
+ {
3044
+ label,
3045
+ close,
3046
+ choices: bound.map((row) => ({
3047
+ id: row.id,
3048
+ label: row.label,
3049
+ icon: row.icon,
3050
+ disabled: !row.state.isEnabled,
3051
+ title: row.state.disabledReason ?? void 0
3052
+ })),
3053
+ onPick: (id) => void bound.find((row) => row.id === id)?.state.execute()
3054
+ }
3055
+ ) });
3056
+ }
3057
+ function CommandAction({
3058
+ command,
3059
+ label,
3060
+ icon,
3061
+ testId
3062
+ }) {
3063
+ const state = useEditorCommand(command);
3064
+ return /* @__PURE__ */ jsx(
3065
+ DocxEditor.Toolbar.Action,
3066
+ {
3067
+ label,
3068
+ icon,
3069
+ active: state.isActive,
3070
+ disabled: !state.isEnabled,
3071
+ disabledReason: state.disabledReason ?? void 0,
3072
+ onSelect: () => void state.execute(),
3073
+ className: `native-docx-table-${testId}`
3074
+ }
3075
+ );
3076
+ }
3077
+ function TableButtons() {
3078
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3079
+ /* @__PURE__ */ jsx(
3080
+ CommandAction,
3081
+ {
3082
+ command: ROW_ABOVE,
3083
+ label: "Insert row above",
3084
+ icon: /* @__PURE__ */ jsx(BetweenHorizontalStart, { size: 16 }),
3085
+ testId: "row-above"
3086
+ }
3087
+ ),
3088
+ /* @__PURE__ */ jsx(
3089
+ CommandAction,
3090
+ {
3091
+ command: ROW_BELOW,
3092
+ label: "Insert row below",
3093
+ icon: /* @__PURE__ */ jsx(BetweenHorizontalEnd, { size: 16 }),
3094
+ testId: "row-below"
3095
+ }
3096
+ ),
3097
+ /* @__PURE__ */ jsx(
3098
+ CommandAction,
3099
+ {
3100
+ command: COLUMN_LEFT,
3101
+ label: "Insert column left",
3102
+ icon: /* @__PURE__ */ jsx(BetweenVerticalStart, { size: 16 }),
3103
+ testId: "column-left"
3104
+ }
3105
+ ),
3106
+ /* @__PURE__ */ jsx(
3107
+ CommandAction,
3108
+ {
3109
+ command: COLUMN_RIGHT,
3110
+ label: "Insert column right",
3111
+ icon: /* @__PURE__ */ jsx(BetweenVerticalEnd, { size: 16 }),
3112
+ testId: "column-right"
3113
+ }
3114
+ ),
3115
+ /* @__PURE__ */ jsx(
3116
+ CommandGallery,
3117
+ {
3118
+ label: "Delete",
3119
+ icon: /* @__PURE__ */ jsx(Trash2, { size: 16 }),
3120
+ testId: "docx-table-delete",
3121
+ rows: [
3122
+ { id: "row", label: "Delete row", command: DELETE_ROW },
3123
+ { id: "column", label: "Delete column", command: DELETE_COLUMN },
3124
+ { id: "table", label: "Delete table", command: DELETE_TABLE }
3125
+ ]
3126
+ }
3127
+ ),
3128
+ /* @__PURE__ */ jsx(
3129
+ CommandAction,
3130
+ {
3131
+ command: MERGE,
3132
+ label: "Merge cells",
3133
+ icon: /* @__PURE__ */ jsx(Merge, { size: 16 }),
3134
+ testId: "merge"
3135
+ }
3136
+ ),
3137
+ /* @__PURE__ */ jsx(CommandAction, { command: SPLIT, label: "Split cell", icon: /* @__PURE__ */ jsx(Split, { size: 16 }), testId: "split" }),
3138
+ /* @__PURE__ */ jsx(
3139
+ CommandAction,
3140
+ {
3141
+ command: HEADER_ROW,
3142
+ label: "Repeat header row",
3143
+ icon: /* @__PURE__ */ jsx(Heading, { size: 16 }),
3144
+ testId: "header-row"
3145
+ }
3146
+ ),
3147
+ /* @__PURE__ */ jsx(
3148
+ CommandGallery,
3149
+ {
3150
+ label: "Cell alignment",
3151
+ icon: /* @__PURE__ */ jsx(AlignVerticalJustifyCenter, { size: 16 }),
3152
+ testId: "docx-table-align",
3153
+ rows: [
3154
+ {
3155
+ id: "top",
3156
+ label: "Top",
3157
+ icon: /* @__PURE__ */ jsx(AlignVerticalJustifyStart, { size: 16 }),
3158
+ command: ALIGN_TOP
3159
+ },
3160
+ {
3161
+ id: "center",
3162
+ label: "Center",
3163
+ icon: /* @__PURE__ */ jsx(AlignVerticalJustifyCenter, { size: 16 }),
3164
+ command: ALIGN_CENTER
3165
+ },
3166
+ {
3167
+ id: "bottom",
3168
+ label: "Bottom",
3169
+ icon: /* @__PURE__ */ jsx(AlignVerticalJustifyEnd, { size: 16 }),
3170
+ command: ALIGN_BOTTOM
3171
+ }
3172
+ ]
3173
+ }
3174
+ ),
3175
+ /* @__PURE__ */ jsx(DocxEditor.Toolbar.TableBorderTarget, {}),
3176
+ /* @__PURE__ */ jsx(DocxEditor.Toolbar.TableBorderStyle, {}),
3177
+ /* @__PURE__ */ jsx(DocxEditor.Toolbar.TableBorderWidth, {}),
3178
+ /* @__PURE__ */ jsx(DocxEditor.Toolbar.TableBorderColor, {}),
3179
+ /* @__PURE__ */ jsx(DocxEditor.Toolbar.TableCellFill, {})
3180
+ ] });
3181
+ }
3182
+ var CAPTION_LABELS = ["Figure", "Table", "Equation"];
3183
+ var CAPTION_STYLES = stylesXml(
3184
+ "",
3185
+ '<w:style w:type="paragraph" w:default="1" w:styleId="Normal"><w:name w:val="Normal"/><w:qFormat/></w:style><w:style w:type="paragraph" w:styleId="Caption"><w:name w:val="caption"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:uiPriority w:val="35"/><w:unhideWhenUsed/><w:qFormat/><w:pPr><w:spacing w:after="200" w:line="240" w:lineRule="auto"/></w:pPr><w:rPr><w:i/><w:iCs/><w:color w:val="44546A"/><w:sz w:val="18"/><w:szCs w:val="18"/></w:rPr></w:style>'
3186
+ );
3187
+ function seqIdentifier(instruction) {
3188
+ const match = /^\s*SEQ\s+("[^"]+"|\S+)/i.exec(instruction);
3189
+ return match ? match[1].replace(/"/g, "") : null;
3190
+ }
3191
+ function countSeqFields(root, label, throughId) {
3192
+ let count = 0;
3193
+ let done = false;
3194
+ const target = label.toLowerCase();
3195
+ const visit = (node) => {
3196
+ if (done) return;
3197
+ if (node.localName === "fldSimple") {
3198
+ const instr = node.attributes?.find((a) => a.localName === "instr")?.value ?? "";
3199
+ if (seqIdentifier(instr)?.toLowerCase() === target) count++;
3200
+ } else if (node.localName === "instrText") {
3201
+ const text = (node.children ?? []).map((c) => c.value ?? "").join("");
3202
+ if (seqIdentifier(text)?.toLowerCase() === target) count++;
3203
+ }
3204
+ node.children?.forEach(visit);
3205
+ if (throughId && node.id === throughId) done = true;
3206
+ };
3207
+ visit(root);
3208
+ return count;
3209
+ }
3210
+ function captionParagraphXml(label, number, text) {
3211
+ const run = (value) => `<w:r><w:t xml:space="preserve">${esc(value)}</w:t></w:r>`;
3212
+ const rest = text.trim() ? `: ${text.trim()}` : "";
3213
+ return `<w:p><w:pPr><w:pStyle w:val="Caption"/></w:pPr>${run(`${label} `)}<w:fldSimple w:instr=" SEQ ${esc(label)} \\* ARABIC "><w:r><w:t>${number}</w:t></w:r></w:fldSimple>${rest ? run(rest) : ""}</w:p>`;
3214
+ }
3215
+ function base642(bytes) {
3216
+ let binary = "";
3217
+ for (let i = 0; i < bytes.length; i += 32768)
3218
+ binary += String.fromCharCode(...bytes.subarray(i, i + 32768));
3219
+ return btoa(binary);
3220
+ }
3221
+ function captionFragmentHtml(label, number, text, revision) {
3222
+ const untracked = docxPackage({
3223
+ document: documentXml(captionParagraphXml(label, number, text)),
3224
+ styles: CAPTION_STYLES,
3225
+ title: "Caption"
3226
+ });
3227
+ const bytes = revision ? trackInsertion(untracked, revision, true) : untracked;
3228
+ return `<div data-docx-fragment="${base642(bytes)}" data-docx-fragment-end="covered"></div>`;
3229
+ }
3230
+ var TRANSFORMS = Object.fromEntries(
3231
+ ["rotateCW", "rotateCCW", "flipH", "flipV"].map((action) => [
3232
+ action,
3233
+ { type: "transformImage", action }
3234
+ ])
3235
+ );
3236
+ function TransformAction({
3237
+ action,
3238
+ label,
3239
+ icon
3240
+ }) {
3241
+ const state = useEditorCommand(TRANSFORMS[action]);
3242
+ return /* @__PURE__ */ jsx(
3243
+ DocxEditor.Toolbar.Action,
3244
+ {
3245
+ label,
3246
+ icon,
3247
+ disabled: !state.isEnabled,
3248
+ disabledReason: state.disabledReason ?? void 0,
3249
+ onSelect: () => void state.execute(),
3250
+ className: `native-docx-picture-${action}`
3251
+ }
3252
+ );
3253
+ }
3254
+ function insertCaption(editor, label, text, track) {
3255
+ const surface = editor.surface;
3256
+ const selection = surface?.state().selection;
3257
+ if (!surface || !selection) return null;
3258
+ const { paragraphId } = selection.head;
3259
+ const number = countSeqFields(
3260
+ surface.session.part().root,
3261
+ label,
3262
+ paragraphId
3263
+ ) + 1;
3264
+ const ids = surface.session.paragraphIds();
3265
+ const next = ids[ids.indexOf(paragraphId) + 1];
3266
+ const caption = `${label} ${number}${text.trim() ? `: ${text.trim()}` : ""}`;
3267
+ const outcome = track({
3268
+ label: `Inserted caption: ${caption}`,
3269
+ inserted: (inserted) => inserted !== null,
3270
+ insert: (revision) => {
3271
+ if (next) {
3272
+ surface.setSelection({
3273
+ anchor: { paragraphId: next, offset: 0 },
3274
+ head: { paragraphId: next, offset: 0 }
3275
+ });
3276
+ } else {
3277
+ editor.exec({ type: "selectAll" });
3278
+ const end = surface.state().selection?.head;
3279
+ if (!end) return null;
3280
+ surface.setSelection({ anchor: end, head: end });
3281
+ surface.splitParagraph();
3282
+ }
3283
+ const ok2 = editor.exec({
3284
+ type: "paste",
3285
+ text: caption,
3286
+ html: captionFragmentHtml(label, number, text, revision)
3287
+ }).ok;
3288
+ return ok2 ? number : null;
3289
+ }
3290
+ });
3291
+ return outcome?.result ?? null;
3292
+ }
3293
+ function CaptionButton({ defaultLabel = "Figure" }) {
3294
+ const editor = useDocxEditor();
3295
+ const track = useTrackedOrNoted();
3296
+ const [label, setLabel] = useState(defaultLabel);
3297
+ const [text, setText] = useState("");
3298
+ const [error, setError] = useState("");
3299
+ return /* @__PURE__ */ jsx(RibbonMenu, { label: "Insert caption", icon: /* @__PURE__ */ jsx(Captions, { size: 16 }), testId: "docx-insert-caption", children: (close) => /* @__PURE__ */ jsxs(
3300
+ "form",
3301
+ {
3302
+ className: "native-docx-form",
3303
+ onSubmit: (event) => {
3304
+ event.preventDefault();
3305
+ if (!editor) return;
3306
+ try {
3307
+ if (insertCaption(editor, label, text, track) === null)
3308
+ return setError("The caption could not be inserted here.");
3309
+ setText("");
3310
+ setError("");
3311
+ close();
3312
+ editor.focus();
3313
+ } catch (failure) {
3314
+ setError(failure instanceof Error ? failure.message : String(failure));
3315
+ }
3316
+ },
3317
+ children: [
3318
+ /* @__PURE__ */ jsxs("label", { children: [
3319
+ "Label",
3320
+ /* @__PURE__ */ jsx(
3321
+ "select",
3322
+ {
3323
+ value: label,
3324
+ onChange: (event) => setLabel(event.target.value),
3325
+ children: CAPTION_LABELS.map((value) => /* @__PURE__ */ jsx("option", { children: value }, value))
3326
+ }
3327
+ )
3328
+ ] }),
3329
+ /* @__PURE__ */ jsxs("label", { children: [
3330
+ "Caption",
3331
+ /* @__PURE__ */ jsx(
3332
+ "input",
3333
+ {
3334
+ autoFocus: true,
3335
+ value: text,
3336
+ placeholder: "Optional text after the number",
3337
+ "data-testid": "docx-caption-text",
3338
+ onChange: (event) => setText(event.target.value)
3339
+ }
3340
+ )
3341
+ ] }),
3342
+ error && /* @__PURE__ */ jsx("p", { role: "alert", children: error }),
3343
+ /* @__PURE__ */ jsx("button", { type: "submit", "data-testid": "docx-caption-insert", children: "Insert" })
3344
+ ]
3345
+ }
3346
+ ) });
3347
+ }
3348
+ function PictureButtons() {
3349
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3350
+ /* @__PURE__ */ jsx(DocxEditor.Toolbar.ImageWrap, {}),
3351
+ /* @__PURE__ */ jsx(DocxEditor.Toolbar.ImageProperties, {}),
3352
+ /* @__PURE__ */ jsx(DocxEditor.Toolbar.ImageAltText, {}),
3353
+ /* @__PURE__ */ jsx(TransformAction, { action: "rotateCW", label: "Rotate right 90\xB0", icon: /* @__PURE__ */ jsx(RotateCw, { size: 16 }) }),
3354
+ /* @__PURE__ */ jsx(TransformAction, { action: "rotateCCW", label: "Rotate left 90\xB0", icon: /* @__PURE__ */ jsx(RotateCcw, { size: 16 }) }),
3355
+ /* @__PURE__ */ jsx(
3356
+ TransformAction,
3357
+ {
3358
+ action: "flipH",
3359
+ label: "Flip horizontal",
3360
+ icon: /* @__PURE__ */ jsx(FlipHorizontal2, { size: 16 })
3361
+ }
3362
+ ),
3363
+ /* @__PURE__ */ jsx(TransformAction, { action: "flipV", label: "Flip vertical", icon: /* @__PURE__ */ jsx(FlipVertical2, { size: 16 }) }),
3364
+ /* @__PURE__ */ jsx(CaptionButton, {})
3365
+ ] });
3366
+ }
3367
+ var LAYOUT_TAB = "Layout";
3368
+ var TABLE_TAB = "Table";
3369
+ var PICTURE_TAB = "Picture";
3370
+ function useContextualTabs(tab) {
3371
+ const inTable = useEditorState((snapshot) => snapshot.table !== null);
3372
+ const onPicture = useEditorState((snapshot) => snapshot.image !== null);
3373
+ const tabs = [...inTable ? [TABLE_TAB] : [], ...onPicture ? [PICTURE_TAB] : []];
3374
+ const contextual = tab === TABLE_TAB || tab === PICTURE_TAB;
3375
+ return { tabs, shown: contextual && !tabs.includes(tab) ? "Home" : tab };
3376
+ }
3377
+ function LayoutTabContent({ tab }) {
3378
+ if (tab === LAYOUT_TAB) return /* @__PURE__ */ jsx(LayoutButtons, {});
3379
+ if (tab === TABLE_TAB) return /* @__PURE__ */ jsx(TableButtons, {});
3380
+ if (tab === PICTURE_TAB) return /* @__PURE__ */ jsx(PictureButtons, {});
3381
+ return null;
3382
+ }
3383
+ var contains = (node, id) => node.id === id || (node.children ?? []).some((child) => contains(child, id));
3384
+ function firstParagraph(node) {
3385
+ for (const child of node.children ?? []) {
3386
+ if (child.kind === "paragraph" && child.id) return child.id;
3387
+ if (child.localName === "tbl") continue;
3388
+ const nested = firstParagraph(child);
3389
+ if (nested) return nested;
3390
+ }
3391
+ return null;
3392
+ }
3393
+ function tableCells(root, paragraphId) {
3394
+ let table = null;
3395
+ const find = (node) => {
3396
+ if (node.localName === "tbl" && contains(node, paragraphId)) table = node;
3397
+ for (const child of node.children ?? []) if (contains(child, paragraphId)) find(child);
3398
+ };
3399
+ find(root);
3400
+ if (!table) return null;
3401
+ const cells = [];
3402
+ let index = -1;
3403
+ const rows = (node) => (node.children ?? []).flatMap(
3404
+ (child) => child.localName === "tr" ? [child] : child.localName === "tbl" ? [] : rows(child)
3405
+ );
3406
+ for (const row of rows(table))
3407
+ for (const cell of (row.children ?? []).filter((child) => child.localName === "tc")) {
3408
+ const first = firstParagraph(cell);
3409
+ if (!first) continue;
3410
+ if (contains(cell, paragraphId)) index = cells.length;
3411
+ cells.push(first);
3412
+ }
3413
+ return index < 0 ? null : { cells, index };
3414
+ }
3415
+ function TableTabKeys({ scope }) {
3416
+ const editor = useDocxEditor();
3417
+ const latest = useRef(editor);
3418
+ latest.current = editor;
3419
+ useEffect(() => {
3420
+ const element = scope.current;
3421
+ if (!element) return;
3422
+ const onKeyDown = (event) => {
3423
+ if (event.key !== "Tab" || event.ctrlKey || event.metaKey || event.altKey) return;
3424
+ const editor2 = latest.current;
3425
+ const surface = editor2?.surface;
3426
+ const head = surface?.state().selection?.head;
3427
+ if (!editor2 || !surface || !head) return;
3428
+ const root = () => surface.session.part().root;
3429
+ const table = tableCells(root(), head.paragraphId);
3430
+ if (!table) return;
3431
+ event.preventDefault();
3432
+ event.stopPropagation();
3433
+ let target = table.cells[table.index + (event.shiftKey ? -1 : 1)];
3434
+ if (!target && !event.shiftKey && editor2.exec({ type: "insertRow", where: "below" }).ok) {
3435
+ const grown = tableCells(
3436
+ root(),
3437
+ surface.state().selection?.head.paragraphId ?? head.paragraphId
3438
+ );
3439
+ target = grown?.cells[table.cells.length] ?? "";
3440
+ }
3441
+ if (!target) return;
3442
+ const point = { paragraphId: target, offset: 0 };
3443
+ surface.setSelection({ anchor: point, head: point });
3444
+ };
3445
+ element.addEventListener("keydown", onKeyDown, true);
3446
+ return () => element.removeEventListener("keydown", onKeyDown, true);
3447
+ }, [scope]);
3448
+ return null;
3449
+ }
2764
3450
  function QuickParts() {
2765
3451
  const house = useHouseTemplate();
2766
3452
  if (!house || house.blocks.length === 0) return null;
@@ -2900,48 +3586,39 @@ function DocxParticipants({ session }) {
2900
3586
  function DefinedTermButtons() {
2901
3587
  const terms = useDefinedTerms();
2902
3588
  if (!terms) return null;
2903
- return /* @__PURE__ */ jsxs(Fragment, { children: [
2904
- /* @__PURE__ */ jsx(
2905
- "button",
2906
- {
2907
- type: "button",
2908
- className: "native-docx-ribbon-trigger",
2909
- "aria-label": terms.labels.insert,
2910
- title: `${terms.labels.insert} (type @@)`,
2911
- "data-testid": "docx-insert-defined-term",
2912
- onMouseDown: (event) => event.preventDefault(),
2913
- onClick: (event) => terms.openPicker(event.currentTarget),
2914
- children: /* @__PURE__ */ jsx(BookA, { size: 16 })
2915
- }
2916
- ),
2917
- /* @__PURE__ */ jsx(
2918
- "button",
2919
- {
2920
- type: "button",
2921
- className: "native-docx-ribbon-trigger",
2922
- "aria-label": terms.labels.update,
2923
- title: terms.labels.update,
2924
- "data-testid": "docx-update-definitions",
2925
- onMouseDown: (event) => event.preventDefault(),
2926
- onClick: () => terms.update(),
2927
- children: /* @__PURE__ */ jsx(ListRestart, { size: 16 })
2928
- }
2929
- )
2930
- ] });
3589
+ return /* @__PURE__ */ jsx(
3590
+ "button",
3591
+ {
3592
+ type: "button",
3593
+ className: "native-docx-ribbon-trigger",
3594
+ "aria-label": terms.labels.insert,
3595
+ title: `${terms.labels.insert} (type @@)`,
3596
+ "data-testid": "docx-insert-defined-term",
3597
+ onMouseDown: (event) => event.preventDefault(),
3598
+ onClick: (event) => terms.openPicker(event.currentTarget),
3599
+ children: /* @__PURE__ */ jsx(BookA, { size: 16 })
3600
+ }
3601
+ );
2931
3602
  }
2932
3603
  function DocxRibbon({
2933
3604
  onSave,
2934
- badge
3605
+ badge,
3606
+ imageGeneration
2935
3607
  }) {
2936
- const [tab, setTab] = useState("Home");
3608
+ const [selected, setTab] = useState("Home");
3609
+ const contextual = useContextualTabs(selected);
3610
+ useGenerateImageTarget();
3611
+ const tab = contextual.shown;
2937
3612
  const t = useChromeTranslate();
2938
3613
  return /* @__PURE__ */ jsxs("div", { className: "native-docx-ribbon", children: [
2939
3614
  /* @__PURE__ */ jsxs("select", { "aria-label": "Ribbon tab", value: tab, onChange: (event) => setTab(event.target.value), children: [
2940
3615
  /* @__PURE__ */ jsx("option", { children: "Home" }),
2941
3616
  /* @__PURE__ */ jsx("option", { children: "Insert" }),
2942
3617
  /* @__PURE__ */ jsx("option", { children: "Design" }),
3618
+ /* @__PURE__ */ jsx("option", { children: LAYOUT_TAB }),
2943
3619
  /* @__PURE__ */ jsx("option", { children: "References" }),
2944
- /* @__PURE__ */ jsx("option", { children: "Review" })
3620
+ /* @__PURE__ */ jsx("option", { children: "Review" }),
3621
+ contextual.tabs.map((name) => /* @__PURE__ */ jsx("option", { children: name }, name))
2945
3622
  ] }),
2946
3623
  /* @__PURE__ */ jsxs(DocxEditor.Toolbar, { t, preset: false, onSave, children: [
2947
3624
  /* @__PURE__ */ jsx(DocxEditor.Toolbar.Undo, {}),
@@ -2972,10 +3649,14 @@ function DocxRibbon({
2972
3649
  tab === "Insert" && /* @__PURE__ */ jsxs(Fragment, { children: [
2973
3650
  /* @__PURE__ */ jsx(DocxEditor.Toolbar.TableInsert, {}),
2974
3651
  /* @__PURE__ */ jsx(DocxEditor.Toolbar.ImageInsert, {}),
3652
+ imageGeneration && /* @__PURE__ */ jsx(GenerateImageButton, { generation: imageGeneration }),
3653
+ /* @__PURE__ */ jsx(DocxEditor.Toolbar.Button, { slotId: "insert.pageBreak" }),
2975
3654
  /* @__PURE__ */ jsx(DocxEditor.Toolbar.Link, {}),
2976
3655
  /* @__PURE__ */ jsx(DefinedTermButtons, {}),
2977
3656
  /* @__PURE__ */ jsx(QuickParts, {})
2978
3657
  ] }),
3658
+ /* @__PURE__ */ jsx(DocxEditor.Toolbar.TableCellFill, { hidden: true }),
3659
+ /* @__PURE__ */ jsx(LayoutTabContent, { tab }),
2979
3660
  tab === "Design" && /* @__PURE__ */ jsx(HouseTemplatePanel, {}),
2980
3661
  tab === "References" && /* @__PURE__ */ jsx(NoteButtons, {}),
2981
3662
  tab === "Review" && /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -3351,6 +4032,10 @@ function NativeDocxEditor({
3351
4032
  DocxRibbon,
3352
4033
  {
3353
4034
  onSave: () => void saveVersion(),
4035
+ imageGeneration: adapter.imageGeneration && {
4036
+ notify: adapter.notify,
4037
+ ...adapter.imageGeneration
4038
+ },
3354
4039
  badge: (
3355
4040
  // Says the document is shared live, in place of a title row above the ribbon.
3356
4041
  ready.room && ready.canEdit && !snapshot ? /* @__PURE__ */ jsx("span", { title: "Edits sync live with everyone who has this document open", children: "Co-edit mode" }) : void 0
@@ -3358,6 +4043,7 @@ function NativeDocxEditor({
3358
4043
  }
3359
4044
  ),
3360
4045
  !stream && /* @__PURE__ */ jsx(WordShortcuts, { scope: stageRef }),
4046
+ !stream && /* @__PURE__ */ jsx(TableTabKeys, { scope: stageRef }),
3361
4047
  /* @__PURE__ */ jsxs(
3362
4048
  "div",
3363
4049
  {
@@ -3490,6 +4176,6 @@ async function loadFonts(baseUrl) {
3490
4176
  };
3491
4177
  }
3492
4178
 
3493
- export { BUILTIN_TEMPLATE_NAME, DEFAULT_DEFINED_TERMS_LABELS, DEFINED_TERM_TRIGGER, DefinedTermsProvider, DocxAuthorContext, DocxCommentActivity, DocxEditorReview, DocxMentions, DocxParticipants, DocxRibbon, HouseTemplateProvider, NativeDocxEditor, builtinHouseTemplate, contentPath, editorPort, findDefinitionsSection, insertDefinedTerm, loadDocxFonts, normalizeDocxExport, resolveHouseTemplate, reviewModule, structuralPort, templateFileName, trackedOrNoted, updateDefinitions, useDefinedTerms, useHouseTemplate, useReview, useReviewItem, useTrackedOrNoted, withDirectEditing };
3494
- //# sourceMappingURL=chunk-4ZTIMQ7Z.js.map
3495
- //# sourceMappingURL=chunk-4ZTIMQ7Z.js.map
4179
+ export { BUILTIN_TEMPLATE_NAME, DEFAULT_DEFINED_TERMS_LABELS, DEFINED_TERM_TRIGGER, DefinedTermsProvider, DocxAuthorContext, DocxCommentActivity, DocxEditorReview, DocxMentions, DocxParticipants, DocxRibbon, GenerateImageButton, HouseTemplateProvider, NativeDocxEditor, builtinHouseTemplate, contentPath, editorPort, findDefinitionsSection, insertDefinedTerm, loadDocxFonts, normalizeDocxExport, resolveHouseTemplate, reviewModule, structuralPort, templateFileName, trackedOrNoted, useDefinedTerms, useHouseTemplate, useReview, useReviewItem, useTrackedOrNoted, withDirectEditing };
4180
+ //# sourceMappingURL=chunk-MYALCKDR.js.map
4181
+ //# sourceMappingURL=chunk-MYALCKDR.js.map