document-cli 1.7.0 → 1.8.0

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/cli.js CHANGED
@@ -1194,7 +1194,7 @@ function registerSetMetadataCommand(program) {
1194
1194
  }
1195
1195
  //#endregion
1196
1196
  //#region package.json
1197
- var version = "1.7.0";
1197
+ var version = "1.8.0";
1198
1198
  //#endregion
1199
1199
  //#region src/program.ts
1200
1200
  function createProgram() {
@@ -1221,7 +1221,7 @@ function createProgram() {
1221
1221
  //#region src/cli.ts
1222
1222
  async function launchTui(startPath, signal) {
1223
1223
  try {
1224
- const { runTui } = await import("./tui-BzdX4QQg.js");
1224
+ const { runTui } = await import("./tui-BCl5_L4H.js");
1225
1225
  await runTui({
1226
1226
  startPath,
1227
1227
  signal
package/dist/index.cjs CHANGED
@@ -1661,7 +1661,7 @@ function registerSetMetadataCommand(program) {
1661
1661
  }
1662
1662
  //#endregion
1663
1663
  //#region package.json
1664
- var version = "1.7.0";
1664
+ var version = "1.8.0";
1665
1665
  //#endregion
1666
1666
  //#region src/program.ts
1667
1667
  function createProgram() {
package/dist/index.js CHANGED
@@ -1660,7 +1660,7 @@ function registerSetMetadataCommand(program) {
1660
1660
  }
1661
1661
  //#endregion
1662
1662
  //#region package.json
1663
- var version = "1.7.0";
1663
+ var version = "1.8.0";
1664
1664
  //#endregion
1665
1665
  //#region src/program.ts
1666
1666
  function createProgram() {
@@ -1,6 +1,6 @@
1
1
  import { c as formatDocxExtrasLines, f as loadProvidedFonts, i as formatOdbReportLines, l as readInput, m as inferFormatFromExtension, n as describeOdbReport, o as formatMetadataLines, p as formatToExtension, r as formatOdbFormLines, t as describeOdbForm } from "./odb-structure-Du1w_hOU.js";
2
2
  import { readFile, writeFile } from "node:fs/promises";
3
- import { buildDocxPackage, buildOdtPackage, convertWordprocessingToLayout, createDocx, createFontMeasurer, createFontRegistry, createOdg, createOdp, createOds, createOdt, createPptx, decodeMarkdownText, docxToPdf, encodeMarkdownText, encodePackage, hsqldbCellDisplayText, markdownToPdf, odgToPdf, odpToPdf, odsToPdf, odtToPdf, openDocx, openOdg, openOdp, openOds, openOdt, openPptx, pptxToPdf, readDocxContent, readDocxExtras, readMarkdownContent, readOdbForms, readOdbReportContent, readOdbReports, readOdbTables, readOdgContent, readOdpContent, readOdsContent, readOdtContent, readPdf, readPptxContent, rgbHexToColor, writePdf, xlsxToPdf } from "documents.js";
3
+ import { buildDocxPackage, buildOdtPackage, convertWordprocessingToLayout, createDocx, createFontMeasurer, createFontRegistry, createOdg, createOdp, createOds, createOdt, createPptx, decodeMarkdownText, docxToPdf, encodeMarkdownText, encodePackage, hsqldbCellDisplayText, markdownToPdf, odgToPdf, odpToPdf, odsToPdf, odtToPdf, openDocx, openOdg, openOdp, openOds, openOdt, openPptx, parseXml, pptxToPdf, readDocxContent, readDocxExtras, readMarkdownContent, readOdbForms, readOdbReportContent, readOdbReports, readOdbTables, readOdgContent, readOdpContent, readOdsContent, readOdtContent, readPdf, readPptxContent, rgbHexToColor, writePdf, xlsxToPdf } from "documents.js";
4
4
  import { basename, dirname, extname, join } from "node:path";
5
5
  import { cellReference, columnIndexToLetters, decodePackage as decodePackage$1, encodePackage as encodePackage$1 } from "odf.js";
6
6
  import { readdirSync } from "node:fs";
@@ -569,6 +569,31 @@ function setTextContainerText(container, text) {
569
569
  function setCellText(cell, text) {
570
570
  setTextContainerText(cell, text);
571
571
  }
572
+ function mutableMathMlNode(node) {
573
+ if (node.type === "element") return {
574
+ type: "element",
575
+ tag: node.tag,
576
+ attributes: [...node.attributes],
577
+ children: node.children.map(mutableMathMlNode)
578
+ };
579
+ if (node.type === "text") return {
580
+ type: "text",
581
+ value: node.value
582
+ };
583
+ if (node.type === "cdata" || node.type === "comment") return {
584
+ type: node.type,
585
+ value: ""
586
+ };
587
+ if (node.type === "declaration") return {
588
+ type: "declaration",
589
+ attributes: []
590
+ };
591
+ return {
592
+ type: "pi",
593
+ target: "",
594
+ content: ""
595
+ };
596
+ }
572
597
  function appReducer(state, action) {
573
598
  switch (action.type) {
574
599
  case "PUSH_SCREEN": return {
@@ -775,6 +800,39 @@ function appReducer(state, action) {
775
800
  setTextContainerText(item, action.text);
776
801
  });
777
802
  }
803
+ case "INSERT_PARAGRAPH_IMAGE": {
804
+ const doc = wordprocessingDocument(state);
805
+ if (doc === void 0) return wrongDocument(state, "a docx or odt document");
806
+ const paragraph = paragraphAt(doc, action.blockIndex);
807
+ if (paragraph === void 0) return withStatus(state, "warning", `There is no paragraph at index ${action.blockIndex}`);
808
+ return mutate(state, doc, () => {
809
+ paragraph.insertImageAfter({
810
+ format: action.format,
811
+ bytes: action.bytes,
812
+ widthPt: action.widthPt,
813
+ heightPt: action.heightPt,
814
+ altText: action.altText
815
+ });
816
+ });
817
+ }
818
+ case "INSERT_DOCX_FORMULA": {
819
+ const doc = state.openDocument;
820
+ if (doc?.format !== "docx") return wrongDocument(state, "a docx document");
821
+ const paragraph = doc.editor.paragraphs()[action.blockIndex];
822
+ if (paragraph === void 0) return withStatus(state, "warning", `There is no paragraph at index ${action.blockIndex}`);
823
+ let written = true;
824
+ const nextState = mutate(state, doc, () => {
825
+ written = paragraph.appendOfficeMath(action.mathml).written;
826
+ });
827
+ return written ? nextState : withStatus(nextState, "warning", "The formula produced no OMML content and was not written");
828
+ }
829
+ case "INSERT_ODT_FORMULA": {
830
+ const doc = state.openDocument;
831
+ if (doc?.format !== "odt") return wrongDocument(state, "an odt document");
832
+ return mutate(state, doc, () => {
833
+ doc.editor.body.appendFormula({ mathml: action.mathml.map(mutableMathMlNode) }, action.frame);
834
+ });
835
+ }
778
836
  case "ADD_SLIDE": {
779
837
  const doc = presentationDocument(state);
780
838
  if (doc === void 0) return wrongDocument(state, "a pptx or odp document");
@@ -1668,6 +1726,220 @@ function StatusLine() {
1668
1726
  ] });
1669
1727
  }
1670
1728
  //#endregion
1729
+ //#region src/tui/screens/shared/field-wizard.tsx
1730
+ function requireFieldValue(values, key) {
1731
+ const value = values[key];
1732
+ if (value === void 0) throw new Error(`Field wizard field '${key}' was never recorded before building the action.`);
1733
+ return value;
1734
+ }
1735
+ function FieldWizard(props) {
1736
+ const [stepIndex, setStepIndex] = useState(0);
1737
+ const [collected, setCollected] = useState({});
1738
+ const initialField = props.fields[0];
1739
+ const [draft, setDraft] = useState(initialField === void 0 ? "" : initialField.defaultValue);
1740
+ const field = props.fields[stepIndex];
1741
+ if (field === void 0) throw new Error(`FieldWizard stepIndex ${stepIndex} is out of range for ${props.fields.length} fields -- onComplete always fires before stepIndex can advance past the last field, so this indicates a bug in that advance.`);
1742
+ return /* @__PURE__ */ jsxs(Box, {
1743
+ flexDirection: "column",
1744
+ borderStyle: "round",
1745
+ paddingX: 1,
1746
+ children: [
1747
+ /* @__PURE__ */ jsx(Text, {
1748
+ bold: true,
1749
+ children: field.label
1750
+ }),
1751
+ /* @__PURE__ */ jsx(TextField, {
1752
+ value: draft,
1753
+ isFocused: true,
1754
+ onChange: setDraft,
1755
+ onCancel: props.onCancel,
1756
+ onSubmit: (value) => {
1757
+ const recorded = {
1758
+ ...collected,
1759
+ [field.key]: value
1760
+ };
1761
+ const nextIndex = stepIndex + 1;
1762
+ const nextField = props.fields[nextIndex];
1763
+ if (nextField === void 0) {
1764
+ props.onComplete(recorded);
1765
+ return;
1766
+ }
1767
+ setCollected(recorded);
1768
+ setDraft(nextField.defaultValue);
1769
+ setStepIndex(nextIndex);
1770
+ }
1771
+ }),
1772
+ /* @__PURE__ */ jsxs(Text, {
1773
+ dimColor: true,
1774
+ children: [
1775
+ "Step ",
1776
+ stepIndex + 1,
1777
+ " of ",
1778
+ props.fields.length,
1779
+ " -- Enter to continue, Esc to cancel"
1780
+ ]
1781
+ })
1782
+ ]
1783
+ });
1784
+ }
1785
+ //#endregion
1786
+ //#region src/tui/screens/shared/formula-presets.ts
1787
+ function element(tag, children = []) {
1788
+ return {
1789
+ type: "element",
1790
+ tag,
1791
+ attributes: [],
1792
+ children
1793
+ };
1794
+ }
1795
+ function text(value) {
1796
+ return {
1797
+ type: "text",
1798
+ value
1799
+ };
1800
+ }
1801
+ function mi(name) {
1802
+ return element("mi", [text(name)]);
1803
+ }
1804
+ function mn(value) {
1805
+ return element("mn", [text(value)]);
1806
+ }
1807
+ function mo(operator) {
1808
+ return element("mo", [text(operator)]);
1809
+ }
1810
+ const FORMULA_PRESETS = [
1811
+ {
1812
+ label: "Fraction: x / 2",
1813
+ mathml: [element("mfrac", [mi("x"), mn("2")])]
1814
+ },
1815
+ {
1816
+ label: "Power: x^2",
1817
+ mathml: [element("msup", [mi("x"), mn("2")])]
1818
+ },
1819
+ {
1820
+ label: "Subscript: x_i",
1821
+ mathml: [element("msub", [mi("x"), mi("i")])]
1822
+ },
1823
+ {
1824
+ label: "Square root: sqrt(x)",
1825
+ mathml: [element("msqrt", [mi("x")])]
1826
+ },
1827
+ {
1828
+ label: "Summation: sum(i=1..n) i",
1829
+ mathml: [element("munderover", [
1830
+ mo("∑"),
1831
+ element("mrow", [
1832
+ mi("i"),
1833
+ mo("="),
1834
+ mn("1")
1835
+ ]),
1836
+ mi("n")
1837
+ ])]
1838
+ },
1839
+ {
1840
+ label: "Quadratic formula",
1841
+ mathml: [element("mrow", [
1842
+ mi("x"),
1843
+ mo("="),
1844
+ element("mfrac", [element("mrow", [
1845
+ mo("-"),
1846
+ mi("b"),
1847
+ mo("±"),
1848
+ element("msqrt", [element("mrow", [
1849
+ element("msup", [mi("b"), mn("2")]),
1850
+ mo("-"),
1851
+ mn("4"),
1852
+ mi("a"),
1853
+ mi("c")
1854
+ ])])
1855
+ ]), element("mrow", [mn("2"), mi("a")])])
1856
+ ])]
1857
+ }
1858
+ ];
1859
+ //#endregion
1860
+ //#region src/tui/screens/shared/formula-picker.tsx
1861
+ const RAW_ENTRY_LABEL = "Raw MathML...";
1862
+ const PICKER_ROWS = [...FORMULA_PRESETS.map((preset) => ({
1863
+ label: preset.label,
1864
+ mathml: preset.mathml
1865
+ })), {
1866
+ label: RAW_ENTRY_LABEL,
1867
+ mathml: void 0
1868
+ }];
1869
+ function FormulaPicker(props) {
1870
+ const [rawInput, setRawInput] = useState(void 0);
1871
+ const { selectedIndex } = useNavigationInput({
1872
+ itemCount: PICKER_ROWS.length,
1873
+ isActive: props.isActive && rawInput === void 0,
1874
+ onBack: props.onCancel,
1875
+ onSelect: (index) => {
1876
+ const row = PICKER_ROWS[index];
1877
+ if (row === void 0) return;
1878
+ if (row.mathml === void 0) {
1879
+ setRawInput("");
1880
+ return;
1881
+ }
1882
+ props.onMathml(row.mathml);
1883
+ }
1884
+ });
1885
+ if (rawInput !== void 0) return /* @__PURE__ */ jsxs(Box, {
1886
+ flexDirection: "column",
1887
+ borderStyle: "round",
1888
+ paddingX: 1,
1889
+ children: [
1890
+ /* @__PURE__ */ jsx(Text, {
1891
+ bold: true,
1892
+ children: "Raw MathML (the children of the <math> root, e.g. <mfrac>...</mfrac>)"
1893
+ }),
1894
+ /* @__PURE__ */ jsx(TextField, {
1895
+ value: rawInput,
1896
+ isFocused: true,
1897
+ onChange: setRawInput,
1898
+ onCancel: () => {
1899
+ setRawInput(void 0);
1900
+ },
1901
+ onSubmit: (value) => {
1902
+ try {
1903
+ const parsed = parseXml(value);
1904
+ props.onMathml(parsed);
1905
+ } catch (error) {
1906
+ props.onInvalidRawMathml(describeError(error));
1907
+ }
1908
+ setRawInput(void 0);
1909
+ }
1910
+ }),
1911
+ /* @__PURE__ */ jsx(Text, {
1912
+ dimColor: true,
1913
+ children: "Enter to insert, Esc to cancel"
1914
+ })
1915
+ ]
1916
+ });
1917
+ return /* @__PURE__ */ jsxs(Box, {
1918
+ flexDirection: "column",
1919
+ borderStyle: "round",
1920
+ paddingX: 1,
1921
+ children: [
1922
+ /* @__PURE__ */ jsx(Text, {
1923
+ bold: true,
1924
+ children: "Insert formula -- choose a preset or write raw MathML"
1925
+ }),
1926
+ /* @__PURE__ */ jsx(ListView, {
1927
+ items: PICKER_ROWS,
1928
+ selectedIndex,
1929
+ reservedRows: PICKER_ROWS.length + 2,
1930
+ renderItem: (row, isSelected) => /* @__PURE__ */ jsxs(Text, {
1931
+ color: isSelected ? "cyan" : void 0,
1932
+ children: [isSelected ? "> " : " ", row.label]
1933
+ })
1934
+ }),
1935
+ /* @__PURE__ */ jsx(Text, {
1936
+ dimColor: true,
1937
+ children: "Enter to choose, Esc to cancel"
1938
+ })
1939
+ ]
1940
+ });
1941
+ }
1942
+ //#endregion
1671
1943
  //#region src/tui/screens/shared/text.ts
1672
1944
  function truncatePreview(text, maxLength) {
1673
1945
  const singleLine = text.replace(/\s+/gu, " ").trim();
@@ -1682,6 +1954,10 @@ function parseNonNegativeIntField(raw, fallback) {
1682
1954
  const parsed = Number.parseInt(raw, 10);
1683
1955
  return Number.isInteger(parsed) && parsed >= 0 ? parsed : fallback;
1684
1956
  }
1957
+ function parseNumberField(raw, fallback) {
1958
+ const parsed = Number.parseFloat(raw);
1959
+ return Number.isFinite(parsed) ? parsed : fallback;
1960
+ }
1685
1961
  //#endregion
1686
1962
  //#region src/tui/screens/shared/paragraph-family.tsx
1687
1963
  function paragraphFamilyDocument(openDocument) {
@@ -1747,6 +2023,36 @@ function listSummary(list, index) {
1747
2023
  }
1748
2024
  const DEFAULT_TABLE_ROWS$1 = 2;
1749
2025
  const DEFAULT_TABLE_COLUMNS$1 = 2;
2026
+ const FORMULA_FRAME_FIELDS = [
2027
+ {
2028
+ key: "xPt",
2029
+ label: "X (pt)",
2030
+ defaultValue: "40"
2031
+ },
2032
+ {
2033
+ key: "yPt",
2034
+ label: "Y (pt)",
2035
+ defaultValue: "40"
2036
+ },
2037
+ {
2038
+ key: "widthPt",
2039
+ label: "Width (pt)",
2040
+ defaultValue: "120"
2041
+ },
2042
+ {
2043
+ key: "heightPt",
2044
+ label: "Height (pt)",
2045
+ defaultValue: "40"
2046
+ }
2047
+ ];
2048
+ function readFormulaFrame(values) {
2049
+ return {
2050
+ xPt: parseNumberField(requireFieldValue(values, "xPt"), 0),
2051
+ yPt: parseNumberField(requireFieldValue(values, "yPt"), 0),
2052
+ widthPt: parseNumberField(requireFieldValue(values, "widthPt"), 120),
2053
+ heightPt: parseNumberField(requireFieldValue(values, "heightPt"), 40)
2054
+ };
2055
+ }
1750
2056
  function ParagraphFamilyBodyList(props) {
1751
2057
  const { adapter } = props;
1752
2058
  const state = useAppState();
@@ -1797,6 +2103,9 @@ function ParagraphFamilyBodyList(props) {
1797
2103
  const [wizardStartColumn, setWizardStartColumn] = useState(0);
1798
2104
  const [wizardRowSpan, setWizardRowSpan] = useState(1);
1799
2105
  const wizardOpen = tableWizard !== "closed";
2106
+ const [formulaFlow, setFormulaFlow] = useState("closed");
2107
+ const [pendingFormulaMathml, setPendingFormulaMathml] = useState(void 0);
2108
+ const formulaFlowOpen = formulaFlow !== "closed";
1800
2109
  const closeWizard = () => {
1801
2110
  setTableWizard("closed");
1802
2111
  };
@@ -1822,7 +2131,10 @@ function ParagraphFamilyBodyList(props) {
1822
2131
  setWizardDraft(String(DEFAULT_TABLE_ROWS$1));
1823
2132
  setTableWizard("rows");
1824
2133
  }
1825
- }, { isActive: !anyOverlayOpen(state) && !wizardOpen });
2134
+ }, { isActive: !anyOverlayOpen(state) && !wizardOpen && !formulaFlowOpen });
2135
+ useInput((input) => {
2136
+ if (input === "m" && adapter.formatLabel === "odt") setFormulaFlow("picking");
2137
+ }, { isActive: !anyOverlayOpen(state) && !wizardOpen && !formulaFlowOpen });
1826
2138
  useInput((input, key) => {
1827
2139
  if (key.escape) {
1828
2140
  closeWizard();
@@ -1870,7 +2182,7 @@ function ParagraphFamilyBodyList(props) {
1870
2182
  };
1871
2183
  const { selectedIndex } = usePersistedSelection(selectionKeyFor({ kind: "bodyList" }), {
1872
2184
  itemCount: selectableRowIndices.length,
1873
- isActive: !anyOverlayOpen(state) && !wizardOpen,
2185
+ isActive: !anyOverlayOpen(state) && !wizardOpen && !formulaFlowOpen,
1874
2186
  onBack: () => {
1875
2187
  dispatch({ type: "POP_SCREEN" });
1876
2188
  },
@@ -2037,9 +2349,46 @@ function ParagraphFamilyBodyList(props) {
2037
2349
  onSubmit: submitWizardMergeColSpan,
2038
2350
  onCancel: closeWizard
2039
2351
  })] }) : void 0,
2040
- /* @__PURE__ */ jsx(Text, {
2352
+ formulaFlow === "picking" ? /* @__PURE__ */ jsx(FormulaPicker, {
2353
+ isActive: !anyOverlayOpen(state),
2354
+ onCancel: () => {
2355
+ setFormulaFlow("closed");
2356
+ },
2357
+ onMathml: (mathml) => {
2358
+ setPendingFormulaMathml(mathml);
2359
+ setFormulaFlow("frame");
2360
+ },
2361
+ onInvalidRawMathml: (message) => {
2362
+ dispatch({
2363
+ type: "SET_STATUS",
2364
+ severity: "warning",
2365
+ text: `Could not parse MathML: ${message}`
2366
+ });
2367
+ }
2368
+ }) : void 0,
2369
+ formulaFlow === "frame" ? /* @__PURE__ */ jsx(FieldWizard, {
2370
+ fields: FORMULA_FRAME_FIELDS,
2371
+ onCancel: () => {
2372
+ setFormulaFlow("closed");
2373
+ setPendingFormulaMathml(void 0);
2374
+ },
2375
+ onComplete: (values) => {
2376
+ if (pendingFormulaMathml !== void 0) dispatch({
2377
+ type: "INSERT_ODT_FORMULA",
2378
+ mathml: pendingFormulaMathml,
2379
+ frame: readFormulaFrame(values)
2380
+ });
2381
+ setFormulaFlow("closed");
2382
+ setPendingFormulaMathml(void 0);
2383
+ }
2384
+ }) : void 0,
2385
+ /* @__PURE__ */ jsxs(Text, {
2041
2386
  dimColor: true,
2042
- children: "Enter to open, a to append a paragraph, T to append a table, Esc back"
2387
+ children: [
2388
+ "Enter to open, a to append a paragraph, T to append a table",
2389
+ adapter.formatLabel === "odt" ? ", m to insert a formula" : "",
2390
+ ", Esc back"
2391
+ ]
2043
2392
  })
2044
2393
  ]
2045
2394
  });
@@ -2059,6 +2408,66 @@ function isValidHexColorInput(input) {
2059
2408
  }
2060
2409
  //#endregion
2061
2410
  //#region src/tui/screens/editors/docx/paragraph-detail.tsx
2411
+ const IMAGE_FIELDS = [
2412
+ {
2413
+ key: "path",
2414
+ label: "Image file path (.png/.jpg/.jpeg)",
2415
+ defaultValue: ""
2416
+ },
2417
+ {
2418
+ key: "widthPt",
2419
+ label: "Width (pt)",
2420
+ defaultValue: "100"
2421
+ },
2422
+ {
2423
+ key: "heightPt",
2424
+ label: "Height (pt)",
2425
+ defaultValue: "60"
2426
+ },
2427
+ {
2428
+ key: "altText",
2429
+ label: "Alt text, blank for none",
2430
+ defaultValue: ""
2431
+ }
2432
+ ];
2433
+ function inferImageFormat$1(path) {
2434
+ const extension = path.slice(path.lastIndexOf(".") + 1).toLowerCase();
2435
+ if (extension === "png") return "png";
2436
+ if (extension === "jpg" || extension === "jpeg") return "jpeg";
2437
+ }
2438
+ async function applyInsertImage(blockIndex, values, dispatch) {
2439
+ const path = requireFieldValue(values, "path");
2440
+ const format = inferImageFormat$1(path);
2441
+ if (format === void 0) {
2442
+ dispatch({
2443
+ type: "SET_STATUS",
2444
+ severity: "warning",
2445
+ text: `${path} is not a .png or .jpg/.jpeg file -- image not inserted`
2446
+ });
2447
+ return;
2448
+ }
2449
+ try {
2450
+ const bytes = new Uint8Array(await readInput(path));
2451
+ const widthPt = parseNumberField(requireFieldValue(values, "widthPt"), 100);
2452
+ const heightPt = parseNumberField(requireFieldValue(values, "heightPt"), 60);
2453
+ const altTextRaw = requireFieldValue(values, "altText").trim();
2454
+ dispatch({
2455
+ type: "INSERT_PARAGRAPH_IMAGE",
2456
+ blockIndex,
2457
+ format,
2458
+ bytes,
2459
+ widthPt,
2460
+ heightPt,
2461
+ altText: altTextRaw.length === 0 ? void 0 : altTextRaw
2462
+ });
2463
+ } catch (error) {
2464
+ dispatch({
2465
+ type: "SET_STATUS",
2466
+ severity: "error",
2467
+ text: `Could not read ${path}: ${describeError(error)}`
2468
+ });
2469
+ }
2470
+ }
2062
2471
  function ParagraphRunsView(props) {
2063
2472
  if (props.runs.length === 0) return /* @__PURE__ */ jsx(Text, {
2064
2473
  dimColor: true,
@@ -2078,6 +2487,8 @@ function ParagraphDetailScreen() {
2078
2487
  const dispatch = useAppDispatch();
2079
2488
  const [runIndex, setRunIndex] = useState(0);
2080
2489
  const [colorInput, setColorInput] = useState(void 0);
2490
+ const [imageWizardOpen, setImageWizardOpen] = useState(false);
2491
+ const [formulaPickerOpen, setFormulaPickerOpen] = useState(false);
2081
2492
  const screen = currentScreen(state);
2082
2493
  const doc = paragraphFamilyDocument(state.openDocument);
2083
2494
  const paragraph = screen.kind === "paragraphDetail" && doc !== void 0 ? liveParagraphAt(doc, screen.blockIndex) : void 0;
@@ -2140,6 +2551,14 @@ function ParagraphDetailScreen() {
2140
2551
  });
2141
2552
  return;
2142
2553
  }
2554
+ if (input === "I") {
2555
+ setImageWizardOpen(true);
2556
+ return;
2557
+ }
2558
+ if (input === "m" && doc?.format === "docx") {
2559
+ setFormulaPickerOpen(true);
2560
+ return;
2561
+ }
2143
2562
  if (selectedRun === void 0) return;
2144
2563
  if (input === "b") {
2145
2564
  dispatch({
@@ -2166,7 +2585,7 @@ function ParagraphDetailScreen() {
2166
2585
  return;
2167
2586
  }
2168
2587
  if (input === "c") setColorInput(selectedRun.color === void 0 ? "" : layoutColorToHex(selectedRun.color).slice(1));
2169
- }, { isActive: !anyOverlayOpen(state) && colorInput === void 0 });
2588
+ }, { isActive: !anyOverlayOpen(state) && colorInput === void 0 && !imageWizardOpen && !formulaPickerOpen });
2170
2589
  if (screen.kind !== "paragraphDetail") return /* @__PURE__ */ jsx(Text, {
2171
2590
  color: "red",
2172
2591
  children: "ParagraphDetailScreen rendered outside a paragraphDetail screen."
@@ -2224,9 +2643,45 @@ function ParagraphDetailScreen() {
2224
2643
  setColorInput(void 0);
2225
2644
  }
2226
2645
  })] }),
2227
- /* @__PURE__ */ jsx(Text, {
2646
+ imageWizardOpen ? /* @__PURE__ */ jsx(FieldWizard, {
2647
+ fields: IMAGE_FIELDS,
2648
+ onCancel: () => {
2649
+ setImageWizardOpen(false);
2650
+ },
2651
+ onComplete: (values) => {
2652
+ applyInsertImage(blockIndex, values, dispatch).then(() => {
2653
+ setImageWizardOpen(false);
2654
+ });
2655
+ }
2656
+ }) : void 0,
2657
+ formulaPickerOpen ? /* @__PURE__ */ jsx(FormulaPicker, {
2658
+ isActive: !anyOverlayOpen(state),
2659
+ onCancel: () => {
2660
+ setFormulaPickerOpen(false);
2661
+ },
2662
+ onMathml: (mathml) => {
2663
+ dispatch({
2664
+ type: "INSERT_DOCX_FORMULA",
2665
+ blockIndex,
2666
+ mathml
2667
+ });
2668
+ setFormulaPickerOpen(false);
2669
+ },
2670
+ onInvalidRawMathml: (message) => {
2671
+ dispatch({
2672
+ type: "SET_STATUS",
2673
+ severity: "warning",
2674
+ text: `Could not parse MathML: ${message}`
2675
+ });
2676
+ }
2677
+ }) : void 0,
2678
+ /* @__PURE__ */ jsxs(Text, {
2228
2679
  dimColor: true,
2229
- children: "<- / -> move, Enter edit text, b/i/u toggle, c colour, a append run, Esc back"
2680
+ children: [
2681
+ "<- / -> move, Enter edit text, b/i/u toggle, c colour, a append run, I image",
2682
+ doc.format === "docx" ? ", m formula" : "",
2683
+ ", Esc back"
2684
+ ]
2230
2685
  })
2231
2686
  ]
2232
2687
  });
@@ -3365,10 +3820,6 @@ function describeFillStroke(vector) {
3365
3820
  if (vector.stroke !== void 0) parts.push(`stroke ${formatColor$1(vector.stroke.color)} ${formatPt(vector.stroke.widthPt)}pt`);
3366
3821
  return parts.length === 0 ? "no fill or stroke" : parts.join(", ");
3367
3822
  }
3368
- function parseNumberField(raw, fallback) {
3369
- const parsed = Number.parseFloat(raw);
3370
- return Number.isFinite(parsed) ? parsed : fallback;
3371
- }
3372
3823
  function parseColorField(raw) {
3373
3824
  const trimmed = raw.trim();
3374
3825
  if (trimmed.length === 0) return;
@@ -3425,11 +3876,6 @@ function defaultTriangleSubpaths(widthPt, heightPt) {
3425
3876
  closed: true
3426
3877
  }];
3427
3878
  }
3428
- function requireFieldValue(values, key) {
3429
- const value = values[key];
3430
- if (value === void 0) throw new Error(`Add-item field '${key}' was never recorded before building the action.`);
3431
- return value;
3432
- }
3433
3879
  //#endregion
3434
3880
  //#region src/tui/screens/editors/odg/page-list.tsx
3435
3881
  function OdgPageListScreen() {
@@ -3736,56 +4182,6 @@ async function applyAddKind(kind, pageIndex, doc, values, dispatch) {
3736
4182
  }
3737
4183
  }
3738
4184
  }
3739
- function FieldWizard(props) {
3740
- const [stepIndex, setStepIndex] = useState(0);
3741
- const [collected, setCollected] = useState({});
3742
- const initialField = props.fields[0];
3743
- const [draft, setDraft] = useState(initialField === void 0 ? "" : initialField.defaultValue);
3744
- const field = props.fields[stepIndex];
3745
- if (field === void 0) throw new Error(`FieldWizard stepIndex ${stepIndex} is out of range for ${props.fields.length} fields -- onComplete always fires before stepIndex can advance past the last field, so this indicates a bug in that advance.`);
3746
- return /* @__PURE__ */ jsxs(Box, {
3747
- flexDirection: "column",
3748
- borderStyle: "round",
3749
- paddingX: 1,
3750
- children: [
3751
- /* @__PURE__ */ jsx(Text, {
3752
- bold: true,
3753
- children: field.label
3754
- }),
3755
- /* @__PURE__ */ jsx(TextField, {
3756
- value: draft,
3757
- isFocused: true,
3758
- onChange: setDraft,
3759
- onCancel: props.onCancel,
3760
- onSubmit: (value) => {
3761
- const recorded = {
3762
- ...collected,
3763
- [field.key]: value
3764
- };
3765
- const nextIndex = stepIndex + 1;
3766
- const nextField = props.fields[nextIndex];
3767
- if (nextField === void 0) {
3768
- props.onComplete(recorded);
3769
- return;
3770
- }
3771
- setCollected(recorded);
3772
- setDraft(nextField.defaultValue);
3773
- setStepIndex(nextIndex);
3774
- }
3775
- }),
3776
- /* @__PURE__ */ jsxs(Text, {
3777
- dimColor: true,
3778
- children: [
3779
- "Step ",
3780
- stepIndex + 1,
3781
- " of ",
3782
- props.fields.length,
3783
- " -- Enter to continue, Esc to cancel"
3784
- ]
3785
- })
3786
- ]
3787
- });
3788
- }
3789
4185
  function AddItemFlow(props) {
3790
4186
  const dispatch = useAppDispatch();
3791
4187
  const [kind, setKind] = useState(void 0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "document-cli",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "CLI and interactive Ink TUI for documents.js: every docx/pptx/odt/odp/ods/odg/odf/pdf/odm/odb/xlsx/markdown conversion, bridge, and editor as a scriptable command or a terminal app.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -72,7 +72,7 @@
72
72
  "packageManager": "pnpm@11.6.0",
73
73
  "dependencies": {
74
74
  "commander": "^15.0.0",
75
- "documents.js": "^1.73.0",
75
+ "documents.js": "^1.75.1",
76
76
  "ink": "^7.1.1",
77
77
  "ink-text-input": "^6.0.0",
78
78
  "odf.js": "^2.2.0",