@arbidocs/blocks 0.4.93 → 0.4.94

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 (89) hide show
  1. package/dist/agents/index.cjs +283 -283
  2. package/dist/agents/index.js +7 -7
  3. package/dist/{chunk-6XS5IJ5R.cjs → chunk-3OXWJ3CZ.cjs} +5 -5
  4. package/dist/{chunk-6XS5IJ5R.cjs.map → chunk-3OXWJ3CZ.cjs.map} +1 -1
  5. package/dist/{chunk-3WW32OUU.cjs → chunk-3US5OIDQ.cjs} +3 -3
  6. package/dist/{chunk-3WW32OUU.cjs.map → chunk-3US5OIDQ.cjs.map} +1 -1
  7. package/dist/chunk-AF6RDAJF.js +14 -0
  8. package/dist/chunk-AF6RDAJF.js.map +1 -0
  9. package/dist/chunk-AOFATOT3.cjs +196 -0
  10. package/dist/chunk-AOFATOT3.cjs.map +1 -0
  11. package/dist/chunk-D3QPYKZG.js +173 -0
  12. package/dist/chunk-D3QPYKZG.js.map +1 -0
  13. package/dist/{chunk-2ZDFVRGV.cjs → chunk-E2AAIMXO.cjs} +975 -61
  14. package/dist/chunk-E2AAIMXO.cjs.map +1 -0
  15. package/dist/{chunk-MROSCSPW.cjs → chunk-KKU7MUWE.cjs} +46 -46
  16. package/dist/{chunk-MROSCSPW.cjs.map → chunk-KKU7MUWE.cjs.map} +1 -1
  17. package/dist/{chunk-AMC5PMJ3.cjs → chunk-LENXDIMY.cjs} +36 -68
  18. package/dist/chunk-LENXDIMY.cjs.map +1 -0
  19. package/dist/{chunk-SF4BDUZS.js → chunk-PGDL26TQ.js} +3 -3
  20. package/dist/{chunk-SF4BDUZS.js.map → chunk-PGDL26TQ.js.map} +1 -1
  21. package/dist/chunk-RC25WMVB.cjs +16 -0
  22. package/dist/chunk-RC25WMVB.cjs.map +1 -0
  23. package/dist/{chunk-5YXG342J.cjs → chunk-RPCQBET5.cjs} +3 -3
  24. package/dist/{chunk-5YXG342J.cjs.map → chunk-RPCQBET5.cjs.map} +1 -1
  25. package/dist/{chunk-YFPIJUV3.cjs → chunk-RZGVMV6B.cjs} +5 -5
  26. package/dist/{chunk-YFPIJUV3.cjs.map → chunk-RZGVMV6B.cjs.map} +1 -1
  27. package/dist/{chunk-W2R7YVFM.js → chunk-WXLKMEMB.js} +970 -65
  28. package/dist/chunk-WXLKMEMB.js.map +1 -0
  29. package/dist/{chunk-BX62HJZU.js → chunk-YPKSLTL5.js} +3 -3
  30. package/dist/{chunk-BX62HJZU.js.map → chunk-YPKSLTL5.js.map} +1 -1
  31. package/dist/{chunk-UO74FLRK.js → chunk-Z3G65XHZ.js} +22 -53
  32. package/dist/chunk-Z3G65XHZ.js.map +1 -0
  33. package/dist/{chunk-W7NZRZ54.js → chunk-Z7OMEYDG.js} +3 -3
  34. package/dist/{chunk-W7NZRZ54.js.map → chunk-Z7OMEYDG.js.map} +1 -1
  35. package/dist/{chunk-UDLMLU6T.js → chunk-ZNDAXSDP.js} +3 -3
  36. package/dist/{chunk-UDLMLU6T.js.map → chunk-ZNDAXSDP.js.map} +1 -1
  37. package/dist/{chunk-SJVUKXS6.js → chunk-ZNGDEQBN.js} +8 -8
  38. package/dist/{chunk-SJVUKXS6.js.map → chunk-ZNGDEQBN.js.map} +1 -1
  39. package/dist/connect/docx.cjs +8 -6
  40. package/dist/connect/docx.cjs.map +1 -1
  41. package/dist/connect/docx.js +6 -4
  42. package/dist/connect/docx.js.map +1 -1
  43. package/dist/connect/index.cjs +55 -53
  44. package/dist/connect/index.cjs.map +1 -1
  45. package/dist/connect/index.js +11 -9
  46. package/dist/connect/index.js.map +1 -1
  47. package/dist/docx/NativeDocxEditor.d.ts +6 -0
  48. package/dist/docx/definitions/DefinedTerms.d.ts +50 -0
  49. package/dist/docx/definitions/commands.d.ts +78 -0
  50. package/dist/docx/definitions/fragment.d.ts +29 -0
  51. package/dist/docx/definitions/port.d.ts +76 -0
  52. package/dist/docx/index.cjs +53 -15
  53. package/dist/docx/index.cjs.map +1 -1
  54. package/dist/docx/index.d.ts +3 -0
  55. package/dist/docx/index.js +5 -3
  56. package/dist/docx/index.js.map +1 -1
  57. package/dist/facts/index.cjs +9 -14
  58. package/dist/facts/index.cjs.map +1 -1
  59. package/dist/facts/index.js +5 -12
  60. package/dist/facts/index.js.map +1 -1
  61. package/dist/files/index.cjs +2 -2
  62. package/dist/files/index.js +2 -2
  63. package/dist/home/index.cjs +1 -1
  64. package/dist/home/index.js +1 -1
  65. package/dist/index.cjs +914 -774
  66. package/dist/index.cjs.map +1 -1
  67. package/dist/index.js +102 -15
  68. package/dist/index.js.map +1 -1
  69. package/dist/settings/index.cjs +35 -35
  70. package/dist/settings/index.js +3 -3
  71. package/dist/shell/index.cjs +1 -1
  72. package/dist/shell/index.js +1 -1
  73. package/dist/studio/index.cjs +1 -1
  74. package/dist/studio/index.js +1 -1
  75. package/dist/tags/definitions.d.ts +92 -0
  76. package/dist/tags/glossary.d.ts +44 -0
  77. package/dist/tags/index.d.ts +2 -0
  78. package/dist/tags/ooxml.d.ts +46 -0
  79. package/dist/tags/tagTableDocx.d.ts +1 -1
  80. package/dist/workflow-canvas/index.cjs +50 -50
  81. package/dist/workflow-canvas/index.js +7 -7
  82. package/dist/workspaces/index.cjs +1 -1
  83. package/dist/workspaces/index.js +1 -1
  84. package/package.json +4 -4
  85. package/src/docx/README.md +11 -0
  86. package/dist/chunk-2ZDFVRGV.cjs.map +0 -1
  87. package/dist/chunk-AMC5PMJ3.cjs.map +0 -1
  88. package/dist/chunk-UO74FLRK.js.map +0 -1
  89. package/dist/chunk-W2R7YVFM.js.map +0 -1
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
+ var chunkAOFATOT3_cjs = require('./chunk-AOFATOT3.cjs');
4
5
  var chunk7UTB4PHM_cjs = require('./chunk-7UTB4PHM.cjs');
5
6
  var fflate = require('fflate');
6
7
  var store = require('@docx-editor.dev/core/store');
