document-cli 1.5.0 → 1.6.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-B-o3iI9a.js → tui-CqYlr4nN.js} +245 -72
- package/package.json +1 -1
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.
|
|
1197
|
+
var version = "1.6.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-
|
|
1224
|
+
const { runTui } = await import("./tui-CqYlr4nN.js");
|
|
1225
1225
|
await runTui({
|
|
1226
1226
|
startPath,
|
|
1227
1227
|
signal
|
package/dist/index.cjs
CHANGED
package/dist/index.js
CHANGED
|
@@ -490,10 +490,6 @@ function shapeAt(doc, containerIndex, shapeIndex) {
|
|
|
490
490
|
if (doc.format === "odg") return doc.editor.pages()[containerIndex]?.shapes()[shapeIndex];
|
|
491
491
|
return doc.editor.slides()[containerIndex]?.shapes()[shapeIndex];
|
|
492
492
|
}
|
|
493
|
-
function rotatableShapeAt(doc, containerIndex, shapeIndex) {
|
|
494
|
-
if (doc.format === "odg") return doc.editor.pages()[containerIndex]?.shapes()[shapeIndex];
|
|
495
|
-
return doc.editor.slides()[containerIndex]?.shapes()[shapeIndex];
|
|
496
|
-
}
|
|
497
493
|
function sheetAt(doc, sheetIndex) {
|
|
498
494
|
return doc.editor.sheets()[sheetIndex];
|
|
499
495
|
}
|
|
@@ -526,8 +522,8 @@ function withSheet(state, sheetIndex, apply) {
|
|
|
526
522
|
apply(sheet);
|
|
527
523
|
});
|
|
528
524
|
}
|
|
529
|
-
function
|
|
530
|
-
const paragraph =
|
|
525
|
+
function setTextContainerText(container, text) {
|
|
526
|
+
const paragraph = container.paragraphs()[0] ?? container.appendParagraph();
|
|
531
527
|
const runs = paragraph.runs();
|
|
532
528
|
const firstRun = runs[0];
|
|
533
529
|
if (firstRun === void 0) {
|
|
@@ -537,6 +533,9 @@ function setCellText(cell, text) {
|
|
|
537
533
|
firstRun.text = text;
|
|
538
534
|
for (const extra of runs.slice(1)) extra.remove();
|
|
539
535
|
}
|
|
536
|
+
function setCellText(cell, text) {
|
|
537
|
+
setTextContainerText(cell, text);
|
|
538
|
+
}
|
|
540
539
|
function appReducer(state, action) {
|
|
541
540
|
switch (action.type) {
|
|
542
541
|
case "PUSH_SCREEN": return {
|
|
@@ -721,6 +720,18 @@ function appReducer(state, action) {
|
|
|
721
720
|
appended.list = membership;
|
|
722
721
|
});
|
|
723
722
|
}
|
|
723
|
+
case "SET_LIST_ITEM_TEXT": {
|
|
724
|
+
const doc = wordprocessingDocument(state);
|
|
725
|
+
if (doc === void 0) return wrongDocument(state, "a docx or odt document");
|
|
726
|
+
if (doc.format !== "odt") return wrongDocument(state, "an odt document (lists are an odt-only concept)");
|
|
727
|
+
const list = doc.editor.lists()[action.blockIndex];
|
|
728
|
+
if (list === void 0) return withStatus(state, "warning", `There is no list at index ${action.blockIndex}`);
|
|
729
|
+
const item = list.items()[action.itemIndex];
|
|
730
|
+
if (item === void 0) return withStatus(state, "warning", `List ${action.blockIndex} has no item at index ${action.itemIndex}`);
|
|
731
|
+
return mutate(state, doc, () => {
|
|
732
|
+
setTextContainerText(item, action.text);
|
|
733
|
+
});
|
|
734
|
+
}
|
|
724
735
|
case "ADD_SLIDE": {
|
|
725
736
|
const doc = presentationDocument(state);
|
|
726
737
|
if (doc === void 0) return wrongDocument(state, "a pptx or odp document");
|
|
@@ -793,16 +804,9 @@ function appReducer(state, action) {
|
|
|
793
804
|
case "SET_SHAPE_FRAME": return withShape(state, action.containerIndex, action.shapeIndex, (shape) => {
|
|
794
805
|
shape.frame = action.frame;
|
|
795
806
|
});
|
|
796
|
-
case "SET_SHAPE_ROTATION": {
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
if (doc.format === "pptx") return withStatus(state, "warning", "documents.js has no rotation setter for a pptx shape; rotate the shape in odp instead");
|
|
800
|
-
const shape = rotatableShapeAt(doc, action.containerIndex, action.shapeIndex);
|
|
801
|
-
if (shape === void 0) return withStatus(state, "warning", `There is no shape ${action.shapeIndex} at index ${action.containerIndex}`);
|
|
802
|
-
return mutate(state, doc, () => {
|
|
803
|
-
shape.rotationDeg = action.rotationDeg;
|
|
804
|
-
});
|
|
805
|
-
}
|
|
807
|
+
case "SET_SHAPE_ROTATION": return withShape(state, action.containerIndex, action.shapeIndex, (shape) => {
|
|
808
|
+
shape.rotationDeg = action.rotationDeg;
|
|
809
|
+
});
|
|
806
810
|
case "SET_SLIDE_NOTES": {
|
|
807
811
|
const doc = presentationDocument(state);
|
|
808
812
|
if (doc === void 0) return wrongDocument(state, "a pptx or odp document");
|
|
@@ -1020,6 +1024,11 @@ const COMMANDS = [
|
|
|
1020
1024
|
usage: ":close",
|
|
1021
1025
|
description: "Close the open document"
|
|
1022
1026
|
},
|
|
1027
|
+
{
|
|
1028
|
+
name: "undo",
|
|
1029
|
+
usage: ":undo",
|
|
1030
|
+
description: "Undo the last change"
|
|
1031
|
+
},
|
|
1023
1032
|
{
|
|
1024
1033
|
name: "help",
|
|
1025
1034
|
usage: ":help",
|
|
@@ -1152,6 +1161,9 @@ async function runCommand(line, state, dispatch) {
|
|
|
1152
1161
|
case "close":
|
|
1153
1162
|
dispatch({ type: "REQUEST_CLOSE" });
|
|
1154
1163
|
return;
|
|
1164
|
+
case "undo":
|
|
1165
|
+
dispatch({ type: "UNDO" });
|
|
1166
|
+
return;
|
|
1155
1167
|
case "help":
|
|
1156
1168
|
dispatch({
|
|
1157
1169
|
type: "OPEN_OVERLAY",
|
|
@@ -1430,6 +1442,10 @@ const GLOBAL_KEYS = [
|
|
|
1430
1442
|
keys: "Ctrl+W",
|
|
1431
1443
|
description: "Close the open document"
|
|
1432
1444
|
},
|
|
1445
|
+
{
|
|
1446
|
+
keys: "Ctrl+Z",
|
|
1447
|
+
description: "Undo the last change"
|
|
1448
|
+
},
|
|
1433
1449
|
{
|
|
1434
1450
|
keys: "q / Ctrl+C",
|
|
1435
1451
|
description: "Quit"
|
|
@@ -3019,6 +3035,10 @@ function requireShapeOrVectorDetailScreen(state) {
|
|
|
3019
3035
|
if (screen.kind !== "shapeOrVectorDetail") throw new Error(`OdgShapeOrVectorDetailScreen rendered while the top of the stack is '${screen.kind}', not 'shapeOrVectorDetail' -- app.tsx's ScreenBody switch only mounts this component for that screen kind, so this cannot happen without a routing bug.`);
|
|
3020
3036
|
return screen;
|
|
3021
3037
|
}
|
|
3038
|
+
function vectorsParityMatch(liveVectors, contentVectors) {
|
|
3039
|
+
if (liveVectors.length !== contentVectors.length) return false;
|
|
3040
|
+
return liveVectors.every((live, index) => live.kind === contentVectors[index]?.kind);
|
|
3041
|
+
}
|
|
3022
3042
|
function buildPageItems(doc, pageIndex) {
|
|
3023
3043
|
const page = doc.editor.pages()[pageIndex];
|
|
3024
3044
|
if (page === void 0) return [];
|
|
@@ -3026,9 +3046,12 @@ function buildPageItems(doc, pageIndex) {
|
|
|
3026
3046
|
if (content.kind !== "drawing") throw new Error(`readOdgContent(doc.editor.toPackage()) returned a '${content.kind}' ContentDocument for an odg-format open document -- an odg package should always read back as the 'drawing' variant, so this indicates a real inconsistency in documents.js's own reader, not a state this screen should paper over.`);
|
|
3027
3047
|
const contentPage = content.pages[pageIndex];
|
|
3028
3048
|
if (contentPage === void 0) throw new Error(`readOdgContent found no page at index ${pageIndex}, but doc.editor.pages() has a page there -- the two read the same live package, so they should always agree on page count.`);
|
|
3029
|
-
const
|
|
3049
|
+
const liveVectors = page.vectors();
|
|
3050
|
+
const parityOk = vectorsParityMatch(liveVectors, contentPage.vectors);
|
|
3051
|
+
const vectorItems = contentPage.vectors.map((vector, index) => ({
|
|
3030
3052
|
kind: "vector",
|
|
3031
|
-
vector
|
|
3053
|
+
vector,
|
|
3054
|
+
liveVector: parityOk ? liveVectors[index] : void 0
|
|
3032
3055
|
}));
|
|
3033
3056
|
const shapeItems = page.shapes().map((shape, index) => {
|
|
3034
3057
|
return {
|
|
@@ -3320,15 +3343,19 @@ function warnVectorIsViewOnly(dispatch, label) {
|
|
|
3320
3343
|
dispatch({
|
|
3321
3344
|
type: "SET_STATUS",
|
|
3322
3345
|
severity: "info",
|
|
3323
|
-
text: `${label} added --
|
|
3346
|
+
text: `${label} added -- but this page also has a vector element documents.js's OdgPage.vectors() cannot wrap, so every vector on it (including this one) shows read-only in this list rather than risk pairing the wrong live handle to the wrong row.`
|
|
3324
3347
|
});
|
|
3325
3348
|
}
|
|
3349
|
+
function warnIfVectorAddedReadOnly(doc, pageIndex, dispatch, label) {
|
|
3350
|
+
const added = buildPageItems(doc, pageIndex).filter((item) => item.kind === "vector").at(-1);
|
|
3351
|
+
if (added !== void 0 && added.liveVector === void 0) warnVectorIsViewOnly(dispatch, label);
|
|
3352
|
+
}
|
|
3326
3353
|
function inferImageFormat(path) {
|
|
3327
3354
|
const extension = path.slice(path.lastIndexOf(".") + 1).toLowerCase();
|
|
3328
3355
|
if (extension === "png") return "png";
|
|
3329
3356
|
if (extension === "jpg" || extension === "jpeg") return "jpeg";
|
|
3330
3357
|
}
|
|
3331
|
-
async function applyAddKind(kind, pageIndex, values, dispatch) {
|
|
3358
|
+
async function applyAddKind(kind, pageIndex, doc, values, dispatch) {
|
|
3332
3359
|
switch (kind) {
|
|
3333
3360
|
case "rect":
|
|
3334
3361
|
dispatch({
|
|
@@ -3340,7 +3367,7 @@ async function applyAddKind(kind, pageIndex, values, dispatch) {
|
|
|
3340
3367
|
stroke: parseStrokeField(requireFieldValue(values, "stroke"))
|
|
3341
3368
|
}
|
|
3342
3369
|
});
|
|
3343
|
-
|
|
3370
|
+
warnIfVectorAddedReadOnly(doc, pageIndex, dispatch, "Rectangle");
|
|
3344
3371
|
return;
|
|
3345
3372
|
case "ellipse":
|
|
3346
3373
|
dispatch({
|
|
@@ -3352,7 +3379,7 @@ async function applyAddKind(kind, pageIndex, values, dispatch) {
|
|
|
3352
3379
|
stroke: parseStrokeField(requireFieldValue(values, "stroke"))
|
|
3353
3380
|
}
|
|
3354
3381
|
});
|
|
3355
|
-
|
|
3382
|
+
warnIfVectorAddedReadOnly(doc, pageIndex, dispatch, "Ellipse");
|
|
3356
3383
|
return;
|
|
3357
3384
|
case "line":
|
|
3358
3385
|
dispatch({
|
|
@@ -3377,7 +3404,7 @@ async function applyAddKind(kind, pageIndex, values, dispatch) {
|
|
|
3377
3404
|
}
|
|
3378
3405
|
}
|
|
3379
3406
|
});
|
|
3380
|
-
|
|
3407
|
+
warnIfVectorAddedReadOnly(doc, pageIndex, dispatch, "Line");
|
|
3381
3408
|
return;
|
|
3382
3409
|
case "path": {
|
|
3383
3410
|
const frame = readFrame(values);
|
|
@@ -3391,7 +3418,7 @@ async function applyAddKind(kind, pageIndex, values, dispatch) {
|
|
|
3391
3418
|
stroke: parseStrokeField(requireFieldValue(values, "stroke"))
|
|
3392
3419
|
}
|
|
3393
3420
|
});
|
|
3394
|
-
|
|
3421
|
+
warnIfVectorAddedReadOnly(doc, pageIndex, dispatch, "Path");
|
|
3395
3422
|
return;
|
|
3396
3423
|
}
|
|
3397
3424
|
case "textbox":
|
|
@@ -3520,7 +3547,7 @@ function AddItemFlow(props) {
|
|
|
3520
3547
|
fields: fieldsForAddKind(kind),
|
|
3521
3548
|
onCancel: props.onCancel,
|
|
3522
3549
|
onComplete: (values) => {
|
|
3523
|
-
applyAddKind(kind, props.pageIndex, values, dispatch).then(props.onCreated);
|
|
3550
|
+
applyAddKind(kind, props.pageIndex, props.doc, values, dispatch).then(props.onCreated);
|
|
3524
3551
|
}
|
|
3525
3552
|
});
|
|
3526
3553
|
}
|
|
@@ -3574,6 +3601,7 @@ function OdgPageDetailScreen() {
|
|
|
3574
3601
|
});
|
|
3575
3602
|
if (isAdding) return /* @__PURE__ */ jsx(AddItemFlow, {
|
|
3576
3603
|
pageIndex,
|
|
3604
|
+
doc,
|
|
3577
3605
|
isActive: !overlayOpen,
|
|
3578
3606
|
onCancel: () => {
|
|
3579
3607
|
setIsAdding(false);
|
|
@@ -3607,19 +3635,75 @@ function OdgPageDetailScreen() {
|
|
|
3607
3635
|
}
|
|
3608
3636
|
//#endregion
|
|
3609
3637
|
//#region src/tui/screens/editors/odg/shape-or-vector-detail.tsx
|
|
3638
|
+
function buildVectorRows(vector, liveVector, dispatch) {
|
|
3639
|
+
const rows = [];
|
|
3640
|
+
if (vector.kind !== "line" && liveVector.kind !== "line") {
|
|
3641
|
+
const fillTarget = liveVector;
|
|
3642
|
+
rows.push({
|
|
3643
|
+
label: `Fill: ${vector.fill === void 0 ? "none" : formatColor$1(vector.fill)}`,
|
|
3644
|
+
currentValue: vector.fill === void 0 ? "" : `${vector.fill.r} ${vector.fill.g} ${vector.fill.b}`,
|
|
3645
|
+
commit: (raw) => {
|
|
3646
|
+
dispatch({
|
|
3647
|
+
type: "SET_VECTOR_FILL",
|
|
3648
|
+
vector: fillTarget,
|
|
3649
|
+
fill: parseColorField(raw)
|
|
3650
|
+
});
|
|
3651
|
+
}
|
|
3652
|
+
});
|
|
3653
|
+
}
|
|
3654
|
+
rows.push({
|
|
3655
|
+
label: `Stroke: ${vector.stroke === void 0 ? "none" : `${formatColor$1(vector.stroke.color)} ${formatPt(vector.stroke.widthPt)}pt`}`,
|
|
3656
|
+
currentValue: vector.stroke === void 0 ? "" : `${vector.stroke.color.r} ${vector.stroke.color.g} ${vector.stroke.color.b} ${vector.stroke.widthPt}`,
|
|
3657
|
+
commit: (raw) => {
|
|
3658
|
+
const stroke = parseStrokeField(raw);
|
|
3659
|
+
if (stroke === void 0) {
|
|
3660
|
+
dispatch({
|
|
3661
|
+
type: "SET_STATUS",
|
|
3662
|
+
severity: "warning",
|
|
3663
|
+
text: "A vector stroke cannot be cleared to none through this editor -- enter \"r g b widthPt\" (0-1 colour, pt width) instead"
|
|
3664
|
+
});
|
|
3665
|
+
return;
|
|
3666
|
+
}
|
|
3667
|
+
dispatch({
|
|
3668
|
+
type: "SET_VECTOR_STROKE",
|
|
3669
|
+
vector: liveVector,
|
|
3670
|
+
stroke
|
|
3671
|
+
});
|
|
3672
|
+
}
|
|
3673
|
+
});
|
|
3674
|
+
return rows;
|
|
3675
|
+
}
|
|
3610
3676
|
function VectorDetail(props) {
|
|
3611
|
-
|
|
3677
|
+
const dispatch = useAppDispatch();
|
|
3678
|
+
const [editingField, setEditingField] = useState(void 0);
|
|
3679
|
+
const [draft, setDraft] = useState("");
|
|
3680
|
+
const { vector, liveVector, isActive } = props;
|
|
3681
|
+
const rows = liveVector === void 0 ? [] : buildVectorRows(vector, liveVector, dispatch);
|
|
3682
|
+
const { selectedIndex } = useNavigationInput({
|
|
3683
|
+
itemCount: rows.length,
|
|
3684
|
+
isActive: isActive && editingField === void 0,
|
|
3685
|
+
onBack: () => {
|
|
3686
|
+
dispatch({ type: "POP_SCREEN" });
|
|
3687
|
+
},
|
|
3688
|
+
onSelect: (index) => {
|
|
3689
|
+
const row = rows[index];
|
|
3690
|
+
if (row === void 0) return;
|
|
3691
|
+
setDraft(row.currentValue);
|
|
3692
|
+
setEditingField(index);
|
|
3693
|
+
}
|
|
3694
|
+
});
|
|
3695
|
+
if (liveVector === void 0) return /* @__PURE__ */ jsxs(Box, {
|
|
3612
3696
|
flexDirection: "column",
|
|
3613
3697
|
children: [
|
|
3614
3698
|
/* @__PURE__ */ jsxs(Text, {
|
|
3615
3699
|
bold: true,
|
|
3616
|
-
children: [vectorKindLabel(
|
|
3700
|
+
children: [vectorKindLabel(vector.kind), " (view-only)"]
|
|
3617
3701
|
}),
|
|
3618
|
-
/* @__PURE__ */ jsxs(Text, { children: ["Geometry: ", describeVectorGeometry(
|
|
3619
|
-
/* @__PURE__ */ jsx(Text, { children: describeFillStroke(
|
|
3702
|
+
/* @__PURE__ */ jsxs(Text, { children: ["Geometry: ", describeVectorGeometry(vector)] }),
|
|
3703
|
+
/* @__PURE__ */ jsx(Text, { children: describeFillStroke(vector) }),
|
|
3620
3704
|
/* @__PURE__ */ jsx(Text, {
|
|
3621
3705
|
color: "yellow",
|
|
3622
|
-
children: "documents.js's OdgPage has no
|
|
3706
|
+
children: "This page's live vectors (documents.js's `OdgPage.vectors()`) don't line up one-to-one with what odf.js's own reader found here -- likely a `draw:circle`/`polygon`/`polyline`/`custom-shape` element the live accessor has no wrapper for, sitting alongside a plain rect/ellipse/line/path it does. Rather than risk pairing the wrong live handle to this row, every vector on this page is shown read-only until that mismatch is resolved outside this TUI. Open the file in a real ODF editor to change it."
|
|
3623
3707
|
}),
|
|
3624
3708
|
/* @__PURE__ */ jsx(Text, {
|
|
3625
3709
|
dimColor: true,
|
|
@@ -3627,6 +3711,53 @@ function VectorDetail(props) {
|
|
|
3627
3711
|
})
|
|
3628
3712
|
]
|
|
3629
3713
|
});
|
|
3714
|
+
if (editingField !== void 0) {
|
|
3715
|
+
const row = rows[editingField];
|
|
3716
|
+
if (row === void 0) throw new Error(`VectorDetail is editing field index ${editingField}, but there are only ${rows.length} rows -- selecting a row always sets editingField to a valid index from that same rows array, so this indicates a bug in that selection.`);
|
|
3717
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
3718
|
+
flexDirection: "column",
|
|
3719
|
+
borderStyle: "round",
|
|
3720
|
+
paddingX: 1,
|
|
3721
|
+
children: [/* @__PURE__ */ jsx(Text, {
|
|
3722
|
+
bold: true,
|
|
3723
|
+
children: row.label
|
|
3724
|
+
}), /* @__PURE__ */ jsx(TextField, {
|
|
3725
|
+
value: draft,
|
|
3726
|
+
isFocused: true,
|
|
3727
|
+
onChange: setDraft,
|
|
3728
|
+
onCancel: () => {
|
|
3729
|
+
setEditingField(void 0);
|
|
3730
|
+
},
|
|
3731
|
+
onSubmit: (value) => {
|
|
3732
|
+
row.commit(value);
|
|
3733
|
+
setEditingField(void 0);
|
|
3734
|
+
}
|
|
3735
|
+
})]
|
|
3736
|
+
});
|
|
3737
|
+
}
|
|
3738
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
3739
|
+
flexDirection: "column",
|
|
3740
|
+
children: [
|
|
3741
|
+
/* @__PURE__ */ jsx(Text, {
|
|
3742
|
+
bold: true,
|
|
3743
|
+
children: vectorKindLabel(vector.kind)
|
|
3744
|
+
}),
|
|
3745
|
+
/* @__PURE__ */ jsxs(Text, { children: ["Geometry: ", describeVectorGeometry(vector)] }),
|
|
3746
|
+
/* @__PURE__ */ jsx(ListView, {
|
|
3747
|
+
items: rows,
|
|
3748
|
+
selectedIndex,
|
|
3749
|
+
reservedRows: 5,
|
|
3750
|
+
renderItem: (row, isSelected) => /* @__PURE__ */ jsxs(Text, {
|
|
3751
|
+
color: isSelected ? "cyan" : void 0,
|
|
3752
|
+
children: [isSelected ? "> " : " ", row.label]
|
|
3753
|
+
})
|
|
3754
|
+
}),
|
|
3755
|
+
/* @__PURE__ */ jsx(Text, {
|
|
3756
|
+
dimColor: true,
|
|
3757
|
+
children: "Enter to edit a field, Esc to go back"
|
|
3758
|
+
})
|
|
3759
|
+
]
|
|
3760
|
+
});
|
|
3630
3761
|
}
|
|
3631
3762
|
function ShapeDetail(props) {
|
|
3632
3763
|
const dispatch = useAppDispatch();
|
|
@@ -3796,7 +3927,7 @@ function OdgShapeOrVectorDetailScreen() {
|
|
|
3796
3927
|
const item = items[itemIndex];
|
|
3797
3928
|
useInput((input, key) => {
|
|
3798
3929
|
if (key.escape || key.leftArrow || input === "h") dispatch({ type: "POP_SCREEN" });
|
|
3799
|
-
}, { isActive: !overlayOpen && item
|
|
3930
|
+
}, { isActive: !overlayOpen && item === void 0 });
|
|
3800
3931
|
if (item === void 0) return /* @__PURE__ */ jsxs(Box, {
|
|
3801
3932
|
flexDirection: "column",
|
|
3802
3933
|
children: [/* @__PURE__ */ jsxs(Text, {
|
|
@@ -3813,7 +3944,11 @@ function OdgShapeOrVectorDetailScreen() {
|
|
|
3813
3944
|
children: "Esc to go back"
|
|
3814
3945
|
})]
|
|
3815
3946
|
});
|
|
3816
|
-
if (item.kind === "vector") return /* @__PURE__ */ jsx(VectorDetail, {
|
|
3947
|
+
if (item.kind === "vector") return /* @__PURE__ */ jsx(VectorDetail, {
|
|
3948
|
+
vector: item.vector,
|
|
3949
|
+
liveVector: item.liveVector,
|
|
3950
|
+
isActive: !overlayOpen
|
|
3951
|
+
});
|
|
3817
3952
|
const vectorCount = items.filter((entry) => entry.kind === "vector").length;
|
|
3818
3953
|
return /* @__PURE__ */ jsx(ShapeDetail, {
|
|
3819
3954
|
pageIndex,
|
|
@@ -3955,10 +4090,6 @@ function formatRotationDeg(value) {
|
|
|
3955
4090
|
return value === void 0 ? "(unset)" : `${Math.round(value * ROTATION_DISPLAY_PRECISION) / ROTATION_DISPLAY_PRECISION}°`;
|
|
3956
4091
|
}
|
|
3957
4092
|
function RotationField(props) {
|
|
3958
|
-
if (!props.isEditable) return /* @__PURE__ */ jsx(Text, {
|
|
3959
|
-
dimColor: true,
|
|
3960
|
-
children: "[R] Rotation: not available for pptx shapes"
|
|
3961
|
-
});
|
|
3962
4093
|
if (props.isEditing) return /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Text, {
|
|
3963
4094
|
color: "cyan",
|
|
3964
4095
|
children: "[R] Rotation (deg, blank to unset): "
|
|
@@ -3992,7 +4123,6 @@ const FIELD_LABELS = {
|
|
|
3992
4123
|
width: "Width (pt)",
|
|
3993
4124
|
height: "Height (pt)"
|
|
3994
4125
|
};
|
|
3995
|
-
const ROTATION_UNAVAILABLE_MESSAGE = "documents.js has no rotation setter for a pptx shape; rotate the shape in odp instead";
|
|
3996
4126
|
const POINT_DISPLAY_PRECISION = 100;
|
|
3997
4127
|
function formatPoints(value) {
|
|
3998
4128
|
return value === void 0 ? "(unset)" : `${Math.round(value * POINT_DISPLAY_PRECISION) / POINT_DISPLAY_PRECISION}pt`;
|
|
@@ -4012,9 +4142,9 @@ function describeFieldValue(key, shape) {
|
|
|
4012
4142
|
function roundForDisplay(value) {
|
|
4013
4143
|
return Math.round(value * POINT_DISPLAY_PRECISION) / POINT_DISPLAY_PRECISION;
|
|
4014
4144
|
}
|
|
4015
|
-
function initialDraftFor(key, shape
|
|
4145
|
+
function initialDraftFor(key, shape) {
|
|
4016
4146
|
if (key === "rotation") {
|
|
4017
|
-
const value =
|
|
4147
|
+
const value = shape.rotationDeg;
|
|
4018
4148
|
return value === void 0 ? "" : String(roundForDisplay(value));
|
|
4019
4149
|
}
|
|
4020
4150
|
if (key === "text") return shape.text;
|
|
@@ -4027,10 +4157,9 @@ function initialDraftFor(key, shape, rotatableShape) {
|
|
|
4027
4157
|
}
|
|
4028
4158
|
}
|
|
4029
4159
|
function FieldRow(props) {
|
|
4030
|
-
const { fieldKey, shape,
|
|
4160
|
+
const { fieldKey, shape, isSelected, isEditing, draft, onDraftChange, onSubmit, onCancel } = props;
|
|
4031
4161
|
if (fieldKey === "rotation") return /* @__PURE__ */ jsx(RotationField, {
|
|
4032
|
-
rotationDeg:
|
|
4033
|
-
isEditable: isOdp,
|
|
4162
|
+
rotationDeg: shape.rotationDeg,
|
|
4034
4163
|
isSelected,
|
|
4035
4164
|
isEditing,
|
|
4036
4165
|
draftValue: draft,
|
|
@@ -4079,9 +4208,7 @@ function ShapeEditorScreen(props) {
|
|
|
4079
4208
|
const overlayOpen = anyOverlayOpen(state);
|
|
4080
4209
|
const doc = assertPresentationDocument(state.openDocument);
|
|
4081
4210
|
const { slideIndex, shapeIndex } = props.screen;
|
|
4082
|
-
const isOdp = doc.format === "odp";
|
|
4083
4211
|
const shape = doc.editor.slides()[slideIndex]?.shapes()[shapeIndex];
|
|
4084
|
-
const rotatableShape = doc.format === "odp" ? doc.editor.slides()[slideIndex]?.shapes()[shapeIndex] : void 0;
|
|
4085
4212
|
const [editingField, setEditingField] = useState(void 0);
|
|
4086
4213
|
const [draft, setDraft] = useState("");
|
|
4087
4214
|
const { selectedIndex } = useNavigationInput({
|
|
@@ -4094,20 +4221,12 @@ function ShapeEditorScreen(props) {
|
|
|
4094
4221
|
if (shape === void 0) return;
|
|
4095
4222
|
const key = FIELD_KEYS[index];
|
|
4096
4223
|
if (key === void 0) return;
|
|
4097
|
-
if (key === "rotation" && !isOdp) {
|
|
4098
|
-
dispatch({
|
|
4099
|
-
type: "SET_STATUS",
|
|
4100
|
-
severity: "warning",
|
|
4101
|
-
text: ROTATION_UNAVAILABLE_MESSAGE
|
|
4102
|
-
});
|
|
4103
|
-
return;
|
|
4104
|
-
}
|
|
4105
4224
|
dispatch({
|
|
4106
4225
|
type: "SET_SELECTION",
|
|
4107
4226
|
key: selectionKeyFor(props.screen),
|
|
4108
4227
|
index
|
|
4109
4228
|
});
|
|
4110
|
-
setDraft(initialDraftFor(key, shape
|
|
4229
|
+
setDraft(initialDraftFor(key, shape));
|
|
4111
4230
|
setEditingField(key);
|
|
4112
4231
|
}
|
|
4113
4232
|
});
|
|
@@ -4232,8 +4351,6 @@ function ShapeEditorScreen(props) {
|
|
|
4232
4351
|
renderItem: (key, isSelected) => /* @__PURE__ */ jsx(FieldRow, {
|
|
4233
4352
|
fieldKey: key,
|
|
4234
4353
|
shape,
|
|
4235
|
-
rotatableShape,
|
|
4236
|
-
isOdp,
|
|
4237
4354
|
isSelected,
|
|
4238
4355
|
isEditing: editingField === key,
|
|
4239
4356
|
draft,
|
|
@@ -5339,28 +5456,40 @@ function OdsSpreadsheetGridScreen() {
|
|
|
5339
5456
|
function ListEditorScreen() {
|
|
5340
5457
|
const state = useAppState();
|
|
5341
5458
|
const dispatch = useAppDispatch();
|
|
5459
|
+
const overlayOpen = anyOverlayOpen(state);
|
|
5342
5460
|
const [isAdding, setIsAdding] = useState(false);
|
|
5343
5461
|
const [newItemText, setNewItemText] = useState("");
|
|
5462
|
+
const [editingIndex, setEditingIndex] = useState(void 0);
|
|
5344
5463
|
const screen = currentScreen(state);
|
|
5345
5464
|
const doc = paragraphFamilyDocument(state.openDocument);
|
|
5346
5465
|
const list = screen.kind === "listEditor" && doc?.format === "odt" ? doc.editor.lists()[screen.blockIndex] : void 0;
|
|
5347
|
-
const
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5466
|
+
const items = list === void 0 ? [] : list.items();
|
|
5467
|
+
const rows = items.map((item, index) => ({
|
|
5468
|
+
item,
|
|
5469
|
+
index
|
|
5470
|
+
}));
|
|
5471
|
+
const itemCount = items.length;
|
|
5472
|
+
const isNavigationActive = !overlayOpen && !isAdding && editingIndex === void 0;
|
|
5473
|
+
const { selectedIndex } = useNavigationInput({
|
|
5474
|
+
itemCount,
|
|
5475
|
+
isActive: isNavigationActive,
|
|
5476
|
+
onBack: () => {
|
|
5351
5477
|
dispatch({ type: "POP_SCREEN" });
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5478
|
+
},
|
|
5479
|
+
onSelect: (index) => {
|
|
5480
|
+
setEditingIndex(index);
|
|
5481
|
+
},
|
|
5482
|
+
onAppend: () => {
|
|
5355
5483
|
setIsAdding(true);
|
|
5356
|
-
return;
|
|
5357
5484
|
}
|
|
5485
|
+
});
|
|
5486
|
+
useInput((input, key) => {
|
|
5358
5487
|
if (key.tab || input === ">" || input === "<") dispatch({
|
|
5359
5488
|
type: "SET_STATUS",
|
|
5360
5489
|
severity: "warning",
|
|
5361
5490
|
text: "Indenting a list item needs a new reducer action this pass didn't add -- OdtListItem.addNestedList() has no wiring yet"
|
|
5362
5491
|
});
|
|
5363
|
-
}, { isActive:
|
|
5492
|
+
}, { isActive: isNavigationActive });
|
|
5364
5493
|
if (screen.kind !== "listEditor") return /* @__PURE__ */ jsx(Text, {
|
|
5365
5494
|
color: "red",
|
|
5366
5495
|
children: "ListEditorScreen rendered outside a listEditor screen."
|
|
@@ -5377,6 +5506,36 @@ function ListEditorScreen() {
|
|
|
5377
5506
|
"."
|
|
5378
5507
|
]
|
|
5379
5508
|
});
|
|
5509
|
+
if (editingIndex !== void 0) {
|
|
5510
|
+
const item = items[editingIndex];
|
|
5511
|
+
if (item === void 0) throw new Error(`ListEditorScreen is editing item index ${editingIndex}, but list ${screen.blockIndex} only has ${items.length} items -- selecting a row always sets editingIndex to a valid index from that same items array, so this indicates a bug in that selection.`);
|
|
5512
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
5513
|
+
flexDirection: "column",
|
|
5514
|
+
children: [/* @__PURE__ */ jsxs(Text, {
|
|
5515
|
+
bold: true,
|
|
5516
|
+
children: [
|
|
5517
|
+
"List ",
|
|
5518
|
+
screen.blockIndex,
|
|
5519
|
+
", item ",
|
|
5520
|
+
editingIndex + 1
|
|
5521
|
+
]
|
|
5522
|
+
}), /* @__PURE__ */ jsx(RunTextEditor, {
|
|
5523
|
+
initialText: item.text,
|
|
5524
|
+
onCommit: (text) => {
|
|
5525
|
+
dispatch({
|
|
5526
|
+
type: "SET_LIST_ITEM_TEXT",
|
|
5527
|
+
blockIndex: screen.blockIndex,
|
|
5528
|
+
itemIndex: editingIndex,
|
|
5529
|
+
text
|
|
5530
|
+
});
|
|
5531
|
+
setEditingIndex(void 0);
|
|
5532
|
+
},
|
|
5533
|
+
onCancel: () => {
|
|
5534
|
+
setEditingIndex(void 0);
|
|
5535
|
+
}
|
|
5536
|
+
})]
|
|
5537
|
+
});
|
|
5538
|
+
}
|
|
5380
5539
|
return /* @__PURE__ */ jsxs(Box, {
|
|
5381
5540
|
flexDirection: "column",
|
|
5382
5541
|
children: [
|
|
@@ -5392,13 +5551,23 @@ function ListEditorScreen() {
|
|
|
5392
5551
|
")"
|
|
5393
5552
|
]
|
|
5394
5553
|
}),
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5554
|
+
/* @__PURE__ */ jsx(ListView, {
|
|
5555
|
+
items: rows,
|
|
5556
|
+
selectedIndex,
|
|
5557
|
+
emptyMessage: "This list has no items yet -- press 'a' to add one.",
|
|
5558
|
+
renderItem: (row, isSelected) => {
|
|
5559
|
+
const trimmed = row.item.text.trim();
|
|
5560
|
+
return /* @__PURE__ */ jsxs(Text, {
|
|
5561
|
+
color: isSelected ? "cyan" : void 0,
|
|
5562
|
+
inverse: isSelected,
|
|
5563
|
+
children: [
|
|
5564
|
+
row.index + 1,
|
|
5565
|
+
". ",
|
|
5566
|
+
trimmed.length === 0 ? "(empty)" : row.item.text
|
|
5567
|
+
]
|
|
5568
|
+
});
|
|
5569
|
+
}
|
|
5570
|
+
}),
|
|
5402
5571
|
isAdding ? /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(Text, {
|
|
5403
5572
|
color: "cyan",
|
|
5404
5573
|
children: "+ "
|
|
@@ -5422,7 +5591,7 @@ function ListEditorScreen() {
|
|
|
5422
5591
|
}
|
|
5423
5592
|
})] }) : /* @__PURE__ */ jsx(Text, {
|
|
5424
5593
|
dimColor: true,
|
|
5425
|
-
children: "
|
|
5594
|
+
children: "Enter to edit an item, a to add, Esc back"
|
|
5426
5595
|
})
|
|
5427
5596
|
]
|
|
5428
5597
|
});
|
|
@@ -6441,6 +6610,10 @@ function AppShell({ startPath }) {
|
|
|
6441
6610
|
dispatch({ type: "REQUEST_CLOSE" });
|
|
6442
6611
|
return;
|
|
6443
6612
|
}
|
|
6613
|
+
if (key.ctrl && input === "z") {
|
|
6614
|
+
dispatch({ type: "UNDO" });
|
|
6615
|
+
return;
|
|
6616
|
+
}
|
|
6444
6617
|
if (input === ":") {
|
|
6445
6618
|
dispatch({
|
|
6446
6619
|
type: "OPEN_OVERLAY",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "document-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.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": {
|