@arbidocs/blocks 0.4.106 → 0.4.107
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/bin/arbidocs-render-take.mjs +27 -0
- package/dist/NativeDocxEditor-3VKJT43D.js +10 -0
- package/dist/NativeDocxEditor-3VKJT43D.js.map +1 -0
- package/dist/NativeDocxEditor-GNG5QV7V.cjs +31 -0
- package/dist/NativeDocxEditor-GNG5QV7V.cjs.map +1 -0
- package/dist/agents/index.cjs +209 -209
- package/dist/agents/index.js +4 -4
- package/dist/chat/index.cjs +125 -125
- package/dist/chat/index.js +3 -3
- package/dist/{chunk-PIT2YZCK.js → chunk-2PYENCW5.js} +3 -3
- package/dist/{chunk-PIT2YZCK.js.map → chunk-2PYENCW5.js.map} +1 -1
- package/dist/{chunk-W2RTZOK3.js → chunk-2SJTXYRM.js} +1749 -1778
- package/dist/chunk-2SJTXYRM.js.map +1 -0
- package/dist/{chunk-S7RHJI5Q.js → chunk-7NLPKJV5.js} +3 -3
- package/dist/{chunk-S7RHJI5Q.js.map → chunk-7NLPKJV5.js.map} +1 -1
- package/dist/{chunk-ZWWN4CUL.cjs → chunk-BHKFENKT.cjs} +1748 -1778
- package/dist/chunk-BHKFENKT.cjs.map +1 -0
- package/dist/{chunk-3R6XBYL7.cjs → chunk-DTBSGG36.cjs} +7 -2
- package/dist/chunk-DTBSGG36.cjs.map +1 -0
- package/dist/{chunk-3Y6NQIDE.js → chunk-EB7QAZLH.js} +5 -5
- package/dist/{chunk-3Y6NQIDE.js.map → chunk-EB7QAZLH.js.map} +1 -1
- package/dist/{chunk-TP3FAP5J.cjs → chunk-FZGMY6NQ.cjs} +5 -5
- package/dist/{chunk-TP3FAP5J.cjs.map → chunk-FZGMY6NQ.cjs.map} +1 -1
- package/dist/{chunk-W7NZRZ54.js → chunk-GFYGYME3.js} +3 -3
- package/dist/{chunk-W7NZRZ54.js.map → chunk-GFYGYME3.js.map} +1 -1
- package/dist/chunk-GYAUJ4KT.js +71 -0
- package/dist/chunk-GYAUJ4KT.js.map +1 -0
- package/dist/{chunk-XMBYDLZQ.cjs → chunk-HUJLKDWX.cjs} +4 -4
- package/dist/{chunk-XMBYDLZQ.cjs.map → chunk-HUJLKDWX.cjs.map} +1 -1
- package/dist/{chunk-4GFB5U3K.js → chunk-LHBJJ2GE.js} +4 -3
- package/dist/chunk-LHBJJ2GE.js.map +1 -0
- package/dist/{chunk-MP6FK43E.cjs → chunk-O5NDG4EA.cjs} +3 -3
- package/dist/{chunk-MP6FK43E.cjs.map → chunk-O5NDG4EA.cjs.map} +1 -1
- package/dist/{chunk-5YXG342J.cjs → chunk-OR4CO743.cjs} +3 -3
- package/dist/{chunk-5YXG342J.cjs.map → chunk-OR4CO743.cjs.map} +1 -1
- package/dist/{chunk-LGX6UFYG.js → chunk-P2KPDPFF.js} +8 -3
- package/dist/chunk-P2KPDPFF.js.map +1 -0
- package/dist/{chunk-DDF5GPIJ.js → chunk-P5ST47VY.js} +3 -3
- package/dist/{chunk-DDF5GPIJ.js.map → chunk-P5ST47VY.js.map} +1 -1
- package/dist/{chunk-EWSEQEPL.js → chunk-PFA43QNX.js} +3 -3
- package/dist/{chunk-EWSEQEPL.js.map → chunk-PFA43QNX.js.map} +1 -1
- package/dist/{chunk-7LLLQUM7.cjs → chunk-Q57MEBCK.cjs} +6 -5
- package/dist/chunk-Q57MEBCK.cjs.map +1 -0
- package/dist/{chunk-LLFW2T6S.cjs → chunk-R6APX23R.cjs} +11 -11
- package/dist/{chunk-LLFW2T6S.cjs.map → chunk-R6APX23R.cjs.map} +1 -1
- package/dist/{chunk-24ND4S6Y.cjs → chunk-RILMICOP.cjs} +5 -5
- package/dist/{chunk-24ND4S6Y.cjs.map → chunk-RILMICOP.cjs.map} +1 -1
- package/dist/chunk-S24XEVPS.cjs +73 -0
- package/dist/chunk-S24XEVPS.cjs.map +1 -0
- package/dist/{chunk-XQDM6T6C.js → chunk-WDD255XQ.js} +3 -3
- package/dist/{chunk-XQDM6T6C.js.map → chunk-WDD255XQ.js.map} +1 -1
- package/dist/{chunk-Z5VUZ6YD.cjs → chunk-ZV3BKLFY.cjs} +3 -3
- package/dist/{chunk-Z5VUZ6YD.cjs.map → chunk-ZV3BKLFY.cjs.map} +1 -1
- package/dist/collaboration/index.cjs +15 -15
- package/dist/collaboration/index.js +1 -1
- package/dist/collaboration/mail/MailMessageView.d.ts +3 -1
- package/dist/connect/docx.cjs +7 -6
- package/dist/connect/docx.cjs.map +1 -1
- package/dist/connect/docx.js +5 -4
- package/dist/connect/docx.js.map +1 -1
- package/dist/connect/index.cjs +407 -91
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.js +361 -46
- package/dist/connect/index.js.map +1 -1
- package/dist/connection/mail/ConnectedMailComposer.d.ts +12 -2
- package/dist/connection/mail/ConnectedMailMessage.d.ts +19 -0
- package/dist/connection/mail/ConnectedMailbox.d.ts +7 -3
- package/dist/connection/mail/MailComposerForm.d.ts +12 -2
- package/dist/connection/mail/index.d.ts +2 -1
- package/dist/connection/mail/types.d.ts +15 -0
- package/dist/connection/mail/useWordBody.d.ts +48 -0
- package/dist/docx/NativeDocxEditor.d.ts +9 -1
- package/dist/docx/index.cjs +51 -50
- package/dist/docx/index.cjs.map +1 -1
- package/dist/docx/index.js +4 -3
- package/dist/docx/index.js.map +1 -1
- package/dist/facts/index.cjs +2 -2
- package/dist/facts/index.js +2 -2
- package/dist/files/index.cjs +2 -2
- package/dist/files/index.js +2 -2
- package/dist/home/index.cjs +17 -17
- package/dist/home/index.js +3 -3
- package/dist/index.cjs +442 -442
- package/dist/index.js +8 -8
- package/dist/record/index.cjs +307 -66
- package/dist/record/index.cjs.map +1 -1
- package/dist/record/index.d.ts +145 -26
- package/dist/record/index.js +301 -67
- package/dist/record/index.js.map +1 -1
- package/dist/retrieval/index.cjs +1 -1
- package/dist/retrieval/index.js +1 -1
- package/dist/settings/index.cjs +35 -35
- package/dist/settings/index.js +2 -2
- package/dist/shell/index.cjs +1 -1
- package/dist/shell/index.js +1 -1
- package/dist/studio/index.cjs +4 -4
- package/dist/studio/index.js +3 -3
- package/dist/workflow-canvas/index.cjs +11 -11
- package/dist/workflow-canvas/index.js +4 -4
- package/dist/workspaces/index.cjs +2 -2
- package/dist/workspaces/index.js +2 -2
- package/node_modules/@arbidocs/coedit/package.json +1 -1
- package/package.json +8 -5
- package/record/render-overlays.mjs +152 -0
- package/record/render-take.py +985 -0
- package/src/docx/styles.css +22 -0
- package/dist/chunk-3R6XBYL7.cjs.map +0 -1
- package/dist/chunk-4GFB5U3K.js.map +0 -1
- package/dist/chunk-7LLLQUM7.cjs.map +0 -1
- package/dist/chunk-LGX6UFYG.js.map +0 -1
- package/dist/chunk-W2RTZOK3.js.map +0 -1
- package/dist/chunk-ZWWN4CUL.cjs.map +0 -1
|
@@ -5,20 +5,20 @@ var chunk5FYU7ZIU_cjs = require('./chunk-5FYU7ZIU.cjs');
|
|
|
5
5
|
var chunk2A4MDHJR_cjs = require('./chunk-2A4MDHJR.cjs');
|
|
6
6
|
var chunk7UTB4PHM_cjs = require('./chunk-7UTB4PHM.cjs');
|
|
7
7
|
var fflate = require('fflate');
|
|
8
|
-
var
|
|
9
|
-
var React4 = require('react');
|
|
10
|
-
var react = require('@docx-editor.dev/react');
|
|
8
|
+
var server = require('react-dom/server');
|
|
11
9
|
var ui = require('@arbidocs/react/ui');
|
|
12
|
-
var lucideReact = require('lucide-react');
|
|
13
10
|
var jsxRuntime = require('react/jsx-runtime');
|
|
11
|
+
var React4 = require('react');
|
|
14
12
|
var reactDom = require('react-dom');
|
|
15
|
-
var
|
|
16
|
-
var
|
|
17
|
-
var
|
|
18
|
-
var server = require('react-dom/server');
|
|
13
|
+
var store = require('@docx-editor.dev/core/store');
|
|
14
|
+
var react = require('@docx-editor.dev/react');
|
|
15
|
+
var lucideReact = require('lucide-react');
|
|
19
16
|
var Y = require('yjs');
|
|
20
17
|
var coedit = require('@arbidocs/coedit');
|
|
21
18
|
var hocuspocus = require('@arbidocs/coedit/hocuspocus');
|
|
19
|
+
var template = require('@arbidocs/coedit/template');
|
|
20
|
+
var layout = require('@docx-editor.dev/core/layout');
|
|
21
|
+
var editor = require('@docx-editor.dev/core/editor');
|
|
22
22
|
|
|
23
23
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
24
24
|
|
|
@@ -107,6 +107,93 @@ function normalizeDocxExport(data) {
|
|
|
107
107
|
if (!changed) return data;
|
|
108
108
|
return fflate.zipSync(files).slice().buffer;
|
|
109
109
|
}
|
|
110
|
+
function wordDraftHtml(markdown) {
|
|
111
|
+
const template = document.createElement("template");
|
|
112
|
+
template.innerHTML = server.renderToStaticMarkup(/* @__PURE__ */ jsxRuntime.jsx(ui.AiMarkdown, { children: markdown }));
|
|
113
|
+
template.content.querySelectorAll('button, svg, [data-testid="code-block-header"]').forEach((node) => node.remove());
|
|
114
|
+
template.content.querySelectorAll('[data-testid="markdown-code-block"]').forEach((node) => {
|
|
115
|
+
const pre = node.querySelector("pre");
|
|
116
|
+
if (pre) node.replaceWith(pre);
|
|
117
|
+
});
|
|
118
|
+
return template.innerHTML;
|
|
119
|
+
}
|
|
120
|
+
function requireEdit(result) {
|
|
121
|
+
if (!result.ok) throw new Error(result.reason);
|
|
122
|
+
}
|
|
123
|
+
var WordDraftStream = class {
|
|
124
|
+
constructor(editor) {
|
|
125
|
+
this.editor = editor;
|
|
126
|
+
}
|
|
127
|
+
editor;
|
|
128
|
+
committed = [];
|
|
129
|
+
pending;
|
|
130
|
+
resetAfterFailure = false;
|
|
131
|
+
update(content, complete) {
|
|
132
|
+
const blocks = ui.splitMarkdownBlocks(content);
|
|
133
|
+
const completeCount = complete ? blocks.length : Math.max(0, blocks.length - 1);
|
|
134
|
+
requireEdit(this.editor.setEditingMode("editing"));
|
|
135
|
+
try {
|
|
136
|
+
if (this.resetAfterFailure || this.committed.some((block, index) => blocks[index] !== block)) {
|
|
137
|
+
requireEdit(this.editor.exec({ type: "selectAll" }));
|
|
138
|
+
requireEdit(this.editor.exec({ type: "deleteText" }));
|
|
139
|
+
this.committed = [];
|
|
140
|
+
this.pending = void 0;
|
|
141
|
+
this.resetAfterFailure = false;
|
|
142
|
+
}
|
|
143
|
+
for (let index = this.committed.length; index < blocks.length; index++) {
|
|
144
|
+
const tail = this.editor.query({ type: "paragraphs" }).at(-1);
|
|
145
|
+
const start = this.pending?.start || tail?.paraId;
|
|
146
|
+
if (!start) throw new Error("The draft insertion paragraph is unavailable.");
|
|
147
|
+
requireEdit(
|
|
148
|
+
this.editor.exec(
|
|
149
|
+
this.pending ? {
|
|
150
|
+
type: "setSelection",
|
|
151
|
+
range: { from: { paraId: start }, to: { paraId: this.pending.end } }
|
|
152
|
+
} : { type: "setSelection", anchor: { paraId: start } }
|
|
153
|
+
)
|
|
154
|
+
);
|
|
155
|
+
const html = wordDraftHtml(blocks[index]) + "<p></p>";
|
|
156
|
+
const element = document.createElement("div");
|
|
157
|
+
element.innerHTML = html;
|
|
158
|
+
const startIndex = this.editor.query({ type: "paragraphs" }).findIndex((p) => p.paraId === start);
|
|
159
|
+
requireEdit(this.editor.exec({ type: "paste", html, text: element.textContent || "" }));
|
|
160
|
+
const inserted = this.editor.query({ type: "paragraphs" }).slice(startIndex);
|
|
161
|
+
let headingIndex = 0;
|
|
162
|
+
for (const heading of Array.from(element.querySelectorAll("h1,h2,h3,h4,h5,h6"))) {
|
|
163
|
+
const match = inserted.findIndex(
|
|
164
|
+
(p, i) => i >= headingIndex && p.text === heading.textContent
|
|
165
|
+
);
|
|
166
|
+
if (match >= 0 && inserted[match].paraId) {
|
|
167
|
+
requireEdit(
|
|
168
|
+
this.editor.exec({
|
|
169
|
+
type: "setSelection",
|
|
170
|
+
anchor: { paraId: inserted[match].paraId }
|
|
171
|
+
})
|
|
172
|
+
);
|
|
173
|
+
requireEdit(
|
|
174
|
+
this.editor.exec({
|
|
175
|
+
type: "setParagraphStyle",
|
|
176
|
+
styleId: `Heading${heading.tagName.slice(1)}`
|
|
177
|
+
})
|
|
178
|
+
);
|
|
179
|
+
headingIndex = match + 1;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const end = this.editor.query({ type: "paragraphs" }).at(-1)?.paraId;
|
|
183
|
+
if (!end) throw new Error("The draft continuation paragraph is unavailable.");
|
|
184
|
+
if (index < completeCount) {
|
|
185
|
+
this.committed.push(blocks[index]);
|
|
186
|
+
this.pending = void 0;
|
|
187
|
+
} else this.pending = { start, end };
|
|
188
|
+
}
|
|
189
|
+
} catch (error) {
|
|
190
|
+
this.resetAfterFailure = true;
|
|
191
|
+
throw error;
|
|
192
|
+
} finally {
|
|
193
|
+
requireEdit(this.editor.setEditingMode("viewing"));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
};
|
|
110
197
|
function findNode(node, id) {
|
|
111
198
|
if (node.id === id) return node;
|
|
112
199
|
for (const child of node.children ?? []) {
|
|
@@ -130,6 +217,22 @@ function reviewModule() {
|
|
|
130
217
|
}
|
|
131
218
|
};
|
|
132
219
|
}
|
|
220
|
+
|
|
221
|
+
// src/docx/review/commentText.ts
|
|
222
|
+
var SKIP = /* @__PURE__ */ new Set(["delText", "instrText", "delInstrText", "pPr", "rPr"]);
|
|
223
|
+
function inline(node) {
|
|
224
|
+
if (node.kind === "textValue") return node.value ?? "";
|
|
225
|
+
if (node.localName && SKIP.has(node.localName)) return "";
|
|
226
|
+
if (node.localName === "br" || node.localName === "cr") return "\n";
|
|
227
|
+
if (node.localName === "tab") return " ";
|
|
228
|
+
return (node.children ?? []).map(inline).join("");
|
|
229
|
+
}
|
|
230
|
+
function commentText(entry) {
|
|
231
|
+
if (entry.kind !== "comment") return entry.text;
|
|
232
|
+
const blocks = entry.item?.comment?.blocks ?? [];
|
|
233
|
+
const text = blocks.map(inline).join("\n").trim();
|
|
234
|
+
return text || entry.text;
|
|
235
|
+
}
|
|
133
236
|
var NONE = [];
|
|
134
237
|
var ok = (result) => result?.ok === true;
|
|
135
238
|
function useReview() {
|
|
@@ -165,22 +268,6 @@ var ReviewItemContext = React4.createContext(null);
|
|
|
165
268
|
function useReviewItem() {
|
|
166
269
|
return React4.useContext(ReviewItemContext);
|
|
167
270
|
}
|
|
168
|
-
|
|
169
|
-
// src/docx/review/commentText.ts
|
|
170
|
-
var SKIP = /* @__PURE__ */ new Set(["delText", "instrText", "delInstrText", "pPr", "rPr"]);
|
|
171
|
-
function inline(node) {
|
|
172
|
-
if (node.kind === "textValue") return node.value ?? "";
|
|
173
|
-
if (node.localName && SKIP.has(node.localName)) return "";
|
|
174
|
-
if (node.localName === "br" || node.localName === "cr") return "\n";
|
|
175
|
-
if (node.localName === "tab") return " ";
|
|
176
|
-
return (node.children ?? []).map(inline).join("");
|
|
177
|
-
}
|
|
178
|
-
function commentText(entry) {
|
|
179
|
-
if (entry.kind !== "comment") return entry.text;
|
|
180
|
-
const blocks = entry.item?.comment?.blocks ?? [];
|
|
181
|
-
const text = blocks.map(inline).join("\n").trim();
|
|
182
|
-
return text || entry.text;
|
|
183
|
-
}
|
|
184
271
|
var CARD_GAP = 8;
|
|
185
272
|
var CLUSTER_GAP = 24;
|
|
186
273
|
var REVIEW_MARGIN_MIN_WIDTH = 900;
|
|
@@ -1818,6 +1905,8 @@ function structuralPort(editor) {
|
|
|
1818
1905
|
}
|
|
1819
1906
|
};
|
|
1820
1907
|
}
|
|
1908
|
+
|
|
1909
|
+
// src/docx/structural/useTrackedOrNoted.ts
|
|
1821
1910
|
var DocxAuthorContext = React4.createContext("You");
|
|
1822
1911
|
function useTrackedOrNoted() {
|
|
1823
1912
|
const editor = react.useDocxEditor();
|
|
@@ -2201,1796 +2290,1529 @@ function DefinedTermMenu({
|
|
|
2201
2290
|
}
|
|
2202
2291
|
);
|
|
2203
2292
|
}
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
try {
|
|
2214
|
-
return await host.load();
|
|
2215
|
-
} catch {
|
|
2216
|
-
return builtinHouseTemplate();
|
|
2217
|
-
}
|
|
2218
|
-
}
|
|
2219
|
-
var HouseTemplateContext = React4.createContext(null);
|
|
2220
|
-
var useHouseTemplate = () => React4.useContext(HouseTemplateContext);
|
|
2221
|
-
function HouseTemplateProvider({
|
|
2222
|
-
host,
|
|
2223
|
-
documentId,
|
|
2224
|
-
editable,
|
|
2225
|
-
notify,
|
|
2226
|
-
enabled = true,
|
|
2227
|
-
children
|
|
2293
|
+
function RibbonMenu({
|
|
2294
|
+
label,
|
|
2295
|
+
icon,
|
|
2296
|
+
children,
|
|
2297
|
+
className,
|
|
2298
|
+
testId,
|
|
2299
|
+
title,
|
|
2300
|
+
keepMounted = false,
|
|
2301
|
+
popoverClassName
|
|
2228
2302
|
}) {
|
|
2229
|
-
const
|
|
2230
|
-
const
|
|
2231
|
-
const [template$1, setTemplate] = React4.useState(builtinHouseTemplate);
|
|
2232
|
-
const [divergence, setDivergence] = React4.useState(null);
|
|
2233
|
-
const [basedOnTemplate, setBasedOnTemplate] = React4.useState(false);
|
|
2234
|
-
const [levels, setLevels] = React4.useState({});
|
|
2235
|
-
const [generation, setGeneration] = React4.useState(0);
|
|
2303
|
+
const [open, setOpen] = React4.useState(false);
|
|
2304
|
+
const element = React4.useRef(null);
|
|
2236
2305
|
React4.useEffect(() => {
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
live = false;
|
|
2306
|
+
if (!open) return;
|
|
2307
|
+
const dismiss = (event) => {
|
|
2308
|
+
if (!element.current?.contains(event.target)) setOpen(false);
|
|
2241
2309
|
};
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
return [];
|
|
2248
|
-
}
|
|
2249
|
-
}, [template$1]);
|
|
2250
|
-
React4.useEffect(() => {
|
|
2251
|
-
if (!editor || !enabled) return;
|
|
2252
|
-
let live = true;
|
|
2253
|
-
void editor.save().then((saved) => {
|
|
2254
|
-
if (!live || !saved) return;
|
|
2255
|
-
const bytes = new Uint8Array(saved);
|
|
2256
|
-
setBasedOnTemplate(template.attachedTemplateOf(bytes) === templateFileName(template$1));
|
|
2257
|
-
setLevels(template.linkedLevelStyles(bytes));
|
|
2258
|
-
setDivergence(template.styleDivergence(bytes, template$1.bytes));
|
|
2259
|
-
}).catch(() => live && setDivergence(null));
|
|
2310
|
+
const escape = (event) => {
|
|
2311
|
+
if (event.key === "Escape") setOpen(false);
|
|
2312
|
+
};
|
|
2313
|
+
document.addEventListener("pointerdown", dismiss);
|
|
2314
|
+
document.addEventListener("keydown", escape);
|
|
2260
2315
|
return () => {
|
|
2261
|
-
|
|
2316
|
+
document.removeEventListener("pointerdown", dismiss);
|
|
2317
|
+
document.removeEventListener("keydown", escape);
|
|
2262
2318
|
};
|
|
2263
|
-
}, [
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
revision ? template.trackInsertion(fragment, revision, true) : fragment
|
|
2278
|
-
)
|
|
2279
|
-
}),
|
|
2280
|
-
inserted: (r) => r.ok
|
|
2281
|
-
})?.result;
|
|
2282
|
-
if (!result?.ok) throw new Error(result?.reason ?? "The block could not be inserted here.");
|
|
2283
|
-
refresh();
|
|
2284
|
-
return true;
|
|
2285
|
-
} catch (failure) {
|
|
2286
|
-
notify?.(
|
|
2287
|
-
failure instanceof Error ? failure.message : "Could not insert the block.",
|
|
2288
|
-
"error"
|
|
2289
|
-
);
|
|
2290
|
-
return false;
|
|
2319
|
+
}, [open]);
|
|
2320
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "native-docx-ribbon-menu", ref: element, children: [
|
|
2321
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2322
|
+
"button",
|
|
2323
|
+
{
|
|
2324
|
+
type: "button",
|
|
2325
|
+
className: ["native-docx-ribbon-trigger", className].filter(Boolean).join(" "),
|
|
2326
|
+
"aria-label": label,
|
|
2327
|
+
title: title ?? label,
|
|
2328
|
+
"aria-expanded": open,
|
|
2329
|
+
"data-testid": testId,
|
|
2330
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
2331
|
+
onClick: () => setOpen((value) => !value),
|
|
2332
|
+
children: icon
|
|
2291
2333
|
}
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
);
|
|
2334
|
+
),
|
|
2335
|
+
(open || keepMounted) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2336
|
+
"div",
|
|
2337
|
+
{
|
|
2338
|
+
className: ["native-docx-ribbon-popover", popoverClassName].filter(Boolean).join(" "),
|
|
2339
|
+
role: "group",
|
|
2340
|
+
"aria-label": label,
|
|
2341
|
+
hidden: !open,
|
|
2342
|
+
onMouseDown: (event) => {
|
|
2343
|
+
if (!(event.target instanceof HTMLInputElement || event.target instanceof HTMLSelectElement))
|
|
2344
|
+
event.preventDefault();
|
|
2345
|
+
},
|
|
2346
|
+
children: typeof children === "function" ? children(() => setOpen(false)) : children
|
|
2306
2347
|
}
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
);
|
|
2310
|
-
const value = React4.useMemo(
|
|
2311
|
-
() => ({
|
|
2312
|
-
template: template$1,
|
|
2313
|
-
blocks,
|
|
2314
|
-
divergence,
|
|
2315
|
-
basedOnTemplate,
|
|
2316
|
-
levels,
|
|
2317
|
-
insertBlock,
|
|
2318
|
-
refresh,
|
|
2319
|
-
setAsHouseTemplate,
|
|
2320
|
-
editable
|
|
2321
|
-
}),
|
|
2322
|
-
[
|
|
2323
|
-
template$1,
|
|
2324
|
-
blocks,
|
|
2325
|
-
divergence,
|
|
2326
|
-
basedOnTemplate,
|
|
2327
|
-
levels,
|
|
2328
|
-
insertBlock,
|
|
2329
|
-
refresh,
|
|
2330
|
-
setAsHouseTemplate,
|
|
2331
|
-
editable
|
|
2332
|
-
]
|
|
2333
|
-
);
|
|
2334
|
-
return /* @__PURE__ */ jsxRuntime.jsx(HouseTemplateContext.Provider, { value: enabled ? value : null, children });
|
|
2348
|
+
)
|
|
2349
|
+
] });
|
|
2335
2350
|
}
|
|
2336
2351
|
|
|
2337
|
-
// src/docx/
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
if (
|
|
2342
|
-
|
|
2343
|
-
const
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
}
|
|
2349
|
-
return null;
|
|
2350
|
-
};
|
|
2351
|
-
const chain = [];
|
|
2352
|
-
const texts = [];
|
|
2353
|
-
for (let u = item.ilvl; u >= 0; u--) {
|
|
2354
|
-
const level = levelOf(item.numId, u);
|
|
2355
|
-
if (!level || !numbers(level)) continue;
|
|
2356
|
-
if (u !== item.ilvl && texts.some((t) => t.includes(`%${u + 1}`))) continue;
|
|
2357
|
-
chain.push(u);
|
|
2358
|
-
texts.push(level.lvlText);
|
|
2359
|
-
}
|
|
2360
|
-
const value = chain.reverse().map((u) => markerAt(u) ?? "").join("");
|
|
2361
|
-
if (!value) return null;
|
|
2362
|
-
return value.length > 1 && value.endsWith(".") ? value.slice(0, -1) : value;
|
|
2363
|
-
}
|
|
2364
|
-
function listTargets(paragraphs, items, levelOf) {
|
|
2365
|
-
const order = paragraphs.map((p) => p.id);
|
|
2366
|
-
const out = [];
|
|
2367
|
-
for (const p of paragraphs) {
|
|
2368
|
-
const text = p.text.replace(//g, "").trim();
|
|
2369
|
-
if (!text) continue;
|
|
2370
|
-
const number = paragraphNumber(order, items, levelOf, p.id);
|
|
2371
|
-
const item = items.get(p.id);
|
|
2372
|
-
if (number !== null)
|
|
2373
|
-
out.push({
|
|
2374
|
-
paragraphId: p.id,
|
|
2375
|
-
kind: "numbered",
|
|
2376
|
-
number,
|
|
2377
|
-
marker: item?.markerText ?? "",
|
|
2378
|
-
text,
|
|
2379
|
-
heading: p.heading,
|
|
2380
|
-
level: item?.ilvl ?? 0
|
|
2381
|
-
});
|
|
2382
|
-
else if (p.heading)
|
|
2383
|
-
out.push({
|
|
2384
|
-
paragraphId: p.id,
|
|
2385
|
-
kind: "heading",
|
|
2386
|
-
number: null,
|
|
2387
|
-
marker: "",
|
|
2388
|
-
text,
|
|
2389
|
-
heading: true,
|
|
2390
|
-
level: 0
|
|
2391
|
-
});
|
|
2352
|
+
// src/docx/overflowPlan.ts
|
|
2353
|
+
function planOverflow(items, available, moreWidth) {
|
|
2354
|
+
const collapsed = /* @__PURE__ */ new Set();
|
|
2355
|
+
let used = items.reduce((sum, item) => sum + item.width, 0);
|
|
2356
|
+
if (used <= available) return collapsed;
|
|
2357
|
+
used += moreWidth;
|
|
2358
|
+
const order = items.map((item, index) => ({ item, index })).sort((a, b) => a.item.priority - b.item.priority || b.index - a.index);
|
|
2359
|
+
for (const { item } of order) {
|
|
2360
|
+
if (used <= available) break;
|
|
2361
|
+
collapsed.add(item.id);
|
|
2362
|
+
used -= item.width;
|
|
2392
2363
|
}
|
|
2393
|
-
return
|
|
2364
|
+
return collapsed;
|
|
2394
2365
|
}
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2366
|
+
var Overflow = React4.createContext(null);
|
|
2367
|
+
var MORE_WIDTH = 32;
|
|
2368
|
+
var sameSet = (a, b) => a.size === b.size && [...a].every((id) => b.has(id));
|
|
2369
|
+
function RibbonOverflow({ tab, children }) {
|
|
2370
|
+
const row = React4.useRef(null);
|
|
2371
|
+
const items = React4.useRef(/* @__PURE__ */ new Map());
|
|
2372
|
+
const widths = React4.useRef(/* @__PURE__ */ new Map());
|
|
2373
|
+
const [version, setVersion] = React4.useState(0);
|
|
2374
|
+
const [collapsed, setCollapsed] = React4.useState(() => /* @__PURE__ */ new Set());
|
|
2375
|
+
const [slots, setSlots] = React4.useState({});
|
|
2376
|
+
const [menu, setMenu] = React4.useState([]);
|
|
2377
|
+
const register = React4.useCallback((id, item) => {
|
|
2378
|
+
items.current.set(id, item);
|
|
2379
|
+
setVersion((v) => v + 1);
|
|
2380
|
+
return () => {
|
|
2381
|
+
if (items.current.get(id) === item) items.current.delete(id);
|
|
2382
|
+
setVersion((v) => v + 1);
|
|
2383
|
+
};
|
|
2384
|
+
}, []);
|
|
2385
|
+
const plan = React4.useCallback(() => {
|
|
2386
|
+
const element = row.current;
|
|
2387
|
+
if (!element) return;
|
|
2388
|
+
const gap = parseFloat(getComputedStyle(element).columnGap) || 0;
|
|
2389
|
+
const ordered = Array.from(element.querySelectorAll("[data-ribbon-item]")).map((node) => node.dataset.ribbonItem).filter((id) => items.current.has(id));
|
|
2390
|
+
const measured = ordered.map((id) => {
|
|
2391
|
+
const { element: node, priority } = items.current.get(id);
|
|
2392
|
+
if (!node.hidden) {
|
|
2393
|
+
const width = node.getBoundingClientRect().width;
|
|
2394
|
+
widths.current.set(id, width ? width + gap : 0);
|
|
2395
|
+
}
|
|
2396
|
+
return { id, priority, width: widths.current.get(id) ?? 0 };
|
|
2397
|
+
});
|
|
2398
|
+
const next = planOverflow(measured, element.clientWidth, MORE_WIDTH);
|
|
2399
|
+
setCollapsed((current) => sameSet(current, next) ? current : next);
|
|
2400
|
+
const entries = ordered.filter((id) => next.has(id)).map((id) => ({ id, label: items.current.get(id).label }));
|
|
2401
|
+
setMenu(
|
|
2402
|
+
(current) => current.length === entries.length && current.every((entry, i) => entry.id === entries[i].id && entry.label === entries[i].label) ? current : entries
|
|
2403
|
+
);
|
|
2404
|
+
}, []);
|
|
2405
|
+
React4.useLayoutEffect(plan, [plan, version, tab, collapsed]);
|
|
2406
|
+
React4.useLayoutEffect(() => {
|
|
2407
|
+
const element = row.current;
|
|
2408
|
+
if (!element) return;
|
|
2409
|
+
const observer = new ResizeObserver(() => plan());
|
|
2410
|
+
observer.observe(element);
|
|
2411
|
+
for (const item of items.current.values()) observer.observe(item.element);
|
|
2412
|
+
return () => observer.disconnect();
|
|
2413
|
+
}, [plan, version]);
|
|
2414
|
+
const slotRef = React4.useCallback(
|
|
2415
|
+
(id) => (node) => setSlots((current) => {
|
|
2416
|
+
if (node ? current[id] === node : !(id in current)) return current;
|
|
2417
|
+
const next = { ...current };
|
|
2418
|
+
if (node) next[id] = node;
|
|
2419
|
+
else delete next[id];
|
|
2420
|
+
return next;
|
|
2421
|
+
}),
|
|
2422
|
+
[]
|
|
2400
2423
|
);
|
|
2424
|
+
const context = React4.useMemo(() => ({ collapsed, slots, register }), [collapsed, slots, register]);
|
|
2425
|
+
const shown = menu.filter((entry) => collapsed.has(entry.id));
|
|
2426
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Overflow.Provider, { value: context, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "native-docx-ribbon-row", ref: row, "data-testid": "docx-ribbon-row", children: [
|
|
2427
|
+
children,
|
|
2428
|
+
shown.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2429
|
+
RibbonMenu,
|
|
2430
|
+
{
|
|
2431
|
+
label: "More",
|
|
2432
|
+
title: "More commands",
|
|
2433
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Ellipsis, { size: 16 }),
|
|
2434
|
+
testId: "docx-ribbon-more",
|
|
2435
|
+
keepMounted: true,
|
|
2436
|
+
popoverClassName: "native-docx-ribbon-more",
|
|
2437
|
+
children: (close) => /* @__PURE__ */ jsxRuntime.jsx(MoreRows, { entries: shown, slotRef, close })
|
|
2438
|
+
},
|
|
2439
|
+
tab
|
|
2440
|
+
)
|
|
2441
|
+
] }) });
|
|
2401
2442
|
}
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2443
|
+
function MoreRows({
|
|
2444
|
+
entries,
|
|
2445
|
+
slotRef,
|
|
2446
|
+
close
|
|
2447
|
+
}) {
|
|
2448
|
+
const refs = React4.useRef(/* @__PURE__ */ new Map());
|
|
2449
|
+
const refFor = (id) => {
|
|
2450
|
+
let ref = refs.current.get(id);
|
|
2451
|
+
if (!ref) refs.current.set(id, ref = slotRef(id));
|
|
2452
|
+
return ref;
|
|
2453
|
+
};
|
|
2454
|
+
const list = React4.useRef(null);
|
|
2455
|
+
const latest = React4.useRef(close);
|
|
2456
|
+
latest.current = close;
|
|
2457
|
+
React4.useEffect(() => {
|
|
2458
|
+
const element = list.current;
|
|
2459
|
+
if (!element) return;
|
|
2460
|
+
const onClick = (event) => {
|
|
2461
|
+
const target = event.target;
|
|
2462
|
+
const row = target.closest(".native-docx-ribbon-more-row");
|
|
2463
|
+
if (!row) return;
|
|
2464
|
+
const control = row.querySelector(".native-docx-ribbon-more-control");
|
|
2465
|
+
if (!control.contains(target)) {
|
|
2466
|
+
control.querySelector("button:not([disabled])")?.click();
|
|
2467
|
+
return;
|
|
2468
|
+
}
|
|
2469
|
+
const button = target.closest("button");
|
|
2470
|
+
if (button && !button.disabled && !control.querySelector(".native-docx-ribbon-popover")?.contains(button) && !button.hasAttribute("aria-expanded") && !button.hasAttribute("aria-haspopup"))
|
|
2471
|
+
latest.current();
|
|
2472
|
+
};
|
|
2473
|
+
element.addEventListener("click", onClick, true);
|
|
2474
|
+
return () => element.removeEventListener("click", onClick, true);
|
|
2475
|
+
}, []);
|
|
2476
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "native-docx-ribbon-more-list", ref: list, children: entries.map((entry) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "native-docx-ribbon-more-row", "data-ribbon-more": entry.id, children: [
|
|
2477
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "native-docx-ribbon-more-control", ref: refFor(entry.id) }),
|
|
2478
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "native-docx-ribbon-more-label", children: entry.label })
|
|
2479
|
+
] }, entry.id)) });
|
|
2410
2480
|
}
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
const name = newRefBookmark(allBookmarks(port));
|
|
2436
|
-
const start = `<w:bookmarkStart w:id="0" w:name="${name}"/>`;
|
|
2437
|
-
const end = '<w:bookmarkEnd w:id="0"/>';
|
|
2438
|
-
if (mode === "number") {
|
|
2439
|
-
port.setCaret({ paragraphId: paragraph.id, offset: 0 });
|
|
2440
|
-
if (!port.paste(`<w:p>${start}${end}</w:p>`, "", false))
|
|
2441
|
-
throw new Error("The cross-reference target could not be marked.");
|
|
2442
|
-
return name;
|
|
2443
|
-
}
|
|
2444
|
-
const runs = port.runsXml(paragraph.id);
|
|
2445
|
-
if (!runs) throw new Error("This heading cannot be referred to by its text; use its number.");
|
|
2446
|
-
port.deleteRange(
|
|
2447
|
-
{ paragraphId: paragraph.id, offset: 0 },
|
|
2448
|
-
{ paragraphId: paragraph.id, offset: paragraph.text.length }
|
|
2449
|
-
);
|
|
2450
|
-
if (!port.paste(`<w:p>${start}${runs}${end}</w:p>`, paragraph.text, false))
|
|
2451
|
-
throw new Error("The cross-reference target could not be marked.");
|
|
2452
|
-
return name;
|
|
2453
|
-
}
|
|
2454
|
-
function pastePoint(port, caret) {
|
|
2455
|
-
const paragraph = port.paragraphs().find((p) => p.id === caret.paragraphId);
|
|
2456
|
-
if (paragraph?.text[caret.offset - 1] !== FIELD_ATOM) return caret;
|
|
2457
|
-
port.setCaret(caret);
|
|
2458
|
-
port.typeText(" ");
|
|
2459
|
-
return { paragraphId: caret.paragraphId, offset: caret.offset + 1 };
|
|
2460
|
-
}
|
|
2461
|
-
function markCrossReferenceTarget(port, target, mode) {
|
|
2462
|
-
if (mode === "number" && !target.number) mode = "text";
|
|
2463
|
-
const bookmark = ensureTargetBookmark(port, target, mode);
|
|
2464
|
-
return { bookmark, mode, value: refResult(target, mode) };
|
|
2465
|
-
}
|
|
2466
|
-
function insertCrossReferenceField(port, { bookmark, mode, value }, caret) {
|
|
2467
|
-
caret = pastePoint(port, caret);
|
|
2468
|
-
port.setCaret(caret);
|
|
2469
|
-
if (!port.paste(`<w:p>${crossReferenceXml(bookmark, mode, value)}</w:p>`, value, false))
|
|
2470
|
-
throw new Error("The cross-reference could not be inserted.");
|
|
2471
|
-
port.setCaret({ paragraphId: caret.paragraphId, offset: caret.offset + 1 });
|
|
2472
|
-
return { bookmark };
|
|
2473
|
-
}
|
|
2474
|
-
function insertCrossReference(port, target, mode, caret) {
|
|
2475
|
-
return insertCrossReferenceField(port, markCrossReferenceTarget(port, target, mode), caret);
|
|
2476
|
-
}
|
|
2477
|
-
var documentReferenceTooltip = (text, appName = "ARBI") => `Cross-reference: ${text} \u2014 opens in ${appName}`;
|
|
2478
|
-
function insertDocumentReference(port, reference, caret) {
|
|
2479
|
-
const text = reference.text.trim();
|
|
2480
|
-
if (!text) throw new Error("Enter the reference text.");
|
|
2481
|
-
const tooltip = documentReferenceTooltip(text, reference.appName).slice(0, 255);
|
|
2482
|
-
caret = pastePoint(port, caret);
|
|
2483
|
-
port.setCaret(caret);
|
|
2484
|
-
const link = `<w:p><w:hyperlink r:id="rIdRef1"${tooltip ? ` w:tooltip="${chunk2A4MDHJR_cjs.esc(tooltip)}"` : ""} w:history="1">${run(text, CROSS_REFERENCE_STYLE)}</w:hyperlink></w:p>`;
|
|
2485
|
-
if (!port.paste(link, text, false, chunk2A4MDHJR_cjs.hyperlinkRelationship("rIdRef1", reference.url)))
|
|
2486
|
-
throw new Error("The reference could not be inserted.");
|
|
2487
|
-
port.setCaret({ paragraphId: caret.paragraphId, offset: caret.offset + text.length });
|
|
2488
|
-
}
|
|
2489
|
-
var REF_FIELD = /^REF\s+(\S+)((?:\s+\\[A-Za-z*]+(?:\s+MERGEFORMAT)?)*)\s*$/i;
|
|
2490
|
-
function staleCrossReferences(port) {
|
|
2491
|
-
const paragraphs = port.paragraphs();
|
|
2492
|
-
if (!paragraphs.some((p) => p.fields?.length)) return [];
|
|
2493
|
-
const items = port.listItems();
|
|
2494
|
-
const order = paragraphs.map((p) => p.id);
|
|
2495
|
-
const owner = /* @__PURE__ */ new Map();
|
|
2496
|
-
for (const p of paragraphs) for (const b of p.bookmarks) if (!owner.has(b)) owner.set(b, p.id);
|
|
2497
|
-
const out = [];
|
|
2498
|
-
for (const p of paragraphs)
|
|
2499
|
-
for (const field of p.fields ?? []) {
|
|
2500
|
-
const match = REF_FIELD.exec(field.instruction);
|
|
2501
|
-
if (!match || !match[1].startsWith(REF_BOOKMARK_PREFIX)) continue;
|
|
2502
|
-
const switches = match[2].toLowerCase();
|
|
2503
|
-
const mode = /\\[rwn]\b/.test(switches) ? "number" : "text";
|
|
2504
|
-
const target = owner.get(match[1]);
|
|
2505
|
-
const base = {
|
|
2506
|
-
paragraphId: p.id,
|
|
2507
|
-
offset: field.offset,
|
|
2508
|
-
instruction: field.instruction,
|
|
2509
|
-
cached: field.result,
|
|
2510
|
-
bookmark: match[1],
|
|
2511
|
-
mode
|
|
2512
|
-
};
|
|
2513
|
-
if (!target) {
|
|
2514
|
-
out.push({ ...base, value: null });
|
|
2515
|
-
continue;
|
|
2516
|
-
}
|
|
2517
|
-
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();
|
|
2518
|
-
if (value && value !== field.result.trim()) out.push({ ...base, value });
|
|
2481
|
+
function RibbonItem({
|
|
2482
|
+
id,
|
|
2483
|
+
label,
|
|
2484
|
+
priority = 0,
|
|
2485
|
+
children
|
|
2486
|
+
}) {
|
|
2487
|
+
const context = React4.useContext(Overflow);
|
|
2488
|
+
const element = React4.useRef(null);
|
|
2489
|
+
const register = context?.register;
|
|
2490
|
+
React4.useLayoutEffect(() => {
|
|
2491
|
+
if (!register || !element.current) return;
|
|
2492
|
+
return register(id, { label, priority, element: element.current });
|
|
2493
|
+
}, [register, id, label, priority]);
|
|
2494
|
+
if (!context) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
2495
|
+
const collapsed = context.collapsed.has(id);
|
|
2496
|
+
const slot = context.slots[id];
|
|
2497
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2498
|
+
"span",
|
|
2499
|
+
{
|
|
2500
|
+
ref: element,
|
|
2501
|
+
className: "native-docx-ribbon-item",
|
|
2502
|
+
"data-ribbon-item": id,
|
|
2503
|
+
hidden: collapsed || void 0,
|
|
2504
|
+
children: collapsed ? slot ? reactDom.createPortal(children, slot) : null : children
|
|
2519
2505
|
}
|
|
2520
|
-
return out;
|
|
2521
|
-
}
|
|
2522
|
-
function brokenCrossReferences(port) {
|
|
2523
|
-
return port.paragraphs().flatMap(
|
|
2524
|
-
(p) => (p.marks ?? []).filter((m) => m.styleId === BROKEN_CROSS_REFERENCE_STYLE).map((m) => ({ paragraphId: p.id, offset: m.offset, text: m.text }))
|
|
2525
2506
|
);
|
|
2526
2507
|
}
|
|
2527
|
-
function refreshCrossReferences(port) {
|
|
2528
|
-
const stale = staleCrossReferences(port).sort(
|
|
2529
|
-
(a, b) => a.paragraphId === b.paragraphId ? b.offset - a.offset : 0
|
|
2530
|
-
);
|
|
2531
|
-
let refreshed = 0;
|
|
2532
|
-
for (const ref of stale) {
|
|
2533
|
-
const paragraph = port.paragraphs().find((p) => p.id === ref.paragraphId);
|
|
2534
|
-
if (!paragraph || paragraph.text[ref.offset - 1] === FIELD_ATOM) continue;
|
|
2535
|
-
const at = { paragraphId: ref.paragraphId, offset: ref.offset };
|
|
2536
|
-
port.deleteRange(at, { paragraphId: ref.paragraphId, offset: ref.offset + 1 });
|
|
2537
|
-
port.setCaret(at);
|
|
2538
|
-
const text = ref.value ?? (ref.cached.trim() || ref.bookmark);
|
|
2539
|
-
const body = ref.value === null ? run(text, BROKEN_CROSS_REFERENCE_STYLE) : crossReferenceXml(ref.bookmark, ref.mode, ref.value);
|
|
2540
|
-
if (port.paste(`<w:p>${body}</w:p>`, text, false) && ref.value !== null) refreshed++;
|
|
2541
|
-
}
|
|
2542
|
-
return { refreshed, broken: brokenCrossReferences(port) };
|
|
2543
|
-
}
|
|
2544
2508
|
|
|
2545
|
-
// src/docx/
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
const
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
function passageClause(text) {
|
|
2552
|
-
const first = text.trim().split("\n")[0] ?? "";
|
|
2553
|
-
const match = /^(?:#+\s*)?(?:\*\*)?(?:clause|section|article)?\s*(\d+(?:\.\d+)*)[.)]?(?:\*\*)?\s+\S/i.exec(
|
|
2554
|
-
first
|
|
2555
|
-
);
|
|
2556
|
-
return match ? match[1] : null;
|
|
2557
|
-
}
|
|
2558
|
-
function referenceText(title, passage) {
|
|
2559
|
-
const name = shortTitle(title);
|
|
2560
|
-
const clause = passageClause(passage.text);
|
|
2561
|
-
if (clause) return `${name}, clause ${clause}`;
|
|
2562
|
-
if (passage.page) return `${name}, p. ${passage.page}`;
|
|
2563
|
-
return name;
|
|
2509
|
+
// src/docx/wordStyles.ts
|
|
2510
|
+
var QUICK_STYLES = ["Normal", "Title", "heading 1", "heading 2", "heading 3"];
|
|
2511
|
+
function findStyle(options, name) {
|
|
2512
|
+
const wanted = name.toLowerCase();
|
|
2513
|
+
const id = name.replace(/(^|\s)(\w)/g, (_, _s, c) => c.toUpperCase());
|
|
2514
|
+
return options.find((o) => o.name.toLowerCase() === wanted) ?? options.find((o) => o.styleId.toLowerCase() === id.toLowerCase());
|
|
2564
2515
|
}
|
|
2565
|
-
function
|
|
2566
|
-
|
|
2567
|
-
return plain.length > max ? `${plain.slice(0, max - 1)}\u2026` : plain;
|
|
2516
|
+
function styleLabel(name) {
|
|
2517
|
+
return name === name.toLowerCase() ? name.replace(/(^|\s)(\w)/g, (m) => m.toUpperCase()) : name;
|
|
2568
2518
|
}
|
|
2569
|
-
function
|
|
2570
|
-
const
|
|
2571
|
-
|
|
2519
|
+
function wordShortcut(event) {
|
|
2520
|
+
const mod = event.ctrlKey || event.metaKey;
|
|
2521
|
+
if (!mod) return null;
|
|
2522
|
+
if (event.altKey && !event.shiftKey) {
|
|
2523
|
+
switch (event.code) {
|
|
2524
|
+
case "KeyF":
|
|
2525
|
+
return "footnote";
|
|
2526
|
+
case "KeyD":
|
|
2527
|
+
return "endnote";
|
|
2528
|
+
case "Digit1":
|
|
2529
|
+
case "Numpad1":
|
|
2530
|
+
return "heading 1";
|
|
2531
|
+
case "Digit2":
|
|
2532
|
+
case "Numpad2":
|
|
2533
|
+
return "heading 2";
|
|
2534
|
+
case "Digit3":
|
|
2535
|
+
case "Numpad3":
|
|
2536
|
+
return "heading 3";
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2539
|
+
if (event.shiftKey && !event.altKey && event.code === "KeyN") return "Normal";
|
|
2540
|
+
return null;
|
|
2572
2541
|
}
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
const
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2542
|
+
function divergenceSummary(divergence) {
|
|
2543
|
+
if (!divergence) return null;
|
|
2544
|
+
const changed = divergence.styles.filter((s) => s.kind === "changed").map((s) => styleLabel(s.name));
|
|
2545
|
+
const missing = divergence.styles.filter((s) => s.kind === "missing").map((s) => styleLabel(s.name));
|
|
2546
|
+
const parts = [
|
|
2547
|
+
divergence.docDefaults ? "default text formatting" : "",
|
|
2548
|
+
changed.length ? `${changed.length === 1 ? "style" : "styles"} ${changed.slice(0, 6).join(", ")}${changed.length > 6 ? "\u2026" : ""}` : "",
|
|
2549
|
+
missing.length ? `${missing.length} house ${missing.length === 1 ? "style" : "styles"} missing` : ""
|
|
2550
|
+
].filter(Boolean);
|
|
2551
|
+
return parts.length ? `Differs from the house template: ${parts.join("; ")}.` : null;
|
|
2581
2552
|
}
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
runs.push(serialize(child));
|
|
2589
|
-
}
|
|
2590
|
-
return runs.length ? runs.join("") : null;
|
|
2553
|
+
var BUILTIN_TEMPLATE_NAME = "ARBI legal template";
|
|
2554
|
+
var templateFileName = (t) => /\.(dotx|dotm|docx|docm)$/i.test(t.name) ? t.name : `${t.name}.dotx`;
|
|
2555
|
+
var builtin;
|
|
2556
|
+
function builtinHouseTemplate() {
|
|
2557
|
+
builtin ??= { bytes: template.defaultLegalTemplate(), name: BUILTIN_TEMPLATE_NAME, source: "builtin" };
|
|
2558
|
+
return builtin;
|
|
2591
2559
|
}
|
|
2592
|
-
function
|
|
2593
|
-
if (
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2560
|
+
async function resolveHouseTemplate(host) {
|
|
2561
|
+
if (!host) return builtinHouseTemplate();
|
|
2562
|
+
try {
|
|
2563
|
+
return await host.load();
|
|
2564
|
+
} catch {
|
|
2565
|
+
return builtinHouseTemplate();
|
|
2597
2566
|
}
|
|
2598
|
-
return void 0;
|
|
2599
2567
|
}
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
if (!s) throw new Error("The document is not open.");
|
|
2605
|
-
return s;
|
|
2606
|
-
};
|
|
2607
|
-
const root = () => session().part().root;
|
|
2608
|
-
let numbering;
|
|
2609
|
-
let cascade;
|
|
2610
|
-
const index = () => {
|
|
2611
|
-
if (!numbering) {
|
|
2612
|
-
const s = session();
|
|
2613
|
-
cascade = layout.buildStyleCascadeTable(s.stylesRoot(), void 0, s.settingsRoot());
|
|
2614
|
-
numbering = layout.withNumberingStyleLinks(layout.buildNumberingIndex(s.numberingRoot()), cascade);
|
|
2615
|
-
}
|
|
2616
|
-
return numbering;
|
|
2617
|
-
};
|
|
2618
|
-
return {
|
|
2619
|
-
...base,
|
|
2620
|
-
listItems: () => {
|
|
2621
|
-
const body = root().children?.find((n) => n.kind === "body");
|
|
2622
|
-
const items = layout.resolveStoryListItems(
|
|
2623
|
-
body?.children ?? [],
|
|
2624
|
-
index(),
|
|
2625
|
-
cascade
|
|
2626
|
-
);
|
|
2627
|
-
const out = /* @__PURE__ */ new Map();
|
|
2628
|
-
for (const [id, item] of items)
|
|
2629
|
-
out.set(id, {
|
|
2630
|
-
numId: item.numId,
|
|
2631
|
-
ilvl: item.ilvl,
|
|
2632
|
-
markerText: item.markerText,
|
|
2633
|
-
numFmt: item.numFmt
|
|
2634
|
-
});
|
|
2635
|
-
return out;
|
|
2636
|
-
},
|
|
2637
|
-
levelOf: (numId, ilvl) => {
|
|
2638
|
-
const level = layout.resolveNumberingLevel(index(), numId, ilvl)?.level;
|
|
2639
|
-
return level ? { lvlText: level.lvlText, numFmt: level.numFmt } : null;
|
|
2640
|
-
},
|
|
2641
|
-
runsXml: (paragraphId) => {
|
|
2642
|
-
const node = findNode2(root(), paragraphId);
|
|
2643
|
-
return node ? paragraphRunsXml(node) : null;
|
|
2644
|
-
}
|
|
2645
|
-
};
|
|
2646
|
-
}
|
|
2647
|
-
|
|
2648
|
-
// src/docx/beforeSave.ts
|
|
2649
|
-
var hooks = /* @__PURE__ */ new WeakMap();
|
|
2650
|
-
function onBeforeSave(editor, fn) {
|
|
2651
|
-
let set = hooks.get(editor);
|
|
2652
|
-
if (!set) hooks.set(editor, set = /* @__PURE__ */ new Set());
|
|
2653
|
-
set.add(fn);
|
|
2654
|
-
return () => set.delete(fn);
|
|
2655
|
-
}
|
|
2656
|
-
function runBeforeSave(editor) {
|
|
2657
|
-
if (!editor) return;
|
|
2658
|
-
for (const fn of hooks.get(editor) ?? [])
|
|
2659
|
-
try {
|
|
2660
|
-
fn();
|
|
2661
|
-
} catch {
|
|
2662
|
-
}
|
|
2663
|
-
}
|
|
2664
|
-
var DEFAULT_CROSS_REFERENCES_LABELS = {
|
|
2665
|
-
insert: "Insert cross-reference",
|
|
2666
|
-
title: "Insert cross-reference",
|
|
2667
|
-
description: "Refer to a clause of this document, or to a passage of another document.",
|
|
2668
|
-
thisDocument: "This document",
|
|
2669
|
-
otherDocument: "Another document",
|
|
2670
|
-
filterTargets: "Find a clause or heading",
|
|
2671
|
-
noTargets: "This document has no numbered clauses or headings yet.",
|
|
2672
|
-
number: "Paragraph number",
|
|
2673
|
-
text: "Heading text",
|
|
2674
|
-
insertAs: "Insert",
|
|
2675
|
-
chooseDocument: "Choose a document",
|
|
2676
|
-
filterPassages: "Find a passage",
|
|
2677
|
-
loadingPassages: "Loading passages\u2026",
|
|
2678
|
-
noPassages: "No passage matches.",
|
|
2679
|
-
referenceText: "Reference text",
|
|
2680
|
-
insertButton: "Insert",
|
|
2681
|
-
cancel: "Cancel",
|
|
2682
|
-
clause: (number) => `Clause ${number}`,
|
|
2683
|
-
heading: "Heading",
|
|
2684
|
-
update: "Update cross-references",
|
|
2685
|
-
updated: "Cross-references updated",
|
|
2686
|
-
updateSummary: (refreshed) => refreshed ? `${refreshed} cross-reference${refreshed === 1 ? "" : "s"} brought up to date.` : "Every cross-reference is up to date.",
|
|
2687
|
-
brokenTitle: "Broken cross-references",
|
|
2688
|
-
brokenNone: "No cross-reference points at a deleted target.",
|
|
2689
|
-
brokenHelp: "Their target was deleted: the last text is kept and marked. Insert the reference again to repair it.",
|
|
2690
|
-
brokenCard: "Broken cross-reference",
|
|
2691
|
-
brokenCardBody: "Its target was deleted. Update cross-references to mark it.",
|
|
2692
|
-
show: "Show",
|
|
2693
|
-
close: "Close"
|
|
2694
|
-
};
|
|
2695
|
-
var CrossReferencesContext = React4.createContext(null);
|
|
2696
|
-
var useCrossReferences = () => React4.useContext(CrossReferencesContext);
|
|
2697
|
-
function CrossReferencesProvider({
|
|
2698
|
-
children,
|
|
2699
|
-
editable,
|
|
2700
|
-
references,
|
|
2568
|
+
var HouseTemplateContext = React4.createContext(null);
|
|
2569
|
+
var useHouseTemplate = () => React4.useContext(HouseTemplateContext);
|
|
2570
|
+
function HouseTemplateProvider({
|
|
2571
|
+
host,
|
|
2701
2572
|
documentId,
|
|
2573
|
+
editable,
|
|
2702
2574
|
notify,
|
|
2703
|
-
|
|
2575
|
+
enabled = true,
|
|
2576
|
+
children
|
|
2704
2577
|
}) {
|
|
2705
2578
|
const editor = react.useDocxEditor();
|
|
2706
2579
|
const track = useTrackedOrNoted();
|
|
2707
|
-
const
|
|
2708
|
-
const [
|
|
2709
|
-
|
|
2710
|
-
);
|
|
2711
|
-
const
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2580
|
+
const [template$1, setTemplate] = React4.useState(builtinHouseTemplate);
|
|
2581
|
+
const [divergence, setDivergence] = React4.useState(null);
|
|
2582
|
+
const [basedOnTemplate, setBasedOnTemplate] = React4.useState(false);
|
|
2583
|
+
const [levels, setLevels] = React4.useState({});
|
|
2584
|
+
const [generation, setGeneration] = React4.useState(0);
|
|
2585
|
+
React4.useEffect(() => {
|
|
2586
|
+
let live = true;
|
|
2587
|
+
void resolveHouseTemplate(host).then((t) => live && setTemplate(t));
|
|
2588
|
+
return () => {
|
|
2589
|
+
live = false;
|
|
2590
|
+
};
|
|
2591
|
+
}, [host]);
|
|
2592
|
+
const blocks = React4.useMemo(() => {
|
|
2716
2593
|
try {
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
setDialog({ caret, targets: listTargets(port.paragraphs(), port.listItems(), port.levelOf) });
|
|
2721
|
-
} catch (error) {
|
|
2722
|
-
notify?.(error instanceof Error ? error.message : "Could not read the document.", "error");
|
|
2594
|
+
return template.listBuildingBlocks(template$1.bytes);
|
|
2595
|
+
} catch {
|
|
2596
|
+
return [];
|
|
2723
2597
|
}
|
|
2724
|
-
}, [
|
|
2725
|
-
|
|
2726
|
-
(
|
|
2727
|
-
|
|
2598
|
+
}, [template$1]);
|
|
2599
|
+
React4.useEffect(() => {
|
|
2600
|
+
if (!editor || !enabled) return;
|
|
2601
|
+
let live = true;
|
|
2602
|
+
void editor.save().then((saved) => {
|
|
2603
|
+
if (!live || !saved) return;
|
|
2604
|
+
const bytes = new Uint8Array(saved);
|
|
2605
|
+
setBasedOnTemplate(template.attachedTemplateOf(bytes) === templateFileName(template$1));
|
|
2606
|
+
setLevels(template.linkedLevelStyles(bytes));
|
|
2607
|
+
setDivergence(template.styleDivergence(bytes, template$1.bytes));
|
|
2608
|
+
}).catch(() => live && setDivergence(null));
|
|
2609
|
+
return () => {
|
|
2610
|
+
live = false;
|
|
2611
|
+
};
|
|
2612
|
+
}, [editor, template$1, generation, enabled]);
|
|
2613
|
+
const refresh = React4.useCallback(() => setGeneration((g) => g + 1), []);
|
|
2614
|
+
const insertBlock = React4.useCallback(
|
|
2615
|
+
(name) => {
|
|
2616
|
+
if (!editor || !editable) return false;
|
|
2617
|
+
const fragment = template.buildingBlockFragment(template$1.bytes, name);
|
|
2618
|
+
if (!fragment) return false;
|
|
2728
2619
|
try {
|
|
2729
|
-
const
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2620
|
+
const result = track({
|
|
2621
|
+
label: `Inserted Quick Part: ${name}`,
|
|
2622
|
+
insert: (revision) => editor.exec({
|
|
2623
|
+
type: "paste",
|
|
2624
|
+
text: "",
|
|
2625
|
+
html: template.fragmentClipboardHtml(
|
|
2626
|
+
revision ? template.trackInsertion(fragment, revision, true) : fragment
|
|
2627
|
+
)
|
|
2628
|
+
}),
|
|
2629
|
+
inserted: (r) => r.ok
|
|
2630
|
+
})?.result;
|
|
2631
|
+
if (!result?.ok) throw new Error(result?.reason ?? "The block could not be inserted here.");
|
|
2632
|
+
refresh();
|
|
2633
|
+
return true;
|
|
2634
|
+
} catch (failure) {
|
|
2736
2635
|
notify?.(
|
|
2737
|
-
|
|
2636
|
+
failure instanceof Error ? failure.message : "Could not insert the block.",
|
|
2738
2637
|
"error"
|
|
2739
2638
|
);
|
|
2639
|
+
return false;
|
|
2740
2640
|
}
|
|
2741
2641
|
},
|
|
2742
|
-
[editor,
|
|
2642
|
+
[editor, editable, template$1, notify, refresh, track]
|
|
2743
2643
|
);
|
|
2744
|
-
React4.
|
|
2745
|
-
|
|
2746
|
-
const refresh = () => {
|
|
2644
|
+
const setAsHouseTemplate = React4.useMemo(
|
|
2645
|
+
() => host?.setFromDocument && documentId ? async () => {
|
|
2747
2646
|
try {
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
} catch {
|
|
2647
|
+
await host.setFromDocument(documentId);
|
|
2648
|
+
setTemplate(await resolveHouseTemplate(host));
|
|
2649
|
+
notify?.("This document is now the house template for new documents.", "success");
|
|
2650
|
+
} catch (failure) {
|
|
2651
|
+
notify?.(
|
|
2652
|
+
failure instanceof Error ? failure.message : "Could not set the house template.",
|
|
2653
|
+
"error"
|
|
2654
|
+
);
|
|
2752
2655
|
}
|
|
2753
|
-
}
|
|
2754
|
-
|
|
2755
|
-
const timer = setTimeout(refresh, 1500);
|
|
2756
|
-
return () => {
|
|
2757
|
-
off();
|
|
2758
|
-
clearTimeout(timer);
|
|
2759
|
-
};
|
|
2760
|
-
}, [editor, editable]);
|
|
2761
|
-
const [report, setReport] = React4.useState(null);
|
|
2762
|
-
const update = React4.useCallback(() => {
|
|
2763
|
-
if (!editor || !editable) return;
|
|
2764
|
-
try {
|
|
2765
|
-
const result = preservingCaret(
|
|
2766
|
-
editor,
|
|
2767
|
-
() => withDirectEditing(editor, () => refreshCrossReferences(referencesPort(editor)))
|
|
2768
|
-
);
|
|
2769
|
-
setReport(result);
|
|
2770
|
-
} catch (error) {
|
|
2771
|
-
notify?.(
|
|
2772
|
-
error instanceof Error ? error.message : "Could not update cross-references.",
|
|
2773
|
-
"error"
|
|
2774
|
-
);
|
|
2775
|
-
}
|
|
2776
|
-
}, [editor, editable, notify]);
|
|
2777
|
-
const [passages, setPassages] = React4.useState({});
|
|
2778
|
-
const loadPassages = React4.useCallback(
|
|
2779
|
-
(id) => {
|
|
2780
|
-
if (!references || passages[id]) return;
|
|
2781
|
-
setPassages((p) => ({ ...p, [id]: "loading" }));
|
|
2782
|
-
references.passages(id).then((list) => setPassages((p) => ({ ...p, [id]: list }))).catch(() => setPassages((p) => ({ ...p, [id]: [] })));
|
|
2783
|
-
},
|
|
2784
|
-
[references, passages]
|
|
2656
|
+
} : void 0,
|
|
2657
|
+
[host, documentId, notify]
|
|
2785
2658
|
);
|
|
2786
|
-
React4.useEffect(() => {
|
|
2787
|
-
if (!viewer || !references) return;
|
|
2788
|
-
const targetOf = (event) => {
|
|
2789
|
-
const link = event.target?.closest?.(
|
|
2790
|
-
'a.docx-hyperlink[data-docx-link-kind="external"]'
|
|
2791
|
-
);
|
|
2792
|
-
if (!link || !viewer.contains(link)) return null;
|
|
2793
|
-
const mouse = event;
|
|
2794
|
-
if (mouse.button !== 0 || mouse.ctrlKey || mouse.metaKey || mouse.shiftKey) return null;
|
|
2795
|
-
return references.targetOf(link.getAttribute("href") ?? "");
|
|
2796
|
-
};
|
|
2797
|
-
const take = (event) => {
|
|
2798
|
-
const target = targetOf(event);
|
|
2799
|
-
if (!target) return;
|
|
2800
|
-
event.preventDefault();
|
|
2801
|
-
event.stopPropagation();
|
|
2802
|
-
if (event.type === "click") references.open(target);
|
|
2803
|
-
};
|
|
2804
|
-
const types = ["pointerdown", "mousedown", "pointerup", "mouseup", "click"];
|
|
2805
|
-
for (const type of types) window.addEventListener(type, take, true);
|
|
2806
|
-
return () => {
|
|
2807
|
-
for (const type of types) window.removeEventListener(type, take, true);
|
|
2808
|
-
};
|
|
2809
|
-
}, [viewer, references]);
|
|
2810
2659
|
const value = React4.useMemo(
|
|
2811
|
-
() =>
|
|
2812
|
-
|
|
2660
|
+
() => ({
|
|
2661
|
+
template: template$1,
|
|
2662
|
+
blocks,
|
|
2663
|
+
divergence,
|
|
2664
|
+
basedOnTemplate,
|
|
2665
|
+
levels,
|
|
2666
|
+
insertBlock,
|
|
2667
|
+
refresh,
|
|
2668
|
+
setAsHouseTemplate,
|
|
2669
|
+
editable
|
|
2670
|
+
}),
|
|
2671
|
+
[
|
|
2672
|
+
template$1,
|
|
2673
|
+
blocks,
|
|
2674
|
+
divergence,
|
|
2675
|
+
basedOnTemplate,
|
|
2676
|
+
levels,
|
|
2677
|
+
insertBlock,
|
|
2678
|
+
refresh,
|
|
2679
|
+
setAsHouseTemplate,
|
|
2680
|
+
editable
|
|
2681
|
+
]
|
|
2813
2682
|
);
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
target.id
|
|
2827
|
-
);
|
|
2828
|
-
return {
|
|
2829
|
-
title: number ? l.clause(number) : l.heading,
|
|
2830
|
-
body: passageExcerpt(target.text.replace(//g, ""))
|
|
2831
|
-
};
|
|
2832
|
-
} catch {
|
|
2833
|
-
return null;
|
|
2834
|
-
}
|
|
2683
|
+
return /* @__PURE__ */ jsxRuntime.jsx(HouseTemplateContext.Provider, { value: enabled ? value : null, children });
|
|
2684
|
+
}
|
|
2685
|
+
var FILTER_FROM = 8;
|
|
2686
|
+
function previewStyle(option) {
|
|
2687
|
+
const { fontFamily, fontSizePt, bold, italic, color } = option.preview;
|
|
2688
|
+
return {
|
|
2689
|
+
fontFamily: fontFamily ? `"${fontFamily}", serif` : void 0,
|
|
2690
|
+
// In the face of the style, but within a row: 9-18pt.
|
|
2691
|
+
fontSize: fontSizePt ? `${Math.min(18, Math.max(9, fontSizePt))}pt` : void 0,
|
|
2692
|
+
fontWeight: bold ? 700 : void 0,
|
|
2693
|
+
fontStyle: italic ? "italic" : void 0,
|
|
2694
|
+
color: color ? `#${color}` : void 0
|
|
2835
2695
|
};
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2696
|
+
}
|
|
2697
|
+
function Gallery({ close }) {
|
|
2698
|
+
const { value, setValue, options, isEnabled } = react.useParagraphStyle();
|
|
2699
|
+
const editor = react.useDocxEditor();
|
|
2700
|
+
const house = useHouseTemplate();
|
|
2701
|
+
const changed = new Set(
|
|
2702
|
+
house?.basedOnTemplate ? house.divergence?.styles.filter((s) => s.kind === "changed").map((s) => s.styleId) : []
|
|
2703
|
+
);
|
|
2704
|
+
const [query, setQuery] = React4.useState("");
|
|
2705
|
+
const quick = React4.useMemo(
|
|
2706
|
+
() => QUICK_STYLES.map((name) => findStyle(options, name)).filter(
|
|
2707
|
+
(o) => !!o
|
|
2847
2708
|
),
|
|
2848
|
-
|
|
2849
|
-
|
|
2709
|
+
[options]
|
|
2710
|
+
);
|
|
2711
|
+
const shown = React4.useMemo(() => {
|
|
2712
|
+
const q = query.trim().toLowerCase();
|
|
2713
|
+
return q ? options.filter(
|
|
2714
|
+
(o) => o.name.toLowerCase().includes(q) || o.styleId.toLowerCase().includes(q)
|
|
2715
|
+
) : options;
|
|
2716
|
+
}, [options, query]);
|
|
2717
|
+
const apply = (option) => {
|
|
2718
|
+
setValue(option.styleId);
|
|
2719
|
+
close();
|
|
2720
|
+
editor?.surface?.focus();
|
|
2721
|
+
};
|
|
2722
|
+
const nav = chunk7UTB4PHM_cjs.useListKeyNav({
|
|
2723
|
+
open: true,
|
|
2724
|
+
items: shown,
|
|
2725
|
+
onPick: apply,
|
|
2726
|
+
onDismiss: close,
|
|
2727
|
+
resetKey: query
|
|
2728
|
+
});
|
|
2729
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "native-docx-style-gallery", "data-testid": "docx-style-gallery", children: [
|
|
2730
|
+
quick.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "native-docx-style-quick", role: "group", "aria-label": "Quick styles", children: quick.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2731
|
+
"button",
|
|
2850
2732
|
{
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
},
|
|
2864
|
-
testId: "docx-cross-reference-card"
|
|
2865
|
-
}
|
|
2866
|
-
),
|
|
2867
|
-
dialog && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2868
|
-
CrossReferenceDialog,
|
|
2733
|
+
type: "button",
|
|
2734
|
+
"aria-pressed": value === option.styleId,
|
|
2735
|
+
disabled: !isEnabled,
|
|
2736
|
+
"data-style-id": option.styleId,
|
|
2737
|
+
title: styleLabel(option.name),
|
|
2738
|
+
onClick: () => apply(option),
|
|
2739
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: previewStyle(option), children: styleLabel(option.name) })
|
|
2740
|
+
},
|
|
2741
|
+
option.styleId
|
|
2742
|
+
)) }),
|
|
2743
|
+
options.length > FILTER_FROM && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2744
|
+
"input",
|
|
2869
2745
|
{
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
() => markCrossReferenceTarget(referencesPort(editor), target, mode),
|
|
2881
|
-
(marked, revision) => insertCrossReferenceField(referencesPort(editor, revision), marked, dialog.caret)
|
|
2882
|
-
),
|
|
2883
|
-
onInsertPassage: (target, text) => run2(
|
|
2884
|
-
`Inserted cross-reference: ${text}`,
|
|
2885
|
-
() => void 0,
|
|
2886
|
-
(_, revision) => insertDocumentReference(
|
|
2887
|
-
referencesPort(editor, revision),
|
|
2888
|
-
{ text, url: references.linkFor(target), appName: references.appName },
|
|
2889
|
-
dialog.caret
|
|
2890
|
-
)
|
|
2891
|
-
)
|
|
2746
|
+
className: "native-docx-style-filter",
|
|
2747
|
+
placeholder: "Find a style",
|
|
2748
|
+
"aria-label": "Find a style",
|
|
2749
|
+
value: query,
|
|
2750
|
+
autoFocus: true,
|
|
2751
|
+
onChange: (event) => setQuery(event.target.value),
|
|
2752
|
+
onKeyDown: (event) => {
|
|
2753
|
+
nav.handleKeyDown(event);
|
|
2754
|
+
},
|
|
2755
|
+
...nav.comboboxProps
|
|
2892
2756
|
}
|
|
2893
2757
|
),
|
|
2894
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2895
|
-
|
|
2758
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2759
|
+
"ul",
|
|
2896
2760
|
{
|
|
2897
|
-
className: "
|
|
2898
|
-
|
|
2761
|
+
className: "native-docx-style-list",
|
|
2762
|
+
role: "listbox",
|
|
2763
|
+
id: nav.listboxId,
|
|
2764
|
+
"aria-label": "Document styles",
|
|
2899
2765
|
children: [
|
|
2900
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
}
|
|
2927
|
-
)
|
|
2928
|
-
]
|
|
2929
|
-
},
|
|
2930
|
-
`${b.paragraphId}:${b.offset}`
|
|
2931
|
-
)) })
|
|
2932
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: l.brokenNone })
|
|
2933
|
-
] }),
|
|
2934
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.DialogFooter, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "outline", onClick: () => setReport(null), children: l.close }) })
|
|
2766
|
+
shown.map((option, index) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2767
|
+
"li",
|
|
2768
|
+
{
|
|
2769
|
+
id: chunk7UTB4PHM_cjs.listOptionId(nav.listboxId, index),
|
|
2770
|
+
role: "option",
|
|
2771
|
+
"aria-selected": value === option.styleId,
|
|
2772
|
+
"aria-disabled": !isEnabled,
|
|
2773
|
+
"data-active": index === nav.selectedIndex || void 0,
|
|
2774
|
+
"data-style-id": option.styleId,
|
|
2775
|
+
onMouseEnter: () => nav.setSelectedIndex(index),
|
|
2776
|
+
onClick: () => isEnabled && apply(option),
|
|
2777
|
+
children: [
|
|
2778
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: previewStyle(option), children: styleLabel(option.name) }),
|
|
2779
|
+
changed.has(option.styleId) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2780
|
+
"span",
|
|
2781
|
+
{
|
|
2782
|
+
className: "native-docx-style-diverged",
|
|
2783
|
+
title: "Defined differently from the house template",
|
|
2784
|
+
"aria-label": "Defined differently from the house template"
|
|
2785
|
+
}
|
|
2786
|
+
)
|
|
2787
|
+
]
|
|
2788
|
+
},
|
|
2789
|
+
option.styleId
|
|
2790
|
+
)),
|
|
2791
|
+
shown.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("li", { className: "native-docx-style-empty", children: "No matching style" })
|
|
2935
2792
|
]
|
|
2936
2793
|
}
|
|
2937
|
-
)
|
|
2794
|
+
)
|
|
2938
2795
|
] });
|
|
2939
2796
|
}
|
|
2940
|
-
function
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
const
|
|
2977
|
-
const
|
|
2797
|
+
function StyleGallery() {
|
|
2798
|
+
const { value, options } = react.useParagraphStyle();
|
|
2799
|
+
const current = options.find((o) => o.styleId === value);
|
|
2800
|
+
const name = current ? styleLabel(current.name) : "Styles";
|
|
2801
|
+
const house = useHouseTemplate();
|
|
2802
|
+
const diverged = house?.basedOnTemplate ? divergenceSummary(house.divergence) : null;
|
|
2803
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2804
|
+
RibbonMenu,
|
|
2805
|
+
{
|
|
2806
|
+
label: "Styles",
|
|
2807
|
+
title: diverged ? `Styles. ${diverged}` : void 0,
|
|
2808
|
+
className: "native-docx-style-trigger",
|
|
2809
|
+
testId: "docx-style-trigger",
|
|
2810
|
+
icon: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2811
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "native-docx-style-current", "data-testid": "docx-current-style", children: name }),
|
|
2812
|
+
diverged && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2813
|
+
"span",
|
|
2814
|
+
{
|
|
2815
|
+
className: "native-docx-style-diverged",
|
|
2816
|
+
"data-testid": "docx-style-diverged",
|
|
2817
|
+
"aria-label": diverged
|
|
2818
|
+
}
|
|
2819
|
+
),
|
|
2820
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { size: 12, "aria-hidden": true })
|
|
2821
|
+
] }),
|
|
2822
|
+
children: (close) => /* @__PURE__ */ jsxRuntime.jsx(Gallery, { close })
|
|
2823
|
+
}
|
|
2824
|
+
);
|
|
2825
|
+
}
|
|
2826
|
+
var W = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
|
|
2827
|
+
var DEFAULT_PARAGRAPH_FONT = {
|
|
2828
|
+
id: "DefaultParagraphFont",
|
|
2829
|
+
type: "character",
|
|
2830
|
+
xml: '<w:style w:type="character" w:default="1" w:styleId="DefaultParagraphFont"><w:name w:val="Default Paragraph Font"/><w:uiPriority w:val="1"/><w:semiHidden/><w:unhideWhenUsed/></w:style>'
|
|
2831
|
+
};
|
|
2832
|
+
function stylesOf(kind) {
|
|
2833
|
+
const Kind = kind === "footnote" ? "Footnote" : "Endnote";
|
|
2834
|
+
const text = `${Kind}Text`;
|
|
2835
|
+
return [
|
|
2836
|
+
{
|
|
2837
|
+
id: text,
|
|
2838
|
+
type: "paragraph",
|
|
2839
|
+
xml: `<w:style w:type="paragraph" w:styleId="${text}"><w:name w:val="${kind} text"/><w:basedOn w:val="Normal"/><w:link w:val="${text}Char"/><w:uiPriority w:val="99"/><w:semiHidden/><w:unhideWhenUsed/><w:pPr><w:spacing w:after="0" w:line="240" w:lineRule="auto"/></w:pPr><w:rPr><w:sz w:val="20"/><w:szCs w:val="20"/></w:rPr></w:style>`
|
|
2840
|
+
},
|
|
2841
|
+
{
|
|
2842
|
+
id: `${text}Char`,
|
|
2843
|
+
type: "character",
|
|
2844
|
+
xml: `<w:style w:type="character" w:customStyle="1" w:styleId="${text}Char"><w:name w:val="${Kind} Text Char"/><w:basedOn w:val="DefaultParagraphFont"/><w:link w:val="${text}"/><w:uiPriority w:val="99"/><w:semiHidden/><w:rPr><w:sz w:val="20"/><w:szCs w:val="20"/></w:rPr></w:style>`
|
|
2845
|
+
},
|
|
2846
|
+
{
|
|
2847
|
+
id: `${Kind}Reference`,
|
|
2848
|
+
type: "character",
|
|
2849
|
+
xml: `<w:style w:type="character" w:styleId="${Kind}Reference"><w:name w:val="${kind} reference"/><w:basedOn w:val="DefaultParagraphFont"/><w:uiPriority w:val="99"/><w:semiHidden/><w:unhideWhenUsed/><w:rPr><w:vertAlign w:val="superscript"/></w:rPr></w:style>`
|
|
2850
|
+
}
|
|
2851
|
+
];
|
|
2852
|
+
}
|
|
2853
|
+
function noteTextStyle(styles, kind) {
|
|
2854
|
+
const paragraph = styles.filter((style) => style.type === "paragraph");
|
|
2855
|
+
const id = kind === "footnote" ? "FootnoteText" : "EndnoteText";
|
|
2856
|
+
return paragraph.find((style) => style.name.toLowerCase() === `${kind} text`)?.styleId ?? paragraph.find((style) => style.styleId === id)?.styleId;
|
|
2857
|
+
}
|
|
2858
|
+
function missingNoteStyles(styles, kind) {
|
|
2859
|
+
const has = (type, id) => styles.some((style) => style.type === type && style.styleId === id);
|
|
2860
|
+
const text = noteTextStyle(styles, kind);
|
|
2861
|
+
const missing = stylesOf(kind).filter(
|
|
2862
|
+
(style) => style.type === "paragraph" ? !text : !has("character", style.id)
|
|
2863
|
+
);
|
|
2864
|
+
if (!missing.length) return [];
|
|
2865
|
+
const base = has("character", DEFAULT_PARAGRAPH_FONT.id) ? [] : [DEFAULT_PARAGRAPH_FONT];
|
|
2866
|
+
return [...base, ...missing].map((style) => style.xml);
|
|
2867
|
+
}
|
|
2868
|
+
var CONTENT_TYPES = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/><Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/></Types>';
|
|
2869
|
+
function stylesOnlyClipboardHtml(styles) {
|
|
2870
|
+
const fragment = fflate.zipSync({
|
|
2871
|
+
"[Content_Types].xml": fflate.strToU8(CONTENT_TYPES),
|
|
2872
|
+
"_rels/.rels": fflate.strToU8(
|
|
2873
|
+
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/></Relationships>'
|
|
2874
|
+
),
|
|
2875
|
+
"word/document.xml": fflate.strToU8(
|
|
2876
|
+
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
2877
|
+
<w:document xmlns:w="${W}"><w:body><w:p/></w:body></w:document>`
|
|
2878
|
+
),
|
|
2879
|
+
"word/_rels/document.xml.rels": fflate.strToU8(
|
|
2880
|
+
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rIdStyles" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/></Relationships>'
|
|
2881
|
+
),
|
|
2882
|
+
"word/styles.xml": fflate.strToU8(
|
|
2883
|
+
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
2884
|
+
<w:styles xmlns:w="${W}">${styles.join("")}</w:styles>`
|
|
2885
|
+
)
|
|
2886
|
+
});
|
|
2887
|
+
return template.fragmentClipboardHtml(fragment, false);
|
|
2888
|
+
}
|
|
2889
|
+
function ensureNoteStyles(editor, kind, direct = (fn) => fn()) {
|
|
2890
|
+
if (!editor.can({ type: "insertNote", noteKind: kind }).ok) return void 0;
|
|
2891
|
+
const missing = missingNoteStyles(editor.getDocumentStyles(), kind);
|
|
2892
|
+
if (missing.length)
|
|
2893
|
+
direct(() => editor.exec({ type: "paste", text: "", html: stylesOnlyClipboardHtml(missing) }));
|
|
2894
|
+
return noteTextStyle(editor.getDocumentStyles(), kind);
|
|
2895
|
+
}
|
|
2896
|
+
function useInsertNote(kind) {
|
|
2897
|
+
const command = react.useEditorCommand(kind === "footnote" ? "insert.footnote" : "insert.endnote");
|
|
2898
|
+
const editor = react.useDocxEditor();
|
|
2978
2899
|
const insert = () => {
|
|
2979
|
-
|
|
2980
|
-
if (
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
text
|
|
2984
|
-
);
|
|
2900
|
+
const text = editor && ensureNoteStyles(editor, kind, (fn) => withDirectEditing(editor, fn));
|
|
2901
|
+
if (!command.execute()) return false;
|
|
2902
|
+
if (editor) {
|
|
2903
|
+
if (text)
|
|
2904
|
+
withDirectEditing(editor, () => editor.exec({ type: "setParagraphStyle", styleId: text }));
|
|
2905
|
+
editor.exec({ type: "insertText", text: " " });
|
|
2906
|
+
}
|
|
2907
|
+
return true;
|
|
2985
2908
|
};
|
|
2986
|
-
return
|
|
2987
|
-
|
|
2909
|
+
return { insert, isEnabled: command.isEnabled, disabledReason: command.disabledReason };
|
|
2910
|
+
}
|
|
2911
|
+
function NoteAction({
|
|
2912
|
+
kind,
|
|
2913
|
+
label,
|
|
2914
|
+
shortcut,
|
|
2915
|
+
icon
|
|
2916
|
+
}) {
|
|
2917
|
+
const note = useInsertNote(kind);
|
|
2918
|
+
return /* @__PURE__ */ jsxRuntime.jsx(RibbonItem, { id: `references-${kind}`, label, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2919
|
+
react.DocxEditor.Toolbar.Action,
|
|
2988
2920
|
{
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
},
|
|
2996
|
-
children: [
|
|
2997
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.DialogHeader, { children: [
|
|
2998
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.DialogTitle, { children: l.title }),
|
|
2999
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.DialogDescription, { children: l.description })
|
|
3000
|
-
] }),
|
|
3001
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.Tabs, { value: tab, onValueChange: (v) => setTab(v), children: [
|
|
3002
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.TabsList, { children: [
|
|
3003
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.TabsTrigger, { value: "this", "data-testid": "docx-cross-reference-this", children: l.thisDocument }),
|
|
3004
|
-
references && /* @__PURE__ */ jsxRuntime.jsx(ui.TabsTrigger, { value: "other", "data-testid": "docx-cross-reference-other", children: l.otherDocument })
|
|
3005
|
-
] }),
|
|
3006
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.TabsContent, { value: "this", className: "space-y-3", children: [
|
|
3007
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3008
|
-
ui.Input,
|
|
3009
|
-
{
|
|
3010
|
-
value: query,
|
|
3011
|
-
placeholder: l.filterTargets,
|
|
3012
|
-
"aria-label": l.filterTargets,
|
|
3013
|
-
onChange: (e) => setQuery(e.target.value),
|
|
3014
|
-
"data-testid": "docx-cross-reference-filter"
|
|
3015
|
-
}
|
|
3016
|
-
),
|
|
3017
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3018
|
-
"div",
|
|
3019
|
-
{
|
|
3020
|
-
role: "listbox",
|
|
3021
|
-
"aria-label": l.filterTargets,
|
|
3022
|
-
className: "max-h-64 space-y-0.5 overflow-y-auto rounded-md border border-border p-1",
|
|
3023
|
-
children: [
|
|
3024
|
-
shown.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "p-2 text-sm text-muted-foreground", children: l.noTargets }),
|
|
3025
|
-
shown.map((t) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3026
|
-
"button",
|
|
3027
|
-
{
|
|
3028
|
-
type: "button",
|
|
3029
|
-
role: "option",
|
|
3030
|
-
"aria-selected": chosen?.paragraphId === t.paragraphId,
|
|
3031
|
-
"data-testid": "docx-cross-reference-target",
|
|
3032
|
-
onClick: () => setChosen(t),
|
|
3033
|
-
onDoubleClick: () => onInsertTarget(t, t.number ? mode : "text"),
|
|
3034
|
-
className: ui.cn(
|
|
3035
|
-
"flex w-full items-baseline gap-2 rounded px-2 py-1 text-left text-sm",
|
|
3036
|
-
chosen?.paragraphId === t.paragraphId ? "bg-accent" : "hover:bg-accent/50"
|
|
3037
|
-
),
|
|
3038
|
-
style: { paddingLeft: 8 + t.level * 16 },
|
|
3039
|
-
children: [
|
|
3040
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 font-mono text-xs text-muted-foreground", children: t.marker || l.heading }),
|
|
3041
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: ui.cn("truncate", t.heading && "font-medium"), children: t.text })
|
|
3042
|
-
]
|
|
3043
|
-
},
|
|
3044
|
-
t.paragraphId
|
|
3045
|
-
))
|
|
3046
|
-
]
|
|
3047
|
-
}
|
|
3048
|
-
),
|
|
3049
|
-
chosen && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-3 text-sm", children: [
|
|
3050
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: l.insertAs }),
|
|
3051
|
-
chosen.number && /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-1", children: [
|
|
3052
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3053
|
-
"input",
|
|
3054
|
-
{
|
|
3055
|
-
type: "radio",
|
|
3056
|
-
name: "cross-reference-mode",
|
|
3057
|
-
checked: effectiveMode === "number",
|
|
3058
|
-
onChange: () => setMode("number")
|
|
3059
|
-
}
|
|
3060
|
-
),
|
|
3061
|
-
l.number
|
|
3062
|
-
] }),
|
|
3063
|
-
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-1", children: [
|
|
3064
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3065
|
-
"input",
|
|
3066
|
-
{
|
|
3067
|
-
type: "radio",
|
|
3068
|
-
name: "cross-reference-mode",
|
|
3069
|
-
checked: effectiveMode === "text",
|
|
3070
|
-
onChange: () => setMode("text")
|
|
3071
|
-
}
|
|
3072
|
-
),
|
|
3073
|
-
l.text
|
|
3074
|
-
] }),
|
|
3075
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3076
|
-
"span",
|
|
3077
|
-
{
|
|
3078
|
-
className: "ml-auto rounded bg-muted px-2 py-0.5",
|
|
3079
|
-
"data-testid": "docx-cross-reference-preview",
|
|
3080
|
-
children: refResult(chosen, effectiveMode)
|
|
3081
|
-
}
|
|
3082
|
-
)
|
|
3083
|
-
] })
|
|
3084
|
-
] }),
|
|
3085
|
-
references && /* @__PURE__ */ jsxRuntime.jsxs(ui.TabsContent, { value: "other", className: "space-y-3", children: [
|
|
3086
|
-
references.renderDocumentPicker ? references.renderDocumentPicker(chooseDocument, docId) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3087
|
-
"select",
|
|
3088
|
-
{
|
|
3089
|
-
className: "h-9 w-full rounded-md border border-border bg-background px-2 text-sm",
|
|
3090
|
-
"aria-label": l.chooseDocument,
|
|
3091
|
-
value: docId ?? "",
|
|
3092
|
-
onChange: (e) => e.target.value && chooseDocument(e.target.value),
|
|
3093
|
-
"data-testid": "docx-cross-reference-document",
|
|
3094
|
-
children: [
|
|
3095
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: l.chooseDocument }),
|
|
3096
|
-
(documents ?? []).map((d) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: d.id, children: d.title }, d.id))
|
|
3097
|
-
]
|
|
3098
|
-
}
|
|
3099
|
-
),
|
|
3100
|
-
docId && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3101
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3102
|
-
ui.Input,
|
|
3103
|
-
{
|
|
3104
|
-
value: passageQuery,
|
|
3105
|
-
placeholder: l.filterPassages,
|
|
3106
|
-
"aria-label": l.filterPassages,
|
|
3107
|
-
onChange: (e) => setPassageQuery(e.target.value),
|
|
3108
|
-
"data-testid": "docx-cross-reference-passage-filter"
|
|
3109
|
-
}
|
|
3110
|
-
),
|
|
3111
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3112
|
-
"div",
|
|
3113
|
-
{
|
|
3114
|
-
className: "max-h-64 space-y-1 overflow-y-auto",
|
|
3115
|
-
"data-testid": "docx-cross-reference-passages",
|
|
3116
|
-
children: list === "loading" || list === void 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "p-2 text-sm text-muted-foreground", children: l.loadingPassages }) : shownPassages.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "p-2 text-sm text-muted-foreground", children: l.noPassages }) : shownPassages.map((p, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3117
|
-
chunk5FYU7ZIU_cjs.FactPassageItem,
|
|
3118
|
-
{
|
|
3119
|
-
index: i,
|
|
3120
|
-
page: p.page,
|
|
3121
|
-
excerpt: passageExcerpt(p.text, 200),
|
|
3122
|
-
isViewing: passage?.chunkId === p.chunkId,
|
|
3123
|
-
onSelect: () => {
|
|
3124
|
-
setPassage(p);
|
|
3125
|
-
setText(referenceText(title, p));
|
|
3126
|
-
},
|
|
3127
|
-
testId: "docx-cross-reference-passage"
|
|
3128
|
-
},
|
|
3129
|
-
p.chunkId
|
|
3130
|
-
))
|
|
3131
|
-
}
|
|
3132
|
-
),
|
|
3133
|
-
passage && /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block space-y-1 text-sm", children: [
|
|
3134
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: l.referenceText }),
|
|
3135
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3136
|
-
ui.Input,
|
|
3137
|
-
{
|
|
3138
|
-
value: text,
|
|
3139
|
-
onChange: (e) => setText(e.target.value),
|
|
3140
|
-
"data-testid": "docx-cross-reference-text"
|
|
3141
|
-
}
|
|
3142
|
-
)
|
|
3143
|
-
] })
|
|
3144
|
-
] })
|
|
3145
|
-
] })
|
|
3146
|
-
] }),
|
|
3147
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.DialogFooter, { children: [
|
|
3148
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "outline", onClick: onCancel, children: l.cancel }),
|
|
3149
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { disabled: !canInsert, onClick: insert, "data-testid": "docx-cross-reference-insert", children: l.insertButton })
|
|
3150
|
-
] })
|
|
3151
|
-
]
|
|
2921
|
+
label: `${label} (${shortcut})`,
|
|
2922
|
+
icon,
|
|
2923
|
+
disabled: !note.isEnabled,
|
|
2924
|
+
disabledReason: note.disabledReason ?? void 0,
|
|
2925
|
+
onSelect: () => void note.insert(),
|
|
2926
|
+
className: `native-docx-insert-${kind}`
|
|
3152
2927
|
}
|
|
3153
2928
|
) });
|
|
3154
2929
|
}
|
|
3155
|
-
function
|
|
3156
|
-
|
|
3157
|
-
icon,
|
|
3158
|
-
children,
|
|
3159
|
-
className,
|
|
3160
|
-
testId,
|
|
3161
|
-
title,
|
|
3162
|
-
keepMounted = false,
|
|
3163
|
-
popoverClassName
|
|
3164
|
-
}) {
|
|
3165
|
-
const [open, setOpen] = React4.useState(false);
|
|
3166
|
-
const element = React4.useRef(null);
|
|
3167
|
-
React4.useEffect(() => {
|
|
3168
|
-
if (!open) return;
|
|
3169
|
-
const dismiss = (event) => {
|
|
3170
|
-
if (!element.current?.contains(event.target)) setOpen(false);
|
|
3171
|
-
};
|
|
3172
|
-
const escape = (event) => {
|
|
3173
|
-
if (event.key === "Escape") setOpen(false);
|
|
3174
|
-
};
|
|
3175
|
-
document.addEventListener("pointerdown", dismiss);
|
|
3176
|
-
document.addEventListener("keydown", escape);
|
|
3177
|
-
return () => {
|
|
3178
|
-
document.removeEventListener("pointerdown", dismiss);
|
|
3179
|
-
document.removeEventListener("keydown", escape);
|
|
3180
|
-
};
|
|
3181
|
-
}, [open]);
|
|
3182
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "native-docx-ribbon-menu", ref: element, children: [
|
|
2930
|
+
function NoteButtons() {
|
|
2931
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3183
2932
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3184
|
-
|
|
2933
|
+
NoteAction,
|
|
3185
2934
|
{
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
"
|
|
3189
|
-
|
|
3190
|
-
"aria-expanded": open,
|
|
3191
|
-
"data-testid": testId,
|
|
3192
|
-
onMouseDown: (event) => event.preventDefault(),
|
|
3193
|
-
onClick: () => setOpen((value) => !value),
|
|
3194
|
-
children: icon
|
|
2935
|
+
kind: "footnote",
|
|
2936
|
+
label: "Insert footnote",
|
|
2937
|
+
shortcut: "Ctrl+Alt+F",
|
|
2938
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Superscript, { size: 16 })
|
|
3195
2939
|
}
|
|
3196
2940
|
),
|
|
3197
|
-
|
|
3198
|
-
|
|
2941
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2942
|
+
NoteAction,
|
|
3199
2943
|
{
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
"
|
|
3203
|
-
|
|
3204
|
-
onMouseDown: (event) => {
|
|
3205
|
-
if (!(event.target instanceof HTMLInputElement || event.target instanceof HTMLSelectElement))
|
|
3206
|
-
event.preventDefault();
|
|
3207
|
-
},
|
|
3208
|
-
children: typeof children === "function" ? children(() => setOpen(false)) : children
|
|
2944
|
+
kind: "endnote",
|
|
2945
|
+
label: "Insert endnote",
|
|
2946
|
+
shortcut: "Ctrl+Alt+D",
|
|
2947
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.NotebookText, { size: 16 })
|
|
3209
2948
|
}
|
|
3210
2949
|
)
|
|
3211
2950
|
] });
|
|
3212
2951
|
}
|
|
3213
|
-
|
|
3214
|
-
const
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
function rememberCaret(editor) {
|
|
3218
|
-
const surface = editor.surface;
|
|
3219
|
-
const head = surface?.state().selection?.head;
|
|
3220
|
-
if (!surface || !head) return null;
|
|
3221
|
-
return { paraId: surface.session.paraIdOf(head.paragraphId), ...head };
|
|
3222
|
-
}
|
|
3223
|
-
var mounted = [];
|
|
3224
|
-
var running = 0;
|
|
3225
|
-
var listeners = /* @__PURE__ */ new Set();
|
|
3226
|
-
var setRunning = (delta) => {
|
|
3227
|
-
running += delta;
|
|
3228
|
-
listeners.forEach((listener) => listener());
|
|
3229
|
-
};
|
|
3230
|
-
var subscribe = (listener) => {
|
|
3231
|
-
listeners.add(listener);
|
|
3232
|
-
return () => void listeners.delete(listener);
|
|
3233
|
-
};
|
|
3234
|
-
function insertionTarget(origin, caret, editors = mounted) {
|
|
3235
|
-
if (editors.includes(origin) && origin.surface) return origin;
|
|
3236
|
-
const paraId = caret?.paraId;
|
|
3237
|
-
if (!paraId) return null;
|
|
3238
|
-
for (let i = editors.length - 1; i >= 0; i--) {
|
|
3239
|
-
const session = editors[i].surface?.session;
|
|
3240
|
-
if (session?.nodeIdOf(paraId)) return editors[i];
|
|
3241
|
-
}
|
|
3242
|
-
return null;
|
|
3243
|
-
}
|
|
3244
|
-
function restoreCaret(editor, caret) {
|
|
3245
|
-
const surface = editor.surface;
|
|
3246
|
-
if (!surface || !caret) return;
|
|
3247
|
-
const paragraphId = caret.paraId && surface.session.nodeIdOf(caret.paraId) || caret.paragraphId;
|
|
3248
|
-
if (!surface.session.paragraphIds().includes(paragraphId)) return;
|
|
3249
|
-
const point = { paragraphId, offset: caret.offset };
|
|
3250
|
-
surface.setSelection({ anchor: point, head: point });
|
|
3251
|
-
}
|
|
3252
|
-
async function insertGeneratedImage(editor$1, bytes, prompt, caret) {
|
|
3253
|
-
const image = react.normalizeImageBytes(bytes);
|
|
3254
|
-
if (!image.ok) throw new Error("The generated image is not in a format Word can embed.");
|
|
3255
|
-
let result;
|
|
3256
|
-
for (let attempt = 0; attempt < 3 && !result?.ok; attempt++) {
|
|
3257
|
-
editor$1.focus();
|
|
3258
|
-
restoreCaret(editor$1, caret);
|
|
3259
|
-
result = await editor.executeImageCommand(editor$1, {
|
|
3260
|
-
type: "insertImage",
|
|
3261
|
-
data: image.bytes,
|
|
3262
|
-
mime: image.mime,
|
|
3263
|
-
widthPoints: image.widthPoints,
|
|
3264
|
-
heightPoints: image.heightPoints,
|
|
3265
|
-
description: prompt.trim(),
|
|
3266
|
-
title: titleOf(prompt)
|
|
3267
|
-
});
|
|
3268
|
-
if (!result.ok && result.reason !== "stale drawing selection") break;
|
|
3269
|
-
}
|
|
3270
|
-
if (!result?.ok) throw new Error(result?.reason || "The picture could not be inserted here.");
|
|
3271
|
-
}
|
|
3272
|
-
var AUTO = "";
|
|
3273
|
-
function useGenerateImageTarget() {
|
|
2952
|
+
function WordShortcuts({ scope }) {
|
|
2953
|
+
const footnote = useInsertNote("footnote");
|
|
2954
|
+
const endnote = useInsertNote("endnote");
|
|
2955
|
+
const styles = react.useParagraphStyle();
|
|
3274
2956
|
const editor = react.useDocxEditor();
|
|
3275
|
-
const
|
|
2957
|
+
const levels = useHouseTemplate()?.levels;
|
|
2958
|
+
const latest = React4.useRef({ footnote, endnote, styles, editor, levels });
|
|
2959
|
+
latest.current = { footnote, endnote, styles, editor, levels };
|
|
3276
2960
|
React4.useEffect(() => {
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
if (!editor || !prompt.trim() || busy) return;
|
|
3295
|
-
const caret = rememberCaret(editor);
|
|
3296
|
-
const controller = new AbortController();
|
|
3297
|
-
abort.current = controller;
|
|
3298
|
-
setBusy(true);
|
|
3299
|
-
setRunning(1);
|
|
3300
|
-
setError("");
|
|
3301
|
-
try {
|
|
3302
|
-
const bytes = await generation.generate(prompt.trim(), {
|
|
3303
|
-
aspectRatio: aspectRatio || void 0,
|
|
3304
|
-
signal: controller.signal
|
|
3305
|
-
});
|
|
3306
|
-
if (controller.signal.aborted) return;
|
|
3307
|
-
const target = insertionTarget(editor, caret);
|
|
3308
|
-
if (!target) throw new Error("The document was closed before the generated image was ready.");
|
|
3309
|
-
await insertGeneratedImage(target, bytes, prompt, caret);
|
|
3310
|
-
setPrompt("");
|
|
3311
|
-
close.current();
|
|
3312
|
-
generation.notify?.("Generated image inserted", "success");
|
|
3313
|
-
} catch (failure) {
|
|
3314
|
-
if (controller.signal.aborted) return;
|
|
3315
|
-
const message = failure instanceof Error ? failure.message : String(failure);
|
|
3316
|
-
setError(message);
|
|
3317
|
-
generation.notify?.(message, "error");
|
|
3318
|
-
} finally {
|
|
3319
|
-
abort.current = null;
|
|
3320
|
-
setRunning(-1);
|
|
3321
|
-
setBusy(false);
|
|
3322
|
-
}
|
|
3323
|
-
}
|
|
3324
|
-
if (!editable && !generating) return null;
|
|
3325
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3326
|
-
RibbonMenu,
|
|
3327
|
-
{
|
|
3328
|
-
label: generating ? "Generating image\u2026" : "Generate image",
|
|
3329
|
-
icon: generating ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: 16, className: "native-docx-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { size: 16 }),
|
|
3330
|
-
testId: "docx-generate-image",
|
|
3331
|
-
children: (dismiss) => {
|
|
3332
|
-
close.current = dismiss;
|
|
3333
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3334
|
-
"form",
|
|
3335
|
-
{
|
|
3336
|
-
className: "native-docx-form native-docx-generate-image",
|
|
3337
|
-
onSubmit: (event) => {
|
|
3338
|
-
event.preventDefault();
|
|
3339
|
-
void run2();
|
|
3340
|
-
},
|
|
3341
|
-
children: [
|
|
3342
|
-
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
3343
|
-
"Describe the image",
|
|
3344
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3345
|
-
"textarea",
|
|
3346
|
-
{
|
|
3347
|
-
autoFocus: true,
|
|
3348
|
-
rows: 3,
|
|
3349
|
-
value: prompt,
|
|
3350
|
-
disabled: busy,
|
|
3351
|
-
placeholder: "A watercolour of a lighthouse at dawn",
|
|
3352
|
-
"data-testid": "docx-generate-image-prompt",
|
|
3353
|
-
onChange: (event) => setPrompt(event.target.value),
|
|
3354
|
-
onKeyDown: (event) => {
|
|
3355
|
-
if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) void run2();
|
|
3356
|
-
}
|
|
3357
|
-
}
|
|
3358
|
-
)
|
|
3359
|
-
] }),
|
|
3360
|
-
generation.aspectRatios && generation.aspectRatios.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
3361
|
-
"Aspect ratio",
|
|
3362
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3363
|
-
"select",
|
|
3364
|
-
{
|
|
3365
|
-
value: aspectRatio,
|
|
3366
|
-
disabled: busy,
|
|
3367
|
-
onChange: (event) => setAspectRatio(event.target.value),
|
|
3368
|
-
children: [
|
|
3369
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: AUTO, children: "Auto" }),
|
|
3370
|
-
generation.aspectRatios.map((ratio) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: ratio.value, children: ratio.label }, ratio.value))
|
|
3371
|
-
]
|
|
3372
|
-
}
|
|
3373
|
-
)
|
|
3374
|
-
] }),
|
|
3375
|
-
busy && /* @__PURE__ */ jsxRuntime.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." }),
|
|
3376
|
-
error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", children: error }),
|
|
3377
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "native-docx-form-actions", children: busy ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => abort.current?.abort(), children: "Cancel" }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3378
|
-
"button",
|
|
3379
|
-
{
|
|
3380
|
-
type: "submit",
|
|
3381
|
-
disabled: !prompt.trim(),
|
|
3382
|
-
"data-testid": "docx-generate-image-submit",
|
|
3383
|
-
children: "Generate"
|
|
3384
|
-
}
|
|
3385
|
-
) })
|
|
3386
|
-
]
|
|
3387
|
-
}
|
|
3388
|
-
);
|
|
2961
|
+
const element = scope.current;
|
|
2962
|
+
if (!element) return;
|
|
2963
|
+
const onKeyDown = (event) => {
|
|
2964
|
+
if (outlineTab(event)) {
|
|
2965
|
+
event.preventDefault();
|
|
2966
|
+
event.stopPropagation();
|
|
2967
|
+
return;
|
|
2968
|
+
}
|
|
2969
|
+
const action = wordShortcut(event);
|
|
2970
|
+
if (!action) return;
|
|
2971
|
+
const { footnote: footnote2, endnote: endnote2, styles: styles2, editor: editor2 } = latest.current;
|
|
2972
|
+
if (action === "footnote" || action === "endnote") {
|
|
2973
|
+
if (!(action === "footnote" ? footnote2 : endnote2).insert()) return;
|
|
2974
|
+
} else {
|
|
2975
|
+
const style = findStyle(styles2.options, action);
|
|
2976
|
+
if (!style) return;
|
|
2977
|
+
styles2.setValue(style.styleId);
|
|
3389
2978
|
}
|
|
2979
|
+
event.preventDefault();
|
|
2980
|
+
event.stopPropagation();
|
|
2981
|
+
editor2?.surface?.focus();
|
|
2982
|
+
};
|
|
2983
|
+
const outlineTab = (event) => {
|
|
2984
|
+
if (event.key !== "Tab" || event.ctrlKey || event.metaKey || event.altKey) return false;
|
|
2985
|
+
const { editor: editor2, levels: levels2, styles: styles2 } = latest.current;
|
|
2986
|
+
const current = editor2?.getSelectionFormatting()?.styleId;
|
|
2987
|
+
const link = current ? levels2?.[current] : void 0;
|
|
2988
|
+
const target = event.shiftKey ? link?.previous : link?.next;
|
|
2989
|
+
if (!target || !editor2 || editorPort(editor2).caret()?.offset !== 0) return false;
|
|
2990
|
+
styles2.setValue(target);
|
|
2991
|
+
return true;
|
|
2992
|
+
};
|
|
2993
|
+
element.addEventListener("keydown", onKeyDown, true);
|
|
2994
|
+
return () => element.removeEventListener("keydown", onKeyDown, true);
|
|
2995
|
+
}, [scope]);
|
|
2996
|
+
return null;
|
|
2997
|
+
}
|
|
2998
|
+
|
|
2999
|
+
// src/docx/beforeSave.ts
|
|
3000
|
+
var hooks = /* @__PURE__ */ new WeakMap();
|
|
3001
|
+
function onBeforeSave(editor, fn) {
|
|
3002
|
+
let set = hooks.get(editor);
|
|
3003
|
+
if (!set) hooks.set(editor, set = /* @__PURE__ */ new Set());
|
|
3004
|
+
set.add(fn);
|
|
3005
|
+
return () => set.delete(fn);
|
|
3006
|
+
}
|
|
3007
|
+
function runBeforeSave(editor) {
|
|
3008
|
+
if (!editor) return;
|
|
3009
|
+
for (const fn of hooks.get(editor) ?? [])
|
|
3010
|
+
try {
|
|
3011
|
+
fn();
|
|
3012
|
+
} catch {
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
|
|
3016
|
+
// src/docx/references/numbering.ts
|
|
3017
|
+
var numbers = (level) => !!level && level.numFmt !== "bullet" && level.numFmt !== "none" && (level.lvlText ?? level.markerText ?? "").length > 0;
|
|
3018
|
+
function paragraphNumber(order, items, levelOf, paragraphId) {
|
|
3019
|
+
const item = items.get(paragraphId);
|
|
3020
|
+
if (!item || !numbers(item)) return null;
|
|
3021
|
+
const at = order.indexOf(paragraphId);
|
|
3022
|
+
const markerAt = (ilvl) => {
|
|
3023
|
+
if (ilvl === item.ilvl) return item.markerText;
|
|
3024
|
+
for (let i = at - 1; i >= 0; i--) {
|
|
3025
|
+
const other = items.get(order[i]);
|
|
3026
|
+
if (other && other.numId === item.numId && other.ilvl === ilvl) return other.markerText;
|
|
3390
3027
|
}
|
|
3028
|
+
return null;
|
|
3029
|
+
};
|
|
3030
|
+
const chain = [];
|
|
3031
|
+
const texts = [];
|
|
3032
|
+
for (let u = item.ilvl; u >= 0; u--) {
|
|
3033
|
+
const level = levelOf(item.numId, u);
|
|
3034
|
+
if (!level || !numbers(level)) continue;
|
|
3035
|
+
if (u !== item.ilvl && texts.some((t) => t.includes(`%${u + 1}`))) continue;
|
|
3036
|
+
chain.push(u);
|
|
3037
|
+
texts.push(level.lvlText);
|
|
3038
|
+
}
|
|
3039
|
+
const value = chain.reverse().map((u) => markerAt(u) ?? "").join("");
|
|
3040
|
+
if (!value) return null;
|
|
3041
|
+
return value.length > 1 && value.endsWith(".") ? value.slice(0, -1) : value;
|
|
3042
|
+
}
|
|
3043
|
+
function listTargets(paragraphs, items, levelOf) {
|
|
3044
|
+
const order = paragraphs.map((p) => p.id);
|
|
3045
|
+
const out = [];
|
|
3046
|
+
for (const p of paragraphs) {
|
|
3047
|
+
const text = p.text.replace(//g, "").trim();
|
|
3048
|
+
if (!text) continue;
|
|
3049
|
+
const number = paragraphNumber(order, items, levelOf, p.id);
|
|
3050
|
+
const item = items.get(p.id);
|
|
3051
|
+
if (number !== null)
|
|
3052
|
+
out.push({
|
|
3053
|
+
paragraphId: p.id,
|
|
3054
|
+
kind: "numbered",
|
|
3055
|
+
number,
|
|
3056
|
+
marker: item?.markerText ?? "",
|
|
3057
|
+
text,
|
|
3058
|
+
heading: p.heading,
|
|
3059
|
+
level: item?.ilvl ?? 0
|
|
3060
|
+
});
|
|
3061
|
+
else if (p.heading)
|
|
3062
|
+
out.push({
|
|
3063
|
+
paragraphId: p.id,
|
|
3064
|
+
kind: "heading",
|
|
3065
|
+
number: null,
|
|
3066
|
+
marker: "",
|
|
3067
|
+
text,
|
|
3068
|
+
heading: true,
|
|
3069
|
+
level: 0
|
|
3070
|
+
});
|
|
3071
|
+
}
|
|
3072
|
+
return out;
|
|
3073
|
+
}
|
|
3074
|
+
function filterTargets(targets, query) {
|
|
3075
|
+
const q = query.trim().toLowerCase();
|
|
3076
|
+
if (!q) return [...targets];
|
|
3077
|
+
return targets.filter(
|
|
3078
|
+
(t) => (t.number ?? "").toLowerCase().startsWith(q) || t.text.toLowerCase().includes(q)
|
|
3391
3079
|
);
|
|
3392
3080
|
}
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
const
|
|
3399
|
-
if (
|
|
3400
|
-
}
|
|
3401
|
-
return template.innerHTML;
|
|
3081
|
+
|
|
3082
|
+
// src/docx/references/commands.ts
|
|
3083
|
+
var REF_BOOKMARK_PREFIX = "_Ref";
|
|
3084
|
+
function newRefBookmark(taken, random = Math.random) {
|
|
3085
|
+
for (; ; ) {
|
|
3086
|
+
const name = `${REF_BOOKMARK_PREFIX}${String(Math.floor(random() * 9e8) + 1e8)}`;
|
|
3087
|
+
if (!taken.has(name)) return name;
|
|
3088
|
+
}
|
|
3402
3089
|
}
|
|
3403
|
-
|
|
3404
|
-
|
|
3090
|
+
var styled = (style) => style ? `<w:rPr><w:rStyle w:val="${style}"/></w:rPr>` : "";
|
|
3091
|
+
var run = (text, style) => `<w:r>${styled(style)}<w:t xml:space="preserve">${chunk2A4MDHJR_cjs.esc(text)}</w:t></w:r>`;
|
|
3092
|
+
function refFieldXml(instruction, cached) {
|
|
3093
|
+
const r = (inner) => `<w:r>${styled(CROSS_REFERENCE_STYLE)}${inner}</w:r>`;
|
|
3094
|
+
return `${r('<w:fldChar w:fldCharType="begin"/>')}${r(
|
|
3095
|
+
`<w:instrText xml:space="preserve"> ${chunk2A4MDHJR_cjs.esc(instruction)} </w:instrText>`
|
|
3096
|
+
)}${r('<w:fldChar w:fldCharType="separate"/>')}${run(cached, CROSS_REFERENCE_STYLE)}${r(
|
|
3097
|
+
'<w:fldChar w:fldCharType="end"/>'
|
|
3098
|
+
)}`;
|
|
3405
3099
|
}
|
|
3406
|
-
var
|
|
3407
|
-
|
|
3408
|
-
|
|
3100
|
+
var refTooltip = (value, mode) => mode === "number" ? `Cross-reference to clause ${value}` : `Cross-reference to \u201C${value}\u201D`;
|
|
3101
|
+
function crossReferenceXml(bookmark, mode, value) {
|
|
3102
|
+
return `<w:hyperlink w:anchor="${chunk2A4MDHJR_cjs.esc(bookmark)}" w:tooltip="${chunk2A4MDHJR_cjs.esc(
|
|
3103
|
+
refTooltip(value, mode)
|
|
3104
|
+
)}" w:history="1">${refFieldXml(refInstruction(bookmark, mode), value)}</w:hyperlink>`;
|
|
3105
|
+
}
|
|
3106
|
+
var refInstruction = (bookmark, mode) => mode === "number" ? `REF ${bookmark} \\r \\h` : `REF ${bookmark} \\h`;
|
|
3107
|
+
var refResult = (target, mode) => mode === "number" && target.number ? target.number : target.text;
|
|
3108
|
+
var allBookmarks = (port) => new Set(port.paragraphs().flatMap((p) => p.bookmarks));
|
|
3109
|
+
function ensureTargetBookmark(port, target, mode) {
|
|
3110
|
+
const paragraph = port.paragraphs().find((p) => p.id === target.paragraphId);
|
|
3111
|
+
if (!paragraph) throw new Error("That clause is no longer in the document.");
|
|
3112
|
+
const existing = paragraph.bookmarks.find((b) => b.startsWith(REF_BOOKMARK_PREFIX));
|
|
3113
|
+
if (existing && mode === "number") return existing;
|
|
3114
|
+
const name = newRefBookmark(allBookmarks(port));
|
|
3115
|
+
const start = `<w:bookmarkStart w:id="0" w:name="${name}"/>`;
|
|
3116
|
+
const end = '<w:bookmarkEnd w:id="0"/>';
|
|
3117
|
+
if (mode === "number") {
|
|
3118
|
+
port.setCaret({ paragraphId: paragraph.id, offset: 0 });
|
|
3119
|
+
if (!port.paste(`<w:p>${start}${end}</w:p>`, "", false))
|
|
3120
|
+
throw new Error("The cross-reference target could not be marked.");
|
|
3121
|
+
return name;
|
|
3409
3122
|
}
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3123
|
+
const runs = port.runsXml(paragraph.id);
|
|
3124
|
+
if (!runs) throw new Error("This heading cannot be referred to by its text; use its number.");
|
|
3125
|
+
port.deleteRange(
|
|
3126
|
+
{ paragraphId: paragraph.id, offset: 0 },
|
|
3127
|
+
{ paragraphId: paragraph.id, offset: paragraph.text.length }
|
|
3128
|
+
);
|
|
3129
|
+
if (!port.paste(`<w:p>${start}${runs}${end}</w:p>`, paragraph.text, false))
|
|
3130
|
+
throw new Error("The cross-reference target could not be marked.");
|
|
3131
|
+
return name;
|
|
3132
|
+
}
|
|
3133
|
+
function pastePoint(port, caret) {
|
|
3134
|
+
const paragraph = port.paragraphs().find((p) => p.id === caret.paragraphId);
|
|
3135
|
+
if (paragraph?.text[caret.offset - 1] !== FIELD_ATOM) return caret;
|
|
3136
|
+
port.setCaret(caret);
|
|
3137
|
+
port.typeText(" ");
|
|
3138
|
+
return { paragraphId: caret.paragraphId, offset: caret.offset + 1 };
|
|
3139
|
+
}
|
|
3140
|
+
function markCrossReferenceTarget(port, target, mode) {
|
|
3141
|
+
if (mode === "number" && !target.number) mode = "text";
|
|
3142
|
+
const bookmark = ensureTargetBookmark(port, target, mode);
|
|
3143
|
+
return { bookmark, mode, value: refResult(target, mode) };
|
|
3144
|
+
}
|
|
3145
|
+
function insertCrossReferenceField(port, { bookmark, mode, value }, caret) {
|
|
3146
|
+
caret = pastePoint(port, caret);
|
|
3147
|
+
port.setCaret(caret);
|
|
3148
|
+
if (!port.paste(`<w:p>${crossReferenceXml(bookmark, mode, value)}</w:p>`, value, false))
|
|
3149
|
+
throw new Error("The cross-reference could not be inserted.");
|
|
3150
|
+
port.setCaret({ paragraphId: caret.paragraphId, offset: caret.offset + 1 });
|
|
3151
|
+
return { bookmark };
|
|
3152
|
+
}
|
|
3153
|
+
function insertCrossReference(port, target, mode, caret) {
|
|
3154
|
+
return insertCrossReferenceField(port, markCrossReferenceTarget(port, target, mode), caret);
|
|
3155
|
+
}
|
|
3156
|
+
var documentReferenceTooltip = (text, appName = "ARBI") => `Cross-reference: ${text} \u2014 opens in ${appName}`;
|
|
3157
|
+
function insertDocumentReference(port, reference, caret) {
|
|
3158
|
+
const text = reference.text.trim();
|
|
3159
|
+
if (!text) throw new Error("Enter the reference text.");
|
|
3160
|
+
const tooltip = documentReferenceTooltip(text, reference.appName).slice(0, 255);
|
|
3161
|
+
caret = pastePoint(port, caret);
|
|
3162
|
+
port.setCaret(caret);
|
|
3163
|
+
const link = `<w:p><w:hyperlink r:id="rIdRef1"${tooltip ? ` w:tooltip="${chunk2A4MDHJR_cjs.esc(tooltip)}"` : ""} w:history="1">${run(text, CROSS_REFERENCE_STYLE)}</w:hyperlink></w:p>`;
|
|
3164
|
+
if (!port.paste(link, text, false, chunk2A4MDHJR_cjs.hyperlinkRelationship("rIdRef1", reference.url)))
|
|
3165
|
+
throw new Error("The reference could not be inserted.");
|
|
3166
|
+
port.setCaret({ paragraphId: caret.paragraphId, offset: caret.offset + text.length });
|
|
3167
|
+
}
|
|
3168
|
+
var REF_FIELD = /^REF\s+(\S+)((?:\s+\\[A-Za-z*]+(?:\s+MERGEFORMAT)?)*)\s*$/i;
|
|
3169
|
+
function staleCrossReferences(port) {
|
|
3170
|
+
const paragraphs = port.paragraphs();
|
|
3171
|
+
if (!paragraphs.some((p) => p.fields?.length)) return [];
|
|
3172
|
+
const items = port.listItems();
|
|
3173
|
+
const order = paragraphs.map((p) => p.id);
|
|
3174
|
+
const owner = /* @__PURE__ */ new Map();
|
|
3175
|
+
for (const p of paragraphs) for (const b of p.bookmarks) if (!owner.has(b)) owner.set(b, p.id);
|
|
3176
|
+
const out = [];
|
|
3177
|
+
for (const p of paragraphs)
|
|
3178
|
+
for (const field of p.fields ?? []) {
|
|
3179
|
+
const match = REF_FIELD.exec(field.instruction);
|
|
3180
|
+
if (!match || !match[1].startsWith(REF_BOOKMARK_PREFIX)) continue;
|
|
3181
|
+
const switches = match[2].toLowerCase();
|
|
3182
|
+
const mode = /\\[rwn]\b/.test(switches) ? "number" : "text";
|
|
3183
|
+
const target = owner.get(match[1]);
|
|
3184
|
+
const base = {
|
|
3185
|
+
paragraphId: p.id,
|
|
3186
|
+
offset: field.offset,
|
|
3187
|
+
instruction: field.instruction,
|
|
3188
|
+
cached: field.result,
|
|
3189
|
+
bookmark: match[1],
|
|
3190
|
+
mode
|
|
3191
|
+
};
|
|
3192
|
+
if (!target) {
|
|
3193
|
+
out.push({ ...base, value: null });
|
|
3194
|
+
continue;
|
|
3471
3195
|
}
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
throw error;
|
|
3475
|
-
} finally {
|
|
3476
|
-
requireEdit(this.editor.setEditingMode("viewing"));
|
|
3196
|
+
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();
|
|
3197
|
+
if (value && value !== field.result.trim()) out.push({ ...base, value });
|
|
3477
3198
|
}
|
|
3199
|
+
return out;
|
|
3200
|
+
}
|
|
3201
|
+
function brokenCrossReferences(port) {
|
|
3202
|
+
return port.paragraphs().flatMap(
|
|
3203
|
+
(p) => (p.marks ?? []).filter((m) => m.styleId === BROKEN_CROSS_REFERENCE_STYLE).map((m) => ({ paragraphId: p.id, offset: m.offset, text: m.text }))
|
|
3204
|
+
);
|
|
3205
|
+
}
|
|
3206
|
+
function refreshCrossReferences(port) {
|
|
3207
|
+
const stale = staleCrossReferences(port).sort(
|
|
3208
|
+
(a, b) => a.paragraphId === b.paragraphId ? b.offset - a.offset : 0
|
|
3209
|
+
);
|
|
3210
|
+
let refreshed = 0;
|
|
3211
|
+
for (const ref of stale) {
|
|
3212
|
+
const paragraph = port.paragraphs().find((p) => p.id === ref.paragraphId);
|
|
3213
|
+
if (!paragraph || paragraph.text[ref.offset - 1] === FIELD_ATOM) continue;
|
|
3214
|
+
const at = { paragraphId: ref.paragraphId, offset: ref.offset };
|
|
3215
|
+
port.deleteRange(at, { paragraphId: ref.paragraphId, offset: ref.offset + 1 });
|
|
3216
|
+
port.setCaret(at);
|
|
3217
|
+
const text = ref.value ?? (ref.cached.trim() || ref.bookmark);
|
|
3218
|
+
const body = ref.value === null ? run(text, BROKEN_CROSS_REFERENCE_STYLE) : crossReferenceXml(ref.bookmark, ref.mode, ref.value);
|
|
3219
|
+
if (port.paste(`<w:p>${body}</w:p>`, text, false) && ref.value !== null) refreshed++;
|
|
3478
3220
|
}
|
|
3479
|
-
};
|
|
3221
|
+
return { refreshed, broken: brokenCrossReferences(port) };
|
|
3222
|
+
}
|
|
3480
3223
|
|
|
3481
|
-
// src/docx/
|
|
3482
|
-
function
|
|
3483
|
-
const
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
used += moreWidth;
|
|
3487
|
-
const order = items.map((item, index) => ({ item, index })).sort((a, b) => a.item.priority - b.item.priority || b.index - a.index);
|
|
3488
|
-
for (const { item } of order) {
|
|
3489
|
-
if (used <= available) break;
|
|
3490
|
-
collapsed.add(item.id);
|
|
3491
|
-
used -= item.width;
|
|
3492
|
-
}
|
|
3493
|
-
return collapsed;
|
|
3224
|
+
// src/docx/references/passages.ts
|
|
3225
|
+
function shortTitle(title) {
|
|
3226
|
+
const base = title.replace(/\.[A-Za-z0-9]{1,5}$/, "").trim();
|
|
3227
|
+
const defined = /\(\s*(?:the\s+)?["“'‘]([^"”'’]{1,30})["”'’]\s*\)/i.exec(base);
|
|
3228
|
+
return defined ? defined[1] : base;
|
|
3494
3229
|
}
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
const row = React4.useRef(null);
|
|
3500
|
-
const items = React4.useRef(/* @__PURE__ */ new Map());
|
|
3501
|
-
const widths = React4.useRef(/* @__PURE__ */ new Map());
|
|
3502
|
-
const [version, setVersion] = React4.useState(0);
|
|
3503
|
-
const [collapsed, setCollapsed] = React4.useState(() => /* @__PURE__ */ new Set());
|
|
3504
|
-
const [slots, setSlots] = React4.useState({});
|
|
3505
|
-
const [menu, setMenu] = React4.useState([]);
|
|
3506
|
-
const register = React4.useCallback((id, item) => {
|
|
3507
|
-
items.current.set(id, item);
|
|
3508
|
-
setVersion((v) => v + 1);
|
|
3509
|
-
return () => {
|
|
3510
|
-
if (items.current.get(id) === item) items.current.delete(id);
|
|
3511
|
-
setVersion((v) => v + 1);
|
|
3512
|
-
};
|
|
3513
|
-
}, []);
|
|
3514
|
-
const plan = React4.useCallback(() => {
|
|
3515
|
-
const element = row.current;
|
|
3516
|
-
if (!element) return;
|
|
3517
|
-
const gap = parseFloat(getComputedStyle(element).columnGap) || 0;
|
|
3518
|
-
const ordered = Array.from(element.querySelectorAll("[data-ribbon-item]")).map((node) => node.dataset.ribbonItem).filter((id) => items.current.has(id));
|
|
3519
|
-
const measured = ordered.map((id) => {
|
|
3520
|
-
const { element: node, priority } = items.current.get(id);
|
|
3521
|
-
if (!node.hidden) {
|
|
3522
|
-
const width = node.getBoundingClientRect().width;
|
|
3523
|
-
widths.current.set(id, width ? width + gap : 0);
|
|
3524
|
-
}
|
|
3525
|
-
return { id, priority, width: widths.current.get(id) ?? 0 };
|
|
3526
|
-
});
|
|
3527
|
-
const next = planOverflow(measured, element.clientWidth, MORE_WIDTH);
|
|
3528
|
-
setCollapsed((current) => sameSet(current, next) ? current : next);
|
|
3529
|
-
const entries = ordered.filter((id) => next.has(id)).map((id) => ({ id, label: items.current.get(id).label }));
|
|
3530
|
-
setMenu(
|
|
3531
|
-
(current) => current.length === entries.length && current.every((entry, i) => entry.id === entries[i].id && entry.label === entries[i].label) ? current : entries
|
|
3532
|
-
);
|
|
3533
|
-
}, []);
|
|
3534
|
-
React4.useLayoutEffect(plan, [plan, version, tab, collapsed]);
|
|
3535
|
-
React4.useLayoutEffect(() => {
|
|
3536
|
-
const element = row.current;
|
|
3537
|
-
if (!element) return;
|
|
3538
|
-
const observer = new ResizeObserver(() => plan());
|
|
3539
|
-
observer.observe(element);
|
|
3540
|
-
for (const item of items.current.values()) observer.observe(item.element);
|
|
3541
|
-
return () => observer.disconnect();
|
|
3542
|
-
}, [plan, version]);
|
|
3543
|
-
const slotRef = React4.useCallback(
|
|
3544
|
-
(id) => (node) => setSlots((current) => {
|
|
3545
|
-
if (node ? current[id] === node : !(id in current)) return current;
|
|
3546
|
-
const next = { ...current };
|
|
3547
|
-
if (node) next[id] = node;
|
|
3548
|
-
else delete next[id];
|
|
3549
|
-
return next;
|
|
3550
|
-
}),
|
|
3551
|
-
[]
|
|
3230
|
+
function passageClause(text) {
|
|
3231
|
+
const first = text.trim().split("\n")[0] ?? "";
|
|
3232
|
+
const match = /^(?:#+\s*)?(?:\*\*)?(?:clause|section|article)?\s*(\d+(?:\.\d+)*)[.)]?(?:\*\*)?\s+\S/i.exec(
|
|
3233
|
+
first
|
|
3552
3234
|
);
|
|
3553
|
-
|
|
3554
|
-
const shown = menu.filter((entry) => collapsed.has(entry.id));
|
|
3555
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Overflow.Provider, { value: context, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "native-docx-ribbon-row", ref: row, "data-testid": "docx-ribbon-row", children: [
|
|
3556
|
-
children,
|
|
3557
|
-
shown.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3558
|
-
RibbonMenu,
|
|
3559
|
-
{
|
|
3560
|
-
label: "More",
|
|
3561
|
-
title: "More commands",
|
|
3562
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Ellipsis, { size: 16 }),
|
|
3563
|
-
testId: "docx-ribbon-more",
|
|
3564
|
-
keepMounted: true,
|
|
3565
|
-
popoverClassName: "native-docx-ribbon-more",
|
|
3566
|
-
children: (close) => /* @__PURE__ */ jsxRuntime.jsx(MoreRows, { entries: shown, slotRef, close })
|
|
3567
|
-
},
|
|
3568
|
-
tab
|
|
3569
|
-
)
|
|
3570
|
-
] }) });
|
|
3235
|
+
return match ? match[1] : null;
|
|
3571
3236
|
}
|
|
3572
|
-
function
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
const refFor = (id) => {
|
|
3579
|
-
let ref = refs.current.get(id);
|
|
3580
|
-
if (!ref) refs.current.set(id, ref = slotRef(id));
|
|
3581
|
-
return ref;
|
|
3582
|
-
};
|
|
3583
|
-
const list = React4.useRef(null);
|
|
3584
|
-
const latest = React4.useRef(close);
|
|
3585
|
-
latest.current = close;
|
|
3586
|
-
React4.useEffect(() => {
|
|
3587
|
-
const element = list.current;
|
|
3588
|
-
if (!element) return;
|
|
3589
|
-
const onClick = (event) => {
|
|
3590
|
-
const target = event.target;
|
|
3591
|
-
const row = target.closest(".native-docx-ribbon-more-row");
|
|
3592
|
-
if (!row) return;
|
|
3593
|
-
const control = row.querySelector(".native-docx-ribbon-more-control");
|
|
3594
|
-
if (!control.contains(target)) {
|
|
3595
|
-
control.querySelector("button:not([disabled])")?.click();
|
|
3596
|
-
return;
|
|
3597
|
-
}
|
|
3598
|
-
const button = target.closest("button");
|
|
3599
|
-
if (button && !button.disabled && !control.querySelector(".native-docx-ribbon-popover")?.contains(button) && !button.hasAttribute("aria-expanded") && !button.hasAttribute("aria-haspopup"))
|
|
3600
|
-
latest.current();
|
|
3601
|
-
};
|
|
3602
|
-
element.addEventListener("click", onClick, true);
|
|
3603
|
-
return () => element.removeEventListener("click", onClick, true);
|
|
3604
|
-
}, []);
|
|
3605
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "native-docx-ribbon-more-list", ref: list, children: entries.map((entry) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "native-docx-ribbon-more-row", "data-ribbon-more": entry.id, children: [
|
|
3606
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "native-docx-ribbon-more-control", ref: refFor(entry.id) }),
|
|
3607
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "native-docx-ribbon-more-label", children: entry.label })
|
|
3608
|
-
] }, entry.id)) });
|
|
3237
|
+
function referenceText(title, passage) {
|
|
3238
|
+
const name = shortTitle(title);
|
|
3239
|
+
const clause = passageClause(passage.text);
|
|
3240
|
+
if (clause) return `${name}, clause ${clause}`;
|
|
3241
|
+
if (passage.page) return `${name}, p. ${passage.page}`;
|
|
3242
|
+
return name;
|
|
3609
3243
|
}
|
|
3610
|
-
function
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
priority = 0,
|
|
3614
|
-
children
|
|
3615
|
-
}) {
|
|
3616
|
-
const context = React4.useContext(Overflow);
|
|
3617
|
-
const element = React4.useRef(null);
|
|
3618
|
-
const register = context?.register;
|
|
3619
|
-
React4.useLayoutEffect(() => {
|
|
3620
|
-
if (!register || !element.current) return;
|
|
3621
|
-
return register(id, { label, priority, element: element.current });
|
|
3622
|
-
}, [register, id, label, priority]);
|
|
3623
|
-
if (!context) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
3624
|
-
const collapsed = context.collapsed.has(id);
|
|
3625
|
-
const slot = context.slots[id];
|
|
3626
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3627
|
-
"span",
|
|
3628
|
-
{
|
|
3629
|
-
ref: element,
|
|
3630
|
-
className: "native-docx-ribbon-item",
|
|
3631
|
-
"data-ribbon-item": id,
|
|
3632
|
-
hidden: collapsed || void 0,
|
|
3633
|
-
children: collapsed ? slot ? reactDom.createPortal(children, slot) : null : children
|
|
3634
|
-
}
|
|
3635
|
-
);
|
|
3244
|
+
function passageExcerpt(text, max = 280) {
|
|
3245
|
+
const plain = text.replace(/[#*_`>|]+/g, " ").replace(/\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/\s+/g, " ").trim();
|
|
3246
|
+
return plain.length > max ? `${plain.slice(0, max - 1)}\u2026` : plain;
|
|
3636
3247
|
}
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
function findStyle(options, name) {
|
|
3641
|
-
const wanted = name.toLowerCase();
|
|
3642
|
-
const id = name.replace(/(^|\s)(\w)/g, (_, _s, c) => c.toUpperCase());
|
|
3643
|
-
return options.find((o) => o.name.toLowerCase() === wanted) ?? options.find((o) => o.styleId.toLowerCase() === id.toLowerCase());
|
|
3248
|
+
function filterPassages(passages, query) {
|
|
3249
|
+
const q = query.trim().toLowerCase();
|
|
3250
|
+
return q ? passages.filter((p) => p.text.toLowerCase().includes(q)) : [...passages];
|
|
3644
3251
|
}
|
|
3645
|
-
|
|
3646
|
-
|
|
3252
|
+
var RUN_PARTS = /* @__PURE__ */ new Set(["rPr", "t", "tab", "br", "lastRenderedPageBreak"]);
|
|
3253
|
+
var SKIPPED = /* @__PURE__ */ new Set(["pPr", "bookmarkStart", "bookmarkEnd", "proofErr", "permStart", "permEnd"]);
|
|
3254
|
+
function serialize(node) {
|
|
3255
|
+
if (node.kind === "textValue") return chunk2A4MDHJR_cjs.esc(node.value ?? "");
|
|
3256
|
+
const name = `${node.prefix ?? "w"}:${node.localName}`;
|
|
3257
|
+
const attrs = (node.attributes ?? []).map((a) => ` ${a.prefix ? `${a.prefix}:` : ""}${a.localName}="${chunk2A4MDHJR_cjs.esc(a.value)}"`).join("");
|
|
3258
|
+
const children = (node.children ?? []).map((c) => serialize(c)).join("");
|
|
3259
|
+
return children ? `<${name}${attrs}>${children}</${name}>` : `<${name}${attrs}/>`;
|
|
3647
3260
|
}
|
|
3648
|
-
function
|
|
3649
|
-
const
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
case "Digit3":
|
|
3664
|
-
case "Numpad3":
|
|
3665
|
-
return "heading 3";
|
|
3666
|
-
}
|
|
3261
|
+
function paragraphRunsXml(paragraph) {
|
|
3262
|
+
const runs = [];
|
|
3263
|
+
for (const child of paragraph.children ?? []) {
|
|
3264
|
+
if (child.localName && SKIPPED.has(child.localName)) continue;
|
|
3265
|
+
if (child.localName !== "r") return null;
|
|
3266
|
+
if ((child.children ?? []).some((c) => !c.localName || !RUN_PARTS.has(c.localName))) return null;
|
|
3267
|
+
runs.push(serialize(child));
|
|
3268
|
+
}
|
|
3269
|
+
return runs.length ? runs.join("") : null;
|
|
3270
|
+
}
|
|
3271
|
+
function findNode2(node, id) {
|
|
3272
|
+
if (node.id === id) return node;
|
|
3273
|
+
for (const child of node.children ?? []) {
|
|
3274
|
+
const found = findNode2(child, id);
|
|
3275
|
+
if (found) return found;
|
|
3667
3276
|
}
|
|
3668
|
-
|
|
3669
|
-
return null;
|
|
3670
|
-
}
|
|
3671
|
-
function divergenceSummary(divergence) {
|
|
3672
|
-
if (!divergence) return null;
|
|
3673
|
-
const changed = divergence.styles.filter((s) => s.kind === "changed").map((s) => styleLabel(s.name));
|
|
3674
|
-
const missing = divergence.styles.filter((s) => s.kind === "missing").map((s) => styleLabel(s.name));
|
|
3675
|
-
const parts = [
|
|
3676
|
-
divergence.docDefaults ? "default text formatting" : "",
|
|
3677
|
-
changed.length ? `${changed.length === 1 ? "style" : "styles"} ${changed.slice(0, 6).join(", ")}${changed.length > 6 ? "\u2026" : ""}` : "",
|
|
3678
|
-
missing.length ? `${missing.length} house ${missing.length === 1 ? "style" : "styles"} missing` : ""
|
|
3679
|
-
].filter(Boolean);
|
|
3680
|
-
return parts.length ? `Differs from the house template: ${parts.join("; ")}.` : null;
|
|
3277
|
+
return void 0;
|
|
3681
3278
|
}
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
const
|
|
3279
|
+
function referencesPort(editor, revision) {
|
|
3280
|
+
const base = editorPort(editor, revision);
|
|
3281
|
+
const session = () => {
|
|
3282
|
+
const s = editor.surface?.session;
|
|
3283
|
+
if (!s) throw new Error("The document is not open.");
|
|
3284
|
+
return s;
|
|
3285
|
+
};
|
|
3286
|
+
const root = () => session().part().root;
|
|
3287
|
+
let numbering;
|
|
3288
|
+
let cascade;
|
|
3289
|
+
const index = () => {
|
|
3290
|
+
if (!numbering) {
|
|
3291
|
+
const s = session();
|
|
3292
|
+
cascade = layout.buildStyleCascadeTable(s.stylesRoot(), void 0, s.settingsRoot());
|
|
3293
|
+
numbering = layout.withNumberingStyleLinks(layout.buildNumberingIndex(s.numberingRoot()), cascade);
|
|
3294
|
+
}
|
|
3295
|
+
return numbering;
|
|
3296
|
+
};
|
|
3685
3297
|
return {
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3298
|
+
...base,
|
|
3299
|
+
listItems: () => {
|
|
3300
|
+
const body = root().children?.find((n) => n.kind === "body");
|
|
3301
|
+
const items = layout.resolveStoryListItems(
|
|
3302
|
+
body?.children ?? [],
|
|
3303
|
+
index(),
|
|
3304
|
+
cascade
|
|
3305
|
+
);
|
|
3306
|
+
const out = /* @__PURE__ */ new Map();
|
|
3307
|
+
for (const [id, item] of items)
|
|
3308
|
+
out.set(id, {
|
|
3309
|
+
numId: item.numId,
|
|
3310
|
+
ilvl: item.ilvl,
|
|
3311
|
+
markerText: item.markerText,
|
|
3312
|
+
numFmt: item.numFmt
|
|
3313
|
+
});
|
|
3314
|
+
return out;
|
|
3315
|
+
},
|
|
3316
|
+
levelOf: (numId, ilvl) => {
|
|
3317
|
+
const level = layout.resolveNumberingLevel(index(), numId, ilvl)?.level;
|
|
3318
|
+
return level ? { lvlText: level.lvlText, numFmt: level.numFmt } : null;
|
|
3319
|
+
},
|
|
3320
|
+
runsXml: (paragraphId) => {
|
|
3321
|
+
const node = findNode2(root(), paragraphId);
|
|
3322
|
+
return node ? paragraphRunsXml(node) : null;
|
|
3323
|
+
}
|
|
3692
3324
|
};
|
|
3693
3325
|
}
|
|
3694
|
-
|
|
3695
|
-
|
|
3326
|
+
var DEFAULT_CROSS_REFERENCES_LABELS = {
|
|
3327
|
+
insert: "Insert cross-reference",
|
|
3328
|
+
title: "Insert cross-reference",
|
|
3329
|
+
description: "Refer to a clause of this document, or to a passage of another document.",
|
|
3330
|
+
thisDocument: "This document",
|
|
3331
|
+
otherDocument: "Another document",
|
|
3332
|
+
filterTargets: "Find a clause or heading",
|
|
3333
|
+
noTargets: "This document has no numbered clauses or headings yet.",
|
|
3334
|
+
number: "Paragraph number",
|
|
3335
|
+
text: "Heading text",
|
|
3336
|
+
insertAs: "Insert",
|
|
3337
|
+
chooseDocument: "Choose a document",
|
|
3338
|
+
filterPassages: "Find a passage",
|
|
3339
|
+
loadingPassages: "Loading passages\u2026",
|
|
3340
|
+
noPassages: "No passage matches.",
|
|
3341
|
+
referenceText: "Reference text",
|
|
3342
|
+
insertButton: "Insert",
|
|
3343
|
+
cancel: "Cancel",
|
|
3344
|
+
clause: (number) => `Clause ${number}`,
|
|
3345
|
+
heading: "Heading",
|
|
3346
|
+
update: "Update cross-references",
|
|
3347
|
+
updated: "Cross-references updated",
|
|
3348
|
+
updateSummary: (refreshed) => refreshed ? `${refreshed} cross-reference${refreshed === 1 ? "" : "s"} brought up to date.` : "Every cross-reference is up to date.",
|
|
3349
|
+
brokenTitle: "Broken cross-references",
|
|
3350
|
+
brokenNone: "No cross-reference points at a deleted target.",
|
|
3351
|
+
brokenHelp: "Their target was deleted: the last text is kept and marked. Insert the reference again to repair it.",
|
|
3352
|
+
brokenCard: "Broken cross-reference",
|
|
3353
|
+
brokenCardBody: "Its target was deleted. Update cross-references to mark it.",
|
|
3354
|
+
show: "Show",
|
|
3355
|
+
close: "Close"
|
|
3356
|
+
};
|
|
3357
|
+
var CrossReferencesContext = React4.createContext(null);
|
|
3358
|
+
var useCrossReferences = () => React4.useContext(CrossReferencesContext);
|
|
3359
|
+
function CrossReferencesProvider({
|
|
3360
|
+
children,
|
|
3361
|
+
editable,
|
|
3362
|
+
references,
|
|
3363
|
+
documentId,
|
|
3364
|
+
notify,
|
|
3365
|
+
labels
|
|
3366
|
+
}) {
|
|
3696
3367
|
const editor = react.useDocxEditor();
|
|
3697
|
-
const
|
|
3698
|
-
const
|
|
3699
|
-
|
|
3368
|
+
const track = useTrackedOrNoted();
|
|
3369
|
+
const l = React4.useMemo(() => ({ ...DEFAULT_CROSS_REFERENCES_LABELS, ...labels }), [labels]);
|
|
3370
|
+
const [dialog, setDialog] = React4.useState(
|
|
3371
|
+
null
|
|
3700
3372
|
);
|
|
3701
|
-
const
|
|
3702
|
-
const
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
)
|
|
3706
|
-
|
|
3373
|
+
const marker = React4.useRef(null);
|
|
3374
|
+
const [viewer, setViewer] = React4.useState(null);
|
|
3375
|
+
React4.useEffect(() => setViewer(marker.current?.closest(".native-docx-viewer") ?? null), []);
|
|
3376
|
+
const openDialog = React4.useCallback(() => {
|
|
3377
|
+
if (!editor || !editable) return;
|
|
3378
|
+
try {
|
|
3379
|
+
const port = referencesPort(editor);
|
|
3380
|
+
const caret = port.caret();
|
|
3381
|
+
if (!caret) return notify?.("Place the cursor where the reference should go.", "error");
|
|
3382
|
+
setDialog({ caret, targets: listTargets(port.paragraphs(), port.listItems(), port.levelOf) });
|
|
3383
|
+
} catch (error) {
|
|
3384
|
+
notify?.(error instanceof Error ? error.message : "Could not read the document.", "error");
|
|
3385
|
+
}
|
|
3386
|
+
}, [editor, editable, notify]);
|
|
3387
|
+
const run2 = React4.useCallback(
|
|
3388
|
+
(label, prepare, insert) => {
|
|
3389
|
+
if (!editor) return;
|
|
3390
|
+
try {
|
|
3391
|
+
const prepared = withDirectEditing(editor, prepare);
|
|
3392
|
+
if (dialog) referencesPort(editor).setCaret(dialog.caret);
|
|
3393
|
+
track({ label, insert: (revision) => insert(prepared, revision), inserted: () => true });
|
|
3394
|
+
setDialog(null);
|
|
3395
|
+
editor.surface?.focus();
|
|
3396
|
+
holdCaret(editor);
|
|
3397
|
+
} catch (error) {
|
|
3398
|
+
notify?.(
|
|
3399
|
+
error instanceof Error ? error.message : "Could not insert the reference.",
|
|
3400
|
+
"error"
|
|
3401
|
+
);
|
|
3402
|
+
}
|
|
3403
|
+
},
|
|
3404
|
+
[editor, dialog, track, notify]
|
|
3707
3405
|
);
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3406
|
+
React4.useEffect(() => {
|
|
3407
|
+
if (!editor || !editable) return;
|
|
3408
|
+
const refresh = () => {
|
|
3409
|
+
try {
|
|
3410
|
+
const port = referencesPort(editor);
|
|
3411
|
+
if (!port.paragraphs().some((p) => p.fields?.length)) return;
|
|
3412
|
+
preservingCaret(editor, () => withDirectEditing(editor, () => refreshCrossReferences(port)));
|
|
3413
|
+
} catch {
|
|
3414
|
+
}
|
|
3415
|
+
};
|
|
3416
|
+
const off = onBeforeSave(editor, refresh);
|
|
3417
|
+
const timer = setTimeout(refresh, 1500);
|
|
3418
|
+
return () => {
|
|
3419
|
+
off();
|
|
3420
|
+
clearTimeout(timer);
|
|
3421
|
+
};
|
|
3422
|
+
}, [editor, editable]);
|
|
3423
|
+
const [report, setReport] = React4.useState(null);
|
|
3424
|
+
const update = React4.useCallback(() => {
|
|
3425
|
+
if (!editor || !editable) return;
|
|
3426
|
+
try {
|
|
3427
|
+
const result = preservingCaret(
|
|
3428
|
+
editor,
|
|
3429
|
+
() => withDirectEditing(editor, () => refreshCrossReferences(referencesPort(editor)))
|
|
3430
|
+
);
|
|
3431
|
+
setReport(result);
|
|
3432
|
+
} catch (error) {
|
|
3433
|
+
notify?.(
|
|
3434
|
+
error instanceof Error ? error.message : "Could not update cross-references.",
|
|
3435
|
+
"error"
|
|
3436
|
+
);
|
|
3437
|
+
}
|
|
3438
|
+
}, [editor, editable, notify]);
|
|
3439
|
+
const [passages, setPassages] = React4.useState({});
|
|
3440
|
+
const loadPassages = React4.useCallback(
|
|
3441
|
+
(id) => {
|
|
3442
|
+
if (!references || passages[id]) return;
|
|
3443
|
+
setPassages((p) => ({ ...p, [id]: "loading" }));
|
|
3444
|
+
references.passages(id).then((list) => setPassages((p) => ({ ...p, [id]: list }))).catch(() => setPassages((p) => ({ ...p, [id]: [] })));
|
|
3445
|
+
},
|
|
3446
|
+
[references, passages]
|
|
3447
|
+
);
|
|
3448
|
+
React4.useEffect(() => {
|
|
3449
|
+
if (!viewer || !references) return;
|
|
3450
|
+
const targetOf = (event) => {
|
|
3451
|
+
const link = event.target?.closest?.(
|
|
3452
|
+
'a.docx-hyperlink[data-docx-link-kind="external"]'
|
|
3453
|
+
);
|
|
3454
|
+
if (!link || !viewer.contains(link)) return null;
|
|
3455
|
+
const mouse = event;
|
|
3456
|
+
if (mouse.button !== 0 || mouse.ctrlKey || mouse.metaKey || mouse.shiftKey) return null;
|
|
3457
|
+
return references.targetOf(link.getAttribute("href") ?? "");
|
|
3458
|
+
};
|
|
3459
|
+
const take = (event) => {
|
|
3460
|
+
const target = targetOf(event);
|
|
3461
|
+
if (!target) return;
|
|
3462
|
+
event.preventDefault();
|
|
3463
|
+
event.stopPropagation();
|
|
3464
|
+
if (event.type === "click") references.open(target);
|
|
3465
|
+
};
|
|
3466
|
+
const types = ["pointerdown", "mousedown", "pointerup", "mouseup", "click"];
|
|
3467
|
+
for (const type of types) window.addEventListener(type, take, true);
|
|
3468
|
+
return () => {
|
|
3469
|
+
for (const type of types) window.removeEventListener(type, take, true);
|
|
3470
|
+
};
|
|
3471
|
+
}, [viewer, references]);
|
|
3472
|
+
const value = React4.useMemo(
|
|
3473
|
+
() => editable ? { openDialog, update, labels: l } : null,
|
|
3474
|
+
[editable, openDialog, update, l]
|
|
3475
|
+
);
|
|
3476
|
+
const resolveInternal = (href) => {
|
|
3477
|
+
if (!editor) return null;
|
|
3478
|
+
const name = href.replace(/^#/, "");
|
|
3479
|
+
try {
|
|
3480
|
+
const port = referencesPort(editor);
|
|
3481
|
+
const paragraphs = port.paragraphs();
|
|
3482
|
+
const target = paragraphs.find((p) => p.bookmarks.includes(name));
|
|
3483
|
+
if (!target) return { title: l.brokenCard, body: l.brokenCardBody };
|
|
3484
|
+
const number = paragraphNumber(
|
|
3485
|
+
paragraphs.map((p) => p.id),
|
|
3486
|
+
port.listItems(),
|
|
3487
|
+
port.levelOf,
|
|
3488
|
+
target.id
|
|
3489
|
+
);
|
|
3490
|
+
return {
|
|
3491
|
+
title: number ? l.clause(number) : l.heading,
|
|
3492
|
+
body: passageExcerpt(target.text.replace(//g, ""))
|
|
3493
|
+
};
|
|
3494
|
+
} catch {
|
|
3495
|
+
return null;
|
|
3496
|
+
}
|
|
3718
3497
|
};
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
resetKey: query
|
|
3725
|
-
});
|
|
3726
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "native-docx-style-gallery", "data-testid": "docx-style-gallery", children: [
|
|
3727
|
-
quick.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "native-docx-style-quick", role: "group", "aria-label": "Quick styles", children: quick.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3728
|
-
"button",
|
|
3729
|
-
{
|
|
3730
|
-
type: "button",
|
|
3731
|
-
"aria-pressed": value === option.styleId,
|
|
3732
|
-
disabled: !isEnabled,
|
|
3733
|
-
"data-style-id": option.styleId,
|
|
3734
|
-
title: styleLabel(option.name),
|
|
3735
|
-
onClick: () => apply(option),
|
|
3736
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: previewStyle(option), children: styleLabel(option.name) })
|
|
3737
|
-
},
|
|
3738
|
-
option.styleId
|
|
3739
|
-
)) }),
|
|
3740
|
-
options.length > FILTER_FROM && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3741
|
-
"input",
|
|
3498
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(CrossReferencesContext.Provider, { value, children: [
|
|
3499
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { ref: marker, hidden: true }),
|
|
3500
|
+
children,
|
|
3501
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3502
|
+
LinkHoverCard,
|
|
3742
3503
|
{
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
autoFocus: true,
|
|
3748
|
-
onChange: (event) => setQuery(event.target.value),
|
|
3749
|
-
onKeyDown: (event) => {
|
|
3750
|
-
nav.handleKeyDown(event);
|
|
3751
|
-
},
|
|
3752
|
-
...nav.comboboxProps
|
|
3504
|
+
root: viewer,
|
|
3505
|
+
matches: (href) => href.startsWith(`#${REF_BOOKMARK_PREFIX}`),
|
|
3506
|
+
resolve: resolveInternal,
|
|
3507
|
+
testId: "docx-cross-reference-card"
|
|
3753
3508
|
}
|
|
3754
3509
|
),
|
|
3755
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3756
|
-
|
|
3510
|
+
references && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3511
|
+
LinkHoverCard,
|
|
3757
3512
|
{
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
onMouseEnter: () => nav.setSelectedIndex(index),
|
|
3773
|
-
onClick: () => isEnabled && apply(option),
|
|
3774
|
-
children: [
|
|
3775
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: previewStyle(option), children: styleLabel(option.name) }),
|
|
3776
|
-
changed.has(option.styleId) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3777
|
-
"span",
|
|
3778
|
-
{
|
|
3779
|
-
className: "native-docx-style-diverged",
|
|
3780
|
-
title: "Defined differently from the house template",
|
|
3781
|
-
"aria-label": "Defined differently from the house template"
|
|
3782
|
-
}
|
|
3783
|
-
)
|
|
3784
|
-
]
|
|
3785
|
-
},
|
|
3786
|
-
option.styleId
|
|
3787
|
-
)),
|
|
3788
|
-
shown.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("li", { className: "native-docx-style-empty", children: "No matching style" })
|
|
3789
|
-
]
|
|
3513
|
+
root: viewer,
|
|
3514
|
+
matches: (href) => !!references.targetOf(href),
|
|
3515
|
+
resolve: (href) => {
|
|
3516
|
+
const target = references.targetOf(href);
|
|
3517
|
+
if (!target) return null;
|
|
3518
|
+
const list = passages[target.documentId];
|
|
3519
|
+
if (!list) loadPassages(target.documentId);
|
|
3520
|
+
const passage = Array.isArray(list) ? list.find((p) => p.chunkId === target.chunkId) : void 0;
|
|
3521
|
+
return passage ? {
|
|
3522
|
+
body: passageExcerpt(passage.text),
|
|
3523
|
+
footer: passage.page ? `p. ${passage.page}` : void 0
|
|
3524
|
+
} : null;
|
|
3525
|
+
},
|
|
3526
|
+
testId: "docx-cross-reference-card"
|
|
3790
3527
|
}
|
|
3791
|
-
)
|
|
3792
|
-
] });
|
|
3793
|
-
}
|
|
3794
|
-
function StyleGallery() {
|
|
3795
|
-
const { value, options } = react.useParagraphStyle();
|
|
3796
|
-
const current = options.find((o) => o.styleId === value);
|
|
3797
|
-
const name = current ? styleLabel(current.name) : "Styles";
|
|
3798
|
-
const house = useHouseTemplate();
|
|
3799
|
-
const diverged = house?.basedOnTemplate ? divergenceSummary(house.divergence) : null;
|
|
3800
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3801
|
-
RibbonMenu,
|
|
3802
|
-
{
|
|
3803
|
-
label: "Styles",
|
|
3804
|
-
title: diverged ? `Styles. ${diverged}` : void 0,
|
|
3805
|
-
className: "native-docx-style-trigger",
|
|
3806
|
-
testId: "docx-style-trigger",
|
|
3807
|
-
icon: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3808
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "native-docx-style-current", "data-testid": "docx-current-style", children: name }),
|
|
3809
|
-
diverged && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3810
|
-
"span",
|
|
3811
|
-
{
|
|
3812
|
-
className: "native-docx-style-diverged",
|
|
3813
|
-
"data-testid": "docx-style-diverged",
|
|
3814
|
-
"aria-label": diverged
|
|
3815
|
-
}
|
|
3816
|
-
),
|
|
3817
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { size: 12, "aria-hidden": true })
|
|
3818
|
-
] }),
|
|
3819
|
-
children: (close) => /* @__PURE__ */ jsxRuntime.jsx(Gallery, { close })
|
|
3820
|
-
}
|
|
3821
|
-
);
|
|
3822
|
-
}
|
|
3823
|
-
var W = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
|
|
3824
|
-
var DEFAULT_PARAGRAPH_FONT = {
|
|
3825
|
-
id: "DefaultParagraphFont",
|
|
3826
|
-
type: "character",
|
|
3827
|
-
xml: '<w:style w:type="character" w:default="1" w:styleId="DefaultParagraphFont"><w:name w:val="Default Paragraph Font"/><w:uiPriority w:val="1"/><w:semiHidden/><w:unhideWhenUsed/></w:style>'
|
|
3828
|
-
};
|
|
3829
|
-
function stylesOf(kind) {
|
|
3830
|
-
const Kind = kind === "footnote" ? "Footnote" : "Endnote";
|
|
3831
|
-
const text = `${Kind}Text`;
|
|
3832
|
-
return [
|
|
3833
|
-
{
|
|
3834
|
-
id: text,
|
|
3835
|
-
type: "paragraph",
|
|
3836
|
-
xml: `<w:style w:type="paragraph" w:styleId="${text}"><w:name w:val="${kind} text"/><w:basedOn w:val="Normal"/><w:link w:val="${text}Char"/><w:uiPriority w:val="99"/><w:semiHidden/><w:unhideWhenUsed/><w:pPr><w:spacing w:after="0" w:line="240" w:lineRule="auto"/></w:pPr><w:rPr><w:sz w:val="20"/><w:szCs w:val="20"/></w:rPr></w:style>`
|
|
3837
|
-
},
|
|
3838
|
-
{
|
|
3839
|
-
id: `${text}Char`,
|
|
3840
|
-
type: "character",
|
|
3841
|
-
xml: `<w:style w:type="character" w:customStyle="1" w:styleId="${text}Char"><w:name w:val="${Kind} Text Char"/><w:basedOn w:val="DefaultParagraphFont"/><w:link w:val="${text}"/><w:uiPriority w:val="99"/><w:semiHidden/><w:rPr><w:sz w:val="20"/><w:szCs w:val="20"/></w:rPr></w:style>`
|
|
3842
|
-
},
|
|
3843
|
-
{
|
|
3844
|
-
id: `${Kind}Reference`,
|
|
3845
|
-
type: "character",
|
|
3846
|
-
xml: `<w:style w:type="character" w:styleId="${Kind}Reference"><w:name w:val="${kind} reference"/><w:basedOn w:val="DefaultParagraphFont"/><w:uiPriority w:val="99"/><w:semiHidden/><w:unhideWhenUsed/><w:rPr><w:vertAlign w:val="superscript"/></w:rPr></w:style>`
|
|
3847
|
-
}
|
|
3848
|
-
];
|
|
3849
|
-
}
|
|
3850
|
-
function noteTextStyle(styles, kind) {
|
|
3851
|
-
const paragraph = styles.filter((style) => style.type === "paragraph");
|
|
3852
|
-
const id = kind === "footnote" ? "FootnoteText" : "EndnoteText";
|
|
3853
|
-
return paragraph.find((style) => style.name.toLowerCase() === `${kind} text`)?.styleId ?? paragraph.find((style) => style.styleId === id)?.styleId;
|
|
3854
|
-
}
|
|
3855
|
-
function missingNoteStyles(styles, kind) {
|
|
3856
|
-
const has = (type, id) => styles.some((style) => style.type === type && style.styleId === id);
|
|
3857
|
-
const text = noteTextStyle(styles, kind);
|
|
3858
|
-
const missing = stylesOf(kind).filter(
|
|
3859
|
-
(style) => style.type === "paragraph" ? !text : !has("character", style.id)
|
|
3860
|
-
);
|
|
3861
|
-
if (!missing.length) return [];
|
|
3862
|
-
const base = has("character", DEFAULT_PARAGRAPH_FONT.id) ? [] : [DEFAULT_PARAGRAPH_FONT];
|
|
3863
|
-
return [...base, ...missing].map((style) => style.xml);
|
|
3864
|
-
}
|
|
3865
|
-
var CONTENT_TYPES = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/><Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/></Types>';
|
|
3866
|
-
function stylesOnlyClipboardHtml(styles) {
|
|
3867
|
-
const fragment = fflate.zipSync({
|
|
3868
|
-
"[Content_Types].xml": fflate.strToU8(CONTENT_TYPES),
|
|
3869
|
-
"_rels/.rels": fflate.strToU8(
|
|
3870
|
-
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/></Relationships>'
|
|
3871
|
-
),
|
|
3872
|
-
"word/document.xml": fflate.strToU8(
|
|
3873
|
-
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
3874
|
-
<w:document xmlns:w="${W}"><w:body><w:p/></w:body></w:document>`
|
|
3875
3528
|
),
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
),
|
|
3879
|
-
"word/styles.xml": fflate.strToU8(
|
|
3880
|
-
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
3881
|
-
<w:styles xmlns:w="${W}">${styles.join("")}</w:styles>`
|
|
3882
|
-
)
|
|
3883
|
-
});
|
|
3884
|
-
return template.fragmentClipboardHtml(fragment, false);
|
|
3885
|
-
}
|
|
3886
|
-
function ensureNoteStyles(editor, kind, direct = (fn) => fn()) {
|
|
3887
|
-
if (!editor.can({ type: "insertNote", noteKind: kind }).ok) return void 0;
|
|
3888
|
-
const missing = missingNoteStyles(editor.getDocumentStyles(), kind);
|
|
3889
|
-
if (missing.length)
|
|
3890
|
-
direct(() => editor.exec({ type: "paste", text: "", html: stylesOnlyClipboardHtml(missing) }));
|
|
3891
|
-
return noteTextStyle(editor.getDocumentStyles(), kind);
|
|
3892
|
-
}
|
|
3893
|
-
function useInsertNote(kind) {
|
|
3894
|
-
const command = react.useEditorCommand(kind === "footnote" ? "insert.footnote" : "insert.endnote");
|
|
3895
|
-
const editor = react.useDocxEditor();
|
|
3896
|
-
const insert = () => {
|
|
3897
|
-
const text = editor && ensureNoteStyles(editor, kind, (fn) => withDirectEditing(editor, fn));
|
|
3898
|
-
if (!command.execute()) return false;
|
|
3899
|
-
if (editor) {
|
|
3900
|
-
if (text)
|
|
3901
|
-
withDirectEditing(editor, () => editor.exec({ type: "setParagraphStyle", styleId: text }));
|
|
3902
|
-
editor.exec({ type: "insertText", text: " " });
|
|
3903
|
-
}
|
|
3904
|
-
return true;
|
|
3905
|
-
};
|
|
3906
|
-
return { insert, isEnabled: command.isEnabled, disabledReason: command.disabledReason };
|
|
3907
|
-
}
|
|
3908
|
-
function NoteAction({
|
|
3909
|
-
kind,
|
|
3910
|
-
label,
|
|
3911
|
-
shortcut,
|
|
3912
|
-
icon
|
|
3913
|
-
}) {
|
|
3914
|
-
const note = useInsertNote(kind);
|
|
3915
|
-
return /* @__PURE__ */ jsxRuntime.jsx(RibbonItem, { id: `references-${kind}`, label, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3916
|
-
react.DocxEditor.Toolbar.Action,
|
|
3917
|
-
{
|
|
3918
|
-
label: `${label} (${shortcut})`,
|
|
3919
|
-
icon,
|
|
3920
|
-
disabled: !note.isEnabled,
|
|
3921
|
-
disabledReason: note.disabledReason ?? void 0,
|
|
3922
|
-
onSelect: () => void note.insert(),
|
|
3923
|
-
className: `native-docx-insert-${kind}`
|
|
3924
|
-
}
|
|
3925
|
-
) });
|
|
3926
|
-
}
|
|
3927
|
-
function NoteButtons() {
|
|
3928
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3929
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3930
|
-
NoteAction,
|
|
3529
|
+
dialog && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3530
|
+
CrossReferenceDialog,
|
|
3931
3531
|
{
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3532
|
+
targets: dialog.targets,
|
|
3533
|
+
references,
|
|
3534
|
+
documentId,
|
|
3535
|
+
passages,
|
|
3536
|
+
loadPassages,
|
|
3537
|
+
labels: l,
|
|
3538
|
+
onCancel: () => setDialog(null),
|
|
3539
|
+
onClosed: () => editor?.surface?.focus(),
|
|
3540
|
+
onInsertTarget: (target, mode) => run2(
|
|
3541
|
+
`Inserted cross-reference: ${refResult(target, mode)}`,
|
|
3542
|
+
() => markCrossReferenceTarget(referencesPort(editor), target, mode),
|
|
3543
|
+
(marked, revision) => insertCrossReferenceField(referencesPort(editor, revision), marked, dialog.caret)
|
|
3544
|
+
),
|
|
3545
|
+
onInsertPassage: (target, text) => run2(
|
|
3546
|
+
`Inserted cross-reference: ${text}`,
|
|
3547
|
+
() => void 0,
|
|
3548
|
+
(_, revision) => insertDocumentReference(
|
|
3549
|
+
referencesPort(editor, revision),
|
|
3550
|
+
{ text, url: references.linkFor(target), appName: references.appName },
|
|
3551
|
+
dialog.caret
|
|
3552
|
+
)
|
|
3553
|
+
)
|
|
3936
3554
|
}
|
|
3937
3555
|
),
|
|
3938
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3939
|
-
|
|
3556
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Dialog, { open: !!report, onOpenChange: (open) => !open && setReport(null), children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3557
|
+
ui.DialogContent,
|
|
3940
3558
|
{
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3559
|
+
className: "max-h-[85dvh] overflow-y-auto",
|
|
3560
|
+
"data-testid": "docx-cross-references-report",
|
|
3561
|
+
children: [
|
|
3562
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.DialogHeader, { children: [
|
|
3563
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DialogTitle, { children: l.updated }),
|
|
3564
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DialogDescription, { children: report && l.updateSummary(report.refreshed) })
|
|
3565
|
+
] }),
|
|
3566
|
+
report && /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "space-y-1 text-sm", children: [
|
|
3567
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-medium", children: l.brokenTitle }),
|
|
3568
|
+
report.broken.length ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3569
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: l.brokenHelp }),
|
|
3570
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-1", "data-testid": "docx-cross-references-broken", children: report.broken.map((b) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3571
|
+
"li",
|
|
3572
|
+
{
|
|
3573
|
+
className: "flex items-center justify-between gap-2",
|
|
3574
|
+
children: [
|
|
3575
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-text", children: b.text }),
|
|
3576
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3577
|
+
ui.Button,
|
|
3578
|
+
{
|
|
3579
|
+
size: "sm",
|
|
3580
|
+
variant: "ghost",
|
|
3581
|
+
onClick: () => {
|
|
3582
|
+
const point = { paragraphId: b.paragraphId, offset: b.offset };
|
|
3583
|
+
editor?.surface?.setSelection({ anchor: point, head: point });
|
|
3584
|
+
editor?.surface?.revealParagraph(b.paragraphId);
|
|
3585
|
+
setReport(null);
|
|
3586
|
+
},
|
|
3587
|
+
children: l.show
|
|
3588
|
+
}
|
|
3589
|
+
)
|
|
3590
|
+
]
|
|
3591
|
+
},
|
|
3592
|
+
`${b.paragraphId}:${b.offset}`
|
|
3593
|
+
)) })
|
|
3594
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: l.brokenNone })
|
|
3595
|
+
] }),
|
|
3596
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DialogFooter, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "outline", onClick: () => setReport(null), children: l.close }) })
|
|
3597
|
+
]
|
|
3945
3598
|
}
|
|
3946
|
-
)
|
|
3599
|
+
) })
|
|
3947
3600
|
] });
|
|
3948
3601
|
}
|
|
3949
|
-
function
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3602
|
+
function CrossReferenceDialog({
|
|
3603
|
+
targets,
|
|
3604
|
+
references,
|
|
3605
|
+
documentId,
|
|
3606
|
+
passages,
|
|
3607
|
+
loadPassages,
|
|
3608
|
+
labels,
|
|
3609
|
+
onCancel,
|
|
3610
|
+
onInsertTarget,
|
|
3611
|
+
onInsertPassage,
|
|
3612
|
+
onClosed
|
|
3613
|
+
}) {
|
|
3614
|
+
const l = { ...DEFAULT_CROSS_REFERENCES_LABELS, ...labels };
|
|
3615
|
+
const [tab, setTab] = React4.useState("this");
|
|
3616
|
+
const [query, setQuery] = React4.useState("");
|
|
3617
|
+
const [chosen, setChosen] = React4.useState(null);
|
|
3618
|
+
const [mode, setMode] = React4.useState("number");
|
|
3619
|
+
const shown = React4.useMemo(() => filterTargets(targets, query), [targets, query]);
|
|
3620
|
+
const effectiveMode = chosen?.number ? mode : "text";
|
|
3621
|
+
const [documents, setDocuments] = React4.useState(null);
|
|
3622
|
+
const [docId, setDocId] = React4.useState(null);
|
|
3623
|
+
const [passageQuery, setPassageQuery] = React4.useState("");
|
|
3624
|
+
const [passage, setPassage] = React4.useState(null);
|
|
3625
|
+
const [text, setText] = React4.useState("");
|
|
3957
3626
|
React4.useEffect(() => {
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3627
|
+
if (tab !== "other" || !references || documents) return;
|
|
3628
|
+
references.documents().then((list2) => setDocuments(list2.filter((d) => d.id !== documentId))).catch(() => setDocuments([]));
|
|
3629
|
+
}, [tab, references, documents, documentId]);
|
|
3630
|
+
const chooseDocument = (id) => {
|
|
3631
|
+
setDocId(id);
|
|
3632
|
+
setPassage(null);
|
|
3633
|
+
setText("");
|
|
3634
|
+
loadPassages(id);
|
|
3635
|
+
};
|
|
3636
|
+
const title = documents?.find((d) => d.id === docId)?.title ?? "";
|
|
3637
|
+
const list = docId ? passages[docId] : void 0;
|
|
3638
|
+
const shownPassages = Array.isArray(list) ? filterPassages(list, passageQuery) : [];
|
|
3639
|
+
const canInsert = tab === "this" ? !!chosen : !!(docId && passage && text.trim());
|
|
3640
|
+
const insert = () => {
|
|
3641
|
+
if (tab === "this" && chosen) onInsertTarget(chosen, effectiveMode);
|
|
3642
|
+
if (tab === "other" && docId && passage)
|
|
3643
|
+
onInsertPassage(
|
|
3644
|
+
{ documentId: docId, chunkId: passage.chunkId, page: passage.page ?? null },
|
|
3645
|
+
text
|
|
3646
|
+
);
|
|
3647
|
+
};
|
|
3648
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ui.Dialog, { open: true, onOpenChange: (open) => !open && onCancel(), children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3649
|
+
ui.DialogContent,
|
|
3650
|
+
{
|
|
3651
|
+
className: "max-h-[85dvh] overflow-y-auto",
|
|
3652
|
+
"data-testid": "docx-cross-reference-dialog",
|
|
3653
|
+
onCloseAutoFocus: (event) => {
|
|
3654
|
+
if (!onClosed) return;
|
|
3962
3655
|
event.preventDefault();
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3656
|
+
onClosed();
|
|
3657
|
+
},
|
|
3658
|
+
children: [
|
|
3659
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.DialogHeader, { children: [
|
|
3660
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DialogTitle, { children: l.title }),
|
|
3661
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DialogDescription, { children: l.description })
|
|
3662
|
+
] }),
|
|
3663
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Tabs, { value: tab, onValueChange: (v) => setTab(v), children: [
|
|
3664
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.TabsList, { children: [
|
|
3665
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.TabsTrigger, { value: "this", "data-testid": "docx-cross-reference-this", children: l.thisDocument }),
|
|
3666
|
+
references && /* @__PURE__ */ jsxRuntime.jsx(ui.TabsTrigger, { value: "other", "data-testid": "docx-cross-reference-other", children: l.otherDocument })
|
|
3667
|
+
] }),
|
|
3668
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.TabsContent, { value: "this", className: "space-y-3", children: [
|
|
3669
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3670
|
+
ui.Input,
|
|
3671
|
+
{
|
|
3672
|
+
value: query,
|
|
3673
|
+
placeholder: l.filterTargets,
|
|
3674
|
+
"aria-label": l.filterTargets,
|
|
3675
|
+
onChange: (e) => setQuery(e.target.value),
|
|
3676
|
+
"data-testid": "docx-cross-reference-filter"
|
|
3677
|
+
}
|
|
3678
|
+
),
|
|
3679
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3680
|
+
"div",
|
|
3681
|
+
{
|
|
3682
|
+
role: "listbox",
|
|
3683
|
+
"aria-label": l.filterTargets,
|
|
3684
|
+
className: "max-h-64 space-y-0.5 overflow-y-auto rounded-md border border-border p-1",
|
|
3685
|
+
children: [
|
|
3686
|
+
shown.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "p-2 text-sm text-muted-foreground", children: l.noTargets }),
|
|
3687
|
+
shown.map((t) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3688
|
+
"button",
|
|
3689
|
+
{
|
|
3690
|
+
type: "button",
|
|
3691
|
+
role: "option",
|
|
3692
|
+
"aria-selected": chosen?.paragraphId === t.paragraphId,
|
|
3693
|
+
"data-testid": "docx-cross-reference-target",
|
|
3694
|
+
onClick: () => setChosen(t),
|
|
3695
|
+
onDoubleClick: () => onInsertTarget(t, t.number ? mode : "text"),
|
|
3696
|
+
className: ui.cn(
|
|
3697
|
+
"flex w-full items-baseline gap-2 rounded px-2 py-1 text-left text-sm",
|
|
3698
|
+
chosen?.paragraphId === t.paragraphId ? "bg-accent" : "hover:bg-accent/50"
|
|
3699
|
+
),
|
|
3700
|
+
style: { paddingLeft: 8 + t.level * 16 },
|
|
3701
|
+
children: [
|
|
3702
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 font-mono text-xs text-muted-foreground", children: t.marker || l.heading }),
|
|
3703
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: ui.cn("truncate", t.heading && "font-medium"), children: t.text })
|
|
3704
|
+
]
|
|
3705
|
+
},
|
|
3706
|
+
t.paragraphId
|
|
3707
|
+
))
|
|
3708
|
+
]
|
|
3709
|
+
}
|
|
3710
|
+
),
|
|
3711
|
+
chosen && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-3 text-sm", children: [
|
|
3712
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: l.insertAs }),
|
|
3713
|
+
chosen.number && /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-1", children: [
|
|
3714
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3715
|
+
"input",
|
|
3716
|
+
{
|
|
3717
|
+
type: "radio",
|
|
3718
|
+
name: "cross-reference-mode",
|
|
3719
|
+
checked: effectiveMode === "number",
|
|
3720
|
+
onChange: () => setMode("number")
|
|
3721
|
+
}
|
|
3722
|
+
),
|
|
3723
|
+
l.number
|
|
3724
|
+
] }),
|
|
3725
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-1", children: [
|
|
3726
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3727
|
+
"input",
|
|
3728
|
+
{
|
|
3729
|
+
type: "radio",
|
|
3730
|
+
name: "cross-reference-mode",
|
|
3731
|
+
checked: effectiveMode === "text",
|
|
3732
|
+
onChange: () => setMode("text")
|
|
3733
|
+
}
|
|
3734
|
+
),
|
|
3735
|
+
l.text
|
|
3736
|
+
] }),
|
|
3737
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3738
|
+
"span",
|
|
3739
|
+
{
|
|
3740
|
+
className: "ml-auto rounded bg-muted px-2 py-0.5",
|
|
3741
|
+
"data-testid": "docx-cross-reference-preview",
|
|
3742
|
+
children: refResult(chosen, effectiveMode)
|
|
3743
|
+
}
|
|
3744
|
+
)
|
|
3745
|
+
] })
|
|
3746
|
+
] }),
|
|
3747
|
+
references && /* @__PURE__ */ jsxRuntime.jsxs(ui.TabsContent, { value: "other", className: "space-y-3", children: [
|
|
3748
|
+
references.renderDocumentPicker ? references.renderDocumentPicker(chooseDocument, docId) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3749
|
+
"select",
|
|
3750
|
+
{
|
|
3751
|
+
className: "h-9 w-full rounded-md border border-border bg-background px-2 text-sm",
|
|
3752
|
+
"aria-label": l.chooseDocument,
|
|
3753
|
+
value: docId ?? "",
|
|
3754
|
+
onChange: (e) => e.target.value && chooseDocument(e.target.value),
|
|
3755
|
+
"data-testid": "docx-cross-reference-document",
|
|
3756
|
+
children: [
|
|
3757
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: l.chooseDocument }),
|
|
3758
|
+
(documents ?? []).map((d) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: d.id, children: d.title }, d.id))
|
|
3759
|
+
]
|
|
3760
|
+
}
|
|
3761
|
+
),
|
|
3762
|
+
docId && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3763
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3764
|
+
ui.Input,
|
|
3765
|
+
{
|
|
3766
|
+
value: passageQuery,
|
|
3767
|
+
placeholder: l.filterPassages,
|
|
3768
|
+
"aria-label": l.filterPassages,
|
|
3769
|
+
onChange: (e) => setPassageQuery(e.target.value),
|
|
3770
|
+
"data-testid": "docx-cross-reference-passage-filter"
|
|
3771
|
+
}
|
|
3772
|
+
),
|
|
3773
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3774
|
+
"div",
|
|
3775
|
+
{
|
|
3776
|
+
className: "max-h-64 space-y-1 overflow-y-auto",
|
|
3777
|
+
"data-testid": "docx-cross-reference-passages",
|
|
3778
|
+
children: list === "loading" || list === void 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "p-2 text-sm text-muted-foreground", children: l.loadingPassages }) : shownPassages.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "p-2 text-sm text-muted-foreground", children: l.noPassages }) : shownPassages.map((p, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3779
|
+
chunk5FYU7ZIU_cjs.FactPassageItem,
|
|
3780
|
+
{
|
|
3781
|
+
index: i,
|
|
3782
|
+
page: p.page,
|
|
3783
|
+
excerpt: passageExcerpt(p.text, 200),
|
|
3784
|
+
isViewing: passage?.chunkId === p.chunkId,
|
|
3785
|
+
onSelect: () => {
|
|
3786
|
+
setPassage(p);
|
|
3787
|
+
setText(referenceText(title, p));
|
|
3788
|
+
},
|
|
3789
|
+
testId: "docx-cross-reference-passage"
|
|
3790
|
+
},
|
|
3791
|
+
p.chunkId
|
|
3792
|
+
))
|
|
3793
|
+
}
|
|
3794
|
+
),
|
|
3795
|
+
passage && /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block space-y-1 text-sm", children: [
|
|
3796
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: l.referenceText }),
|
|
3797
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3798
|
+
ui.Input,
|
|
3799
|
+
{
|
|
3800
|
+
value: text,
|
|
3801
|
+
onChange: (e) => setText(e.target.value),
|
|
3802
|
+
"data-testid": "docx-cross-reference-text"
|
|
3803
|
+
}
|
|
3804
|
+
)
|
|
3805
|
+
] })
|
|
3806
|
+
] })
|
|
3807
|
+
] })
|
|
3808
|
+
] }),
|
|
3809
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.DialogFooter, { children: [
|
|
3810
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "outline", onClick: onCancel, children: l.cancel }),
|
|
3811
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { disabled: !canInsert, onClick: insert, "data-testid": "docx-cross-reference-insert", children: l.insertButton })
|
|
3812
|
+
] })
|
|
3813
|
+
]
|
|
3814
|
+
}
|
|
3815
|
+
) });
|
|
3994
3816
|
}
|
|
3995
3817
|
function CrossReferenceButton() {
|
|
3996
3818
|
const references = useCrossReferences();
|
|
@@ -4657,6 +4479,186 @@ function LayoutTabContent({ tab }) {
|
|
|
4657
4479
|
if (tab === PICTURE_TAB) return /* @__PURE__ */ jsxRuntime.jsx(PictureButtons, {});
|
|
4658
4480
|
return null;
|
|
4659
4481
|
}
|
|
4482
|
+
var titleOf = (prompt) => {
|
|
4483
|
+
const line = prompt.trim().split("\n")[0];
|
|
4484
|
+
return line.length > 80 ? `${line.slice(0, 79)}\u2026` : line;
|
|
4485
|
+
};
|
|
4486
|
+
function rememberCaret(editor) {
|
|
4487
|
+
const surface = editor.surface;
|
|
4488
|
+
const head = surface?.state().selection?.head;
|
|
4489
|
+
if (!surface || !head) return null;
|
|
4490
|
+
return { paraId: surface.session.paraIdOf(head.paragraphId), ...head };
|
|
4491
|
+
}
|
|
4492
|
+
var mounted = [];
|
|
4493
|
+
var running = 0;
|
|
4494
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
4495
|
+
var setRunning = (delta) => {
|
|
4496
|
+
running += delta;
|
|
4497
|
+
listeners.forEach((listener) => listener());
|
|
4498
|
+
};
|
|
4499
|
+
var subscribe = (listener) => {
|
|
4500
|
+
listeners.add(listener);
|
|
4501
|
+
return () => void listeners.delete(listener);
|
|
4502
|
+
};
|
|
4503
|
+
function insertionTarget(origin, caret, editors = mounted) {
|
|
4504
|
+
if (editors.includes(origin) && origin.surface) return origin;
|
|
4505
|
+
const paraId = caret?.paraId;
|
|
4506
|
+
if (!paraId) return null;
|
|
4507
|
+
for (let i = editors.length - 1; i >= 0; i--) {
|
|
4508
|
+
const session = editors[i].surface?.session;
|
|
4509
|
+
if (session?.nodeIdOf(paraId)) return editors[i];
|
|
4510
|
+
}
|
|
4511
|
+
return null;
|
|
4512
|
+
}
|
|
4513
|
+
function restoreCaret(editor, caret) {
|
|
4514
|
+
const surface = editor.surface;
|
|
4515
|
+
if (!surface || !caret) return;
|
|
4516
|
+
const paragraphId = caret.paraId && surface.session.nodeIdOf(caret.paraId) || caret.paragraphId;
|
|
4517
|
+
if (!surface.session.paragraphIds().includes(paragraphId)) return;
|
|
4518
|
+
const point = { paragraphId, offset: caret.offset };
|
|
4519
|
+
surface.setSelection({ anchor: point, head: point });
|
|
4520
|
+
}
|
|
4521
|
+
async function insertGeneratedImage(editor$1, bytes, prompt, caret) {
|
|
4522
|
+
const image = react.normalizeImageBytes(bytes);
|
|
4523
|
+
if (!image.ok) throw new Error("The generated image is not in a format Word can embed.");
|
|
4524
|
+
let result;
|
|
4525
|
+
for (let attempt = 0; attempt < 3 && !result?.ok; attempt++) {
|
|
4526
|
+
editor$1.focus();
|
|
4527
|
+
restoreCaret(editor$1, caret);
|
|
4528
|
+
result = await editor.executeImageCommand(editor$1, {
|
|
4529
|
+
type: "insertImage",
|
|
4530
|
+
data: image.bytes,
|
|
4531
|
+
mime: image.mime,
|
|
4532
|
+
widthPoints: image.widthPoints,
|
|
4533
|
+
heightPoints: image.heightPoints,
|
|
4534
|
+
description: prompt.trim(),
|
|
4535
|
+
title: titleOf(prompt)
|
|
4536
|
+
});
|
|
4537
|
+
if (!result.ok && result.reason !== "stale drawing selection") break;
|
|
4538
|
+
}
|
|
4539
|
+
if (!result?.ok) throw new Error(result?.reason || "The picture could not be inserted here.");
|
|
4540
|
+
}
|
|
4541
|
+
var AUTO = "";
|
|
4542
|
+
function useGenerateImageTarget() {
|
|
4543
|
+
const editor = react.useDocxEditor();
|
|
4544
|
+
const loaded = react.useEditorState((snapshot) => !snapshot.isLoading);
|
|
4545
|
+
React4.useEffect(() => {
|
|
4546
|
+
if (!editor || !loaded) return;
|
|
4547
|
+
mounted.push(editor);
|
|
4548
|
+
return () => void mounted.splice(mounted.indexOf(editor), 1);
|
|
4549
|
+
}, [editor, loaded]);
|
|
4550
|
+
}
|
|
4551
|
+
function GenerateImageButton({ generation }) {
|
|
4552
|
+
const editor = react.useDocxEditor();
|
|
4553
|
+
const [prompt, setPrompt] = React4.useState("");
|
|
4554
|
+
const [aspectRatio, setAspectRatio] = React4.useState(AUTO);
|
|
4555
|
+
const [busy, setBusy] = React4.useState(false);
|
|
4556
|
+
const [error, setError] = React4.useState("");
|
|
4557
|
+
const abort = React4.useRef(null);
|
|
4558
|
+
const close = React4.useRef(() => {
|
|
4559
|
+
});
|
|
4560
|
+
const editable = react.useEditorState((snapshot) => snapshot.editable);
|
|
4561
|
+
const generating = React4.useSyncExternalStore(subscribe, () => running > 0);
|
|
4562
|
+
async function run2() {
|
|
4563
|
+
if (!editor || !prompt.trim() || busy) return;
|
|
4564
|
+
const caret = rememberCaret(editor);
|
|
4565
|
+
const controller = new AbortController();
|
|
4566
|
+
abort.current = controller;
|
|
4567
|
+
setBusy(true);
|
|
4568
|
+
setRunning(1);
|
|
4569
|
+
setError("");
|
|
4570
|
+
try {
|
|
4571
|
+
const bytes = await generation.generate(prompt.trim(), {
|
|
4572
|
+
aspectRatio: aspectRatio || void 0,
|
|
4573
|
+
signal: controller.signal
|
|
4574
|
+
});
|
|
4575
|
+
if (controller.signal.aborted) return;
|
|
4576
|
+
const target = insertionTarget(editor, caret);
|
|
4577
|
+
if (!target) throw new Error("The document was closed before the generated image was ready.");
|
|
4578
|
+
await insertGeneratedImage(target, bytes, prompt, caret);
|
|
4579
|
+
setPrompt("");
|
|
4580
|
+
close.current();
|
|
4581
|
+
generation.notify?.("Generated image inserted", "success");
|
|
4582
|
+
} catch (failure) {
|
|
4583
|
+
if (controller.signal.aborted) return;
|
|
4584
|
+
const message = failure instanceof Error ? failure.message : String(failure);
|
|
4585
|
+
setError(message);
|
|
4586
|
+
generation.notify?.(message, "error");
|
|
4587
|
+
} finally {
|
|
4588
|
+
abort.current = null;
|
|
4589
|
+
setRunning(-1);
|
|
4590
|
+
setBusy(false);
|
|
4591
|
+
}
|
|
4592
|
+
}
|
|
4593
|
+
if (!editable && !generating) return null;
|
|
4594
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4595
|
+
RibbonMenu,
|
|
4596
|
+
{
|
|
4597
|
+
label: generating ? "Generating image\u2026" : "Generate image",
|
|
4598
|
+
icon: generating ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: 16, className: "native-docx-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { size: 16 }),
|
|
4599
|
+
testId: "docx-generate-image",
|
|
4600
|
+
children: (dismiss) => {
|
|
4601
|
+
close.current = dismiss;
|
|
4602
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4603
|
+
"form",
|
|
4604
|
+
{
|
|
4605
|
+
className: "native-docx-form native-docx-generate-image",
|
|
4606
|
+
onSubmit: (event) => {
|
|
4607
|
+
event.preventDefault();
|
|
4608
|
+
void run2();
|
|
4609
|
+
},
|
|
4610
|
+
children: [
|
|
4611
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
4612
|
+
"Describe the image",
|
|
4613
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4614
|
+
"textarea",
|
|
4615
|
+
{
|
|
4616
|
+
autoFocus: true,
|
|
4617
|
+
rows: 3,
|
|
4618
|
+
value: prompt,
|
|
4619
|
+
disabled: busy,
|
|
4620
|
+
placeholder: "A watercolour of a lighthouse at dawn",
|
|
4621
|
+
"data-testid": "docx-generate-image-prompt",
|
|
4622
|
+
onChange: (event) => setPrompt(event.target.value),
|
|
4623
|
+
onKeyDown: (event) => {
|
|
4624
|
+
if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) void run2();
|
|
4625
|
+
}
|
|
4626
|
+
}
|
|
4627
|
+
)
|
|
4628
|
+
] }),
|
|
4629
|
+
generation.aspectRatios && generation.aspectRatios.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
4630
|
+
"Aspect ratio",
|
|
4631
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4632
|
+
"select",
|
|
4633
|
+
{
|
|
4634
|
+
value: aspectRatio,
|
|
4635
|
+
disabled: busy,
|
|
4636
|
+
onChange: (event) => setAspectRatio(event.target.value),
|
|
4637
|
+
children: [
|
|
4638
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: AUTO, children: "Auto" }),
|
|
4639
|
+
generation.aspectRatios.map((ratio) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: ratio.value, children: ratio.label }, ratio.value))
|
|
4640
|
+
]
|
|
4641
|
+
}
|
|
4642
|
+
)
|
|
4643
|
+
] }),
|
|
4644
|
+
busy && /* @__PURE__ */ jsxRuntime.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." }),
|
|
4645
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", children: error }),
|
|
4646
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "native-docx-form-actions", children: busy ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => abort.current?.abort(), children: "Cancel" }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
4647
|
+
"button",
|
|
4648
|
+
{
|
|
4649
|
+
type: "submit",
|
|
4650
|
+
disabled: !prompt.trim(),
|
|
4651
|
+
"data-testid": "docx-generate-image-submit",
|
|
4652
|
+
children: "Generate"
|
|
4653
|
+
}
|
|
4654
|
+
) })
|
|
4655
|
+
]
|
|
4656
|
+
}
|
|
4657
|
+
);
|
|
4658
|
+
}
|
|
4659
|
+
}
|
|
4660
|
+
);
|
|
4661
|
+
}
|
|
4660
4662
|
var contains = (node, id) => node.id === id || (node.children ?? []).some((child) => contains(child, id));
|
|
4661
4663
|
function firstParagraph(node) {
|
|
4662
4664
|
for (const child of node.children ?? []) {
|
|
@@ -4952,6 +4954,19 @@ function DocxRibbon({
|
|
|
4952
4954
|
badge && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "native-docx-ribbon-badge", "data-testid": "docx-ribbon-badge", children: badge })
|
|
4953
4955
|
] });
|
|
4954
4956
|
}
|
|
4957
|
+
function CompactToolbar() {
|
|
4958
|
+
const t = react.useChromeTranslate();
|
|
4959
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(react.DocxEditor.Toolbar, { t, preset: false, children: [
|
|
4960
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.Undo, {}),
|
|
4961
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.Redo, {}),
|
|
4962
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.Bold, {}),
|
|
4963
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.Italic, {}),
|
|
4964
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.Underline, {}),
|
|
4965
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.BulletList, {}),
|
|
4966
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.NumberedList, {}),
|
|
4967
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.Link, {})
|
|
4968
|
+
] });
|
|
4969
|
+
}
|
|
4955
4970
|
var fixedZoomMode = { type: "fixed" };
|
|
4956
4971
|
function NativeDocxEditor({
|
|
4957
4972
|
documentId,
|
|
@@ -4961,7 +4976,9 @@ function NativeDocxEditor({
|
|
|
4961
4976
|
snapshot = false,
|
|
4962
4977
|
onSaved,
|
|
4963
4978
|
stream,
|
|
4964
|
-
adapter
|
|
4979
|
+
adapter,
|
|
4980
|
+
compact = false,
|
|
4981
|
+
stateRef
|
|
4965
4982
|
}) {
|
|
4966
4983
|
const [ready, setReady] = React4.useState(), [error, setError] = React4.useState(""), [retry, setRetry] = React4.useState(0);
|
|
4967
4984
|
const [status, setStatus] = React4.useState("Connecting\u2026"), [dirty, setDirty] = React4.useState(false), [saving, setSaving] = React4.useState(false), [offline, setOffline] = React4.useState(false);
|
|
@@ -5132,6 +5149,14 @@ function NativeDocxEditor({
|
|
|
5132
5149
|
room?.destroy();
|
|
5133
5150
|
};
|
|
5134
5151
|
}, [documentId, isDraft, snapshot, retry]);
|
|
5152
|
+
React4.useEffect(() => {
|
|
5153
|
+
if (!stateRef) return;
|
|
5154
|
+
const room = ready?.room;
|
|
5155
|
+
stateRef.current = () => room ? encodeState(room) : void 0;
|
|
5156
|
+
return () => {
|
|
5157
|
+
stateRef.current = null;
|
|
5158
|
+
};
|
|
5159
|
+
}, [stateRef, ready?.room]);
|
|
5135
5160
|
React4.useEffect(() => {
|
|
5136
5161
|
adapter.onDirtyChange?.(dirty);
|
|
5137
5162
|
const beforeUnload = (e) => {
|
|
@@ -5215,7 +5240,7 @@ function NativeDocxEditor({
|
|
|
5215
5240
|
if (!pageWidth) return;
|
|
5216
5241
|
const style = getComputedStyle(viewport);
|
|
5217
5242
|
const available = viewport.clientWidth - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight);
|
|
5218
|
-
const zoom = Math.max(0.1, Math.min(2.5, available / pageWidth));
|
|
5243
|
+
const zoom = Math.max(0.1, Math.min(compact ? 1 : 2.5, available / pageWidth));
|
|
5219
5244
|
if (Math.abs(editor.getZoom() - zoom) > 1e-3) editor.setZoom(zoom);
|
|
5220
5245
|
};
|
|
5221
5246
|
const resize = new ResizeObserver(fit);
|
|
@@ -5251,7 +5276,7 @@ function NativeDocxEditor({
|
|
|
5251
5276
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5252
5277
|
"section",
|
|
5253
5278
|
{
|
|
5254
|
-
className: "native-docx-viewer",
|
|
5279
|
+
className: compact ? "native-docx-viewer native-docx-compact" : "native-docx-viewer",
|
|
5255
5280
|
"data-testid": "native-docx-editor",
|
|
5256
5281
|
"aria-busy": !!stream?.busy,
|
|
5257
5282
|
"data-generation-state": stream ? stream.busy ? "generating" : stream.error ? "stopped" : "generated" : "ready",
|
|
@@ -5280,7 +5305,7 @@ function NativeDocxEditor({
|
|
|
5280
5305
|
document: ready.document,
|
|
5281
5306
|
modules: ready.modules,
|
|
5282
5307
|
fonts: ready.fonts,
|
|
5283
|
-
mode: stream || isDraft && ready.canEdit && !snapshot ? "edit" : !ready.canEdit || snapshot ? "view" : "suggesting",
|
|
5308
|
+
mode: stream || isDraft && ready.canEdit && !snapshot || compact && ready.canEdit ? "edit" : !ready.canEdit || snapshot ? "view" : "suggesting",
|
|
5284
5309
|
reviewDisplayMode: "all-markup",
|
|
5285
5310
|
zoomMode: fixedZoomMode,
|
|
5286
5311
|
author: ready.author,
|
|
@@ -5321,7 +5346,8 @@ function NativeDocxEditor({
|
|
|
5321
5346
|
trackMoves: true
|
|
5322
5347
|
}
|
|
5323
5348
|
),
|
|
5324
|
-
!stream && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5349
|
+
compact && !stream && /* @__PURE__ */ jsxRuntime.jsx(CompactToolbar, {}),
|
|
5350
|
+
!compact && !stream && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5325
5351
|
DocxRibbon,
|
|
5326
5352
|
{
|
|
5327
5353
|
onSave: () => void saveVersion(),
|
|
@@ -5360,13 +5386,13 @@ function NativeDocxEditor({
|
|
|
5360
5386
|
children: /* @__PURE__ */ jsxRuntime.jsx(DocxEditorReview, { children: () => /* @__PURE__ */ jsxRuntime.jsx(DocxEditorReview.Card, { children: /* @__PURE__ */ jsxRuntime.jsx(DocxCommentActivity, {}) }) })
|
|
5361
5387
|
}
|
|
5362
5388
|
),
|
|
5363
|
-
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.HeaderFooterChrome, {}),
|
|
5364
|
-
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.NotesChrome, {}),
|
|
5389
|
+
!compact && /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.HeaderFooterChrome, {}),
|
|
5390
|
+
!compact && /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.NotesChrome, {}),
|
|
5365
5391
|
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Equation, {}),
|
|
5366
5392
|
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.HyperLink, {}),
|
|
5367
5393
|
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.ContextMenu, { children: /* @__PURE__ */ jsxRuntime.jsx(DocxContextMenuExtras, {}) })
|
|
5368
5394
|
] }),
|
|
5369
|
-
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.PageNumber, {})
|
|
5395
|
+
!compact && /* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.PageNumber, {})
|
|
5370
5396
|
]
|
|
5371
5397
|
}
|
|
5372
5398
|
)
|
|
@@ -5385,11 +5411,19 @@ function NativeDocxEditor({
|
|
|
5385
5411
|
status
|
|
5386
5412
|
] }),
|
|
5387
5413
|
/* @__PURE__ */ jsxRuntime.jsx(DocxParticipants, { session: ready?.room?.session }),
|
|
5388
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5414
|
+
!compact && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5415
|
+
"button",
|
|
5416
|
+
{
|
|
5417
|
+
onClick: () => void exportDocument(),
|
|
5418
|
+
disabled: !ready,
|
|
5419
|
+
"aria-label": "Download DOCX",
|
|
5420
|
+
children: [
|
|
5421
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { size: 14 }),
|
|
5422
|
+
"DOCX"
|
|
5423
|
+
]
|
|
5424
|
+
}
|
|
5425
|
+
),
|
|
5426
|
+
!compact && !snapshot && !stream && ready?.canEdit && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5393
5427
|
"button",
|
|
5394
5428
|
{
|
|
5395
5429
|
className: "native-docx-save",
|
|
@@ -5407,69 +5441,6 @@ function NativeDocxEditor({
|
|
|
5407
5441
|
}
|
|
5408
5442
|
);
|
|
5409
5443
|
}
|
|
5410
|
-
var loaded = /* @__PURE__ */ new Map();
|
|
5411
|
-
function loadDocxFonts(baseUrl = "/native-docx/fonts") {
|
|
5412
|
-
let promise = loaded.get(baseUrl);
|
|
5413
|
-
if (!promise) {
|
|
5414
|
-
promise = loadFonts(baseUrl).catch((error) => {
|
|
5415
|
-
loaded.delete(baseUrl);
|
|
5416
|
-
throw error;
|
|
5417
|
-
});
|
|
5418
|
-
loaded.set(baseUrl, promise);
|
|
5419
|
-
}
|
|
5420
|
-
return promise;
|
|
5421
|
-
}
|
|
5422
|
-
async function loadFonts(baseUrl) {
|
|
5423
|
-
const families = ["Liberation Serif", "Liberation Sans", "Liberation Mono"];
|
|
5424
|
-
const variants = [
|
|
5425
|
-
{ suffix: "Regular", weight: 400, style: "normal" },
|
|
5426
|
-
{ suffix: "Bold", weight: 700, style: "normal" },
|
|
5427
|
-
{ suffix: "Italic", weight: 400, style: "italic" },
|
|
5428
|
-
{ suffix: "BoldItalic", weight: 700, style: "italic" }
|
|
5429
|
-
];
|
|
5430
|
-
const sources = await Promise.all(
|
|
5431
|
-
families.flatMap(
|
|
5432
|
-
(family) => variants.map(async (face) => {
|
|
5433
|
-
const r = await fetch(
|
|
5434
|
-
`${baseUrl.replace(/\/$/, "")}/${family.replace(" ", "")}-${face.suffix}.ttf`
|
|
5435
|
-
);
|
|
5436
|
-
if (!r.ok) throw new Error(`Could not load the document font ${family}.`);
|
|
5437
|
-
const result = react.createFontSource(new Uint8Array(await r.arrayBuffer()), {
|
|
5438
|
-
family,
|
|
5439
|
-
weight: face.weight,
|
|
5440
|
-
style: face.style
|
|
5441
|
-
});
|
|
5442
|
-
if ("failure" in result)
|
|
5443
|
-
throw new Error(`Could not initialize the document font ${family}.`);
|
|
5444
|
-
return result.source;
|
|
5445
|
-
})
|
|
5446
|
-
)
|
|
5447
|
-
);
|
|
5448
|
-
const aliases = {
|
|
5449
|
-
"Times New Roman": "Liberation Serif",
|
|
5450
|
-
Cambria: "Liberation Serif",
|
|
5451
|
-
"DejaVu Serif": "Liberation Serif",
|
|
5452
|
-
Calibri: "Liberation Sans",
|
|
5453
|
-
Aptos: "Liberation Sans",
|
|
5454
|
-
Arial: "Liberation Sans",
|
|
5455
|
-
Helvetica: "Liberation Sans",
|
|
5456
|
-
"Courier New": "Liberation Mono",
|
|
5457
|
-
"DejaVu Sans Mono": "Liberation Mono"
|
|
5458
|
-
};
|
|
5459
|
-
return {
|
|
5460
|
-
epoch: 1,
|
|
5461
|
-
maxFontBytes: 12 * 1024 * 1024,
|
|
5462
|
-
sources,
|
|
5463
|
-
defaultFont: { family: "Liberation Serif", sizeHalfPoints: 22 },
|
|
5464
|
-
supportedFamilies: [...families, ...Object.keys(aliases)],
|
|
5465
|
-
substitutions: Object.entries(aliases).flatMap(
|
|
5466
|
-
([from, to]) => variants.map((face) => ({
|
|
5467
|
-
from: { family: from, weight: face.weight, style: face.style },
|
|
5468
|
-
to: { family: to, weight: face.weight, style: face.style }
|
|
5469
|
-
}))
|
|
5470
|
-
)
|
|
5471
|
-
};
|
|
5472
|
-
}
|
|
5473
5444
|
|
|
5474
5445
|
exports.BUILTIN_TEMPLATE_NAME = BUILTIN_TEMPLATE_NAME;
|
|
5475
5446
|
exports.CrossReferenceDialog = CrossReferenceDialog;
|
|
@@ -5496,7 +5467,6 @@ exports.insertCrossReference = insertCrossReference;
|
|
|
5496
5467
|
exports.insertDefinedTerm = insertDefinedTerm;
|
|
5497
5468
|
exports.insertDocumentReference = insertDocumentReference;
|
|
5498
5469
|
exports.listTargets = listTargets;
|
|
5499
|
-
exports.loadDocxFonts = loadDocxFonts;
|
|
5500
5470
|
exports.normalizeDocxExport = normalizeDocxExport;
|
|
5501
5471
|
exports.paragraphNumber = paragraphNumber;
|
|
5502
5472
|
exports.referenceText = referenceText;
|
|
@@ -5514,5 +5484,5 @@ exports.useReview = useReview;
|
|
|
5514
5484
|
exports.useReviewItem = useReviewItem;
|
|
5515
5485
|
exports.useTrackedOrNoted = useTrackedOrNoted;
|
|
5516
5486
|
exports.withDirectEditing = withDirectEditing;
|
|
5517
|
-
//# sourceMappingURL=chunk-
|
|
5518
|
-
//# sourceMappingURL=chunk-
|
|
5487
|
+
//# sourceMappingURL=chunk-BHKFENKT.cjs.map
|
|
5488
|
+
//# sourceMappingURL=chunk-BHKFENKT.cjs.map
|