@@ -533,18 +534,18 @@ function ReviewCardSlot({ children }) {
533
534
  var DocxEditorReview = Object.assign(DocxEditorReviewRail, { Card: ReviewCardSlot });
534
535
 
535
536
  // src/docx/mentions.ts
536
- function mentionCandidates(mentions) {
537
+ function mentionCandidates(mentions2) {
537
538
  return [
538
539
  { id: "arbi", label: "ARBI", kind: "assistant" },
539
- ...mentions.filter((person) => person.name.trim()).map((person) => ({
540
+ ...mentions2.filter((person) => person.name.trim()).map((person) => ({
540
541
  id: person.id,
541
542
  label: person.name,
542
543
  kind: person.kind === "agent" ? "assistant" : "user"
543
544
  }))
544
545
  ];
545
546
  }
546
- function mentionedDocxRecipients(text, mentions) {
547
- return chunk7UTB4PHM_cjs.extractMentions(text, mentionCandidates(mentions)).map((person) => person.id);
547
+ function mentionedDocxRecipients(text, mentions2) {
548
+ return chunk7UTB4PHM_cjs.extractMentions(text, mentionCandidates(mentions2)).map((person) => person.id);
548
549
  }
549
550
  var ActivityContext = React3.createContext({});
550
551
  function DocxCommentActivity() {
@@ -627,7 +628,7 @@ function DocxCommentActivity() {
627
628
  }
628
629
  function DocxMentions({
629
630
  children,
630
- mentions = [],
631
+ mentions: mentions2 = [],
631
632
  initialCommentId,
632
633
  requestAgent,
633
634
  getAgentStatus,
@@ -686,7 +687,7 @@ function DocxMentions({
686
687
  const [suggestions, setSuggestions] = React3.useState(null);
687
688
  const [selected, setSelected] = React3.useState(0);
688
689
  const candidates = chunk7UTB4PHM_cjs.filterMentionCandidates(
689
- mentionCandidates(mentions),
690
+ mentionCandidates(mentions2),
690
691
  suggestions?.query || ""
691
692
  ).slice(0, 8);
692
693
  React3.useEffect(() => {
@@ -707,7 +708,7 @@ function DocxMentions({
707
708
  }));
708
709
  };
709
710
  const hasAgent = submission.recipientIds.some(
710
- (id) => id === "arbi" || mentions.some((person) => person.id === id && person.kind === "agent")
711
+ (id) => id === "arbi" || mentions2.some((person) => person.id === id && person.kind === "agent")
711
712
  );
712
713
  if (hasAgent) update("delivering");
713
714
  void requestAgent({
@@ -741,7 +742,7 @@ function DocxMentions({
741
742
  "error"
742
743
  );
743
744
  });
744
- }, [review.items, requestAgent, getAgentStatus, mentions, notify]);
745
+ }, [review.items, requestAgent, getAgentStatus, mentions2, notify]);
745
746
  const choose = (name) => {
746
747
  const field = input.current;
747
748
  if (!field || !suggestions) return;
@@ -759,7 +760,7 @@ function DocxMentions({
759
760
  '[data-testid="review-draft-input"], [data-testid="review-reply-input"]'
760
761
  );
761
762
  if (!field || field.readOnly || !requestAgent) return false;
762
- const recipientIds = mentionedDocxRecipients(field.value, mentions);
763
+ const recipientIds = mentionedDocxRecipients(field.value, mentions2);
763
764
  if (!recipientIds.length) return false;
764
765
  pending.current = {
765
766
  ids: new Set(review.items.filter((i) => i.kind === "comment").map((i) => i.item.id)),
@@ -806,7 +807,7 @@ function DocxMentions({
806
807
  (entry) => entry.kind === "comment" && entry.parentId === commentId
807
808
  );
808
809
  const author = replies.at(-1)?.author || target.author;
809
- const agent = mentions.find((person) => person.kind === "agent" && person.name === author);
810
+ const agent = mentions2.find((person) => person.kind === "agent" && person.name === author);
810
811
  if (agent || author === "ARBI" || author === "Assistant")
811
812
  prefixMention(
812
813
  field,
@@ -884,7 +885,7 @@ function DocxMentions({
884
885
  onMouseDown: (event) => event.preventDefault(),
885
886
  onClick: (event) => {
886
887
  event.stopPropagation();
887
- if (!mentionedDocxRecipients(field.value, mentions).includes("arbi"))
888
+ if (!mentionedDocxRecipients(field.value, mentions2).includes("arbi"))
888
889
  prefixMention(field);
889
890
  else field.focus();
890
891
  },
@@ -929,6 +930,869 @@ function DocxMentions({
929
930
  }
930
931
  ) });
931
932
  }
933
+
934
+ // src/docx/definitions/fragment.ts
935
+ var DEFINED_TERM_STYLE = "DefinedTerm";
936
+ var FRAGMENT_STYLES = chunkAOFATOT3_cjs.stylesXml(
937
+ "",
938
+ `<w:style w:type="paragraph" w:default="1" w:styleId="Normal"><w:name w:val="Normal"/><w:qFormat/></w:style><w:style w:type="character" w:customStyle="1" w:styleId="${DEFINED_TERM_STYLE}"><w:name w:val="Defined Term"/><w:rPr><w:u w:val="dotted" w:color="7F7F7F"/></w:rPr></w:style>`
939
+ );
940
+ var textRun = (text, props = "") => `<w:r>${props ? `<w:rPr>${props}</w:rPr>` : ""}<w:t xml:space="preserve">${chunkAOFATOT3_cjs.esc(text)}</w:t></w:r>`;
941
+ function definitionTooltip(definition) {
942
+ const line = `\u201C${definition.term}\u201D${definition.rest}`.replace(/\s+/g, " ").trim();
943
+ return line.length > 255 ? `${line.slice(0, 254)}\u2026` : line;
944
+ }
945
+ var definitionParagraphText = (definition) => `\u201C${definition.term}\u201D${definition.rest}`;
946
+ function definitionParagraphXml(definition, bookmark, id = 0) {
947
+ return `<w:p><w:bookmarkStart w:id="${id}" w:name="${chunkAOFATOT3_cjs.esc(bookmark)}"/>${textRun("\u201C")}${textRun(
948
+ definition.term,
949
+ "<w:b/>"
950
+ )}${textRun("\u201D")}<w:bookmarkEnd w:id="${id}"/>${textRun(definition.rest)}</w:p>`;
951
+ }
952
+ function headingParagraphXml(text, styleId) {
953
+ return styleId ? `<w:p><w:pPr><w:pStyle w:val="${chunkAOFATOT3_cjs.esc(styleId)}"/></w:pPr>${textRun(text)}</w:p>` : `<w:p><w:pPr><w:keepNext/></w:pPr>${textRun(text, "<w:b/>")}</w:p>`;
954
+ }
955
+ function termLinkXml(term, bookmark, tooltip) {
956
+ return `<w:p><w:hyperlink w:anchor="${chunkAOFATOT3_cjs.esc(bookmark)}" w:tooltip="${chunkAOFATOT3_cjs.esc(tooltip)}" w:history="1">${textRun(
957
+ term,
958
+ `<w:rStyle w:val="${DEFINED_TERM_STYLE}"/>`
959
+ )}</w:hyperlink></w:p>`;
960
+ }
961
+ function base64(bytes) {
962
+ let binary = "";
963
+ for (let i = 0; i < bytes.length; i += 32768)
964
+ binary += String.fromCharCode(...bytes.subarray(i, i + 32768));
965
+ return btoa(binary);
966
+ }
967
+ function fragmentHtml(body, covered2) {
968
+ const bytes = chunkAOFATOT3_cjs.docxPackage({
969
+ document: chunkAOFATOT3_cjs.documentXml(body),
970
+ styles: FRAGMENT_STYLES,
971
+ title: "Defined terms"
972
+ });
973
+ return `<div data-docx-fragment="${base64(bytes)}" data-docx-fragment-end="${covered2 ? "covered" : "open"}"></div>`;
974
+ }
975
+
976
+ // src/docx/definitions/commands.ts
977
+ var DEFINITIONS_HEADING = "Definitions";
978
+ var SECTION_TITLE = /^(definitions?(\s*(and|&)\s*interpretations?)?|interpretations?(\s*(and|&)\s*definitions?)?|defined\s+terms|glossary)$/i;
979
+ var NUMBERING = /^(?:(?:clause|section|article|schedule|part)\s+)?(?:[0-9]+(?:\.[0-9]+)*|[A-Z]|[ivxlc]+)[.):]?\s+(?:[-–—]\s*)?/i;
980
+ function isDefinitionsTitle(paragraph) {
981
+ if (!paragraph.topLevel) return false;
982
+ const title = paragraph.text.trim().replace(NUMBERING, "").replace(/[.:]+$/, "").trim();
983
+ return SECTION_TITLE.test(title) && (paragraph.heading || title.length <= 40);
984
+ }
985
+ function findDefinitionsSection(paragraphs) {
986
+ const title = paragraphs.findIndex(isDefinitionsTitle);
987
+ if (title < 0) return null;
988
+ let end = title + 1;
989
+ while (end < paragraphs.length && paragraphs[end].topLevel && !paragraphs[end].heading) end++;
990
+ return { title, start: title + 1, end };
991
+ }
992
+ var termOf = (paragraph) => chunkAOFATOT3_cjs.parseDefinition(paragraph.text)?.term ?? null;
993
+ function insertionIndex(paragraphs, section, term, skip = /* @__PURE__ */ new Set()) {
994
+ let afterLast = section.start;
995
+ for (let i = section.start; i < section.end; i++) {
996
+ if (skip.has(paragraphs[i].id)) continue;
997
+ const other = termOf(paragraphs[i]);
998
+ if (other === null) continue;
999
+ if (chunkAOFATOT3_cjs.compareTerms(other, term) > 0) return i;
1000
+ afterLast = i + 1;
1001
+ }
1002
+ return afterLast;
1003
+ }
1004
+ var headingStyle = (paragraphs) => paragraphs.find((p) => p.topLevel && p.heading && p.styleId)?.styleId;
1005
+ function insertParagraphs(port, index, body, count, keep) {
1006
+ const before = port.paragraphs();
1007
+ const kept = keep ? before.findIndex((p) => p.id === keep.paragraphId) : -1;
1008
+ if (index < before.length) {
1009
+ port.setCaret({ paragraphId: before[index].id, offset: 0 });
1010
+ } else {
1011
+ const last = before[before.length - 1];
1012
+ port.setCaret({ paragraphId: last.id, offset: last.text.length });
1013
+ port.splitParagraph();
1014
+ const opened = port.paragraphs();
1015
+ port.setCaret({ paragraphId: opened[opened.length - 1].id, offset: 0 });
1016
+ }
1017
+ if (!port.paste(body, "", true)) throw new Error("The definition could not be added.");
1018
+ if (!keep || kept < 0) return keep;
1019
+ const after = port.paragraphs();
1020
+ const moved = index <= kept ? kept + count : kept;
1021
+ return { paragraphId: after[moved]?.id ?? keep.paragraphId, offset: keep.offset };
1022
+ }
1023
+ function addDefinition(port, definition, keep) {
1024
+ const paragraphs = port.paragraphs();
1025
+ const section = findDefinitionsSection(paragraphs);
1026
+ const paragraph = definitionParagraphXml(definition, chunkAOFATOT3_cjs.definitionBookmark(definition.id));
1027
+ if (section)
1028
+ return insertParagraphs(
1029
+ port,
1030
+ insertionIndex(paragraphs, section, definition.term),
1031
+ paragraph,
1032
+ 1,
1033
+ keep
1034
+ );
1035
+ return insertParagraphs(
1036
+ port,
1037
+ paragraphs.length,
1038
+ headingParagraphXml(DEFINITIONS_HEADING, headingStyle(paragraphs)) + paragraph,
1039
+ 2,
1040
+ keep
1041
+ );
1042
+ }
1043
+ var hasBookmark = (paragraphs, name) => paragraphs.some((p) => p.bookmarks.includes(name));
1044
+ function insertDefinedTerm(port, definition, options = {}) {
1045
+ const start = port.caret();
1046
+ if (!start) throw new Error("Place the cursor where the term should go.");
1047
+ let caret = start;
1048
+ if (options.replace) {
1049
+ caret = { paragraphId: start.paragraphId, offset: Math.max(0, start.offset - options.replace) };
1050
+ port.deleteRange(caret, start);
1051
+ }
1052
+ const bookmark = chunkAOFATOT3_cjs.definitionBookmark(definition.id);
1053
+ const addedDefinition = !hasBookmark(port.paragraphs(), bookmark);
1054
+ if (addedDefinition) caret = addDefinition(port, definition, caret) ?? caret;
1055
+ port.setCaret(caret);
1056
+ if (!port.paste(
1057
+ termLinkXml(definition.term, bookmark, definitionTooltip(definition)),
1058
+ definition.term,
1059
+ false
1060
+ ))
1061
+ throw new Error("The term could not be inserted.");
1062
+ port.setCaret({ paragraphId: caret.paragraphId, offset: caret.offset + definition.term.length });
1063
+ return { addedDefinition };
1064
+ }
1065
+ var escapeRegExp = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1066
+ var mentions = (text, term) => new RegExp(`(^|[^\\p{L}\\p{N}])${escapeRegExp(term)}($|[^\\p{L}\\p{N}])`, "iu").test(text);
1067
+ function updateDefinitions(port, definitions) {
1068
+ const result = {
1069
+ added: [],
1070
+ refreshed: [],
1071
+ reordered: [],
1072
+ unused: [],
1073
+ unknown: []
1074
+ };
1075
+ let paragraphs = port.paragraphs();
1076
+ const linked = new Set(
1077
+ paragraphs.flatMap(
1078
+ (p) => p.links.map((l) => l.anchor).filter((a) => a.startsWith(chunkAOFATOT3_cjs.DEFINITION_BOOKMARK_PREFIX))
1079
+ )
1080
+ );
1081
+ const declared = /* @__PURE__ */ new Map();
1082
+ for (const p of paragraphs)
1083
+ for (const b of p.bookmarks)
1084
+ if (b.startsWith(chunkAOFATOT3_cjs.DEFINITION_BOOKMARK_PREFIX) && !declared.has(b)) declared.set(b, p);
1085
+ const factOf = (bookmark) => {
1086
+ const id = chunkAOFATOT3_cjs.definitionIdOfBookmark(bookmark);
1087
+ return id ? definitions.get(id) : void 0;
1088
+ };
1089
+ for (const bookmark of [...linked, ...declared.keys()])
1090
+ if (!factOf(bookmark) && !result.unknown.includes(bookmark)) result.unknown.push(bookmark);
1091
+ const section = findDefinitionsSection(paragraphs);
1092
+ const rewrite = /* @__PURE__ */ new Map();
1093
+ for (const [bookmark, paragraph] of declared) {
1094
+ const fact = factOf(bookmark);
1095
+ if (fact && paragraph.text !== definitionParagraphText(fact)) {
1096
+ rewrite.set(paragraph.id, fact);
1097
+ result.refreshed.push(fact.term);
1098
+ }
1099
+ }
1100
+ if (section) {
1101
+ let previous = null;
1102
+ for (let i = section.start; i < section.end; i++) {
1103
+ const p = paragraphs[i];
1104
+ const term = termOf(p);
1105
+ if (term === null) continue;
1106
+ const bookmark = p.bookmarks.find((b) => b.startsWith(chunkAOFATOT3_cjs.DEFINITION_BOOKMARK_PREFIX));
1107
+ const fact = bookmark ? factOf(bookmark) : void 0;
1108
+ if (previous !== null && chunkAOFATOT3_cjs.compareTerms(term, previous) < 0 && fact) {
1109
+ if (!rewrite.has(p.id)) result.reordered.push(fact.term);
1110
+ rewrite.set(p.id, fact);
1111
+ continue;
1112
+ }
1113
+ previous = term;
1114
+ }
1115
+ }
1116
+ for (const id of [...rewrite.keys()].reverse()) {
1117
+ const index = paragraphs.findIndex((p) => p.id === id);
1118
+ const previous = paragraphs[index - 1];
1119
+ const target = paragraphs[index];
1120
+ if (!previous) continue;
1121
+ port.deleteRange(
1122
+ { paragraphId: previous.id, offset: previous.text.length },
1123
+ { paragraphId: target.id, offset: target.text.length }
1124
+ );
1125
+ paragraphs = port.paragraphs();
1126
+ }
1127
+ const toAdd = [...rewrite.values()];
1128
+ for (const bookmark of linked) {
1129
+ const fact = factOf(bookmark);
1130
+ if (fact && !declared.has(bookmark) && !toAdd.some((d) => d.id === fact.id)) {
1131
+ toAdd.push(fact);
1132
+ result.added.push(fact.term);
1133
+ }
1134
+ }
1135
+ toAdd.sort((a, b) => chunkAOFATOT3_cjs.compareTerms(a.term, b.term));
1136
+ for (const definition of toAdd) addDefinition(port, definition);
1137
+ paragraphs = port.paragraphs();
1138
+ const after = findDefinitionsSection(paragraphs);
1139
+ if (after) {
1140
+ const inSection = (i) => i >= after.title && i < after.end;
1141
+ const outside = paragraphs.filter((_, i) => !inSection(i));
1142
+ const linkedNow = new Set(outside.flatMap((p) => p.links.map((l) => l.anchor)));
1143
+ const outsideText = outside.map((p) => p.text).join("\n");
1144
+ for (let i = after.start; i < after.end; i++) {
1145
+ const p = paragraphs[i];
1146
+ const term = termOf(p);
1147
+ if (term === null) continue;
1148
+ const used = p.bookmarks.some((b) => linkedNow.has(b)) || mentions(outsideText, term);
1149
+ if (!used) result.unused.push({ term, paragraphId: p.id });
1150
+ }
1151
+ }
1152
+ return result;
1153
+ }
1154
+ function definitionOfAnchor(anchor, definitions) {
1155
+ const id = chunkAOFATOT3_cjs.definitionIdOfBookmark(anchor.replace(/^#/, ""));
1156
+ return id ? definitions.get(id) : void 0;
1157
+ }
1158
+
1159
+ // src/docx/definitions/port.ts
1160
+ var attr = (node, name) => node.attributes?.find((a) => a.localName === name)?.value;
1161
+ var HEADING_STYLE = /^(heading|berschrift|titre|t[ií]tulo|titolo|kop)\s*\d/i;
1162
+ function readParagraphs(root) {
1163
+ const out = [];
1164
+ const body = root.children?.find((n) => n.kind === "body") ?? root;
1165
+ const visit = (node, topLevel, pending) => {
1166
+ for (const child of node.children ?? []) {
1167
+ if (child.kind === "paragraph") {
1168
+ out.push(readParagraph(child, topLevel, pending.splice(0)));
1169
+ } else if (child.localName === "bookmarkStart") {
1170
+ const name = attr(child, "name");
1171
+ if (name) pending.push(name);
1172
+ } else if (child.localName === "tbl" || child.localName === "tr" || child.localName === "tc") {
1173
+ visit(child, false, pending);
1174
+ } else if (child.localName === "sdt" || child.localName === "sdtContent") {
1175
+ visit(child, topLevel, pending);
1176
+ }
1177
+ }
1178
+ };
1179
+ visit(body, true, []);
1180
+ return out;
1181
+ }
1182
+ function readParagraph(node, topLevel, bookmarks) {
1183
+ let text = "";
1184
+ const links = [];
1185
+ let styleId;
1186
+ let outline = false;
1187
+ const walk = (n, link) => {
1188
+ for (const c of n.children ?? []) {
1189
+ if (c.kind === "paragraphProperties" || c.localName === "pPr") {
1190
+ for (const p of c.children ?? []) {
1191
+ if (p.localName === "pStyle") styleId = attr(p, "val");
1192
+ if (p.localName === "outlineLvl" && Number(attr(p, "val")) < 9) outline = true;
1193
+ }
1194
+ continue;
1195
+ }
1196
+ if (c.localName === "delText" || c.localName === "del" || c.localName === "rPr") continue;
1197
+ if (c.localName === "bookmarkStart") {
1198
+ const name = attr(c, "name");
1199
+ if (name) bookmarks.push(name);
1200
+ continue;
1201
+ }
1202
+ if (c.localName === "hyperlink") {
1203
+ const anchor = attr(c, "anchor");
1204
+ const next = anchor ? { anchor, text: "" } : void 0;
1205
+ walk(c, next ?? link);
1206
+ if (next) links.push(next);
1207
+ continue;
1208
+ }
1209
+ if (c.kind === "textValue") {
1210
+ text += c.value ?? "";
1211
+ if (link) link.text += c.value ?? "";
1212
+ continue;
1213
+ }
1214
+ if (c.localName === "tab") text += " ";
1215
+ walk(c, link);
1216
+ }
1217
+ };
1218
+ walk(node);
1219
+ return {
1220
+ id: node.id,
1221
+ text,
1222
+ heading: outline || !!styleId && HEADING_STYLE.test(styleId),
1223
+ styleId,
1224
+ topLevel,
1225
+ bookmarks,
1226
+ links
1227
+ };
1228
+ }
1229
+ function editorPort(editor) {
1230
+ const surface = () => {
1231
+ const s = editor.surface;
1232
+ if (!s) throw new Error("The document is not open.");
1233
+ return s;
1234
+ };
1235
+ return {
1236
+ paragraphs: () => readParagraphs(surface().session.part().root),
1237
+ caret: () => {
1238
+ const selection = surface().state().selection;
1239
+ if (!selection) return null;
1240
+ const { anchor, head } = selection;
1241
+ return anchor.paragraphId === head.paragraphId && anchor.offset === head.offset ? { paragraphId: anchor.paragraphId, offset: anchor.offset } : null;
1242
+ },
1243
+ setCaret: (point) => surface().setSelection({ anchor: point, head: point }),
1244
+ deleteRange: (from, to) => {
1245
+ surface().setSelection({ anchor: from, head: to });
1246
+ surface().deleteSelection();
1247
+ },
1248
+ paste: (body, text, covered2) => editor.exec({ type: "paste", text, html: fragmentHtml(body, covered2) }).ok,
1249
+ splitParagraph: () => surface().splitParagraph()
1250
+ };
1251
+ }
1252
+ function withDirectEditing(editor, fn) {
1253
+ const mode = editor.getEditingMode();
1254
+ if (mode === "viewing") throw new Error("This document is read only.");
1255
+ if (mode === "suggesting") editor.setEditingMode("editing");
1256
+ try {
1257
+ return fn();
1258
+ } finally {
1259
+ if (mode === "suggesting") editor.setEditingMode("suggesting");
1260
+ }
1261
+ }
1262
+ function holdCaret(editor, timeoutMs = 5e3) {
1263
+ const surface = editor.surface;
1264
+ const selection = surface?.state().selection;
1265
+ if (!surface || !selection) return;
1266
+ const { paragraphId, offset } = selection.head;
1267
+ const paraId = surface.session.paraIdOf(paragraphId);
1268
+ if (!paraId) return;
1269
+ let done = false;
1270
+ const stop = () => {
1271
+ done = true;
1272
+ offChange();
1273
+ offSelection();
1274
+ clearTimeout(timer);
1275
+ };
1276
+ const restore = () => {
1277
+ if (done) return;
1278
+ const now = surface.state().selection;
1279
+ const node = surface.session.nodeIdOf(paraId);
1280
+ if (!now || !node) return;
1281
+ if (now.head.offset !== offset || now.head.paragraphId !== paragraphId) return stop();
1282
+ if (node === paragraphId) return;
1283
+ stop();
1284
+ const point = { paragraphId: node, offset };
1285
+ surface.setSelection({ anchor: point, head: point });
1286
+ };
1287
+ const offChange = editor.on("change", restore);
1288
+ const offSelection = editor.on("selectionChange", restore);
1289
+ const timer = setTimeout(stop, timeoutMs);
1290
+ }
1291
+ var DEFINED_TERM_TRIGGER = "@@";
1292
+ var TRIGGER_QUERY = /(?:^|[\s([{"“‘'])@@([^@\n\t]{0,40})$/;
1293
+ var MAX_GROUPS = 8;
1294
+ var STALE_AFTER_MS = 3e4;
1295
+ var DEFAULT_DEFINED_TERMS_LABELS = {
1296
+ insert: "Defined term",
1297
+ update: "Update definitions",
1298
+ search: "Search defined terms",
1299
+ allAgreements: "All definitions",
1300
+ loading: "Loading definitions\u2026",
1301
+ empty: "No definitions yet. Label a fact \u201CDefinitions\u201D to use it here.",
1302
+ noMatch: "No defined term matches.",
1303
+ hint: "Enter to insert \xB7 Esc to close",
1304
+ preferred: "Preferred",
1305
+ alsoIn: (source) => `Also defined${source ? ` in ${source}` : ""}`,
1306
+ updated: "Definitions updated",
1307
+ updateSummary: (r) => [
1308
+ r.added.length ? `${r.added.length} added` : "",
1309
+ r.refreshed.length ? `${r.refreshed.length} reworded` : "",
1310
+ r.reordered.length ? `${r.reordered.length} reordered` : ""
1311
+ ].filter(Boolean).join(" \xB7 ") || "The Definitions section is up to date.",
1312
+ unusedTitle: "Defined but never used",
1313
+ unusedNone: "Every definition in the section is used.",
1314
+ unknownTitle: "Links to definitions that no longer exist",
1315
+ show: "Show",
1316
+ close: "Close"
1317
+ };
1318
+ var DefinedTermsContext = React3.createContext(null);
1319
+ var useDefinedTerms = () => React3.useContext(DefinedTermsContext);
1320
+ function rowsOf(groups) {
1321
+ return groups.flatMap(
1322
+ (group) => group.definitions.map((definition, i) => ({ group, definition, variant: i > 0 }))
1323
+ );
1324
+ }
1325
+ var sourceOf = (d) => [d.source, ...(d.labels ?? []).map((l) => l.name)].filter(Boolean).join(" \xB7 ");
1326
+ function DefinedTermsProvider({
1327
+ children,
1328
+ load,
1329
+ editable,
1330
+ notify,
1331
+ labels
1332
+ }) {
1333
+ const editor = react.useDocxEditor();
1334
+ const l = React3.useMemo(() => ({ ...DEFAULT_DEFINED_TERMS_LABELS, ...labels }), [labels]);
1335
+ const [sources, setSources] = React3.useState(null);
1336
+ const loadedAt = React3.useRef(0);
1337
+ const loading = React3.useRef(null);
1338
+ const [labelId, setLabelId] = React3.useState(null);
1339
+ const [picker, setPicker] = React3.useState(null);
1340
+ const [selected, setSelected] = React3.useState(0);
1341
+ const [report, setReport] = React3.useState(null);
1342
+ const marker = React3.useRef(null);
1343
+ const dismissedAt = React3.useRef(null);
1344
+ const refresh = React3.useCallback(
1345
+ (force = false) => {
1346
+ if (!load) return Promise.resolve([]);
1347
+ if (!force && sources && Date.now() - loadedAt.current < STALE_AFTER_MS)
1348
+ return Promise.resolve(sources);
1349
+ if (!loading.current)
1350
+ loading.current = load().then((list) => {
1351
+ loadedAt.current = Date.now();
1352
+ setSources(list);
1353
+ return list;
1354
+ }).catch((error) => {
1355
+ notify?.(
1356
+ error instanceof Error ? error.message : "Could not load definitions.",
1357
+ "error"
1358
+ );
1359
+ setSources((previous) => previous ?? []);
1360
+ return sources ?? [];
1361
+ }).finally(() => {
1362
+ loading.current = null;
1363
+ });
1364
+ return loading.current;
1365
+ },
1366
+ [load, sources, notify]
1367
+ );
1368
+ const all = React3.useMemo(() => chunkAOFATOT3_cjs.groupDefinitions(sources ?? []).groups, [sources]);
1369
+ const byId = React3.useMemo(
1370
+ () => new Map(all.flatMap((g) => g.definitions).map((d) => [d.id, d])),
1371
+ [all]
1372
+ );
1373
+ const agreements = React3.useMemo(() => chunkAOFATOT3_cjs.definitionLabels(sources ?? []), [sources]);
1374
+ const groups = React3.useMemo(
1375
+ () => picker ? chunkAOFATOT3_cjs.filterTermGroups(chunkAOFATOT3_cjs.groupDefinitions(sources ?? [], { labelId }).groups, picker.query).slice(
1376
+ 0,
1377
+ MAX_GROUPS
1378
+ ) : [],
1379
+ [sources, labelId, picker]
1380
+ );
1381
+ const rows = React3.useMemo(() => rowsOf(groups), [groups]);
1382
+ React3.useEffect(() => setSelected(0), [picker?.query, labelId]);
1383
+ const container = () => marker.current?.closest(".native-docx-viewer") ?? document.body;
1384
+ const [viewer, setViewer] = React3.useState(null);
1385
+ React3.useEffect(() => setViewer(container()), []);
1386
+ const refreshRef = React3.useRef(refresh);
1387
+ refreshRef.current = refresh;
1388
+ const firstHover = React3.useCallback(() => void refreshRef.current(), []);
1389
+ const caretRect = () => container().querySelector(".docx-editor-one-surface__caret")?.getBoundingClientRect();
1390
+ const run = React3.useCallback(
1391
+ (fn) => {
1392
+ if (!editor) return void 0;
1393
+ try {
1394
+ return withDirectEditing(editor, fn);
1395
+ } catch (error) {
1396
+ notify?.(error instanceof Error ? error.message : "Could not change the document.", "error");
1397
+ return void 0;
1398
+ }
1399
+ },
1400
+ [editor, notify]
1401
+ );
1402
+ const pick = React3.useCallback(
1403
+ (row) => {
1404
+ if (!editor || !picker || !row) return;
1405
+ const port = editorPort(editor);
1406
+ const result = run(() => {
1407
+ if (picker.mode === "search" && picker.caret) port.setCaret(picker.caret);
1408
+ return insertDefinedTerm(port, row.definition, {
1409
+ replace: picker.mode === "typing" ? DEFINED_TERM_TRIGGER.length + picker.query.length : 0
1410
+ });
1411
+ });
1412
+ setPicker(null);
1413
+ editor.surface?.focus();
1414
+ if (result) holdCaret(editor);
1415
+ if (result?.addedDefinition)
1416
+ notify?.(`\u201C${row.definition.term}\u201D added to the Definitions section.`, "success");
1417
+ },
1418
+ [editor, picker, run, notify]
1419
+ );
1420
+ const openPicker = React3.useCallback(
1421
+ (anchor) => {
1422
+ if (!editor || !editable) return;
1423
+ const caret = editorPort(editor).caret();
1424
+ const rect = caretRect() ?? anchor?.getBoundingClientRect();
1425
+ void refresh();
1426
+ setPicker({
1427
+ mode: "search",
1428
+ query: "",
1429
+ left: rect?.left ?? 120,
1430
+ top: (rect?.bottom ?? 120) + 4,
1431
+ caret
1432
+ });
1433
+ },
1434
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1435
+ [editor, editable, refresh]
1436
+ );
1437
+ React3.useEffect(() => {
1438
+ if (!editor || !editable || !load) return;
1439
+ let frame = 0;
1440
+ const check = () => {
1441
+ cancelAnimationFrame(frame);
1442
+ frame = requestAnimationFrame(() => {
1443
+ const port = editorPort(editor);
1444
+ const caret = port.caret();
1445
+ const paragraph = caret && port.paragraphs().find((p) => p.id === caret.paragraphId);
1446
+ const match = paragraph && TRIGGER_QUERY.exec(paragraph.text.slice(0, caret.offset));
1447
+ setPicker((current) => {
1448
+ if (current?.mode === "search") return current;
1449
+ if (!match || !caret) return null;
1450
+ const key = `${caret.paragraphId}:${caret.offset - match[1].length}`;
1451
+ if (dismissedAt.current === key) return null;
1452
+ const rect = caretRect();
1453
+ return {
1454
+ mode: "typing",
1455
+ query: match[1],
1456
+ left: current?.left ?? rect?.left ?? 120,
1457
+ top: current?.top ?? (rect?.bottom ?? 120) + 4,
1458
+ caret
1459
+ };
1460
+ });
1461
+ if (match) void refresh();
1462
+ });
1463
+ };
1464
+ const offChange = editor.on("change", check);
1465
+ const offSelection = editor.on("selectionChange", check);
1466
+ return () => {
1467
+ cancelAnimationFrame(frame);
1468
+ offChange();
1469
+ offSelection();
1470
+ };
1471
+ }, [editor, editable, load, refresh]);
1472
+ React3.useEffect(() => {
1473
+ if (picker?.mode !== "typing") return;
1474
+ const keys = (event) => {
1475
+ if (event.key === "Escape") {
1476
+ dismissedAt.current = picker.caret ? `${picker.caret.paragraphId}:${picker.caret.offset - picker.query.length}` : null;
1477
+ setPicker(null);
1478
+ } else if (!rows.length) return;
1479
+ else if (event.key === "ArrowDown") setSelected((i) => (i + 1) % rows.length);
1480
+ else if (event.key === "ArrowUp") setSelected((i) => (i - 1 + rows.length) % rows.length);
1481
+ else if (event.key === "Enter" || event.key === "Tab") pick(rows[selected] ?? rows[0]);
1482
+ else return;
1483
+ event.preventDefault();
1484
+ event.stopPropagation();
1485
+ };
1486
+ window.addEventListener("keydown", keys, true);
1487
+ return () => window.removeEventListener("keydown", keys, true);
1488
+ }, [picker, rows, selected, pick]);
1489
+ const update = React3.useCallback(() => {
1490
+ if (!editor || !editable) return;
1491
+ void refresh(true).then((list) => {
1492
+ const definitions = new Map(
1493
+ list.flatMap((s) => {
1494
+ const d = chunkAOFATOT3_cjs.toDefinition(s);
1495
+ return d ? [[d.id, d]] : [];
1496
+ })
1497
+ );
1498
+ const surface = editor.surface;
1499
+ const before = surface?.state().selection?.head;
1500
+ const paraId = before && surface?.session.paraIdOf(before.paragraphId);
1501
+ const result = run(() => updateDefinitions(editorPort(editor), definitions));
1502
+ const node = paraId && surface?.session.nodeIdOf(paraId);
1503
+ if (result && before && node) {
1504
+ const point = { paragraphId: node, offset: before.offset };
1505
+ surface.setSelection({ anchor: point, head: point });
1506
+ holdCaret(editor);
1507
+ }
1508
+ if (result) setReport(result);
1509
+ });
1510
+ }, [editor, editable, refresh, run]);
1511
+ const value = React3.useMemo(
1512
+ () => load && editable ? { openPicker, update, labels: l } : null,
1513
+ [load, editable, openPicker, update, l]
1514
+ );
1515
+ return /* @__PURE__ */ jsxRuntime.jsxs(DefinedTermsContext.Provider, { value, children: [
1516
+ /* @__PURE__ */ jsxRuntime.jsx("span", { ref: marker, hidden: true }),
1517
+ children,
1518
+ load && /* @__PURE__ */ jsxRuntime.jsx(
1519
+ DefinedTermHover,
1520
+ {
1521
+ root: viewer,
1522
+ resolve: (anchor) => definitionOfAnchor(anchor, byId),
1523
+ onFirstHover: firstHover
1524
+ }
1525
+ ),
1526
+ picker && reactDom.createPortal(
1527
+ /* @__PURE__ */ jsxRuntime.jsx(
1528
+ DefinedTermMenu,
1529
+ {
1530
+ picker,
1531
+ rows,
1532
+ loading: sources === null,
1533
+ selected,
1534
+ setSelected,
1535
+ agreements,
1536
+ labelId,
1537
+ setLabelId,
1538
+ onQuery: (query) => setPicker((p) => p ? { ...p, query } : p),
1539
+ onPick: pick,
1540
+ onClose: () => {
1541
+ setPicker(null);
1542
+ editor?.surface?.focus();
1543
+ },
1544
+ labels: l
1545
+ }
1546
+ ),
1547
+ document.body
1548
+ ),
1549
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Dialog, { open: !!report, onOpenChange: (open) => !open && setReport(null), children: /* @__PURE__ */ jsxRuntime.jsxs(
1550
+ ui.DialogContent,
1551
+ {
1552
+ className: "max-h-[85dvh] overflow-y-auto",
1553
+ "data-testid": "docx-definitions-report",
1554
+ children: [
1555
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogHeader, { children: [
1556
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DialogTitle, { children: l.updated }),
1557
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DialogDescription, { children: report && l.updateSummary(report) })
1558
+ ] }),
1559
+ report && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 text-sm", children: [
1560
+ /* @__PURE__ */ jsxRuntime.jsxs("section", { children: [
1561
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mb-1 font-medium", children: l.unusedTitle }),
1562
+ report.unused.length ? /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-1", "data-testid": "docx-definitions-unused", children: report.unused.map((u) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center justify-between gap-2", children: [
1563
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: u.term }),
1564
+ /* @__PURE__ */ jsxRuntime.jsx(
1565
+ ui.Button,
1566
+ {
1567
+ size: "sm",
1568
+ variant: "ghost",
1569
+ onClick: () => {
1570
+ const surface = editor?.surface;
1571
+ surface?.setSelection({
1572
+ anchor: { paragraphId: u.paragraphId, offset: 0 },
1573
+ head: { paragraphId: u.paragraphId, offset: 0 }
1574
+ });
1575
+ surface?.revealParagraph(u.paragraphId);
1576
+ setReport(null);
1577
+ },
1578
+ children: l.show
1579
+ }
1580
+ )
1581
+ ] }, u.paragraphId)) }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: l.unusedNone })
1582
+ ] }),
1583
+ report.unknown.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("section", { children: [
1584
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mb-1 font-medium", children: l.unknownTitle }),
1585
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "list-disc pl-5 text-muted-foreground", children: report.unknown.map((name) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: name }, name)) })
1586
+ ] })
1587
+ ] }),
1588
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DialogFooter, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "outline", onClick: () => setReport(null), children: l.close }) })
1589
+ ]
1590
+ }
1591
+ ) })
1592
+ ] });
1593
+ }
1594
+ function DefinedTermMenu({
1595
+ picker,
1596
+ rows,
1597
+ loading,
1598
+ selected,
1599
+ setSelected,
1600
+ agreements,
1601
+ labelId,
1602
+ setLabelId,
1603
+ onQuery,
1604
+ onPick,
1605
+ onClose,
1606
+ labels: l
1607
+ }) {
1608
+ const listboxId = React3__default.default.useId();
1609
+ const element = React3.useRef(null);
1610
+ const search = picker.mode === "search";
1611
+ React3.useEffect(() => {
1612
+ const dismiss = (event) => {
1613
+ if (!element.current?.contains(event.target)) onClose();
1614
+ };
1615
+ document.addEventListener("pointerdown", dismiss);
1616
+ return () => document.removeEventListener("pointerdown", dismiss);
1617
+ }, [onClose]);
1618
+ React3.useEffect(() => {
1619
+ element.current?.querySelector(`[data-index="${selected}"]`)?.scrollIntoView?.({ block: "nearest" });
1620
+ }, [selected]);
1621
+ const left = Math.max(8, Math.min(picker.left, window.innerWidth - 368));
1622
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1623
+ "div",
1624
+ {
1625
+ ref: element,
1626
+ className: "native-docx-term-menu rounded-md border border-border bg-popover text-popover-foreground shadow-lg",
1627
+ style: { position: "fixed", left, top: picker.top, width: 360, zIndex: 1e3 },
1628
+ "data-testid": "docx-defined-term-menu",
1629
+ onMouseDown: (event) => {
1630
+ if (!(event.target instanceof HTMLInputElement || event.target instanceof HTMLSelectElement))
1631
+ event.preventDefault();
1632
+ },
1633
+ children: [
1634
+ (search || agreements.length > 0) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 border-b border-border/50 p-2", children: [
1635
+ search && /* @__PURE__ */ jsxRuntime.jsx(
1636
+ "input",
1637
+ {
1638
+ autoFocus: true,
1639
+ className: "min-w-0 flex-1 rounded border border-border bg-background px-2 py-1 text-sm",
1640
+ placeholder: l.search,
1641
+ "aria-label": l.search,
1642
+ role: "combobox",
1643
+ "aria-expanded": true,
1644
+ "aria-controls": listboxId,
1645
+ "aria-activedescendant": rows.length ? chunk7UTB4PHM_cjs.listOptionId(listboxId, selected) : void 0,
1646
+ value: picker.query,
1647
+ "data-testid": "docx-defined-term-search",
1648
+ onChange: (event) => onQuery(event.target.value),
1649
+ onKeyDown: (event) => {
1650
+ if (event.key === "Escape") onClose();
1651
+ else if (!rows.length) return;
1652
+ else if (event.key === "ArrowDown") setSelected((selected + 1) % rows.length);
1653
+ else if (event.key === "ArrowUp")
1654
+ setSelected((selected - 1 + rows.length) % rows.length);
1655
+ else if (event.key === "Enter") onPick(rows[selected] ?? rows[0]);
1656
+ else return;
1657
+ event.preventDefault();
1658
+ }
1659
+ }
1660
+ ),
1661
+ agreements.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
1662
+ "select",
1663
+ {
1664
+ className: "max-w-[45%] rounded border border-border bg-background px-1 py-1 text-xs",
1665
+ "aria-label": "Narrow to",
1666
+ value: labelId ?? "",
1667
+ "data-testid": "docx-defined-term-label",
1668
+ onChange: (event) => setLabelId(event.target.value || null),
1669
+ children: [
1670
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: l.allAgreements }),
1671
+ agreements.map((a) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: a.id, children: a.name }, a.id))
1672
+ ]
1673
+ }
1674
+ )
1675
+ ] }),
1676
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-border/50 px-3 py-1.5 text-xs text-muted-foreground", children: l.hint }),
1677
+ /* @__PURE__ */ jsxRuntime.jsxs(
1678
+ "div",
1679
+ {
1680
+ id: listboxId,
1681
+ role: "listbox",
1682
+ "aria-label": l.search,
1683
+ className: "scrollbar-subtle max-h-72 overflow-y-auto py-1",
1684
+ children: [
1685
+ rows.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 py-2 text-sm text-muted-foreground", children: loading ? l.loading : picker.query ? l.noMatch : l.empty }),
1686
+ rows.map((row, index) => /* @__PURE__ */ jsxRuntime.jsxs(
1687
+ "div",
1688
+ {
1689
+ id: chunk7UTB4PHM_cjs.listOptionId(listboxId, index),
1690
+ role: "option",
1691
+ "aria-selected": index === selected,
1692
+ "data-index": index,
1693
+ "data-testid": `docx-defined-term-${row.definition.id}`,
1694
+ className: ui.cn(
1695
+ "cursor-pointer px-3 py-1.5 text-sm",
1696
+ row.variant && "pl-6",
1697
+ index === selected ? "bg-accent text-accent-foreground" : "hover:bg-accent/50"
1698
+ ),
1699
+ onMouseEnter: () => setSelected(index),
1700
+ onClick: () => onPick(row),
1701
+ children: [
1702
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2", children: [
1703
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: ui.cn("shrink-0", row.variant ? "text-xs" : "font-medium"), children: row.variant ? l.alsoIn(sourceOf(row.definition)) : row.group.term }),
1704
+ !row.variant && sourceOf(row.definition) && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-xs text-muted-foreground", children: sourceOf(row.definition) }),
1705
+ !row.variant && row.group.definitions.length > 1 && row.definition.confirmed && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto shrink-0 rounded bg-muted px-1 text-[10px] uppercase text-muted-foreground", children: l.preferred })
1706
+ ] }),
1707
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "line-clamp-2 text-xs text-muted-foreground", children: row.definition.meaning })
1708
+ ]
1709
+ },
1710
+ row.definition.id
1711
+ ))
1712
+ ]
1713
+ }
1714
+ )
1715
+ ]
1716
+ }
1717
+ );
1718
+ }
1719
+ function DefinedTermHover({
1720
+ root,
1721
+ resolve,
1722
+ onFirstHover
1723
+ }) {
1724
+ const [card, setCard] = React3.useState(null);
1725
+ const hovered = React3.useRef(false);
1726
+ React3.useEffect(() => {
1727
+ if (!root) return;
1728
+ const over = (event) => {
1729
+ const link = event.target?.closest?.(
1730
+ 'a.docx-hyperlink[data-docx-link-kind="internal"]'
1731
+ );
1732
+ const href = link?.getAttribute("href") ?? "";
1733
+ if (!link || !href.startsWith("#_dt_")) return;
1734
+ if (!hovered.current) {
1735
+ hovered.current = true;
1736
+ onFirstHover();
1737
+ }
1738
+ const title = link.getAttribute("title");
1739
+ if (title) {
1740
+ link.dataset.definition = title;
1741
+ link.removeAttribute("title");
1742
+ }
1743
+ const rect = link.getBoundingClientRect();
1744
+ setCard({
1745
+ left: rect.left,
1746
+ top: rect.bottom + 6,
1747
+ anchor: href.slice(1),
1748
+ fallback: link.dataset.definition ?? ""
1749
+ });
1750
+ };
1751
+ const out = (event) => {
1752
+ const link = event.target?.closest?.("a.docx-hyperlink");
1753
+ if (link && !link.contains(event.relatedTarget)) setCard(null);
1754
+ };
1755
+ root.addEventListener("mouseover", over);
1756
+ root.addEventListener("mouseout", out);
1757
+ const hide = () => setCard(null);
1758
+ window.addEventListener("keydown", hide, true);
1759
+ window.addEventListener("pointerdown", hide, true);
1760
+ window.addEventListener("scroll", hide, true);
1761
+ return () => {
1762
+ root.removeEventListener("mouseover", over);
1763
+ root.removeEventListener("mouseout", out);
1764
+ window.removeEventListener("keydown", hide, true);
1765
+ window.removeEventListener("pointerdown", hide, true);
1766
+ window.removeEventListener("scroll", hide, true);
1767
+ };
1768
+ }, [root, onFirstHover]);
1769
+ if (!card) return null;
1770
+ const definition = resolve(card.anchor);
1771
+ return reactDom.createPortal(
1772
+ /* @__PURE__ */ jsxRuntime.jsx(
1773
+ "div",
1774
+ {
1775
+ role: "tooltip",
1776
+ className: "native-docx-term-card rounded-md border border-border bg-popover p-3 text-sm text-popover-foreground shadow-lg",
1777
+ style: {
1778
+ position: "fixed",
1779
+ left: Math.max(8, Math.min(card.left, window.innerWidth - 348)),
1780
+ top: card.top,
1781
+ width: 340,
1782
+ zIndex: 1e3,
1783
+ pointerEvents: "none"
1784
+ },
1785
+ "data-testid": "docx-defined-term-card",
1786
+ children: definition ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1787
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium", children: definition.term }),
1788
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-muted-foreground", children: definition.meaning }),
1789
+ sourceOf(definition) && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: sourceOf(definition) })
1790
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { children: card.fallback })
1791
+ }
1792
+ ),
1793
+ document.body
1794
+ );
1795
+ }
932
1796
  function wordDraftHtml(markdown) {
933
1797
  const template = document.createElement("template");
934
1798
  template.innerHTML = server.renderToStaticMarkup(/* @__PURE__ */ jsxRuntime.jsx(ui.AiMarkdown, { children: markdown }));
@@ -1114,6 +1978,38 @@ function RibbonMenu({
1114
1978
  )
1115
1979
  ] });
