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