document-cli 1.7.0 → 1.9.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 +2 -2
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/{tui-BzdX4QQg.js → tui-D9SLI7oT.js} +1010 -156
- package/package.json +2 -2
|
@@ -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, bytesToBase64, 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";
|
|
@@ -508,6 +508,11 @@ function drawingDocument(state) {
|
|
|
508
508
|
if (doc === void 0) return;
|
|
509
509
|
return doc.format === "odg" ? doc : void 0;
|
|
510
510
|
}
|
|
511
|
+
function vectorHostDocument(state) {
|
|
512
|
+
const doc = state.openDocument;
|
|
513
|
+
if (doc === void 0) return;
|
|
514
|
+
return doc.format === "odg" || doc.format === "odp" ? doc : void 0;
|
|
515
|
+
}
|
|
511
516
|
function markdownDocument(state) {
|
|
512
517
|
const doc = state.openDocument;
|
|
513
518
|
if (doc === void 0) return;
|
|
@@ -569,6 +574,31 @@ function setTextContainerText(container, text) {
|
|
|
569
574
|
function setCellText(cell, text) {
|
|
570
575
|
setTextContainerText(cell, text);
|
|
571
576
|
}
|
|
577
|
+
function mutableMathMlNode(node) {
|
|
578
|
+
if (node.type === "element") return {
|
|
579
|
+
type: "element",
|
|
580
|
+
tag: node.tag,
|
|
581
|
+
attributes: [...node.attributes],
|
|
582
|
+
children: node.children.map(mutableMathMlNode)
|
|
583
|
+
};
|
|
584
|
+
if (node.type === "text") return {
|
|
585
|
+
type: "text",
|
|
586
|
+
value: node.value
|
|
587
|
+
};
|
|
588
|
+
if (node.type === "cdata" || node.type === "comment") return {
|
|
589
|
+
type: node.type,
|
|
590
|
+
value: ""
|
|
591
|
+
};
|
|
592
|
+
if (node.type === "declaration") return {
|
|
593
|
+
type: "declaration",
|
|
594
|
+
attributes: []
|
|
595
|
+
};
|
|
596
|
+
return {
|
|
597
|
+
type: "pi",
|
|
598
|
+
target: "",
|
|
599
|
+
content: ""
|
|
600
|
+
};
|
|
601
|
+
}
|
|
572
602
|
function appReducer(state, action) {
|
|
573
603
|
switch (action.type) {
|
|
574
604
|
case "PUSH_SCREEN": return {
|
|
@@ -715,6 +745,12 @@ function appReducer(state, action) {
|
|
|
715
745
|
case "SET_RUN_COLOR": return withRun(state, action.blockIndex, action.runIndex, (run) => {
|
|
716
746
|
run.color = action.color;
|
|
717
747
|
});
|
|
748
|
+
case "SET_RUN_FONT_FAMILY": return withRun(state, action.blockIndex, action.runIndex, (run) => {
|
|
749
|
+
run.fontFamily = action.fontFamily;
|
|
750
|
+
});
|
|
751
|
+
case "SET_RUN_FONT_SIZE": return withRun(state, action.blockIndex, action.runIndex, (run) => {
|
|
752
|
+
run.sizePt = action.sizePt;
|
|
753
|
+
});
|
|
718
754
|
case "APPEND_TABLE": {
|
|
719
755
|
const doc = wordprocessingDocument(state);
|
|
720
756
|
if (doc === void 0) return wrongDocument(state, "a docx or odt document");
|
|
@@ -775,6 +811,47 @@ function appReducer(state, action) {
|
|
|
775
811
|
setTextContainerText(item, action.text);
|
|
776
812
|
});
|
|
777
813
|
}
|
|
814
|
+
case "ADD_LIST": {
|
|
815
|
+
const doc = wordprocessingDocument(state);
|
|
816
|
+
if (doc === void 0) return wrongDocument(state, "a docx or odt document");
|
|
817
|
+
if (doc.format !== "odt") return wrongDocument(state, "an odt document (lists are an odt-only concept)");
|
|
818
|
+
return mutate(state, doc, () => {
|
|
819
|
+
doc.editor.body.appendList();
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
case "INSERT_PARAGRAPH_IMAGE": {
|
|
823
|
+
const doc = wordprocessingDocument(state);
|
|
824
|
+
if (doc === void 0) return wrongDocument(state, "a docx or odt document");
|
|
825
|
+
const paragraph = paragraphAt(doc, action.blockIndex);
|
|
826
|
+
if (paragraph === void 0) return withStatus(state, "warning", `There is no paragraph at index ${action.blockIndex}`);
|
|
827
|
+
return mutate(state, doc, () => {
|
|
828
|
+
paragraph.insertImageAfter({
|
|
829
|
+
format: action.format,
|
|
830
|
+
bytes: action.bytes,
|
|
831
|
+
widthPt: action.widthPt,
|
|
832
|
+
heightPt: action.heightPt,
|
|
833
|
+
altText: action.altText
|
|
834
|
+
});
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
case "INSERT_DOCX_FORMULA": {
|
|
838
|
+
const doc = state.openDocument;
|
|
839
|
+
if (doc?.format !== "docx") return wrongDocument(state, "a docx document");
|
|
840
|
+
const paragraph = doc.editor.paragraphs()[action.blockIndex];
|
|
841
|
+
if (paragraph === void 0) return withStatus(state, "warning", `There is no paragraph at index ${action.blockIndex}`);
|
|
842
|
+
let written = true;
|
|
843
|
+
const nextState = mutate(state, doc, () => {
|
|
844
|
+
written = paragraph.appendOfficeMath(action.mathml).written;
|
|
845
|
+
});
|
|
846
|
+
return written ? nextState : withStatus(nextState, "warning", "The formula produced no OMML content and was not written");
|
|
847
|
+
}
|
|
848
|
+
case "INSERT_ODT_FORMULA": {
|
|
849
|
+
const doc = state.openDocument;
|
|
850
|
+
if (doc?.format !== "odt") return wrongDocument(state, "an odt document");
|
|
851
|
+
return mutate(state, doc, () => {
|
|
852
|
+
doc.editor.body.appendFormula({ mathml: action.mathml.map(mutableMathMlNode) }, action.frame);
|
|
853
|
+
});
|
|
854
|
+
}
|
|
778
855
|
case "ADD_SLIDE": {
|
|
779
856
|
const doc = presentationDocument(state);
|
|
780
857
|
if (doc === void 0) return wrongDocument(state, "a pptx or odp document");
|
|
@@ -885,6 +962,23 @@ function appReducer(state, action) {
|
|
|
885
962
|
case "SET_CELL_VALUE": return withSheet(state, action.sheetIndex, (sheet) => {
|
|
886
963
|
sheet.cell(action.row, action.column).value = action.value;
|
|
887
964
|
});
|
|
965
|
+
case "SET_CELL_FORMULA": return withSheet(state, action.sheetIndex, (sheet) => {
|
|
966
|
+
sheet.cell(action.row, action.column).formula = action.formula;
|
|
967
|
+
});
|
|
968
|
+
case "ADD_SHEET_IMAGE": return withSheet(state, action.sheetIndex, (sheet) => {
|
|
969
|
+
sheet.addImage({
|
|
970
|
+
kind: "image",
|
|
971
|
+
format: action.format,
|
|
972
|
+
base64: bytesToBase64(action.bytes),
|
|
973
|
+
widthPt: action.widthPt,
|
|
974
|
+
heightPt: action.heightPt,
|
|
975
|
+
altText: action.altText,
|
|
976
|
+
anchorRow: action.anchorRow,
|
|
977
|
+
anchorColumn: action.anchorColumn,
|
|
978
|
+
offsetXPt: action.offsetXPt,
|
|
979
|
+
offsetYPt: action.offsetYPt
|
|
980
|
+
});
|
|
981
|
+
});
|
|
888
982
|
case "MERGE_CELLS": {
|
|
889
983
|
const doc = spreadsheetDocument(state);
|
|
890
984
|
if (doc === void 0) return wrongDocument(state, "an ods document");
|
|
@@ -908,23 +1002,64 @@ function appReducer(state, action) {
|
|
|
908
1002
|
case "ADD_ELLIPSE":
|
|
909
1003
|
case "ADD_LINE":
|
|
910
1004
|
case "ADD_PATH": {
|
|
911
|
-
const doc =
|
|
912
|
-
if (doc === void 0) return wrongDocument(state, "an odg document");
|
|
913
|
-
|
|
914
|
-
|
|
1005
|
+
const doc = vectorHostDocument(state);
|
|
1006
|
+
if (doc === void 0) return wrongDocument(state, "an odg or odp document");
|
|
1007
|
+
if (doc.format === "odg") {
|
|
1008
|
+
const page = doc.editor.pages()[action.containerIndex];
|
|
1009
|
+
if (page === void 0) return withStatus(state, "warning", `There is no page at index ${action.containerIndex}`);
|
|
1010
|
+
return mutate(state, doc, () => {
|
|
1011
|
+
switch (action.type) {
|
|
1012
|
+
case "ADD_RECT":
|
|
1013
|
+
page.addRect(action.init);
|
|
1014
|
+
return;
|
|
1015
|
+
case "ADD_ELLIPSE":
|
|
1016
|
+
page.addEllipse(action.init);
|
|
1017
|
+
return;
|
|
1018
|
+
case "ADD_LINE":
|
|
1019
|
+
page.addLine(action.init);
|
|
1020
|
+
return;
|
|
1021
|
+
case "ADD_PATH":
|
|
1022
|
+
page.addPath(action.init);
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
const slide = doc.editor.slides()[action.containerIndex];
|
|
1028
|
+
if (slide === void 0) return withStatus(state, "warning", `There is no slide at index ${action.containerIndex}`);
|
|
915
1029
|
return mutate(state, doc, () => {
|
|
916
1030
|
switch (action.type) {
|
|
917
1031
|
case "ADD_RECT":
|
|
918
|
-
|
|
1032
|
+
slide.addVector({
|
|
1033
|
+
kind: "rect",
|
|
1034
|
+
frame: action.init.frame,
|
|
1035
|
+
fill: action.init.fill,
|
|
1036
|
+
stroke: action.init.stroke
|
|
1037
|
+
});
|
|
919
1038
|
return;
|
|
920
1039
|
case "ADD_ELLIPSE":
|
|
921
|
-
|
|
1040
|
+
slide.addVector({
|
|
1041
|
+
kind: "ellipse",
|
|
1042
|
+
frame: action.init.frame,
|
|
1043
|
+
fill: action.init.fill,
|
|
1044
|
+
stroke: action.init.stroke
|
|
1045
|
+
});
|
|
922
1046
|
return;
|
|
923
1047
|
case "ADD_LINE":
|
|
924
|
-
|
|
1048
|
+
slide.addVector({
|
|
1049
|
+
kind: "line",
|
|
1050
|
+
from: action.init.from,
|
|
1051
|
+
to: action.init.to,
|
|
1052
|
+
stroke: action.init.stroke
|
|
1053
|
+
});
|
|
925
1054
|
return;
|
|
926
1055
|
case "ADD_PATH":
|
|
927
|
-
|
|
1056
|
+
slide.addVector({
|
|
1057
|
+
kind: "path",
|
|
1058
|
+
frame: action.init.frame,
|
|
1059
|
+
subpaths: [...action.init.subpaths],
|
|
1060
|
+
fill: action.init.fill,
|
|
1061
|
+
stroke: action.init.stroke
|
|
1062
|
+
});
|
|
928
1063
|
return;
|
|
929
1064
|
}
|
|
930
1065
|
});
|
|
@@ -1668,6 +1803,220 @@ function StatusLine() {
|
|
|
1668
1803
|
] });
|
|
1669
1804
|
}
|
|
1670
1805
|
//#endregion
|
|
1806
|
+
//#region src/tui/screens/shared/field-wizard.tsx
|
|
1807
|
+
function requireFieldValue(values, key) {
|
|
1808
|
+
const value = values[key];
|
|
1809
|
+
if (value === void 0) throw new Error(`Field wizard field '${key}' was never recorded before building the action.`);
|
|
1810
|
+
return value;
|
|
1811
|
+
}
|
|
1812
|
+
function FieldWizard(props) {
|
|
1813
|
+
const [stepIndex, setStepIndex] = useState(0);
|
|
1814
|
+
const [collected, setCollected] = useState({});
|
|
1815
|
+
const initialField = props.fields[0];
|
|
1816
|
+
const [draft, setDraft] = useState(initialField === void 0 ? "" : initialField.defaultValue);
|
|
1817
|
+
const field = props.fields[stepIndex];
|
|
1818
|
+
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.`);
|
|
1819
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
1820
|
+
flexDirection: "column",
|
|
1821
|
+
borderStyle: "round",
|
|
1822
|
+
paddingX: 1,
|
|
1823
|
+
children: [
|
|
1824
|
+
/* @__PURE__ */ jsx(Text, {
|
|
1825
|
+
bold: true,
|
|
1826
|
+
children: field.label
|
|
1827
|
+
}),
|
|
1828
|
+
/* @__PURE__ */ jsx(TextField, {
|
|
1829
|
+
value: draft,
|
|
1830
|
+
isFocused: true,
|
|
1831
|
+
onChange: setDraft,
|
|
1832
|
+
onCancel: props.onCancel,
|
|
1833
|
+
onSubmit: (value) => {
|
|
1834
|
+
const recorded = {
|
|
1835
|
+
...collected,
|
|
1836
|
+
[field.key]: value
|
|
1837
|
+
};
|
|
1838
|
+
const nextIndex = stepIndex + 1;
|
|
1839
|
+
const nextField = props.fields[nextIndex];
|
|
1840
|
+
if (nextField === void 0) {
|
|
1841
|
+
props.onComplete(recorded);
|
|
1842
|
+
return;
|
|
1843
|
+
}
|
|
1844
|
+
setCollected(recorded);
|
|
1845
|
+
setDraft(nextField.defaultValue);
|
|
1846
|
+
setStepIndex(nextIndex);
|
|
1847
|
+
}
|
|
1848
|
+
}),
|
|
1849
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
1850
|
+
dimColor: true,
|
|
1851
|
+
children: [
|
|
1852
|
+
"Step ",
|
|
1853
|
+
stepIndex + 1,
|
|
1854
|
+
" of ",
|
|
1855
|
+
props.fields.length,
|
|
1856
|
+
" -- Enter to continue, Esc to cancel"
|
|
1857
|
+
]
|
|
1858
|
+
})
|
|
1859
|
+
]
|
|
1860
|
+
});
|
|
1861
|
+
}
|
|
1862
|
+
//#endregion
|
|
1863
|
+
//#region src/tui/screens/shared/formula-presets.ts
|
|
1864
|
+
function element(tag, children = []) {
|
|
1865
|
+
return {
|
|
1866
|
+
type: "element",
|
|
1867
|
+
tag,
|
|
1868
|
+
attributes: [],
|
|
1869
|
+
children
|
|
1870
|
+
};
|
|
1871
|
+
}
|
|
1872
|
+
function text(value) {
|
|
1873
|
+
return {
|
|
1874
|
+
type: "text",
|
|
1875
|
+
value
|
|
1876
|
+
};
|
|
1877
|
+
}
|
|
1878
|
+
function mi(name) {
|
|
1879
|
+
return element("mi", [text(name)]);
|
|
1880
|
+
}
|
|
1881
|
+
function mn(value) {
|
|
1882
|
+
return element("mn", [text(value)]);
|
|
1883
|
+
}
|
|
1884
|
+
function mo(operator) {
|
|
1885
|
+
return element("mo", [text(operator)]);
|
|
1886
|
+
}
|
|
1887
|
+
const FORMULA_PRESETS = [
|
|
1888
|
+
{
|
|
1889
|
+
label: "Fraction: x / 2",
|
|
1890
|
+
mathml: [element("mfrac", [mi("x"), mn("2")])]
|
|
1891
|
+
},
|
|
1892
|
+
{
|
|
1893
|
+
label: "Power: x^2",
|
|
1894
|
+
mathml: [element("msup", [mi("x"), mn("2")])]
|
|
1895
|
+
},
|
|
1896
|
+
{
|
|
1897
|
+
label: "Subscript: x_i",
|
|
1898
|
+
mathml: [element("msub", [mi("x"), mi("i")])]
|
|
1899
|
+
},
|
|
1900
|
+
{
|
|
1901
|
+
label: "Square root: sqrt(x)",
|
|
1902
|
+
mathml: [element("msqrt", [mi("x")])]
|
|
1903
|
+
},
|
|
1904
|
+
{
|
|
1905
|
+
label: "Summation: sum(i=1..n) i",
|
|
1906
|
+
mathml: [element("munderover", [
|
|
1907
|
+
mo("∑"),
|
|
1908
|
+
element("mrow", [
|
|
1909
|
+
mi("i"),
|
|
1910
|
+
mo("="),
|
|
1911
|
+
mn("1")
|
|
1912
|
+
]),
|
|
1913
|
+
mi("n")
|
|
1914
|
+
])]
|
|
1915
|
+
},
|
|
1916
|
+
{
|
|
1917
|
+
label: "Quadratic formula",
|
|
1918
|
+
mathml: [element("mrow", [
|
|
1919
|
+
mi("x"),
|
|
1920
|
+
mo("="),
|
|
1921
|
+
element("mfrac", [element("mrow", [
|
|
1922
|
+
mo("-"),
|
|
1923
|
+
mi("b"),
|
|
1924
|
+
mo("±"),
|
|
1925
|
+
element("msqrt", [element("mrow", [
|
|
1926
|
+
element("msup", [mi("b"), mn("2")]),
|
|
1927
|
+
mo("-"),
|
|
1928
|
+
mn("4"),
|
|
1929
|
+
mi("a"),
|
|
1930
|
+
mi("c")
|
|
1931
|
+
])])
|
|
1932
|
+
]), element("mrow", [mn("2"), mi("a")])])
|
|
1933
|
+
])]
|
|
1934
|
+
}
|
|
1935
|
+
];
|
|
1936
|
+
//#endregion
|
|
1937
|
+
//#region src/tui/screens/shared/formula-picker.tsx
|
|
1938
|
+
const RAW_ENTRY_LABEL = "Raw MathML...";
|
|
1939
|
+
const PICKER_ROWS = [...FORMULA_PRESETS.map((preset) => ({
|
|
1940
|
+
label: preset.label,
|
|
1941
|
+
mathml: preset.mathml
|
|
1942
|
+
})), {
|
|
1943
|
+
label: RAW_ENTRY_LABEL,
|
|
1944
|
+
mathml: void 0
|
|
1945
|
+
}];
|
|
1946
|
+
function FormulaPicker(props) {
|
|
1947
|
+
const [rawInput, setRawInput] = useState(void 0);
|
|
1948
|
+
const { selectedIndex } = useNavigationInput({
|
|
1949
|
+
itemCount: PICKER_ROWS.length,
|
|
1950
|
+
isActive: props.isActive && rawInput === void 0,
|
|
1951
|
+
onBack: props.onCancel,
|
|
1952
|
+
onSelect: (index) => {
|
|
1953
|
+
const row = PICKER_ROWS[index];
|
|
1954
|
+
if (row === void 0) return;
|
|
1955
|
+
if (row.mathml === void 0) {
|
|
1956
|
+
setRawInput("");
|
|
1957
|
+
return;
|
|
1958
|
+
}
|
|
1959
|
+
props.onMathml(row.mathml);
|
|
1960
|
+
}
|
|
1961
|
+
});
|
|
1962
|
+
if (rawInput !== void 0) return /* @__PURE__ */ jsxs(Box, {
|
|
1963
|
+
flexDirection: "column",
|
|
1964
|
+
borderStyle: "round",
|
|
1965
|
+
paddingX: 1,
|
|
1966
|
+
children: [
|
|
1967
|
+
/* @__PURE__ */ jsx(Text, {
|
|
1968
|
+
bold: true,
|
|
1969
|
+
children: "Raw MathML (the children of the <math> root, e.g. <mfrac>...</mfrac>)"
|
|
1970
|
+
}),
|
|
1971
|
+
/* @__PURE__ */ jsx(TextField, {
|
|
1972
|
+
value: rawInput,
|
|
1973
|
+
isFocused: true,
|
|
1974
|
+
onChange: setRawInput,
|
|
1975
|
+
onCancel: () => {
|
|
1976
|
+
setRawInput(void 0);
|
|
1977
|
+
},
|
|
1978
|
+
onSubmit: (value) => {
|
|
1979
|
+
try {
|
|
1980
|
+
const parsed = parseXml(value);
|
|
1981
|
+
props.onMathml(parsed);
|
|
1982
|
+
} catch (error) {
|
|
1983
|
+
props.onInvalidRawMathml(describeError(error));
|
|
1984
|
+
}
|
|
1985
|
+
setRawInput(void 0);
|
|
1986
|
+
}
|
|
1987
|
+
}),
|
|
1988
|
+
/* @__PURE__ */ jsx(Text, {
|
|
1989
|
+
dimColor: true,
|
|
1990
|
+
children: "Enter to insert, Esc to cancel"
|
|
1991
|
+
})
|
|
1992
|
+
]
|
|
1993
|
+
});
|
|
1994
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
1995
|
+
flexDirection: "column",
|
|
1996
|
+
borderStyle: "round",
|
|
1997
|
+
paddingX: 1,
|
|
1998
|
+
children: [
|
|
1999
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2000
|
+
bold: true,
|
|
2001
|
+
children: "Insert formula -- choose a preset or write raw MathML"
|
|
2002
|
+
}),
|
|
2003
|
+
/* @__PURE__ */ jsx(ListView, {
|
|
2004
|
+
items: PICKER_ROWS,
|
|
2005
|
+
selectedIndex,
|
|
2006
|
+
reservedRows: PICKER_ROWS.length + 2,
|
|
2007
|
+
renderItem: (row, isSelected) => /* @__PURE__ */ jsxs(Text, {
|
|
2008
|
+
color: isSelected ? "cyan" : void 0,
|
|
2009
|
+
children: [isSelected ? "> " : " ", row.label]
|
|
2010
|
+
})
|
|
2011
|
+
}),
|
|
2012
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2013
|
+
dimColor: true,
|
|
2014
|
+
children: "Enter to choose, Esc to cancel"
|
|
2015
|
+
})
|
|
2016
|
+
]
|
|
2017
|
+
});
|
|
2018
|
+
}
|
|
2019
|
+
//#endregion
|
|
1671
2020
|
//#region src/tui/screens/shared/text.ts
|
|
1672
2021
|
function truncatePreview(text, maxLength) {
|
|
1673
2022
|
const singleLine = text.replace(/\s+/gu, " ").trim();
|
|
@@ -1682,6 +2031,10 @@ function parseNonNegativeIntField(raw, fallback) {
|
|
|
1682
2031
|
const parsed = Number.parseInt(raw, 10);
|
|
1683
2032
|
return Number.isInteger(parsed) && parsed >= 0 ? parsed : fallback;
|
|
1684
2033
|
}
|
|
2034
|
+
function parseNumberField(raw, fallback) {
|
|
2035
|
+
const parsed = Number.parseFloat(raw);
|
|
2036
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
2037
|
+
}
|
|
1685
2038
|
//#endregion
|
|
1686
2039
|
//#region src/tui/screens/shared/paragraph-family.tsx
|
|
1687
2040
|
function paragraphFamilyDocument(openDocument) {
|
|
@@ -1747,6 +2100,36 @@ function listSummary(list, index) {
|
|
|
1747
2100
|
}
|
|
1748
2101
|
const DEFAULT_TABLE_ROWS$1 = 2;
|
|
1749
2102
|
const DEFAULT_TABLE_COLUMNS$1 = 2;
|
|
2103
|
+
const FORMULA_FRAME_FIELDS = [
|
|
2104
|
+
{
|
|
2105
|
+
key: "xPt",
|
|
2106
|
+
label: "X (pt)",
|
|
2107
|
+
defaultValue: "40"
|
|
2108
|
+
},
|
|
2109
|
+
{
|
|
2110
|
+
key: "yPt",
|
|
2111
|
+
label: "Y (pt)",
|
|
2112
|
+
defaultValue: "40"
|
|
2113
|
+
},
|
|
2114
|
+
{
|
|
2115
|
+
key: "widthPt",
|
|
2116
|
+
label: "Width (pt)",
|
|
2117
|
+
defaultValue: "120"
|
|
2118
|
+
},
|
|
2119
|
+
{
|
|
2120
|
+
key: "heightPt",
|
|
2121
|
+
label: "Height (pt)",
|
|
2122
|
+
defaultValue: "40"
|
|
2123
|
+
}
|
|
2124
|
+
];
|
|
2125
|
+
function readFormulaFrame(values) {
|
|
2126
|
+
return {
|
|
2127
|
+
xPt: parseNumberField(requireFieldValue(values, "xPt"), 0),
|
|
2128
|
+
yPt: parseNumberField(requireFieldValue(values, "yPt"), 0),
|
|
2129
|
+
widthPt: parseNumberField(requireFieldValue(values, "widthPt"), 120),
|
|
2130
|
+
heightPt: parseNumberField(requireFieldValue(values, "heightPt"), 40)
|
|
2131
|
+
};
|
|
2132
|
+
}
|
|
1750
2133
|
function ParagraphFamilyBodyList(props) {
|
|
1751
2134
|
const { adapter } = props;
|
|
1752
2135
|
const state = useAppState();
|
|
@@ -1797,6 +2180,9 @@ function ParagraphFamilyBodyList(props) {
|
|
|
1797
2180
|
const [wizardStartColumn, setWizardStartColumn] = useState(0);
|
|
1798
2181
|
const [wizardRowSpan, setWizardRowSpan] = useState(1);
|
|
1799
2182
|
const wizardOpen = tableWizard !== "closed";
|
|
2183
|
+
const [formulaFlow, setFormulaFlow] = useState("closed");
|
|
2184
|
+
const [pendingFormulaMathml, setPendingFormulaMathml] = useState(void 0);
|
|
2185
|
+
const formulaFlowOpen = formulaFlow !== "closed";
|
|
1800
2186
|
const closeWizard = () => {
|
|
1801
2187
|
setTableWizard("closed");
|
|
1802
2188
|
};
|
|
@@ -1822,7 +2208,23 @@ function ParagraphFamilyBodyList(props) {
|
|
|
1822
2208
|
setWizardDraft(String(DEFAULT_TABLE_ROWS$1));
|
|
1823
2209
|
setTableWizard("rows");
|
|
1824
2210
|
}
|
|
1825
|
-
}, { isActive: !anyOverlayOpen(state) && !wizardOpen });
|
|
2211
|
+
}, { isActive: !anyOverlayOpen(state) && !wizardOpen && !formulaFlowOpen });
|
|
2212
|
+
useInput((input) => {
|
|
2213
|
+
if (input === "L" && adapter.lists !== void 0) {
|
|
2214
|
+
const newIndex = adapter.lists().length;
|
|
2215
|
+
dispatch({ type: "ADD_LIST" });
|
|
2216
|
+
dispatch({
|
|
2217
|
+
type: "PUSH_SCREEN",
|
|
2218
|
+
screen: {
|
|
2219
|
+
kind: "listEditor",
|
|
2220
|
+
blockIndex: newIndex
|
|
2221
|
+
}
|
|
2222
|
+
});
|
|
2223
|
+
}
|
|
2224
|
+
}, { isActive: !anyOverlayOpen(state) && !wizardOpen && !formulaFlowOpen });
|
|
2225
|
+
useInput((input) => {
|
|
2226
|
+
if (input === "m" && adapter.formatLabel === "odt") setFormulaFlow("picking");
|
|
2227
|
+
}, { isActive: !anyOverlayOpen(state) && !wizardOpen && !formulaFlowOpen });
|
|
1826
2228
|
useInput((input, key) => {
|
|
1827
2229
|
if (key.escape) {
|
|
1828
2230
|
closeWizard();
|
|
@@ -1870,7 +2272,7 @@ function ParagraphFamilyBodyList(props) {
|
|
|
1870
2272
|
};
|
|
1871
2273
|
const { selectedIndex } = usePersistedSelection(selectionKeyFor({ kind: "bodyList" }), {
|
|
1872
2274
|
itemCount: selectableRowIndices.length,
|
|
1873
|
-
isActive: !anyOverlayOpen(state) && !wizardOpen,
|
|
2275
|
+
isActive: !anyOverlayOpen(state) && !wizardOpen && !formulaFlowOpen,
|
|
1874
2276
|
onBack: () => {
|
|
1875
2277
|
dispatch({ type: "POP_SCREEN" });
|
|
1876
2278
|
},
|
|
@@ -2037,9 +2439,47 @@ function ParagraphFamilyBodyList(props) {
|
|
|
2037
2439
|
onSubmit: submitWizardMergeColSpan,
|
|
2038
2440
|
onCancel: closeWizard
|
|
2039
2441
|
})] }) : void 0,
|
|
2040
|
-
/* @__PURE__ */ jsx(
|
|
2442
|
+
formulaFlow === "picking" ? /* @__PURE__ */ jsx(FormulaPicker, {
|
|
2443
|
+
isActive: !anyOverlayOpen(state),
|
|
2444
|
+
onCancel: () => {
|
|
2445
|
+
setFormulaFlow("closed");
|
|
2446
|
+
},
|
|
2447
|
+
onMathml: (mathml) => {
|
|
2448
|
+
setPendingFormulaMathml(mathml);
|
|
2449
|
+
setFormulaFlow("frame");
|
|
2450
|
+
},
|
|
2451
|
+
onInvalidRawMathml: (message) => {
|
|
2452
|
+
dispatch({
|
|
2453
|
+
type: "SET_STATUS",
|
|
2454
|
+
severity: "warning",
|
|
2455
|
+
text: `Could not parse MathML: ${message}`
|
|
2456
|
+
});
|
|
2457
|
+
}
|
|
2458
|
+
}) : void 0,
|
|
2459
|
+
formulaFlow === "frame" ? /* @__PURE__ */ jsx(FieldWizard, {
|
|
2460
|
+
fields: FORMULA_FRAME_FIELDS,
|
|
2461
|
+
onCancel: () => {
|
|
2462
|
+
setFormulaFlow("closed");
|
|
2463
|
+
setPendingFormulaMathml(void 0);
|
|
2464
|
+
},
|
|
2465
|
+
onComplete: (values) => {
|
|
2466
|
+
if (pendingFormulaMathml !== void 0) dispatch({
|
|
2467
|
+
type: "INSERT_ODT_FORMULA",
|
|
2468
|
+
mathml: pendingFormulaMathml,
|
|
2469
|
+
frame: readFormulaFrame(values)
|
|
2470
|
+
});
|
|
2471
|
+
setFormulaFlow("closed");
|
|
2472
|
+
setPendingFormulaMathml(void 0);
|
|
2473
|
+
}
|
|
2474
|
+
}) : void 0,
|
|
2475
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
2041
2476
|
dimColor: true,
|
|
2042
|
-
children:
|
|
2477
|
+
children: [
|
|
2478
|
+
"Enter to open, a to append a paragraph, T to append a table",
|
|
2479
|
+
adapter.lists !== void 0 ? ", L to add a list" : "",
|
|
2480
|
+
adapter.formatLabel === "odt" ? ", m to insert a formula" : "",
|
|
2481
|
+
", Esc back"
|
|
2482
|
+
]
|
|
2043
2483
|
})
|
|
2044
2484
|
]
|
|
2045
2485
|
});
|
|
@@ -2059,6 +2499,67 @@ function isValidHexColorInput(input) {
|
|
|
2059
2499
|
}
|
|
2060
2500
|
//#endregion
|
|
2061
2501
|
//#region src/tui/screens/editors/docx/paragraph-detail.tsx
|
|
2502
|
+
const DEFAULT_RUN_SIZE_PT = 12;
|
|
2503
|
+
const IMAGE_FIELDS = [
|
|
2504
|
+
{
|
|
2505
|
+
key: "path",
|
|
2506
|
+
label: "Image file path (.png/.jpg/.jpeg)",
|
|
2507
|
+
defaultValue: ""
|
|
2508
|
+
},
|
|
2509
|
+
{
|
|
2510
|
+
key: "widthPt",
|
|
2511
|
+
label: "Width (pt)",
|
|
2512
|
+
defaultValue: "100"
|
|
2513
|
+
},
|
|
2514
|
+
{
|
|
2515
|
+
key: "heightPt",
|
|
2516
|
+
label: "Height (pt)",
|
|
2517
|
+
defaultValue: "60"
|
|
2518
|
+
},
|
|
2519
|
+
{
|
|
2520
|
+
key: "altText",
|
|
2521
|
+
label: "Alt text, blank for none",
|
|
2522
|
+
defaultValue: ""
|
|
2523
|
+
}
|
|
2524
|
+
];
|
|
2525
|
+
function inferImageFormat$1(path) {
|
|
2526
|
+
const extension = path.slice(path.lastIndexOf(".") + 1).toLowerCase();
|
|
2527
|
+
if (extension === "png") return "png";
|
|
2528
|
+
if (extension === "jpg" || extension === "jpeg") return "jpeg";
|
|
2529
|
+
}
|
|
2530
|
+
async function applyInsertImage(blockIndex, values, dispatch) {
|
|
2531
|
+
const path = requireFieldValue(values, "path");
|
|
2532
|
+
const format = inferImageFormat$1(path);
|
|
2533
|
+
if (format === void 0) {
|
|
2534
|
+
dispatch({
|
|
2535
|
+
type: "SET_STATUS",
|
|
2536
|
+
severity: "warning",
|
|
2537
|
+
text: `${path} is not a .png or .jpg/.jpeg file -- image not inserted`
|
|
2538
|
+
});
|
|
2539
|
+
return;
|
|
2540
|
+
}
|
|
2541
|
+
try {
|
|
2542
|
+
const bytes = new Uint8Array(await readInput(path));
|
|
2543
|
+
const widthPt = parseNumberField(requireFieldValue(values, "widthPt"), 100);
|
|
2544
|
+
const heightPt = parseNumberField(requireFieldValue(values, "heightPt"), 60);
|
|
2545
|
+
const altTextRaw = requireFieldValue(values, "altText").trim();
|
|
2546
|
+
dispatch({
|
|
2547
|
+
type: "INSERT_PARAGRAPH_IMAGE",
|
|
2548
|
+
blockIndex,
|
|
2549
|
+
format,
|
|
2550
|
+
bytes,
|
|
2551
|
+
widthPt,
|
|
2552
|
+
heightPt,
|
|
2553
|
+
altText: altTextRaw.length === 0 ? void 0 : altTextRaw
|
|
2554
|
+
});
|
|
2555
|
+
} catch (error) {
|
|
2556
|
+
dispatch({
|
|
2557
|
+
type: "SET_STATUS",
|
|
2558
|
+
severity: "error",
|
|
2559
|
+
text: `Could not read ${path}: ${describeError(error)}`
|
|
2560
|
+
});
|
|
2561
|
+
}
|
|
2562
|
+
}
|
|
2062
2563
|
function ParagraphRunsView(props) {
|
|
2063
2564
|
if (props.runs.length === 0) return /* @__PURE__ */ jsx(Text, {
|
|
2064
2565
|
dimColor: true,
|
|
@@ -2078,6 +2579,10 @@ function ParagraphDetailScreen() {
|
|
|
2078
2579
|
const dispatch = useAppDispatch();
|
|
2079
2580
|
const [runIndex, setRunIndex] = useState(0);
|
|
2080
2581
|
const [colorInput, setColorInput] = useState(void 0);
|
|
2582
|
+
const [fontFamilyInput, setFontFamilyInput] = useState(void 0);
|
|
2583
|
+
const [fontSizeInput, setFontSizeInput] = useState(void 0);
|
|
2584
|
+
const [imageWizardOpen, setImageWizardOpen] = useState(false);
|
|
2585
|
+
const [formulaPickerOpen, setFormulaPickerOpen] = useState(false);
|
|
2081
2586
|
const screen = currentScreen(state);
|
|
2082
2587
|
const doc = paragraphFamilyDocument(state.openDocument);
|
|
2083
2588
|
const paragraph = screen.kind === "paragraphDetail" && doc !== void 0 ? liveParagraphAt(doc, screen.blockIndex) : void 0;
|
|
@@ -2140,6 +2645,14 @@ function ParagraphDetailScreen() {
|
|
|
2140
2645
|
});
|
|
2141
2646
|
return;
|
|
2142
2647
|
}
|
|
2648
|
+
if (input === "I") {
|
|
2649
|
+
setImageWizardOpen(true);
|
|
2650
|
+
return;
|
|
2651
|
+
}
|
|
2652
|
+
if (input === "m" && doc?.format === "docx") {
|
|
2653
|
+
setFormulaPickerOpen(true);
|
|
2654
|
+
return;
|
|
2655
|
+
}
|
|
2143
2656
|
if (selectedRun === void 0) return;
|
|
2144
2657
|
if (input === "b") {
|
|
2145
2658
|
dispatch({
|
|
@@ -2165,8 +2678,16 @@ function ParagraphDetailScreen() {
|
|
|
2165
2678
|
});
|
|
2166
2679
|
return;
|
|
2167
2680
|
}
|
|
2168
|
-
if (input === "c")
|
|
2169
|
-
|
|
2681
|
+
if (input === "c") {
|
|
2682
|
+
setColorInput(selectedRun.color === void 0 ? "" : layoutColorToHex(selectedRun.color).slice(1));
|
|
2683
|
+
return;
|
|
2684
|
+
}
|
|
2685
|
+
if (input === "f") {
|
|
2686
|
+
setFontFamilyInput(selectedRun.fontFamily ?? "");
|
|
2687
|
+
return;
|
|
2688
|
+
}
|
|
2689
|
+
if (input === "s") setFontSizeInput(selectedRun.sizePt === void 0 ? "" : String(selectedRun.sizePt));
|
|
2690
|
+
}, { isActive: !anyOverlayOpen(state) && colorInput === void 0 && fontFamilyInput === void 0 && fontSizeInput === void 0 && !imageWizardOpen && !formulaPickerOpen });
|
|
2170
2691
|
if (screen.kind !== "paragraphDetail") return /* @__PURE__ */ jsx(Text, {
|
|
2171
2692
|
color: "red",
|
|
2172
2693
|
children: "ParagraphDetailScreen rendered outside a paragraphDetail screen."
|
|
@@ -2224,9 +2745,99 @@ function ParagraphDetailScreen() {
|
|
|
2224
2745
|
setColorInput(void 0);
|
|
2225
2746
|
}
|
|
2226
2747
|
})] }),
|
|
2227
|
-
/* @__PURE__ */ jsx(Text, {
|
|
2748
|
+
fontFamilyInput === void 0 ? void 0 : /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Text, {
|
|
2749
|
+
color: "cyan",
|
|
2750
|
+
children: "Font family: "
|
|
2751
|
+
}), /* @__PURE__ */ jsx(TextField, {
|
|
2752
|
+
value: fontFamilyInput,
|
|
2753
|
+
isFocused: true,
|
|
2754
|
+
placeholder: "e.g. Calibri",
|
|
2755
|
+
onChange: setFontFamilyInput,
|
|
2756
|
+
onSubmit: (value) => {
|
|
2757
|
+
const trimmed = value.trim();
|
|
2758
|
+
if (trimmed.length === 0) dispatch({
|
|
2759
|
+
type: "SET_STATUS",
|
|
2760
|
+
severity: "warning",
|
|
2761
|
+
text: "A font family name cannot be blank"
|
|
2762
|
+
});
|
|
2763
|
+
else dispatch({
|
|
2764
|
+
type: "SET_RUN_FONT_FAMILY",
|
|
2765
|
+
blockIndex,
|
|
2766
|
+
runIndex: clampedRunIndex,
|
|
2767
|
+
fontFamily: trimmed
|
|
2768
|
+
});
|
|
2769
|
+
setFontFamilyInput(void 0);
|
|
2770
|
+
},
|
|
2771
|
+
onCancel: () => {
|
|
2772
|
+
setFontFamilyInput(void 0);
|
|
2773
|
+
}
|
|
2774
|
+
})] }),
|
|
2775
|
+
fontSizeInput === void 0 ? void 0 : /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Text, {
|
|
2776
|
+
color: "cyan",
|
|
2777
|
+
children: "Font size (pt): "
|
|
2778
|
+
}), /* @__PURE__ */ jsx(TextField, {
|
|
2779
|
+
value: fontSizeInput,
|
|
2780
|
+
isFocused: true,
|
|
2781
|
+
placeholder: "e.g. 12",
|
|
2782
|
+
onChange: setFontSizeInput,
|
|
2783
|
+
onSubmit: (value) => {
|
|
2784
|
+
const sizePt = parseNumberField(value, selectedRun?.sizePt ?? DEFAULT_RUN_SIZE_PT);
|
|
2785
|
+
if (sizePt <= 0) dispatch({
|
|
2786
|
+
type: "SET_STATUS",
|
|
2787
|
+
severity: "warning",
|
|
2788
|
+
text: `"${value}" is not a positive font size`
|
|
2789
|
+
});
|
|
2790
|
+
else dispatch({
|
|
2791
|
+
type: "SET_RUN_FONT_SIZE",
|
|
2792
|
+
blockIndex,
|
|
2793
|
+
runIndex: clampedRunIndex,
|
|
2794
|
+
sizePt
|
|
2795
|
+
});
|
|
2796
|
+
setFontSizeInput(void 0);
|
|
2797
|
+
},
|
|
2798
|
+
onCancel: () => {
|
|
2799
|
+
setFontSizeInput(void 0);
|
|
2800
|
+
}
|
|
2801
|
+
})] }),
|
|
2802
|
+
imageWizardOpen ? /* @__PURE__ */ jsx(FieldWizard, {
|
|
2803
|
+
fields: IMAGE_FIELDS,
|
|
2804
|
+
onCancel: () => {
|
|
2805
|
+
setImageWizardOpen(false);
|
|
2806
|
+
},
|
|
2807
|
+
onComplete: (values) => {
|
|
2808
|
+
applyInsertImage(blockIndex, values, dispatch).then(() => {
|
|
2809
|
+
setImageWizardOpen(false);
|
|
2810
|
+
});
|
|
2811
|
+
}
|
|
2812
|
+
}) : void 0,
|
|
2813
|
+
formulaPickerOpen ? /* @__PURE__ */ jsx(FormulaPicker, {
|
|
2814
|
+
isActive: !anyOverlayOpen(state),
|
|
2815
|
+
onCancel: () => {
|
|
2816
|
+
setFormulaPickerOpen(false);
|
|
2817
|
+
},
|
|
2818
|
+
onMathml: (mathml) => {
|
|
2819
|
+
dispatch({
|
|
2820
|
+
type: "INSERT_DOCX_FORMULA",
|
|
2821
|
+
blockIndex,
|
|
2822
|
+
mathml
|
|
2823
|
+
});
|
|
2824
|
+
setFormulaPickerOpen(false);
|
|
2825
|
+
},
|
|
2826
|
+
onInvalidRawMathml: (message) => {
|
|
2827
|
+
dispatch({
|
|
2828
|
+
type: "SET_STATUS",
|
|
2829
|
+
severity: "warning",
|
|
2830
|
+
text: `Could not parse MathML: ${message}`
|
|
2831
|
+
});
|
|
2832
|
+
}
|
|
2833
|
+
}) : void 0,
|
|
2834
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
2228
2835
|
dimColor: true,
|
|
2229
|
-
children:
|
|
2836
|
+
children: [
|
|
2837
|
+
"<- / -> move, Enter edit text, b/i/u toggle, c colour, f font, s size, a append run, I image",
|
|
2838
|
+
doc.format === "docx" ? ", m formula" : "",
|
|
2839
|
+
", Esc back"
|
|
2840
|
+
]
|
|
2230
2841
|
})
|
|
2231
2842
|
]
|
|
2232
2843
|
});
|
|
@@ -3292,6 +3903,64 @@ function OdbTableRowsScreen() {
|
|
|
3292
3903
|
});
|
|
3293
3904
|
}
|
|
3294
3905
|
//#endregion
|
|
3906
|
+
//#region src/tui/screens/shared/vector-fields.ts
|
|
3907
|
+
function parseColorField(raw) {
|
|
3908
|
+
const trimmed = raw.trim();
|
|
3909
|
+
if (trimmed.length === 0) return;
|
|
3910
|
+
const [r, g, b] = trimmed.split(/\s+/).map((part) => Number.parseFloat(part));
|
|
3911
|
+
if (r === void 0 || g === void 0 || b === void 0 || ![
|
|
3912
|
+
r,
|
|
3913
|
+
g,
|
|
3914
|
+
b
|
|
3915
|
+
].every((value) => Number.isFinite(value))) return;
|
|
3916
|
+
return {
|
|
3917
|
+
r,
|
|
3918
|
+
g,
|
|
3919
|
+
b
|
|
3920
|
+
};
|
|
3921
|
+
}
|
|
3922
|
+
function parseStrokeField(raw) {
|
|
3923
|
+
const trimmed = raw.trim();
|
|
3924
|
+
if (trimmed.length === 0) return;
|
|
3925
|
+
const [r, g, b, widthPt] = trimmed.split(/\s+/).map((part) => Number.parseFloat(part));
|
|
3926
|
+
if (r === void 0 || g === void 0 || b === void 0 || widthPt === void 0 || ![
|
|
3927
|
+
r,
|
|
3928
|
+
g,
|
|
3929
|
+
b,
|
|
3930
|
+
widthPt
|
|
3931
|
+
].every((value) => Number.isFinite(value))) return;
|
|
3932
|
+
return {
|
|
3933
|
+
color: {
|
|
3934
|
+
r,
|
|
3935
|
+
g,
|
|
3936
|
+
b
|
|
3937
|
+
},
|
|
3938
|
+
widthPt
|
|
3939
|
+
};
|
|
3940
|
+
}
|
|
3941
|
+
function defaultTriangleSubpaths(widthPt, heightPt) {
|
|
3942
|
+
return [{
|
|
3943
|
+
start: {
|
|
3944
|
+
xPt: 0,
|
|
3945
|
+
yPt: heightPt
|
|
3946
|
+
},
|
|
3947
|
+
segments: [{
|
|
3948
|
+
kind: "line",
|
|
3949
|
+
to: {
|
|
3950
|
+
xPt: widthPt / 2,
|
|
3951
|
+
yPt: 0
|
|
3952
|
+
}
|
|
3953
|
+
}, {
|
|
3954
|
+
kind: "line",
|
|
3955
|
+
to: {
|
|
3956
|
+
xPt: widthPt,
|
|
3957
|
+
yPt: heightPt
|
|
3958
|
+
}
|
|
3959
|
+
}],
|
|
3960
|
+
closed: true
|
|
3961
|
+
}];
|
|
3962
|
+
}
|
|
3963
|
+
//#endregion
|
|
3295
3964
|
//#region src/tui/screens/editors/odg/shared.ts
|
|
3296
3965
|
function requireOdgDocument(state) {
|
|
3297
3966
|
const doc = state.openDocument;
|
|
@@ -3350,85 +4019,20 @@ function formatFrame(box) {
|
|
|
3350
4019
|
return `${formatPt(box.xPt)},${formatPt(box.yPt)} ${formatPt(box.widthPt)}x${formatPt(box.heightPt)}pt`;
|
|
3351
4020
|
}
|
|
3352
4021
|
function formatPoint$1(point) {
|
|
3353
|
-
return `${formatPt(point.xPt)},${formatPt(point.yPt)}`;
|
|
3354
|
-
}
|
|
3355
|
-
function formatColor$1(color) {
|
|
3356
|
-
return `rgb(${color.r.toFixed(2)}, ${color.g.toFixed(2)}, ${color.b.toFixed(2)})`;
|
|
3357
|
-
}
|
|
3358
|
-
function describeVectorGeometry(vector) {
|
|
3359
|
-
if (vector.kind === "line") return `${formatPoint$1(vector.from)} -> ${formatPoint$1(vector.to)}`;
|
|
3360
|
-
return formatFrame(vector.frame);
|
|
3361
|
-
}
|
|
3362
|
-
function describeFillStroke(vector) {
|
|
3363
|
-
const parts = [];
|
|
3364
|
-
if (vector.kind !== "line" && vector.fill !== void 0) parts.push(`fill ${formatColor$1(vector.fill)}`);
|
|
3365
|
-
if (vector.stroke !== void 0) parts.push(`stroke ${formatColor$1(vector.stroke.color)} ${formatPt(vector.stroke.widthPt)}pt`);
|
|
3366
|
-
return parts.length === 0 ? "no fill or stroke" : parts.join(", ");
|
|
3367
|
-
}
|
|
3368
|
-
function parseNumberField(raw, fallback) {
|
|
3369
|
-
const parsed = Number.parseFloat(raw);
|
|
3370
|
-
return Number.isFinite(parsed) ? parsed : fallback;
|
|
3371
|
-
}
|
|
3372
|
-
function parseColorField(raw) {
|
|
3373
|
-
const trimmed = raw.trim();
|
|
3374
|
-
if (trimmed.length === 0) return;
|
|
3375
|
-
const [r, g, b] = trimmed.split(/\s+/).map((part) => Number.parseFloat(part));
|
|
3376
|
-
if (r === void 0 || g === void 0 || b === void 0 || ![
|
|
3377
|
-
r,
|
|
3378
|
-
g,
|
|
3379
|
-
b
|
|
3380
|
-
].every((value) => Number.isFinite(value))) return;
|
|
3381
|
-
return {
|
|
3382
|
-
r,
|
|
3383
|
-
g,
|
|
3384
|
-
b
|
|
3385
|
-
};
|
|
3386
|
-
}
|
|
3387
|
-
function parseStrokeField(raw) {
|
|
3388
|
-
const trimmed = raw.trim();
|
|
3389
|
-
if (trimmed.length === 0) return;
|
|
3390
|
-
const [r, g, b, widthPt] = trimmed.split(/\s+/).map((part) => Number.parseFloat(part));
|
|
3391
|
-
if (r === void 0 || g === void 0 || b === void 0 || widthPt === void 0 || ![
|
|
3392
|
-
r,
|
|
3393
|
-
g,
|
|
3394
|
-
b,
|
|
3395
|
-
widthPt
|
|
3396
|
-
].every((value) => Number.isFinite(value))) return;
|
|
3397
|
-
return {
|
|
3398
|
-
color: {
|
|
3399
|
-
r,
|
|
3400
|
-
g,
|
|
3401
|
-
b
|
|
3402
|
-
},
|
|
3403
|
-
widthPt
|
|
3404
|
-
};
|
|
4022
|
+
return `${formatPt(point.xPt)},${formatPt(point.yPt)}`;
|
|
3405
4023
|
}
|
|
3406
|
-
function
|
|
3407
|
-
return
|
|
3408
|
-
start: {
|
|
3409
|
-
xPt: 0,
|
|
3410
|
-
yPt: heightPt
|
|
3411
|
-
},
|
|
3412
|
-
segments: [{
|
|
3413
|
-
kind: "line",
|
|
3414
|
-
to: {
|
|
3415
|
-
xPt: widthPt / 2,
|
|
3416
|
-
yPt: 0
|
|
3417
|
-
}
|
|
3418
|
-
}, {
|
|
3419
|
-
kind: "line",
|
|
3420
|
-
to: {
|
|
3421
|
-
xPt: widthPt,
|
|
3422
|
-
yPt: heightPt
|
|
3423
|
-
}
|
|
3424
|
-
}],
|
|
3425
|
-
closed: true
|
|
3426
|
-
}];
|
|
4024
|
+
function formatColor$1(color) {
|
|
4025
|
+
return `rgb(${color.r.toFixed(2)}, ${color.g.toFixed(2)}, ${color.b.toFixed(2)})`;
|
|
3427
4026
|
}
|
|
3428
|
-
function
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
4027
|
+
function describeVectorGeometry(vector) {
|
|
4028
|
+
if (vector.kind === "line") return `${formatPoint$1(vector.from)} -> ${formatPoint$1(vector.to)}`;
|
|
4029
|
+
return formatFrame(vector.frame);
|
|
4030
|
+
}
|
|
4031
|
+
function describeFillStroke(vector) {
|
|
4032
|
+
const parts = [];
|
|
4033
|
+
if (vector.kind !== "line" && vector.fill !== void 0) parts.push(`fill ${formatColor$1(vector.fill)}`);
|
|
4034
|
+
if (vector.stroke !== void 0) parts.push(`stroke ${formatColor$1(vector.stroke.color)} ${formatPt(vector.stroke.widthPt)}pt`);
|
|
4035
|
+
return parts.length === 0 ? "no fill or stroke" : parts.join(", ");
|
|
3432
4036
|
}
|
|
3433
4037
|
//#endregion
|
|
3434
4038
|
//#region src/tui/screens/editors/odg/page-list.tsx
|
|
@@ -3633,7 +4237,7 @@ async function applyAddKind(kind, pageIndex, doc, values, dispatch) {
|
|
|
3633
4237
|
case "rect":
|
|
3634
4238
|
dispatch({
|
|
3635
4239
|
type: "ADD_RECT",
|
|
3636
|
-
pageIndex,
|
|
4240
|
+
containerIndex: pageIndex,
|
|
3637
4241
|
init: {
|
|
3638
4242
|
frame: readFrame(values),
|
|
3639
4243
|
fill: parseColorField(requireFieldValue(values, "fill")),
|
|
@@ -3645,7 +4249,7 @@ async function applyAddKind(kind, pageIndex, doc, values, dispatch) {
|
|
|
3645
4249
|
case "ellipse":
|
|
3646
4250
|
dispatch({
|
|
3647
4251
|
type: "ADD_ELLIPSE",
|
|
3648
|
-
pageIndex,
|
|
4252
|
+
containerIndex: pageIndex,
|
|
3649
4253
|
init: {
|
|
3650
4254
|
frame: readFrame(values),
|
|
3651
4255
|
fill: parseColorField(requireFieldValue(values, "fill")),
|
|
@@ -3657,7 +4261,7 @@ async function applyAddKind(kind, pageIndex, doc, values, dispatch) {
|
|
|
3657
4261
|
case "line":
|
|
3658
4262
|
dispatch({
|
|
3659
4263
|
type: "ADD_LINE",
|
|
3660
|
-
pageIndex,
|
|
4264
|
+
containerIndex: pageIndex,
|
|
3661
4265
|
init: {
|
|
3662
4266
|
from: {
|
|
3663
4267
|
xPt: parseNumberField(requireFieldValue(values, "fromXPt"), 0),
|
|
@@ -3683,7 +4287,7 @@ async function applyAddKind(kind, pageIndex, doc, values, dispatch) {
|
|
|
3683
4287
|
const frame = readFrame(values);
|
|
3684
4288
|
dispatch({
|
|
3685
4289
|
type: "ADD_PATH",
|
|
3686
|
-
pageIndex,
|
|
4290
|
+
containerIndex: pageIndex,
|
|
3687
4291
|
init: {
|
|
3688
4292
|
frame,
|
|
3689
4293
|
subpaths: defaultTriangleSubpaths(frame.widthPt, frame.heightPt),
|
|
@@ -3736,56 +4340,6 @@ async function applyAddKind(kind, pageIndex, doc, values, dispatch) {
|
|
|
3736
4340
|
}
|
|
3737
4341
|
}
|
|
3738
4342
|
}
|
|
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
4343
|
function AddItemFlow(props) {
|
|
3790
4344
|
const dispatch = useAppDispatch();
|
|
3791
4345
|
const [kind, setKind] = useState(void 0);
|
|
@@ -4665,17 +5219,149 @@ function summarizeSlideTables(doc, slideIndex) {
|
|
|
4665
5219
|
}
|
|
4666
5220
|
//#endregion
|
|
4667
5221
|
//#region src/tui/screens/editors/pptx/slide-detail.tsx
|
|
4668
|
-
const IMAGE_EXTENSION_TO_FORMAT = {
|
|
5222
|
+
const IMAGE_EXTENSION_TO_FORMAT$1 = {
|
|
4669
5223
|
png: "png",
|
|
4670
5224
|
jpg: "jpeg",
|
|
4671
5225
|
jpeg: "jpeg"
|
|
4672
5226
|
};
|
|
4673
5227
|
const DEFAULT_TABLE_ROWS = 2;
|
|
4674
5228
|
const DEFAULT_TABLE_COLUMNS = 2;
|
|
5229
|
+
const VECTOR_GEOMETRY_FIELDS = [
|
|
5230
|
+
{
|
|
5231
|
+
key: "xPt",
|
|
5232
|
+
label: "X (pt)",
|
|
5233
|
+
defaultValue: "40"
|
|
5234
|
+
},
|
|
5235
|
+
{
|
|
5236
|
+
key: "yPt",
|
|
5237
|
+
label: "Y (pt)",
|
|
5238
|
+
defaultValue: "40"
|
|
5239
|
+
},
|
|
5240
|
+
{
|
|
5241
|
+
key: "widthPt",
|
|
5242
|
+
label: "Width (pt)",
|
|
5243
|
+
defaultValue: "160"
|
|
5244
|
+
},
|
|
5245
|
+
{
|
|
5246
|
+
key: "heightPt",
|
|
5247
|
+
label: "Height (pt)",
|
|
5248
|
+
defaultValue: "100"
|
|
5249
|
+
}
|
|
5250
|
+
];
|
|
5251
|
+
const VECTOR_FILL_FIELD = {
|
|
5252
|
+
key: "fill",
|
|
5253
|
+
label: "Fill \"r g b\" (0-1 each), blank for none",
|
|
5254
|
+
defaultValue: "0.8 0.8 0.8"
|
|
5255
|
+
};
|
|
5256
|
+
const VECTOR_STROKE_FIELD = {
|
|
5257
|
+
key: "stroke",
|
|
5258
|
+
label: "Stroke \"r g b widthPt\" (0-1 colour, pt width), blank for none",
|
|
5259
|
+
defaultValue: "0 0 0 1"
|
|
5260
|
+
};
|
|
5261
|
+
const VECTOR_LINE_FIELDS = [
|
|
5262
|
+
{
|
|
5263
|
+
key: "fromXPt",
|
|
5264
|
+
label: "From X (pt)",
|
|
5265
|
+
defaultValue: "40"
|
|
5266
|
+
},
|
|
5267
|
+
{
|
|
5268
|
+
key: "fromYPt",
|
|
5269
|
+
label: "From Y (pt)",
|
|
5270
|
+
defaultValue: "40"
|
|
5271
|
+
},
|
|
5272
|
+
{
|
|
5273
|
+
key: "toXPt",
|
|
5274
|
+
label: "To X (pt)",
|
|
5275
|
+
defaultValue: "200"
|
|
5276
|
+
},
|
|
5277
|
+
{
|
|
5278
|
+
key: "toYPt",
|
|
5279
|
+
label: "To Y (pt)",
|
|
5280
|
+
defaultValue: "40"
|
|
5281
|
+
},
|
|
5282
|
+
VECTOR_STROKE_FIELD
|
|
5283
|
+
];
|
|
5284
|
+
function fieldsForVectorKind(kind) {
|
|
5285
|
+
switch (kind) {
|
|
5286
|
+
case "rect":
|
|
5287
|
+
case "ellipse":
|
|
5288
|
+
case "path": return [
|
|
5289
|
+
...VECTOR_GEOMETRY_FIELDS,
|
|
5290
|
+
VECTOR_FILL_FIELD,
|
|
5291
|
+
VECTOR_STROKE_FIELD
|
|
5292
|
+
];
|
|
5293
|
+
case "line": return VECTOR_LINE_FIELDS;
|
|
5294
|
+
}
|
|
5295
|
+
}
|
|
5296
|
+
function readVectorFrame(values) {
|
|
5297
|
+
return {
|
|
5298
|
+
xPt: parseNumberField(requireFieldValue(values, "xPt"), 0),
|
|
5299
|
+
yPt: parseNumberField(requireFieldValue(values, "yPt"), 0),
|
|
5300
|
+
widthPt: parseNumberField(requireFieldValue(values, "widthPt"), 160),
|
|
5301
|
+
heightPt: parseNumberField(requireFieldValue(values, "heightPt"), 100)
|
|
5302
|
+
};
|
|
5303
|
+
}
|
|
5304
|
+
function buildVectorAction(kind, slideIndex, values) {
|
|
5305
|
+
switch (kind) {
|
|
5306
|
+
case "rect": return {
|
|
5307
|
+
type: "ADD_RECT",
|
|
5308
|
+
containerIndex: slideIndex,
|
|
5309
|
+
init: {
|
|
5310
|
+
frame: readVectorFrame(values),
|
|
5311
|
+
fill: parseColorField(requireFieldValue(values, "fill")),
|
|
5312
|
+
stroke: parseStrokeField(requireFieldValue(values, "stroke"))
|
|
5313
|
+
}
|
|
5314
|
+
};
|
|
5315
|
+
case "ellipse": return {
|
|
5316
|
+
type: "ADD_ELLIPSE",
|
|
5317
|
+
containerIndex: slideIndex,
|
|
5318
|
+
init: {
|
|
5319
|
+
frame: readVectorFrame(values),
|
|
5320
|
+
fill: parseColorField(requireFieldValue(values, "fill")),
|
|
5321
|
+
stroke: parseStrokeField(requireFieldValue(values, "stroke"))
|
|
5322
|
+
}
|
|
5323
|
+
};
|
|
5324
|
+
case "line": return {
|
|
5325
|
+
type: "ADD_LINE",
|
|
5326
|
+
containerIndex: slideIndex,
|
|
5327
|
+
init: {
|
|
5328
|
+
from: {
|
|
5329
|
+
xPt: parseNumberField(requireFieldValue(values, "fromXPt"), 0),
|
|
5330
|
+
yPt: parseNumberField(requireFieldValue(values, "fromYPt"), 0)
|
|
5331
|
+
},
|
|
5332
|
+
to: {
|
|
5333
|
+
xPt: parseNumberField(requireFieldValue(values, "toXPt"), 100),
|
|
5334
|
+
yPt: parseNumberField(requireFieldValue(values, "toYPt"), 0)
|
|
5335
|
+
},
|
|
5336
|
+
stroke: parseStrokeField(requireFieldValue(values, "stroke")) ?? {
|
|
5337
|
+
color: {
|
|
5338
|
+
r: 0,
|
|
5339
|
+
g: 0,
|
|
5340
|
+
b: 0
|
|
5341
|
+
},
|
|
5342
|
+
widthPt: 1
|
|
5343
|
+
}
|
|
5344
|
+
}
|
|
5345
|
+
};
|
|
5346
|
+
case "path": {
|
|
5347
|
+
const frame = readVectorFrame(values);
|
|
5348
|
+
return {
|
|
5349
|
+
type: "ADD_PATH",
|
|
5350
|
+
containerIndex: slideIndex,
|
|
5351
|
+
init: {
|
|
5352
|
+
frame,
|
|
5353
|
+
subpaths: defaultTriangleSubpaths(frame.widthPt, frame.heightPt),
|
|
5354
|
+
fill: parseColorField(requireFieldValue(values, "fill")),
|
|
5355
|
+
stroke: parseStrokeField(requireFieldValue(values, "stroke"))
|
|
5356
|
+
}
|
|
5357
|
+
};
|
|
5358
|
+
}
|
|
5359
|
+
}
|
|
5360
|
+
}
|
|
4675
5361
|
function imageFormatFromPath(path) {
|
|
4676
5362
|
const dotIndex = path.lastIndexOf(".");
|
|
4677
5363
|
if (dotIndex < 0) return;
|
|
4678
|
-
return IMAGE_EXTENSION_TO_FORMAT[path.slice(dotIndex + 1).toLowerCase()];
|
|
5364
|
+
return IMAGE_EXTENSION_TO_FORMAT$1[path.slice(dotIndex + 1).toLowerCase()];
|
|
4679
5365
|
}
|
|
4680
5366
|
async function readImageForShape(path) {
|
|
4681
5367
|
const format = imageFormatFromPath(path);
|
|
@@ -4716,6 +5402,7 @@ function SlideDetailScreen(props) {
|
|
|
4716
5402
|
const [draft, setDraft] = useState("");
|
|
4717
5403
|
const [imageError, setImageError] = useState(void 0);
|
|
4718
5404
|
const [tableRows, setTableRows] = useState(DEFAULT_TABLE_ROWS);
|
|
5405
|
+
const [vectorKind, setVectorKind] = useState(void 0);
|
|
4719
5406
|
const formIsOpen = addMode !== "closed";
|
|
4720
5407
|
const { selectedIndex } = useNavigationInput({
|
|
4721
5408
|
itemCount: selectableRowIndices.length,
|
|
@@ -4776,6 +5463,27 @@ function SlideDetailScreen(props) {
|
|
|
4776
5463
|
if (input === "b") {
|
|
4777
5464
|
setDraft(String(DEFAULT_TABLE_ROWS));
|
|
4778
5465
|
setAddMode("tableRows");
|
|
5466
|
+
return;
|
|
5467
|
+
}
|
|
5468
|
+
if (doc.format !== "odp") return;
|
|
5469
|
+
if (input === "r") {
|
|
5470
|
+
setVectorKind("rect");
|
|
5471
|
+
setAddMode("vector");
|
|
5472
|
+
return;
|
|
5473
|
+
}
|
|
5474
|
+
if (input === "e") {
|
|
5475
|
+
setVectorKind("ellipse");
|
|
5476
|
+
setAddMode("vector");
|
|
5477
|
+
return;
|
|
5478
|
+
}
|
|
5479
|
+
if (input === "n") {
|
|
5480
|
+
setVectorKind("line");
|
|
5481
|
+
setAddMode("vector");
|
|
5482
|
+
return;
|
|
5483
|
+
}
|
|
5484
|
+
if (input === "p") {
|
|
5485
|
+
setVectorKind("path");
|
|
5486
|
+
setAddMode("vector");
|
|
4779
5487
|
}
|
|
4780
5488
|
}, { isActive: !overlayOpen && addMode === "chooseKind" });
|
|
4781
5489
|
useInput((input) => {
|
|
@@ -4889,9 +5597,25 @@ function SlideDetailScreen(props) {
|
|
|
4889
5597
|
});
|
|
4890
5598
|
}
|
|
4891
5599
|
}),
|
|
4892
|
-
addMode === "chooseKind" ? /* @__PURE__ */
|
|
5600
|
+
addMode === "chooseKind" ? /* @__PURE__ */ jsxs(Text, {
|
|
4893
5601
|
color: "cyan",
|
|
4894
|
-
children:
|
|
5602
|
+
children: [
|
|
5603
|
+
"Add shape: t textbox, i image, b table",
|
|
5604
|
+
doc.format === "odp" ? ", r rect, e ellipse, n line, p path" : "",
|
|
5605
|
+
", Esc cancel"
|
|
5606
|
+
]
|
|
5607
|
+
}) : void 0,
|
|
5608
|
+
addMode === "vector" && vectorKind !== void 0 ? /* @__PURE__ */ jsx(FieldWizard, {
|
|
5609
|
+
fields: fieldsForVectorKind(vectorKind),
|
|
5610
|
+
onCancel: () => {
|
|
5611
|
+
setAddMode("closed");
|
|
5612
|
+
setVectorKind(void 0);
|
|
5613
|
+
},
|
|
5614
|
+
onComplete: (values) => {
|
|
5615
|
+
dispatch(buildVectorAction(vectorKind, slideIndex, values));
|
|
5616
|
+
setAddMode("closed");
|
|
5617
|
+
setVectorKind(void 0);
|
|
5618
|
+
}
|
|
4895
5619
|
}) : void 0,
|
|
4896
5620
|
addMode === "textbox" ? /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Text, {
|
|
4897
5621
|
color: "cyan",
|
|
@@ -5714,8 +6438,90 @@ const RESERVED_LETTERS = /* @__PURE__ */ new Set([
|
|
|
5714
6438
|
"l",
|
|
5715
6439
|
"p",
|
|
5716
6440
|
"t",
|
|
5717
|
-
"m"
|
|
6441
|
+
"m",
|
|
6442
|
+
"f",
|
|
6443
|
+
"i"
|
|
5718
6444
|
]);
|
|
6445
|
+
const IMAGE_EXTENSION_TO_FORMAT = {
|
|
6446
|
+
png: "png",
|
|
6447
|
+
jpg: "jpeg",
|
|
6448
|
+
jpeg: "jpeg"
|
|
6449
|
+
};
|
|
6450
|
+
function inferSheetImageFormat(path) {
|
|
6451
|
+
const extension = path.slice(path.lastIndexOf(".") + 1).toLowerCase();
|
|
6452
|
+
return IMAGE_EXTENSION_TO_FORMAT[extension];
|
|
6453
|
+
}
|
|
6454
|
+
const SHEET_IMAGE_FIELDS = [
|
|
6455
|
+
{
|
|
6456
|
+
key: "path",
|
|
6457
|
+
label: "Image file path (.png/.jpg/.jpeg)",
|
|
6458
|
+
defaultValue: ""
|
|
6459
|
+
},
|
|
6460
|
+
{
|
|
6461
|
+
key: "widthPt",
|
|
6462
|
+
label: "Width (pt)",
|
|
6463
|
+
defaultValue: "100"
|
|
6464
|
+
},
|
|
6465
|
+
{
|
|
6466
|
+
key: "heightPt",
|
|
6467
|
+
label: "Height (pt)",
|
|
6468
|
+
defaultValue: "60"
|
|
6469
|
+
},
|
|
6470
|
+
{
|
|
6471
|
+
key: "offsetXPt",
|
|
6472
|
+
label: "Offset X from anchor cell (pt)",
|
|
6473
|
+
defaultValue: "0"
|
|
6474
|
+
},
|
|
6475
|
+
{
|
|
6476
|
+
key: "offsetYPt",
|
|
6477
|
+
label: "Offset Y from anchor cell (pt)",
|
|
6478
|
+
defaultValue: "0"
|
|
6479
|
+
},
|
|
6480
|
+
{
|
|
6481
|
+
key: "altText",
|
|
6482
|
+
label: "Alt text, blank for none",
|
|
6483
|
+
defaultValue: ""
|
|
6484
|
+
}
|
|
6485
|
+
];
|
|
6486
|
+
async function applyAddSheetImage(sheetIndex, anchorRow, anchorColumn, values, dispatch) {
|
|
6487
|
+
const path = requireFieldValue(values, "path");
|
|
6488
|
+
const format = inferSheetImageFormat(path);
|
|
6489
|
+
if (format === void 0) {
|
|
6490
|
+
dispatch({
|
|
6491
|
+
type: "SET_STATUS",
|
|
6492
|
+
severity: "warning",
|
|
6493
|
+
text: `${path} is not a .png or .jpg/.jpeg file -- image not added`
|
|
6494
|
+
});
|
|
6495
|
+
return;
|
|
6496
|
+
}
|
|
6497
|
+
try {
|
|
6498
|
+
const bytes = new Uint8Array(await readInput(path));
|
|
6499
|
+
const widthPt = parseNumberField(requireFieldValue(values, "widthPt"), 100);
|
|
6500
|
+
const heightPt = parseNumberField(requireFieldValue(values, "heightPt"), 60);
|
|
6501
|
+
const offsetXPt = parseNumberField(requireFieldValue(values, "offsetXPt"), 0);
|
|
6502
|
+
const offsetYPt = parseNumberField(requireFieldValue(values, "offsetYPt"), 0);
|
|
6503
|
+
const altTextRaw = requireFieldValue(values, "altText").trim();
|
|
6504
|
+
dispatch({
|
|
6505
|
+
type: "ADD_SHEET_IMAGE",
|
|
6506
|
+
sheetIndex,
|
|
6507
|
+
anchorRow,
|
|
6508
|
+
anchorColumn,
|
|
6509
|
+
offsetXPt,
|
|
6510
|
+
offsetYPt,
|
|
6511
|
+
format,
|
|
6512
|
+
bytes,
|
|
6513
|
+
widthPt,
|
|
6514
|
+
heightPt,
|
|
6515
|
+
altText: altTextRaw.length === 0 ? void 0 : altTextRaw
|
|
6516
|
+
});
|
|
6517
|
+
} catch (error) {
|
|
6518
|
+
dispatch({
|
|
6519
|
+
type: "SET_STATUS",
|
|
6520
|
+
severity: "error",
|
|
6521
|
+
text: `Could not read ${path}: ${describeError(error)}`
|
|
6522
|
+
});
|
|
6523
|
+
}
|
|
6524
|
+
}
|
|
5719
6525
|
function windowStart(cursor, total, viewport) {
|
|
5720
6526
|
const maxStart = Math.max(0, total - viewport);
|
|
5721
6527
|
return Math.min(Math.max(cursor - Math.floor(viewport / 2), 0), maxStart);
|
|
@@ -5738,6 +6544,9 @@ function OdsSpreadsheetGridScreen() {
|
|
|
5738
6544
|
const [viewMode, setViewMode] = useState("grid");
|
|
5739
6545
|
const [editSession, setEditSession] = useState(void 0);
|
|
5740
6546
|
const [mergeAnchor, setMergeAnchor] = useState(void 0);
|
|
6547
|
+
const [formulaEditing, setFormulaEditing] = useState(false);
|
|
6548
|
+
const [formulaDraft, setFormulaDraft] = useState("");
|
|
6549
|
+
const [imageWizardOpen, setImageWizardOpen] = useState(false);
|
|
5741
6550
|
const { columns: terminalColumns, rows: terminalRows } = useWindowSize();
|
|
5742
6551
|
const sheet = resolveSheet(doc.editor, sheetIndex);
|
|
5743
6552
|
const { rowCount, columnCount } = sheetExtent(sheet);
|
|
@@ -5746,6 +6555,7 @@ function OdsSpreadsheetGridScreen() {
|
|
|
5746
6555
|
const clampedColumn = Math.min(cursorColumn, columnCount - 1);
|
|
5747
6556
|
const overlayOpen = anyOverlayOpen(state);
|
|
5748
6557
|
const editing = editSession !== void 0;
|
|
6558
|
+
const editingAnything = editing || formulaEditing || imageWizardOpen;
|
|
5749
6559
|
function moveCursor(deltaRow, deltaColumn) {
|
|
5750
6560
|
setCursorRow((row) => Math.min(Math.max(row + deltaRow, 0), rowCount - 1));
|
|
5751
6561
|
setCursorColumn((column) => Math.min(Math.max(column + deltaColumn, 0), columnCount - 1));
|
|
@@ -5783,7 +6593,7 @@ function OdsSpreadsheetGridScreen() {
|
|
|
5783
6593
|
sheetIndex
|
|
5784
6594
|
}
|
|
5785
6595
|
});
|
|
5786
|
-
}, { isActive: !overlayOpen && !
|
|
6596
|
+
}, { isActive: !overlayOpen && !editingAnything });
|
|
5787
6597
|
useInput((input, key) => {
|
|
5788
6598
|
if (key.upArrow || input === "k") {
|
|
5789
6599
|
moveCursor(-1, 0);
|
|
@@ -5833,6 +6643,16 @@ function OdsSpreadsheetGridScreen() {
|
|
|
5833
6643
|
else commitMerge(mergeAnchor);
|
|
5834
6644
|
return;
|
|
5835
6645
|
}
|
|
6646
|
+
if (input === "f") {
|
|
6647
|
+
const cell = cells.get(cellKey(clampedRow, clampedColumn));
|
|
6648
|
+
setFormulaDraft(cell?.formula ?? "");
|
|
6649
|
+
setFormulaEditing(true);
|
|
6650
|
+
return;
|
|
6651
|
+
}
|
|
6652
|
+
if (input === "i") {
|
|
6653
|
+
setImageWizardOpen(true);
|
|
6654
|
+
return;
|
|
6655
|
+
}
|
|
5836
6656
|
if (key.return) {
|
|
5837
6657
|
if (mergeAnchor !== void 0) {
|
|
5838
6658
|
commitMerge(mergeAnchor);
|
|
@@ -5844,7 +6664,7 @@ function OdsSpreadsheetGridScreen() {
|
|
|
5844
6664
|
return;
|
|
5845
6665
|
}
|
|
5846
6666
|
if (input.length === 1 && !key.ctrl && !key.meta && !RESERVED_LETTERS.has(input)) beginEdit(input, inferKind(input));
|
|
5847
|
-
}, { isActive: !overlayOpen && !
|
|
6667
|
+
}, { isActive: !overlayOpen && !editingAnything && viewMode === "grid" });
|
|
5848
6668
|
const compactRows = sheet === void 0 ? [] : sheet.cells.filter((cell) => cell.value.kind !== "empty").map((cell) => ({
|
|
5849
6669
|
row: cell.row,
|
|
5850
6670
|
column: cell.column,
|
|
@@ -5962,9 +6782,43 @@ function OdsSpreadsheetGridScreen() {
|
|
|
5962
6782
|
setEditSession(void 0);
|
|
5963
6783
|
}
|
|
5964
6784
|
}),
|
|
6785
|
+
formulaEditing ? /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsxs(Text, {
|
|
6786
|
+
color: "cyan",
|
|
6787
|
+
children: [cursorAddress, " formula: "]
|
|
6788
|
+
}), /* @__PURE__ */ jsx(TextField, {
|
|
6789
|
+
value: formulaDraft,
|
|
6790
|
+
isFocused: !overlayOpen,
|
|
6791
|
+
placeholder: "e.g. of:=[.A1]+[.A2]",
|
|
6792
|
+
onChange: setFormulaDraft,
|
|
6793
|
+
onSubmit: (value) => {
|
|
6794
|
+
const trimmed = value.trim();
|
|
6795
|
+
dispatch({
|
|
6796
|
+
type: "SET_CELL_FORMULA",
|
|
6797
|
+
sheetIndex,
|
|
6798
|
+
row: clampedRow,
|
|
6799
|
+
column: clampedColumn,
|
|
6800
|
+
formula: trimmed.length === 0 ? void 0 : trimmed
|
|
6801
|
+
});
|
|
6802
|
+
setFormulaEditing(false);
|
|
6803
|
+
},
|
|
6804
|
+
onCancel: () => {
|
|
6805
|
+
setFormulaEditing(false);
|
|
6806
|
+
}
|
|
6807
|
+
})] }) : void 0,
|
|
6808
|
+
imageWizardOpen ? /* @__PURE__ */ jsx(FieldWizard, {
|
|
6809
|
+
fields: SHEET_IMAGE_FIELDS,
|
|
6810
|
+
onCancel: () => {
|
|
6811
|
+
setImageWizardOpen(false);
|
|
6812
|
+
},
|
|
6813
|
+
onComplete: (values) => {
|
|
6814
|
+
applyAddSheetImage(sheetIndex, clampedRow, clampedColumn, values, dispatch).then(() => {
|
|
6815
|
+
setImageWizardOpen(false);
|
|
6816
|
+
});
|
|
6817
|
+
}
|
|
6818
|
+
}) : void 0,
|
|
5965
6819
|
/* @__PURE__ */ jsx(Text, {
|
|
5966
6820
|
dimColor: true,
|
|
5967
|
-
children: mergeAnchor === void 0 ? `hjkl/arrows move, Enter/type to edit, m to anchor a merge, p print settings, t ${viewMode === "grid" ? "compact list" : "grid"} view, Esc back` : "hjkl/arrows to the opposite corner, m/Enter to merge, Esc to cancel"
|
|
6821
|
+
children: mergeAnchor === void 0 ? `hjkl/arrows move, Enter/type to edit, m to anchor a merge, p print settings, t ${viewMode === "grid" ? "compact list" : "grid"} view, f formula, i image, Esc back` : "hjkl/arrows to the opposite corner, m/Enter to merge, Esc to cancel"
|
|
5968
6822
|
})
|
|
5969
6823
|
]
|
|
5970
6824
|
});
|