1116
1980
  }
1981
+ function DefinedTermButtons() {
1982
+ const terms = useDefinedTerms();
1983
+ if (!terms) return null;
1984
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1985
+ /* @__PURE__ */ jsxRuntime.jsx(
1986
+ "button",
1987
+ {
1988
+ type: "button",
1989
+ className: "native-docx-ribbon-trigger",
1990
+ "aria-label": terms.labels.insert,
1991
+ title: `${terms.labels.insert} (type @@)`,
1992
+ "data-testid": "docx-insert-defined-term",
1993
+ onMouseDown: (event) => event.preventDefault(),
1994
+ onClick: (event) => terms.openPicker(event.currentTarget),
1995
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BookA, { size: 16 })
1996
+ }
1997
+ ),
1998
+ /* @__PURE__ */ jsxRuntime.jsx(
1999
+ "button",
2000
+ {
2001
+ type: "button",
2002
+ className: "native-docx-ribbon-trigger",
2003
+ "aria-label": terms.labels.update,
2004
+ title: terms.labels.update,
2005
+ "data-testid": "docx-update-definitions",
2006
+ onMouseDown: (event) => event.preventDefault(),
2007
+ onClick: () => terms.update(),
2008
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ListRestart, { size: 16 })
2009
+ }
2010
+ )
2011
+ ] });
2012
+ }
1117
2013
  function DocxRibbon({ onSave }) {
1118
2014
  const [tab, setTab] = React3.useState("Home");
1119
2015
  const t = react.useChromeTranslate();
@@ -1152,7 +2048,8 @@ function DocxRibbon({ onSave }) {
1152
2048
  tab === "Insert" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1153
2049
  /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.TableInsert, {}),
1154
2050
  /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.ImageInsert, {}),
