@pixerate/editor 0.23.0 → 0.24.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/README.md +96 -1
- package/THIRD_PARTY_NOTICES.md +51 -0
- package/dist/agent/index.cjs +9 -8
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +4 -3
- package/dist/agent/index.d.ts +4 -3
- package/dist/agent/index.js +3 -2
- package/dist/agent/index.js.map +1 -1
- package/dist/canvas/index.cjs +1210 -17
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +318 -1
- package/dist/canvas/index.d.ts +318 -1
- package/dist/canvas/index.js +1199 -6
- package/dist/canvas/index.js.map +1 -1
- package/dist/{chunk-QBJ22YZR.js → chunk-3CN2WD3X.js} +1354 -206
- package/dist/chunk-3CN2WD3X.js.map +1 -0
- package/dist/{chunk-JJDLPEWL.js → chunk-3LV6RRPH.js} +2 -2
- package/dist/{chunk-MJZBNWG7.js → chunk-5S3Z4PPF.js} +78 -557
- package/dist/chunk-5S3Z4PPF.js.map +1 -0
- package/dist/chunk-664LQYFJ.js +115 -0
- package/dist/chunk-664LQYFJ.js.map +1 -0
- package/dist/{chunk-AA4ZEVCC.cjs → chunk-D27YFC46.cjs} +101 -580
- package/dist/chunk-D27YFC46.cjs.map +1 -0
- package/dist/chunk-D6FH2YAX.cjs +131 -0
- package/dist/chunk-D6FH2YAX.cjs.map +1 -0
- package/dist/{chunk-4SUNJZWB.cjs → chunk-FD4LPFAE.cjs} +48 -200
- package/dist/chunk-FD4LPFAE.cjs.map +1 -0
- package/dist/chunk-FODNLX5N.js +749 -0
- package/dist/chunk-FODNLX5N.js.map +1 -0
- package/dist/{chunk-OYXSKQFR.js → chunk-FPENXAEJ.js} +35 -187
- package/dist/chunk-FPENXAEJ.js.map +1 -0
- package/dist/chunk-HLIMTC6N.js +1 -0
- package/dist/chunk-HLIMTC6N.js.map +1 -0
- package/dist/{chunk-QGHGJ56O.js → chunk-ITBSKI26.js} +1483 -19
- package/dist/chunk-ITBSKI26.js.map +1 -0
- package/dist/{chunk-XDMXXC4Z.cjs → chunk-MA2F5KHF.cjs} +350 -227
- package/dist/chunk-MA2F5KHF.cjs.map +1 -0
- package/dist/{chunk-RIKBJLS2.cjs → chunk-MCSJFWAO.cjs} +1356 -208
- package/dist/chunk-MCSJFWAO.cjs.map +1 -0
- package/dist/chunk-MKA3AHLV.cjs +256 -0
- package/dist/chunk-MKA3AHLV.cjs.map +1 -0
- package/dist/chunk-OLZJXL4R.cjs +749 -0
- package/dist/chunk-OLZJXL4R.cjs.map +1 -0
- package/dist/chunk-OXSV64JX.js +689 -0
- package/dist/chunk-OXSV64JX.js.map +1 -0
- package/dist/chunk-P3RQ5UJE.cjs +689 -0
- package/dist/chunk-P3RQ5UJE.cjs.map +1 -0
- package/dist/chunk-P6ODPZ4W.js +256 -0
- package/dist/chunk-P6ODPZ4W.js.map +1 -0
- package/dist/chunk-PGNZKFQS.js +685 -0
- package/dist/chunk-PGNZKFQS.js.map +1 -0
- package/dist/chunk-PL4JB3BF.cjs +1 -0
- package/dist/chunk-PL4JB3BF.cjs.map +1 -0
- package/dist/{chunk-GVSMRPHB.cjs → chunk-SBCZ6RN5.cjs} +1568 -104
- package/dist/chunk-SBCZ6RN5.cjs.map +1 -0
- package/dist/{chunk-CL37JGFW.cjs → chunk-SML64VJG.cjs} +4 -4
- package/dist/{chunk-CL37JGFW.cjs.map → chunk-SML64VJG.cjs.map} +1 -1
- package/dist/chunk-TNNJXF46.cjs +115 -0
- package/dist/chunk-TNNJXF46.cjs.map +1 -0
- package/dist/chunk-U5HZSFCS.js +131 -0
- package/dist/chunk-U5HZSFCS.js.map +1 -0
- package/dist/{chunk-K3R5NG2D.js → chunk-U5KWZU4X.js} +251 -128
- package/dist/chunk-U5KWZU4X.js.map +1 -0
- package/dist/chunk-XNORY7M6.cjs +685 -0
- package/dist/chunk-XNORY7M6.cjs.map +1 -0
- package/dist/commands/index.d.cts +5 -353
- package/dist/commands/index.d.ts +5 -353
- package/dist/comment-store-BEMgVlAA.d.cts +135 -0
- package/dist/comment-store-BEMgVlAA.d.ts +135 -0
- package/dist/compare/index.cjs +15 -0
- package/dist/compare/index.cjs.map +1 -0
- package/dist/compare/index.d.cts +58 -0
- package/dist/compare/index.d.ts +58 -0
- package/dist/compare/index.js +15 -0
- package/dist/compare/index.js.map +1 -0
- package/dist/{controller-pePCJLT1.d.cts → controller-BhLLAoi8.d.cts} +45 -4
- package/dist/{controller-pePCJLT1.d.ts → controller-BhLLAoi8.d.ts} +45 -4
- package/dist/documents-BQjzJNe2.d.ts +76 -0
- package/dist/documents-KRTPhvst.d.cts +76 -0
- package/dist/extensions/index.cjs +53 -5
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.d.cts +7 -3
- package/dist/extensions/index.d.ts +7 -3
- package/dist/extensions/index.js +52 -4
- package/dist/generation/index.cjs +1373 -0
- package/dist/generation/index.cjs.map +1 -0
- package/dist/generation/index.d.cts +554 -0
- package/dist/generation/index.d.ts +554 -0
- package/dist/generation/index.js +1373 -0
- package/dist/generation/index.js.map +1 -0
- package/dist/grammar/index.cjs +48 -3
- package/dist/grammar/index.cjs.map +1 -1
- package/dist/grammar/index.d.cts +322 -100
- package/dist/grammar/index.d.ts +322 -100
- package/dist/grammar/index.js +54 -9
- package/dist/image-editor/index.cjs +1831 -30
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +590 -3
- package/dist/image-editor/index.d.ts +590 -3
- package/dist/image-editor/index.js +1807 -6
- package/dist/image-editor/index.js.map +1 -1
- package/dist/{index-CCr_z9kF.d.cts → index-BhJBSm2d.d.cts} +370 -4
- package/dist/{index-Ck6ajwXh.d.ts → index-fJrlkJCd.d.ts} +370 -4
- package/dist/index.cjs +162 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -8
- package/dist/index.d.ts +14 -8
- package/dist/index.js +174 -37
- package/dist/index.js.map +1 -1
- package/dist/migrate-iTlm3a8h.d.cts +112 -0
- package/dist/migrate-iTlm3a8h.d.ts +112 -0
- package/dist/persistence/index.cjs +676 -0
- package/dist/persistence/index.cjs.map +1 -0
- package/dist/persistence/index.d.cts +347 -0
- package/dist/persistence/index.d.ts +347 -0
- package/dist/persistence/index.js +676 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/{registry-D5-R90p0.d.cts → registry-BDe-vlv3.d.ts} +2 -40
- package/dist/registry-D32LpIc4.d.cts +354 -0
- package/dist/{registry-D5-R90p0.d.ts → registry-DnzpgY27.d.cts} +2 -40
- package/dist/registry-evKTP4ls.d.ts +354 -0
- package/dist/schema-DYDGdYL9.d.cts +41 -0
- package/dist/schema-DYDGdYL9.d.ts +41 -0
- package/dist/serializers/index.cjs +4 -3
- package/dist/serializers/index.cjs.map +1 -1
- package/dist/serializers/index.d.cts +2 -1
- package/dist/serializers/index.d.ts +2 -1
- package/dist/serializers/index.js +3 -2
- package/dist/sourcemap-C8AH3MBQ.d.cts +91 -0
- package/dist/sourcemap-DA1Evhrv.d.ts +91 -0
- package/dist/spreadsheet/index.cjs +37 -3
- package/dist/spreadsheet/index.cjs.map +1 -1
- package/dist/spreadsheet/index.d.cts +188 -17
- package/dist/spreadsheet/index.d.ts +188 -17
- package/dist/spreadsheet/index.js +43 -9
- package/dist/{tokens-CyLZmIei.d.cts → tokens-D7yXvUU6.d.cts} +15 -2
- package/dist/{tokens-CyLZmIei.d.ts → tokens-D7yXvUU6.d.ts} +15 -2
- package/dist/{track-changes-BSF58RK0.d.ts → track-changes-BK5sVf4_.d.cts} +18 -136
- package/dist/{track-changes-BSF58RK0.d.cts → track-changes-CDjCrwKe.d.ts} +18 -136
- package/package.json +16 -1
- package/dist/chunk-4SUNJZWB.cjs.map +0 -1
- package/dist/chunk-AA4ZEVCC.cjs.map +0 -1
- package/dist/chunk-AXV2ZW34.cjs +0 -118
- package/dist/chunk-AXV2ZW34.cjs.map +0 -1
- package/dist/chunk-B2ZRLN4S.js +0 -118
- package/dist/chunk-B2ZRLN4S.js.map +0 -1
- package/dist/chunk-GVSMRPHB.cjs.map +0 -1
- package/dist/chunk-K3R5NG2D.js.map +0 -1
- package/dist/chunk-MJZBNWG7.js.map +0 -1
- package/dist/chunk-OYXSKQFR.js.map +0 -1
- package/dist/chunk-QBJ22YZR.js.map +0 -1
- package/dist/chunk-QGHGJ56O.js.map +0 -1
- package/dist/chunk-RIKBJLS2.cjs.map +0 -1
- package/dist/chunk-XDMXXC4Z.cjs.map +0 -1
- /package/dist/{chunk-JJDLPEWL.js.map → chunk-3LV6RRPH.js.map} +0 -0
|
@@ -1,15 +1,23 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parseCsv,
|
|
3
|
+
parseTsv,
|
|
4
|
+
serializeCsv,
|
|
5
|
+
serializeTsv
|
|
6
|
+
} from "./chunk-664LQYFJ.js";
|
|
1
7
|
import {
|
|
2
8
|
FormulaEvaluator,
|
|
9
|
+
NumberFormat,
|
|
3
10
|
WHOLE_COLUMN_END_ROW,
|
|
4
11
|
colNameToIndex,
|
|
5
12
|
compareValues,
|
|
6
13
|
describeFormulaError,
|
|
7
|
-
|
|
14
|
+
formatTextFunction,
|
|
8
15
|
getFormulaArgumentSpecIndex,
|
|
9
16
|
getFormulaFunction,
|
|
10
17
|
getFormulaSignature,
|
|
11
18
|
getFormulaSignatureParts,
|
|
12
19
|
indexToColName,
|
|
20
|
+
isBlank,
|
|
13
21
|
isFormulaError,
|
|
14
22
|
numericValue,
|
|
15
23
|
parseCellInput,
|
|
@@ -17,8 +25,9 @@ import {
|
|
|
17
25
|
parseIsoDate,
|
|
18
26
|
searchFormulaFunctions,
|
|
19
27
|
sortCompareValues,
|
|
28
|
+
toText,
|
|
20
29
|
tokenizeFormula
|
|
21
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-3CN2WD3X.js";
|
|
22
31
|
|
|
23
32
|
// src/spreadsheet/formula/dependency-graph.ts
|
|
24
33
|
var columnDependencyKey = (col) => `${col.toUpperCase()}:`;
|
|
@@ -566,6 +575,68 @@ function applyFormulaSuggestion(input, caret, name) {
|
|
|
566
575
|
return { value, caret: start + insert.length + (hasParen ? 1 : 0) };
|
|
567
576
|
}
|
|
568
577
|
|
|
578
|
+
// src/spreadsheet/numfmt/presets.ts
|
|
579
|
+
var NUMBER_FORMAT_PRESETS = [
|
|
580
|
+
{ id: "general", label: "General", code: "General" },
|
|
581
|
+
{ id: "number", label: "Number (0.00)", code: "0.00" },
|
|
582
|
+
{ id: "currency", label: "Currency ($1,234.50)", code: '"$"#,##0.00' },
|
|
583
|
+
{ id: "percent", label: "Percent (12.5%)", code: "0.0%" },
|
|
584
|
+
{ id: "date", label: "Date (3/14/2026)", code: "m/d/yyyy" },
|
|
585
|
+
{ id: "time", label: "Time (1:30 PM)", code: "h:mm AM/PM" }
|
|
586
|
+
];
|
|
587
|
+
function numberFormatForCellFormat(format) {
|
|
588
|
+
switch (format) {
|
|
589
|
+
case "currency":
|
|
590
|
+
return '"$"#,##0.00';
|
|
591
|
+
case "percentage":
|
|
592
|
+
return "0%";
|
|
593
|
+
case "date":
|
|
594
|
+
return "m/d/yyyy";
|
|
595
|
+
default:
|
|
596
|
+
return void 0;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
function cellFormatForNumberFormat(code) {
|
|
600
|
+
switch (NumberFormat.parseCached(code).kind()) {
|
|
601
|
+
case "number":
|
|
602
|
+
case "fraction":
|
|
603
|
+
case "scientific":
|
|
604
|
+
case "special":
|
|
605
|
+
return "number";
|
|
606
|
+
case "currency":
|
|
607
|
+
case "accounting":
|
|
608
|
+
return "currency";
|
|
609
|
+
case "percentage":
|
|
610
|
+
return "percentage";
|
|
611
|
+
case "date":
|
|
612
|
+
return "date";
|
|
613
|
+
case "text":
|
|
614
|
+
return "text";
|
|
615
|
+
default:
|
|
616
|
+
return void 0;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
var isGeneralNumberFormat = (code) => code === void 0 || NumberFormat.parseCached(code).isGeneral();
|
|
620
|
+
|
|
621
|
+
// src/spreadsheet/formula/format.ts
|
|
622
|
+
function formatCellForDisplay(cell) {
|
|
623
|
+
if (!cell) return { text: "", numeric: false };
|
|
624
|
+
if (cell.error) return { text: cell.error, numeric: false };
|
|
625
|
+
const { value } = cell;
|
|
626
|
+
const code = cell.numberFormat ?? (typeof value === "number" ? numberFormatForCellFormat(cell.format) : void 0);
|
|
627
|
+
if (code !== void 0 && !isGeneralNumberFormat(code) && !isBlank(value) && typeof value !== "boolean") {
|
|
628
|
+
return NumberFormat.parseCached(code).format(value);
|
|
629
|
+
}
|
|
630
|
+
return { text: toText(value), numeric: typeof value === "number" };
|
|
631
|
+
}
|
|
632
|
+
function formatCellDisplay(cell) {
|
|
633
|
+
return formatCellForDisplay(cell).text;
|
|
634
|
+
}
|
|
635
|
+
function formatValueWithCode(value, format) {
|
|
636
|
+
const result = formatTextFunction(value, format);
|
|
637
|
+
return "text" in result ? result.text : null;
|
|
638
|
+
}
|
|
639
|
+
|
|
569
640
|
// src/spreadsheet/datasource/index.ts
|
|
570
641
|
var DataSourceBinder = class {
|
|
571
642
|
dataSources = /* @__PURE__ */ new Map();
|
|
@@ -912,113 +983,6 @@ function getFillDirection(source, target) {
|
|
|
912
983
|
return null;
|
|
913
984
|
}
|
|
914
985
|
|
|
915
|
-
// src/spreadsheet/csv.ts
|
|
916
|
-
var BOM = "\uFEFF";
|
|
917
|
-
function parseCsv(text, options = {}) {
|
|
918
|
-
const delimiter = options.delimiter ?? ",";
|
|
919
|
-
if (delimiter.length !== 1 || delimiter === '"' || delimiter === "\n" || delimiter === "\r") {
|
|
920
|
-
throw new Error(`Invalid CSV delimiter: ${JSON.stringify(delimiter)}`);
|
|
921
|
-
}
|
|
922
|
-
const input = text.startsWith(BOM) ? text.slice(1) : text;
|
|
923
|
-
const records = [];
|
|
924
|
-
let record = [];
|
|
925
|
-
let field = "";
|
|
926
|
-
let i = 0;
|
|
927
|
-
let recordStarted = false;
|
|
928
|
-
const endField = () => {
|
|
929
|
-
record.push(field);
|
|
930
|
-
field = "";
|
|
931
|
-
};
|
|
932
|
-
const endRecord = () => {
|
|
933
|
-
endField();
|
|
934
|
-
records.push(record);
|
|
935
|
-
record = [];
|
|
936
|
-
recordStarted = false;
|
|
937
|
-
};
|
|
938
|
-
let atFieldStart = true;
|
|
939
|
-
while (i < input.length) {
|
|
940
|
-
const char = input[i];
|
|
941
|
-
if (char === '"' && atFieldStart) {
|
|
942
|
-
const quoted = readQuoted(input, i, delimiter);
|
|
943
|
-
if (quoted.wellFormed || !options.requireWellFormedQuotes) {
|
|
944
|
-
recordStarted = true;
|
|
945
|
-
atFieldStart = false;
|
|
946
|
-
field += quoted.value;
|
|
947
|
-
i = quoted.end;
|
|
948
|
-
continue;
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
if (char === delimiter) {
|
|
952
|
-
recordStarted = true;
|
|
953
|
-
endField();
|
|
954
|
-
atFieldStart = true;
|
|
955
|
-
i++;
|
|
956
|
-
continue;
|
|
957
|
-
}
|
|
958
|
-
if (char === "\r" || char === "\n") {
|
|
959
|
-
endRecord();
|
|
960
|
-
atFieldStart = true;
|
|
961
|
-
i += char === "\r" && input[i + 1] === "\n" ? 2 : 1;
|
|
962
|
-
continue;
|
|
963
|
-
}
|
|
964
|
-
recordStarted = true;
|
|
965
|
-
atFieldStart = false;
|
|
966
|
-
field += char;
|
|
967
|
-
i++;
|
|
968
|
-
}
|
|
969
|
-
if (recordStarted || field !== "" || record.length > 0) endRecord();
|
|
970
|
-
return records;
|
|
971
|
-
}
|
|
972
|
-
function readQuoted(input, start, delimiter) {
|
|
973
|
-
let value = "";
|
|
974
|
-
let i = start + 1;
|
|
975
|
-
while (i < input.length) {
|
|
976
|
-
if (input[i] === '"') {
|
|
977
|
-
if (input[i + 1] === '"') {
|
|
978
|
-
value += '"';
|
|
979
|
-
i += 2;
|
|
980
|
-
continue;
|
|
981
|
-
}
|
|
982
|
-
const next = input[i + 1];
|
|
983
|
-
const wellFormed = next === void 0 || next === delimiter || next === "\r" || next === "\n";
|
|
984
|
-
return { value, end: i + 1, wellFormed };
|
|
985
|
-
}
|
|
986
|
-
value += input[i];
|
|
987
|
-
i++;
|
|
988
|
-
}
|
|
989
|
-
return { value, end: i, wellFormed: false };
|
|
990
|
-
}
|
|
991
|
-
function escapeCsvField(value, delimiter = ",", quoteAll = false) {
|
|
992
|
-
if (quoteAll || value.includes(delimiter) || /["\r\n]/.test(value)) {
|
|
993
|
-
return `"${value.replace(/"/g, '""')}"`;
|
|
994
|
-
}
|
|
995
|
-
return value;
|
|
996
|
-
}
|
|
997
|
-
function serializeCsv(rows, options = {}) {
|
|
998
|
-
const delimiter = options.delimiter ?? ",";
|
|
999
|
-
const lineEnding = options.lineEnding ?? "\r\n";
|
|
1000
|
-
const body = rows.map(
|
|
1001
|
-
(row) => row.map((value) => escapeCsvField(value == null ? "" : String(value), delimiter, options.quoteAll)).join(delimiter)
|
|
1002
|
-
).join(lineEnding);
|
|
1003
|
-
return options.bom ? BOM + body : body;
|
|
1004
|
-
}
|
|
1005
|
-
function parseTsv(text) {
|
|
1006
|
-
const normalized = text.startsWith(BOM) ? text.slice(1) : text;
|
|
1007
|
-
if (!normalized.includes('"')) {
|
|
1008
|
-
const body = normalized.replace(/\r\n?/g, "\n").replace(/\n$/, "");
|
|
1009
|
-
return body === "" ? [] : body.split("\n").map((line) => line.split(" "));
|
|
1010
|
-
}
|
|
1011
|
-
return parseCsv(normalized, { delimiter: " ", requireWellFormedQuotes: true });
|
|
1012
|
-
}
|
|
1013
|
-
function serializeTsv(rows) {
|
|
1014
|
-
return rows.map(
|
|
1015
|
-
(row) => row.map((value) => {
|
|
1016
|
-
const text = value == null ? "" : String(value);
|
|
1017
|
-
return /[\t\r\n]/.test(text) || text.startsWith('"') ? `"${text.replace(/"/g, '""')}"` : text;
|
|
1018
|
-
}).join(" ")
|
|
1019
|
-
).join("\n");
|
|
1020
|
-
}
|
|
1021
|
-
|
|
1022
986
|
// src/spreadsheet/clipboard.ts
|
|
1023
987
|
var SPREADSHEET_CLIPBOARD_MIME = "application/x.pixerate.spreadsheet+json";
|
|
1024
988
|
var displayText = (value) => value === null || value === void 0 ? "" : String(value);
|
|
@@ -1422,7 +1386,7 @@ var SpreadsheetController = class {
|
|
|
1422
1386
|
const cell = cells[col.id];
|
|
1423
1387
|
if (!cell || typeof cell.raw !== "string" || cell.raw.startsWith("=")) continue;
|
|
1424
1388
|
if (col.type === "bound" && col.binding && row.recordId) continue;
|
|
1425
|
-
const typed = this.typedCell(cell.raw, cell.format);
|
|
1389
|
+
const typed = this.typedCell(cell.raw, cell.format, col, cell);
|
|
1426
1390
|
cell.value = typed.value;
|
|
1427
1391
|
if (typed.numberFormat) cell.numberFormat = typed.numberFormat;
|
|
1428
1392
|
else delete cell.numberFormat;
|
|
@@ -1436,14 +1400,31 @@ var SpreadsheetController = class {
|
|
|
1436
1400
|
* `CellFormat` to use: the automatic one (currency, percentage, date,
|
|
1437
1401
|
* number) when `format` is unset or `text` (the default of new columns).
|
|
1438
1402
|
*/
|
|
1439
|
-
typedCell(raw, format) {
|
|
1403
|
+
typedCell(raw, format, col, existing) {
|
|
1440
1404
|
const parsed = parseCellInput(raw);
|
|
1405
|
+
const fixed = this.fixedNumberFormat(col, existing);
|
|
1406
|
+
const numberFormat = fixed ?? parsed.numberFormat;
|
|
1441
1407
|
return {
|
|
1442
1408
|
value: parsed.value,
|
|
1443
|
-
...
|
|
1444
|
-
|
|
1409
|
+
...numberFormat ? { numberFormat } : {},
|
|
1410
|
+
...existing?.explicitNumberFormat ? { explicitNumberFormat: true } : {},
|
|
1411
|
+
format: fixed === void 0 && parsed.cellFormat && (!format || format === "text") ? parsed.cellFormat : format
|
|
1445
1412
|
};
|
|
1446
1413
|
}
|
|
1414
|
+
/**
|
|
1415
|
+
* The number format a cell keeps whatever is typed into it: its explicit
|
|
1416
|
+
* one, else its column's. Undefined lets typed input choose one.
|
|
1417
|
+
*/
|
|
1418
|
+
fixedNumberFormat(col, existing) {
|
|
1419
|
+
if (existing?.explicitNumberFormat && existing.numberFormat !== void 0) return existing.numberFormat;
|
|
1420
|
+
return col?.numberFormat && !isGeneralNumberFormat(col.numberFormat) ? col.numberFormat : void 0;
|
|
1421
|
+
}
|
|
1422
|
+
/** `numberFormat` / `explicitNumberFormat` fields for a formula, bound or spilled cell. */
|
|
1423
|
+
fixedNumberFormatFields(col, existing) {
|
|
1424
|
+
const numberFormat = this.fixedNumberFormat(col, existing);
|
|
1425
|
+
if (numberFormat === void 0) return {};
|
|
1426
|
+
return existing?.explicitNumberFormat ? { numberFormat, explicitNumberFormat: true } : { numberFormat };
|
|
1427
|
+
}
|
|
1447
1428
|
/**
|
|
1448
1429
|
* Typed input for a bound field, coerced by the field's declared type:
|
|
1449
1430
|
* number, boolean and date fields get a number, boolean or ISO date when
|
|
@@ -1501,10 +1482,13 @@ var SpreadsheetController = class {
|
|
|
1501
1482
|
const spilled = this.spillCells.get(spillCellId(rowId, colId));
|
|
1502
1483
|
if (spilled) return spilled;
|
|
1503
1484
|
}
|
|
1504
|
-
if (existing) return existing;
|
|
1485
|
+
if (existing && !existing.explicitNumberFormat) return existing;
|
|
1505
1486
|
const col = this.document.columns.find((c) => c.id === colId);
|
|
1506
1487
|
const row = this.document.rows.find((r) => r.id === rowId);
|
|
1507
|
-
|
|
1488
|
+
const derived = this.getDerivedCell(row, col);
|
|
1489
|
+
if (!existing) return derived;
|
|
1490
|
+
if (derived.raw === "") return existing;
|
|
1491
|
+
return { ...derived, numberFormat: existing.numberFormat, explicitNumberFormat: true };
|
|
1508
1492
|
}
|
|
1509
1493
|
/** Value of a cell with no stored data: bound record value, column formula, or blank. */
|
|
1510
1494
|
getDerivedCell(row, col) {
|
|
@@ -1517,17 +1501,19 @@ var SpreadsheetController = class {
|
|
|
1517
1501
|
return {
|
|
1518
1502
|
raw: boundVal !== void 0 ? String(boundVal) : "",
|
|
1519
1503
|
value: boundVal ?? "",
|
|
1520
|
-
format: col.format
|
|
1504
|
+
format: col.format,
|
|
1505
|
+
...this.fixedNumberFormatFields(col, void 0)
|
|
1521
1506
|
};
|
|
1522
1507
|
}
|
|
1523
1508
|
if (col && col.type === "formula" && col.formula) {
|
|
1524
1509
|
return {
|
|
1525
1510
|
raw: col.formula,
|
|
1526
1511
|
value: "",
|
|
1527
|
-
format: col.format
|
|
1512
|
+
format: col.format,
|
|
1513
|
+
...this.fixedNumberFormatFields(col, void 0)
|
|
1528
1514
|
};
|
|
1529
1515
|
}
|
|
1530
|
-
return { raw: "", value: "", format: col?.format };
|
|
1516
|
+
return { raw: "", value: "", format: col?.format, ...this.fixedNumberFormatFields(col, void 0) };
|
|
1531
1517
|
}
|
|
1532
1518
|
setCellValue(rowId, colId, raw) {
|
|
1533
1519
|
this.recordSnapshot();
|
|
@@ -1537,15 +1523,16 @@ var SpreadsheetController = class {
|
|
|
1537
1523
|
const col = this.document.columns.find((c) => c.id === colId);
|
|
1538
1524
|
const row = this.document.rows.find((r) => r.id === rowId);
|
|
1539
1525
|
const isFormula = raw.startsWith("=");
|
|
1526
|
+
const existing = this.document.cells[rowId][colId];
|
|
1540
1527
|
let cell;
|
|
1541
1528
|
if (col?.type === "bound" && col.binding && row?.recordId) {
|
|
1542
1529
|
const value = this.boundInputValue(col.binding.dataSource, col.binding.field, raw);
|
|
1543
1530
|
this.binder.commitBoundValue(col.binding.dataSource, row.recordId, col.binding.field, value);
|
|
1544
|
-
cell = { raw, value, format: col.format };
|
|
1531
|
+
cell = { raw, value, format: col.format, ...this.fixedNumberFormatFields(col, existing) };
|
|
1545
1532
|
} else if (isFormula) {
|
|
1546
|
-
cell = { raw, value: raw, format: col?.format };
|
|
1533
|
+
cell = { raw, value: raw, format: col?.format, ...this.fixedNumberFormatFields(col, existing) };
|
|
1547
1534
|
} else {
|
|
1548
|
-
cell = { raw, ...this.typedCell(raw, col?.format) };
|
|
1535
|
+
cell = { raw, ...this.typedCell(raw, col?.format, col, existing) };
|
|
1549
1536
|
}
|
|
1550
1537
|
const cellKey = this.getCellKey(rowId, colId);
|
|
1551
1538
|
this.depGraph.setCellFormula(cellKey, isFormula ? raw : null);
|
|
@@ -1748,7 +1735,13 @@ var SpreadsheetController = class {
|
|
|
1748
1735
|
const rowObj = this.document.rows[row + r];
|
|
1749
1736
|
const key = `${column.key}${row + r + 1}`.toUpperCase();
|
|
1750
1737
|
const value = array.values[c * rows + r] ?? "";
|
|
1751
|
-
const display = {
|
|
1738
|
+
const display = {
|
|
1739
|
+
raw: "",
|
|
1740
|
+
value,
|
|
1741
|
+
format: column.format,
|
|
1742
|
+
spillAnchor: anchor,
|
|
1743
|
+
...this.fixedNumberFormatFields(column, this.document.cells[rowObj.id]?.[column.id])
|
|
1744
|
+
};
|
|
1752
1745
|
if (isFormulaError(value)) {
|
|
1753
1746
|
display.error = value;
|
|
1754
1747
|
display.errorMessage = describeFormulaError(value);
|
|
@@ -1973,6 +1966,7 @@ var SpreadsheetController = class {
|
|
|
1973
1966
|
binding: config?.binding,
|
|
1974
1967
|
formula: config?.formula,
|
|
1975
1968
|
format: config?.format || "text",
|
|
1969
|
+
...config?.numberFormat ? { numberFormat: config.numberFormat } : {},
|
|
1976
1970
|
readOnly: config?.readOnly
|
|
1977
1971
|
};
|
|
1978
1972
|
this.shiftReferences({ axis: "col", index, type: "insert" });
|
|
@@ -2460,6 +2454,94 @@ var SpreadsheetController = class {
|
|
|
2460
2454
|
this.table[key] = value;
|
|
2461
2455
|
});
|
|
2462
2456
|
}
|
|
2457
|
+
// --- Number formats ---
|
|
2458
|
+
//
|
|
2459
|
+
// Cells are replaced, never mutated in place: framework bindings compare
|
|
2460
|
+
// cell objects by identity to decide what to re-render.
|
|
2461
|
+
/**
|
|
2462
|
+
* Sets an explicit number format code (e.g. `0.00`, `"$"#,##0.00`,
|
|
2463
|
+
* `m/d/yyyy`, `[Red]0;[Blue]-0`) on every cell in `range`, including blank
|
|
2464
|
+
* cells, so values typed later keep it. `null` removes explicit formats: the
|
|
2465
|
+
* cells go back to their column's format or the one chosen for typed input.
|
|
2466
|
+
* Undoable as one step. Returns false when there is no range.
|
|
2467
|
+
*/
|
|
2468
|
+
setCellNumberFormat(range, code) {
|
|
2469
|
+
if (!range) return false;
|
|
2470
|
+
const r = normalizeRange(range);
|
|
2471
|
+
this.recordSnapshot();
|
|
2472
|
+
const kind = code === null ? void 0 : cellFormatForNumberFormat(code);
|
|
2473
|
+
for (let ri = r.startRow; ri <= r.endRow; ri++) {
|
|
2474
|
+
const row = this.document.rows[ri];
|
|
2475
|
+
if (!row) continue;
|
|
2476
|
+
for (let ci = r.startCol; ci <= r.endCol; ci++) {
|
|
2477
|
+
const col = this.document.columns[ci];
|
|
2478
|
+
if (!col) continue;
|
|
2479
|
+
const cells = this.document.cells[row.id] ??= {};
|
|
2480
|
+
const existing = cells[col.id];
|
|
2481
|
+
if (code === null) {
|
|
2482
|
+
if (!existing?.explicitNumberFormat) continue;
|
|
2483
|
+
if (existing.raw === "" && existing.value === "" && !existing.error) {
|
|
2484
|
+
delete cells[col.id];
|
|
2485
|
+
} else {
|
|
2486
|
+
const { explicitNumberFormat: _explicit, ...rest } = existing;
|
|
2487
|
+
cells[col.id] = this.withNumberFormat(rest, this.implicitNumberFormat(rest, col, row));
|
|
2488
|
+
}
|
|
2489
|
+
} else {
|
|
2490
|
+
cells[col.id] = {
|
|
2491
|
+
...existing ?? { raw: "", value: "" },
|
|
2492
|
+
format: kind ?? existing?.format ?? col.format,
|
|
2493
|
+
numberFormat: code,
|
|
2494
|
+
explicitNumberFormat: true
|
|
2495
|
+
};
|
|
2496
|
+
}
|
|
2497
|
+
this.refreshSpilledNumberFormat(row, col);
|
|
2498
|
+
}
|
|
2499
|
+
}
|
|
2500
|
+
this.document.updatedAt = Date.now();
|
|
2501
|
+
this.notifyChange();
|
|
2502
|
+
return true;
|
|
2503
|
+
}
|
|
2504
|
+
/**
|
|
2505
|
+
* Sets the number format code of a column (`null` or `General` clears it).
|
|
2506
|
+
* Its cells without an explicit format of their own use it, including
|
|
2507
|
+
* values typed later; when cleared they go back to the format chosen for
|
|
2508
|
+
* typed input. Undoable.
|
|
2509
|
+
*/
|
|
2510
|
+
setColumnNumberFormat(colId, code) {
|
|
2511
|
+
const col = this.getColumn(colId);
|
|
2512
|
+
if (!col) return;
|
|
2513
|
+
this.recordSnapshot();
|
|
2514
|
+
if (code === null || isGeneralNumberFormat(code)) delete col.numberFormat;
|
|
2515
|
+
else col.numberFormat = code;
|
|
2516
|
+
for (const row of this.document.rows) {
|
|
2517
|
+
const cells = this.document.cells[row.id];
|
|
2518
|
+
const cell = cells?.[col.id];
|
|
2519
|
+
if (cells && cell && !cell.explicitNumberFormat) {
|
|
2520
|
+
cells[col.id] = this.withNumberFormat(cell, this.implicitNumberFormat(cell, col, row));
|
|
2521
|
+
}
|
|
2522
|
+
this.refreshSpilledNumberFormat(row, col);
|
|
2523
|
+
}
|
|
2524
|
+
this.document.updatedAt = Date.now();
|
|
2525
|
+
this.notifyChange();
|
|
2526
|
+
}
|
|
2527
|
+
/** The column's format, or the one typed input chose (typed cells only). */
|
|
2528
|
+
implicitNumberFormat(cell, col, row) {
|
|
2529
|
+
const typed = cell.raw !== "" && !cell.raw.startsWith("=") && !(col.type === "bound" && col.binding && row.recordId);
|
|
2530
|
+
return this.fixedNumberFormat(col, void 0) ?? (typed ? parseCellInput(cell.raw).numberFormat : void 0);
|
|
2531
|
+
}
|
|
2532
|
+
/** A copy of `cell` with `numberFormat` set, or removed when undefined. */
|
|
2533
|
+
withNumberFormat(cell, numberFormat) {
|
|
2534
|
+
const { numberFormat: _old, ...rest } = cell;
|
|
2535
|
+
return numberFormat === void 0 ? rest : { ...rest, numberFormat };
|
|
2536
|
+
}
|
|
2537
|
+
/** Re-applies the stored cell's (or the column's) format to a spilled value shown there. */
|
|
2538
|
+
refreshSpilledNumberFormat(row, col) {
|
|
2539
|
+
const id = spillCellId(row.id, col.id);
|
|
2540
|
+
const spilled = this.spillCells.get(id);
|
|
2541
|
+
if (!spilled) return;
|
|
2542
|
+
const { numberFormat: _old, explicitNumberFormat: _explicit, ...rest } = spilled;
|
|
2543
|
+
this.spillCells.set(id, { ...rest, ...this.fixedNumberFormatFields(col, this.document.cells[row.id]?.[col.id]) });
|
|
2544
|
+
}
|
|
2463
2545
|
// --- Hide / unhide ---
|
|
2464
2546
|
hideRows(indices) {
|
|
2465
2547
|
this.setHidden("row", indices, true);
|
|
@@ -2793,6 +2875,17 @@ function stepInOrder(order, from, delta) {
|
|
|
2793
2875
|
}
|
|
2794
2876
|
|
|
2795
2877
|
// src/spreadsheet/menu.ts
|
|
2878
|
+
function runSpreadsheetMenuItem(item, ask) {
|
|
2879
|
+
if (!item.input) {
|
|
2880
|
+
item.run();
|
|
2881
|
+
return true;
|
|
2882
|
+
}
|
|
2883
|
+
const prompt = ask ?? ((label, value) => typeof window !== "undefined" && window.prompt ? window.prompt(label, value) : null);
|
|
2884
|
+
const text = prompt(item.input.label, item.input.defaultValue ?? "");
|
|
2885
|
+
if (text === null || text === void 0) return false;
|
|
2886
|
+
item.run(text);
|
|
2887
|
+
return true;
|
|
2888
|
+
}
|
|
2796
2889
|
function clampMenuPosition(point, size, viewport, margin = 4) {
|
|
2797
2890
|
const place = (start, length, limit) => {
|
|
2798
2891
|
if (start + length <= limit - margin) return Math.max(margin, start);
|
|
@@ -2927,6 +3020,31 @@ function getSpreadsheetMenuItems(controller, cell) {
|
|
|
2927
3020
|
}
|
|
2928
3021
|
}
|
|
2929
3022
|
];
|
|
3023
|
+
const currentFormat = cellData.numberFormat;
|
|
3024
|
+
const presetMatch = NUMBER_FORMAT_PRESETS.find(
|
|
3025
|
+
(p) => p.id === "general" ? isGeneralNumberFormat(currentFormat) : p.code === currentFormat
|
|
3026
|
+
);
|
|
3027
|
+
NUMBER_FORMAT_PRESETS.forEach((preset, i) => {
|
|
3028
|
+
items.push({
|
|
3029
|
+
id: `number-format-${preset.id}`,
|
|
3030
|
+
label: `Format cells: ${preset.label}`,
|
|
3031
|
+
separatorBefore: i === 0,
|
|
3032
|
+
checked: presetMatch === preset,
|
|
3033
|
+
run: () => {
|
|
3034
|
+
controller.setCellNumberFormat(selection, preset.code);
|
|
3035
|
+
}
|
|
3036
|
+
});
|
|
3037
|
+
});
|
|
3038
|
+
items.push({
|
|
3039
|
+
id: "number-format-custom",
|
|
3040
|
+
label: "Format cells: Custom\u2026",
|
|
3041
|
+
checked: !presetMatch,
|
|
3042
|
+
input: { label: "Number format code, e.g. #,##0.00;[Red](#,##0.00)", defaultValue: currentFormat ?? "General" },
|
|
3043
|
+
run: (code) => {
|
|
3044
|
+
if (code === void 0) return;
|
|
3045
|
+
controller.setCellNumberFormat(selection, code.trim() === "" ? null : code);
|
|
3046
|
+
}
|
|
3047
|
+
});
|
|
2930
3048
|
if (grouping) {
|
|
2931
3049
|
items.push(
|
|
2932
3050
|
{
|
|
@@ -2985,6 +3103,8 @@ var SPREADSHEET_TABLE_ACTIONS = [
|
|
|
2985
3103
|
"toggleGroupCollapsed",
|
|
2986
3104
|
"getGroups",
|
|
2987
3105
|
"transposeRange",
|
|
3106
|
+
"setCellNumberFormat",
|
|
3107
|
+
"setColumnNumberFormat",
|
|
2988
3108
|
"exportToCsv",
|
|
2989
3109
|
"importFromCsv",
|
|
2990
3110
|
"copyToClipboardData",
|
|
@@ -3053,6 +3173,13 @@ export {
|
|
|
3053
3173
|
getFormulaCaretContext,
|
|
3054
3174
|
getFormulaHints,
|
|
3055
3175
|
applyFormulaSuggestion,
|
|
3176
|
+
NUMBER_FORMAT_PRESETS,
|
|
3177
|
+
numberFormatForCellFormat,
|
|
3178
|
+
cellFormatForNumberFormat,
|
|
3179
|
+
isGeneralNumberFormat,
|
|
3180
|
+
formatCellForDisplay,
|
|
3181
|
+
formatCellDisplay,
|
|
3182
|
+
formatValueWithCode,
|
|
3056
3183
|
DataSourceBinder,
|
|
3057
3184
|
normalizeRange,
|
|
3058
3185
|
rangeContains,
|
|
@@ -3068,11 +3195,6 @@ export {
|
|
|
3068
3195
|
fillSeries,
|
|
3069
3196
|
computeFillTarget,
|
|
3070
3197
|
getFillDirection,
|
|
3071
|
-
parseCsv,
|
|
3072
|
-
escapeCsvField,
|
|
3073
|
-
serializeCsv,
|
|
3074
|
-
parseTsv,
|
|
3075
|
-
serializeTsv,
|
|
3076
3198
|
SPREADSHEET_CLIPBOARD_MIME,
|
|
3077
3199
|
serializeHtmlTable,
|
|
3078
3200
|
parseHtmlTable,
|
|
@@ -3087,6 +3209,7 @@ export {
|
|
|
3087
3209
|
computeRowGroups,
|
|
3088
3210
|
buildSpreadsheetView,
|
|
3089
3211
|
SpreadsheetController,
|
|
3212
|
+
runSpreadsheetMenuItem,
|
|
3090
3213
|
clampMenuPosition,
|
|
3091
3214
|
getSpreadsheetMenuItems,
|
|
3092
3215
|
SPREADSHEET_TABLE_ACTIONS,
|
|
@@ -3097,4 +3220,4 @@ export {
|
|
|
3097
3220
|
registerSpreadsheetImportAdapters,
|
|
3098
3221
|
importFileIntoSpreadsheet
|
|
3099
3222
|
};
|
|
3100
|
-
//# sourceMappingURL=chunk-
|
|
3223
|
+
//# sourceMappingURL=chunk-U5KWZU4X.js.map
|