@arbidocs/blocks 0.4.103 → 0.4.104
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/index.cjs +207 -207
- package/dist/agents/index.js +2 -2
- package/dist/{chunk-AOFATOT3.cjs → chunk-2A4MDHJR.cjs} +7 -5
- package/dist/chunk-2A4MDHJR.cjs.map +1 -0
- package/dist/{chunk-GQTIAATM.js → chunk-4GFB5U3K.js} +3 -3
- package/dist/{chunk-GQTIAATM.js.map → chunk-4GFB5U3K.js.map} +1 -1
- package/dist/chunk-5FYU7ZIU.cjs +139 -0
- package/dist/chunk-5FYU7ZIU.cjs.map +1 -0
- package/dist/{chunk-TFDU2KGS.cjs → chunk-7LLLQUM7.cjs} +5 -5
- package/dist/{chunk-TFDU2KGS.cjs.map → chunk-7LLLQUM7.cjs.map} +1 -1
- package/dist/{chunk-D3QPYKZG.js → chunk-EPHGD4YV.js} +7 -6
- package/dist/chunk-EPHGD4YV.js.map +1 -0
- package/dist/chunk-HFZ45FD3.js +133 -0
- package/dist/chunk-HFZ45FD3.js.map +1 -0
- package/dist/{chunk-5NQIBJPP.js → chunk-NJX774HB.js} +3 -3
- package/dist/{chunk-5NQIBJPP.js.map → chunk-NJX774HB.js.map} +1 -1
- package/dist/{chunk-DDYXFALG.cjs → chunk-NW3LFDZL.cjs} +3 -3
- package/dist/{chunk-DDYXFALG.cjs.map → chunk-NW3LFDZL.cjs.map} +1 -1
- package/dist/{chunk-H6DFXG5N.js → chunk-PIT2YZCK.js} +3 -3
- package/dist/{chunk-H6DFXG5N.js.map → chunk-PIT2YZCK.js.map} +1 -1
- package/dist/{chunk-Z3G65XHZ.js → chunk-S55VDTX3.js} +3 -3
- package/dist/{chunk-Z3G65XHZ.js.map → chunk-S55VDTX3.js.map} +1 -1
- package/dist/{chunk-LENXDIMY.cjs → chunk-SKSE4OT6.cjs} +22 -22
- package/dist/{chunk-LENXDIMY.cjs.map → chunk-SKSE4OT6.cjs.map} +1 -1
- package/dist/{chunk-N36PWG7A.cjs → chunk-TP3FAP5J.cjs} +5 -5
- package/dist/{chunk-N36PWG7A.cjs.map → chunk-TP3FAP5J.cjs.map} +1 -1
- package/dist/{chunk-CVYY4X5R.js → chunk-W2RTZOK3.js} +1232 -193
- package/dist/chunk-W2RTZOK3.js.map +1 -0
- package/dist/{chunk-O33EBMIX.cjs → chunk-ZWWN4CUL.cjs} +1410 -359
- package/dist/chunk-ZWWN4CUL.cjs.map +1 -0
- package/dist/connect/docx.cjs +8 -7
- package/dist/connect/docx.cjs.map +1 -1
- package/dist/connect/docx.js +6 -5
- package/dist/connect/docx.js.map +1 -1
- package/dist/connect/index.cjs +12 -11
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.js +5 -4
- package/dist/connect/index.js.map +1 -1
- package/dist/docx/LinkHoverCard.d.ts +24 -0
- package/dist/docx/NativeDocxEditor.d.ts +6 -0
- package/dist/docx/beforeSave.d.ts +9 -0
- package/dist/docx/definitions/fragment.d.ts +19 -1
- package/dist/docx/definitions/port.d.ts +43 -11
- package/dist/docx/index.cjs +85 -36
- package/dist/docx/index.cjs.map +1 -1
- package/dist/docx/index.d.ts +6 -0
- package/dist/docx/index.js +5 -4
- package/dist/docx/index.js.map +1 -1
- package/dist/docx/references/CrossReferences.d.ts +97 -0
- package/dist/docx/references/EditorMenus.d.ts +10 -0
- package/dist/docx/references/commands.d.ts +119 -0
- package/dist/docx/references/numbering.d.ts +49 -0
- package/dist/docx/references/passages.d.ts +32 -0
- package/dist/docx/references/port.d.ts +20 -0
- package/dist/facts/index.cjs +22 -129
- package/dist/facts/index.cjs.map +1 -1
- package/dist/facts/index.js +3 -125
- package/dist/facts/index.js.map +1 -1
- package/dist/files/index.cjs +1 -1
- package/dist/files/index.js +1 -1
- package/dist/home/index.cjs +1 -1
- package/dist/home/index.js +1 -1
- package/dist/index.cjs +314 -314
- package/dist/index.js +8 -8
- package/dist/shell/index.cjs +1 -1
- package/dist/shell/index.js +1 -1
- package/dist/studio/index.cjs +1 -1
- package/dist/studio/index.js +1 -1
- package/dist/tags/ooxml.d.ts +4 -0
- package/dist/workflow-canvas/index.cjs +9 -9
- package/dist/workflow-canvas/index.js +2 -2
- package/node_modules/@arbidocs/coedit/package.json +1 -1
- package/package.json +4 -4
- package/src/docx/README.md +22 -0
- package/dist/chunk-AOFATOT3.cjs.map +0 -1
- package/dist/chunk-CVYY4X5R.js.map +0 -1
- package/dist/chunk-D3QPYKZG.js.map +0 -1
- package/dist/chunk-O33EBMIX.cjs.map +0 -1
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { FactPassageItem } from './chunk-HFZ45FD3.js';
|
|
3
|
+
import { stylesXml, definitionBookmark, groupDefinitions, definitionLabels, filterTermGroups, esc, hyperlinkRelationship, docxPackage, documentXml, definitionIdOfBookmark, compareTerms, parseDefinition } from './chunk-EPHGD4YV.js';
|
|
3
4
|
import { filterMentionCandidates, MentionMenu, findMentionQuery, listOptionId, extractMentions, useListKeyNav } from './chunk-AA3PT6KR.js';
|
|
4
5
|
import { unzipSync, strFromU8, strToU8, zipSync } from 'fflate';
|
|
5
6
|
import { collectReviewItems, revisionItemsOf } from '@docx-editor.dev/core/store';
|
|
6
|
-
import
|
|
7
|
+
import React4, { createContext, useContext, useState, useRef, useCallback, useEffect, useLayoutEffect, useMemo, useSyncExternalStore } from 'react';
|
|
7
8
|
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, Pilcrow, UsersRound, RefreshCw, WifiOff, Download, Save, Ellipsis, 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';
|
|
9
|
+
import { AiMarkdown, Dialog, DialogContent, DialogHeader, DialogTitle, cn, DialogDescription, Button, DialogFooter, Tabs, TabsList, TabsTrigger, TabsContent, Input, splitMarkdownBlocks } from '@arbidocs/react/ui';
|
|
10
|
+
import { MessageSquarePlus, MessageSquare, PencilLine, ChevronLeft, ChevronRight, X, ChevronUp, ChevronDown, CheckCheck, RotateCcw, CircleCheck, Trash2, Check, SendHorizontal, Loader2, Sparkles, Type, Pilcrow, UsersRound, RefreshCw, WifiOff, Download, Save, Ellipsis, BookA, Blocks, Link2, Superscript, NotebookText, RefreshCcw, 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
11
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
11
12
|
import { createPortal } from 'react-dom';
|
|
12
13
|
import { defaultLegalTemplate, listBuildingBlocks, attachedTemplateOf, linkedLevelStyles, styleDivergence, buildingBlockFragment, fragmentClipboardHtml, trackInsertion, newFromTemplate } from '@arbidocs/coedit/template';
|
|
14
|
+
import { resolveNumberingLevel, resolveStoryListItems, buildStyleCascadeTable, withNumberingStyleLinks, buildNumberingIndex } from '@docx-editor.dev/core/layout';
|
|
13
15
|
import { executeImageCommand } from '@docx-editor.dev/core/editor';
|
|
14
16
|
import { renderToStaticMarkup } from 'react-dom/server';
|
|
15
17
|
import * as Y from 'yjs';
|
|
@@ -896,7 +898,7 @@ function DocxCommentActivity() {
|
|
|
896
898
|
const thread = review.items.filter(
|
|
897
899
|
(entry) => entry.kind === "comment" && (entry.item.id === commentId || entry.parentId === commentId)
|
|
898
900
|
);
|
|
899
|
-
const statuses = Object.entries(activity).filter(([,
|
|
901
|
+
const statuses = Object.entries(activity).filter(([, run2]) => run2.commentId === commentId);
|
|
900
902
|
const labels = {
|
|
901
903
|
delivering: "Delivering mention\u2026",
|
|
902
904
|
queued: "Queued\u2026",
|
|
@@ -908,18 +910,18 @@ function DocxCommentActivity() {
|
|
|
908
910
|
unknown: "Status unavailable"
|
|
909
911
|
};
|
|
910
912
|
return /* @__PURE__ */ jsxs("div", { className: "native-docx-comment-extra", "data-review-selectable": "", children: [
|
|
911
|
-
statuses.map(([id,
|
|
913
|
+
statuses.map(([id, run2]) => /* @__PURE__ */ jsxs(
|
|
912
914
|
"div",
|
|
913
915
|
{
|
|
914
916
|
role: "status",
|
|
915
917
|
"data-testid": "docx-comment-agent-status",
|
|
916
|
-
"data-status":
|
|
918
|
+
"data-status": run2.status,
|
|
917
919
|
className: "native-docx-comment-activity",
|
|
918
920
|
children: [
|
|
919
|
-
["delivering", "queued", "in_progress"].includes(
|
|
920
|
-
|
|
921
|
+
["delivering", "queued", "in_progress"].includes(run2.status) && /* @__PURE__ */ jsx("span", { className: "native-docx-agent-spinner", "aria-hidden": "true" }),
|
|
922
|
+
run2.label,
|
|
921
923
|
": ",
|
|
922
|
-
labels[
|
|
924
|
+
labels[run2.status]
|
|
923
925
|
]
|
|
924
926
|
},
|
|
925
927
|
id
|
|
@@ -947,10 +949,10 @@ function DocxCommentActivity() {
|
|
|
947
949
|
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: entry.author || "Reviewer" }),
|
|
948
950
|
/* @__PURE__ */ jsx("div", { "data-testid": "docx-full-comment-text", children: /* @__PURE__ */ jsx(AiMarkdown, { allowHtml: false, children: commentText(entry) }) })
|
|
949
951
|
] }, entry.key)),
|
|
950
|
-
statuses.map(([id,
|
|
951
|
-
|
|
952
|
+
statuses.map(([id, run2]) => /* @__PURE__ */ jsxs("p", { role: "status", className: "text-sm", children: [
|
|
953
|
+
run2.label,
|
|
952
954
|
": ",
|
|
953
|
-
labels[
|
|
955
|
+
labels[run2.status]
|
|
954
956
|
] }, id))
|
|
955
957
|
]
|
|
956
958
|
}
|
|
@@ -1262,9 +1264,19 @@ function DocxMentions({
|
|
|
1262
1264
|
) });
|
|
1263
1265
|
}
|
|
1264
1266
|
var DEFINED_TERM_STYLE = "DefinedTerm";
|
|
1265
|
-
var
|
|
1267
|
+
var CROSS_REFERENCE_STYLE = "CrossReference";
|
|
1268
|
+
var BROKEN_CROSS_REFERENCE_STYLE = "CrossReferenceBroken";
|
|
1269
|
+
var CHARACTER_STYLES = {
|
|
1270
|
+
[DEFINED_TERM_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>`,
|
|
1271
|
+
[CROSS_REFERENCE_STYLE]: `<w:style w:type="character" w:customStyle="1" w:styleId="${CROSS_REFERENCE_STYLE}"><w:name w:val="Cross Reference"/><w:rPr><w:color w:val="1F4E79"/><w:u w:val="dotted" w:color="8EA9C1"/></w:rPr></w:style>`,
|
|
1272
|
+
[BROKEN_CROSS_REFERENCE_STYLE]: `<w:style w:type="character" w:customStyle="1" w:styleId="${BROKEN_CROSS_REFERENCE_STYLE}"><w:name w:val="Cross Reference Broken"/><w:basedOn w:val="${CROSS_REFERENCE_STYLE}"/><w:rPr><w:color w:val="C00000"/><w:u w:val="wave" w:color="C00000"/></w:rPr></w:style>`
|
|
1273
|
+
};
|
|
1274
|
+
function stylesUsed(body) {
|
|
1275
|
+
return [...new Set([...body.matchAll(/<w:rStyle w:val="([^"]+)"/g)].map((m) => m[1]))];
|
|
1276
|
+
}
|
|
1277
|
+
var fragmentStyles = (ids) => stylesXml(
|
|
1266
1278
|
"",
|
|
1267
|
-
`<w:style w:type="paragraph" w:default="1" w:styleId="Normal"><w:name w:val="Normal"/><w:qFormat/></w:style
|
|
1279
|
+
`<w:style w:type="paragraph" w:default="1" w:styleId="Normal"><w:name w:val="Normal"/><w:qFormat/></w:style>${ids.map((id) => CHARACTER_STYLES[id] ?? "").join("")}`
|
|
1268
1280
|
);
|
|
1269
1281
|
var textRun = (text, props = "") => `<w:r>${props ? `<w:rPr>${props}</w:rPr>` : ""}<w:t xml:space="preserve">${esc(text)}</w:t></w:r>`;
|
|
1270
1282
|
function definitionTooltip(definition) {
|
|
@@ -1292,11 +1304,16 @@ function base64(bytes) {
|
|
|
1292
1304
|
binary += String.fromCharCode(...bytes.subarray(i, i + 32768));
|
|
1293
1305
|
return btoa(binary);
|
|
1294
1306
|
}
|
|
1295
|
-
function fragmentHtml(body, covered2,
|
|
1307
|
+
function fragmentHtml(body, covered2, {
|
|
1308
|
+
revision,
|
|
1309
|
+
relationships,
|
|
1310
|
+
styles = stylesUsed(body)
|
|
1311
|
+
} = {}) {
|
|
1296
1312
|
const untracked = docxPackage({
|
|
1297
1313
|
document: documentXml(body),
|
|
1298
|
-
styles:
|
|
1299
|
-
title: "Defined terms"
|
|
1314
|
+
styles: fragmentStyles(styles),
|
|
1315
|
+
title: "Defined terms",
|
|
1316
|
+
relationships
|
|
1300
1317
|
});
|
|
1301
1318
|
const bytes = revision ? trackInsertion(untracked, revision, covered2) : untracked;
|
|
1302
1319
|
return `<div data-docx-fragment="${base64(bytes)}" data-docx-fragment-end="${covered2 ? "covered" : "open"}"></div>`;
|
|
@@ -1395,9 +1412,93 @@ function definitionOfAnchor(anchor, definitions) {
|
|
|
1395
1412
|
const id = definitionIdOfBookmark(anchor.replace(/^#/, ""));
|
|
1396
1413
|
return id ? definitions.get(id) : void 0;
|
|
1397
1414
|
}
|
|
1415
|
+
function LinkHoverCard({
|
|
1416
|
+
root,
|
|
1417
|
+
matches,
|
|
1418
|
+
resolve,
|
|
1419
|
+
onFirstHover,
|
|
1420
|
+
testId
|
|
1421
|
+
}) {
|
|
1422
|
+
const [card, setCard] = useState(null);
|
|
1423
|
+
const hovered = useRef(false);
|
|
1424
|
+
const latest = useRef({ matches, onFirstHover });
|
|
1425
|
+
latest.current = { matches, onFirstHover };
|
|
1426
|
+
useEffect(() => {
|
|
1427
|
+
if (!root) return;
|
|
1428
|
+
const over = (event) => {
|
|
1429
|
+
const link = event.target?.closest?.(
|
|
1430
|
+
"a.docx-hyperlink"
|
|
1431
|
+
);
|
|
1432
|
+
const href = link?.getAttribute("href") ?? "";
|
|
1433
|
+
if (!link || !href || !latest.current.matches(href, link)) return;
|
|
1434
|
+
if (!hovered.current) {
|
|
1435
|
+
hovered.current = true;
|
|
1436
|
+
latest.current.onFirstHover?.();
|
|
1437
|
+
}
|
|
1438
|
+
const title = link.getAttribute("title");
|
|
1439
|
+
if (title) {
|
|
1440
|
+
link.dataset.hoverTitle = title;
|
|
1441
|
+
link.removeAttribute("title");
|
|
1442
|
+
}
|
|
1443
|
+
const rect = link.getBoundingClientRect();
|
|
1444
|
+
setCard({
|
|
1445
|
+
left: rect.left,
|
|
1446
|
+
top: rect.bottom + 6,
|
|
1447
|
+
href,
|
|
1448
|
+
fallback: link.dataset.hoverTitle ?? ""
|
|
1449
|
+
});
|
|
1450
|
+
};
|
|
1451
|
+
const out = (event) => {
|
|
1452
|
+
const link = event.target?.closest?.("a.docx-hyperlink");
|
|
1453
|
+
if (link && !link.contains(event.relatedTarget)) setCard(null);
|
|
1454
|
+
};
|
|
1455
|
+
const hide = () => setCard(null);
|
|
1456
|
+
root.addEventListener("mouseover", over);
|
|
1457
|
+
root.addEventListener("mouseout", out);
|
|
1458
|
+
window.addEventListener("keydown", hide, true);
|
|
1459
|
+
window.addEventListener("pointerdown", hide, true);
|
|
1460
|
+
window.addEventListener("scroll", hide, true);
|
|
1461
|
+
return () => {
|
|
1462
|
+
root.removeEventListener("mouseover", over);
|
|
1463
|
+
root.removeEventListener("mouseout", out);
|
|
1464
|
+
window.removeEventListener("keydown", hide, true);
|
|
1465
|
+
window.removeEventListener("pointerdown", hide, true);
|
|
1466
|
+
window.removeEventListener("scroll", hide, true);
|
|
1467
|
+
};
|
|
1468
|
+
}, [root]);
|
|
1469
|
+
if (!card) return null;
|
|
1470
|
+
const content = resolve(card.href);
|
|
1471
|
+
if (!content && !card.fallback) return null;
|
|
1472
|
+
return createPortal(
|
|
1473
|
+
/* @__PURE__ */ jsx(
|
|
1474
|
+
"div",
|
|
1475
|
+
{
|
|
1476
|
+
role: "tooltip",
|
|
1477
|
+
className: "native-docx-link-card rounded-md border border-border bg-popover p-3 text-sm text-popover-foreground shadow-lg",
|
|
1478
|
+
style: {
|
|
1479
|
+
position: "fixed",
|
|
1480
|
+
left: Math.max(8, Math.min(card.left, window.innerWidth - 348)),
|
|
1481
|
+
top: card.top,
|
|
1482
|
+
width: 340,
|
|
1483
|
+
zIndex: 1e3,
|
|
1484
|
+
pointerEvents: "none"
|
|
1485
|
+
},
|
|
1486
|
+
"data-testid": testId,
|
|
1487
|
+
children: content ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1488
|
+
content.title && /* @__PURE__ */ jsx("p", { className: "font-medium", children: content.title }),
|
|
1489
|
+
/* @__PURE__ */ jsx("p", { className: content.title ? "mt-1 text-muted-foreground" : void 0, children: content.body }),
|
|
1490
|
+
content.footer && /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: content.footer })
|
|
1491
|
+
] }) : /* @__PURE__ */ jsx("p", { children: card.fallback })
|
|
1492
|
+
}
|
|
1493
|
+
),
|
|
1494
|
+
document.body
|
|
1495
|
+
);
|
|
1496
|
+
}
|
|
1398
1497
|
|
|
1399
1498
|
// src/docx/definitions/port.ts
|
|
1499
|
+
var WATCHED_STYLES = /* @__PURE__ */ new Set([BROKEN_CROSS_REFERENCE_STYLE]);
|
|
1400
1500
|
var attr = (node, name) => node.attributes?.find((a) => a.localName === name)?.value;
|
|
1501
|
+
var FIELD_ATOM = "\uFFFC";
|
|
1401
1502
|
var HEADING_STYLE = /^(heading|berschrift|titre|t[ií]tulo|titolo|kop)\s*\d/i;
|
|
1402
1503
|
function readParagraphs(root) {
|
|
1403
1504
|
const out = [];
|
|
@@ -1424,8 +1525,44 @@ function readParagraph(node, topLevel, bookmarks) {
|
|
|
1424
1525
|
const links = [];
|
|
1425
1526
|
let styleId;
|
|
1426
1527
|
let outline = false;
|
|
1528
|
+
let fieldDepth = 0;
|
|
1529
|
+
const marks = [];
|
|
1530
|
+
let runStyle;
|
|
1531
|
+
const fields = [];
|
|
1532
|
+
let current = null;
|
|
1533
|
+
const field = (c) => {
|
|
1534
|
+
const type = attr(c, "fldCharType");
|
|
1535
|
+
if (type === "begin") {
|
|
1536
|
+
if (fieldDepth === 0) {
|
|
1537
|
+
current = { offset: text.length, instruction: "", result: "", inResult: false };
|
|
1538
|
+
text += FIELD_ATOM;
|
|
1539
|
+
}
|
|
1540
|
+
fieldDepth++;
|
|
1541
|
+
} else if (type === "separate" && fieldDepth === 1 && current) current.inResult = true;
|
|
1542
|
+
else if (type === "end") {
|
|
1543
|
+
fieldDepth = Math.max(0, fieldDepth - 1);
|
|
1544
|
+
if (fieldDepth === 0 && current) {
|
|
1545
|
+
const { offset, instruction, result } = current;
|
|
1546
|
+
fields.push({ offset, instruction: instruction.trim(), result });
|
|
1547
|
+
current = null;
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
};
|
|
1427
1551
|
const walk = (n, link) => {
|
|
1428
1552
|
for (const c of n.children ?? []) {
|
|
1553
|
+
if (c.localName === "fldChar") {
|
|
1554
|
+
field(c);
|
|
1555
|
+
continue;
|
|
1556
|
+
}
|
|
1557
|
+
if (c.localName === "fldSimple") {
|
|
1558
|
+
if (fieldDepth === 0) text += FIELD_ATOM;
|
|
1559
|
+
continue;
|
|
1560
|
+
}
|
|
1561
|
+
if (c.localName === "instrText") {
|
|
1562
|
+
if (fieldDepth === 1 && current)
|
|
1563
|
+
current.instruction += (c.children ?? []).map((t) => t.value ?? "").join("");
|
|
1564
|
+
continue;
|
|
1565
|
+
}
|
|
1429
1566
|
if (c.kind === "paragraphProperties" || c.localName === "pPr") {
|
|
1430
1567
|
for (const p of c.children ?? []) {
|
|
1431
1568
|
if (p.localName === "pStyle") styleId = attr(p, "val");
|
|
@@ -1434,6 +1571,14 @@ function readParagraph(node, topLevel, bookmarks) {
|
|
|
1434
1571
|
continue;
|
|
1435
1572
|
}
|
|
1436
1573
|
if (c.localName === "delText" || c.localName === "del" || c.localName === "rPr") continue;
|
|
1574
|
+
if (c.localName === "r") {
|
|
1575
|
+
const rStyle = c.children?.find((x) => x.localName === "rPr")?.children?.find((x) => x.localName === "rStyle");
|
|
1576
|
+
const watched = rStyle && attr(rStyle, "val");
|
|
1577
|
+
runStyle = watched && WATCHED_STYLES.has(watched) ? watched : void 0;
|
|
1578
|
+
walk(c, link);
|
|
1579
|
+
runStyle = void 0;
|
|
1580
|
+
continue;
|
|
1581
|
+
}
|
|
1437
1582
|
if (c.localName === "bookmarkStart") {
|
|
1438
1583
|
const name = attr(c, "name");
|
|
1439
1584
|
if (name) bookmarks.push(name);
|
|
@@ -1447,11 +1592,22 @@ function readParagraph(node, topLevel, bookmarks) {
|
|
|
1447
1592
|
continue;
|
|
1448
1593
|
}
|
|
1449
1594
|
if (c.kind === "textValue") {
|
|
1595
|
+
if (fieldDepth > 0) {
|
|
1596
|
+
const open = current;
|
|
1597
|
+
if (fieldDepth === 1 && open?.inResult) open.result += c.value ?? "";
|
|
1598
|
+
continue;
|
|
1599
|
+
}
|
|
1600
|
+
if (runStyle && c.value) {
|
|
1601
|
+
const last = marks[marks.length - 1];
|
|
1602
|
+
if (last && last.styleId === runStyle && last.offset + last.text.length === text.length)
|
|
1603
|
+
last.text += c.value;
|
|
1604
|
+
else marks.push({ styleId: runStyle, offset: text.length, text: c.value });
|
|
1605
|
+
}
|
|
1450
1606
|
text += c.value ?? "";
|
|
1451
1607
|
if (link) link.text += c.value ?? "";
|
|
1452
1608
|
continue;
|
|
1453
1609
|
}
|
|
1454
|
-
if (c.localName === "tab") text += " ";
|
|
1610
|
+
if (c.localName === "tab" && fieldDepth === 0) text += " ";
|
|
1455
1611
|
walk(c, link);
|
|
1456
1612
|
}
|
|
1457
1613
|
};
|
|
@@ -1463,9 +1619,20 @@ function readParagraph(node, topLevel, bookmarks) {
|
|
|
1463
1619
|
styleId,
|
|
1464
1620
|
topLevel,
|
|
1465
1621
|
bookmarks,
|
|
1466
|
-
links
|
|
1622
|
+
links,
|
|
1623
|
+
...fields.length ? { fields } : {},
|
|
1624
|
+
...marks.length ? { marks } : {}
|
|
1467
1625
|
};
|
|
1468
1626
|
}
|
|
1627
|
+
function documentStyleIds(root) {
|
|
1628
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1629
|
+
for (const style of root?.children ?? [])
|
|
1630
|
+
if (style.localName === "style") {
|
|
1631
|
+
const id = attr(style, "styleId");
|
|
1632
|
+
if (id) ids.add(id);
|
|
1633
|
+
}
|
|
1634
|
+
return ids;
|
|
1635
|
+
}
|
|
1469
1636
|
function editorPort(editor, revision) {
|
|
1470
1637
|
const surface = () => {
|
|
1471
1638
|
const s = editor.surface;
|
|
@@ -1485,8 +1652,17 @@ function editorPort(editor, revision) {
|
|
|
1485
1652
|
surface().setSelection({ anchor: from, head: to });
|
|
1486
1653
|
surface().deleteSelection();
|
|
1487
1654
|
},
|
|
1488
|
-
paste: (body, text, covered2) =>
|
|
1489
|
-
|
|
1655
|
+
paste: (body, text, covered2, relationships) => {
|
|
1656
|
+
const defined = documentStyleIds(surface().session.stylesRoot());
|
|
1657
|
+
const styles = stylesUsed(body).filter((id) => !defined.has(id));
|
|
1658
|
+
return editor.exec({
|
|
1659
|
+
type: "paste",
|
|
1660
|
+
text,
|
|
1661
|
+
html: fragmentHtml(body, covered2, { revision, relationships, styles })
|
|
1662
|
+
}).ok;
|
|
1663
|
+
},
|
|
1664
|
+
splitParagraph: () => surface().splitParagraph(),
|
|
1665
|
+
typeText: (text) => surface().insertPlainText(text)
|
|
1490
1666
|
};
|
|
1491
1667
|
}
|
|
1492
1668
|
function withDirectEditing(editor, fn) {
|
|
@@ -1499,34 +1675,68 @@ function withDirectEditing(editor, fn) {
|
|
|
1499
1675
|
if (mode === "suggesting") editor.setEditingMode("suggesting");
|
|
1500
1676
|
}
|
|
1501
1677
|
}
|
|
1502
|
-
function holdCaret(editor,
|
|
1678
|
+
function holdCaret(editor, { settleMs = 600, maxMs = 2e3 } = {}) {
|
|
1503
1679
|
const surface = editor.surface;
|
|
1504
1680
|
const selection = surface?.state().selection;
|
|
1505
1681
|
if (!surface || !selection) return;
|
|
1506
|
-
const {
|
|
1507
|
-
const paraId = surface.session.paraIdOf(paragraphId);
|
|
1682
|
+
const { offset } = selection.head;
|
|
1683
|
+
const paraId = surface.session.paraIdOf(selection.head.paragraphId);
|
|
1508
1684
|
if (!paraId) return;
|
|
1685
|
+
let typed = "";
|
|
1509
1686
|
let done = false;
|
|
1687
|
+
let settle;
|
|
1510
1688
|
const stop = () => {
|
|
1511
1689
|
done = true;
|
|
1512
1690
|
offChange();
|
|
1513
|
-
|
|
1514
|
-
clearTimeout(
|
|
1691
|
+
clearTimeout(settle);
|
|
1692
|
+
clearTimeout(limit);
|
|
1693
|
+
window.removeEventListener("keydown", key, true);
|
|
1694
|
+
window.removeEventListener("pointerdown", click, true);
|
|
1515
1695
|
};
|
|
1516
|
-
const
|
|
1696
|
+
const finish = () => {
|
|
1517
1697
|
if (done) return;
|
|
1518
|
-
const now = surface.state().selection;
|
|
1519
|
-
const node = surface.session.nodeIdOf(paraId);
|
|
1520
|
-
if (!now || !node) return;
|
|
1521
|
-
if (now.head.offset !== offset || now.head.paragraphId !== paragraphId) return stop();
|
|
1522
|
-
if (node === paragraphId) return;
|
|
1523
1698
|
stop();
|
|
1699
|
+
const node = surface.session.nodeIdOf(paraId);
|
|
1700
|
+
if (!node) return;
|
|
1524
1701
|
const point = { paragraphId: node, offset };
|
|
1525
1702
|
surface.setSelection({ anchor: point, head: point });
|
|
1703
|
+
if (typed) surface.insertPlainText(typed);
|
|
1704
|
+
};
|
|
1705
|
+
const key = (event) => {
|
|
1706
|
+
if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
|
|
1707
|
+
event.preventDefault();
|
|
1708
|
+
event.stopPropagation();
|
|
1709
|
+
typed += event.key;
|
|
1710
|
+
return;
|
|
1711
|
+
}
|
|
1712
|
+
finish();
|
|
1713
|
+
};
|
|
1714
|
+
const click = () => {
|
|
1715
|
+
if (typed) finish();
|
|
1716
|
+
else stop();
|
|
1717
|
+
};
|
|
1718
|
+
const quiet = () => {
|
|
1719
|
+
clearTimeout(settle);
|
|
1720
|
+
settle = setTimeout(finish, settleMs);
|
|
1526
1721
|
};
|
|
1527
|
-
const offChange = editor.on("change",
|
|
1528
|
-
|
|
1529
|
-
|
|
1722
|
+
const offChange = editor.on("change", quiet);
|
|
1723
|
+
window.addEventListener("keydown", key, true);
|
|
1724
|
+
window.addEventListener("pointerdown", click, true);
|
|
1725
|
+
settle = setTimeout(finish, settleMs);
|
|
1726
|
+
const limit = setTimeout(finish, maxMs);
|
|
1727
|
+
}
|
|
1728
|
+
function preservingCaret(editor, fn) {
|
|
1729
|
+
const surface = editor.surface;
|
|
1730
|
+
const before = surface?.state().selection?.head;
|
|
1731
|
+
const paraId = before && surface?.session.paraIdOf(before.paragraphId);
|
|
1732
|
+
const result = fn();
|
|
1733
|
+
const node = paraId && surface?.session.nodeIdOf(paraId);
|
|
1734
|
+
if (before && node) {
|
|
1735
|
+
const point = { paragraphId: node, offset: before.offset };
|
|
1736
|
+
surface.setSelection({ anchor: point, head: point });
|
|
1737
|
+
holdCaret(editor);
|
|
1738
|
+
}
|
|
1739
|
+
return result;
|
|
1530
1740
|
}
|
|
1531
1741
|
|
|
1532
1742
|
// src/docx/structural/trackedOrNoted.ts
|
|
@@ -1690,19 +1900,26 @@ function DefinedTermsProvider({
|
|
|
1690
1900
|
},
|
|
1691
1901
|
[notify]
|
|
1692
1902
|
);
|
|
1693
|
-
const
|
|
1903
|
+
const run2 = useCallback(
|
|
1694
1904
|
(fn) => editor ? attempt(() => withDirectEditing(editor, fn)) : void 0,
|
|
1695
1905
|
[editor, attempt]
|
|
1696
1906
|
);
|
|
1907
|
+
const typedTrigger = (port) => {
|
|
1908
|
+
if (picker?.mode !== "typing") return 0;
|
|
1909
|
+
const caret = port.caret();
|
|
1910
|
+
const paragraph = caret && port.paragraphs().find((p) => p.id === caret.paragraphId);
|
|
1911
|
+
const match = paragraph && TRIGGER_QUERY.exec(paragraph.text.slice(0, caret.offset));
|
|
1912
|
+
return match ? DEFINED_TERM_TRIGGER.length + match[1].length : 0;
|
|
1913
|
+
};
|
|
1697
1914
|
const pick = useCallback(
|
|
1698
1915
|
(row) => {
|
|
1699
1916
|
if (!editor || !picker || !row) return;
|
|
1700
1917
|
const port = editorPort(editor);
|
|
1701
|
-
const placed =
|
|
1918
|
+
const placed = run2(() => {
|
|
1702
1919
|
if (picker.mode === "search" && picker.caret) port.setCaret(picker.caret);
|
|
1703
1920
|
const caret = port.caret();
|
|
1704
1921
|
if (!caret) throw new Error("Place the cursor where the term should go.");
|
|
1705
|
-
const typed =
|
|
1922
|
+
const typed = typedTrigger(port);
|
|
1706
1923
|
if (typed) port.deleteRange({ ...caret, offset: Math.max(0, caret.offset - typed) }, caret);
|
|
1707
1924
|
return true;
|
|
1708
1925
|
});
|
|
@@ -1718,7 +1935,7 @@ function DefinedTermsProvider({
|
|
|
1718
1935
|
if (result?.addedDefinition)
|
|
1719
1936
|
notify?.(`\u201C${row.definition.term}\u201D added to the Definitions section.`, "success");
|
|
1720
1937
|
},
|
|
1721
|
-
[editor, picker,
|
|
1938
|
+
[editor, picker, run2, attempt, track, notify]
|
|
1722
1939
|
);
|
|
1723
1940
|
const openPicker = useCallback(
|
|
1724
1941
|
(anchor) => {
|
|
@@ -1797,11 +2014,16 @@ function DefinedTermsProvider({
|
|
|
1797
2014
|
/* @__PURE__ */ jsx("span", { ref: marker, hidden: true }),
|
|
1798
2015
|
children,
|
|
1799
2016
|
load && /* @__PURE__ */ jsx(
|
|
1800
|
-
|
|
2017
|
+
LinkHoverCard,
|
|
1801
2018
|
{
|
|
1802
2019
|
root: viewer,
|
|
1803
|
-
|
|
1804
|
-
|
|
2020
|
+
matches: (href) => href.startsWith("#_dt_"),
|
|
2021
|
+
resolve: (href) => {
|
|
2022
|
+
const definition = definitionOfAnchor(href, byId);
|
|
2023
|
+
return definition ? { title: definition.term, body: definition.meaning, footer: sourceOf(definition) } : null;
|
|
2024
|
+
},
|
|
2025
|
+
onFirstHover: firstHover,
|
|
2026
|
+
testId: "docx-defined-term-card"
|
|
1805
2027
|
}
|
|
1806
2028
|
),
|
|
1807
2029
|
picker && createPortal(
|
|
@@ -1843,7 +2065,7 @@ function DefinedTermMenu({
|
|
|
1843
2065
|
onClose,
|
|
1844
2066
|
labels: l
|
|
1845
2067
|
}) {
|
|
1846
|
-
const listboxId =
|
|
2068
|
+
const listboxId = React4.useId();
|
|
1847
2069
|
const element = useRef(null);
|
|
1848
2070
|
const search = picker.mode === "search";
|
|
1849
2071
|
useEffect(() => {
|
|
@@ -1954,83 +2176,6 @@ function DefinedTermMenu({
|
|
|
1954
2176
|
}
|
|
1955
2177
|
);
|
|
1956
2178
|
}
|
|
1957
|
-
function DefinedTermHover({
|
|
1958
|
-
root,
|
|
1959
|
-
resolve,
|
|
1960
|
-
onFirstHover
|
|
1961
|
-
}) {
|
|
1962
|
-
const [card, setCard] = useState(null);
|
|
1963
|
-
const hovered = useRef(false);
|
|
1964
|
-
useEffect(() => {
|
|
1965
|
-
if (!root) return;
|
|
1966
|
-
const over = (event) => {
|
|
1967
|
-
const link = event.target?.closest?.(
|
|
1968
|
-
'a.docx-hyperlink[data-docx-link-kind="internal"]'
|
|
1969
|
-
);
|
|
1970
|
-
const href = link?.getAttribute("href") ?? "";
|
|
1971
|
-
if (!link || !href.startsWith("#_dt_")) return;
|
|
1972
|
-
if (!hovered.current) {
|
|
1973
|
-
hovered.current = true;
|
|
1974
|
-
onFirstHover();
|
|
1975
|
-
}
|
|
1976
|
-
const title = link.getAttribute("title");
|
|
1977
|
-
if (title) {
|
|
1978
|
-
link.dataset.definition = title;
|
|
1979
|
-
link.removeAttribute("title");
|
|
1980
|
-
}
|
|
1981
|
-
const rect = link.getBoundingClientRect();
|
|
1982
|
-
setCard({
|
|
1983
|
-
left: rect.left,
|
|
1984
|
-
top: rect.bottom + 6,
|
|
1985
|
-
anchor: href.slice(1),
|
|
1986
|
-
fallback: link.dataset.definition ?? ""
|
|
1987
|
-
});
|
|
1988
|
-
};
|
|
1989
|
-
const out = (event) => {
|
|
1990
|
-
const link = event.target?.closest?.("a.docx-hyperlink");
|
|
1991
|
-
if (link && !link.contains(event.relatedTarget)) setCard(null);
|
|
1992
|
-
};
|
|
1993
|
-
root.addEventListener("mouseover", over);
|
|
1994
|
-
root.addEventListener("mouseout", out);
|
|
1995
|
-
const hide = () => setCard(null);
|
|
1996
|
-
window.addEventListener("keydown", hide, true);
|
|
1997
|
-
window.addEventListener("pointerdown", hide, true);
|
|
1998
|
-
window.addEventListener("scroll", hide, true);
|
|
1999
|
-
return () => {
|
|
2000
|
-
root.removeEventListener("mouseover", over);
|
|
2001
|
-
root.removeEventListener("mouseout", out);
|
|
2002
|
-
window.removeEventListener("keydown", hide, true);
|
|
2003
|
-
window.removeEventListener("pointerdown", hide, true);
|
|
2004
|
-
window.removeEventListener("scroll", hide, true);
|
|
2005
|
-
};
|
|
2006
|
-
}, [root, onFirstHover]);
|
|
2007
|
-
if (!card) return null;
|
|
2008
|
-
const definition = resolve(card.anchor);
|
|
2009
|
-
return createPortal(
|
|
2010
|
-
/* @__PURE__ */ jsx(
|
|
2011
|
-
"div",
|
|
2012
|
-
{
|
|
2013
|
-
role: "tooltip",
|
|
2014
|
-
className: "native-docx-term-card rounded-md border border-border bg-popover p-3 text-sm text-popover-foreground shadow-lg",
|
|
2015
|
-
style: {
|
|
2016
|
-
position: "fixed",
|
|
2017
|
-
left: Math.max(8, Math.min(card.left, window.innerWidth - 348)),
|
|
2018
|
-
top: card.top,
|
|
2019
|
-
width: 340,
|
|
2020
|
-
zIndex: 1e3,
|
|
2021
|
-
pointerEvents: "none"
|
|
2022
|
-
},
|
|
2023
|
-
"data-testid": "docx-defined-term-card",
|
|
2024
|
-
children: definition ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2025
|
-
/* @__PURE__ */ jsx("p", { className: "font-medium", children: definition.term }),
|
|
2026
|
-
/* @__PURE__ */ jsx("p", { className: "mt-1 text-muted-foreground", children: definition.meaning }),
|
|
2027
|
-
sourceOf(definition) && /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: sourceOf(definition) })
|
|
2028
|
-
] }) : /* @__PURE__ */ jsx("p", { children: card.fallback })
|
|
2029
|
-
}
|
|
2030
|
-
),
|
|
2031
|
-
document.body
|
|
2032
|
-
);
|
|
2033
|
-
}
|
|
2034
2179
|
var BUILTIN_TEMPLATE_NAME = "ARBI legal template";
|
|
2035
2180
|
var templateFileName = (t) => /\.(dotx|dotm|docx|docm)$/i.test(t.name) ? t.name : `${t.name}.dotx`;
|
|
2036
2181
|
var builtin;
|
|
@@ -2163,6 +2308,825 @@ function HouseTemplateProvider({
|
|
|
2163
2308
|
);
|
|
2164
2309
|
return /* @__PURE__ */ jsx(HouseTemplateContext.Provider, { value: enabled ? value : null, children });
|
|
2165
2310
|
}
|
|
2311
|
+
|
|
2312
|
+
// src/docx/references/numbering.ts
|
|
2313
|
+
var numbers = (level) => !!level && level.numFmt !== "bullet" && level.numFmt !== "none" && (level.lvlText ?? level.markerText ?? "").length > 0;
|
|
2314
|
+
function paragraphNumber(order, items, levelOf, paragraphId) {
|
|
2315
|
+
const item = items.get(paragraphId);
|
|
2316
|
+
if (!item || !numbers(item)) return null;
|
|
2317
|
+
const at = order.indexOf(paragraphId);
|
|
2318
|
+
const markerAt = (ilvl) => {
|
|
2319
|
+
if (ilvl === item.ilvl) return item.markerText;
|
|
2320
|
+
for (let i = at - 1; i >= 0; i--) {
|
|
2321
|
+
const other = items.get(order[i]);
|
|
2322
|
+
if (other && other.numId === item.numId && other.ilvl === ilvl) return other.markerText;
|
|
2323
|
+
}
|
|
2324
|
+
return null;
|
|
2325
|
+
};
|
|
2326
|
+
const chain = [];
|
|
2327
|
+
const texts = [];
|
|
2328
|
+
for (let u = item.ilvl; u >= 0; u--) {
|
|
2329
|
+
const level = levelOf(item.numId, u);
|
|
2330
|
+
if (!level || !numbers(level)) continue;
|
|
2331
|
+
if (u !== item.ilvl && texts.some((t) => t.includes(`%${u + 1}`))) continue;
|
|
2332
|
+
chain.push(u);
|
|
2333
|
+
texts.push(level.lvlText);
|
|
2334
|
+
}
|
|
2335
|
+
const value = chain.reverse().map((u) => markerAt(u) ?? "").join("");
|
|
2336
|
+
if (!value) return null;
|
|
2337
|
+
return value.length > 1 && value.endsWith(".") ? value.slice(0, -1) : value;
|
|
2338
|
+
}
|
|
2339
|
+
function listTargets(paragraphs, items, levelOf) {
|
|
2340
|
+
const order = paragraphs.map((p) => p.id);
|
|
2341
|
+
const out = [];
|
|
2342
|
+
for (const p of paragraphs) {
|
|
2343
|
+
const text = p.text.replace(//g, "").trim();
|
|
2344
|
+
if (!text) continue;
|
|
2345
|
+
const number = paragraphNumber(order, items, levelOf, p.id);
|
|
2346
|
+
const item = items.get(p.id);
|
|
2347
|
+
if (number !== null)
|
|
2348
|
+
out.push({
|
|
2349
|
+
paragraphId: p.id,
|
|
2350
|
+
kind: "numbered",
|
|
2351
|
+
number,
|
|
2352
|
+
marker: item?.markerText ?? "",
|
|
2353
|
+
text,
|
|
2354
|
+
heading: p.heading,
|
|
2355
|
+
level: item?.ilvl ?? 0
|
|
2356
|
+
});
|
|
2357
|
+
else if (p.heading)
|
|
2358
|
+
out.push({
|
|
2359
|
+
paragraphId: p.id,
|
|
2360
|
+
kind: "heading",
|
|
2361
|
+
number: null,
|
|
2362
|
+
marker: "",
|
|
2363
|
+
text,
|
|
2364
|
+
heading: true,
|
|
2365
|
+
level: 0
|
|
2366
|
+
});
|
|
2367
|
+
}
|
|
2368
|
+
return out;
|
|
2369
|
+
}
|
|
2370
|
+
function filterTargets(targets, query) {
|
|
2371
|
+
const q = query.trim().toLowerCase();
|
|
2372
|
+
if (!q) return [...targets];
|
|
2373
|
+
return targets.filter(
|
|
2374
|
+
(t) => (t.number ?? "").toLowerCase().startsWith(q) || t.text.toLowerCase().includes(q)
|
|
2375
|
+
);
|
|
2376
|
+
}
|
|
2377
|
+
|
|
2378
|
+
// src/docx/references/commands.ts
|
|
2379
|
+
var REF_BOOKMARK_PREFIX = "_Ref";
|
|
2380
|
+
function newRefBookmark(taken, random = Math.random) {
|
|
2381
|
+
for (; ; ) {
|
|
2382
|
+
const name = `${REF_BOOKMARK_PREFIX}${String(Math.floor(random() * 9e8) + 1e8)}`;
|
|
2383
|
+
if (!taken.has(name)) return name;
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
var styled = (style) => style ? `<w:rPr><w:rStyle w:val="${style}"/></w:rPr>` : "";
|
|
2387
|
+
var run = (text, style) => `<w:r>${styled(style)}<w:t xml:space="preserve">${esc(text)}</w:t></w:r>`;
|
|
2388
|
+
function refFieldXml(instruction, cached) {
|
|
2389
|
+
const r = (inner) => `<w:r>${styled(CROSS_REFERENCE_STYLE)}${inner}</w:r>`;
|
|
2390
|
+
return `${r('<w:fldChar w:fldCharType="begin"/>')}${r(
|
|
2391
|
+
`<w:instrText xml:space="preserve"> ${esc(instruction)} </w:instrText>`
|
|
2392
|
+
)}${r('<w:fldChar w:fldCharType="separate"/>')}${run(cached, CROSS_REFERENCE_STYLE)}${r(
|
|
2393
|
+
'<w:fldChar w:fldCharType="end"/>'
|
|
2394
|
+
)}`;
|
|
2395
|
+
}
|
|
2396
|
+
var refTooltip = (value, mode) => mode === "number" ? `Cross-reference to clause ${value}` : `Cross-reference to \u201C${value}\u201D`;
|
|
2397
|
+
function crossReferenceXml(bookmark, mode, value) {
|
|
2398
|
+
return `<w:hyperlink w:anchor="${esc(bookmark)}" w:tooltip="${esc(
|
|
2399
|
+
refTooltip(value, mode)
|
|
2400
|
+
)}" w:history="1">${refFieldXml(refInstruction(bookmark, mode), value)}</w:hyperlink>`;
|
|
2401
|
+
}
|
|
2402
|
+
var refInstruction = (bookmark, mode) => mode === "number" ? `REF ${bookmark} \\r \\h` : `REF ${bookmark} \\h`;
|
|
2403
|
+
var refResult = (target, mode) => mode === "number" && target.number ? target.number : target.text;
|
|
2404
|
+
var allBookmarks = (port) => new Set(port.paragraphs().flatMap((p) => p.bookmarks));
|
|
2405
|
+
function ensureTargetBookmark(port, target, mode) {
|
|
2406
|
+
const paragraph = port.paragraphs().find((p) => p.id === target.paragraphId);
|
|
2407
|
+
if (!paragraph) throw new Error("That clause is no longer in the document.");
|
|
2408
|
+
const existing = paragraph.bookmarks.find((b) => b.startsWith(REF_BOOKMARK_PREFIX));
|
|
2409
|
+
if (existing && mode === "number") return existing;
|
|
2410
|
+
const name = newRefBookmark(allBookmarks(port));
|
|
2411
|
+
const start = `<w:bookmarkStart w:id="0" w:name="${name}"/>`;
|
|
2412
|
+
const end = '<w:bookmarkEnd w:id="0"/>';
|
|
2413
|
+
if (mode === "number") {
|
|
2414
|
+
port.setCaret({ paragraphId: paragraph.id, offset: 0 });
|
|
2415
|
+
if (!port.paste(`<w:p>${start}${end}</w:p>`, "", false))
|
|
2416
|
+
throw new Error("The cross-reference target could not be marked.");
|
|
2417
|
+
return name;
|
|
2418
|
+
}
|
|
2419
|
+
const runs = port.runsXml(paragraph.id);
|
|
2420
|
+
if (!runs) throw new Error("This heading cannot be referred to by its text; use its number.");
|
|
2421
|
+
port.deleteRange(
|
|
2422
|
+
{ paragraphId: paragraph.id, offset: 0 },
|
|
2423
|
+
{ paragraphId: paragraph.id, offset: paragraph.text.length }
|
|
2424
|
+
);
|
|
2425
|
+
if (!port.paste(`<w:p>${start}${runs}${end}</w:p>`, paragraph.text, false))
|
|
2426
|
+
throw new Error("The cross-reference target could not be marked.");
|
|
2427
|
+
return name;
|
|
2428
|
+
}
|
|
2429
|
+
function pastePoint(port, caret) {
|
|
2430
|
+
const paragraph = port.paragraphs().find((p) => p.id === caret.paragraphId);
|
|
2431
|
+
if (paragraph?.text[caret.offset - 1] !== FIELD_ATOM) return caret;
|
|
2432
|
+
port.setCaret(caret);
|
|
2433
|
+
port.typeText(" ");
|
|
2434
|
+
return { paragraphId: caret.paragraphId, offset: caret.offset + 1 };
|
|
2435
|
+
}
|
|
2436
|
+
function markCrossReferenceTarget(port, target, mode) {
|
|
2437
|
+
if (mode === "number" && !target.number) mode = "text";
|
|
2438
|
+
const bookmark = ensureTargetBookmark(port, target, mode);
|
|
2439
|
+
return { bookmark, mode, value: refResult(target, mode) };
|
|
2440
|
+
}
|
|
2441
|
+
function insertCrossReferenceField(port, { bookmark, mode, value }, caret) {
|
|
2442
|
+
caret = pastePoint(port, caret);
|
|
2443
|
+
port.setCaret(caret);
|
|
2444
|
+
if (!port.paste(`<w:p>${crossReferenceXml(bookmark, mode, value)}</w:p>`, value, false))
|
|
2445
|
+
throw new Error("The cross-reference could not be inserted.");
|
|
2446
|
+
port.setCaret({ paragraphId: caret.paragraphId, offset: caret.offset + 1 });
|
|
2447
|
+
return { bookmark };
|
|
2448
|
+
}
|
|
2449
|
+
function insertCrossReference(port, target, mode, caret) {
|
|
2450
|
+
return insertCrossReferenceField(port, markCrossReferenceTarget(port, target, mode), caret);
|
|
2451
|
+
}
|
|
2452
|
+
var documentReferenceTooltip = (text, appName = "ARBI") => `Cross-reference: ${text} \u2014 opens in ${appName}`;
|
|
2453
|
+
function insertDocumentReference(port, reference, caret) {
|
|
2454
|
+
const text = reference.text.trim();
|
|
2455
|
+
if (!text) throw new Error("Enter the reference text.");
|
|
2456
|
+
const tooltip = documentReferenceTooltip(text, reference.appName).slice(0, 255);
|
|
2457
|
+
caret = pastePoint(port, caret);
|
|
2458
|
+
port.setCaret(caret);
|
|
2459
|
+
const link = `<w:p><w:hyperlink r:id="rIdRef1"${tooltip ? ` w:tooltip="${esc(tooltip)}"` : ""} w:history="1">${run(text, CROSS_REFERENCE_STYLE)}</w:hyperlink></w:p>`;
|
|
2460
|
+
if (!port.paste(link, text, false, hyperlinkRelationship("rIdRef1", reference.url)))
|
|
2461
|
+
throw new Error("The reference could not be inserted.");
|
|
2462
|
+
port.setCaret({ paragraphId: caret.paragraphId, offset: caret.offset + text.length });
|
|
2463
|
+
}
|
|
2464
|
+
var REF_FIELD = /^REF\s+(\S+)((?:\s+\\[A-Za-z*]+(?:\s+MERGEFORMAT)?)*)\s*$/i;
|
|
2465
|
+
function staleCrossReferences(port) {
|
|
2466
|
+
const paragraphs = port.paragraphs();
|
|
2467
|
+
if (!paragraphs.some((p) => p.fields?.length)) return [];
|
|
2468
|
+
const items = port.listItems();
|
|
2469
|
+
const order = paragraphs.map((p) => p.id);
|
|
2470
|
+
const owner = /* @__PURE__ */ new Map();
|
|
2471
|
+
for (const p of paragraphs) for (const b of p.bookmarks) if (!owner.has(b)) owner.set(b, p.id);
|
|
2472
|
+
const out = [];
|
|
2473
|
+
for (const p of paragraphs)
|
|
2474
|
+
for (const field of p.fields ?? []) {
|
|
2475
|
+
const match = REF_FIELD.exec(field.instruction);
|
|
2476
|
+
if (!match || !match[1].startsWith(REF_BOOKMARK_PREFIX)) continue;
|
|
2477
|
+
const switches = match[2].toLowerCase();
|
|
2478
|
+
const mode = /\\[rwn]\b/.test(switches) ? "number" : "text";
|
|
2479
|
+
const target = owner.get(match[1]);
|
|
2480
|
+
const base = {
|
|
2481
|
+
paragraphId: p.id,
|
|
2482
|
+
offset: field.offset,
|
|
2483
|
+
instruction: field.instruction,
|
|
2484
|
+
cached: field.result,
|
|
2485
|
+
bookmark: match[1],
|
|
2486
|
+
mode
|
|
2487
|
+
};
|
|
2488
|
+
if (!target) {
|
|
2489
|
+
out.push({ ...base, value: null });
|
|
2490
|
+
continue;
|
|
2491
|
+
}
|
|
2492
|
+
const value = /\\[rwn]\b/.test(switches) ? switches.includes("\\r") ? paragraphNumber(order, items, port.levelOf, target) : null : (paragraphs.find((x) => x.id === target)?.text ?? "").replace(//g, "").trim();
|
|
2493
|
+
if (value && value !== field.result.trim()) out.push({ ...base, value });
|
|
2494
|
+
}
|
|
2495
|
+
return out;
|
|
2496
|
+
}
|
|
2497
|
+
function brokenCrossReferences(port) {
|
|
2498
|
+
return port.paragraphs().flatMap(
|
|
2499
|
+
(p) => (p.marks ?? []).filter((m) => m.styleId === BROKEN_CROSS_REFERENCE_STYLE).map((m) => ({ paragraphId: p.id, offset: m.offset, text: m.text }))
|
|
2500
|
+
);
|
|
2501
|
+
}
|
|
2502
|
+
function refreshCrossReferences(port) {
|
|
2503
|
+
const stale = staleCrossReferences(port).sort(
|
|
2504
|
+
(a, b) => a.paragraphId === b.paragraphId ? b.offset - a.offset : 0
|
|
2505
|
+
);
|
|
2506
|
+
let refreshed = 0;
|
|
2507
|
+
for (const ref of stale) {
|
|
2508
|
+
const paragraph = port.paragraphs().find((p) => p.id === ref.paragraphId);
|
|
2509
|
+
if (!paragraph || paragraph.text[ref.offset - 1] === FIELD_ATOM) continue;
|
|
2510
|
+
const at = { paragraphId: ref.paragraphId, offset: ref.offset };
|
|
2511
|
+
port.deleteRange(at, { paragraphId: ref.paragraphId, offset: ref.offset + 1 });
|
|
2512
|
+
port.setCaret(at);
|
|
2513
|
+
const text = ref.value ?? (ref.cached.trim() || ref.bookmark);
|
|
2514
|
+
const body = ref.value === null ? run(text, BROKEN_CROSS_REFERENCE_STYLE) : crossReferenceXml(ref.bookmark, ref.mode, ref.value);
|
|
2515
|
+
if (port.paste(`<w:p>${body}</w:p>`, text, false) && ref.value !== null) refreshed++;
|
|
2516
|
+
}
|
|
2517
|
+
return { refreshed, broken: brokenCrossReferences(port) };
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
// src/docx/references/passages.ts
|
|
2521
|
+
function shortTitle(title) {
|
|
2522
|
+
const base = title.replace(/\.[A-Za-z0-9]{1,5}$/, "").trim();
|
|
2523
|
+
const defined = /\(\s*(?:the\s+)?["“'‘]([^"”'’]{1,30})["”'’]\s*\)/i.exec(base);
|
|
2524
|
+
return defined ? defined[1] : base;
|
|
2525
|
+
}
|
|
2526
|
+
function passageClause(text) {
|
|
2527
|
+
const first = text.trim().split("\n")[0] ?? "";
|
|
2528
|
+
const match = /^(?:#+\s*)?(?:\*\*)?(?:clause|section|article)?\s*(\d+(?:\.\d+)*)[.)]?(?:\*\*)?\s+\S/i.exec(
|
|
2529
|
+
first
|
|
2530
|
+
);
|
|
2531
|
+
return match ? match[1] : null;
|
|
2532
|
+
}
|
|
2533
|
+
function referenceText(title, passage) {
|
|
2534
|
+
const name = shortTitle(title);
|
|
2535
|
+
const clause = passageClause(passage.text);
|
|
2536
|
+
if (clause) return `${name}, clause ${clause}`;
|
|
2537
|
+
if (passage.page) return `${name}, p. ${passage.page}`;
|
|
2538
|
+
return name;
|
|
2539
|
+
}
|
|
2540
|
+
function passageExcerpt(text, max = 280) {
|
|
2541
|
+
const plain = text.replace(/[#*_`>|]+/g, " ").replace(/\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/\s+/g, " ").trim();
|
|
2542
|
+
return plain.length > max ? `${plain.slice(0, max - 1)}\u2026` : plain;
|
|
2543
|
+
}
|
|
2544
|
+
function filterPassages(passages, query) {
|
|
2545
|
+
const q = query.trim().toLowerCase();
|
|
2546
|
+
return q ? passages.filter((p) => p.text.toLowerCase().includes(q)) : [...passages];
|
|
2547
|
+
}
|
|
2548
|
+
var RUN_PARTS = /* @__PURE__ */ new Set(["rPr", "t", "tab", "br", "lastRenderedPageBreak"]);
|
|
2549
|
+
var SKIPPED = /* @__PURE__ */ new Set(["pPr", "bookmarkStart", "bookmarkEnd", "proofErr", "permStart", "permEnd"]);
|
|
2550
|
+
function serialize(node) {
|
|
2551
|
+
if (node.kind === "textValue") return esc(node.value ?? "");
|
|
2552
|
+
const name = `${node.prefix ?? "w"}:${node.localName}`;
|
|
2553
|
+
const attrs = (node.attributes ?? []).map((a) => ` ${a.prefix ? `${a.prefix}:` : ""}${a.localName}="${esc(a.value)}"`).join("");
|
|
2554
|
+
const children = (node.children ?? []).map((c) => serialize(c)).join("");
|
|
2555
|
+
return children ? `<${name}${attrs}>${children}</${name}>` : `<${name}${attrs}/>`;
|
|
2556
|
+
}
|
|
2557
|
+
function paragraphRunsXml(paragraph) {
|
|
2558
|
+
const runs = [];
|
|
2559
|
+
for (const child of paragraph.children ?? []) {
|
|
2560
|
+
if (child.localName && SKIPPED.has(child.localName)) continue;
|
|
2561
|
+
if (child.localName !== "r") return null;
|
|
2562
|
+
if ((child.children ?? []).some((c) => !c.localName || !RUN_PARTS.has(c.localName))) return null;
|
|
2563
|
+
runs.push(serialize(child));
|
|
2564
|
+
}
|
|
2565
|
+
return runs.length ? runs.join("") : null;
|
|
2566
|
+
}
|
|
2567
|
+
function findNode2(node, id) {
|
|
2568
|
+
if (node.id === id) return node;
|
|
2569
|
+
for (const child of node.children ?? []) {
|
|
2570
|
+
const found = findNode2(child, id);
|
|
2571
|
+
if (found) return found;
|
|
2572
|
+
}
|
|
2573
|
+
return void 0;
|
|
2574
|
+
}
|
|
2575
|
+
function referencesPort(editor, revision) {
|
|
2576
|
+
const base = editorPort(editor, revision);
|
|
2577
|
+
const session = () => {
|
|
2578
|
+
const s = editor.surface?.session;
|
|
2579
|
+
if (!s) throw new Error("The document is not open.");
|
|
2580
|
+
return s;
|
|
2581
|
+
};
|
|
2582
|
+
const root = () => session().part().root;
|
|
2583
|
+
let numbering;
|
|
2584
|
+
let cascade;
|
|
2585
|
+
const index = () => {
|
|
2586
|
+
if (!numbering) {
|
|
2587
|
+
const s = session();
|
|
2588
|
+
cascade = buildStyleCascadeTable(s.stylesRoot(), void 0, s.settingsRoot());
|
|
2589
|
+
numbering = withNumberingStyleLinks(buildNumberingIndex(s.numberingRoot()), cascade);
|
|
2590
|
+
}
|
|
2591
|
+
return numbering;
|
|
2592
|
+
};
|
|
2593
|
+
return {
|
|
2594
|
+
...base,
|
|
2595
|
+
listItems: () => {
|
|
2596
|
+
const body = root().children?.find((n) => n.kind === "body");
|
|
2597
|
+
const items = resolveStoryListItems(
|
|
2598
|
+
body?.children ?? [],
|
|
2599
|
+
index(),
|
|
2600
|
+
cascade
|
|
2601
|
+
);
|
|
2602
|
+
const out = /* @__PURE__ */ new Map();
|
|
2603
|
+
for (const [id, item] of items)
|
|
2604
|
+
out.set(id, {
|
|
2605
|
+
numId: item.numId,
|
|
2606
|
+
ilvl: item.ilvl,
|
|
2607
|
+
markerText: item.markerText,
|
|
2608
|
+
numFmt: item.numFmt
|
|
2609
|
+
});
|
|
2610
|
+
return out;
|
|
2611
|
+
},
|
|
2612
|
+
levelOf: (numId, ilvl) => {
|
|
2613
|
+
const level = resolveNumberingLevel(index(), numId, ilvl)?.level;
|
|
2614
|
+
return level ? { lvlText: level.lvlText, numFmt: level.numFmt } : null;
|
|
2615
|
+
},
|
|
2616
|
+
runsXml: (paragraphId) => {
|
|
2617
|
+
const node = findNode2(root(), paragraphId);
|
|
2618
|
+
return node ? paragraphRunsXml(node) : null;
|
|
2619
|
+
}
|
|
2620
|
+
};
|
|
2621
|
+
}
|
|
2622
|
+
|
|
2623
|
+
// src/docx/beforeSave.ts
|
|
2624
|
+
var hooks = /* @__PURE__ */ new WeakMap();
|
|
2625
|
+
function onBeforeSave(editor, fn) {
|
|
2626
|
+
let set = hooks.get(editor);
|
|
2627
|
+
if (!set) hooks.set(editor, set = /* @__PURE__ */ new Set());
|
|
2628
|
+
set.add(fn);
|
|
2629
|
+
return () => set.delete(fn);
|
|
2630
|
+
}
|
|
2631
|
+
function runBeforeSave(editor) {
|
|
2632
|
+
if (!editor) return;
|
|
2633
|
+
for (const fn of hooks.get(editor) ?? [])
|
|
2634
|
+
try {
|
|
2635
|
+
fn();
|
|
2636
|
+
} catch {
|
|
2637
|
+
}
|
|
2638
|
+
}
|
|
2639
|
+
var DEFAULT_CROSS_REFERENCES_LABELS = {
|
|
2640
|
+
insert: "Insert cross-reference",
|
|
2641
|
+
title: "Insert cross-reference",
|
|
2642
|
+
description: "Refer to a clause of this document, or to a passage of another document.",
|
|
2643
|
+
thisDocument: "This document",
|
|
2644
|
+
otherDocument: "Another document",
|
|
2645
|
+
filterTargets: "Find a clause or heading",
|
|
2646
|
+
noTargets: "This document has no numbered clauses or headings yet.",
|
|
2647
|
+
number: "Paragraph number",
|
|
2648
|
+
text: "Heading text",
|
|
2649
|
+
insertAs: "Insert",
|
|
2650
|
+
chooseDocument: "Choose a document",
|
|
2651
|
+
filterPassages: "Find a passage",
|
|
2652
|
+
loadingPassages: "Loading passages\u2026",
|
|
2653
|
+
noPassages: "No passage matches.",
|
|
2654
|
+
referenceText: "Reference text",
|
|
2655
|
+
insertButton: "Insert",
|
|
2656
|
+
cancel: "Cancel",
|
|
2657
|
+
clause: (number) => `Clause ${number}`,
|
|
2658
|
+
heading: "Heading",
|
|
2659
|
+
update: "Update cross-references",
|
|
2660
|
+
updated: "Cross-references updated",
|
|
2661
|
+
updateSummary: (refreshed) => refreshed ? `${refreshed} cross-reference${refreshed === 1 ? "" : "s"} brought up to date.` : "Every cross-reference is up to date.",
|
|
2662
|
+
brokenTitle: "Broken cross-references",
|
|
2663
|
+
brokenNone: "No cross-reference points at a deleted target.",
|
|
2664
|
+
brokenHelp: "Their target was deleted: the last text is kept and marked. Insert the reference again to repair it.",
|
|
2665
|
+
brokenCard: "Broken cross-reference",
|
|
2666
|
+
brokenCardBody: "Its target was deleted. Update cross-references to mark it.",
|
|
2667
|
+
show: "Show",
|
|
2668
|
+
close: "Close"
|
|
2669
|
+
};
|
|
2670
|
+
var CrossReferencesContext = createContext(null);
|
|
2671
|
+
var useCrossReferences = () => useContext(CrossReferencesContext);
|
|
2672
|
+
function CrossReferencesProvider({
|
|
2673
|
+
children,
|
|
2674
|
+
editable,
|
|
2675
|
+
references,
|
|
2676
|
+
documentId,
|
|
2677
|
+
notify,
|
|
2678
|
+
labels
|
|
2679
|
+
}) {
|
|
2680
|
+
const editor = useDocxEditor();
|
|
2681
|
+
const track = useTrackedOrNoted();
|
|
2682
|
+
const l = useMemo(() => ({ ...DEFAULT_CROSS_REFERENCES_LABELS, ...labels }), [labels]);
|
|
2683
|
+
const [dialog, setDialog] = useState(
|
|
2684
|
+
null
|
|
2685
|
+
);
|
|
2686
|
+
const marker = useRef(null);
|
|
2687
|
+
const [viewer, setViewer] = useState(null);
|
|
2688
|
+
useEffect(() => setViewer(marker.current?.closest(".native-docx-viewer") ?? null), []);
|
|
2689
|
+
const openDialog = useCallback(() => {
|
|
2690
|
+
if (!editor || !editable) return;
|
|
2691
|
+
try {
|
|
2692
|
+
const port = referencesPort(editor);
|
|
2693
|
+
const caret = port.caret();
|
|
2694
|
+
if (!caret) return notify?.("Place the cursor where the reference should go.", "error");
|
|
2695
|
+
setDialog({ caret, targets: listTargets(port.paragraphs(), port.listItems(), port.levelOf) });
|
|
2696
|
+
} catch (error) {
|
|
2697
|
+
notify?.(error instanceof Error ? error.message : "Could not read the document.", "error");
|
|
2698
|
+
}
|
|
2699
|
+
}, [editor, editable, notify]);
|
|
2700
|
+
const run2 = useCallback(
|
|
2701
|
+
(label, prepare, insert) => {
|
|
2702
|
+
if (!editor) return;
|
|
2703
|
+
try {
|
|
2704
|
+
const prepared = withDirectEditing(editor, prepare);
|
|
2705
|
+
if (dialog) referencesPort(editor).setCaret(dialog.caret);
|
|
2706
|
+
track({ label, insert: (revision) => insert(prepared, revision), inserted: () => true });
|
|
2707
|
+
setDialog(null);
|
|
2708
|
+
editor.surface?.focus();
|
|
2709
|
+
holdCaret(editor);
|
|
2710
|
+
} catch (error) {
|
|
2711
|
+
notify?.(
|
|
2712
|
+
error instanceof Error ? error.message : "Could not insert the reference.",
|
|
2713
|
+
"error"
|
|
2714
|
+
);
|
|
2715
|
+
}
|
|
2716
|
+
},
|
|
2717
|
+
[editor, dialog, track, notify]
|
|
2718
|
+
);
|
|
2719
|
+
useEffect(() => {
|
|
2720
|
+
if (!editor || !editable) return;
|
|
2721
|
+
const refresh = () => {
|
|
2722
|
+
try {
|
|
2723
|
+
const port = referencesPort(editor);
|
|
2724
|
+
if (!port.paragraphs().some((p) => p.fields?.length)) return;
|
|
2725
|
+
preservingCaret(editor, () => withDirectEditing(editor, () => refreshCrossReferences(port)));
|
|
2726
|
+
} catch {
|
|
2727
|
+
}
|
|
2728
|
+
};
|
|
2729
|
+
const off = onBeforeSave(editor, refresh);
|
|
2730
|
+
const timer = setTimeout(refresh, 1500);
|
|
2731
|
+
return () => {
|
|
2732
|
+
off();
|
|
2733
|
+
clearTimeout(timer);
|
|
2734
|
+
};
|
|
2735
|
+
}, [editor, editable]);
|
|
2736
|
+
const [report, setReport] = useState(null);
|
|
2737
|
+
const update = useCallback(() => {
|
|
2738
|
+
if (!editor || !editable) return;
|
|
2739
|
+
try {
|
|
2740
|
+
const result = preservingCaret(
|
|
2741
|
+
editor,
|
|
2742
|
+
() => withDirectEditing(editor, () => refreshCrossReferences(referencesPort(editor)))
|
|
2743
|
+
);
|
|
2744
|
+
setReport(result);
|
|
2745
|
+
} catch (error) {
|
|
2746
|
+
notify?.(
|
|
2747
|
+
error instanceof Error ? error.message : "Could not update cross-references.",
|
|
2748
|
+
"error"
|
|
2749
|
+
);
|
|
2750
|
+
}
|
|
2751
|
+
}, [editor, editable, notify]);
|
|
2752
|
+
const [passages, setPassages] = useState({});
|
|
2753
|
+
const loadPassages = useCallback(
|
|
2754
|
+
(id) => {
|
|
2755
|
+
if (!references || passages[id]) return;
|
|
2756
|
+
setPassages((p) => ({ ...p, [id]: "loading" }));
|
|
2757
|
+
references.passages(id).then((list) => setPassages((p) => ({ ...p, [id]: list }))).catch(() => setPassages((p) => ({ ...p, [id]: [] })));
|
|
2758
|
+
},
|
|
2759
|
+
[references, passages]
|
|
2760
|
+
);
|
|
2761
|
+
useEffect(() => {
|
|
2762
|
+
if (!viewer || !references) return;
|
|
2763
|
+
const targetOf = (event) => {
|
|
2764
|
+
const link = event.target?.closest?.(
|
|
2765
|
+
'a.docx-hyperlink[data-docx-link-kind="external"]'
|
|
2766
|
+
);
|
|
2767
|
+
if (!link || !viewer.contains(link)) return null;
|
|
2768
|
+
const mouse = event;
|
|
2769
|
+
if (mouse.button !== 0 || mouse.ctrlKey || mouse.metaKey || mouse.shiftKey) return null;
|
|
2770
|
+
return references.targetOf(link.getAttribute("href") ?? "");
|
|
2771
|
+
};
|
|
2772
|
+
const take = (event) => {
|
|
2773
|
+
const target = targetOf(event);
|
|
2774
|
+
if (!target) return;
|
|
2775
|
+
event.preventDefault();
|
|
2776
|
+
event.stopPropagation();
|
|
2777
|
+
if (event.type === "click") references.open(target);
|
|
2778
|
+
};
|
|
2779
|
+
const types = ["pointerdown", "mousedown", "pointerup", "mouseup", "click"];
|
|
2780
|
+
for (const type of types) window.addEventListener(type, take, true);
|
|
2781
|
+
return () => {
|
|
2782
|
+
for (const type of types) window.removeEventListener(type, take, true);
|
|
2783
|
+
};
|
|
2784
|
+
}, [viewer, references]);
|
|
2785
|
+
const value = useMemo(
|
|
2786
|
+
() => editable ? { openDialog, update, labels: l } : null,
|
|
2787
|
+
[editable, openDialog, update, l]
|
|
2788
|
+
);
|
|
2789
|
+
const resolveInternal = (href) => {
|
|
2790
|
+
if (!editor) return null;
|
|
2791
|
+
const name = href.replace(/^#/, "");
|
|
2792
|
+
try {
|
|
2793
|
+
const port = referencesPort(editor);
|
|
2794
|
+
const paragraphs = port.paragraphs();
|
|
2795
|
+
const target = paragraphs.find((p) => p.bookmarks.includes(name));
|
|
2796
|
+
if (!target) return { title: l.brokenCard, body: l.brokenCardBody };
|
|
2797
|
+
const number = paragraphNumber(
|
|
2798
|
+
paragraphs.map((p) => p.id),
|
|
2799
|
+
port.listItems(),
|
|
2800
|
+
port.levelOf,
|
|
2801
|
+
target.id
|
|
2802
|
+
);
|
|
2803
|
+
return {
|
|
2804
|
+
title: number ? l.clause(number) : l.heading,
|
|
2805
|
+
body: passageExcerpt(target.text.replace(//g, ""))
|
|
2806
|
+
};
|
|
2807
|
+
} catch {
|
|
2808
|
+
return null;
|
|
2809
|
+
}
|
|
2810
|
+
};
|
|
2811
|
+
return /* @__PURE__ */ jsxs(CrossReferencesContext.Provider, { value, children: [
|
|
2812
|
+
/* @__PURE__ */ jsx("span", { ref: marker, hidden: true }),
|
|
2813
|
+
children,
|
|
2814
|
+
/* @__PURE__ */ jsx(
|
|
2815
|
+
LinkHoverCard,
|
|
2816
|
+
{
|
|
2817
|
+
root: viewer,
|
|
2818
|
+
matches: (href) => href.startsWith(`#${REF_BOOKMARK_PREFIX}`),
|
|
2819
|
+
resolve: resolveInternal,
|
|
2820
|
+
testId: "docx-cross-reference-card"
|
|
2821
|
+
}
|
|
2822
|
+
),
|
|
2823
|
+
references && /* @__PURE__ */ jsx(
|
|
2824
|
+
LinkHoverCard,
|
|
2825
|
+
{
|
|
2826
|
+
root: viewer,
|
|
2827
|
+
matches: (href) => !!references.targetOf(href),
|
|
2828
|
+
resolve: (href) => {
|
|
2829
|
+
const target = references.targetOf(href);
|
|
2830
|
+
if (!target) return null;
|
|
2831
|
+
const list = passages[target.documentId];
|
|
2832
|
+
if (!list) loadPassages(target.documentId);
|
|
2833
|
+
const passage = Array.isArray(list) ? list.find((p) => p.chunkId === target.chunkId) : void 0;
|
|
2834
|
+
return passage ? {
|
|
2835
|
+
body: passageExcerpt(passage.text),
|
|
2836
|
+
footer: passage.page ? `p. ${passage.page}` : void 0
|
|
2837
|
+
} : null;
|
|
2838
|
+
},
|
|
2839
|
+
testId: "docx-cross-reference-card"
|
|
2840
|
+
}
|
|
2841
|
+
),
|
|
2842
|
+
dialog && /* @__PURE__ */ jsx(
|
|
2843
|
+
CrossReferenceDialog,
|
|
2844
|
+
{
|
|
2845
|
+
targets: dialog.targets,
|
|
2846
|
+
references,
|
|
2847
|
+
documentId,
|
|
2848
|
+
passages,
|
|
2849
|
+
loadPassages,
|
|
2850
|
+
labels: l,
|
|
2851
|
+
onCancel: () => setDialog(null),
|
|
2852
|
+
onClosed: () => editor?.surface?.focus(),
|
|
2853
|
+
onInsertTarget: (target, mode) => run2(
|
|
2854
|
+
`Inserted cross-reference: ${refResult(target, mode)}`,
|
|
2855
|
+
() => markCrossReferenceTarget(referencesPort(editor), target, mode),
|
|
2856
|
+
(marked, revision) => insertCrossReferenceField(referencesPort(editor, revision), marked, dialog.caret)
|
|
2857
|
+
),
|
|
2858
|
+
onInsertPassage: (target, text) => run2(
|
|
2859
|
+
`Inserted cross-reference: ${text}`,
|
|
2860
|
+
() => void 0,
|
|
2861
|
+
(_, revision) => insertDocumentReference(
|
|
2862
|
+
referencesPort(editor, revision),
|
|
2863
|
+
{ text, url: references.linkFor(target), appName: references.appName },
|
|
2864
|
+
dialog.caret
|
|
2865
|
+
)
|
|
2866
|
+
)
|
|
2867
|
+
}
|
|
2868
|
+
),
|
|
2869
|
+
/* @__PURE__ */ jsx(Dialog, { open: !!report, onOpenChange: (open) => !open && setReport(null), children: /* @__PURE__ */ jsxs(
|
|
2870
|
+
DialogContent,
|
|
2871
|
+
{
|
|
2872
|
+
className: "max-h-[85dvh] overflow-y-auto",
|
|
2873
|
+
"data-testid": "docx-cross-references-report",
|
|
2874
|
+
children: [
|
|
2875
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
2876
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: l.updated }),
|
|
2877
|
+
/* @__PURE__ */ jsx(DialogDescription, { children: report && l.updateSummary(report.refreshed) })
|
|
2878
|
+
] }),
|
|
2879
|
+
report && /* @__PURE__ */ jsxs("section", { className: "space-y-1 text-sm", children: [
|
|
2880
|
+
/* @__PURE__ */ jsx("h3", { className: "font-medium", children: l.brokenTitle }),
|
|
2881
|
+
report.broken.length ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2882
|
+
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: l.brokenHelp }),
|
|
2883
|
+
/* @__PURE__ */ jsx("ul", { className: "space-y-1", "data-testid": "docx-cross-references-broken", children: report.broken.map((b) => /* @__PURE__ */ jsxs(
|
|
2884
|
+
"li",
|
|
2885
|
+
{
|
|
2886
|
+
className: "flex items-center justify-between gap-2",
|
|
2887
|
+
children: [
|
|
2888
|
+
/* @__PURE__ */ jsx("span", { className: "text-red-text", children: b.text }),
|
|
2889
|
+
/* @__PURE__ */ jsx(
|
|
2890
|
+
Button,
|
|
2891
|
+
{
|
|
2892
|
+
size: "sm",
|
|
2893
|
+
variant: "ghost",
|
|
2894
|
+
onClick: () => {
|
|
2895
|
+
const point = { paragraphId: b.paragraphId, offset: b.offset };
|
|
2896
|
+
editor?.surface?.setSelection({ anchor: point, head: point });
|
|
2897
|
+
editor?.surface?.revealParagraph(b.paragraphId);
|
|
2898
|
+
setReport(null);
|
|
2899
|
+
},
|
|
2900
|
+
children: l.show
|
|
2901
|
+
}
|
|
2902
|
+
)
|
|
2903
|
+
]
|
|
2904
|
+
},
|
|
2905
|
+
`${b.paragraphId}:${b.offset}`
|
|
2906
|
+
)) })
|
|
2907
|
+
] }) : /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: l.brokenNone })
|
|
2908
|
+
] }),
|
|
2909
|
+
/* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => setReport(null), children: l.close }) })
|
|
2910
|
+
]
|
|
2911
|
+
}
|
|
2912
|
+
) })
|
|
2913
|
+
] });
|
|
2914
|
+
}
|
|
2915
|
+
function CrossReferenceDialog({
|
|
2916
|
+
targets,
|
|
2917
|
+
references,
|
|
2918
|
+
documentId,
|
|
2919
|
+
passages,
|
|
2920
|
+
loadPassages,
|
|
2921
|
+
labels,
|
|
2922
|
+
onCancel,
|
|
2923
|
+
onInsertTarget,
|
|
2924
|
+
onInsertPassage,
|
|
2925
|
+
onClosed
|
|
2926
|
+
}) {
|
|
2927
|
+
const l = { ...DEFAULT_CROSS_REFERENCES_LABELS, ...labels };
|
|
2928
|
+
const [tab, setTab] = useState("this");
|
|
2929
|
+
const [query, setQuery] = useState("");
|
|
2930
|
+
const [chosen, setChosen] = useState(null);
|
|
2931
|
+
const [mode, setMode] = useState("number");
|
|
2932
|
+
const shown = useMemo(() => filterTargets(targets, query), [targets, query]);
|
|
2933
|
+
const effectiveMode = chosen?.number ? mode : "text";
|
|
2934
|
+
const [documents, setDocuments] = useState(null);
|
|
2935
|
+
const [docId, setDocId] = useState(null);
|
|
2936
|
+
const [passageQuery, setPassageQuery] = useState("");
|
|
2937
|
+
const [passage, setPassage] = useState(null);
|
|
2938
|
+
const [text, setText] = useState("");
|
|
2939
|
+
useEffect(() => {
|
|
2940
|
+
if (tab !== "other" || !references || documents) return;
|
|
2941
|
+
references.documents().then((list2) => setDocuments(list2.filter((d) => d.id !== documentId))).catch(() => setDocuments([]));
|
|
2942
|
+
}, [tab, references, documents, documentId]);
|
|
2943
|
+
const chooseDocument = (id) => {
|
|
2944
|
+
setDocId(id);
|
|
2945
|
+
setPassage(null);
|
|
2946
|
+
setText("");
|
|
2947
|
+
loadPassages(id);
|
|
2948
|
+
};
|
|
2949
|
+
const title = documents?.find((d) => d.id === docId)?.title ?? "";
|
|
2950
|
+
const list = docId ? passages[docId] : void 0;
|
|
2951
|
+
const shownPassages = Array.isArray(list) ? filterPassages(list, passageQuery) : [];
|
|
2952
|
+
const canInsert = tab === "this" ? !!chosen : !!(docId && passage && text.trim());
|
|
2953
|
+
const insert = () => {
|
|
2954
|
+
if (tab === "this" && chosen) onInsertTarget(chosen, effectiveMode);
|
|
2955
|
+
if (tab === "other" && docId && passage)
|
|
2956
|
+
onInsertPassage(
|
|
2957
|
+
{ documentId: docId, chunkId: passage.chunkId, page: passage.page ?? null },
|
|
2958
|
+
text
|
|
2959
|
+
);
|
|
2960
|
+
};
|
|
2961
|
+
return /* @__PURE__ */ jsx(Dialog, { open: true, onOpenChange: (open) => !open && onCancel(), children: /* @__PURE__ */ jsxs(
|
|
2962
|
+
DialogContent,
|
|
2963
|
+
{
|
|
2964
|
+
className: "max-h-[85dvh] overflow-y-auto",
|
|
2965
|
+
"data-testid": "docx-cross-reference-dialog",
|
|
2966
|
+
onCloseAutoFocus: (event) => {
|
|
2967
|
+
if (!onClosed) return;
|
|
2968
|
+
event.preventDefault();
|
|
2969
|
+
onClosed();
|
|
2970
|
+
},
|
|
2971
|
+
children: [
|
|
2972
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
2973
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: l.title }),
|
|
2974
|
+
/* @__PURE__ */ jsx(DialogDescription, { children: l.description })
|
|
2975
|
+
] }),
|
|
2976
|
+
/* @__PURE__ */ jsxs(Tabs, { value: tab, onValueChange: (v) => setTab(v), children: [
|
|
2977
|
+
/* @__PURE__ */ jsxs(TabsList, { children: [
|
|
2978
|
+
/* @__PURE__ */ jsx(TabsTrigger, { value: "this", "data-testid": "docx-cross-reference-this", children: l.thisDocument }),
|
|
2979
|
+
references && /* @__PURE__ */ jsx(TabsTrigger, { value: "other", "data-testid": "docx-cross-reference-other", children: l.otherDocument })
|
|
2980
|
+
] }),
|
|
2981
|
+
/* @__PURE__ */ jsxs(TabsContent, { value: "this", className: "space-y-3", children: [
|
|
2982
|
+
/* @__PURE__ */ jsx(
|
|
2983
|
+
Input,
|
|
2984
|
+
{
|
|
2985
|
+
value: query,
|
|
2986
|
+
placeholder: l.filterTargets,
|
|
2987
|
+
"aria-label": l.filterTargets,
|
|
2988
|
+
onChange: (e) => setQuery(e.target.value),
|
|
2989
|
+
"data-testid": "docx-cross-reference-filter"
|
|
2990
|
+
}
|
|
2991
|
+
),
|
|
2992
|
+
/* @__PURE__ */ jsxs(
|
|
2993
|
+
"div",
|
|
2994
|
+
{
|
|
2995
|
+
role: "listbox",
|
|
2996
|
+
"aria-label": l.filterTargets,
|
|
2997
|
+
className: "max-h-64 space-y-0.5 overflow-y-auto rounded-md border border-border p-1",
|
|
2998
|
+
children: [
|
|
2999
|
+
shown.length === 0 && /* @__PURE__ */ jsx("p", { className: "p-2 text-sm text-muted-foreground", children: l.noTargets }),
|
|
3000
|
+
shown.map((t) => /* @__PURE__ */ jsxs(
|
|
3001
|
+
"button",
|
|
3002
|
+
{
|
|
3003
|
+
type: "button",
|
|
3004
|
+
role: "option",
|
|
3005
|
+
"aria-selected": chosen?.paragraphId === t.paragraphId,
|
|
3006
|
+
"data-testid": "docx-cross-reference-target",
|
|
3007
|
+
onClick: () => setChosen(t),
|
|
3008
|
+
onDoubleClick: () => onInsertTarget(t, t.number ? mode : "text"),
|
|
3009
|
+
className: cn(
|
|
3010
|
+
"flex w-full items-baseline gap-2 rounded px-2 py-1 text-left text-sm",
|
|
3011
|
+
chosen?.paragraphId === t.paragraphId ? "bg-accent" : "hover:bg-accent/50"
|
|
3012
|
+
),
|
|
3013
|
+
style: { paddingLeft: 8 + t.level * 16 },
|
|
3014
|
+
children: [
|
|
3015
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 font-mono text-xs text-muted-foreground", children: t.marker || l.heading }),
|
|
3016
|
+
/* @__PURE__ */ jsx("span", { className: cn("truncate", t.heading && "font-medium"), children: t.text })
|
|
3017
|
+
]
|
|
3018
|
+
},
|
|
3019
|
+
t.paragraphId
|
|
3020
|
+
))
|
|
3021
|
+
]
|
|
3022
|
+
}
|
|
3023
|
+
),
|
|
3024
|
+
chosen && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3 text-sm", children: [
|
|
3025
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: l.insertAs }),
|
|
3026
|
+
chosen.number && /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-1", children: [
|
|
3027
|
+
/* @__PURE__ */ jsx(
|
|
3028
|
+
"input",
|
|
3029
|
+
{
|
|
3030
|
+
type: "radio",
|
|
3031
|
+
name: "cross-reference-mode",
|
|
3032
|
+
checked: effectiveMode === "number",
|
|
3033
|
+
onChange: () => setMode("number")
|
|
3034
|
+
}
|
|
3035
|
+
),
|
|
3036
|
+
l.number
|
|
3037
|
+
] }),
|
|
3038
|
+
/* @__PURE__ */ jsxs("label", { className: "flex items-center gap-1", children: [
|
|
3039
|
+
/* @__PURE__ */ jsx(
|
|
3040
|
+
"input",
|
|
3041
|
+
{
|
|
3042
|
+
type: "radio",
|
|
3043
|
+
name: "cross-reference-mode",
|
|
3044
|
+
checked: effectiveMode === "text",
|
|
3045
|
+
onChange: () => setMode("text")
|
|
3046
|
+
}
|
|
3047
|
+
),
|
|
3048
|
+
l.text
|
|
3049
|
+
] }),
|
|
3050
|
+
/* @__PURE__ */ jsx(
|
|
3051
|
+
"span",
|
|
3052
|
+
{
|
|
3053
|
+
className: "ml-auto rounded bg-muted px-2 py-0.5",
|
|
3054
|
+
"data-testid": "docx-cross-reference-preview",
|
|
3055
|
+
children: refResult(chosen, effectiveMode)
|
|
3056
|
+
}
|
|
3057
|
+
)
|
|
3058
|
+
] })
|
|
3059
|
+
] }),
|
|
3060
|
+
references && /* @__PURE__ */ jsxs(TabsContent, { value: "other", className: "space-y-3", children: [
|
|
3061
|
+
references.renderDocumentPicker ? references.renderDocumentPicker(chooseDocument, docId) : /* @__PURE__ */ jsxs(
|
|
3062
|
+
"select",
|
|
3063
|
+
{
|
|
3064
|
+
className: "h-9 w-full rounded-md border border-border bg-background px-2 text-sm",
|
|
3065
|
+
"aria-label": l.chooseDocument,
|
|
3066
|
+
value: docId ?? "",
|
|
3067
|
+
onChange: (e) => e.target.value && chooseDocument(e.target.value),
|
|
3068
|
+
"data-testid": "docx-cross-reference-document",
|
|
3069
|
+
children: [
|
|
3070
|
+
/* @__PURE__ */ jsx("option", { value: "", children: l.chooseDocument }),
|
|
3071
|
+
(documents ?? []).map((d) => /* @__PURE__ */ jsx("option", { value: d.id, children: d.title }, d.id))
|
|
3072
|
+
]
|
|
3073
|
+
}
|
|
3074
|
+
),
|
|
3075
|
+
docId && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3076
|
+
/* @__PURE__ */ jsx(
|
|
3077
|
+
Input,
|
|
3078
|
+
{
|
|
3079
|
+
value: passageQuery,
|
|
3080
|
+
placeholder: l.filterPassages,
|
|
3081
|
+
"aria-label": l.filterPassages,
|
|
3082
|
+
onChange: (e) => setPassageQuery(e.target.value),
|
|
3083
|
+
"data-testid": "docx-cross-reference-passage-filter"
|
|
3084
|
+
}
|
|
3085
|
+
),
|
|
3086
|
+
/* @__PURE__ */ jsx(
|
|
3087
|
+
"div",
|
|
3088
|
+
{
|
|
3089
|
+
className: "max-h-64 space-y-1 overflow-y-auto",
|
|
3090
|
+
"data-testid": "docx-cross-reference-passages",
|
|
3091
|
+
children: list === "loading" || list === void 0 ? /* @__PURE__ */ jsx("p", { className: "p-2 text-sm text-muted-foreground", children: l.loadingPassages }) : shownPassages.length === 0 ? /* @__PURE__ */ jsx("p", { className: "p-2 text-sm text-muted-foreground", children: l.noPassages }) : shownPassages.map((p, i) => /* @__PURE__ */ jsx(
|
|
3092
|
+
FactPassageItem,
|
|
3093
|
+
{
|
|
3094
|
+
index: i,
|
|
3095
|
+
page: p.page,
|
|
3096
|
+
excerpt: passageExcerpt(p.text, 200),
|
|
3097
|
+
isViewing: passage?.chunkId === p.chunkId,
|
|
3098
|
+
onSelect: () => {
|
|
3099
|
+
setPassage(p);
|
|
3100
|
+
setText(referenceText(title, p));
|
|
3101
|
+
},
|
|
3102
|
+
testId: "docx-cross-reference-passage"
|
|
3103
|
+
},
|
|
3104
|
+
p.chunkId
|
|
3105
|
+
))
|
|
3106
|
+
}
|
|
3107
|
+
),
|
|
3108
|
+
passage && /* @__PURE__ */ jsxs("label", { className: "block space-y-1 text-sm", children: [
|
|
3109
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: l.referenceText }),
|
|
3110
|
+
/* @__PURE__ */ jsx(
|
|
3111
|
+
Input,
|
|
3112
|
+
{
|
|
3113
|
+
value: text,
|
|
3114
|
+
onChange: (e) => setText(e.target.value),
|
|
3115
|
+
"data-testid": "docx-cross-reference-text"
|
|
3116
|
+
}
|
|
3117
|
+
)
|
|
3118
|
+
] })
|
|
3119
|
+
] })
|
|
3120
|
+
] })
|
|
3121
|
+
] }),
|
|
3122
|
+
/* @__PURE__ */ jsxs(DialogFooter, { children: [
|
|
3123
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", onClick: onCancel, children: l.cancel }),
|
|
3124
|
+
/* @__PURE__ */ jsx(Button, { disabled: !canInsert, onClick: insert, "data-testid": "docx-cross-reference-insert", children: l.insertButton })
|
|
3125
|
+
] })
|
|
3126
|
+
]
|
|
3127
|
+
}
|
|
3128
|
+
) });
|
|
3129
|
+
}
|
|
2166
3130
|
function RibbonMenu({
|
|
2167
3131
|
label,
|
|
2168
3132
|
icon,
|
|
@@ -2301,7 +3265,7 @@ function GenerateImageButton({ generation }) {
|
|
|
2301
3265
|
});
|
|
2302
3266
|
const editable = useEditorState((snapshot) => snapshot.editable);
|
|
2303
3267
|
const generating = useSyncExternalStore(subscribe, () => running > 0);
|
|
2304
|
-
async function
|
|
3268
|
+
async function run2() {
|
|
2305
3269
|
if (!editor || !prompt.trim() || busy) return;
|
|
2306
3270
|
const caret = rememberCaret(editor);
|
|
2307
3271
|
const controller = new AbortController();
|
|
@@ -2347,7 +3311,7 @@ function GenerateImageButton({ generation }) {
|
|
|
2347
3311
|
className: "native-docx-form native-docx-generate-image",
|
|
2348
3312
|
onSubmit: (event) => {
|
|
2349
3313
|
event.preventDefault();
|
|
2350
|
-
void
|
|
3314
|
+
void run2();
|
|
2351
3315
|
},
|
|
2352
3316
|
children: [
|
|
2353
3317
|
/* @__PURE__ */ jsxs("label", { children: [
|
|
@@ -2363,7 +3327,7 @@ function GenerateImageButton({ generation }) {
|
|
|
2363
3327
|
"data-testid": "docx-generate-image-prompt",
|
|
2364
3328
|
onChange: (event) => setPrompt(event.target.value),
|
|
2365
3329
|
onKeyDown: (event) => {
|
|
2366
|
-
if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) void
|
|
3330
|
+
if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) void run2();
|
|
2367
3331
|
}
|
|
2368
3332
|
}
|
|
2369
3333
|
)
|
|
@@ -3003,6 +3967,65 @@ function WordShortcuts({ scope }) {
|
|
|
3003
3967
|
}, [scope]);
|
|
3004
3968
|
return null;
|
|
3005
3969
|
}
|
|
3970
|
+
function CrossReferenceButton() {
|
|
3971
|
+
const references = useCrossReferences();
|
|
3972
|
+
if (!references) return null;
|
|
3973
|
+
return /* @__PURE__ */ jsx(
|
|
3974
|
+
"button",
|
|
3975
|
+
{
|
|
3976
|
+
type: "button",
|
|
3977
|
+
className: "native-docx-ribbon-trigger",
|
|
3978
|
+
"aria-label": references.labels.insert,
|
|
3979
|
+
title: references.labels.insert,
|
|
3980
|
+
"data-testid": "docx-insert-cross-reference",
|
|
3981
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
3982
|
+
onClick: () => references.openDialog(),
|
|
3983
|
+
children: /* @__PURE__ */ jsx(Link2, { size: 16 })
|
|
3984
|
+
}
|
|
3985
|
+
);
|
|
3986
|
+
}
|
|
3987
|
+
function UpdateCrossReferencesButton() {
|
|
3988
|
+
const references = useCrossReferences();
|
|
3989
|
+
if (!references) return null;
|
|
3990
|
+
return /* @__PURE__ */ jsx(
|
|
3991
|
+
"button",
|
|
3992
|
+
{
|
|
3993
|
+
type: "button",
|
|
3994
|
+
className: "native-docx-ribbon-trigger",
|
|
3995
|
+
"aria-label": references.labels.update,
|
|
3996
|
+
title: references.labels.update,
|
|
3997
|
+
"data-testid": "docx-update-cross-references",
|
|
3998
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
3999
|
+
onClick: () => references.update(),
|
|
4000
|
+
children: /* @__PURE__ */ jsx(RefreshCcw, { size: 16 })
|
|
4001
|
+
}
|
|
4002
|
+
);
|
|
4003
|
+
}
|
|
4004
|
+
function DocxContextMenuExtras() {
|
|
4005
|
+
const terms = useDefinedTerms();
|
|
4006
|
+
const references = useCrossReferences();
|
|
4007
|
+
if (!terms && !references) return null;
|
|
4008
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4009
|
+
/* @__PURE__ */ jsx(DocxEditor.ContextMenu.Separator, {}),
|
|
4010
|
+
terms && /* @__PURE__ */ jsx(
|
|
4011
|
+
DocxEditor.ContextMenu.Item,
|
|
4012
|
+
{
|
|
4013
|
+
label: "Insert defined term",
|
|
4014
|
+
icon: /* @__PURE__ */ jsx(BookA, { size: 14 }),
|
|
4015
|
+
shortcut: "@@",
|
|
4016
|
+
onSelect: () => terms.openPicker()
|
|
4017
|
+
}
|
|
4018
|
+
),
|
|
4019
|
+
references && /* @__PURE__ */ jsx(
|
|
4020
|
+
DocxEditor.ContextMenu.Item,
|
|
4021
|
+
{
|
|
4022
|
+
label: references.labels.insert,
|
|
4023
|
+
icon: /* @__PURE__ */ jsx(Link2, { size: 14 }),
|
|
4024
|
+
onSelect: () => references.openDialog()
|
|
4025
|
+
}
|
|
4026
|
+
)
|
|
4027
|
+
] });
|
|
4028
|
+
}
|
|
3006
4029
|
|
|
3007
4030
|
// src/docx/layout/presets.ts
|
|
3008
4031
|
var TWIPS_PER_INCH = 1440;
|
|
@@ -3437,9 +4460,9 @@ function countSeqFields(root, label, throughId) {
|
|
|
3437
4460
|
return count;
|
|
3438
4461
|
}
|
|
3439
4462
|
function captionParagraphXml(label, number, text) {
|
|
3440
|
-
const
|
|
4463
|
+
const run2 = (value) => `<w:r><w:t xml:space="preserve">${esc(value)}</w:t></w:r>`;
|
|
3441
4464
|
const rest = text.trim() ? `: ${text.trim()}` : "";
|
|
3442
|
-
return `<w:p><w:pPr><w:pStyle w:val="Caption"/></w:pPr>${
|
|
4465
|
+
return `<w:p><w:pPr><w:pStyle w:val="Caption"/></w:pPr>${run2(`${label} `)}<w:fldSimple w:instr=" SEQ ${esc(label)} \\* ARABIC "><w:r><w:t>${number}</w:t></w:r></w:fldSimple>${rest ? run2(rest) : ""}</w:p>`;
|
|
3443
4466
|
}
|
|
3444
4467
|
function base642(bytes) {
|
|
3445
4468
|
let binary = "";
|
|
@@ -3791,7 +4814,7 @@ function covered(room, vector, receipt) {
|
|
|
3791
4814
|
}
|
|
3792
4815
|
return true;
|
|
3793
4816
|
}
|
|
3794
|
-
var EditorBoundary = class extends
|
|
4817
|
+
var EditorBoundary = class extends React4.Component {
|
|
3795
4818
|
state = {};
|
|
3796
4819
|
static getDerivedStateFromError(error) {
|
|
3797
4820
|
return { error };
|
|
@@ -3883,11 +4906,16 @@ function DocxRibbon({
|
|
|
3883
4906
|
/* @__PURE__ */ jsx(RibbonItem, { id: "insert-page-break", label: "Page break", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Button, { slotId: "insert.pageBreak" }) }),
|
|
3884
4907
|
/* @__PURE__ */ jsx(RibbonItem, { id: "insert-link", label: "Link", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Link, {}) }),
|
|
3885
4908
|
/* @__PURE__ */ jsx(RibbonItem, { id: "insert-defined-term", label: "Defined term", children: /* @__PURE__ */ jsx(DefinedTermButtons, {}) }),
|
|
3886
|
-
/* @__PURE__ */ jsx(RibbonItem, { id: "insert-quick-parts", label: "Quick Parts", children: /* @__PURE__ */ jsx(QuickParts, {}) })
|
|
4909
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "insert-quick-parts", label: "Quick Parts", children: /* @__PURE__ */ jsx(QuickParts, {}) }),
|
|
4910
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "insert-cross-reference", label: "Cross-reference", children: /* @__PURE__ */ jsx(CrossReferenceButton, {}) })
|
|
3887
4911
|
] }),
|
|
3888
4912
|
/* @__PURE__ */ jsx(LayoutTabContent, { tab }),
|
|
3889
4913
|
tab === "Design" && /* @__PURE__ */ jsx(RibbonItem, { id: "design-house-template", label: "House template", children: /* @__PURE__ */ jsx(HouseTemplatePanel, {}) }),
|
|
3890
|
-
tab === "References" && /* @__PURE__ */
|
|
4914
|
+
tab === "References" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4915
|
+
/* @__PURE__ */ jsx(NoteButtons, {}),
|
|
4916
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "references-cross-reference", label: "Cross-reference", children: /* @__PURE__ */ jsx(CrossReferenceButton, {}) }),
|
|
4917
|
+
/* @__PURE__ */ jsx(RibbonItem, { id: "references-update-cross-references", label: "Update cross-references", children: /* @__PURE__ */ jsx(UpdateCrossReferencesButton, {}) })
|
|
4918
|
+
] }),
|
|
3891
4919
|
tab === "Review" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3892
4920
|
/* @__PURE__ */ jsx(RibbonItem, { id: "review-editing-mode", label: "Editing mode", priority: 10, children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.EditingMode, {}) }),
|
|
3893
4921
|
/* @__PURE__ */ jsx(RibbonItem, { id: "review-comments", label: "Comments", children: /* @__PURE__ */ jsx(DocxEditor.Toolbar.Comments, {}) }),
|
|
@@ -4091,6 +5119,7 @@ function NativeDocxEditor({
|
|
|
4091
5119
|
};
|
|
4092
5120
|
}, [dirty]);
|
|
4093
5121
|
async function exportDocument() {
|
|
5122
|
+
runBeforeSave(ref.current);
|
|
4094
5123
|
const data = await ref.current?.save();
|
|
4095
5124
|
if (!data) return;
|
|
4096
5125
|
const url = URL.createObjectURL(
|
|
@@ -4117,6 +5146,7 @@ function NativeDocxEditor({
|
|
|
4117
5146
|
async function saveVersion() {
|
|
4118
5147
|
if (!ready || saving || stream) return;
|
|
4119
5148
|
setSaving(true);
|
|
5149
|
+
runBeforeSave(ref.current);
|
|
4120
5150
|
const atRevision = revision.current;
|
|
4121
5151
|
try {
|
|
4122
5152
|
const result = isDraft ? await (async () => {
|
|
@@ -4240,7 +5270,7 @@ function NativeDocxEditor({
|
|
|
4240
5270
|
load: adapter.definitions,
|
|
4241
5271
|
editable: !stream && !snapshot && ready.canEdit,
|
|
4242
5272
|
notify: adapter.notify,
|
|
4243
|
-
children: /* @__PURE__ */
|
|
5273
|
+
children: /* @__PURE__ */ jsx(
|
|
4244
5274
|
HouseTemplateProvider,
|
|
4245
5275
|
{
|
|
4246
5276
|
enabled: !stream,
|
|
@@ -4248,67 +5278,76 @@ function NativeDocxEditor({
|
|
|
4248
5278
|
documentId: isDraft || snapshot ? void 0 : documentId,
|
|
4249
5279
|
editable: !stream && !snapshot && ready.canEdit,
|
|
4250
5280
|
notify: adapter.notify,
|
|
4251
|
-
children:
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
5281
|
+
children: /* @__PURE__ */ jsxs(
|
|
5282
|
+
CrossReferencesProvider,
|
|
5283
|
+
{
|
|
5284
|
+
editable: !stream && !snapshot && ready.canEdit,
|
|
5285
|
+
references: adapter.references,
|
|
5286
|
+
documentId,
|
|
5287
|
+
notify: adapter.notify,
|
|
5288
|
+
children: [
|
|
5289
|
+
/* @__PURE__ */ jsx(
|
|
5290
|
+
DocxEditor.RevisionMarkup,
|
|
5291
|
+
{
|
|
5292
|
+
insertions: { mark: "underline", color: "blue" },
|
|
5293
|
+
deletions: { mark: "strikethrough", color: "red" },
|
|
5294
|
+
movedFrom: { mark: "doubleStrikethrough", color: "green" },
|
|
5295
|
+
movedTo: { mark: "doubleUnderline", color: "green" },
|
|
5296
|
+
trackMoves: true
|
|
5297
|
+
}
|
|
5298
|
+
),
|
|
5299
|
+
!stream && /* @__PURE__ */ jsx(
|
|
5300
|
+
DocxRibbon,
|
|
5301
|
+
{
|
|
5302
|
+
onSave: () => void saveVersion(),
|
|
5303
|
+
imageGeneration: adapter.imageGeneration && {
|
|
5304
|
+
notify: adapter.notify,
|
|
5305
|
+
...adapter.imageGeneration
|
|
5306
|
+
},
|
|
5307
|
+
badge: (
|
|
5308
|
+
// Says the document is shared live, in place of a title row above the ribbon.
|
|
5309
|
+
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
|
|
5310
|
+
)
|
|
5311
|
+
}
|
|
5312
|
+
),
|
|
5313
|
+
!stream && /* @__PURE__ */ jsx(WordShortcuts, { scope: stageRef }),
|
|
5314
|
+
!stream && /* @__PURE__ */ jsx(TableTabKeys, { scope: stageRef }),
|
|
5315
|
+
/* @__PURE__ */ jsxs(
|
|
5316
|
+
"div",
|
|
5317
|
+
{
|
|
5318
|
+
className: "native-docx-stage",
|
|
5319
|
+
ref: stageRef,
|
|
5320
|
+
onMouseDownCapture: (event) => {
|
|
5321
|
+
if (event.button === 2 && ref.current?.getSelectionPlacement())
|
|
5322
|
+
event.preventDefault();
|
|
5323
|
+
},
|
|
5324
|
+
children: [
|
|
5325
|
+
/* @__PURE__ */ jsxs(DocxEditor.Viewport, { className: "native-docx-viewport", children: [
|
|
5326
|
+
/* @__PURE__ */ jsx(DocxEditor.Content, {}),
|
|
5327
|
+
/* @__PURE__ */ jsx(
|
|
5328
|
+
DocxMentions,
|
|
5329
|
+
{
|
|
5330
|
+
initialCommentId,
|
|
5331
|
+
mentions: adapter.mentions,
|
|
5332
|
+
notify: adapter.notify,
|
|
5333
|
+
getAgentStatus: adapter.getAgentStatus,
|
|
5334
|
+
requestAgent: adapter.requestAgent ? (request) => adapter.requestAgent(documentId, request) : void 0,
|
|
5335
|
+
children: /* @__PURE__ */ jsx(DocxEditorReview, { children: () => /* @__PURE__ */ jsx(DocxEditorReview.Card, { children: /* @__PURE__ */ jsx(DocxCommentActivity, {}) }) })
|
|
5336
|
+
}
|
|
5337
|
+
),
|
|
5338
|
+
/* @__PURE__ */ jsx(DocxEditor.HeaderFooterChrome, {}),
|
|
5339
|
+
/* @__PURE__ */ jsx(DocxEditor.NotesChrome, {}),
|
|
5340
|
+
/* @__PURE__ */ jsx(DocxEditor.Equation, {}),
|
|
5341
|
+
/* @__PURE__ */ jsx(DocxEditor.HyperLink, {}),
|
|
5342
|
+
/* @__PURE__ */ jsx(DocxEditor.ContextMenu, { children: /* @__PURE__ */ jsx(DocxContextMenuExtras, {}) })
|
|
5343
|
+
] }),
|
|
5344
|
+
/* @__PURE__ */ jsx(DocxEditor.PageNumber, {})
|
|
5345
|
+
]
|
|
5346
|
+
}
|
|
4273
5347
|
)
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
!stream && /* @__PURE__ */ jsx(TableTabKeys, { scope: stageRef }),
|
|
4278
|
-
/* @__PURE__ */ jsxs(
|
|
4279
|
-
"div",
|
|
4280
|
-
{
|
|
4281
|
-
className: "native-docx-stage",
|
|
4282
|
-
ref: stageRef,
|
|
4283
|
-
onMouseDownCapture: (event) => {
|
|
4284
|
-
if (event.button === 2 && ref.current?.getSelectionPlacement())
|
|
4285
|
-
event.preventDefault();
|
|
4286
|
-
},
|
|
4287
|
-
children: [
|
|
4288
|
-
/* @__PURE__ */ jsxs(DocxEditor.Viewport, { className: "native-docx-viewport", children: [
|
|
4289
|
-
/* @__PURE__ */ jsx(DocxEditor.Content, {}),
|
|
4290
|
-
/* @__PURE__ */ jsx(
|
|
4291
|
-
DocxMentions,
|
|
4292
|
-
{
|
|
4293
|
-
initialCommentId,
|
|
4294
|
-
mentions: adapter.mentions,
|
|
4295
|
-
notify: adapter.notify,
|
|
4296
|
-
getAgentStatus: adapter.getAgentStatus,
|
|
4297
|
-
requestAgent: adapter.requestAgent ? (request) => adapter.requestAgent(documentId, request) : void 0,
|
|
4298
|
-
children: /* @__PURE__ */ jsx(DocxEditorReview, { children: () => /* @__PURE__ */ jsx(DocxEditorReview.Card, { children: /* @__PURE__ */ jsx(DocxCommentActivity, {}) }) })
|
|
4299
|
-
}
|
|
4300
|
-
),
|
|
4301
|
-
/* @__PURE__ */ jsx(DocxEditor.HeaderFooterChrome, {}),
|
|
4302
|
-
/* @__PURE__ */ jsx(DocxEditor.NotesChrome, {}),
|
|
4303
|
-
/* @__PURE__ */ jsx(DocxEditor.Equation, {}),
|
|
4304
|
-
/* @__PURE__ */ jsx(DocxEditor.HyperLink, {}),
|
|
4305
|
-
/* @__PURE__ */ jsx(DocxEditor.ContextMenu, {})
|
|
4306
|
-
] }),
|
|
4307
|
-
/* @__PURE__ */ jsx(DocxEditor.PageNumber, {})
|
|
4308
|
-
]
|
|
4309
|
-
}
|
|
4310
|
-
)
|
|
4311
|
-
]
|
|
5348
|
+
]
|
|
5349
|
+
}
|
|
5350
|
+
)
|
|
4312
5351
|
}
|
|
4313
5352
|
)
|
|
4314
5353
|
}
|
|
@@ -4407,6 +5446,6 @@ async function loadFonts(baseUrl) {
|
|
|
4407
5446
|
};
|
|
4408
5447
|
}
|
|
4409
5448
|
|
|
4410
|
-
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 };
|
|
4411
|
-
//# sourceMappingURL=chunk-
|
|
4412
|
-
//# sourceMappingURL=chunk-
|
|
5449
|
+
export { BUILTIN_TEMPLATE_NAME, CrossReferenceDialog, CrossReferencesProvider, DEFAULT_CROSS_REFERENCES_LABELS, DEFAULT_DEFINED_TERMS_LABELS, DEFINED_TERM_TRIGGER, DefinedTermsProvider, DocxAuthorContext, DocxCommentActivity, DocxEditorReview, DocxMentions, DocxParticipants, DocxRibbon, GenerateImageButton, HouseTemplateProvider, LinkHoverCard, NativeDocxEditor, builtinHouseTemplate, contentPath, editorPort, findDefinitionsSection, insertCrossReference, insertDefinedTerm, insertDocumentReference, listTargets, loadDocxFonts, normalizeDocxExport, paragraphNumber, referenceText, referencesPort, resolveHouseTemplate, reviewModule, shortTitle, structuralPort, templateFileName, trackedOrNoted, useCrossReferences, useDefinedTerms, useHouseTemplate, useReview, useReviewItem, useTrackedOrNoted, withDirectEditing };
|
|
5450
|
+
//# sourceMappingURL=chunk-W2RTZOK3.js.map
|
|
5451
|
+
//# sourceMappingURL=chunk-W2RTZOK3.js.map
|