1155
- /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.Link, {})
2051
+ /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.Link, {}),
2052
+ /* @__PURE__ */ jsxRuntime.jsx(DefinedTermButtons, {})
1156
2053
  ] }),
1157
2054
  tab === "Review" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1158
2055
  /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.EditingMode, {}),
@@ -1474,7 +2371,7 @@ function NativeDocxEditor({
1474
2371
  )
1475
2372
  ] }),
1476
2373
  !ready && !error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "native-docx-error", role: "status", children: "Opening Word document\u2026" }),
1477
- ready && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "native-docx-body docx-editor", children: /* @__PURE__ */ jsxRuntime.jsx(EditorBoundary, { children: /* @__PURE__ */ jsxRuntime.jsxs(
2374
+ ready && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "native-docx-body docx-editor", children: /* @__PURE__ */ jsxRuntime.jsx(EditorBoundary, { children: /* @__PURE__ */ jsxRuntime.jsx(
1478
2375
  react.DocxEditor.Root,
1479
2376
  {
1480
2377
  document: ready.document,
@@ -1489,52 +2386,60 @@ function NativeDocxEditor({
1489
2386
  if (change.source !== "load") changed();
1490
2387
  },
1491
2388
  onFontError: (e) => setError(e.message),
1492
- children: [
1493
- /* @__PURE__ */ jsxRuntime.jsx(
1494
- react.DocxEditor.RevisionMarkup,
1495
- {
1496
- insertions: { mark: "underline", color: "blue" },
1497
- deletions: { mark: "strikethrough", color: "red" },
1498
- movedFrom: { mark: "doubleStrikethrough", color: "green" },
1499
- movedTo: { mark: "doubleUnderline", color: "green" },
1500
- trackMoves: true
1501
- }
1502
- ),
1503
- !stream && /* @__PURE__ */ jsxRuntime.jsx(DocxRibbon, { onSave: () => void saveVersion() }),
1504
- /* @__PURE__ */ jsxRuntime.jsxs(
1505
- "div",
1506
- {
1507
- className: "native-docx-stage",
1508
- ref: stageRef,
1509
- onMouseDownCapture: (event) => {
1510
- if (event.button === 2 && ref.current?.getSelectionPlacement())
1511
- event.preventDefault();
1512
- },
1513
- children: [
1514
- /* @__PURE__ */ jsxRuntime.jsxs(react.DocxEditor.Viewport, { className: "native-docx-viewport", children: [
1515
- /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Content, {}),
1516
- /* @__PURE__ */ jsxRuntime.jsx(
1517
- DocxMentions,
1518
- {
1519
- initialCommentId,
1520
- mentions: adapter.mentions,
1521
- notify: adapter.notify,
1522
- getAgentStatus: adapter.getAgentStatus,
1523
- requestAgent: adapter.requestAgent ? (request) => adapter.requestAgent(documentId, request) : void 0,
1524
- children: /* @__PURE__ */ jsxRuntime.jsx(DocxEditorReview, { children: () => /* @__PURE__ */ jsxRuntime.jsx(DocxEditorReview.Card, { children: /* @__PURE__ */ jsxRuntime.jsx(DocxCommentActivity, {}) }) })
1525
- }
1526
- ),
1527
- /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.HeaderFooterChrome, {}),
1528
- /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.NotesChrome, {}),
1529
- /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Equation, {}),
1530
- /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.HyperLink, {}),
1531
- /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.ContextMenu, {})
1532
- ] }),
1533
- /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.PageNumber, {})
1534
- ]
1535
- }
1536
- )
1537
- ]
2389
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
2390
+ DefinedTermsProvider,
2391
+ {
2392
+ load: adapter.definitions,
2393
+ editable: !stream && !snapshot && ready.canEdit,
2394
+ notify: adapter.notify,
2395
+ children: [
2396
+ /* @__PURE__ */ jsxRuntime.jsx(
2397
+ react.DocxEditor.RevisionMarkup,
2398
+ {
2399
+ insertions: { mark: "underline", color: "blue" },
2400
+ deletions: { mark: "strikethrough", color: "red" },
2401
+ movedFrom: { mark: "doubleStrikethrough", color: "green" },
2402
+ movedTo: { mark: "doubleUnderline", color: "green" },
2403
+ trackMoves: true
2404
+ }
2405
+ ),
2406
+ !stream && /* @__PURE__ */ jsxRuntime.jsx(DocxRibbon, { onSave: () => void saveVersion() }),
2407
+ /* @__PURE__ */ jsxRuntime.jsxs(
2408
+ "div",
2409
+ {
2410
+ className: "native-docx-stage",
2411
+ ref: stageRef,
2412
+ onMouseDownCapture: (event) => {
2413
+ if (event.button === 2 && ref.current?.getSelectionPlacement())
2414
+ event.preventDefault();
2415
+ },
2416
+ children: [
2417
+ /* @__PURE__ */ jsxRuntime.jsxs(react.DocxEditor.Viewport, { className: "native-docx-viewport", children: [
2418
+ /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Content, {}),
2419
+ /* @__PURE__ */ jsxRuntime.jsx(
2420
+ DocxMentions,
2421
+ {
2422
+ initialCommentId,
2423
+ mentions: adapter.mentions,
2424
+ notify: adapter.notify,
2425
+ getAgentStatus: adapter.getAgentStatus,
2426
+ requestAgent: adapter.requestAgent ? (request) => adapter.requestAgent(documentId, request) : void 0,
2427
+ children: /* @__PURE__ */ jsxRuntime.jsx(DocxEditorReview, { children: () => /* @__PURE__ */ jsxRuntime.jsx(DocxEditorReview.Card, { children: /* @__PURE__ */ jsxRuntime.jsx(DocxCommentActivity, {}) }) })
2428
+ }
2429
+ ),
2430
+ /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.HeaderFooterChrome, {}),
2431
+ /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.NotesChrome, {}),
2432
+ /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Equation, {}),
2433
+ /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.HyperLink, {}),
2434
+ /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.ContextMenu, {})
2435
+ ] }),
2436
+ /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.PageNumber, {})
2437
+ ]
2438
+ }
2439
+ )
2440
+ ]
2441
+ }
2442
+ )
1538
2443
  }
