@arbidocs/blocks 0.4.98 → 0.4.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/index.cjs +207 -207
- package/dist/agents/index.js +2 -2
- package/dist/{chunk-LZ5AFAWC.js → chunk-6HZNFOHW.js} +3 -3
- package/dist/{chunk-LZ5AFAWC.js.map → chunk-6HZNFOHW.js.map} +1 -1
- package/dist/{chunk-FIEAWH4K.js → chunk-72PQ42YI.js} +1040 -88
- package/dist/chunk-72PQ42YI.js.map +1 -0
- package/dist/{chunk-MIMVRMKC.cjs → chunk-B7P73VHX.cjs} +1040 -83
- package/dist/chunk-B7P73VHX.cjs.map +1 -0
- package/dist/{chunk-6B2AWE3I.js → chunk-E2QWWLK5.js} +3 -3
- package/dist/{chunk-6B2AWE3I.js.map → chunk-E2QWWLK5.js.map} +1 -1
- package/dist/{chunk-MUYZP5FB.cjs → chunk-IE55TWIG.cjs} +5 -5
- package/dist/{chunk-MUYZP5FB.cjs.map → chunk-IE55TWIG.cjs.map} +1 -1
- package/dist/{chunk-5NQIBJPP.js → chunk-NJX774HB.js} +3 -3
- package/dist/{chunk-5NQIBJPP.js.map → chunk-NJX774HB.js.map} +1 -1
- package/dist/{chunk-DDYXFALG.cjs → chunk-NW3LFDZL.cjs} +3 -3
- package/dist/{chunk-DDYXFALG.cjs.map → chunk-NW3LFDZL.cjs.map} +1 -1
- package/dist/{chunk-VJO66VVF.cjs → chunk-O24WPHLD.cjs} +5 -5
- package/dist/{chunk-VJO66VVF.cjs.map → chunk-O24WPHLD.cjs.map} +1 -1
- package/dist/connect/docx.cjs +6 -6
- package/dist/connect/docx.js +4 -4
- package/dist/connect/index.cjs +3 -3
- package/dist/connect/index.js +2 -2
- package/dist/docx/NativeDocxEditor.d.ts +6 -1
- package/dist/docx/definitions/fragment.d.ts +3 -1
- package/dist/docx/definitions/port.d.ts +6 -2
- package/dist/docx/index.cjs +51 -31
- package/dist/docx/index.d.ts +3 -0
- package/dist/docx/index.js +3 -3
- package/dist/docx/layout/GenerateImage.d.ts +50 -0
- package/dist/docx/layout/LayoutRibbon.d.ts +32 -0
- package/dist/docx/layout/LayoutTabs.d.ts +20 -0
- package/dist/docx/layout/PictureRibbon.d.ts +23 -0
- package/dist/docx/layout/TableKeys.d.ts +25 -0
- package/dist/docx/layout/TableRibbon.d.ts +11 -0
- package/dist/docx/layout/caption.d.ts +38 -0
- package/dist/docx/layout/presets.d.ts +40 -0
- package/dist/docx/structural/trackedOrNoted.d.ts +51 -0
- package/dist/docx/structural/useTrackedOrNoted.d.ts +5 -0
- package/dist/facts/index.cjs +1 -1
- package/dist/facts/index.js +1 -1
- package/dist/files/index.cjs +1 -1
- package/dist/files/index.js +1 -1
- package/dist/home/index.cjs +1 -1
- package/dist/home/index.js +1 -1
- package/dist/index.cjs +253 -253
- package/dist/index.js +3 -3
- package/dist/shell/index.cjs +1 -1
- package/dist/shell/index.js +1 -1
- package/dist/studio/index.cjs +1 -1
- package/dist/studio/index.js +1 -1
- package/dist/workflow-canvas/index.cjs +9 -9
- package/dist/workflow-canvas/index.js +2 -2
- package/package.json +5 -4
- package/src/docx/README.md +22 -0
- package/src/docx/layout/layout.css +120 -0
- package/src/docx/styles.css +2 -0
- package/dist/chunk-FIEAWH4K.js.map +0 -1
- package/dist/chunk-MIMVRMKC.cjs.map +0 -1
|
@@ -12,6 +12,7 @@ var lucideReact = require('lucide-react');
|
|
|
12
12
|
var jsxRuntime = require('react/jsx-runtime');
|
|
13
13
|
var reactDom = require('react-dom');
|
|
14
14
|
var template = require('@arbidocs/coedit/template');
|
|
15
|
+
var editor = require('@docx-editor.dev/core/editor');
|
|
15
16
|
var server = require('react-dom/server');
|
|
16
17
|
var Y = require('yjs');
|
|
17
18
|
var coedit = require('@arbidocs/coedit');
|
|
@@ -1285,8 +1286,6 @@ function DocxMentions({
|
|
|
1285
1286
|
}
|
|
1286
1287
|
) });
|
|
1287
1288
|
}
|
|
1288
|
-
|
|
1289
|
-
// src/docx/definitions/fragment.ts
|
|
1290
1289
|
var DEFINED_TERM_STYLE = "DefinedTerm";
|
|
1291
1290
|
var FRAGMENT_STYLES = chunkAOFATOT3_cjs.stylesXml(
|
|
1292
1291
|
"",
|
|
@@ -1319,12 +1318,13 @@ function base64(bytes) {
|
|
|
1319
1318
|
binary += String.fromCharCode(...bytes.subarray(i, i + 32768));
|
|
1320
1319
|
return btoa(binary);
|
|
1321
1320
|
}
|
|
1322
|
-
function fragmentHtml(body, covered2) {
|
|
1323
|
-
const
|
|
1321
|
+
function fragmentHtml(body, covered2, revision) {
|
|
1322
|
+
const untracked = chunkAOFATOT3_cjs.docxPackage({
|
|
1324
1323
|
document: chunkAOFATOT3_cjs.documentXml(body),
|
|
1325
1324
|
styles: FRAGMENT_STYLES,
|
|
1326
1325
|
title: "Defined terms"
|
|
1327
1326
|
});
|
|
1327
|
+
const bytes = revision ? template.trackInsertion(untracked, revision, covered2) : untracked;
|
|
1328
1328
|
return `<div data-docx-fragment="${base64(bytes)}" data-docx-fragment-end="${covered2 ? "covered" : "open"}"></div>`;
|
|
1329
1329
|
}
|
|
1330
1330
|
|
|
@@ -1581,7 +1581,7 @@ function readParagraph(node, topLevel, bookmarks) {
|
|
|
1581
1581
|
links
|
|
1582
1582
|
};
|
|
1583
1583
|
}
|
|
1584
|
-
function editorPort(editor) {
|
|
1584
|
+
function editorPort(editor, revision) {
|
|
1585
1585
|
const surface = () => {
|
|
1586
1586
|
const s = editor.surface;
|
|
1587
1587
|
if (!s) throw new Error("The document is not open.");
|
|
@@ -1600,7 +1600,7 @@ function editorPort(editor) {
|
|
|
1600
1600
|
surface().setSelection({ anchor: from, head: to });
|
|
1601
1601
|
surface().deleteSelection();
|
|
1602
1602
|
},
|
|
1603
|
-
paste: (body, text, covered2) => editor.exec({ type: "paste", text, html: fragmentHtml(body, covered2) }).ok,
|
|
1603
|
+
paste: (body, text, covered2) => editor.exec({ type: "paste", text, html: fragmentHtml(body, covered2, revision) }).ok,
|
|
1604
1604
|
splitParagraph: () => surface().splitParagraph()
|
|
1605
1605
|
};
|
|
1606
1606
|
}
|
|
@@ -1643,6 +1643,70 @@ function holdCaret(editor, timeoutMs = 5e3) {
|
|
|
1643
1643
|
const offSelection = editor.on("selectionChange", restore);
|
|
1644
1644
|
const timer = setTimeout(stop, timeoutMs);
|
|
1645
1645
|
}
|
|
1646
|
+
|
|
1647
|
+
// src/docx/structural/trackedOrNoted.ts
|
|
1648
|
+
var revisionDate = (at = /* @__PURE__ */ new Date()) => at.toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
1649
|
+
function trackedOrNoted(port, { label, author, insert, inserted = Boolean }) {
|
|
1650
|
+
const mode = port.mode();
|
|
1651
|
+
if (mode === "viewing") throw new Error("This document is read only.");
|
|
1652
|
+
if (mode !== "suggesting") return { result: insert(null), how: "direct" };
|
|
1653
|
+
const revision = { author, date: revisionDate() };
|
|
1654
|
+
const before = port.caret();
|
|
1655
|
+
const tracked = port.trackedBy(revision);
|
|
1656
|
+
port.setMode("editing");
|
|
1657
|
+
let result;
|
|
1658
|
+
try {
|
|
1659
|
+
result = insert(revision);
|
|
1660
|
+
} finally {
|
|
1661
|
+
port.setMode("suggesting");
|
|
1662
|
+
}
|
|
1663
|
+
if (!inserted(result) || port.trackedBy(revision) > tracked)
|
|
1664
|
+
return { result, how: inserted(result) ? "tracked" : "direct" };
|
|
1665
|
+
const after = port.caret();
|
|
1666
|
+
if (before && after && port.comment(before, after, label)) return { result, how: "noted" };
|
|
1667
|
+
return { result, how: "direct" };
|
|
1668
|
+
}
|
|
1669
|
+
var attr2 = (node, name) => node.attributes?.find((a) => a.localName === name)?.value;
|
|
1670
|
+
function structuralPort(editor) {
|
|
1671
|
+
return {
|
|
1672
|
+
mode: () => editor.getEditingMode(),
|
|
1673
|
+
setMode: (mode) => void editor.setEditingMode(mode),
|
|
1674
|
+
caret: () => {
|
|
1675
|
+
const head = editor.surface?.state().selection?.head;
|
|
1676
|
+
return head ? { paragraphId: head.paragraphId, offset: head.offset } : null;
|
|
1677
|
+
},
|
|
1678
|
+
// Read from the story's tree: the review pane merges adjacent insertions by one author into
|
|
1679
|
+
// one card, so a card's date need not be this insert's.
|
|
1680
|
+
trackedBy: ({ author, date }) => {
|
|
1681
|
+
const root = editor.surface?.session.part().root;
|
|
1682
|
+
let count = 0;
|
|
1683
|
+
const visit = (node) => {
|
|
1684
|
+
if (node.localName === "ins" && attr2(node, "author") === author && attr2(node, "date") === date)
|
|
1685
|
+
count++;
|
|
1686
|
+
node.children?.forEach(visit);
|
|
1687
|
+
};
|
|
1688
|
+
if (root) visit(root);
|
|
1689
|
+
return count;
|
|
1690
|
+
},
|
|
1691
|
+
comment: (from, to, text) => {
|
|
1692
|
+
const surface = editor.surface;
|
|
1693
|
+
if (!surface) return false;
|
|
1694
|
+
surface.setSelection({ anchor: from, head: to });
|
|
1695
|
+
const ok2 = editor.addComment(text).ok;
|
|
1696
|
+
surface.setSelection({ anchor: to, head: to });
|
|
1697
|
+
return ok2;
|
|
1698
|
+
}
|
|
1699
|
+
};
|
|
1700
|
+
}
|
|
1701
|
+
var DocxAuthorContext = React3.createContext("You");
|
|
1702
|
+
function useTrackedOrNoted() {
|
|
1703
|
+
const editor = react.useDocxEditor();
|
|
1704
|
+
const author = React3.useContext(DocxAuthorContext);
|
|
1705
|
+
return React3.useCallback(
|
|
1706
|
+
(spec) => editor ? trackedOrNoted(structuralPort(editor), { ...spec, author }) : void 0,
|
|
1707
|
+
[editor, author]
|
|
1708
|
+
);
|
|
1709
|
+
}
|
|
1646
1710
|
var DEFINED_TERM_TRIGGER = "@@";
|
|
1647
1711
|
var TRIGGER_QUERY = /(?:^|[\s([{"“‘'])@@([^@\n\t]{0,40})$/;
|
|
1648
1712
|
var MAX_GROUPS = 8;
|
|
@@ -1686,6 +1750,7 @@ function DefinedTermsProvider({
|
|
|
1686
1750
|
labels
|
|
1687
1751
|
}) {
|
|
1688
1752
|
const editor = react.useDocxEditor();
|
|
1753
|
+
const track = useTrackedOrNoted();
|
|
1689
1754
|
const l = React3.useMemo(() => ({ ...DEFAULT_DEFINED_TERMS_LABELS, ...labels }), [labels]);
|
|
1690
1755
|
const [sources, setSources] = React3.useState(null);
|
|
1691
1756
|
const loadedAt = React3.useRef(0);
|
|
@@ -1742,35 +1807,46 @@ function DefinedTermsProvider({
|
|
|
1742
1807
|
refreshRef.current = refresh;
|
|
1743
1808
|
const firstHover = React3.useCallback(() => void refreshRef.current(), []);
|
|
1744
1809
|
const caretRect = () => container().querySelector(".docx-editor-one-surface__caret")?.getBoundingClientRect();
|
|
1745
|
-
const
|
|
1810
|
+
const attempt = React3.useCallback(
|
|
1746
1811
|
(fn) => {
|
|
1747
|
-
if (!editor) return void 0;
|
|
1748
1812
|
try {
|
|
1749
|
-
return
|
|
1813
|
+
return fn();
|
|
1750
1814
|
} catch (error) {
|
|
1751
1815
|
notify?.(error instanceof Error ? error.message : "Could not change the document.", "error");
|
|
1752
1816
|
return void 0;
|
|
1753
1817
|
}
|
|
1754
1818
|
},
|
|
1755
|
-
[
|
|
1819
|
+
[notify]
|
|
1820
|
+
);
|
|
1821
|
+
const run = React3.useCallback(
|
|
1822
|
+
(fn) => editor ? attempt(() => withDirectEditing(editor, fn)) : void 0,
|
|
1823
|
+
[editor, attempt]
|
|
1756
1824
|
);
|
|
1757
1825
|
const pick = React3.useCallback(
|
|
1758
1826
|
(row) => {
|
|
1759
1827
|
if (!editor || !picker || !row) return;
|
|
1760
1828
|
const port = editorPort(editor);
|
|
1761
|
-
const
|
|
1829
|
+
const placed = run(() => {
|
|
1762
1830
|
if (picker.mode === "search" && picker.caret) port.setCaret(picker.caret);
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1831
|
+
const caret = port.caret();
|
|
1832
|
+
if (!caret) throw new Error("Place the cursor where the term should go.");
|
|
1833
|
+
const typed = picker.mode === "typing" ? DEFINED_TERM_TRIGGER.length + picker.query.length : 0;
|
|
1834
|
+
if (typed) port.deleteRange({ ...caret, offset: Math.max(0, caret.offset - typed) }, caret);
|
|
1835
|
+
return true;
|
|
1766
1836
|
});
|
|
1837
|
+
const result = placed ? attempt(
|
|
1838
|
+
() => track({
|
|
1839
|
+
label: `Inserted defined term: ${row.definition.term}`,
|
|
1840
|
+
insert: (revision) => insertDefinedTerm(editorPort(editor, revision), row.definition)
|
|
1841
|
+
})?.result
|
|
1842
|
+
) : void 0;
|
|
1767
1843
|
setPicker(null);
|
|
1768
1844
|
editor.surface?.focus();
|
|
1769
1845
|
if (result) holdCaret(editor);
|
|
1770
1846
|
if (result?.addedDefinition)
|
|
1771
1847
|
notify?.(`\u201C${row.definition.term}\u201D added to the Definitions section.`, "success");
|
|
1772
1848
|
},
|
|
1773
|
-
[editor, picker, run, notify]
|
|
1849
|
+
[editor, picker, run, attempt, track, notify]
|
|
1774
1850
|
);
|
|
1775
1851
|
const openPicker = React3.useCallback(
|
|
1776
1852
|
(anchor) => {
|
|
@@ -2174,6 +2250,7 @@ function HouseTemplateProvider({
|
|
|
2174
2250
|
children
|
|
2175
2251
|
}) {
|
|
2176
2252
|
const editor = react.useDocxEditor();
|
|
2253
|
+
const track = useTrackedOrNoted();
|
|
2177
2254
|
const [template$1, setTemplate] = React3.useState(builtinHouseTemplate);
|
|
2178
2255
|
const [divergence, setDivergence] = React3.useState(null);
|
|
2179
2256
|
const [basedOnTemplate, setBasedOnTemplate] = React3.useState(false);
|
|
@@ -2214,11 +2291,18 @@ function HouseTemplateProvider({
|
|
|
2214
2291
|
const fragment = template.buildingBlockFragment(template$1.bytes, name);
|
|
2215
2292
|
if (!fragment) return false;
|
|
2216
2293
|
try {
|
|
2217
|
-
const result =
|
|
2218
|
-
|
|
2219
|
-
() => editor.exec({
|
|
2220
|
-
|
|
2221
|
-
|
|
2294
|
+
const result = track({
|
|
2295
|
+
label: `Inserted Quick Part: ${name}`,
|
|
2296
|
+
insert: (revision) => editor.exec({
|
|
2297
|
+
type: "paste",
|
|
2298
|
+
text: "",
|
|
2299
|
+
html: template.fragmentClipboardHtml(
|
|
2300
|
+
revision ? template.trackInsertion(fragment, revision, true) : fragment
|
|
2301
|
+
)
|
|
2302
|
+
}),
|
|
2303
|
+
inserted: (r) => r.ok
|
|
2304
|
+
})?.result;
|
|
2305
|
+
if (!result?.ok) throw new Error(result?.reason ?? "The block could not be inserted here.");
|
|
2222
2306
|
refresh();
|
|
2223
2307
|
return true;
|
|
2224
2308
|
} catch (failure) {
|
|
@@ -2229,7 +2313,7 @@ function HouseTemplateProvider({
|
|
|
2229
2313
|
return false;
|
|
2230
2314
|
}
|
|
2231
2315
|
},
|
|
2232
|
-
[editor, editable, template$1, notify, refresh]
|
|
2316
|
+
[editor, editable, template$1, notify, refresh, track]
|
|
2233
2317
|
);
|
|
2234
2318
|
const setAsHouseTemplate = React3.useMemo(
|
|
2235
2319
|
() => host?.setFromDocument && documentId ? async () => {
|
|
@@ -2272,6 +2356,241 @@ function HouseTemplateProvider({
|
|
|
2272
2356
|
);
|
|
2273
2357
|
return /* @__PURE__ */ jsxRuntime.jsx(HouseTemplateContext.Provider, { value: enabled ? value : null, children });
|
|
2274
2358
|
}
|
|
2359
|
+
function RibbonMenu({
|
|
2360
|
+
label,
|
|
2361
|
+
icon,
|
|
2362
|
+
children,
|
|
2363
|
+
className,
|
|
2364
|
+
testId,
|
|
2365
|
+
title
|
|
2366
|
+
}) {
|
|
2367
|
+
const [open, setOpen] = React3.useState(false);
|
|
2368
|
+
const element = React3.useRef(null);
|
|
2369
|
+
React3.useEffect(() => {
|
|
2370
|
+
if (!open) return;
|
|
2371
|
+
const dismiss = (event) => {
|
|
2372
|
+
if (!element.current?.contains(event.target)) setOpen(false);
|
|
2373
|
+
};
|
|
2374
|
+
const escape = (event) => {
|
|
2375
|
+
if (event.key === "Escape") setOpen(false);
|
|
2376
|
+
};
|
|
2377
|
+
document.addEventListener("pointerdown", dismiss);
|
|
2378
|
+
document.addEventListener("keydown", escape);
|
|
2379
|
+
return () => {
|
|
2380
|
+
document.removeEventListener("pointerdown", dismiss);
|
|
2381
|
+
document.removeEventListener("keydown", escape);
|
|
2382
|
+
};
|
|
2383
|
+
}, [open]);
|
|
2384
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "native-docx-ribbon-menu", ref: element, children: [
|
|
2385
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2386
|
+
"button",
|
|
2387
|
+
{
|
|
2388
|
+
type: "button",
|
|
2389
|
+
className: ["native-docx-ribbon-trigger", className].filter(Boolean).join(" "),
|
|
2390
|
+
"aria-label": label,
|
|
2391
|
+
title: title ?? label,
|
|
2392
|
+
"aria-expanded": open,
|
|
2393
|
+
"data-testid": testId,
|
|
2394
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
2395
|
+
onClick: () => setOpen((value) => !value),
|
|
2396
|
+
children: icon
|
|
2397
|
+
}
|
|
2398
|
+
),
|
|
2399
|
+
open && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2400
|
+
"div",
|
|
2401
|
+
{
|
|
2402
|
+
className: "native-docx-ribbon-popover",
|
|
2403
|
+
role: "group",
|
|
2404
|
+
"aria-label": label,
|
|
2405
|
+
onMouseDown: (event) => {
|
|
2406
|
+
if (!(event.target instanceof HTMLInputElement || event.target instanceof HTMLSelectElement))
|
|
2407
|
+
event.preventDefault();
|
|
2408
|
+
},
|
|
2409
|
+
children: typeof children === "function" ? children(() => setOpen(false)) : children
|
|
2410
|
+
}
|
|
2411
|
+
)
|
|
2412
|
+
] });
|
|
2413
|
+
}
|
|
2414
|
+
var titleOf = (prompt) => {
|
|
2415
|
+
const line = prompt.trim().split("\n")[0];
|
|
2416
|
+
return line.length > 80 ? `${line.slice(0, 79)}\u2026` : line;
|
|
2417
|
+
};
|
|
2418
|
+
function rememberCaret(editor) {
|
|
2419
|
+
const surface = editor.surface;
|
|
2420
|
+
const head = surface?.state().selection?.head;
|
|
2421
|
+
if (!surface || !head) return null;
|
|
2422
|
+
return { paraId: surface.session.paraIdOf(head.paragraphId), ...head };
|
|
2423
|
+
}
|
|
2424
|
+
var mounted = [];
|
|
2425
|
+
var running = 0;
|
|
2426
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
2427
|
+
var setRunning = (delta) => {
|
|
2428
|
+
running += delta;
|
|
2429
|
+
listeners.forEach((listener) => listener());
|
|
2430
|
+
};
|
|
2431
|
+
var subscribe = (listener) => {
|
|
2432
|
+
listeners.add(listener);
|
|
2433
|
+
return () => void listeners.delete(listener);
|
|
2434
|
+
};
|
|
2435
|
+
function insertionTarget(origin, caret, editors = mounted) {
|
|
2436
|
+
if (editors.includes(origin) && origin.surface) return origin;
|
|
2437
|
+
const paraId = caret?.paraId;
|
|
2438
|
+
if (!paraId) return null;
|
|
2439
|
+
for (let i = editors.length - 1; i >= 0; i--) {
|
|
2440
|
+
const session = editors[i].surface?.session;
|
|
2441
|
+
if (session?.nodeIdOf(paraId)) return editors[i];
|
|
2442
|
+
}
|
|
2443
|
+
return null;
|
|
2444
|
+
}
|
|
2445
|
+
function restoreCaret(editor, caret) {
|
|
2446
|
+
const surface = editor.surface;
|
|
2447
|
+
if (!surface || !caret) return;
|
|
2448
|
+
const paragraphId = caret.paraId && surface.session.nodeIdOf(caret.paraId) || caret.paragraphId;
|
|
2449
|
+
if (!surface.session.paragraphIds().includes(paragraphId)) return;
|
|
2450
|
+
const point = { paragraphId, offset: caret.offset };
|
|
2451
|
+
surface.setSelection({ anchor: point, head: point });
|
|
2452
|
+
}
|
|
2453
|
+
async function insertGeneratedImage(editor$1, bytes, prompt, caret) {
|
|
2454
|
+
const image = react.normalizeImageBytes(bytes);
|
|
2455
|
+
if (!image.ok) throw new Error("The generated image is not in a format Word can embed.");
|
|
2456
|
+
let result;
|
|
2457
|
+
for (let attempt = 0; attempt < 3 && !result?.ok; attempt++) {
|
|
2458
|
+
editor$1.focus();
|
|
2459
|
+
restoreCaret(editor$1, caret);
|
|
2460
|
+
result = await editor.executeImageCommand(editor$1, {
|
|
2461
|
+
type: "insertImage",
|
|
2462
|
+
data: image.bytes,
|
|
2463
|
+
mime: image.mime,
|
|
2464
|
+
widthPoints: image.widthPoints,
|
|
2465
|
+
heightPoints: image.heightPoints,
|
|
2466
|
+
description: prompt.trim(),
|
|
2467
|
+
title: titleOf(prompt)
|
|
2468
|
+
});
|
|
2469
|
+
if (!result.ok && result.reason !== "stale drawing selection") break;
|
|
2470
|
+
}
|
|
2471
|
+
if (!result?.ok) throw new Error(result?.reason || "The picture could not be inserted here.");
|
|
2472
|
+
}
|
|
2473
|
+
var AUTO = "";
|
|
2474
|
+
function useGenerateImageTarget() {
|
|
2475
|
+
const editor = react.useDocxEditor();
|
|
2476
|
+
const loaded2 = react.useEditorState((snapshot) => !snapshot.isLoading);
|
|
2477
|
+
React3.useEffect(() => {
|
|
2478
|
+
if (!editor || !loaded2) return;
|
|
2479
|
+
mounted.push(editor);
|
|
2480
|
+
return () => void mounted.splice(mounted.indexOf(editor), 1);
|
|
2481
|
+
}, [editor, loaded2]);
|
|
2482
|
+
}
|
|
2483
|
+
function GenerateImageButton({ generation }) {
|
|
2484
|
+
const editor = react.useDocxEditor();
|
|
2485
|
+
const [prompt, setPrompt] = React3.useState("");
|
|
2486
|
+
const [aspectRatio, setAspectRatio] = React3.useState(AUTO);
|
|
2487
|
+
const [busy, setBusy] = React3.useState(false);
|
|
2488
|
+
const [error, setError] = React3.useState("");
|
|
2489
|
+
const abort = React3.useRef(null);
|
|
2490
|
+
const close = React3.useRef(() => {
|
|
2491
|
+
});
|
|
2492
|
+
const editable = react.useEditorState((snapshot) => snapshot.editable);
|
|
2493
|
+
const generating = React3.useSyncExternalStore(subscribe, () => running > 0);
|
|
2494
|
+
async function run() {
|
|
2495
|
+
if (!editor || !prompt.trim() || busy) return;
|
|
2496
|
+
const caret = rememberCaret(editor);
|
|
2497
|
+
const controller = new AbortController();
|
|
2498
|
+
abort.current = controller;
|
|
2499
|
+
setBusy(true);
|
|
2500
|
+
setRunning(1);
|
|
2501
|
+
setError("");
|
|
2502
|
+
try {
|
|
2503
|
+
const bytes = await generation.generate(prompt.trim(), {
|
|
2504
|
+
aspectRatio: aspectRatio || void 0,
|
|
2505
|
+
signal: controller.signal
|
|
2506
|
+
});
|
|
2507
|
+
if (controller.signal.aborted) return;
|
|
2508
|
+
const target = insertionTarget(editor, caret);
|
|
2509
|
+
if (!target) throw new Error("The document was closed before the generated image was ready.");
|
|
2510
|
+
await insertGeneratedImage(target, bytes, prompt, caret);
|
|
2511
|
+
setPrompt("");
|
|
2512
|
+
close.current();
|
|
2513
|
+
generation.notify?.("Generated image inserted", "success");
|
|
2514
|
+
} catch (failure) {
|
|
2515
|
+
if (controller.signal.aborted) return;
|
|
2516
|
+
const message = failure instanceof Error ? failure.message : String(failure);
|
|
2517
|
+
setError(message);
|
|
2518
|
+
generation.notify?.(message, "error");
|
|
2519
|
+
} finally {
|
|
2520
|
+
abort.current = null;
|
|
2521
|
+
setRunning(-1);
|
|
2522
|
+
setBusy(false);
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
if (!editable && !generating) return null;
|
|
2526
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2527
|
+
RibbonMenu,
|
|
2528
|
+
{
|
|
2529
|
+
label: generating ? "Generating image\u2026" : "Generate image",
|
|
2530
|
+
icon: generating ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { size: 16, className: "native-docx-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { size: 16 }),
|
|
2531
|
+
testId: "docx-generate-image",
|
|
2532
|
+
children: (dismiss) => {
|
|
2533
|
+
close.current = dismiss;
|
|
2534
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2535
|
+
"form",
|
|
2536
|
+
{
|
|
2537
|
+
className: "native-docx-form native-docx-generate-image",
|
|
2538
|
+
onSubmit: (event) => {
|
|
2539
|
+
event.preventDefault();
|
|
2540
|
+
void run();
|
|
2541
|
+
},
|
|
2542
|
+
children: [
|
|
2543
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
2544
|
+
"Describe the image",
|
|
2545
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2546
|
+
"textarea",
|
|
2547
|
+
{
|
|
2548
|
+
autoFocus: true,
|
|
2549
|
+
rows: 3,
|
|
2550
|
+
value: prompt,
|
|
2551
|
+
disabled: busy,
|
|
2552
|
+
placeholder: "A watercolour of a lighthouse at dawn",
|
|
2553
|
+
"data-testid": "docx-generate-image-prompt",
|
|
2554
|
+
onChange: (event) => setPrompt(event.target.value),
|
|
2555
|
+
onKeyDown: (event) => {
|
|
2556
|
+
if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) void run();
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
)
|
|
2560
|
+
] }),
|
|
2561
|
+
generation.aspectRatios && generation.aspectRatios.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
2562
|
+
"Aspect ratio",
|
|
2563
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2564
|
+
"select",
|
|
2565
|
+
{
|
|
2566
|
+
value: aspectRatio,
|
|
2567
|
+
disabled: busy,
|
|
2568
|
+
onChange: (event) => setAspectRatio(event.target.value),
|
|
2569
|
+
children: [
|
|
2570
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: AUTO, children: "Auto" }),
|
|
2571
|
+
generation.aspectRatios.map((ratio) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: ratio.value, children: ratio.label }, ratio.value))
|
|
2572
|
+
]
|
|
2573
|
+
}
|
|
2574
|
+
)
|
|
2575
|
+
] }),
|
|
2576
|
+
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." }),
|
|
2577
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", children: error }),
|
|
2578
|
+
/* @__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(
|
|
2579
|
+
"button",
|
|
2580
|
+
{
|
|
2581
|
+
type: "submit",
|
|
2582
|
+
disabled: !prompt.trim(),
|
|
2583
|
+
"data-testid": "docx-generate-image-submit",
|
|
2584
|
+
children: "Generate"
|
|
2585
|
+
}
|
|
2586
|
+
) })
|
|
2587
|
+
]
|
|
2588
|
+
}
|
|
2589
|
+
);
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
);
|
|
2593
|
+
}
|
|
2275
2594
|
function wordDraftHtml(markdown) {
|
|
2276
2595
|
const template = document.createElement("template");
|
|
2277
2596
|
template.innerHTML = server.renderToStaticMarkup(/* @__PURE__ */ jsxRuntime.jsx(ui.AiMarkdown, { children: markdown }));
|
|
@@ -2359,61 +2678,6 @@ var WordDraftStream = class {
|
|
|
2359
2678
|
}
|
|
2360
2679
|
}
|
|
2361
2680
|
};
|
|
2362
|
-
function RibbonMenu({
|
|
2363
|
-
label,
|
|
2364
|
-
icon,
|
|
2365
|
-
children,
|
|
2366
|
-
className,
|
|
2367
|
-
testId,
|
|
2368
|
-
title
|
|
2369
|
-
}) {
|
|
2370
|
-
const [open, setOpen] = React3.useState(false);
|
|
2371
|
-
const element = React3.useRef(null);
|
|
2372
|
-
React3.useEffect(() => {
|
|
2373
|
-
if (!open) return;
|
|
2374
|
-
const dismiss = (event) => {
|
|
2375
|
-
if (!element.current?.contains(event.target)) setOpen(false);
|
|
2376
|
-
};
|
|
2377
|
-
const escape = (event) => {
|
|
2378
|
-
if (event.key === "Escape") setOpen(false);
|
|
2379
|
-
};
|
|
2380
|
-
document.addEventListener("pointerdown", dismiss);
|
|
2381
|
-
document.addEventListener("keydown", escape);
|
|
2382
|
-
return () => {
|
|
2383
|
-
document.removeEventListener("pointerdown", dismiss);
|
|
2384
|
-
document.removeEventListener("keydown", escape);
|
|
2385
|
-
};
|
|
2386
|
-
}, [open]);
|
|
2387
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "native-docx-ribbon-menu", ref: element, children: [
|
|
2388
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2389
|
-
"button",
|
|
2390
|
-
{
|
|
2391
|
-
type: "button",
|
|
2392
|
-
className: ["native-docx-ribbon-trigger", className].filter(Boolean).join(" "),
|
|
2393
|
-
"aria-label": label,
|
|
2394
|
-
title: title ?? label,
|
|
2395
|
-
"aria-expanded": open,
|
|
2396
|
-
"data-testid": testId,
|
|
2397
|
-
onMouseDown: (event) => event.preventDefault(),
|
|
2398
|
-
onClick: () => setOpen((value) => !value),
|
|
2399
|
-
children: icon
|
|
2400
|
-
}
|
|
2401
|
-
),
|
|
2402
|
-
open && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2403
|
-
"div",
|
|
2404
|
-
{
|
|
2405
|
-
className: "native-docx-ribbon-popover",
|
|
2406
|
-
role: "group",
|
|
2407
|
-
"aria-label": label,
|
|
2408
|
-
onMouseDown: (event) => {
|
|
2409
|
-
if (!(event.target instanceof HTMLInputElement || event.target instanceof HTMLSelectElement))
|
|
2410
|
-
event.preventDefault();
|
|
2411
|
-
},
|
|
2412
|
-
children: typeof children === "function" ? children(() => setOpen(false)) : children
|
|
2413
|
-
}
|
|
2414
|
-
)
|
|
2415
|
-
] });
|
|
2416
|
-
}
|
|
2417
2681
|
|
|
2418
2682
|
// src/docx/wordStyles.ts
|
|
2419
2683
|
var QUICK_STYLES = ["Normal", "Title", "heading 1", "heading 2", "heading 3"];
|
|
@@ -2703,6 +2967,679 @@ function WordShortcuts({ scope }) {
|
|
|
2703
2967
|
}, [scope]);
|
|
2704
2968
|
return null;
|
|
2705
2969
|
}
|
|
2970
|
+
|
|
2971
|
+
// src/docx/layout/presets.ts
|
|
2972
|
+
var TWIPS_PER_INCH = 1440;
|
|
2973
|
+
var MARGIN_PRESETS = [
|
|
2974
|
+
{ id: "normal", label: "Normal", top: 1440, right: 1440, bottom: 1440, left: 1440 },
|
|
2975
|
+
{ id: "narrow", label: "Narrow", top: 720, right: 720, bottom: 720, left: 720 },
|
|
2976
|
+
{ id: "moderate", label: "Moderate", top: 1440, right: 1080, bottom: 1440, left: 1080 },
|
|
2977
|
+
{ id: "wide", label: "Wide", top: 1440, right: 2880, bottom: 1440, left: 2880 }
|
|
2978
|
+
];
|
|
2979
|
+
var PAPER_SIZES = [
|
|
2980
|
+
{ id: "letter", label: "Letter", width: 12240, height: 15840 },
|
|
2981
|
+
{ id: "legal", label: "Legal", width: 12240, height: 20160 },
|
|
2982
|
+
{ id: "a4", label: "A4", width: 11906, height: 16838 },
|
|
2983
|
+
{ id: "a5", label: "A5", width: 8391, height: 11906 },
|
|
2984
|
+
{ id: "executive", label: "Executive", width: 10440, height: 15120 }
|
|
2985
|
+
];
|
|
2986
|
+
var TOLERANCE = 20;
|
|
2987
|
+
var near = (a, b) => Math.abs(a - b) <= TOLERANCE;
|
|
2988
|
+
function matchMargins(setup) {
|
|
2989
|
+
if (!setup) return null;
|
|
2990
|
+
const m = setup.marginsTwips;
|
|
2991
|
+
return MARGIN_PRESETS.find(
|
|
2992
|
+
(p) => near(p.top, m.top) && near(p.right, m.right) && near(p.bottom, m.bottom) && near(p.left, m.left)
|
|
2993
|
+
)?.id ?? null;
|
|
2994
|
+
}
|
|
2995
|
+
function matchPaper(setup) {
|
|
2996
|
+
if (!setup) return null;
|
|
2997
|
+
const short = Math.min(setup.pageWidthTwips, setup.pageHeightTwips);
|
|
2998
|
+
const long = Math.max(setup.pageWidthTwips, setup.pageHeightTwips);
|
|
2999
|
+
return PAPER_SIZES.find((p) => near(p.width, short) && near(p.height, long))?.id ?? null;
|
|
3000
|
+
}
|
|
3001
|
+
function orientedSize(paper, orientation) {
|
|
3002
|
+
return orientation === "landscape" ? { pageWidthTwips: paper.height, pageHeightTwips: paper.width } : { pageWidthTwips: paper.width, pageHeightTwips: paper.height };
|
|
3003
|
+
}
|
|
3004
|
+
function inches(twips) {
|
|
3005
|
+
return `${Number((twips / TWIPS_PER_INCH).toFixed(2))}"`;
|
|
3006
|
+
}
|
|
3007
|
+
function paperDescription(paper) {
|
|
3008
|
+
return `${inches(paper.width)} \xD7 ${inches(paper.height)}`;
|
|
3009
|
+
}
|
|
3010
|
+
var COLUMNS_UNSUPPORTED = "Text columns are not available in this editor yet. Documents that already use columns display and save them unchanged.";
|
|
3011
|
+
function RibbonGallery({
|
|
3012
|
+
label,
|
|
3013
|
+
choices,
|
|
3014
|
+
current,
|
|
3015
|
+
onPick,
|
|
3016
|
+
close,
|
|
3017
|
+
testId
|
|
3018
|
+
}) {
|
|
3019
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "native-docx-gallery", role: "menu", "aria-label": label, "data-testid": testId, children: choices.map((choice) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3020
|
+
"button",
|
|
3021
|
+
{
|
|
3022
|
+
type: "button",
|
|
3023
|
+
role: "menuitemradio",
|
|
3024
|
+
"aria-checked": current === choice.id,
|
|
3025
|
+
disabled: choice.disabled,
|
|
3026
|
+
title: choice.title,
|
|
3027
|
+
"data-choice": choice.id,
|
|
3028
|
+
onClick: () => {
|
|
3029
|
+
onPick(choice.id);
|
|
3030
|
+
close();
|
|
3031
|
+
},
|
|
3032
|
+
children: [
|
|
3033
|
+
choice.icon,
|
|
3034
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "native-docx-gallery-text", children: [
|
|
3035
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "native-docx-gallery-label", children: choice.label }),
|
|
3036
|
+
choice.detail && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "native-docx-gallery-detail", children: choice.detail })
|
|
3037
|
+
] })
|
|
3038
|
+
]
|
|
3039
|
+
},
|
|
3040
|
+
choice.id
|
|
3041
|
+
)) });
|
|
3042
|
+
}
|
|
3043
|
+
var marginDetail = (p) => `Top ${inches(p.top)} \xB7 Bottom ${inches(p.bottom)} \xB7 Left ${inches(p.left)} \xB7 Right ${inches(p.right)}`;
|
|
3044
|
+
function Margins({ setup, apply, openDialog }) {
|
|
3045
|
+
return /* @__PURE__ */ jsxRuntime.jsx(RibbonMenu, { label: "Margins", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Scaling, { size: 16 }), testId: "docx-layout-margins", children: (close) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3046
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3047
|
+
RibbonGallery,
|
|
3048
|
+
{
|
|
3049
|
+
label: "Margins",
|
|
3050
|
+
current: matchMargins(setup),
|
|
3051
|
+
close,
|
|
3052
|
+
choices: MARGIN_PRESETS.map((p) => ({
|
|
3053
|
+
id: p.id,
|
|
3054
|
+
label: p.label,
|
|
3055
|
+
detail: marginDetail(p)
|
|
3056
|
+
})),
|
|
3057
|
+
onPick: (id) => {
|
|
3058
|
+
const p = MARGIN_PRESETS.find((m) => m.id === id);
|
|
3059
|
+
apply({
|
|
3060
|
+
marginTopTwips: p.top,
|
|
3061
|
+
marginRightTwips: p.right,
|
|
3062
|
+
marginBottomTwips: p.bottom,
|
|
3063
|
+
marginLeftTwips: p.left,
|
|
3064
|
+
scope: "section"
|
|
3065
|
+
});
|
|
3066
|
+
}
|
|
3067
|
+
}
|
|
3068
|
+
),
|
|
3069
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3070
|
+
"button",
|
|
3071
|
+
{
|
|
3072
|
+
type: "button",
|
|
3073
|
+
className: "native-docx-gallery-more",
|
|
3074
|
+
onClick: () => {
|
|
3075
|
+
close();
|
|
3076
|
+
openDialog();
|
|
3077
|
+
},
|
|
3078
|
+
children: "Custom margins\u2026"
|
|
3079
|
+
}
|
|
3080
|
+
)
|
|
3081
|
+
] }) });
|
|
3082
|
+
}
|
|
3083
|
+
function Orientation({ setup, apply }) {
|
|
3084
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3085
|
+
RibbonMenu,
|
|
3086
|
+
{
|
|
3087
|
+
label: "Orientation",
|
|
3088
|
+
icon: setup?.orientation === "landscape" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RectangleHorizontal, { size: 16 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RectangleVertical, { size: 16 }),
|
|
3089
|
+
testId: "docx-layout-orientation",
|
|
3090
|
+
children: (close) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3091
|
+
RibbonGallery,
|
|
3092
|
+
{
|
|
3093
|
+
label: "Orientation",
|
|
3094
|
+
current: setup?.orientation,
|
|
3095
|
+
close,
|
|
3096
|
+
choices: [
|
|
3097
|
+
{ id: "portrait", label: "Portrait", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RectangleVertical, { size: 16 }) },
|
|
3098
|
+
{ id: "landscape", label: "Landscape", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RectangleHorizontal, { size: 16 }) }
|
|
3099
|
+
],
|
|
3100
|
+
onPick: (id) => apply({ orientation: id, scope: "section" })
|
|
3101
|
+
}
|
|
3102
|
+
)
|
|
3103
|
+
}
|
|
3104
|
+
);
|
|
3105
|
+
}
|
|
3106
|
+
function Size({ setup, apply, openDialog }) {
|
|
3107
|
+
return /* @__PURE__ */ jsxRuntime.jsx(RibbonMenu, { label: "Size", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { size: 16 }), testId: "docx-layout-size", children: (close) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3108
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3109
|
+
RibbonGallery,
|
|
3110
|
+
{
|
|
3111
|
+
label: "Size",
|
|
3112
|
+
current: matchPaper(setup),
|
|
3113
|
+
close,
|
|
3114
|
+
choices: PAPER_SIZES.map((p) => ({
|
|
3115
|
+
id: p.id,
|
|
3116
|
+
label: p.label,
|
|
3117
|
+
detail: paperDescription(p)
|
|
3118
|
+
})),
|
|
3119
|
+
onPick: (id) => apply({
|
|
3120
|
+
...orientedSize(
|
|
3121
|
+
PAPER_SIZES.find((p) => p.id === id),
|
|
3122
|
+
setup?.orientation
|
|
3123
|
+
),
|
|
3124
|
+
scope: "section"
|
|
3125
|
+
})
|
|
3126
|
+
}
|
|
3127
|
+
),
|
|
3128
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3129
|
+
"button",
|
|
3130
|
+
{
|
|
3131
|
+
type: "button",
|
|
3132
|
+
className: "native-docx-gallery-more",
|
|
3133
|
+
onClick: () => {
|
|
3134
|
+
close();
|
|
3135
|
+
openDialog();
|
|
3136
|
+
},
|
|
3137
|
+
children: "More paper sizes\u2026"
|
|
3138
|
+
}
|
|
3139
|
+
)
|
|
3140
|
+
] }) });
|
|
3141
|
+
}
|
|
3142
|
+
var COLUMN_BREAK = { type: "insertBreak", kind: "column" };
|
|
3143
|
+
function Breaks() {
|
|
3144
|
+
const page = react.useEditorCommand("insert.pageBreak");
|
|
3145
|
+
const nextPage = react.useEditorCommand("insert.sectionBreakNextPage");
|
|
3146
|
+
const continuous = react.useEditorCommand("insert.sectionBreakContinuous");
|
|
3147
|
+
const column = react.useEditorCommand(COLUMN_BREAK);
|
|
3148
|
+
const rows = [
|
|
3149
|
+
{ id: "page", label: "Page", detail: "Start the next page here", command: page },
|
|
3150
|
+
{ id: "column", label: "Column", detail: "Start the next column here", command: column },
|
|
3151
|
+
{
|
|
3152
|
+
id: "nextPage",
|
|
3153
|
+
label: "Next Page",
|
|
3154
|
+
detail: "Section break: new section on the next page",
|
|
3155
|
+
command: nextPage
|
|
3156
|
+
},
|
|
3157
|
+
{
|
|
3158
|
+
id: "continuous",
|
|
3159
|
+
label: "Continuous",
|
|
3160
|
+
detail: "Section break: new section on the same page",
|
|
3161
|
+
command: continuous
|
|
3162
|
+
}
|
|
3163
|
+
];
|
|
3164
|
+
return /* @__PURE__ */ jsxRuntime.jsx(RibbonMenu, { label: "Breaks", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SeparatorHorizontal, { size: 16 }), testId: "docx-layout-breaks", children: (close) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3165
|
+
RibbonGallery,
|
|
3166
|
+
{
|
|
3167
|
+
label: "Breaks",
|
|
3168
|
+
close,
|
|
3169
|
+
choices: rows.map((row) => ({
|
|
3170
|
+
id: row.id,
|
|
3171
|
+
label: row.label,
|
|
3172
|
+
detail: row.detail,
|
|
3173
|
+
disabled: !row.command.isEnabled,
|
|
3174
|
+
title: row.command.disabledReason ?? void 0
|
|
3175
|
+
})),
|
|
3176
|
+
onPick: (id) => void rows.find((row) => row.id === id)?.command.execute()
|
|
3177
|
+
}
|
|
3178
|
+
) });
|
|
3179
|
+
}
|
|
3180
|
+
function LayoutButtons() {
|
|
3181
|
+
const { pageSetup, apply } = react.usePageSetup();
|
|
3182
|
+
const [dialog, setDialog] = React3.useState(false);
|
|
3183
|
+
const props = { setup: pageSetup, apply, openDialog: () => setDialog(true) };
|
|
3184
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3185
|
+
/* @__PURE__ */ jsxRuntime.jsx(Margins, { ...props }),
|
|
3186
|
+
/* @__PURE__ */ jsxRuntime.jsx(Orientation, { ...props }),
|
|
3187
|
+
/* @__PURE__ */ jsxRuntime.jsx(Size, { ...props }),
|
|
3188
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3189
|
+
react.DocxEditor.Toolbar.Action,
|
|
3190
|
+
{
|
|
3191
|
+
label: "Columns",
|
|
3192
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Columns2, { size: 16 }),
|
|
3193
|
+
disabled: true,
|
|
3194
|
+
disabledReason: COLUMNS_UNSUPPORTED,
|
|
3195
|
+
className: "native-docx-layout-columns"
|
|
3196
|
+
}
|
|
3197
|
+
),
|
|
3198
|
+
/* @__PURE__ */ jsxRuntime.jsx(Breaks, {}),
|
|
3199
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3200
|
+
react.DocxEditor.Toolbar.Action,
|
|
3201
|
+
{
|
|
3202
|
+
label: "Page Setup\u2026",
|
|
3203
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings2, { size: 16 }),
|
|
3204
|
+
onSelect: () => setDialog(true),
|
|
3205
|
+
className: "native-docx-layout-page-setup"
|
|
3206
|
+
}
|
|
3207
|
+
),
|
|
3208
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.PageSetupDialog, { open: dialog, onClose: () => setDialog(false) })
|
|
3209
|
+
] });
|
|
3210
|
+
}
|
|
3211
|
+
var ROW_ABOVE = { type: "insertRow", where: "above" };
|
|
3212
|
+
var ROW_BELOW = { type: "insertRow", where: "below" };
|
|
3213
|
+
var COLUMN_LEFT = { type: "insertColumn", where: "left" };
|
|
3214
|
+
var COLUMN_RIGHT = { type: "insertColumn", where: "right" };
|
|
3215
|
+
var MERGE = { type: "mergeCells" };
|
|
3216
|
+
var SPLIT = { type: "splitCell", rows: 1, cols: 2 };
|
|
3217
|
+
var HEADER_ROW = { type: "toggleHeaderRow" };
|
|
3218
|
+
var DELETE_ROW = { type: "deleteRow" };
|
|
3219
|
+
var DELETE_COLUMN = { type: "deleteColumn" };
|
|
3220
|
+
var DELETE_TABLE = { type: "deleteTable" };
|
|
3221
|
+
var ALIGN_TOP = { type: "setTableCellVerticalAlignment", alignment: "top" };
|
|
3222
|
+
var ALIGN_CENTER = { type: "setTableCellVerticalAlignment", alignment: "center" };
|
|
3223
|
+
var ALIGN_BOTTOM = { type: "setTableCellVerticalAlignment", alignment: "bottom" };
|
|
3224
|
+
function useRows(rows) {
|
|
3225
|
+
return rows.map((row) => ({ ...row, state: react.useEditorCommand(row.command) }));
|
|
3226
|
+
}
|
|
3227
|
+
function CommandGallery({
|
|
3228
|
+
label,
|
|
3229
|
+
icon,
|
|
3230
|
+
testId,
|
|
3231
|
+
rows
|
|
3232
|
+
}) {
|
|
3233
|
+
const bound = useRows(rows);
|
|
3234
|
+
return /* @__PURE__ */ jsxRuntime.jsx(RibbonMenu, { label, icon, testId, children: (close) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3235
|
+
RibbonGallery,
|
|
3236
|
+
{
|
|
3237
|
+
label,
|
|
3238
|
+
close,
|
|
3239
|
+
choices: bound.map((row) => ({
|
|
3240
|
+
id: row.id,
|
|
3241
|
+
label: row.label,
|
|
3242
|
+
icon: row.icon,
|
|
3243
|
+
disabled: !row.state.isEnabled,
|
|
3244
|
+
title: row.state.disabledReason ?? void 0
|
|
3245
|
+
})),
|
|
3246
|
+
onPick: (id) => void bound.find((row) => row.id === id)?.state.execute()
|
|
3247
|
+
}
|
|
3248
|
+
) });
|
|
3249
|
+
}
|
|
3250
|
+
function CommandAction({
|
|
3251
|
+
command,
|
|
3252
|
+
label,
|
|
3253
|
+
icon,
|
|
3254
|
+
testId
|
|
3255
|
+
}) {
|
|
3256
|
+
const state = react.useEditorCommand(command);
|
|
3257
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3258
|
+
react.DocxEditor.Toolbar.Action,
|
|
3259
|
+
{
|
|
3260
|
+
label,
|
|
3261
|
+
icon,
|
|
3262
|
+
active: state.isActive,
|
|
3263
|
+
disabled: !state.isEnabled,
|
|
3264
|
+
disabledReason: state.disabledReason ?? void 0,
|
|
3265
|
+
onSelect: () => void state.execute(),
|
|
3266
|
+
className: `native-docx-table-${testId}`
|
|
3267
|
+
}
|
|
3268
|
+
);
|
|
3269
|
+
}
|
|
3270
|
+
function TableButtons() {
|
|
3271
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3272
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3273
|
+
CommandAction,
|
|
3274
|
+
{
|
|
3275
|
+
command: ROW_ABOVE,
|
|
3276
|
+
label: "Insert row above",
|
|
3277
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BetweenHorizontalStart, { size: 16 }),
|
|
3278
|
+
testId: "row-above"
|
|
3279
|
+
}
|
|
3280
|
+
),
|
|
3281
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3282
|
+
CommandAction,
|
|
3283
|
+
{
|
|
3284
|
+
command: ROW_BELOW,
|
|
3285
|
+
label: "Insert row below",
|
|
3286
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BetweenHorizontalEnd, { size: 16 }),
|
|
3287
|
+
testId: "row-below"
|
|
3288
|
+
}
|
|
3289
|
+
),
|
|
3290
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3291
|
+
CommandAction,
|
|
3292
|
+
{
|
|
3293
|
+
command: COLUMN_LEFT,
|
|
3294
|
+
label: "Insert column left",
|
|
3295
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BetweenVerticalStart, { size: 16 }),
|
|
3296
|
+
testId: "column-left"
|
|
3297
|
+
}
|
|
3298
|
+
),
|
|
3299
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3300
|
+
CommandAction,
|
|
3301
|
+
{
|
|
3302
|
+
command: COLUMN_RIGHT,
|
|
3303
|
+
label: "Insert column right",
|
|
3304
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BetweenVerticalEnd, { size: 16 }),
|
|
3305
|
+
testId: "column-right"
|
|
3306
|
+
}
|
|
3307
|
+
),
|
|
3308
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3309
|
+
CommandGallery,
|
|
3310
|
+
{
|
|
3311
|
+
label: "Delete",
|
|
3312
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: 16 }),
|
|
3313
|
+
testId: "docx-table-delete",
|
|
3314
|
+
rows: [
|
|
3315
|
+
{ id: "row", label: "Delete row", command: DELETE_ROW },
|
|
3316
|
+
{ id: "column", label: "Delete column", command: DELETE_COLUMN },
|
|
3317
|
+
{ id: "table", label: "Delete table", command: DELETE_TABLE }
|
|
3318
|
+
]
|
|
3319
|
+
}
|
|
3320
|
+
),
|
|
3321
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3322
|
+
CommandAction,
|
|
3323
|
+
{
|
|
3324
|
+
command: MERGE,
|
|
3325
|
+
label: "Merge cells",
|
|
3326
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Merge, { size: 16 }),
|
|
3327
|
+
testId: "merge"
|
|
3328
|
+
}
|
|
3329
|
+
),
|
|
3330
|
+
/* @__PURE__ */ jsxRuntime.jsx(CommandAction, { command: SPLIT, label: "Split cell", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Split, { size: 16 }), testId: "split" }),
|
|
3331
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3332
|
+
CommandAction,
|
|
3333
|
+
{
|
|
3334
|
+
command: HEADER_ROW,
|
|
3335
|
+
label: "Repeat header row",
|
|
3336
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Heading, { size: 16 }),
|
|
3337
|
+
testId: "header-row"
|
|
3338
|
+
}
|
|
3339
|
+
),
|
|
3340
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3341
|
+
CommandGallery,
|
|
3342
|
+
{
|
|
3343
|
+
label: "Cell alignment",
|
|
3344
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignVerticalJustifyCenter, { size: 16 }),
|
|
3345
|
+
testId: "docx-table-align",
|
|
3346
|
+
rows: [
|
|
3347
|
+
{
|
|
3348
|
+
id: "top",
|
|
3349
|
+
label: "Top",
|
|
3350
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignVerticalJustifyStart, { size: 16 }),
|
|
3351
|
+
command: ALIGN_TOP
|
|
3352
|
+
},
|
|
3353
|
+
{
|
|
3354
|
+
id: "center",
|
|
3355
|
+
label: "Center",
|
|
3356
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignVerticalJustifyCenter, { size: 16 }),
|
|
3357
|
+
command: ALIGN_CENTER
|
|
3358
|
+
},
|
|
3359
|
+
{
|
|
3360
|
+
id: "bottom",
|
|
3361
|
+
label: "Bottom",
|
|
3362
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignVerticalJustifyEnd, { size: 16 }),
|
|
3363
|
+
command: ALIGN_BOTTOM
|
|
3364
|
+
}
|
|
3365
|
+
]
|
|
3366
|
+
}
|
|
3367
|
+
),
|
|
3368
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.TableBorderTarget, {}),
|
|
3369
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.TableBorderStyle, {}),
|
|
3370
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.TableBorderWidth, {}),
|
|
3371
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.TableBorderColor, {}),
|
|
3372
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.TableCellFill, {})
|
|
3373
|
+
] });
|
|
3374
|
+
}
|
|
3375
|
+
var CAPTION_LABELS = ["Figure", "Table", "Equation"];
|
|
3376
|
+
var CAPTION_STYLES = chunkAOFATOT3_cjs.stylesXml(
|
|
3377
|
+
"",
|
|
3378
|
+
'<w:style w:type="paragraph" w:default="1" w:styleId="Normal"><w:name w:val="Normal"/><w:qFormat/></w:style><w:style w:type="paragraph" w:styleId="Caption"><w:name w:val="caption"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:uiPriority w:val="35"/><w:unhideWhenUsed/><w:qFormat/><w:pPr><w:spacing w:after="200" w:line="240" w:lineRule="auto"/></w:pPr><w:rPr><w:i/><w:iCs/><w:color w:val="44546A"/><w:sz w:val="18"/><w:szCs w:val="18"/></w:rPr></w:style>'
|
|
3379
|
+
);
|
|
3380
|
+
function seqIdentifier(instruction) {
|
|
3381
|
+
const match = /^\s*SEQ\s+("[^"]+"|\S+)/i.exec(instruction);
|
|
3382
|
+
return match ? match[1].replace(/"/g, "") : null;
|
|
3383
|
+
}
|
|
3384
|
+
function countSeqFields(root, label, throughId) {
|
|
3385
|
+
let count = 0;
|
|
3386
|
+
let done = false;
|
|
3387
|
+
const target = label.toLowerCase();
|
|
3388
|
+
const visit = (node) => {
|
|
3389
|
+
if (done) return;
|
|
3390
|
+
if (node.localName === "fldSimple") {
|
|
3391
|
+
const instr = node.attributes?.find((a) => a.localName === "instr")?.value ?? "";
|
|
3392
|
+
if (seqIdentifier(instr)?.toLowerCase() === target) count++;
|
|
3393
|
+
} else if (node.localName === "instrText") {
|
|
3394
|
+
const text = (node.children ?? []).map((c) => c.value ?? "").join("");
|
|
3395
|
+
if (seqIdentifier(text)?.toLowerCase() === target) count++;
|
|
3396
|
+
}
|
|
3397
|
+
node.children?.forEach(visit);
|
|
3398
|
+
if (throughId && node.id === throughId) done = true;
|
|
3399
|
+
};
|
|
3400
|
+
visit(root);
|
|
3401
|
+
return count;
|
|
3402
|
+
}
|
|
3403
|
+
function captionParagraphXml(label, number, text) {
|
|
3404
|
+
const run = (value) => `<w:r><w:t xml:space="preserve">${chunkAOFATOT3_cjs.esc(value)}</w:t></w:r>`;
|
|
3405
|
+
const rest = text.trim() ? `: ${text.trim()}` : "";
|
|
3406
|
+
return `<w:p><w:pPr><w:pStyle w:val="Caption"/></w:pPr>${run(`${label} `)}<w:fldSimple w:instr=" SEQ ${chunkAOFATOT3_cjs.esc(label)} \\* ARABIC "><w:r><w:t>${number}</w:t></w:r></w:fldSimple>${rest ? run(rest) : ""}</w:p>`;
|
|
3407
|
+
}
|
|
3408
|
+
function base642(bytes) {
|
|
3409
|
+
let binary = "";
|
|
3410
|
+
for (let i = 0; i < bytes.length; i += 32768)
|
|
3411
|
+
binary += String.fromCharCode(...bytes.subarray(i, i + 32768));
|
|
3412
|
+
return btoa(binary);
|
|
3413
|
+
}
|
|
3414
|
+
function captionFragmentHtml(label, number, text, revision) {
|
|
3415
|
+
const untracked = chunkAOFATOT3_cjs.docxPackage({
|
|
3416
|
+
document: chunkAOFATOT3_cjs.documentXml(captionParagraphXml(label, number, text)),
|
|
3417
|
+
styles: CAPTION_STYLES,
|
|
3418
|
+
title: "Caption"
|
|
3419
|
+
});
|
|
3420
|
+
const bytes = revision ? template.trackInsertion(untracked, revision, true) : untracked;
|
|
3421
|
+
return `<div data-docx-fragment="${base642(bytes)}" data-docx-fragment-end="covered"></div>`;
|
|
3422
|
+
}
|
|
3423
|
+
var TRANSFORMS = Object.fromEntries(
|
|
3424
|
+
["rotateCW", "rotateCCW", "flipH", "flipV"].map((action) => [
|
|
3425
|
+
action,
|
|
3426
|
+
{ type: "transformImage", action }
|
|
3427
|
+
])
|
|
3428
|
+
);
|
|
3429
|
+
function TransformAction({
|
|
3430
|
+
action,
|
|
3431
|
+
label,
|
|
3432
|
+
icon
|
|
3433
|
+
}) {
|
|
3434
|
+
const state = react.useEditorCommand(TRANSFORMS[action]);
|
|
3435
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3436
|
+
react.DocxEditor.Toolbar.Action,
|
|
3437
|
+
{
|
|
3438
|
+
label,
|
|
3439
|
+
icon,
|
|
3440
|
+
disabled: !state.isEnabled,
|
|
3441
|
+
disabledReason: state.disabledReason ?? void 0,
|
|
3442
|
+
onSelect: () => void state.execute(),
|
|
3443
|
+
className: `native-docx-picture-${action}`
|
|
3444
|
+
}
|
|
3445
|
+
);
|
|
3446
|
+
}
|
|
3447
|
+
function insertCaption(editor, label, text, track) {
|
|
3448
|
+
const surface = editor.surface;
|
|
3449
|
+
const selection = surface?.state().selection;
|
|
3450
|
+
if (!surface || !selection) return null;
|
|
3451
|
+
const { paragraphId } = selection.head;
|
|
3452
|
+
const number = countSeqFields(
|
|
3453
|
+
surface.session.part().root,
|
|
3454
|
+
label,
|
|
3455
|
+
paragraphId
|
|
3456
|
+
) + 1;
|
|
3457
|
+
const ids = surface.session.paragraphIds();
|
|
3458
|
+
const next = ids[ids.indexOf(paragraphId) + 1];
|
|
3459
|
+
const caption = `${label} ${number}${text.trim() ? `: ${text.trim()}` : ""}`;
|
|
3460
|
+
const outcome = track({
|
|
3461
|
+
label: `Inserted caption: ${caption}`,
|
|
3462
|
+
inserted: (inserted) => inserted !== null,
|
|
3463
|
+
insert: (revision) => {
|
|
3464
|
+
if (next) {
|
|
3465
|
+
surface.setSelection({
|
|
3466
|
+
anchor: { paragraphId: next, offset: 0 },
|
|
3467
|
+
head: { paragraphId: next, offset: 0 }
|
|
3468
|
+
});
|
|
3469
|
+
} else {
|
|
3470
|
+
editor.exec({ type: "selectAll" });
|
|
3471
|
+
const end = surface.state().selection?.head;
|
|
3472
|
+
if (!end) return null;
|
|
3473
|
+
surface.setSelection({ anchor: end, head: end });
|
|
3474
|
+
surface.splitParagraph();
|
|
3475
|
+
}
|
|
3476
|
+
const ok2 = editor.exec({
|
|
3477
|
+
type: "paste",
|
|
3478
|
+
text: caption,
|
|
3479
|
+
html: captionFragmentHtml(label, number, text, revision)
|
|
3480
|
+
}).ok;
|
|
3481
|
+
return ok2 ? number : null;
|
|
3482
|
+
}
|
|
3483
|
+
});
|
|
3484
|
+
return outcome?.result ?? null;
|
|
3485
|
+
}
|
|
3486
|
+
function CaptionButton({ defaultLabel = "Figure" }) {
|
|
3487
|
+
const editor = react.useDocxEditor();
|
|
3488
|
+
const track = useTrackedOrNoted();
|
|
3489
|
+
const [label, setLabel] = React3.useState(defaultLabel);
|
|
3490
|
+
const [text, setText] = React3.useState("");
|
|
3491
|
+
const [error, setError] = React3.useState("");
|
|
3492
|
+
return /* @__PURE__ */ jsxRuntime.jsx(RibbonMenu, { label: "Insert caption", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Captions, { size: 16 }), testId: "docx-insert-caption", children: (close) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3493
|
+
"form",
|
|
3494
|
+
{
|
|
3495
|
+
className: "native-docx-form",
|
|
3496
|
+
onSubmit: (event) => {
|
|
3497
|
+
event.preventDefault();
|
|
3498
|
+
if (!editor) return;
|
|
3499
|
+
try {
|
|
3500
|
+
if (insertCaption(editor, label, text, track) === null)
|
|
3501
|
+
return setError("The caption could not be inserted here.");
|
|
3502
|
+
setText("");
|
|
3503
|
+
setError("");
|
|
3504
|
+
close();
|
|
3505
|
+
editor.focus();
|
|
3506
|
+
} catch (failure) {
|
|
3507
|
+
setError(failure instanceof Error ? failure.message : String(failure));
|
|
3508
|
+
}
|
|
3509
|
+
},
|
|
3510
|
+
children: [
|
|
3511
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
3512
|
+
"Label",
|
|
3513
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3514
|
+
"select",
|
|
3515
|
+
{
|
|
3516
|
+
value: label,
|
|
3517
|
+
onChange: (event) => setLabel(event.target.value),
|
|
3518
|
+
children: CAPTION_LABELS.map((value) => /* @__PURE__ */ jsxRuntime.jsx("option", { children: value }, value))
|
|
3519
|
+
}
|
|
3520
|
+
)
|
|
3521
|
+
] }),
|
|
3522
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
|
|
3523
|
+
"Caption",
|
|
3524
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3525
|
+
"input",
|
|
3526
|
+
{
|
|
3527
|
+
autoFocus: true,
|
|
3528
|
+
value: text,
|
|
3529
|
+
placeholder: "Optional text after the number",
|
|
3530
|
+
"data-testid": "docx-caption-text",
|
|
3531
|
+
onChange: (event) => setText(event.target.value)
|
|
3532
|
+
}
|
|
3533
|
+
)
|
|
3534
|
+
] }),
|
|
3535
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", children: error }),
|
|
3536
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", "data-testid": "docx-caption-insert", children: "Insert" })
|
|
3537
|
+
]
|
|
3538
|
+
}
|
|
3539
|
+
) });
|
|
3540
|
+
}
|
|
3541
|
+
function PictureButtons() {
|
|
3542
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3543
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.ImageWrap, {}),
|
|
3544
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.ImageProperties, {}),
|
|
3545
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.ImageAltText, {}),
|
|
3546
|
+
/* @__PURE__ */ jsxRuntime.jsx(TransformAction, { action: "rotateCW", label: "Rotate right 90\xB0", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCw, { size: 16 }) }),
|
|
3547
|
+
/* @__PURE__ */ jsxRuntime.jsx(TransformAction, { action: "rotateCCW", label: "Rotate left 90\xB0", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcw, { size: 16 }) }),
|
|
3548
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3549
|
+
TransformAction,
|
|
3550
|
+
{
|
|
3551
|
+
action: "flipH",
|
|
3552
|
+
label: "Flip horizontal",
|
|
3553
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FlipHorizontal2, { size: 16 })
|
|
3554
|
+
}
|
|
3555
|
+
),
|
|
3556
|
+
/* @__PURE__ */ jsxRuntime.jsx(TransformAction, { action: "flipV", label: "Flip vertical", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FlipVertical2, { size: 16 }) }),
|
|
3557
|
+
/* @__PURE__ */ jsxRuntime.jsx(CaptionButton, {})
|
|
3558
|
+
] });
|
|
3559
|
+
}
|
|
3560
|
+
var LAYOUT_TAB = "Layout";
|
|
3561
|
+
var TABLE_TAB = "Table";
|
|
3562
|
+
var PICTURE_TAB = "Picture";
|
|
3563
|
+
function useContextualTabs(tab) {
|
|
3564
|
+
const inTable = react.useEditorState((snapshot) => snapshot.table !== null);
|
|
3565
|
+
const onPicture = react.useEditorState((snapshot) => snapshot.image !== null);
|
|
3566
|
+
const tabs = [...inTable ? [TABLE_TAB] : [], ...onPicture ? [PICTURE_TAB] : []];
|
|
3567
|
+
const contextual = tab === TABLE_TAB || tab === PICTURE_TAB;
|
|
3568
|
+
return { tabs, shown: contextual && !tabs.includes(tab) ? "Home" : tab };
|
|
3569
|
+
}
|
|
3570
|
+
function LayoutTabContent({ tab }) {
|
|
3571
|
+
if (tab === LAYOUT_TAB) return /* @__PURE__ */ jsxRuntime.jsx(LayoutButtons, {});
|
|
3572
|
+
if (tab === TABLE_TAB) return /* @__PURE__ */ jsxRuntime.jsx(TableButtons, {});
|
|
3573
|
+
if (tab === PICTURE_TAB) return /* @__PURE__ */ jsxRuntime.jsx(PictureButtons, {});
|
|
3574
|
+
return null;
|
|
3575
|
+
}
|
|
3576
|
+
var contains = (node, id) => node.id === id || (node.children ?? []).some((child) => contains(child, id));
|
|
3577
|
+
function firstParagraph(node) {
|
|
3578
|
+
for (const child of node.children ?? []) {
|
|
3579
|
+
if (child.kind === "paragraph" && child.id) return child.id;
|
|
3580
|
+
if (child.localName === "tbl") continue;
|
|
3581
|
+
const nested = firstParagraph(child);
|
|
3582
|
+
if (nested) return nested;
|
|
3583
|
+
}
|
|
3584
|
+
return null;
|
|
3585
|
+
}
|
|
3586
|
+
function tableCells(root, paragraphId) {
|
|
3587
|
+
let table = null;
|
|
3588
|
+
const find = (node) => {
|
|
3589
|
+
if (node.localName === "tbl" && contains(node, paragraphId)) table = node;
|
|
3590
|
+
for (const child of node.children ?? []) if (contains(child, paragraphId)) find(child);
|
|
3591
|
+
};
|
|
3592
|
+
find(root);
|
|
3593
|
+
if (!table) return null;
|
|
3594
|
+
const cells = [];
|
|
3595
|
+
let index = -1;
|
|
3596
|
+
const rows = (node) => (node.children ?? []).flatMap(
|
|
3597
|
+
(child) => child.localName === "tr" ? [child] : child.localName === "tbl" ? [] : rows(child)
|
|
3598
|
+
);
|
|
3599
|
+
for (const row of rows(table))
|
|
3600
|
+
for (const cell of (row.children ?? []).filter((child) => child.localName === "tc")) {
|
|
3601
|
+
const first = firstParagraph(cell);
|
|
3602
|
+
if (!first) continue;
|
|
3603
|
+
if (contains(cell, paragraphId)) index = cells.length;
|
|
3604
|
+
cells.push(first);
|
|
3605
|
+
}
|
|
3606
|
+
return index < 0 ? null : { cells, index };
|
|
3607
|
+
}
|
|
3608
|
+
function TableTabKeys({ scope }) {
|
|
3609
|
+
const editor = react.useDocxEditor();
|
|
3610
|
+
const latest = React3.useRef(editor);
|
|
3611
|
+
latest.current = editor;
|
|
3612
|
+
React3.useEffect(() => {
|
|
3613
|
+
const element = scope.current;
|
|
3614
|
+
if (!element) return;
|
|
3615
|
+
const onKeyDown = (event) => {
|
|
3616
|
+
if (event.key !== "Tab" || event.ctrlKey || event.metaKey || event.altKey) return;
|
|
3617
|
+
const editor2 = latest.current;
|
|
3618
|
+
const surface = editor2?.surface;
|
|
3619
|
+
const head = surface?.state().selection?.head;
|
|
3620
|
+
if (!editor2 || !surface || !head) return;
|
|
3621
|
+
const root = () => surface.session.part().root;
|
|
3622
|
+
const table = tableCells(root(), head.paragraphId);
|
|
3623
|
+
if (!table) return;
|
|
3624
|
+
event.preventDefault();
|
|
3625
|
+
event.stopPropagation();
|
|
3626
|
+
let target = table.cells[table.index + (event.shiftKey ? -1 : 1)];
|
|
3627
|
+
if (!target && !event.shiftKey && editor2.exec({ type: "insertRow", where: "below" }).ok) {
|
|
3628
|
+
const grown = tableCells(
|
|
3629
|
+
root(),
|
|
3630
|
+
surface.state().selection?.head.paragraphId ?? head.paragraphId
|
|
3631
|
+
);
|
|
3632
|
+
target = grown?.cells[table.cells.length] ?? "";
|
|
3633
|
+
}
|
|
3634
|
+
if (!target) return;
|
|
3635
|
+
const point = { paragraphId: target, offset: 0 };
|
|
3636
|
+
surface.setSelection({ anchor: point, head: point });
|
|
3637
|
+
};
|
|
3638
|
+
element.addEventListener("keydown", onKeyDown, true);
|
|
3639
|
+
return () => element.removeEventListener("keydown", onKeyDown, true);
|
|
3640
|
+
}, [scope]);
|
|
3641
|
+
return null;
|
|
3642
|
+
}
|
|
2706
3643
|
function QuickParts() {
|
|
2707
3644
|
const house = useHouseTemplate();
|
|
2708
3645
|
if (!house || house.blocks.length === 0) return null;
|
|
@@ -2873,17 +3810,23 @@ function DefinedTermButtons() {
|
|
|
2873
3810
|
}
|
|
2874
3811
|
function DocxRibbon({
|
|
2875
3812
|
onSave,
|
|
2876
|
-
badge
|
|
3813
|
+
badge,
|
|
3814
|
+
imageGeneration
|
|
2877
3815
|
}) {
|
|
2878
|
-
const [
|
|
3816
|
+
const [selected, setTab] = React3.useState("Home");
|
|
3817
|
+
const contextual = useContextualTabs(selected);
|
|
3818
|
+
useGenerateImageTarget();
|
|
3819
|
+
const tab = contextual.shown;
|
|
2879
3820
|
const t = react.useChromeTranslate();
|
|
2880
3821
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "native-docx-ribbon", children: [
|
|
2881
3822
|
/* @__PURE__ */ jsxRuntime.jsxs("select", { "aria-label": "Ribbon tab", value: tab, onChange: (event) => setTab(event.target.value), children: [
|
|
2882
3823
|
/* @__PURE__ */ jsxRuntime.jsx("option", { children: "Home" }),
|
|
2883
3824
|
/* @__PURE__ */ jsxRuntime.jsx("option", { children: "Insert" }),
|
|
2884
3825
|
/* @__PURE__ */ jsxRuntime.jsx("option", { children: "Design" }),
|
|
3826
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { children: LAYOUT_TAB }),
|
|
2885
3827
|
/* @__PURE__ */ jsxRuntime.jsx("option", { children: "References" }),
|
|
2886
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { children: "Review" })
|
|
3828
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { children: "Review" }),
|
|
3829
|
+
contextual.tabs.map((name) => /* @__PURE__ */ jsxRuntime.jsx("option", { children: name }, name))
|
|
2887
3830
|
] }),
|
|
2888
3831
|
/* @__PURE__ */ jsxRuntime.jsxs(react.DocxEditor.Toolbar, { t, preset: false, onSave, children: [
|
|
2889
3832
|
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.Undo, {}),
|
|
@@ -2914,10 +3857,14 @@ function DocxRibbon({
|
|
|
2914
3857
|
tab === "Insert" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2915
3858
|
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.TableInsert, {}),
|
|
2916
3859
|
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.ImageInsert, {}),
|
|
3860
|
+
imageGeneration && /* @__PURE__ */ jsxRuntime.jsx(GenerateImageButton, { generation: imageGeneration }),
|
|
3861
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.Button, { slotId: "insert.pageBreak" }),
|
|
2917
3862
|
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.Link, {}),
|
|
2918
3863
|
/* @__PURE__ */ jsxRuntime.jsx(DefinedTermButtons, {}),
|
|
2919
3864
|
/* @__PURE__ */ jsxRuntime.jsx(QuickParts, {})
|
|
2920
3865
|
] }),
|
|
3866
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.DocxEditor.Toolbar.TableCellFill, { hidden: true }),
|
|
3867
|
+
/* @__PURE__ */ jsxRuntime.jsx(LayoutTabContent, { tab }),
|
|
2921
3868
|
tab === "Design" && /* @__PURE__ */ jsxRuntime.jsx(HouseTemplatePanel, {}),
|
|
2922
3869
|
tab === "References" && /* @__PURE__ */ jsxRuntime.jsx(NoteButtons, {}),
|
|
2923
3870
|
tab === "Review" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
@@ -3264,7 +4211,7 @@ function NativeDocxEditor({
|
|
|
3264
4211
|
if (change.source !== "load") changed();
|
|
3265
4212
|
},
|
|
3266
4213
|
onFontError: (e) => setError(e.message),
|
|
3267
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4214
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(DocxAuthorContext.Provider, { value: ready.author, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3268
4215
|
DefinedTermsProvider,
|
|
3269
4216
|
{
|
|
3270
4217
|
load: adapter.definitions,
|
|
@@ -3293,6 +4240,10 @@ function NativeDocxEditor({
|
|
|
3293
4240
|
DocxRibbon,
|
|
3294
4241
|
{
|
|
3295
4242
|
onSave: () => void saveVersion(),
|
|
4243
|
+
imageGeneration: adapter.imageGeneration && {
|
|
4244
|
+
notify: adapter.notify,
|
|
4245
|
+
...adapter.imageGeneration
|
|
4246
|
+
},
|
|
3296
4247
|
badge: (
|
|
3297
4248
|
// Says the document is shared live, in place of a title row above the ribbon.
|
|
3298
4249
|
ready.room && ready.canEdit && !snapshot ? /* @__PURE__ */ jsxRuntime.jsx("span", { title: "Edits sync live with everyone who has this document open", children: "Co-edit mode" }) : void 0
|
|
@@ -3300,6 +4251,7 @@ function NativeDocxEditor({
|
|
|
3300
4251
|
}
|
|
3301
4252
|
),
|
|
3302
4253
|
!stream && /* @__PURE__ */ jsxRuntime.jsx(WordShortcuts, { scope: stageRef }),
|
|
4254
|
+
!stream && /* @__PURE__ */ jsxRuntime.jsx(TableTabKeys, { scope: stageRef }),
|
|
3303
4255
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3304
4256
|
"div",
|
|
3305
4257
|
{
|
|
@@ -3337,7 +4289,7 @@ function NativeDocxEditor({
|
|
|
3337
4289
|
}
|
|
3338
4290
|
)
|
|
3339
4291
|
}
|
|
3340
|
-
)
|
|
4292
|
+
) })
|
|
3341
4293
|
}
|
|
3342
4294
|
) }, retry) }),
|
|
3343
4295
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "native-docx-actions", children: [
|
|
@@ -3436,11 +4388,13 @@ exports.BUILTIN_TEMPLATE_NAME = BUILTIN_TEMPLATE_NAME;
|
|
|
3436
4388
|
exports.DEFAULT_DEFINED_TERMS_LABELS = DEFAULT_DEFINED_TERMS_LABELS;
|
|
3437
4389
|
exports.DEFINED_TERM_TRIGGER = DEFINED_TERM_TRIGGER;
|
|
3438
4390
|
exports.DefinedTermsProvider = DefinedTermsProvider;
|
|
4391
|
+
exports.DocxAuthorContext = DocxAuthorContext;
|
|
3439
4392
|
exports.DocxCommentActivity = DocxCommentActivity;
|
|
3440
4393
|
exports.DocxEditorReview = DocxEditorReview;
|
|
3441
4394
|
exports.DocxMentions = DocxMentions;
|
|
3442
4395
|
exports.DocxParticipants = DocxParticipants;
|
|
3443
4396
|
exports.DocxRibbon = DocxRibbon;
|
|
4397
|
+
exports.GenerateImageButton = GenerateImageButton;
|
|
3444
4398
|
exports.HouseTemplateProvider = HouseTemplateProvider;
|
|
3445
4399
|
exports.NativeDocxEditor = NativeDocxEditor;
|
|
3446
4400
|
exports.builtinHouseTemplate = builtinHouseTemplate;
|
|
@@ -3452,12 +4406,15 @@ exports.loadDocxFonts = loadDocxFonts;
|
|
|
3452
4406
|
exports.normalizeDocxExport = normalizeDocxExport;
|
|
3453
4407
|
exports.resolveHouseTemplate = resolveHouseTemplate;
|
|
3454
4408
|
exports.reviewModule = reviewModule;
|
|
4409
|
+
exports.structuralPort = structuralPort;
|
|
3455
4410
|
exports.templateFileName = templateFileName;
|
|
4411
|
+
exports.trackedOrNoted = trackedOrNoted;
|
|
3456
4412
|
exports.updateDefinitions = updateDefinitions;
|
|
3457
4413
|
exports.useDefinedTerms = useDefinedTerms;
|
|
3458
4414
|
exports.useHouseTemplate = useHouseTemplate;
|
|
3459
4415
|
exports.useReview = useReview;
|
|
3460
4416
|
exports.useReviewItem = useReviewItem;
|
|
4417
|
+
exports.useTrackedOrNoted = useTrackedOrNoted;
|
|
3461
4418
|
exports.withDirectEditing = withDirectEditing;
|
|
3462
|
-
//# sourceMappingURL=chunk-
|
|
3463
|
-
//# sourceMappingURL=chunk-
|
|
4419
|
+
//# sourceMappingURL=chunk-B7P73VHX.cjs.map
|
|
4420
|
+
//# sourceMappingURL=chunk-B7P73VHX.cjs.map
|