@arbidocs/blocks 0.4.98 → 0.4.99

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.
@@ -9,7 +9,7 @@ import { AiMarkdown, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDes
9
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';
10
10
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
11
11
  import { createPortal } from 'react-dom';
12
- import { defaultLegalTemplate, listBuildingBlocks, attachedTemplateOf, linkedLevelStyles, styleDivergence, buildingBlockFragment, fragmentClipboardHtml, newFromTemplate } from '@arbidocs/coedit/template';
12
+ import { defaultLegalTemplate, listBuildingBlocks, attachedTemplateOf, linkedLevelStyles, styleDivergence, buildingBlockFragment, fragmentClipboardHtml, trackInsertion, newFromTemplate } from '@arbidocs/coedit/template';
13
13
  import { renderToStaticMarkup } from 'react-dom/server';
14
14
  import * as Y from 'yjs';
15
15
  import { DOCUMENT_COLLABORATION_VERSIONS, collaborationModule } from '@arbidocs/coedit';
@@ -1260,8 +1260,6 @@ function DocxMentions({
1260
1260
  }
1261
1261
  ) });
1262
1262
  }
1263
-
1264
- // src/docx/definitions/fragment.ts
1265
1263
  var DEFINED_TERM_STYLE = "DefinedTerm";
1266
1264
  var FRAGMENT_STYLES = stylesXml(
1267
1265
  "",
@@ -1294,12 +1292,13 @@ function base64(bytes) {
1294
1292
  binary += String.fromCharCode(...bytes.subarray(i, i + 32768));
1295
1293
  return btoa(binary);
1296
1294
  }
1297
- function fragmentHtml(body, covered2) {
1298
- const bytes = docxPackage({
1295
+ function fragmentHtml(body, covered2, revision) {
1296
+ const untracked = docxPackage({
1299
1297
  document: documentXml(body),
1300
1298
  styles: FRAGMENT_STYLES,
1301
1299
  title: "Defined terms"
1302
1300
  });
1301
+ const bytes = revision ? trackInsertion(untracked, revision, covered2) : untracked;
1303
1302
  return `<div data-docx-fragment="${base64(bytes)}" data-docx-fragment-end="${covered2 ? "covered" : "open"}"></div>`;
1304
1303
  }
1305
1304
 
@@ -1556,7 +1555,7 @@ function readParagraph(node, topLevel, bookmarks) {
1556
1555
  links
1557
1556
  };
1558
1557
  }
1559
- function editorPort(editor) {
1558
+ function editorPort(editor, revision) {
1560
1559
  const surface = () => {
1561
1560
  const s = editor.surface;
1562
1561
  if (!s) throw new Error("The document is not open.");
@@ -1575,7 +1574,7 @@ function editorPort(editor) {
1575
1574
  surface().setSelection({ anchor: from, head: to });
1576
1575
  surface().deleteSelection();
1577
1576
  },
1578
- paste: (body, text, covered2) => editor.exec({ type: "paste", text, html: fragmentHtml(body, covered2) }).ok,
1577
+ paste: (body, text, covered2) => editor.exec({ type: "paste", text, html: fragmentHtml(body, covered2, revision) }).ok,
1579
1578
  splitParagraph: () => surface().splitParagraph()
1580
1579
  };
1581
1580
  }
@@ -1618,6 +1617,70 @@ function holdCaret(editor, timeoutMs = 5e3) {
1618
1617
  const offSelection = editor.on("selectionChange", restore);
1619
1618
  const timer = setTimeout(stop, timeoutMs);
1620
1619
  }
1620
+
1621
+ // src/docx/structural/trackedOrNoted.ts
1622
+ var revisionDate = (at = /* @__PURE__ */ new Date()) => at.toISOString().replace(/\.\d{3}Z$/, "Z");
1623
+ function trackedOrNoted(port, { label, author, insert, inserted = Boolean }) {
1624
+ const mode = port.mode();
1625
+ if (mode === "viewing") throw new Error("This document is read only.");
1626
+ if (mode !== "suggesting") return { result: insert(null), how: "direct" };
1627
+ const revision = { author, date: revisionDate() };
1628
+ const before = port.caret();
1629
+ const tracked = port.trackedBy(revision);
1630
+ port.setMode("editing");
1631
+ let result;
1632
+ try {
1633
+ result = insert(revision);
1634
+ } finally {
1635
+ port.setMode("suggesting");
1636
+ }
1637
+ if (!inserted(result) || port.trackedBy(revision) > tracked)
1638
+ return { result, how: inserted(result) ? "tracked" : "direct" };
1639
+ const after = port.caret();
1640
+ if (before && after && port.comment(before, after, label)) return { result, how: "noted" };
1641
+ return { result, how: "direct" };
1642
+ }
1643
+ var attr2 = (node, name) => node.attributes?.find((a) => a.localName === name)?.value;
1644
+ function structuralPort(editor) {
1645
+ return {
1646
+ mode: () => editor.getEditingMode(),
1647
+ setMode: (mode) => void editor.setEditingMode(mode),
1648
+ caret: () => {
1649
+ const head = editor.surface?.state().selection?.head;
1650
+ return head ? { paragraphId: head.paragraphId, offset: head.offset } : null;
1651
+ },
1652
+ // Read from the story's tree: the review pane merges adjacent insertions by one author into
1653
+ // one card, so a card's date need not be this insert's.
1654
+ trackedBy: ({ author, date }) => {
1655
+ const root = editor.surface?.session.part().root;
1656
+ let count = 0;
1657
+ const visit = (node) => {
1658
+ if (node.localName === "ins" && attr2(node, "author") === author && attr2(node, "date") === date)
1659
+ count++;
1660
+ node.children?.forEach(visit);
1661
+ };
1662
+ if (root) visit(root);
1663
+ return count;
1664
+ },
1665
+ comment: (from, to, text) => {
1666
+ const surface = editor.surface;
1667
+ if (!surface) return false;
1668
+ surface.setSelection({ anchor: from, head: to });
1669
+ const ok2 = editor.addComment(text).ok;
1670
+ surface.setSelection({ anchor: to, head: to });
1671
+ return ok2;
1672
+ }
1673
+ };
1674
+ }
1675
+ var DocxAuthorContext = createContext("You");
1676
+ function useTrackedOrNoted() {
1677
+ const editor = useDocxEditor();
1678
+ const author = useContext(DocxAuthorContext);
1679
+ return useCallback(
1680
+ (spec) => editor ? trackedOrNoted(structuralPort(editor), { ...spec, author }) : void 0,
1681
+ [editor, author]
1682
+ );
1683
+ }
1621
1684
  var DEFINED_TERM_TRIGGER = "@@";
1622
1685
  var TRIGGER_QUERY = /(?:^|[\s([{"“‘'])@@([^@\n\t]{0,40})$/;
1623
1686
  var MAX_GROUPS = 8;
@@ -1661,6 +1724,7 @@ function DefinedTermsProvider({
1661
1724
  labels
1662
1725
  }) {
1663
1726
  const editor = useDocxEditor();
1727
+ const track = useTrackedOrNoted();
1664
1728
  const l = useMemo(() => ({ ...DEFAULT_DEFINED_TERMS_LABELS, ...labels }), [labels]);
1665
1729
  const [sources, setSources] = useState(null);
1666
1730
  const loadedAt = useRef(0);
@@ -1717,35 +1781,46 @@ function DefinedTermsProvider({
1717
1781
  refreshRef.current = refresh;
1718
1782
  const firstHover = useCallback(() => void refreshRef.current(), []);
1719
1783
  const caretRect = () => container().querySelector(".docx-editor-one-surface__caret")?.getBoundingClientRect();
1720
- const run = useCallback(
1784
+ const attempt = useCallback(
1721
1785
  (fn) => {
1722
- if (!editor) return void 0;
1723
1786
  try {
1724
- return withDirectEditing(editor, fn);
1787
+ return fn();
1725
1788
  } catch (error) {
1726
1789
  notify?.(error instanceof Error ? error.message : "Could not change the document.", "error");
1727
1790
  return void 0;
1728
1791
  }
1729
1792
  },
1730
- [editor, notify]
1793
+ [notify]
1794
+ );
1795
+ const run = useCallback(
1796
+ (fn) => editor ? attempt(() => withDirectEditing(editor, fn)) : void 0,
1797
+ [editor, attempt]
1731
1798
  );
1732
1799
  const pick = useCallback(
1733
1800
  (row) => {
1734
1801
  if (!editor || !picker || !row) return;
1735
1802
  const port = editorPort(editor);
1736
- const result = run(() => {
1803
+ const placed = run(() => {
1737
1804
  if (picker.mode === "search" && picker.caret) port.setCaret(picker.caret);
1738
- return insertDefinedTerm(port, row.definition, {
1739
- replace: picker.mode === "typing" ? DEFINED_TERM_TRIGGER.length + picker.query.length : 0
1740
- });
1805
+ const caret = port.caret();
1806
+ if (!caret) throw new Error("Place the cursor where the term should go.");
1807
+ const typed = picker.mode === "typing" ? DEFINED_TERM_TRIGGER.length + picker.query.length : 0;
1808
+ if (typed) port.deleteRange({ ...caret, offset: Math.max(0, caret.offset - typed) }, caret);
1809
+ return true;
1741
1810
  });
1811
+ const result = placed ? attempt(
1812
+ () => track({
1813
+ label: `Inserted defined term: ${row.definition.term}`,
1814
+ insert: (revision) => insertDefinedTerm(editorPort(editor, revision), row.definition)
1815
+ })?.result
1816
+ ) : void 0;
1742
1817
  setPicker(null);
1743
1818
  editor.surface?.focus();
1744
1819
  if (result) holdCaret(editor);
1745
1820
  if (result?.addedDefinition)
1746
1821
  notify?.(`\u201C${row.definition.term}\u201D added to the Definitions section.`, "success");
1747
1822
  },
1748
- [editor, picker, run, notify]
1823
+ [editor, picker, run, attempt, track, notify]
1749
1824
  );
1750
1825
  const openPicker = useCallback(
1751
1826
  (anchor) => {
@@ -2149,6 +2224,7 @@ function HouseTemplateProvider({
2149
2224
  children
2150
2225
  }) {
2151
2226
  const editor = useDocxEditor();
2227
+ const track = useTrackedOrNoted();
2152
2228
  const [template, setTemplate] = useState(builtinHouseTemplate);
2153
2229
  const [divergence, setDivergence] = useState(null);
2154
2230
  const [basedOnTemplate, setBasedOnTemplate] = useState(false);
@@ -2189,11 +2265,18 @@ function HouseTemplateProvider({
2189
2265
  const fragment = buildingBlockFragment(template.bytes, name);
2190
2266
  if (!fragment) return false;
2191
2267
  try {
2192
- const result = withDirectEditing(
2193
- editor,
2194
- () => editor.exec({ type: "paste", text: "", html: fragmentClipboardHtml(fragment) })
2195
- );
2196
- if (!result.ok) throw new Error(result.reason ?? "The block could not be inserted here.");
2268
+ const result = track({
2269
+ label: `Inserted Quick Part: ${name}`,
2270
+ insert: (revision) => editor.exec({
2271
+ type: "paste",
2272
+ text: "",
2273
+ html: fragmentClipboardHtml(
2274
+ revision ? trackInsertion(fragment, revision, true) : fragment
2275
+ )
2276
+ }),
2277
+ inserted: (r) => r.ok
2278
+ })?.result;
2279
+ if (!result?.ok) throw new Error(result?.reason ?? "The block could not be inserted here.");
2197
2280
  refresh();
2198
2281
  return true;
2199
2282
  } catch (failure) {
@@ -2204,7 +2287,7 @@ function HouseTemplateProvider({
2204
2287
  return false;
2205
2288
  }
2206
2289
  },
2207
- [editor, editable, template, notify, refresh]
2290
+ [editor, editable, template, notify, refresh, track]
2208
2291
  );
2209
2292
  const setAsHouseTemplate = useMemo(
2210
2293
  () => host?.setFromDocument && documentId ? async () => {
@@ -3239,7 +3322,7 @@ function NativeDocxEditor({
3239
3322
  if (change.source !== "load") changed();
3240
3323
  },
3241
3324
  onFontError: (e) => setError(e.message),
3242
- children: /* @__PURE__ */ jsx(
3325
+ children: /* @__PURE__ */ jsx(DocxAuthorContext.Provider, { value: ready.author, children: /* @__PURE__ */ jsx(
3243
3326
  DefinedTermsProvider,
3244
3327
  {
3245
3328
  load: adapter.definitions,
@@ -3312,7 +3395,7 @@ function NativeDocxEditor({
3312
3395
  }
3313
3396
  )
3314
3397
  }
3315
- )
3398
+ ) })
3316
3399
  }
3317
3400
  ) }, retry) }),
3318
3401
  /* @__PURE__ */ jsxs("div", { className: "native-docx-actions", children: [
@@ -3407,6 +3490,6 @@ async function loadFonts(baseUrl) {
3407
3490
  };
3408
3491
  }
3409
3492
 
3410
- export { BUILTIN_TEMPLATE_NAME, DEFAULT_DEFINED_TERMS_LABELS, DEFINED_TERM_TRIGGER, DefinedTermsProvider, DocxCommentActivity, DocxEditorReview, DocxMentions, DocxParticipants, DocxRibbon, HouseTemplateProvider, NativeDocxEditor, builtinHouseTemplate, contentPath, editorPort, findDefinitionsSection, insertDefinedTerm, loadDocxFonts, normalizeDocxExport, resolveHouseTemplate, reviewModule, templateFileName, updateDefinitions, useDefinedTerms, useHouseTemplate, useReview, useReviewItem, withDirectEditing };
3411
- //# sourceMappingURL=chunk-FIEAWH4K.js.map
3412
- //# sourceMappingURL=chunk-FIEAWH4K.js.map
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