1539
2444
  ) }, retry) }),
1540
2445
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "native-docx-actions", children: [
@@ -1629,16 +2534,25 @@ async function loadFonts(baseUrl) {
1629
2534
  };
1630
2535
  }
1631
2536
 
2537
+ exports.DEFAULT_DEFINED_TERMS_LABELS = DEFAULT_DEFINED_TERMS_LABELS;
2538
+ exports.DEFINED_TERM_TRIGGER = DEFINED_TERM_TRIGGER;
2539
+ exports.DefinedTermsProvider = DefinedTermsProvider;
1632
2540
  exports.DocxCommentActivity = DocxCommentActivity;
1633
2541
  exports.DocxEditorReview = DocxEditorReview;
1634
2542
  exports.DocxMentions = DocxMentions;
1635
2543
  exports.DocxParticipants = DocxParticipants;
1636
2544
  exports.DocxRibbon = DocxRibbon;
1637
2545
  exports.NativeDocxEditor = NativeDocxEditor;
2546
+ exports.editorPort = editorPort;
2547
+ exports.findDefinitionsSection = findDefinitionsSection;
2548
+ exports.insertDefinedTerm = insertDefinedTerm;
1638
2549
  exports.loadDocxFonts = loadDocxFonts;
1639
2550
  exports.normalizeDocxExport = normalizeDocxExport;
1640
2551
  exports.reviewModule = reviewModule;
2552
+ exports.updateDefinitions = updateDefinitions;
2553
+ exports.useDefinedTerms = useDefinedTerms;
1641
2554
  exports.useReview = useReview;
1642
2555
  exports.useReviewItem = useReviewItem;
1643
- //# sourceMappingURL=chunk-2ZDFVRGV.cjs.map
1644
- //# sourceMappingURL=chunk-2ZDFVRGV.cjs.map
2556
+ exports.withDirectEditing = withDirectEditing;
2557
+ //# sourceMappingURL=chunk-E2AAIMXO.cjs.map
2558
+ //# sourceMappingURL=chunk-E2AAIMXO.cjs.map