document-cli 1.9.0 → 1.10.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-D9SLI7oT.js → tui-BVeYd0ry.js} +1271 -170
- package/package.json +1 -1
|
@@ -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, 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";
|
|
3
|
+
import { buildDocxPackage, buildOdtPackage, bytesToBase64, convertWordprocessingToLayout, createDocx, createFontMeasurer, createFontRegistry, createOdg, createOdp, createOds, createOdt, createPdf, createPptx, decodeMarkdownText, docxToPdf, encodeMarkdownText, encodePackage, hsqldbCellDisplayText, markdownToPdf, odgToPdf, odpToPdf, odsToPdf, odtToPdf, openDocx, openOdg, openOdp, openOds, openOdt, openPdf, 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";
|
|
@@ -36,7 +36,7 @@ function toPdfOptions(options, fonts) {
|
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
async function exportToPdf(openDocument, destinationPath, options) {
|
|
39
|
-
if (openDocument.format === "odb" || openDocument.format === "pdf") throw new Error(`A ${openDocument.format} document is
|
|
39
|
+
if (openDocument.format === "odb" || openDocument.format === "pdf") throw new Error(`A ${openDocument.format} document has no export-to-PDF path -- ${openDocument.format === "pdf" ? "save it directly instead" : "it is a read-only source with nothing to convert"}`);
|
|
40
40
|
const pdfOptions = toPdfOptions(options, await loadProvidedFonts(options.fontFiles ?? [], { signal: options.signal }));
|
|
41
41
|
if (openDocument.format === "markdown") {
|
|
42
42
|
const pdfBytes = markdownToPdf(encodeMarkdownText(openDocument.source), pdfOptions);
|
|
@@ -120,11 +120,15 @@ async function openDocumentAtPath(path) {
|
|
|
120
120
|
editor: openOdg(bytes),
|
|
121
121
|
path
|
|
122
122
|
};
|
|
123
|
-
case "pdf":
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
123
|
+
case "pdf": {
|
|
124
|
+
const editor = openPdf(bytes);
|
|
125
|
+
return {
|
|
126
|
+
format,
|
|
127
|
+
editor,
|
|
128
|
+
layout: editor.toLayoutDocument(),
|
|
129
|
+
path
|
|
130
|
+
};
|
|
131
|
+
}
|
|
128
132
|
case "markdown": return {
|
|
129
133
|
format,
|
|
130
134
|
source: decodeMarkdownText(bytes),
|
|
@@ -171,10 +175,19 @@ function createNewDocument(format) {
|
|
|
171
175
|
editor: createOdg(),
|
|
172
176
|
path: void 0
|
|
173
177
|
};
|
|
178
|
+
case "pdf": {
|
|
179
|
+
const editor = createPdf();
|
|
180
|
+
return {
|
|
181
|
+
format,
|
|
182
|
+
editor,
|
|
183
|
+
layout: editor.toLayoutDocument(),
|
|
184
|
+
path: void 0
|
|
185
|
+
};
|
|
186
|
+
}
|
|
174
187
|
}
|
|
175
188
|
}
|
|
176
189
|
async function saveDocumentTo(openDocument, path) {
|
|
177
|
-
if (openDocument.format === "odb" || openDocument.format === "
|
|
190
|
+
if (openDocument.format === "odb" || openDocument.format === "xlsx") throw new Error(`A ${openDocument.format} document is opened read-only and cannot be written back`);
|
|
178
191
|
if (openDocument.format === "markdown") {
|
|
179
192
|
await writeFile(path, encodeMarkdownText(openDocument.source));
|
|
180
193
|
return;
|
|
@@ -189,7 +202,8 @@ const EDITABLE_FORMATS = {
|
|
|
189
202
|
odt: true,
|
|
190
203
|
odp: true,
|
|
191
204
|
ods: true,
|
|
192
|
-
odg: true
|
|
205
|
+
odg: true,
|
|
206
|
+
pdf: true
|
|
193
207
|
};
|
|
194
208
|
const WRITABLE_FORMATS = {
|
|
195
209
|
...EDITABLE_FORMATS,
|
|
@@ -368,6 +382,12 @@ function documentWithPath(doc, path) {
|
|
|
368
382
|
editor: doc.editor,
|
|
369
383
|
path
|
|
370
384
|
};
|
|
385
|
+
case "pdf": return {
|
|
386
|
+
format: "pdf",
|
|
387
|
+
editor: doc.editor,
|
|
388
|
+
layout: doc.layout,
|
|
389
|
+
path
|
|
390
|
+
};
|
|
371
391
|
case "odb": return {
|
|
372
392
|
format: "odb",
|
|
373
393
|
tables: doc.tables,
|
|
@@ -380,11 +400,6 @@ function documentWithPath(doc, path) {
|
|
|
380
400
|
source: doc.source,
|
|
381
401
|
path
|
|
382
402
|
};
|
|
383
|
-
case "pdf": return {
|
|
384
|
-
format: "pdf",
|
|
385
|
-
layout: doc.layout,
|
|
386
|
-
path
|
|
387
|
-
};
|
|
388
403
|
case "xlsx": return {
|
|
389
404
|
format: "xlsx",
|
|
390
405
|
layout: doc.layout,
|
|
@@ -425,6 +440,15 @@ function reopenEditable(doc, bytes) {
|
|
|
425
440
|
editor: openOdg(bytes),
|
|
426
441
|
path: doc.path
|
|
427
442
|
};
|
|
443
|
+
case "pdf": {
|
|
444
|
+
const editor = openPdf(bytes);
|
|
445
|
+
return {
|
|
446
|
+
format: "pdf",
|
|
447
|
+
editor,
|
|
448
|
+
layout: editor.toLayoutDocument(),
|
|
449
|
+
path: doc.path
|
|
450
|
+
};
|
|
451
|
+
}
|
|
428
452
|
}
|
|
429
453
|
}
|
|
430
454
|
function mutate(state, doc, apply) {
|
|
@@ -508,6 +532,40 @@ function drawingDocument(state) {
|
|
|
508
532
|
if (doc === void 0) return;
|
|
509
533
|
return doc.format === "odg" ? doc : void 0;
|
|
510
534
|
}
|
|
535
|
+
function pdfDocument(state) {
|
|
536
|
+
const doc = state.openDocument;
|
|
537
|
+
if (doc === void 0) return;
|
|
538
|
+
return doc.format === "pdf" ? doc : void 0;
|
|
539
|
+
}
|
|
540
|
+
function pdfItemAt(doc, pageIndex, itemIndex) {
|
|
541
|
+
return doc.editor.page(pageIndex)?.items()[itemIndex];
|
|
542
|
+
}
|
|
543
|
+
function withPdfPage(state, pageIndex, apply) {
|
|
544
|
+
const doc = pdfDocument(state);
|
|
545
|
+
if (doc === void 0) return wrongDocument(state, "a pdf document");
|
|
546
|
+
const page = doc.editor.page(pageIndex);
|
|
547
|
+
if (page === void 0) return withStatus(state, "warning", `There is no page at index ${pageIndex}`);
|
|
548
|
+
return mutate(state, doc, () => {
|
|
549
|
+
apply(page);
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
function withPdfItemMatching(state, pageIndex, itemIndex, guard, kindLabel, apply) {
|
|
553
|
+
const doc = pdfDocument(state);
|
|
554
|
+
if (doc === void 0) return wrongDocument(state, "a pdf document");
|
|
555
|
+
const item = pdfItemAt(doc, pageIndex, itemIndex);
|
|
556
|
+
if (item === void 0) return withStatus(state, "warning", `Page ${pageIndex} has no item at index ${itemIndex}`);
|
|
557
|
+
if (!guard(item)) return withStatus(state, "warning", `Item ${itemIndex} on page ${pageIndex} is a ${item.kind} item, not ${kindLabel}`);
|
|
558
|
+
return mutate(state, doc, () => {
|
|
559
|
+
apply(item);
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
const isPdfTextItem = (item) => item.kind === "text";
|
|
563
|
+
const isPdfRectItem = (item) => item.kind === "rect";
|
|
564
|
+
const isPdfEllipseItem = (item) => item.kind === "ellipse";
|
|
565
|
+
const isPdfLineItem = (item) => item.kind === "line";
|
|
566
|
+
const isPdfPathItem = (item) => item.kind === "path";
|
|
567
|
+
const isPdfImageItem = (item) => item.kind === "image";
|
|
568
|
+
const isPdfLinkItem = (item) => item.kind === "link";
|
|
511
569
|
function vectorHostDocument(state) {
|
|
512
570
|
const doc = state.openDocument;
|
|
513
571
|
if (doc === void 0) return;
|
|
@@ -1078,6 +1136,129 @@ function appReducer(state, action) {
|
|
|
1078
1136
|
action.vector.stroke = action.stroke;
|
|
1079
1137
|
});
|
|
1080
1138
|
}
|
|
1139
|
+
case "ADD_PDF_TEXT": return withPdfPage(state, action.pageIndex, (page) => {
|
|
1140
|
+
page.appendText(action.init);
|
|
1141
|
+
});
|
|
1142
|
+
case "ADD_PDF_RECT": return withPdfPage(state, action.pageIndex, (page) => {
|
|
1143
|
+
page.appendRect(action.init);
|
|
1144
|
+
});
|
|
1145
|
+
case "ADD_PDF_ELLIPSE": return withPdfPage(state, action.pageIndex, (page) => {
|
|
1146
|
+
page.appendEllipse(action.init);
|
|
1147
|
+
});
|
|
1148
|
+
case "ADD_PDF_LINE": return withPdfPage(state, action.pageIndex, (page) => {
|
|
1149
|
+
page.appendLine(action.init);
|
|
1150
|
+
});
|
|
1151
|
+
case "ADD_PDF_PATH": return withPdfPage(state, action.pageIndex, (page) => {
|
|
1152
|
+
page.appendPath(action.init);
|
|
1153
|
+
});
|
|
1154
|
+
case "ADD_PDF_IMAGE": return withPdfPage(state, action.pageIndex, (page) => {
|
|
1155
|
+
page.appendImage(action.init);
|
|
1156
|
+
});
|
|
1157
|
+
case "ADD_PDF_LINK": return withPdfPage(state, action.pageIndex, (page) => {
|
|
1158
|
+
page.appendLink(action.init);
|
|
1159
|
+
});
|
|
1160
|
+
case "REMOVE_PDF_ITEM": {
|
|
1161
|
+
const doc = pdfDocument(state);
|
|
1162
|
+
if (doc === void 0) return wrongDocument(state, "a pdf document");
|
|
1163
|
+
const item = pdfItemAt(doc, action.pageIndex, action.itemIndex);
|
|
1164
|
+
if (item === void 0) return withStatus(state, "warning", `Page ${action.pageIndex} has no item at index ${action.itemIndex}`);
|
|
1165
|
+
return mutate(state, doc, () => {
|
|
1166
|
+
item.remove();
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
case "SET_PDF_TEXT_TEXT": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfTextItem, "text", (item) => {
|
|
1170
|
+
item.text = action.text;
|
|
1171
|
+
});
|
|
1172
|
+
case "SET_PDF_TEXT_POSITION": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfTextItem, "text", (item) => {
|
|
1173
|
+
item.xPt = action.xPt;
|
|
1174
|
+
item.yPt = action.yPt;
|
|
1175
|
+
});
|
|
1176
|
+
case "SET_PDF_TEXT_FONT": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfTextItem, "text", (item) => {
|
|
1177
|
+
item.font = action.font;
|
|
1178
|
+
});
|
|
1179
|
+
case "SET_PDF_TEXT_SIZE": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfTextItem, "text", (item) => {
|
|
1180
|
+
item.sizePt = action.sizePt;
|
|
1181
|
+
});
|
|
1182
|
+
case "SET_PDF_TEXT_COLOR": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfTextItem, "text", (item) => {
|
|
1183
|
+
item.color = action.color;
|
|
1184
|
+
});
|
|
1185
|
+
case "SET_PDF_TEXT_ROTATION": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfTextItem, "text", (item) => {
|
|
1186
|
+
item.rotationDeg = action.rotationDeg;
|
|
1187
|
+
});
|
|
1188
|
+
case "SET_PDF_TEXT_WIDTH": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfTextItem, "text", (item) => {
|
|
1189
|
+
item.widthPt = action.widthPt;
|
|
1190
|
+
});
|
|
1191
|
+
case "TOGGLE_PDF_TEXT_UNDERLINE": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfTextItem, "text", (item) => {
|
|
1192
|
+
item.underline = !(item.underline ?? false);
|
|
1193
|
+
});
|
|
1194
|
+
case "SET_PDF_RECT_FRAME": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfRectItem, "rect", (item) => {
|
|
1195
|
+
item.xPt = action.xPt;
|
|
1196
|
+
item.yPt = action.yPt;
|
|
1197
|
+
item.widthPt = action.widthPt;
|
|
1198
|
+
item.heightPt = action.heightPt;
|
|
1199
|
+
});
|
|
1200
|
+
case "SET_PDF_RECT_FILL": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfRectItem, "rect", (item) => {
|
|
1201
|
+
item.fill = action.fill;
|
|
1202
|
+
});
|
|
1203
|
+
case "SET_PDF_RECT_STROKE": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfRectItem, "rect", (item) => {
|
|
1204
|
+
item.stroke = action.stroke;
|
|
1205
|
+
});
|
|
1206
|
+
case "SET_PDF_ELLIPSE_FRAME": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfEllipseItem, "ellipse", (item) => {
|
|
1207
|
+
item.xPt = action.xPt;
|
|
1208
|
+
item.yPt = action.yPt;
|
|
1209
|
+
item.widthPt = action.widthPt;
|
|
1210
|
+
item.heightPt = action.heightPt;
|
|
1211
|
+
});
|
|
1212
|
+
case "SET_PDF_ELLIPSE_FILL": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfEllipseItem, "ellipse", (item) => {
|
|
1213
|
+
item.fill = action.fill;
|
|
1214
|
+
});
|
|
1215
|
+
case "SET_PDF_ELLIPSE_STROKE": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfEllipseItem, "ellipse", (item) => {
|
|
1216
|
+
item.stroke = action.stroke;
|
|
1217
|
+
});
|
|
1218
|
+
case "SET_PDF_LINE_FROM": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfLineItem, "line", (item) => {
|
|
1219
|
+
item.x1Pt = action.x1Pt;
|
|
1220
|
+
item.y1Pt = action.y1Pt;
|
|
1221
|
+
});
|
|
1222
|
+
case "SET_PDF_LINE_TO": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfLineItem, "line", (item) => {
|
|
1223
|
+
item.x2Pt = action.x2Pt;
|
|
1224
|
+
item.y2Pt = action.y2Pt;
|
|
1225
|
+
});
|
|
1226
|
+
case "SET_PDF_LINE_COLOR": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfLineItem, "line", (item) => {
|
|
1227
|
+
item.color = action.color;
|
|
1228
|
+
});
|
|
1229
|
+
case "SET_PDF_LINE_WIDTH": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfLineItem, "line", (item) => {
|
|
1230
|
+
item.widthPt = action.widthPt;
|
|
1231
|
+
});
|
|
1232
|
+
case "SET_PDF_PATH_FILL": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfPathItem, "path", (item) => {
|
|
1233
|
+
item.fill = action.fill;
|
|
1234
|
+
});
|
|
1235
|
+
case "SET_PDF_PATH_FILL_RULE": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfPathItem, "path", (item) => {
|
|
1236
|
+
item.fillRule = action.fillRule;
|
|
1237
|
+
});
|
|
1238
|
+
case "SET_PDF_PATH_STROKE": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfPathItem, "path", (item) => {
|
|
1239
|
+
item.stroke = action.stroke;
|
|
1240
|
+
});
|
|
1241
|
+
case "SET_PDF_IMAGE_FRAME": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfImageItem, "image", (item) => {
|
|
1242
|
+
item.xPt = action.xPt;
|
|
1243
|
+
item.yPt = action.yPt;
|
|
1244
|
+
item.widthPt = action.widthPt;
|
|
1245
|
+
item.heightPt = action.heightPt;
|
|
1246
|
+
});
|
|
1247
|
+
case "SET_PDF_IMAGE_ROTATION": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfImageItem, "image", (item) => {
|
|
1248
|
+
item.rotationDeg = action.rotationDeg;
|
|
1249
|
+
});
|
|
1250
|
+
case "SET_PDF_IMAGE_SOURCE": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfImageItem, "image", (item) => {
|
|
1251
|
+
item.setImage(action.bytes, action.format);
|
|
1252
|
+
});
|
|
1253
|
+
case "SET_PDF_LINK_URI": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfLinkItem, "link", (item) => {
|
|
1254
|
+
item.uri = action.uri;
|
|
1255
|
+
});
|
|
1256
|
+
case "SET_PDF_LINK_FRAME": return withPdfItemMatching(state, action.pageIndex, action.itemIndex, isPdfLinkItem, "link", (item) => {
|
|
1257
|
+
item.xPt = action.xPt;
|
|
1258
|
+
item.yPt = action.yPt;
|
|
1259
|
+
item.widthPt = action.widthPt;
|
|
1260
|
+
item.heightPt = action.heightPt;
|
|
1261
|
+
});
|
|
1081
1262
|
case "SET_MARKDOWN_SOURCE": {
|
|
1082
1263
|
const doc = markdownDocument(state);
|
|
1083
1264
|
if (doc === void 0) return wrongDocument(state, "a markdown document");
|
|
@@ -1111,7 +1292,7 @@ function appReducer(state, action) {
|
|
|
1111
1292
|
case "UNDO": {
|
|
1112
1293
|
const doc = state.openDocument;
|
|
1113
1294
|
if (doc === void 0) return withStatus(state, "info", "There is nothing to undo");
|
|
1114
|
-
if (doc.format === "odb" || doc.format === "
|
|
1295
|
+
if (doc.format === "odb" || doc.format === "xlsx") return withStatus(state, "warning", `A ${doc.format} document is read-only, so it has no history to undo`);
|
|
1115
1296
|
const snapshot = state.undoStack.at(-1);
|
|
1116
1297
|
if (snapshot === void 0) return withStatus(state, "info", "There is nothing to undo");
|
|
1117
1298
|
const restored = doc.format === "markdown" ? {
|
|
@@ -1195,7 +1376,7 @@ function TextField(props) {
|
|
|
1195
1376
|
}
|
|
1196
1377
|
//#endregion
|
|
1197
1378
|
//#region src/tui/components/command-palette.tsx
|
|
1198
|
-
const USAGE_COLUMN_WIDTH =
|
|
1379
|
+
const USAGE_COLUMN_WIDTH = 36;
|
|
1199
1380
|
const COMMANDS = [
|
|
1200
1381
|
{
|
|
1201
1382
|
name: "save",
|
|
@@ -1214,7 +1395,7 @@ const COMMANDS = [
|
|
|
1214
1395
|
},
|
|
1215
1396
|
{
|
|
1216
1397
|
name: "new",
|
|
1217
|
-
usage: ":new docx|pptx|odt|odp|ods|odg",
|
|
1398
|
+
usage: ":new docx|pptx|odt|odp|ods|odg|pdf",
|
|
1218
1399
|
description: "Create an empty document"
|
|
1219
1400
|
},
|
|
1220
1401
|
{
|
|
@@ -1331,7 +1512,7 @@ async function runCommand(line, state, dispatch) {
|
|
|
1331
1512
|
case "new": {
|
|
1332
1513
|
const format = args[0];
|
|
1333
1514
|
if (format === void 0 || !isEditableFormat(format)) {
|
|
1334
|
-
warn(dispatch, "Usage: :new docx|pptx|odt|odp|ods|odg");
|
|
1515
|
+
warn(dispatch, "Usage: :new docx|pptx|odt|odp|ods|odg|pdf");
|
|
1335
1516
|
return;
|
|
1336
1517
|
}
|
|
1337
1518
|
dispatch({
|
|
@@ -2522,14 +2703,14 @@ const IMAGE_FIELDS = [
|
|
|
2522
2703
|
defaultValue: ""
|
|
2523
2704
|
}
|
|
2524
2705
|
];
|
|
2525
|
-
function inferImageFormat$
|
|
2706
|
+
function inferImageFormat$2(path) {
|
|
2526
2707
|
const extension = path.slice(path.lastIndexOf(".") + 1).toLowerCase();
|
|
2527
2708
|
if (extension === "png") return "png";
|
|
2528
2709
|
if (extension === "jpg" || extension === "jpeg") return "jpeg";
|
|
2529
2710
|
}
|
|
2530
2711
|
async function applyInsertImage(blockIndex, values, dispatch) {
|
|
2531
2712
|
const path = requireFieldValue(values, "path");
|
|
2532
|
-
const format = inferImageFormat$
|
|
2713
|
+
const format = inferImageFormat$2(path);
|
|
2533
2714
|
if (format === void 0) {
|
|
2534
2715
|
dispatch({
|
|
2535
2716
|
type: "SET_STATUS",
|
|
@@ -4012,14 +4193,14 @@ function vectorKindLabel(kind) {
|
|
|
4012
4193
|
case "path": return "Path";
|
|
4013
4194
|
}
|
|
4014
4195
|
}
|
|
4015
|
-
function formatPt(value) {
|
|
4196
|
+
function formatPt$1(value) {
|
|
4016
4197
|
return value.toFixed(1);
|
|
4017
4198
|
}
|
|
4018
4199
|
function formatFrame(box) {
|
|
4019
|
-
return `${formatPt(box.xPt)},${formatPt(box.yPt)} ${formatPt(box.widthPt)}x${formatPt(box.heightPt)}pt`;
|
|
4200
|
+
return `${formatPt$1(box.xPt)},${formatPt$1(box.yPt)} ${formatPt$1(box.widthPt)}x${formatPt$1(box.heightPt)}pt`;
|
|
4020
4201
|
}
|
|
4021
4202
|
function formatPoint$1(point) {
|
|
4022
|
-
return `${formatPt(point.xPt)},${formatPt(point.yPt)}`;
|
|
4203
|
+
return `${formatPt$1(point.xPt)},${formatPt$1(point.yPt)}`;
|
|
4023
4204
|
}
|
|
4024
4205
|
function formatColor$1(color) {
|
|
4025
4206
|
return `rgb(${color.r.toFixed(2)}, ${color.g.toFixed(2)}, ${color.b.toFixed(2)})`;
|
|
@@ -4031,7 +4212,7 @@ function describeVectorGeometry(vector) {
|
|
|
4031
4212
|
function describeFillStroke(vector) {
|
|
4032
4213
|
const parts = [];
|
|
4033
4214
|
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`);
|
|
4215
|
+
if (vector.stroke !== void 0) parts.push(`stroke ${formatColor$1(vector.stroke.color)} ${formatPt$1(vector.stroke.widthPt)}pt`);
|
|
4035
4216
|
return parts.length === 0 ? "no fill or stroke" : parts.join(", ");
|
|
4036
4217
|
}
|
|
4037
4218
|
//#endregion
|
|
@@ -4098,7 +4279,7 @@ function OdgPageListScreen() {
|
|
|
4098
4279
|
}
|
|
4099
4280
|
//#endregion
|
|
4100
4281
|
//#region src/tui/screens/editors/odg/page-detail.tsx
|
|
4101
|
-
const ADD_KIND_OPTIONS = [
|
|
4282
|
+
const ADD_KIND_OPTIONS$1 = [
|
|
4102
4283
|
{
|
|
4103
4284
|
kind: "rect",
|
|
4104
4285
|
label: "Rectangle"
|
|
@@ -4124,7 +4305,7 @@ const ADD_KIND_OPTIONS = [
|
|
|
4124
4305
|
label: "Image"
|
|
4125
4306
|
}
|
|
4126
4307
|
];
|
|
4127
|
-
const GEOMETRY_FIELDS = [
|
|
4308
|
+
const GEOMETRY_FIELDS$1 = [
|
|
4128
4309
|
{
|
|
4129
4310
|
key: "xPt",
|
|
4130
4311
|
label: "X (pt)",
|
|
@@ -4146,24 +4327,24 @@ const GEOMETRY_FIELDS = [
|
|
|
4146
4327
|
defaultValue: "100"
|
|
4147
4328
|
}
|
|
4148
4329
|
];
|
|
4149
|
-
const FILL_FIELD = {
|
|
4330
|
+
const FILL_FIELD$1 = {
|
|
4150
4331
|
key: "fill",
|
|
4151
4332
|
label: "Fill \"r g b\" (0-1 each), blank for none",
|
|
4152
4333
|
defaultValue: "0.8 0.8 0.8"
|
|
4153
4334
|
};
|
|
4154
|
-
const STROKE_FIELD = {
|
|
4335
|
+
const STROKE_FIELD$1 = {
|
|
4155
4336
|
key: "stroke",
|
|
4156
4337
|
label: "Stroke \"r g b widthPt\" (0-1 colour, pt width), blank for none",
|
|
4157
4338
|
defaultValue: "0 0 0 1"
|
|
4158
4339
|
};
|
|
4159
|
-
function fieldsForAddKind(kind) {
|
|
4340
|
+
function fieldsForAddKind$1(kind) {
|
|
4160
4341
|
switch (kind) {
|
|
4161
4342
|
case "rect":
|
|
4162
4343
|
case "ellipse":
|
|
4163
4344
|
case "path": return [
|
|
4164
|
-
...GEOMETRY_FIELDS,
|
|
4165
|
-
FILL_FIELD,
|
|
4166
|
-
STROKE_FIELD
|
|
4345
|
+
...GEOMETRY_FIELDS$1,
|
|
4346
|
+
FILL_FIELD$1,
|
|
4347
|
+
STROKE_FIELD$1
|
|
4167
4348
|
];
|
|
4168
4349
|
case "line": return [
|
|
4169
4350
|
{
|
|
@@ -4186,15 +4367,15 @@ function fieldsForAddKind(kind) {
|
|
|
4186
4367
|
label: "To Y (pt)",
|
|
4187
4368
|
defaultValue: "40"
|
|
4188
4369
|
},
|
|
4189
|
-
STROKE_FIELD
|
|
4370
|
+
STROKE_FIELD$1
|
|
4190
4371
|
];
|
|
4191
|
-
case "textbox": return [...GEOMETRY_FIELDS, {
|
|
4372
|
+
case "textbox": return [...GEOMETRY_FIELDS$1, {
|
|
4192
4373
|
key: "text",
|
|
4193
4374
|
label: "Text",
|
|
4194
4375
|
defaultValue: "Text"
|
|
4195
4376
|
}];
|
|
4196
4377
|
case "image": return [
|
|
4197
|
-
...GEOMETRY_FIELDS,
|
|
4378
|
+
...GEOMETRY_FIELDS$1,
|
|
4198
4379
|
{
|
|
4199
4380
|
key: "path",
|
|
4200
4381
|
label: "Image file path (.png/.jpg/.jpeg)",
|
|
@@ -4208,7 +4389,7 @@ function fieldsForAddKind(kind) {
|
|
|
4208
4389
|
];
|
|
4209
4390
|
}
|
|
4210
4391
|
}
|
|
4211
|
-
function readFrame(values) {
|
|
4392
|
+
function readFrame$1(values) {
|
|
4212
4393
|
return {
|
|
4213
4394
|
xPt: parseNumberField(requireFieldValue(values, "xPt"), 0),
|
|
4214
4395
|
yPt: parseNumberField(requireFieldValue(values, "yPt"), 0),
|
|
@@ -4227,19 +4408,19 @@ function warnIfVectorAddedReadOnly(doc, pageIndex, dispatch, label) {
|
|
|
4227
4408
|
const added = buildPageItems(doc, pageIndex).filter((item) => item.kind === "vector").at(-1);
|
|
4228
4409
|
if (added !== void 0 && added.liveVector === void 0) warnVectorIsViewOnly(dispatch, label);
|
|
4229
4410
|
}
|
|
4230
|
-
function inferImageFormat(path) {
|
|
4411
|
+
function inferImageFormat$1(path) {
|
|
4231
4412
|
const extension = path.slice(path.lastIndexOf(".") + 1).toLowerCase();
|
|
4232
4413
|
if (extension === "png") return "png";
|
|
4233
4414
|
if (extension === "jpg" || extension === "jpeg") return "jpeg";
|
|
4234
4415
|
}
|
|
4235
|
-
async function applyAddKind(kind, pageIndex, doc, values, dispatch) {
|
|
4416
|
+
async function applyAddKind$1(kind, pageIndex, doc, values, dispatch) {
|
|
4236
4417
|
switch (kind) {
|
|
4237
4418
|
case "rect":
|
|
4238
4419
|
dispatch({
|
|
4239
4420
|
type: "ADD_RECT",
|
|
4240
4421
|
containerIndex: pageIndex,
|
|
4241
4422
|
init: {
|
|
4242
|
-
frame: readFrame(values),
|
|
4423
|
+
frame: readFrame$1(values),
|
|
4243
4424
|
fill: parseColorField(requireFieldValue(values, "fill")),
|
|
4244
4425
|
stroke: parseStrokeField(requireFieldValue(values, "stroke"))
|
|
4245
4426
|
}
|
|
@@ -4251,7 +4432,7 @@ async function applyAddKind(kind, pageIndex, doc, values, dispatch) {
|
|
|
4251
4432
|
type: "ADD_ELLIPSE",
|
|
4252
4433
|
containerIndex: pageIndex,
|
|
4253
4434
|
init: {
|
|
4254
|
-
frame: readFrame(values),
|
|
4435
|
+
frame: readFrame$1(values),
|
|
4255
4436
|
fill: parseColorField(requireFieldValue(values, "fill")),
|
|
4256
4437
|
stroke: parseStrokeField(requireFieldValue(values, "stroke"))
|
|
4257
4438
|
}
|
|
@@ -4284,7 +4465,7 @@ async function applyAddKind(kind, pageIndex, doc, values, dispatch) {
|
|
|
4284
4465
|
warnIfVectorAddedReadOnly(doc, pageIndex, dispatch, "Line");
|
|
4285
4466
|
return;
|
|
4286
4467
|
case "path": {
|
|
4287
|
-
const frame = readFrame(values);
|
|
4468
|
+
const frame = readFrame$1(values);
|
|
4288
4469
|
dispatch({
|
|
4289
4470
|
type: "ADD_PATH",
|
|
4290
4471
|
containerIndex: pageIndex,
|
|
@@ -4302,14 +4483,14 @@ async function applyAddKind(kind, pageIndex, doc, values, dispatch) {
|
|
|
4302
4483
|
dispatch({
|
|
4303
4484
|
type: "ADD_TEXTBOX",
|
|
4304
4485
|
containerIndex: pageIndex,
|
|
4305
|
-
frame: readFrame(values),
|
|
4486
|
+
frame: readFrame$1(values),
|
|
4306
4487
|
text: requireFieldValue(values, "text")
|
|
4307
4488
|
});
|
|
4308
4489
|
return;
|
|
4309
4490
|
case "image": {
|
|
4310
|
-
const frame = readFrame(values);
|
|
4491
|
+
const frame = readFrame$1(values);
|
|
4311
4492
|
const path = requireFieldValue(values, "path");
|
|
4312
|
-
const format = inferImageFormat(path);
|
|
4493
|
+
const format = inferImageFormat$1(path);
|
|
4313
4494
|
if (format === void 0) {
|
|
4314
4495
|
dispatch({
|
|
4315
4496
|
type: "SET_STATUS",
|
|
@@ -4340,15 +4521,15 @@ async function applyAddKind(kind, pageIndex, doc, values, dispatch) {
|
|
|
4340
4521
|
}
|
|
4341
4522
|
}
|
|
4342
4523
|
}
|
|
4343
|
-
function AddItemFlow(props) {
|
|
4524
|
+
function AddItemFlow$1(props) {
|
|
4344
4525
|
const dispatch = useAppDispatch();
|
|
4345
4526
|
const [kind, setKind] = useState(void 0);
|
|
4346
4527
|
const { selectedIndex } = useNavigationInput({
|
|
4347
|
-
itemCount: ADD_KIND_OPTIONS.length,
|
|
4528
|
+
itemCount: ADD_KIND_OPTIONS$1.length,
|
|
4348
4529
|
isActive: props.isActive && kind === void 0,
|
|
4349
4530
|
onBack: props.onCancel,
|
|
4350
4531
|
onSelect: (index) => {
|
|
4351
|
-
const option = ADD_KIND_OPTIONS[index];
|
|
4532
|
+
const option = ADD_KIND_OPTIONS$1[index];
|
|
4352
4533
|
if (option === void 0) return;
|
|
4353
4534
|
setKind(option.kind);
|
|
4354
4535
|
}
|
|
@@ -4361,7 +4542,7 @@ function AddItemFlow(props) {
|
|
|
4361
4542
|
bold: true,
|
|
4362
4543
|
children: "Add item -- choose a kind"
|
|
4363
4544
|
}), /* @__PURE__ */ jsx(ListView, {
|
|
4364
|
-
items: ADD_KIND_OPTIONS,
|
|
4545
|
+
items: ADD_KIND_OPTIONS$1,
|
|
4365
4546
|
selectedIndex,
|
|
4366
4547
|
reservedRows: 6,
|
|
4367
4548
|
renderItem: (option, isSelected) => /* @__PURE__ */ jsxs(Text, {
|
|
@@ -4371,10 +4552,10 @@ function AddItemFlow(props) {
|
|
|
4371
4552
|
})]
|
|
4372
4553
|
});
|
|
4373
4554
|
return /* @__PURE__ */ jsx(FieldWizard, {
|
|
4374
|
-
fields: fieldsForAddKind(kind),
|
|
4555
|
+
fields: fieldsForAddKind$1(kind),
|
|
4375
4556
|
onCancel: props.onCancel,
|
|
4376
4557
|
onComplete: (values) => {
|
|
4377
|
-
applyAddKind(kind, props.pageIndex, props.doc, values, dispatch).then(props.onCreated);
|
|
4558
|
+
applyAddKind$1(kind, props.pageIndex, props.doc, values, dispatch).then(props.onCreated);
|
|
4378
4559
|
}
|
|
4379
4560
|
});
|
|
4380
4561
|
}
|
|
@@ -4426,7 +4607,7 @@ function OdgPageDetailScreen() {
|
|
|
4426
4607
|
setIsAdding(true);
|
|
4427
4608
|
}
|
|
4428
4609
|
});
|
|
4429
|
-
if (isAdding) return /* @__PURE__ */ jsx(AddItemFlow, {
|
|
4610
|
+
if (isAdding) return /* @__PURE__ */ jsx(AddItemFlow$1, {
|
|
4430
4611
|
pageIndex,
|
|
4431
4612
|
doc,
|
|
4432
4613
|
isActive: !overlayOpen,
|
|
@@ -4479,7 +4660,7 @@ function buildVectorRows(vector, liveVector, dispatch) {
|
|
|
4479
4660
|
});
|
|
4480
4661
|
}
|
|
4481
4662
|
rows.push({
|
|
4482
|
-
label: `Stroke: ${vector.stroke === void 0 ? "none" : `${formatColor$1(vector.stroke.color)} ${formatPt(vector.stroke.widthPt)}pt`}`,
|
|
4663
|
+
label: `Stroke: ${vector.stroke === void 0 ? "none" : `${formatColor$1(vector.stroke.color)} ${formatPt$1(vector.stroke.widthPt)}pt`}`,
|
|
4483
4664
|
currentValue: vector.stroke === void 0 ? "" : `${vector.stroke.color.r} ${vector.stroke.color.g} ${vector.stroke.color.b} ${vector.stroke.widthPt}`,
|
|
4484
4665
|
commit: (raw) => {
|
|
4485
4666
|
const stroke = parseStrokeField(raw);
|
|
@@ -4611,7 +4792,7 @@ function ShapeDetail(props) {
|
|
|
4611
4792
|
}
|
|
4612
4793
|
},
|
|
4613
4794
|
{
|
|
4614
|
-
label: `X: ${formatPt(frame.xPt)}pt`,
|
|
4795
|
+
label: `X: ${formatPt$1(frame.xPt)}pt`,
|
|
4615
4796
|
currentValue: String(frame.xPt),
|
|
4616
4797
|
commit: (raw) => {
|
|
4617
4798
|
dispatch({
|
|
@@ -4626,7 +4807,7 @@ function ShapeDetail(props) {
|
|
|
4626
4807
|
}
|
|
4627
4808
|
},
|
|
4628
4809
|
{
|
|
4629
|
-
label: `Y: ${formatPt(frame.yPt)}pt`,
|
|
4810
|
+
label: `Y: ${formatPt$1(frame.yPt)}pt`,
|
|
4630
4811
|
currentValue: String(frame.yPt),
|
|
4631
4812
|
commit: (raw) => {
|
|
4632
4813
|
dispatch({
|
|
@@ -4641,7 +4822,7 @@ function ShapeDetail(props) {
|
|
|
4641
4822
|
}
|
|
4642
4823
|
},
|
|
4643
4824
|
{
|
|
4644
|
-
label: `Width: ${formatPt(frame.widthPt)}pt`,
|
|
4825
|
+
label: `Width: ${formatPt$1(frame.widthPt)}pt`,
|
|
4645
4826
|
currentValue: String(frame.widthPt),
|
|
4646
4827
|
commit: (raw) => {
|
|
4647
4828
|
dispatch({
|
|
@@ -4656,7 +4837,7 @@ function ShapeDetail(props) {
|
|
|
4656
4837
|
}
|
|
4657
4838
|
},
|
|
4658
4839
|
{
|
|
4659
|
-
label: `Height: ${formatPt(frame.heightPt)}pt`,
|
|
4840
|
+
label: `Height: ${formatPt$1(frame.heightPt)}pt`,
|
|
4660
4841
|
currentValue: String(frame.heightPt),
|
|
4661
4842
|
commit: (raw) => {
|
|
4662
4843
|
dispatch({
|
|
@@ -4671,7 +4852,7 @@ function ShapeDetail(props) {
|
|
|
4671
4852
|
}
|
|
4672
4853
|
},
|
|
4673
4854
|
{
|
|
4674
|
-
label: `Rotation: ${shape.rotationDeg === void 0 ? "none" : `${formatPt(shape.rotationDeg)} deg`}`,
|
|
4855
|
+
label: `Rotation: ${shape.rotationDeg === void 0 ? "none" : `${formatPt$1(shape.rotationDeg)} deg`}`,
|
|
4675
4856
|
currentValue: shape.rotationDeg === void 0 ? "" : String(shape.rotationDeg),
|
|
4676
4857
|
commit: (raw) => {
|
|
4677
4858
|
const trimmed = raw.trim();
|
|
@@ -6997,9 +7178,58 @@ function requirePdfDocument(openDocument) {
|
|
|
6997
7178
|
if (openDocument?.format !== "pdf" && openDocument?.format !== "xlsx") throw new Error("A PDF inspection screen rendered without an open PDF or xlsx document; the app router only reaches this screen group from pdfPageList, which is only ever the root screen of one of those two formats.");
|
|
6998
7179
|
return openDocument;
|
|
6999
7180
|
}
|
|
7181
|
+
function isEditablePdfDocument(doc) {
|
|
7182
|
+
return doc.format === "pdf";
|
|
7183
|
+
}
|
|
7000
7184
|
function formatSize(widthPt, heightPt) {
|
|
7001
7185
|
return `${widthPt.toFixed(0)}×${heightPt.toFixed(0)}pt`;
|
|
7002
7186
|
}
|
|
7187
|
+
function formatPt(value) {
|
|
7188
|
+
return value.toFixed(1);
|
|
7189
|
+
}
|
|
7190
|
+
function formatColor(color) {
|
|
7191
|
+
const byte = (component) => Math.round(component * 255).toString(16).padStart(2, "0");
|
|
7192
|
+
return `#${byte(color.r)}${byte(color.g)}${byte(color.b)}`;
|
|
7193
|
+
}
|
|
7194
|
+
function formatStroke(stroke) {
|
|
7195
|
+
return `${formatColor(stroke.color)} @ ${stroke.widthPt.toFixed(1)}pt`;
|
|
7196
|
+
}
|
|
7197
|
+
function parseRequiredColorField(raw, fallback) {
|
|
7198
|
+
return parseColorField(raw) ?? fallback;
|
|
7199
|
+
}
|
|
7200
|
+
function parseFontWeight(raw) {
|
|
7201
|
+
return raw.trim().toLowerCase() === "bold" ? "bold" : "normal";
|
|
7202
|
+
}
|
|
7203
|
+
function parseFontStyle(raw) {
|
|
7204
|
+
return raw.trim().toLowerCase() === "italic" ? "italic" : "normal";
|
|
7205
|
+
}
|
|
7206
|
+
function parseOptionalNumberField(raw) {
|
|
7207
|
+
const trimmed = raw.trim();
|
|
7208
|
+
if (trimmed.length === 0) return;
|
|
7209
|
+
const parsed = Number.parseFloat(trimmed);
|
|
7210
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
7211
|
+
}
|
|
7212
|
+
function defaultTriangleLayoutSubpaths(widthPt, heightPt) {
|
|
7213
|
+
return [{
|
|
7214
|
+
startXPt: 0,
|
|
7215
|
+
startYPt: heightPt,
|
|
7216
|
+
segments: [{
|
|
7217
|
+
kind: "line",
|
|
7218
|
+
xPt: widthPt / 2,
|
|
7219
|
+
yPt: 0
|
|
7220
|
+
}, {
|
|
7221
|
+
kind: "line",
|
|
7222
|
+
xPt: widthPt,
|
|
7223
|
+
yPt: heightPt
|
|
7224
|
+
}],
|
|
7225
|
+
closed: true
|
|
7226
|
+
}];
|
|
7227
|
+
}
|
|
7228
|
+
function inferImageFormat(path) {
|
|
7229
|
+
const extension = path.slice(path.lastIndexOf(".") + 1).toLowerCase();
|
|
7230
|
+
if (extension === "png") return "png";
|
|
7231
|
+
if (extension === "jpg" || extension === "jpeg") return "jpeg";
|
|
7232
|
+
}
|
|
7003
7233
|
//#endregion
|
|
7004
7234
|
//#region src/tui/screens/editors/pdf/page-list.tsx
|
|
7005
7235
|
const LAYOUT_ITEM_KIND_ORDER = [
|
|
@@ -7088,13 +7318,6 @@ function PdfPageListScreen() {
|
|
|
7088
7318
|
function formatPoint(xPt, yPt) {
|
|
7089
7319
|
return `(${xPt.toFixed(1)}, ${yPt.toFixed(1)})pt`;
|
|
7090
7320
|
}
|
|
7091
|
-
function formatColor(color) {
|
|
7092
|
-
const byte = (component) => Math.round(component * 255).toString(16).padStart(2, "0");
|
|
7093
|
-
return `#${byte(color.r)}${byte(color.g)}${byte(color.b)}`;
|
|
7094
|
-
}
|
|
7095
|
-
function formatStroke(stroke) {
|
|
7096
|
-
return `${formatColor(stroke.color)} @ ${stroke.widthPt.toFixed(1)}pt`;
|
|
7097
|
-
}
|
|
7098
7321
|
function fieldsFor(item) {
|
|
7099
7322
|
const fields = [["Kind", item.kind]];
|
|
7100
7323
|
switch (item.kind) {
|
|
@@ -7146,19 +7369,10 @@ function fieldsFor(item) {
|
|
|
7146
7369
|
if (item.sourcePath !== void 0) fields.push(["Source path", item.sourcePath]);
|
|
7147
7370
|
return fields;
|
|
7148
7371
|
}
|
|
7149
|
-
function
|
|
7150
|
-
const state = useAppState();
|
|
7151
|
-
const dispatch = useAppDispatch();
|
|
7152
|
-
const doc = requirePdfDocument(state.openDocument);
|
|
7153
|
-
const screen = currentScreen(state);
|
|
7154
|
-
if (screen.kind !== "pdfItemDetail") throw new Error(`PdfItemDetailScreen rendered while the current screen is "${screen.kind}", not "pdfItemDetail".`);
|
|
7155
|
-
const page = doc.layout.pages[screen.pageIndex];
|
|
7156
|
-
if (page === void 0) throw new Error(`pdfItemDetail was pushed for page ${screen.pageIndex}, but the open PDF has no page at that index.`);
|
|
7157
|
-
const item = page.items[screen.itemIndex];
|
|
7158
|
-
if (item === void 0) throw new Error(`pdfItemDetail was pushed for item ${screen.itemIndex} on page ${screen.pageIndex}, but that page has no item at that index.`);
|
|
7372
|
+
function ReadOnlyItemDetail(props) {
|
|
7159
7373
|
useInput((input, key) => {
|
|
7160
|
-
if (key.escape || key.leftArrow || input === "h")
|
|
7161
|
-
}, { isActive:
|
|
7374
|
+
if (key.escape || key.leftArrow || input === "h") props.onBack();
|
|
7375
|
+
}, { isActive: props.isActive });
|
|
7162
7376
|
return /* @__PURE__ */ jsxs(Box, {
|
|
7163
7377
|
flexDirection: "column",
|
|
7164
7378
|
children: [
|
|
@@ -7166,12 +7380,12 @@ function PdfItemDetailScreen() {
|
|
|
7166
7380
|
bold: true,
|
|
7167
7381
|
children: [
|
|
7168
7382
|
"Page ",
|
|
7169
|
-
|
|
7383
|
+
props.pageIndex + 1,
|
|
7170
7384
|
", item ",
|
|
7171
|
-
|
|
7385
|
+
props.itemIndex + 1
|
|
7172
7386
|
]
|
|
7173
7387
|
}),
|
|
7174
|
-
fieldsFor(item).map(([label, value]) => /* @__PURE__ */ jsxs(Text, { children: [
|
|
7388
|
+
fieldsFor(props.item).map(([label, value]) => /* @__PURE__ */ jsxs(Text, { children: [
|
|
7175
7389
|
label,
|
|
7176
7390
|
": ",
|
|
7177
7391
|
value
|
|
@@ -7183,109 +7397,996 @@ function PdfItemDetailScreen() {
|
|
|
7183
7397
|
]
|
|
7184
7398
|
});
|
|
7185
7399
|
}
|
|
7186
|
-
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
|
|
7191
|
-
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
|
|
7195
|
-
|
|
7196
|
-
|
|
7197
|
-
|
|
7198
|
-
|
|
7199
|
-
|
|
7200
|
-
|
|
7201
|
-
|
|
7202
|
-
|
|
7203
|
-
|
|
7204
|
-
|
|
7205
|
-
|
|
7206
|
-
|
|
7207
|
-
|
|
7208
|
-
|
|
7209
|
-
|
|
7210
|
-
|
|
7400
|
+
function buildFrameRows(frame, onFrameChange) {
|
|
7401
|
+
return [
|
|
7402
|
+
{
|
|
7403
|
+
label: `X: ${formatPt(frame.xPt)}pt`,
|
|
7404
|
+
currentValue: String(frame.xPt),
|
|
7405
|
+
commit: (raw) => onFrameChange({
|
|
7406
|
+
...frame,
|
|
7407
|
+
xPt: parseNumberField(raw, frame.xPt)
|
|
7408
|
+
})
|
|
7409
|
+
},
|
|
7410
|
+
{
|
|
7411
|
+
label: `Y: ${formatPt(frame.yPt)}pt`,
|
|
7412
|
+
currentValue: String(frame.yPt),
|
|
7413
|
+
commit: (raw) => onFrameChange({
|
|
7414
|
+
...frame,
|
|
7415
|
+
yPt: parseNumberField(raw, frame.yPt)
|
|
7416
|
+
})
|
|
7417
|
+
},
|
|
7418
|
+
{
|
|
7419
|
+
label: `Width: ${formatPt(frame.widthPt)}pt`,
|
|
7420
|
+
currentValue: String(frame.widthPt),
|
|
7421
|
+
commit: (raw) => onFrameChange({
|
|
7422
|
+
...frame,
|
|
7423
|
+
widthPt: parseNumberField(raw, frame.widthPt)
|
|
7424
|
+
})
|
|
7425
|
+
},
|
|
7426
|
+
{
|
|
7427
|
+
label: `Height: ${formatPt(frame.heightPt)}pt`,
|
|
7428
|
+
currentValue: String(frame.heightPt),
|
|
7429
|
+
commit: (raw) => onFrameChange({
|
|
7430
|
+
...frame,
|
|
7431
|
+
heightPt: parseNumberField(raw, frame.heightPt)
|
|
7432
|
+
})
|
|
7211
7433
|
}
|
|
7212
|
-
|
|
7213
|
-
if (minX > maxX) return "empty path";
|
|
7214
|
-
return formatSize(maxX - minX, maxY - minY);
|
|
7434
|
+
];
|
|
7215
7435
|
}
|
|
7216
|
-
function
|
|
7217
|
-
|
|
7218
|
-
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
|
|
7222
|
-
|
|
7223
|
-
|
|
7224
|
-
|
|
7225
|
-
}
|
|
7436
|
+
function buildFillStrokeRows(fill, stroke, onFillChange, onStrokeChange) {
|
|
7437
|
+
return [{
|
|
7438
|
+
label: `Fill: ${fill === void 0 ? "none" : formatColor(fill)}`,
|
|
7439
|
+
currentValue: fill === void 0 ? "" : `${fill.r} ${fill.g} ${fill.b}`,
|
|
7440
|
+
commit: (raw) => onFillChange(parseColorField(raw))
|
|
7441
|
+
}, {
|
|
7442
|
+
label: `Stroke: ${stroke === void 0 ? "none" : formatStroke(stroke)}`,
|
|
7443
|
+
currentValue: stroke === void 0 ? "" : `${stroke.color.r} ${stroke.color.g} ${stroke.color.b} ${stroke.widthPt}`,
|
|
7444
|
+
commit: (raw) => onStrokeChange(parseStrokeField(raw))
|
|
7445
|
+
}];
|
|
7226
7446
|
}
|
|
7227
|
-
function
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
|
|
7235
|
-
|
|
7236
|
-
|
|
7237
|
-
|
|
7238
|
-
itemIndex
|
|
7239
|
-
}));
|
|
7240
|
-
const items = query === "" ? indexed : indexed.filter((entry) => `${entry.item.kind} ${previewFor(entry.item)}`.toLowerCase().includes(query));
|
|
7241
|
-
const { selectedIndex } = useNavigationInput({
|
|
7242
|
-
itemCount: items.length,
|
|
7243
|
-
onSelect: (index) => {
|
|
7244
|
-
const entry = items[index];
|
|
7245
|
-
if (entry === void 0) return;
|
|
7246
|
-
dispatch({
|
|
7247
|
-
type: "PUSH_SCREEN",
|
|
7248
|
-
screen: {
|
|
7249
|
-
kind: "pdfItemDetail",
|
|
7250
|
-
pageIndex: screen.pageIndex,
|
|
7251
|
-
itemIndex: entry.itemIndex
|
|
7252
|
-
}
|
|
7253
|
-
});
|
|
7447
|
+
function buildTextRows(item, pageIndex, itemIndex, dispatch) {
|
|
7448
|
+
return [
|
|
7449
|
+
{
|
|
7450
|
+
label: `Text: ${item.text}`,
|
|
7451
|
+
currentValue: item.text,
|
|
7452
|
+
commit: (raw) => dispatch({
|
|
7453
|
+
type: "SET_PDF_TEXT_TEXT",
|
|
7454
|
+
pageIndex,
|
|
7455
|
+
itemIndex,
|
|
7456
|
+
text: raw
|
|
7457
|
+
})
|
|
7254
7458
|
},
|
|
7255
|
-
|
|
7256
|
-
|
|
7459
|
+
{
|
|
7460
|
+
label: `X: ${formatPt(item.xPt)}pt`,
|
|
7461
|
+
currentValue: String(item.xPt),
|
|
7462
|
+
commit: (raw) => dispatch({
|
|
7463
|
+
type: "SET_PDF_TEXT_POSITION",
|
|
7464
|
+
pageIndex,
|
|
7465
|
+
itemIndex,
|
|
7466
|
+
xPt: parseNumberField(raw, item.xPt),
|
|
7467
|
+
yPt: item.yPt
|
|
7468
|
+
})
|
|
7257
7469
|
},
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
|
|
7262
|
-
|
|
7263
|
-
|
|
7264
|
-
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
|
|
7268
|
-
|
|
7269
|
-
|
|
7270
|
-
|
|
7271
|
-
|
|
7470
|
+
{
|
|
7471
|
+
label: `Y: ${formatPt(item.yPt)}pt`,
|
|
7472
|
+
currentValue: String(item.yPt),
|
|
7473
|
+
commit: (raw) => dispatch({
|
|
7474
|
+
type: "SET_PDF_TEXT_POSITION",
|
|
7475
|
+
pageIndex,
|
|
7476
|
+
itemIndex,
|
|
7477
|
+
xPt: item.xPt,
|
|
7478
|
+
yPt: parseNumberField(raw, item.yPt)
|
|
7479
|
+
})
|
|
7480
|
+
},
|
|
7481
|
+
{
|
|
7482
|
+
label: `Font family: ${item.font.family}`,
|
|
7483
|
+
currentValue: item.font.family,
|
|
7484
|
+
commit: (raw) => {
|
|
7485
|
+
const family = raw.trim();
|
|
7486
|
+
dispatch({
|
|
7487
|
+
type: "SET_PDF_TEXT_FONT",
|
|
7488
|
+
pageIndex,
|
|
7489
|
+
itemIndex,
|
|
7490
|
+
font: {
|
|
7491
|
+
...item.font,
|
|
7492
|
+
family: family.length === 0 ? item.font.family : family
|
|
7493
|
+
}
|
|
7494
|
+
});
|
|
7495
|
+
}
|
|
7496
|
+
},
|
|
7497
|
+
{
|
|
7498
|
+
label: `Font weight: ${item.font.weight} (Enter to toggle)`,
|
|
7499
|
+
currentValue: "",
|
|
7500
|
+
activate: () => dispatch({
|
|
7501
|
+
type: "SET_PDF_TEXT_FONT",
|
|
7502
|
+
pageIndex,
|
|
7503
|
+
itemIndex,
|
|
7504
|
+
font: {
|
|
7505
|
+
...item.font,
|
|
7506
|
+
weight: item.font.weight === "bold" ? "normal" : "bold"
|
|
7507
|
+
}
|
|
7508
|
+
})
|
|
7509
|
+
},
|
|
7510
|
+
{
|
|
7511
|
+
label: `Font style: ${item.font.style} (Enter to toggle)`,
|
|
7512
|
+
currentValue: "",
|
|
7513
|
+
activate: () => dispatch({
|
|
7514
|
+
type: "SET_PDF_TEXT_FONT",
|
|
7515
|
+
pageIndex,
|
|
7516
|
+
itemIndex,
|
|
7517
|
+
font: {
|
|
7518
|
+
...item.font,
|
|
7519
|
+
style: item.font.style === "italic" ? "normal" : "italic"
|
|
7520
|
+
}
|
|
7521
|
+
})
|
|
7522
|
+
},
|
|
7523
|
+
{
|
|
7524
|
+
label: `Size: ${item.sizePt}pt`,
|
|
7525
|
+
currentValue: String(item.sizePt),
|
|
7526
|
+
commit: (raw) => dispatch({
|
|
7527
|
+
type: "SET_PDF_TEXT_SIZE",
|
|
7528
|
+
pageIndex,
|
|
7529
|
+
itemIndex,
|
|
7530
|
+
sizePt: parseNumberField(raw, item.sizePt)
|
|
7531
|
+
})
|
|
7532
|
+
},
|
|
7533
|
+
{
|
|
7534
|
+
label: `Colour: ${formatColor(item.color)}`,
|
|
7535
|
+
currentValue: `${item.color.r} ${item.color.g} ${item.color.b}`,
|
|
7536
|
+
commit: (raw) => dispatch({
|
|
7537
|
+
type: "SET_PDF_TEXT_COLOR",
|
|
7538
|
+
pageIndex,
|
|
7539
|
+
itemIndex,
|
|
7540
|
+
color: parseRequiredColorField(raw, item.color)
|
|
7541
|
+
})
|
|
7542
|
+
},
|
|
7543
|
+
{
|
|
7544
|
+
label: `Width: ${item.widthPt === void 0 ? "unset" : `${item.widthPt}pt`}`,
|
|
7545
|
+
currentValue: item.widthPt === void 0 ? "" : String(item.widthPt),
|
|
7546
|
+
commit: (raw) => dispatch({
|
|
7547
|
+
type: "SET_PDF_TEXT_WIDTH",
|
|
7548
|
+
pageIndex,
|
|
7549
|
+
itemIndex,
|
|
7550
|
+
widthPt: parseOptionalNumberField(raw)
|
|
7551
|
+
})
|
|
7552
|
+
},
|
|
7553
|
+
{
|
|
7554
|
+
label: `Rotation: ${item.rotationDeg === void 0 ? "unset" : `${item.rotationDeg}°`}`,
|
|
7555
|
+
currentValue: item.rotationDeg === void 0 ? "" : String(item.rotationDeg),
|
|
7556
|
+
commit: (raw) => dispatch({
|
|
7557
|
+
type: "SET_PDF_TEXT_ROTATION",
|
|
7558
|
+
pageIndex,
|
|
7559
|
+
itemIndex,
|
|
7560
|
+
rotationDeg: parseOptionalNumberField(raw)
|
|
7561
|
+
})
|
|
7562
|
+
},
|
|
7563
|
+
{
|
|
7564
|
+
label: `Underline: ${item.underline === true ? "yes" : "no"} (Enter to toggle)`,
|
|
7565
|
+
currentValue: "",
|
|
7566
|
+
activate: () => dispatch({
|
|
7567
|
+
type: "TOGGLE_PDF_TEXT_UNDERLINE",
|
|
7568
|
+
pageIndex,
|
|
7569
|
+
itemIndex
|
|
7570
|
+
})
|
|
7571
|
+
}
|
|
7572
|
+
];
|
|
7573
|
+
}
|
|
7574
|
+
function buildRectRows(item, pageIndex, itemIndex, dispatch) {
|
|
7575
|
+
return [...buildFrameRows(item, (frame) => dispatch({
|
|
7576
|
+
type: "SET_PDF_RECT_FRAME",
|
|
7577
|
+
pageIndex,
|
|
7578
|
+
itemIndex,
|
|
7579
|
+
...frame
|
|
7580
|
+
})), ...buildFillStrokeRows(item.fill, item.stroke, (fill) => dispatch({
|
|
7581
|
+
type: "SET_PDF_RECT_FILL",
|
|
7582
|
+
pageIndex,
|
|
7583
|
+
itemIndex,
|
|
7584
|
+
fill
|
|
7585
|
+
}), (stroke) => dispatch({
|
|
7586
|
+
type: "SET_PDF_RECT_STROKE",
|
|
7587
|
+
pageIndex,
|
|
7588
|
+
itemIndex,
|
|
7589
|
+
stroke
|
|
7590
|
+
}))];
|
|
7591
|
+
}
|
|
7592
|
+
function buildEllipseRows(item, pageIndex, itemIndex, dispatch) {
|
|
7593
|
+
return [...buildFrameRows(item, (frame) => dispatch({
|
|
7594
|
+
type: "SET_PDF_ELLIPSE_FRAME",
|
|
7595
|
+
pageIndex,
|
|
7596
|
+
itemIndex,
|
|
7597
|
+
...frame
|
|
7598
|
+
})), ...buildFillStrokeRows(item.fill, item.stroke, (fill) => dispatch({
|
|
7599
|
+
type: "SET_PDF_ELLIPSE_FILL",
|
|
7600
|
+
pageIndex,
|
|
7601
|
+
itemIndex,
|
|
7602
|
+
fill
|
|
7603
|
+
}), (stroke) => dispatch({
|
|
7604
|
+
type: "SET_PDF_ELLIPSE_STROKE",
|
|
7605
|
+
pageIndex,
|
|
7606
|
+
itemIndex,
|
|
7607
|
+
stroke
|
|
7608
|
+
}))];
|
|
7609
|
+
}
|
|
7610
|
+
function buildLineRows(item, pageIndex, itemIndex, dispatch) {
|
|
7611
|
+
return [
|
|
7612
|
+
{
|
|
7613
|
+
label: `From X: ${formatPt(item.x1Pt)}pt`,
|
|
7614
|
+
currentValue: String(item.x1Pt),
|
|
7615
|
+
commit: (raw) => dispatch({
|
|
7616
|
+
type: "SET_PDF_LINE_FROM",
|
|
7617
|
+
pageIndex,
|
|
7618
|
+
itemIndex,
|
|
7619
|
+
x1Pt: parseNumberField(raw, item.x1Pt),
|
|
7620
|
+
y1Pt: item.y1Pt
|
|
7621
|
+
})
|
|
7622
|
+
},
|
|
7623
|
+
{
|
|
7624
|
+
label: `From Y: ${formatPt(item.y1Pt)}pt`,
|
|
7625
|
+
currentValue: String(item.y1Pt),
|
|
7626
|
+
commit: (raw) => dispatch({
|
|
7627
|
+
type: "SET_PDF_LINE_FROM",
|
|
7628
|
+
pageIndex,
|
|
7629
|
+
itemIndex,
|
|
7630
|
+
x1Pt: item.x1Pt,
|
|
7631
|
+
y1Pt: parseNumberField(raw, item.y1Pt)
|
|
7632
|
+
})
|
|
7633
|
+
},
|
|
7634
|
+
{
|
|
7635
|
+
label: `To X: ${formatPt(item.x2Pt)}pt`,
|
|
7636
|
+
currentValue: String(item.x2Pt),
|
|
7637
|
+
commit: (raw) => dispatch({
|
|
7638
|
+
type: "SET_PDF_LINE_TO",
|
|
7639
|
+
pageIndex,
|
|
7640
|
+
itemIndex,
|
|
7641
|
+
x2Pt: parseNumberField(raw, item.x2Pt),
|
|
7642
|
+
y2Pt: item.y2Pt
|
|
7643
|
+
})
|
|
7644
|
+
},
|
|
7645
|
+
{
|
|
7646
|
+
label: `To Y: ${formatPt(item.y2Pt)}pt`,
|
|
7647
|
+
currentValue: String(item.y2Pt),
|
|
7648
|
+
commit: (raw) => dispatch({
|
|
7649
|
+
type: "SET_PDF_LINE_TO",
|
|
7650
|
+
pageIndex,
|
|
7651
|
+
itemIndex,
|
|
7652
|
+
x2Pt: item.x2Pt,
|
|
7653
|
+
y2Pt: parseNumberField(raw, item.y2Pt)
|
|
7654
|
+
})
|
|
7655
|
+
},
|
|
7656
|
+
{
|
|
7657
|
+
label: `Colour: ${formatColor(item.color)}`,
|
|
7658
|
+
currentValue: `${item.color.r} ${item.color.g} ${item.color.b}`,
|
|
7659
|
+
commit: (raw) => dispatch({
|
|
7660
|
+
type: "SET_PDF_LINE_COLOR",
|
|
7661
|
+
pageIndex,
|
|
7662
|
+
itemIndex,
|
|
7663
|
+
color: parseRequiredColorField(raw, item.color)
|
|
7664
|
+
})
|
|
7665
|
+
},
|
|
7666
|
+
{
|
|
7667
|
+
label: `Width: ${item.widthPt}pt`,
|
|
7668
|
+
currentValue: String(item.widthPt),
|
|
7669
|
+
commit: (raw) => dispatch({
|
|
7670
|
+
type: "SET_PDF_LINE_WIDTH",
|
|
7671
|
+
pageIndex,
|
|
7672
|
+
itemIndex,
|
|
7673
|
+
widthPt: Math.max(parseNumberField(raw, item.widthPt), Number.EPSILON)
|
|
7674
|
+
})
|
|
7675
|
+
}
|
|
7676
|
+
];
|
|
7677
|
+
}
|
|
7678
|
+
function buildPathRows(item, pageIndex, itemIndex, dispatch) {
|
|
7679
|
+
return [{
|
|
7680
|
+
label: `Fill rule: ${item.fillRule ?? "nonzero (default)"} (Enter to cycle)`,
|
|
7681
|
+
currentValue: "",
|
|
7682
|
+
activate: () => dispatch({
|
|
7683
|
+
type: "SET_PDF_PATH_FILL_RULE",
|
|
7684
|
+
pageIndex,
|
|
7685
|
+
itemIndex,
|
|
7686
|
+
fillRule: item.fillRule === "evenodd" ? void 0 : item.fillRule === "nonzero" ? "evenodd" : "nonzero"
|
|
7687
|
+
})
|
|
7688
|
+
}, ...buildFillStrokeRows(item.fill, item.stroke, (fill) => dispatch({
|
|
7689
|
+
type: "SET_PDF_PATH_FILL",
|
|
7690
|
+
pageIndex,
|
|
7691
|
+
itemIndex,
|
|
7692
|
+
fill
|
|
7693
|
+
}), (stroke) => dispatch({
|
|
7694
|
+
type: "SET_PDF_PATH_STROKE",
|
|
7695
|
+
pageIndex,
|
|
7696
|
+
itemIndex,
|
|
7697
|
+
stroke
|
|
7698
|
+
}))];
|
|
7699
|
+
}
|
|
7700
|
+
function buildImageRows(item, pageIndex, itemIndex, dispatch, onReplaceImage) {
|
|
7701
|
+
return [
|
|
7702
|
+
...buildFrameRows(item, (frame) => dispatch({
|
|
7703
|
+
type: "SET_PDF_IMAGE_FRAME",
|
|
7704
|
+
pageIndex,
|
|
7705
|
+
itemIndex,
|
|
7706
|
+
...frame
|
|
7707
|
+
})),
|
|
7708
|
+
{
|
|
7709
|
+
label: `Rotation: ${item.rotationDeg === void 0 ? "unset" : `${item.rotationDeg}°`}`,
|
|
7710
|
+
currentValue: item.rotationDeg === void 0 ? "" : String(item.rotationDeg),
|
|
7711
|
+
commit: (raw) => dispatch({
|
|
7712
|
+
type: "SET_PDF_IMAGE_ROTATION",
|
|
7713
|
+
pageIndex,
|
|
7714
|
+
itemIndex,
|
|
7715
|
+
rotationDeg: parseOptionalNumberField(raw)
|
|
7716
|
+
})
|
|
7717
|
+
},
|
|
7718
|
+
{
|
|
7719
|
+
label: "Replace image...",
|
|
7720
|
+
currentValue: "",
|
|
7721
|
+
activate: onReplaceImage
|
|
7722
|
+
}
|
|
7723
|
+
];
|
|
7724
|
+
}
|
|
7725
|
+
function buildLinkRows(item, pageIndex, itemIndex, dispatch) {
|
|
7726
|
+
return [{
|
|
7727
|
+
label: `URI: ${item.uri}`,
|
|
7728
|
+
currentValue: item.uri,
|
|
7729
|
+
commit: (raw) => dispatch({
|
|
7730
|
+
type: "SET_PDF_LINK_URI",
|
|
7731
|
+
pageIndex,
|
|
7732
|
+
itemIndex,
|
|
7733
|
+
uri: raw
|
|
7734
|
+
})
|
|
7735
|
+
}, ...buildFrameRows(item, (frame) => dispatch({
|
|
7736
|
+
type: "SET_PDF_LINK_FRAME",
|
|
7737
|
+
pageIndex,
|
|
7738
|
+
itemIndex,
|
|
7739
|
+
...frame
|
|
7740
|
+
}))];
|
|
7741
|
+
}
|
|
7742
|
+
function buildRowsFor(item, pageIndex, itemIndex, dispatch, onReplaceImage) {
|
|
7743
|
+
switch (item.kind) {
|
|
7744
|
+
case "text": return buildTextRows(item, pageIndex, itemIndex, dispatch);
|
|
7745
|
+
case "rect": return buildRectRows(item, pageIndex, itemIndex, dispatch);
|
|
7746
|
+
case "ellipse": return buildEllipseRows(item, pageIndex, itemIndex, dispatch);
|
|
7747
|
+
case "line": return buildLineRows(item, pageIndex, itemIndex, dispatch);
|
|
7748
|
+
case "path": return buildPathRows(item, pageIndex, itemIndex, dispatch);
|
|
7749
|
+
case "image": return buildImageRows(item, pageIndex, itemIndex, dispatch, onReplaceImage);
|
|
7750
|
+
case "link": return buildLinkRows(item, pageIndex, itemIndex, dispatch);
|
|
7751
|
+
}
|
|
7752
|
+
}
|
|
7753
|
+
function pathSummary(item) {
|
|
7754
|
+
const segmentCount = item.subpaths.reduce((total, subpath) => total + subpath.segments.length, 0);
|
|
7755
|
+
return `${item.subpaths.length} subpath${item.subpaths.length === 1 ? "" : "s"}, ${segmentCount} segment${segmentCount === 1 ? "" : "s"} (not editable here -- see documents.js's own PdfPathItem doc comment)`;
|
|
7756
|
+
}
|
|
7757
|
+
async function applyImageReplace(pageIndex, itemIndex, path, dispatch) {
|
|
7758
|
+
const format = inferImageFormat(path);
|
|
7759
|
+
if (format === void 0) {
|
|
7760
|
+
dispatch({
|
|
7761
|
+
type: "SET_STATUS",
|
|
7762
|
+
severity: "warning",
|
|
7763
|
+
text: `${path} is not a .png or .jpg/.jpeg file -- image not replaced`
|
|
7764
|
+
});
|
|
7765
|
+
return;
|
|
7766
|
+
}
|
|
7767
|
+
try {
|
|
7768
|
+
dispatch({
|
|
7769
|
+
type: "SET_PDF_IMAGE_SOURCE",
|
|
7770
|
+
pageIndex,
|
|
7771
|
+
itemIndex,
|
|
7772
|
+
format,
|
|
7773
|
+
bytes: new Uint8Array(await readInput(path))
|
|
7774
|
+
});
|
|
7775
|
+
} catch (error) {
|
|
7776
|
+
dispatch({
|
|
7777
|
+
type: "SET_STATUS",
|
|
7778
|
+
severity: "error",
|
|
7779
|
+
text: `Could not read ${path}: ${describeError(error)}`
|
|
7780
|
+
});
|
|
7781
|
+
}
|
|
7782
|
+
}
|
|
7783
|
+
function EditableItemDetail(props) {
|
|
7784
|
+
const dispatch = useAppDispatch();
|
|
7785
|
+
const { doc, pageIndex, itemIndex } = props;
|
|
7786
|
+
const [editingField, setEditingField] = useState(void 0);
|
|
7787
|
+
const [draft, setDraft] = useState("");
|
|
7788
|
+
const [replacingImage, setReplacingImage] = useState(false);
|
|
7789
|
+
const item = doc.editor.page(pageIndex)?.items()[itemIndex];
|
|
7790
|
+
const rows = item === void 0 ? [] : buildRowsFor(item, pageIndex, itemIndex, dispatch, () => setReplacingImage(true));
|
|
7791
|
+
const { selectedIndex } = useNavigationInput({
|
|
7792
|
+
itemCount: rows.length,
|
|
7793
|
+
isActive: props.isActive && editingField === void 0 && !replacingImage,
|
|
7794
|
+
onBack: () => {
|
|
7795
|
+
dispatch({ type: "POP_SCREEN" });
|
|
7796
|
+
},
|
|
7797
|
+
onSelect: (index) => {
|
|
7798
|
+
const row = rows[index];
|
|
7799
|
+
if (row === void 0) return;
|
|
7800
|
+
if (row.activate !== void 0) {
|
|
7801
|
+
row.activate();
|
|
7802
|
+
return;
|
|
7803
|
+
}
|
|
7804
|
+
setDraft(row.currentValue);
|
|
7805
|
+
setEditingField(index);
|
|
7806
|
+
}
|
|
7807
|
+
});
|
|
7808
|
+
if (item === void 0) return /* @__PURE__ */ jsxs(Box, {
|
|
7809
|
+
flexDirection: "column",
|
|
7810
|
+
children: [/* @__PURE__ */ jsxs(Text, {
|
|
7811
|
+
color: "yellow",
|
|
7812
|
+
children: [
|
|
7813
|
+
"There is no item ",
|
|
7814
|
+
itemIndex + 1,
|
|
7815
|
+
" on page ",
|
|
7816
|
+
pageIndex + 1,
|
|
7817
|
+
" any more."
|
|
7272
7818
|
]
|
|
7819
|
+
}), /* @__PURE__ */ jsx(Text, {
|
|
7820
|
+
dimColor: true,
|
|
7821
|
+
children: "Esc to go back"
|
|
7822
|
+
})]
|
|
7823
|
+
});
|
|
7824
|
+
if (replacingImage) return /* @__PURE__ */ jsx(FieldWizard, {
|
|
7825
|
+
fields: [{
|
|
7826
|
+
key: "path",
|
|
7827
|
+
label: "Image file path (.png/.jpg/.jpeg)",
|
|
7828
|
+
defaultValue: ""
|
|
7829
|
+
}],
|
|
7830
|
+
onCancel: () => {
|
|
7831
|
+
setReplacingImage(false);
|
|
7832
|
+
},
|
|
7833
|
+
onComplete: (values) => {
|
|
7834
|
+
applyImageReplace(pageIndex, itemIndex, requireFieldValue(values, "path"), dispatch).then(() => {
|
|
7835
|
+
setReplacingImage(false);
|
|
7836
|
+
});
|
|
7837
|
+
}
|
|
7838
|
+
});
|
|
7839
|
+
if (editingField !== void 0) {
|
|
7840
|
+
const row = rows[editingField];
|
|
7841
|
+
if (row === void 0) throw new Error(`EditableItemDetail 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.`);
|
|
7842
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
7843
|
+
flexDirection: "column",
|
|
7844
|
+
borderStyle: "round",
|
|
7845
|
+
paddingX: 1,
|
|
7846
|
+
children: [/* @__PURE__ */ jsx(Text, {
|
|
7847
|
+
bold: true,
|
|
7848
|
+
children: row.label
|
|
7849
|
+
}), /* @__PURE__ */ jsx(TextField, {
|
|
7850
|
+
value: draft,
|
|
7851
|
+
isFocused: true,
|
|
7852
|
+
onChange: setDraft,
|
|
7853
|
+
onCancel: () => {
|
|
7854
|
+
setEditingField(void 0);
|
|
7855
|
+
},
|
|
7856
|
+
onSubmit: (value) => {
|
|
7857
|
+
row.commit?.(value);
|
|
7858
|
+
setEditingField(void 0);
|
|
7859
|
+
}
|
|
7860
|
+
})]
|
|
7861
|
+
});
|
|
7862
|
+
}
|
|
7863
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
7864
|
+
flexDirection: "column",
|
|
7865
|
+
children: [
|
|
7866
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
7867
|
+
bold: true,
|
|
7868
|
+
children: [
|
|
7869
|
+
"Page ",
|
|
7870
|
+
pageIndex + 1,
|
|
7871
|
+
", item ",
|
|
7872
|
+
itemIndex + 1,
|
|
7873
|
+
" -- ",
|
|
7874
|
+
item.kind
|
|
7875
|
+
]
|
|
7876
|
+
}),
|
|
7877
|
+
item.kind === "path" && /* @__PURE__ */ jsx(Text, {
|
|
7878
|
+
dimColor: true,
|
|
7879
|
+
children: pathSummary(item)
|
|
7880
|
+
}),
|
|
7881
|
+
item.kind === "image" && /* @__PURE__ */ jsxs(Text, {
|
|
7882
|
+
dimColor: true,
|
|
7883
|
+
children: ["Image ID: ", item.imageId]
|
|
7884
|
+
}),
|
|
7885
|
+
/* @__PURE__ */ jsx(ListView, {
|
|
7886
|
+
items: rows,
|
|
7887
|
+
selectedIndex,
|
|
7888
|
+
reservedRows: 5,
|
|
7889
|
+
renderItem: (row, isSelected) => /* @__PURE__ */ jsx(Text, {
|
|
7890
|
+
color: isSelected ? "cyan" : void 0,
|
|
7891
|
+
inverse: isSelected,
|
|
7892
|
+
children: row.label
|
|
7893
|
+
})
|
|
7894
|
+
}),
|
|
7895
|
+
/* @__PURE__ */ jsx(Text, {
|
|
7896
|
+
dimColor: true,
|
|
7897
|
+
children: "Enter to edit a field, Esc to go back"
|
|
7898
|
+
})
|
|
7899
|
+
]
|
|
7900
|
+
});
|
|
7901
|
+
}
|
|
7902
|
+
function PdfItemDetailScreen() {
|
|
7903
|
+
const state = useAppState();
|
|
7904
|
+
const dispatch = useAppDispatch();
|
|
7905
|
+
const doc = requirePdfDocument(state.openDocument);
|
|
7906
|
+
const screen = currentScreen(state);
|
|
7907
|
+
if (screen.kind !== "pdfItemDetail") throw new Error(`PdfItemDetailScreen rendered while the current screen is "${screen.kind}", not "pdfItemDetail".`);
|
|
7908
|
+
const isActive = !anyOverlayOpen(state);
|
|
7909
|
+
if (!isEditablePdfDocument(doc)) {
|
|
7910
|
+
const page = doc.layout.pages[screen.pageIndex];
|
|
7911
|
+
if (page === void 0) throw new Error(`pdfItemDetail was pushed for page ${screen.pageIndex}, but the open PDF has no page at that index.`);
|
|
7912
|
+
const item = page.items[screen.itemIndex];
|
|
7913
|
+
if (item === void 0) throw new Error(`pdfItemDetail was pushed for item ${screen.itemIndex} on page ${screen.pageIndex}, but that page has no item at that index.`);
|
|
7914
|
+
return /* @__PURE__ */ jsx(ReadOnlyItemDetail, {
|
|
7915
|
+
item,
|
|
7916
|
+
pageIndex: screen.pageIndex,
|
|
7917
|
+
itemIndex: screen.itemIndex,
|
|
7918
|
+
isActive,
|
|
7919
|
+
onBack: () => {
|
|
7920
|
+
dispatch({ type: "POP_SCREEN" });
|
|
7921
|
+
}
|
|
7922
|
+
});
|
|
7923
|
+
}
|
|
7924
|
+
return /* @__PURE__ */ jsx(EditableItemDetail, {
|
|
7925
|
+
doc,
|
|
7926
|
+
pageIndex: screen.pageIndex,
|
|
7927
|
+
itemIndex: screen.itemIndex,
|
|
7928
|
+
isActive
|
|
7929
|
+
});
|
|
7930
|
+
}
|
|
7931
|
+
//#endregion
|
|
7932
|
+
//#region src/tui/screens/editors/pdf/page-items.tsx
|
|
7933
|
+
const TEXT_PREVIEW_MAX_CHARS = 48;
|
|
7934
|
+
function truncate(text, maxChars) {
|
|
7935
|
+
return text.length > maxChars ? `${text.slice(0, maxChars)}…` : text;
|
|
7936
|
+
}
|
|
7937
|
+
function pathDimensions(item) {
|
|
7938
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
7939
|
+
let minY = Number.POSITIVE_INFINITY;
|
|
7940
|
+
let maxX = Number.NEGATIVE_INFINITY;
|
|
7941
|
+
let maxY = Number.NEGATIVE_INFINITY;
|
|
7942
|
+
const consider = (xPt, yPt) => {
|
|
7943
|
+
minX = Math.min(minX, xPt);
|
|
7944
|
+
minY = Math.min(minY, yPt);
|
|
7945
|
+
maxX = Math.max(maxX, xPt);
|
|
7946
|
+
maxY = Math.max(maxY, yPt);
|
|
7947
|
+
};
|
|
7948
|
+
for (const subpath of item.subpaths) {
|
|
7949
|
+
consider(subpath.startXPt, subpath.startYPt);
|
|
7950
|
+
for (const segment of subpath.segments) {
|
|
7951
|
+
if (segment.kind === "cubic") {
|
|
7952
|
+
consider(segment.c1xPt, segment.c1yPt);
|
|
7953
|
+
consider(segment.c2xPt, segment.c2yPt);
|
|
7954
|
+
}
|
|
7955
|
+
consider(segment.xPt, segment.yPt);
|
|
7956
|
+
}
|
|
7957
|
+
}
|
|
7958
|
+
if (minX > maxX) return "empty path";
|
|
7959
|
+
return formatSize(maxX - minX, maxY - minY);
|
|
7960
|
+
}
|
|
7961
|
+
function previewFor(item) {
|
|
7962
|
+
switch (item.kind) {
|
|
7963
|
+
case "text": return truncate(item.text, TEXT_PREVIEW_MAX_CHARS);
|
|
7964
|
+
case "link": return item.uri;
|
|
7965
|
+
case "image":
|
|
7966
|
+
case "rect":
|
|
7967
|
+
case "ellipse": return formatSize(item.widthPt, item.heightPt);
|
|
7968
|
+
case "line": return formatSize(Math.abs(item.x2Pt - item.x1Pt), Math.abs(item.y2Pt - item.y1Pt));
|
|
7969
|
+
case "path": return pathDimensions(item);
|
|
7970
|
+
}
|
|
7971
|
+
}
|
|
7972
|
+
const ADD_KIND_OPTIONS = [
|
|
7973
|
+
{
|
|
7974
|
+
kind: "text",
|
|
7975
|
+
label: "Text"
|
|
7976
|
+
},
|
|
7977
|
+
{
|
|
7978
|
+
kind: "rect",
|
|
7979
|
+
label: "Rectangle"
|
|
7980
|
+
},
|
|
7981
|
+
{
|
|
7982
|
+
kind: "ellipse",
|
|
7983
|
+
label: "Ellipse"
|
|
7984
|
+
},
|
|
7985
|
+
{
|
|
7986
|
+
kind: "line",
|
|
7987
|
+
label: "Line"
|
|
7988
|
+
},
|
|
7989
|
+
{
|
|
7990
|
+
kind: "path",
|
|
7991
|
+
label: "Path (fixed triangle shape)"
|
|
7992
|
+
},
|
|
7993
|
+
{
|
|
7994
|
+
kind: "image",
|
|
7995
|
+
label: "Image"
|
|
7996
|
+
},
|
|
7997
|
+
{
|
|
7998
|
+
kind: "link",
|
|
7999
|
+
label: "Link"
|
|
8000
|
+
}
|
|
8001
|
+
];
|
|
8002
|
+
const GEOMETRY_FIELDS = [
|
|
8003
|
+
{
|
|
8004
|
+
key: "xPt",
|
|
8005
|
+
label: "X (pt)",
|
|
8006
|
+
defaultValue: "40"
|
|
8007
|
+
},
|
|
8008
|
+
{
|
|
8009
|
+
key: "yPt",
|
|
8010
|
+
label: "Y (pt)",
|
|
8011
|
+
defaultValue: "40"
|
|
8012
|
+
},
|
|
8013
|
+
{
|
|
8014
|
+
key: "widthPt",
|
|
8015
|
+
label: "Width (pt)",
|
|
8016
|
+
defaultValue: "160"
|
|
8017
|
+
},
|
|
8018
|
+
{
|
|
8019
|
+
key: "heightPt",
|
|
8020
|
+
label: "Height (pt)",
|
|
8021
|
+
defaultValue: "100"
|
|
8022
|
+
}
|
|
8023
|
+
];
|
|
8024
|
+
const FILL_FIELD = {
|
|
8025
|
+
key: "fill",
|
|
8026
|
+
label: "Fill \"r g b\" (0-1 each), blank for none",
|
|
8027
|
+
defaultValue: "0.8 0.8 0.8"
|
|
8028
|
+
};
|
|
8029
|
+
const STROKE_FIELD = {
|
|
8030
|
+
key: "stroke",
|
|
8031
|
+
label: "Stroke \"r g b widthPt\" (0-1 colour, pt width), blank for none",
|
|
8032
|
+
defaultValue: "0 0 0 1"
|
|
8033
|
+
};
|
|
8034
|
+
const REQUIRED_COLOR_FIELD = {
|
|
8035
|
+
key: "color",
|
|
8036
|
+
label: "Colour \"r g b\" (0-1 each)",
|
|
8037
|
+
defaultValue: "0 0 0"
|
|
8038
|
+
};
|
|
8039
|
+
function fieldsForAddKind(kind) {
|
|
8040
|
+
switch (kind) {
|
|
8041
|
+
case "text": return [
|
|
8042
|
+
{
|
|
8043
|
+
key: "xPt",
|
|
8044
|
+
label: "X (pt)",
|
|
8045
|
+
defaultValue: "40"
|
|
8046
|
+
},
|
|
8047
|
+
{
|
|
8048
|
+
key: "yPt",
|
|
8049
|
+
label: "Y (pt)",
|
|
8050
|
+
defaultValue: "40"
|
|
8051
|
+
},
|
|
8052
|
+
{
|
|
8053
|
+
key: "text",
|
|
8054
|
+
label: "Text",
|
|
8055
|
+
defaultValue: "Text"
|
|
8056
|
+
},
|
|
8057
|
+
{
|
|
8058
|
+
key: "fontFamily",
|
|
8059
|
+
label: "Font family",
|
|
8060
|
+
defaultValue: "Helvetica"
|
|
8061
|
+
},
|
|
8062
|
+
{
|
|
8063
|
+
key: "fontWeight",
|
|
8064
|
+
label: "Font weight (normal/bold)",
|
|
8065
|
+
defaultValue: "normal"
|
|
8066
|
+
},
|
|
8067
|
+
{
|
|
8068
|
+
key: "fontStyle",
|
|
8069
|
+
label: "Font style (normal/italic)",
|
|
8070
|
+
defaultValue: "normal"
|
|
8071
|
+
},
|
|
8072
|
+
{
|
|
8073
|
+
key: "sizePt",
|
|
8074
|
+
label: "Size (pt)",
|
|
8075
|
+
defaultValue: "12"
|
|
8076
|
+
},
|
|
8077
|
+
REQUIRED_COLOR_FIELD
|
|
8078
|
+
];
|
|
8079
|
+
case "rect":
|
|
8080
|
+
case "ellipse":
|
|
8081
|
+
case "path": return [
|
|
8082
|
+
...GEOMETRY_FIELDS,
|
|
8083
|
+
FILL_FIELD,
|
|
8084
|
+
STROKE_FIELD
|
|
8085
|
+
];
|
|
8086
|
+
case "line": return [
|
|
8087
|
+
{
|
|
8088
|
+
key: "fromXPt",
|
|
8089
|
+
label: "From X (pt)",
|
|
8090
|
+
defaultValue: "40"
|
|
8091
|
+
},
|
|
8092
|
+
{
|
|
8093
|
+
key: "fromYPt",
|
|
8094
|
+
label: "From Y (pt)",
|
|
8095
|
+
defaultValue: "40"
|
|
8096
|
+
},
|
|
8097
|
+
{
|
|
8098
|
+
key: "toXPt",
|
|
8099
|
+
label: "To X (pt)",
|
|
8100
|
+
defaultValue: "200"
|
|
8101
|
+
},
|
|
8102
|
+
{
|
|
8103
|
+
key: "toYPt",
|
|
8104
|
+
label: "To Y (pt)",
|
|
8105
|
+
defaultValue: "40"
|
|
8106
|
+
},
|
|
8107
|
+
REQUIRED_COLOR_FIELD,
|
|
8108
|
+
{
|
|
8109
|
+
key: "widthPt",
|
|
8110
|
+
label: "Width (pt)",
|
|
8111
|
+
defaultValue: "1"
|
|
8112
|
+
}
|
|
8113
|
+
];
|
|
8114
|
+
case "image": return [...GEOMETRY_FIELDS, {
|
|
8115
|
+
key: "path",
|
|
8116
|
+
label: "Image file path (.png/.jpg/.jpeg)",
|
|
8117
|
+
defaultValue: ""
|
|
8118
|
+
}];
|
|
8119
|
+
case "link": return [{
|
|
8120
|
+
key: "uri",
|
|
8121
|
+
label: "URI",
|
|
8122
|
+
defaultValue: "https://example.com"
|
|
8123
|
+
}, ...GEOMETRY_FIELDS];
|
|
8124
|
+
}
|
|
8125
|
+
}
|
|
8126
|
+
function readFrame(values) {
|
|
8127
|
+
return {
|
|
8128
|
+
xPt: parseNumberField(requireFieldValue(values, "xPt"), 0),
|
|
8129
|
+
yPt: parseNumberField(requireFieldValue(values, "yPt"), 0),
|
|
8130
|
+
widthPt: parseNumberField(requireFieldValue(values, "widthPt"), 100),
|
|
8131
|
+
heightPt: parseNumberField(requireFieldValue(values, "heightPt"), 60)
|
|
8132
|
+
};
|
|
8133
|
+
}
|
|
8134
|
+
async function applyAddKind(kind, pageIndex, values, dispatch) {
|
|
8135
|
+
switch (kind) {
|
|
8136
|
+
case "text":
|
|
8137
|
+
dispatch({
|
|
8138
|
+
type: "ADD_PDF_TEXT",
|
|
8139
|
+
pageIndex,
|
|
8140
|
+
init: {
|
|
8141
|
+
xPt: parseNumberField(requireFieldValue(values, "xPt"), 0),
|
|
8142
|
+
yPt: parseNumberField(requireFieldValue(values, "yPt"), 0),
|
|
8143
|
+
text: requireFieldValue(values, "text"),
|
|
8144
|
+
font: {
|
|
8145
|
+
family: requireFieldValue(values, "fontFamily").trim() || "Helvetica",
|
|
8146
|
+
weight: parseFontWeight(requireFieldValue(values, "fontWeight")),
|
|
8147
|
+
style: parseFontStyle(requireFieldValue(values, "fontStyle"))
|
|
8148
|
+
},
|
|
8149
|
+
sizePt: Math.max(parseNumberField(requireFieldValue(values, "sizePt"), 12), Number.EPSILON),
|
|
8150
|
+
color: parseColorField(requireFieldValue(values, "color")) ?? {
|
|
8151
|
+
r: 0,
|
|
8152
|
+
g: 0,
|
|
8153
|
+
b: 0
|
|
8154
|
+
}
|
|
8155
|
+
}
|
|
8156
|
+
});
|
|
8157
|
+
return;
|
|
8158
|
+
case "rect":
|
|
8159
|
+
dispatch({
|
|
8160
|
+
type: "ADD_PDF_RECT",
|
|
8161
|
+
pageIndex,
|
|
8162
|
+
init: {
|
|
8163
|
+
...readFrame(values),
|
|
8164
|
+
fill: parseColorField(requireFieldValue(values, "fill")),
|
|
8165
|
+
stroke: parseStrokeField(requireFieldValue(values, "stroke"))
|
|
8166
|
+
}
|
|
8167
|
+
});
|
|
8168
|
+
return;
|
|
8169
|
+
case "ellipse":
|
|
8170
|
+
dispatch({
|
|
8171
|
+
type: "ADD_PDF_ELLIPSE",
|
|
8172
|
+
pageIndex,
|
|
8173
|
+
init: {
|
|
8174
|
+
...readFrame(values),
|
|
8175
|
+
fill: parseColorField(requireFieldValue(values, "fill")),
|
|
8176
|
+
stroke: parseStrokeField(requireFieldValue(values, "stroke"))
|
|
8177
|
+
}
|
|
8178
|
+
});
|
|
8179
|
+
return;
|
|
8180
|
+
case "line":
|
|
8181
|
+
dispatch({
|
|
8182
|
+
type: "ADD_PDF_LINE",
|
|
8183
|
+
pageIndex,
|
|
8184
|
+
init: {
|
|
8185
|
+
x1Pt: parseNumberField(requireFieldValue(values, "fromXPt"), 0),
|
|
8186
|
+
y1Pt: parseNumberField(requireFieldValue(values, "fromYPt"), 0),
|
|
8187
|
+
x2Pt: parseNumberField(requireFieldValue(values, "toXPt"), 100),
|
|
8188
|
+
y2Pt: parseNumberField(requireFieldValue(values, "toYPt"), 0),
|
|
8189
|
+
color: parseColorField(requireFieldValue(values, "color")) ?? {
|
|
8190
|
+
r: 0,
|
|
8191
|
+
g: 0,
|
|
8192
|
+
b: 0
|
|
8193
|
+
},
|
|
8194
|
+
widthPt: Math.max(parseNumberField(requireFieldValue(values, "widthPt"), 1), Number.EPSILON)
|
|
8195
|
+
}
|
|
8196
|
+
});
|
|
8197
|
+
return;
|
|
8198
|
+
case "path": {
|
|
8199
|
+
const frame = readFrame(values);
|
|
8200
|
+
dispatch({
|
|
8201
|
+
type: "ADD_PDF_PATH",
|
|
8202
|
+
pageIndex,
|
|
8203
|
+
init: {
|
|
8204
|
+
subpaths: defaultTriangleLayoutSubpaths(frame.widthPt, frame.heightPt),
|
|
8205
|
+
fill: parseColorField(requireFieldValue(values, "fill")),
|
|
8206
|
+
stroke: parseStrokeField(requireFieldValue(values, "stroke"))
|
|
8207
|
+
}
|
|
8208
|
+
});
|
|
8209
|
+
return;
|
|
8210
|
+
}
|
|
8211
|
+
case "image": {
|
|
8212
|
+
const frame = readFrame(values);
|
|
8213
|
+
const path = requireFieldValue(values, "path");
|
|
8214
|
+
const format = inferImageFormat(path);
|
|
8215
|
+
if (format === void 0) {
|
|
8216
|
+
dispatch({
|
|
8217
|
+
type: "SET_STATUS",
|
|
8218
|
+
severity: "warning",
|
|
8219
|
+
text: `${path} is not a .png or .jpg/.jpeg file -- image not added`
|
|
8220
|
+
});
|
|
8221
|
+
return;
|
|
8222
|
+
}
|
|
8223
|
+
try {
|
|
8224
|
+
const bytes = new Uint8Array(await readInput(path));
|
|
8225
|
+
dispatch({
|
|
8226
|
+
type: "ADD_PDF_IMAGE",
|
|
8227
|
+
pageIndex,
|
|
8228
|
+
init: {
|
|
8229
|
+
...frame,
|
|
8230
|
+
format,
|
|
8231
|
+
bytes
|
|
8232
|
+
}
|
|
8233
|
+
});
|
|
8234
|
+
} catch (error) {
|
|
8235
|
+
dispatch({
|
|
8236
|
+
type: "SET_STATUS",
|
|
8237
|
+
severity: "error",
|
|
8238
|
+
text: `Could not read ${path}: ${describeError(error)}`
|
|
8239
|
+
});
|
|
8240
|
+
}
|
|
8241
|
+
return;
|
|
8242
|
+
}
|
|
8243
|
+
case "link": {
|
|
8244
|
+
const frame = readFrame(values);
|
|
8245
|
+
dispatch({
|
|
8246
|
+
type: "ADD_PDF_LINK",
|
|
8247
|
+
pageIndex,
|
|
8248
|
+
init: {
|
|
8249
|
+
uri: requireFieldValue(values, "uri"),
|
|
8250
|
+
...frame
|
|
8251
|
+
}
|
|
8252
|
+
});
|
|
8253
|
+
return;
|
|
8254
|
+
}
|
|
8255
|
+
}
|
|
8256
|
+
}
|
|
8257
|
+
function AddItemFlow(props) {
|
|
8258
|
+
const dispatch = useAppDispatch();
|
|
8259
|
+
const [kind, setKind] = useState(void 0);
|
|
8260
|
+
const { selectedIndex } = useNavigationInput({
|
|
8261
|
+
itemCount: ADD_KIND_OPTIONS.length,
|
|
8262
|
+
isActive: props.isActive && kind === void 0,
|
|
8263
|
+
onBack: props.onCancel,
|
|
8264
|
+
onSelect: (index) => {
|
|
8265
|
+
const option = ADD_KIND_OPTIONS[index];
|
|
8266
|
+
if (option === void 0) return;
|
|
8267
|
+
setKind(option.kind);
|
|
8268
|
+
}
|
|
8269
|
+
});
|
|
8270
|
+
if (kind === void 0) return /* @__PURE__ */ jsxs(Box, {
|
|
8271
|
+
flexDirection: "column",
|
|
8272
|
+
borderStyle: "round",
|
|
8273
|
+
paddingX: 1,
|
|
8274
|
+
children: [/* @__PURE__ */ jsx(Text, {
|
|
8275
|
+
bold: true,
|
|
8276
|
+
children: "Add item -- choose a kind"
|
|
7273
8277
|
}), /* @__PURE__ */ jsx(ListView, {
|
|
7274
|
-
items,
|
|
8278
|
+
items: ADD_KIND_OPTIONS,
|
|
7275
8279
|
selectedIndex,
|
|
7276
|
-
|
|
7277
|
-
renderItem: (
|
|
8280
|
+
reservedRows: 6,
|
|
8281
|
+
renderItem: (option, isSelected) => /* @__PURE__ */ jsxs(Text, {
|
|
7278
8282
|
color: isSelected ? "cyan" : void 0,
|
|
7279
|
-
|
|
8283
|
+
children: [isSelected ? "> " : " ", option.label]
|
|
8284
|
+
})
|
|
8285
|
+
})]
|
|
8286
|
+
});
|
|
8287
|
+
return /* @__PURE__ */ jsx(FieldWizard, {
|
|
8288
|
+
fields: fieldsForAddKind(kind),
|
|
8289
|
+
onCancel: props.onCancel,
|
|
8290
|
+
onComplete: (values) => {
|
|
8291
|
+
applyAddKind(kind, props.pageIndex, values, dispatch).then(props.onCreated);
|
|
8292
|
+
}
|
|
8293
|
+
});
|
|
8294
|
+
}
|
|
8295
|
+
function PdfPageItemsScreen() {
|
|
8296
|
+
const state = useAppState();
|
|
8297
|
+
const dispatch = useAppDispatch();
|
|
8298
|
+
const doc = requirePdfDocument(state.openDocument);
|
|
8299
|
+
const editable = isEditablePdfDocument(doc);
|
|
8300
|
+
const screen = currentScreen(state);
|
|
8301
|
+
if (screen.kind !== "pdfPageItems") throw new Error(`PdfPageItemsScreen rendered while the current screen is "${screen.kind}", not "pdfPageItems".`);
|
|
8302
|
+
const page = doc.layout.pages[screen.pageIndex];
|
|
8303
|
+
if (page === void 0) throw new Error(`pdfPageItems was pushed for page ${screen.pageIndex}, but the open PDF has no page at that index.`);
|
|
8304
|
+
const [isAdding, setIsAdding] = useState(false);
|
|
8305
|
+
const overlayOpen = anyOverlayOpen(state);
|
|
8306
|
+
const query = state.searchQuery.trim().toLowerCase();
|
|
8307
|
+
const indexed = page.items.map((item, itemIndex) => ({
|
|
8308
|
+
item,
|
|
8309
|
+
itemIndex
|
|
8310
|
+
}));
|
|
8311
|
+
const items = query === "" ? indexed : indexed.filter((entry) => `${entry.item.kind} ${previewFor(entry.item)}`.toLowerCase().includes(query));
|
|
8312
|
+
const { selectedIndex } = useNavigationInput({
|
|
8313
|
+
itemCount: items.length,
|
|
8314
|
+
isActive: !overlayOpen && !isAdding,
|
|
8315
|
+
onSelect: (index) => {
|
|
8316
|
+
const entry = items[index];
|
|
8317
|
+
if (entry === void 0) return;
|
|
8318
|
+
dispatch({
|
|
8319
|
+
type: "PUSH_SCREEN",
|
|
8320
|
+
screen: {
|
|
8321
|
+
kind: "pdfItemDetail",
|
|
8322
|
+
pageIndex: screen.pageIndex,
|
|
8323
|
+
itemIndex: entry.itemIndex
|
|
8324
|
+
}
|
|
8325
|
+
});
|
|
8326
|
+
},
|
|
8327
|
+
onBack: () => {
|
|
8328
|
+
dispatch({ type: "POP_SCREEN" });
|
|
8329
|
+
},
|
|
8330
|
+
onAppend: editable ? () => {
|
|
8331
|
+
setIsAdding(true);
|
|
8332
|
+
} : void 0
|
|
8333
|
+
});
|
|
8334
|
+
useInput((input) => {
|
|
8335
|
+
if (input !== "d") return;
|
|
8336
|
+
const entry = items[selectedIndex];
|
|
8337
|
+
if (entry === void 0) return;
|
|
8338
|
+
dispatch({
|
|
8339
|
+
type: "REMOVE_PDF_ITEM",
|
|
8340
|
+
pageIndex: screen.pageIndex,
|
|
8341
|
+
itemIndex: entry.itemIndex
|
|
8342
|
+
});
|
|
8343
|
+
}, { isActive: editable && !overlayOpen && !isAdding && items.length > 0 });
|
|
8344
|
+
if (isAdding) return /* @__PURE__ */ jsx(AddItemFlow, {
|
|
8345
|
+
pageIndex: screen.pageIndex,
|
|
8346
|
+
isActive: !overlayOpen,
|
|
8347
|
+
onCancel: () => {
|
|
8348
|
+
setIsAdding(false);
|
|
8349
|
+
},
|
|
8350
|
+
onCreated: () => {
|
|
8351
|
+
setIsAdding(false);
|
|
8352
|
+
}
|
|
8353
|
+
});
|
|
8354
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
8355
|
+
flexDirection: "column",
|
|
8356
|
+
children: [
|
|
8357
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
8358
|
+
bold: true,
|
|
7280
8359
|
children: [
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
8360
|
+
"Page ",
|
|
8361
|
+
screen.pageIndex + 1,
|
|
8362
|
+
" items (",
|
|
8363
|
+
items.length,
|
|
8364
|
+
" of ",
|
|
8365
|
+
page.items.length,
|
|
8366
|
+
")"
|
|
7286
8367
|
]
|
|
8368
|
+
}),
|
|
8369
|
+
/* @__PURE__ */ jsx(ListView, {
|
|
8370
|
+
items,
|
|
8371
|
+
selectedIndex,
|
|
8372
|
+
emptyMessage: query === "" ? editable ? "This page has no items -- press 'a' to add one" : "This page has no items." : `No items match "${state.searchQuery}".`,
|
|
8373
|
+
renderItem: ({ item, itemIndex }, isSelected) => /* @__PURE__ */ jsxs(Text, {
|
|
8374
|
+
color: isSelected ? "cyan" : void 0,
|
|
8375
|
+
inverse: isSelected,
|
|
8376
|
+
children: [
|
|
8377
|
+
itemIndex + 1,
|
|
8378
|
+
". ",
|
|
8379
|
+
item.kind,
|
|
8380
|
+
" -- ",
|
|
8381
|
+
previewFor(item)
|
|
8382
|
+
]
|
|
8383
|
+
})
|
|
8384
|
+
}),
|
|
8385
|
+
editable && /* @__PURE__ */ jsx(Text, {
|
|
8386
|
+
dimColor: true,
|
|
8387
|
+
children: "a to add an item, d to delete the selected item"
|
|
7287
8388
|
})
|
|
7288
|
-
|
|
8389
|
+
]
|
|
7289
8390
|
});
|
|
7290
8391
|
}
|
|
7291
8392
|
//#endregion
|