@bendyline/squisq-editor-react 2.11.14 → 2.11.16
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 +9 -1
- package/dist/{chunk-DN6XFOY2.js → chunk-27WOOJXR.js} +1 -1
- package/dist/{chunk-BJ3TXAIQ.js → chunk-4D7QMRTZ.js} +367 -105
- package/dist/{chunk-QY2ZFRJE.js → chunk-5TYCTE33.js} +334 -141
- package/dist/{chunk-V44VP242.js → chunk-K4Z2GIX4.js} +29 -14
- package/dist/image-editor/index.js +1 -1
- package/dist/index.d.ts +11 -10
- package/dist/index.js +4 -4
- package/dist/recorder/index.d.ts +2 -2
- package/dist/recorder/index.js +2 -2
- package/dist/{recorder-CC3VW9Z7.d.ts → recorder-C6ArYQBa.d.ts} +6 -1
- package/dist/shell/index.d.ts +1 -1
- package/dist/shell/index.js +3 -3
- package/dist/{shell-3UAmXcYE.d.ts → shell-X0EoQbbN.d.ts} +9 -3
- package/dist/teleprompter/index.d.ts +2 -2
- package/dist/{useNarrationStage-D3Sgcf0L.d.ts → useNarrationStage-DopDr_P5.d.ts} +10 -1
- package/package.json +7 -7
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
ImageEditor,
|
|
34
34
|
ImageViewer,
|
|
35
35
|
ShapePalette
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-K4Z2GIX4.js";
|
|
37
37
|
import {
|
|
38
38
|
BlockThumbnail,
|
|
39
39
|
RecorderPanel,
|
|
@@ -41,7 +41,7 @@ import {
|
|
|
41
41
|
documentTitleFromFileName,
|
|
42
42
|
resolveBlockVisual,
|
|
43
43
|
useModalDialog
|
|
44
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-4D7QMRTZ.js";
|
|
45
45
|
import {
|
|
46
46
|
Icon
|
|
47
47
|
} from "./chunk-GS7QWYFT.js";
|
|
@@ -1026,7 +1026,7 @@ function VersionHistoryPanel() {
|
|
|
1026
1026
|
}
|
|
1027
1027
|
),
|
|
1028
1028
|
visibleVersions.map((v2) => {
|
|
1029
|
-
const
|
|
1029
|
+
const pending2 = state.pendingRevert !== null && state.pendingRevert.path === v2.path;
|
|
1030
1030
|
const selected = state.selected?.version.path === v2.path;
|
|
1031
1031
|
return /* @__PURE__ */ jsxs(
|
|
1032
1032
|
"li",
|
|
@@ -1054,7 +1054,7 @@ function VersionHistoryPanel() {
|
|
|
1054
1054
|
children: "Revert"
|
|
1055
1055
|
}
|
|
1056
1056
|
) }),
|
|
1057
|
-
|
|
1057
|
+
pending2 && /* @__PURE__ */ jsxs("div", { className: "squisq-version-history-confirm", children: [
|
|
1058
1058
|
/* @__PURE__ */ jsx("span", { children: "Revert to this version? Your current draft will be saved as a new snapshot first. Reverting will reset your editor undo state." }),
|
|
1059
1059
|
/* @__PURE__ */ jsxs("span", { className: "squisq-version-history-confirm-actions", children: [
|
|
1060
1060
|
/* @__PURE__ */ jsx(
|
|
@@ -27541,15 +27541,15 @@ async function loadDataPreview(bytes, ext, opts) {
|
|
|
27541
27541
|
var previewCache = /* @__PURE__ */ new Map();
|
|
27542
27542
|
function loadDataPreviewCached(path, revision, load) {
|
|
27543
27543
|
const key = `${revision}\0${path}`;
|
|
27544
|
-
let
|
|
27545
|
-
if (!
|
|
27544
|
+
let pending2 = previewCache.get(key);
|
|
27545
|
+
if (!pending2) {
|
|
27546
27546
|
for (const existing of previewCache.keys()) {
|
|
27547
27547
|
if (existing.endsWith(`\0${path}`) && existing !== key) previewCache.delete(existing);
|
|
27548
27548
|
}
|
|
27549
|
-
|
|
27550
|
-
previewCache.set(key,
|
|
27549
|
+
pending2 = load();
|
|
27550
|
+
previewCache.set(key, pending2);
|
|
27551
27551
|
}
|
|
27552
|
-
return
|
|
27552
|
+
return pending2;
|
|
27553
27553
|
}
|
|
27554
27554
|
|
|
27555
27555
|
// src/dataCard/ingestAdapters.ts
|
|
@@ -27591,20 +27591,25 @@ async function ingestSidecarBytes(bytes, ext, params) {
|
|
|
27591
27591
|
};
|
|
27592
27592
|
}
|
|
27593
27593
|
if (ext === "xlsx") {
|
|
27594
|
-
const { xlsxToCellGrids, gridToTables, parseCellRef } = await import("@bendyline/squisq-formats/xlsx");
|
|
27595
|
-
const grids = await xlsxToCellGrids(bytes
|
|
27596
|
-
...params.sheet !== void 0 ? { sheet: params.sheet } : {}
|
|
27597
|
-
});
|
|
27594
|
+
const { xlsxToCellGrids, gridToTables, parseCellRef, formatCellRef } = await import("@bendyline/squisq-formats/xlsx");
|
|
27595
|
+
const grids = await xlsxToCellGrids(bytes);
|
|
27598
27596
|
const bySheet = new Map(grids.sheets.map((sheet) => [sheet.name, sheet]));
|
|
27599
|
-
const tables = grids.sheets.flatMap(
|
|
27600
|
-
(sheet) => gridToTables(sheet.name, sheet.cells, sheet.merges)
|
|
27601
|
-
);
|
|
27597
|
+
const tables = grids.sheets.filter((sheet) => params.sheet === void 0 || sheet.name === params.sheet).flatMap((sheet) => gridToTables(sheet.name, sheet.cells, sheet.merges));
|
|
27602
27598
|
const table = params.anchor && tables.find((t) => t.anchor.toUpperCase() === params.anchor.toUpperCase()) || tables.reduce(
|
|
27603
27599
|
(best, candidate) => !best || candidate.rows.length * candidate.columns.length > best.rows.length * best.columns.length ? candidate : best,
|
|
27604
27600
|
null
|
|
27605
27601
|
);
|
|
27606
27602
|
if (!table) throw new Error("no tabular data found in workbook");
|
|
27607
27603
|
const anchor = parseCellRef(table.anchor);
|
|
27604
|
+
if (params.headerRow === false && table.hasHeader) {
|
|
27605
|
+
table.rows.unshift(table.columns.map((column) => column.name));
|
|
27606
|
+
table.columns = table.columns.map((column, col) => ({
|
|
27607
|
+
...column,
|
|
27608
|
+
name: formatCellRef(0, (anchor?.col ?? 0) + col).slice(0, -1),
|
|
27609
|
+
kind: "mixed"
|
|
27610
|
+
}));
|
|
27611
|
+
table.hasHeader = false;
|
|
27612
|
+
}
|
|
27608
27613
|
const sheetGrid = bySheet.get(table.sheet);
|
|
27609
27614
|
const locked = /* @__PURE__ */ new Set();
|
|
27610
27615
|
const dateLocked = /* @__PURE__ */ new Set();
|
|
@@ -27834,6 +27839,43 @@ import { EMPTY_TABLE_VIEW_STATE } from "@bendyline/squisq/table";
|
|
|
27834
27839
|
|
|
27835
27840
|
// src/dataCard/gridSave.ts
|
|
27836
27841
|
import { DATA_BACKUP_PREFIX, buildDataBackupPath } from "@bendyline/squisq/versions";
|
|
27842
|
+
|
|
27843
|
+
// src/dataCard/saveSession.ts
|
|
27844
|
+
var sessions = /* @__PURE__ */ new WeakMap();
|
|
27845
|
+
function withDataSave(options, save) {
|
|
27846
|
+
const owner = options.container ?? options.mediaProvider;
|
|
27847
|
+
let files = sessions.get(owner);
|
|
27848
|
+
if (!files) {
|
|
27849
|
+
files = /* @__PURE__ */ new Map();
|
|
27850
|
+
sessions.set(owner, files);
|
|
27851
|
+
}
|
|
27852
|
+
let session = files.get(options.path);
|
|
27853
|
+
if (!session) {
|
|
27854
|
+
session = { tail: Promise.resolve() };
|
|
27855
|
+
files.set(options.path, session);
|
|
27856
|
+
}
|
|
27857
|
+
const current = session;
|
|
27858
|
+
const result = current.tail.catch(() => void 0).then(async () => {
|
|
27859
|
+
let latest = await options.container?.readFile(options.path);
|
|
27860
|
+
if (!latest && !options.container) {
|
|
27861
|
+
const url = await options.mediaProvider.resolveUrl(options.path);
|
|
27862
|
+
if (url !== options.path) {
|
|
27863
|
+
const response = await fetch(url);
|
|
27864
|
+
if (!response.ok)
|
|
27865
|
+
throw new Error(`Could not read the current file before saving (${response.status})`);
|
|
27866
|
+
latest = await response.arrayBuffer();
|
|
27867
|
+
}
|
|
27868
|
+
}
|
|
27869
|
+
const baseline = latest ?? current.bytes ?? options.originalBytes;
|
|
27870
|
+
const saved = await save(baseline);
|
|
27871
|
+
if (saved.ok && saved.bytes) current.bytes = saved.bytes;
|
|
27872
|
+
return saved;
|
|
27873
|
+
});
|
|
27874
|
+
current.tail = result;
|
|
27875
|
+
return result;
|
|
27876
|
+
}
|
|
27877
|
+
|
|
27878
|
+
// src/dataCard/gridSave.ts
|
|
27837
27879
|
var BACKUPS_KEPT_PER_SIDECAR = 3;
|
|
27838
27880
|
var FORMULA_PREFIX = /^[\t\r\n \uFEFF]*[=+\-@]/;
|
|
27839
27881
|
function renderCell(value) {
|
|
@@ -27856,96 +27898,111 @@ async function backupOriginal(container, path, original, mime) {
|
|
|
27856
27898
|
}
|
|
27857
27899
|
}
|
|
27858
27900
|
async function saveCsvEdits(options) {
|
|
27859
|
-
const { path,
|
|
27860
|
-
const
|
|
27861
|
-
|
|
27862
|
-
|
|
27863
|
-
|
|
27864
|
-
|
|
27865
|
-
|
|
27866
|
-
|
|
27867
|
-
|
|
27868
|
-
|
|
27869
|
-
|
|
27870
|
-
|
|
27871
|
-
const
|
|
27872
|
-
|
|
27873
|
-
const
|
|
27874
|
-
|
|
27875
|
-
|
|
27876
|
-
|
|
27877
|
-
|
|
27878
|
-
|
|
27879
|
-
|
|
27880
|
-
|
|
27881
|
-
|
|
27882
|
-
|
|
27883
|
-
|
|
27884
|
-
|
|
27885
|
-
|
|
27886
|
-
|
|
27901
|
+
const { path, csv, journal, mediaProvider, container } = options;
|
|
27902
|
+
const snapshot = journal.entries();
|
|
27903
|
+
return withDataSave(options, async (originalBytes) => {
|
|
27904
|
+
const notices = [];
|
|
27905
|
+
const mime = path.toLowerCase().endsWith(".tsv") ? "text/tab-separated-values" : "text/csv";
|
|
27906
|
+
try {
|
|
27907
|
+
if (container) {
|
|
27908
|
+
await backupOriginal(container, path, originalBytes, mime);
|
|
27909
|
+
} else {
|
|
27910
|
+
notices.push("no workspace container \u2014 saved without a backup copy");
|
|
27911
|
+
}
|
|
27912
|
+
const { parseCsv, serializeCsvRows } = await import("@bendyline/squisq-formats/csv");
|
|
27913
|
+
const rows = parseCsv(new TextDecoder().decode(originalBytes), csv.delimiter);
|
|
27914
|
+
const offset = csv.hasHeader ? 1 : 0;
|
|
27915
|
+
for (const entry of snapshot) {
|
|
27916
|
+
const targetRow = entry.rowId + offset;
|
|
27917
|
+
while (rows.length <= targetRow) rows.push([]);
|
|
27918
|
+
const row = rows[targetRow];
|
|
27919
|
+
while (row.length <= entry.col) row.push("");
|
|
27920
|
+
row[entry.col] = neutralizeEdited(renderCell(entry.next));
|
|
27921
|
+
}
|
|
27922
|
+
const text = serializeCsvRows(rows, {
|
|
27923
|
+
delimiter: csv.delimiter,
|
|
27924
|
+
newline: csv.newline,
|
|
27925
|
+
trailingNewline: csv.trailingNewline,
|
|
27926
|
+
formulaHandling: "preserve"
|
|
27927
|
+
});
|
|
27928
|
+
const bytes = new TextEncoder().encode(csv.bom ? `\uFEFF${text}` : text).buffer;
|
|
27929
|
+
const savedPath = await mediaProvider.addMedia(path, bytes, mime);
|
|
27930
|
+
if (savedPath !== path) {
|
|
27931
|
+
return {
|
|
27932
|
+
ok: false,
|
|
27933
|
+
savedPath,
|
|
27934
|
+
notices,
|
|
27935
|
+
error: `the host saved a copy at "${savedPath}" instead of overwriting "${path}" \u2014 the document still references the original`
|
|
27936
|
+
};
|
|
27937
|
+
}
|
|
27938
|
+
journal.acknowledge(snapshot);
|
|
27939
|
+
return { ok: true, savedPath, notices, bytes };
|
|
27940
|
+
} catch (err) {
|
|
27887
27941
|
return {
|
|
27888
27942
|
ok: false,
|
|
27889
|
-
savedPath,
|
|
27890
27943
|
notices,
|
|
27891
|
-
error:
|
|
27944
|
+
error: err instanceof Error ? err.message : String(err)
|
|
27892
27945
|
};
|
|
27893
27946
|
}
|
|
27894
|
-
|
|
27895
|
-
|
|
27896
|
-
|
|
27897
|
-
|
|
27898
|
-
|
|
27899
|
-
notices,
|
|
27900
|
-
error: err instanceof Error ? err.message : String(err)
|
|
27901
|
-
};
|
|
27902
|
-
}
|
|
27947
|
+
}).catch((error) => ({
|
|
27948
|
+
ok: false,
|
|
27949
|
+
notices: [],
|
|
27950
|
+
error: error instanceof Error ? error.message : String(error)
|
|
27951
|
+
}));
|
|
27903
27952
|
}
|
|
27904
27953
|
var XLSX_MIME = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
27905
27954
|
async function saveXlsxEdits(options) {
|
|
27906
|
-
const { path,
|
|
27907
|
-
const
|
|
27908
|
-
|
|
27909
|
-
|
|
27910
|
-
|
|
27911
|
-
|
|
27912
|
-
|
|
27913
|
-
|
|
27914
|
-
|
|
27915
|
-
|
|
27916
|
-
|
|
27917
|
-
|
|
27918
|
-
|
|
27919
|
-
|
|
27920
|
-
}));
|
|
27921
|
-
for (const [key, record] of formulaEdits ?? []) {
|
|
27922
|
-
const [row, col] = key.split(":").map(Number);
|
|
27923
|
-
patches.push({
|
|
27955
|
+
const { path, xlsx, journal, mediaProvider, container } = options;
|
|
27956
|
+
const snapshot = journal.entries();
|
|
27957
|
+
const formulaEdits = new Map(options.formulaEdits);
|
|
27958
|
+
return withDataSave(options, async (originalBytes) => {
|
|
27959
|
+
const notices = [];
|
|
27960
|
+
try {
|
|
27961
|
+
if (container) {
|
|
27962
|
+
await backupOriginal(container, path, originalBytes, XLSX_MIME);
|
|
27963
|
+
} else {
|
|
27964
|
+
notices.push("no workspace container \u2014 saved without a backup copy");
|
|
27965
|
+
}
|
|
27966
|
+
const { patchXlsxCellValues, formatCellRef } = await import("@bendyline/squisq-formats/xlsx");
|
|
27967
|
+
const bodyTop = xlsx.anchorRow + (xlsx.hasHeader ? 1 : 0);
|
|
27968
|
+
const patches = snapshot.filter((entry) => !formulaEdits.has(`${entry.rowId}:${entry.col}`)).map((entry) => ({
|
|
27924
27969
|
sheet: xlsx.sheet,
|
|
27925
|
-
ref: formatCellRef(bodyTop +
|
|
27926
|
-
|
|
27927
|
-
|
|
27928
|
-
|
|
27929
|
-
|
|
27930
|
-
|
|
27931
|
-
|
|
27932
|
-
|
|
27970
|
+
ref: formatCellRef(bodyTop + entry.rowId, xlsx.anchorCol + entry.col),
|
|
27971
|
+
value: entry.next
|
|
27972
|
+
}));
|
|
27973
|
+
for (const [key, record] of formulaEdits ?? []) {
|
|
27974
|
+
const [row, col] = key.split(":").map(Number);
|
|
27975
|
+
patches.push({
|
|
27976
|
+
sheet: xlsx.sheet,
|
|
27977
|
+
ref: formatCellRef(bodyTop + row, xlsx.anchorCol + col),
|
|
27978
|
+
...record.formula === null ? { value: record.value ?? null, removeFormula: true } : { formula: record.formula },
|
|
27979
|
+
...record.cachedValue !== void 0 ? { cachedValue: record.cachedValue } : {}
|
|
27980
|
+
});
|
|
27981
|
+
}
|
|
27982
|
+
const bytes = await patchXlsxCellValues(originalBytes, patches);
|
|
27983
|
+
const savedPath = await mediaProvider.addMedia(path, bytes, XLSX_MIME);
|
|
27984
|
+
if (savedPath !== path) {
|
|
27985
|
+
return {
|
|
27986
|
+
ok: false,
|
|
27987
|
+
savedPath,
|
|
27988
|
+
notices,
|
|
27989
|
+
error: `the host saved a copy at "${savedPath}" instead of overwriting "${path}" \u2014 the document still references the original`
|
|
27990
|
+
};
|
|
27991
|
+
}
|
|
27992
|
+
journal.acknowledge(snapshot);
|
|
27993
|
+
return { ok: true, savedPath, notices, bytes };
|
|
27994
|
+
} catch (err) {
|
|
27933
27995
|
return {
|
|
27934
27996
|
ok: false,
|
|
27935
|
-
savedPath,
|
|
27936
27997
|
notices,
|
|
27937
|
-
error:
|
|
27998
|
+
error: err instanceof Error ? err.message : String(err)
|
|
27938
27999
|
};
|
|
27939
28000
|
}
|
|
27940
|
-
|
|
27941
|
-
|
|
27942
|
-
|
|
27943
|
-
|
|
27944
|
-
|
|
27945
|
-
notices,
|
|
27946
|
-
error: err instanceof Error ? err.message : String(err)
|
|
27947
|
-
};
|
|
27948
|
-
}
|
|
28001
|
+
}).catch((error) => ({
|
|
28002
|
+
ok: false,
|
|
28003
|
+
notices: [],
|
|
28004
|
+
error: error instanceof Error ? error.message : String(error)
|
|
28005
|
+
}));
|
|
27949
28006
|
}
|
|
27950
28007
|
|
|
27951
28008
|
// src/dataCard/formulaSupport.ts
|
|
@@ -28002,8 +28059,15 @@ async function createXlsxFormulaSession(meta, options = {}) {
|
|
|
28002
28059
|
engine = calc.createInHouseEngine(engineConfig);
|
|
28003
28060
|
}
|
|
28004
28061
|
}
|
|
28005
|
-
await
|
|
28006
|
-
|
|
28062
|
+
const initial = await (async () => {
|
|
28063
|
+
try {
|
|
28064
|
+
await engine.loadWorkbook(buildSeed(calc, meta));
|
|
28065
|
+
return await engine.evaluateAll();
|
|
28066
|
+
} catch (error) {
|
|
28067
|
+
engine.dispose();
|
|
28068
|
+
throw error;
|
|
28069
|
+
}
|
|
28070
|
+
})();
|
|
28007
28071
|
if (initial.status === "budget-exceeded") {
|
|
28008
28072
|
engine.dispose();
|
|
28009
28073
|
return null;
|
|
@@ -28015,7 +28079,7 @@ async function createXlsxFormulaSession(meta, options = {}) {
|
|
|
28015
28079
|
col: meta.anchorCol + col
|
|
28016
28080
|
});
|
|
28017
28081
|
const formulas = new Map(meta.formulas);
|
|
28018
|
-
const edits = /* @__PURE__ */ new Map();
|
|
28082
|
+
const edits = options.edits ?? /* @__PURE__ */ new Map();
|
|
28019
28083
|
let disposed = false;
|
|
28020
28084
|
const readValues = async (keys) => {
|
|
28021
28085
|
const coords = keys.map((key) => key.split(":").map(Number));
|
|
@@ -28032,6 +28096,13 @@ async function createXlsxFormulaSession(meta, options = {}) {
|
|
|
28032
28096
|
const updates = [];
|
|
28033
28097
|
keyList.forEach((key, index2) => {
|
|
28034
28098
|
const raw = states[index2].value;
|
|
28099
|
+
const formula = formulas.get(key);
|
|
28100
|
+
if (formula !== void 0 && (edits.has(key) || before.get(key) !== displayValue(calc, raw))) {
|
|
28101
|
+
edits.set(key, {
|
|
28102
|
+
formula,
|
|
28103
|
+
...!calc.isCalcError(raw) && raw !== null ? { cachedValue: raw } : {}
|
|
28104
|
+
});
|
|
28105
|
+
}
|
|
28035
28106
|
if (calc.isCalcError(raw) && raw.code === "#NAME?") return;
|
|
28036
28107
|
const value = displayValue(calc, raw);
|
|
28037
28108
|
if (before.get(key) !== value) {
|
|
@@ -28041,7 +28112,13 @@ async function createXlsxFormulaSession(meta, options = {}) {
|
|
|
28041
28112
|
});
|
|
28042
28113
|
return updates;
|
|
28043
28114
|
};
|
|
28044
|
-
|
|
28115
|
+
let mutationTail = Promise.resolve();
|
|
28116
|
+
const serial = (operation) => {
|
|
28117
|
+
const result = mutationTail.catch(() => void 0).then(operation);
|
|
28118
|
+
mutationTail = result;
|
|
28119
|
+
return result;
|
|
28120
|
+
};
|
|
28121
|
+
const session = {
|
|
28045
28122
|
getFormula: (bodyRow, col) => formulas.get(`${bodyRow}:${col}`),
|
|
28046
28123
|
isCellLocked: (bodyRow, col) => {
|
|
28047
28124
|
const key = `${bodyRow}:${col}`;
|
|
@@ -28095,7 +28172,8 @@ async function createXlsxFormulaSession(meta, options = {}) {
|
|
|
28095
28172
|
if (disposed) return [];
|
|
28096
28173
|
const key = `${bodyRow}:${col}`;
|
|
28097
28174
|
formulas.delete(key);
|
|
28098
|
-
edits.
|
|
28175
|
+
if (meta.formulas.has(key)) edits.set(key, { formula: null, value });
|
|
28176
|
+
else edits.delete(key);
|
|
28099
28177
|
const before = await snapshotRegion();
|
|
28100
28178
|
engine.setCellValue(toAddress(bodyRow, col), value);
|
|
28101
28179
|
const result = await engine.evaluateAll();
|
|
@@ -28105,7 +28183,7 @@ async function createXlsxFormulaSession(meta, options = {}) {
|
|
|
28105
28183
|
get dirtyCount() {
|
|
28106
28184
|
return edits.size;
|
|
28107
28185
|
},
|
|
28108
|
-
formulaEdits: () => edits,
|
|
28186
|
+
formulaEdits: () => new Map(edits),
|
|
28109
28187
|
async discard() {
|
|
28110
28188
|
const before = await snapshotRegion();
|
|
28111
28189
|
const staleKeys = new Set(formulas.keys());
|
|
@@ -28115,29 +28193,49 @@ async function createXlsxFormulaSession(meta, options = {}) {
|
|
|
28115
28193
|
await engine.loadWorkbook(buildSeed(calc, meta));
|
|
28116
28194
|
await engine.evaluateAll();
|
|
28117
28195
|
for (const key of formulas.keys()) staleKeys.add(key);
|
|
28118
|
-
|
|
28119
|
-
},
|
|
28120
|
-
markSaved() {
|
|
28196
|
+
const updates = await diffAgainst(before, staleKeys);
|
|
28121
28197
|
edits.clear();
|
|
28198
|
+
return updates;
|
|
28199
|
+
},
|
|
28200
|
+
markSaved(snapshot = new Map(edits), baseline) {
|
|
28201
|
+
if (baseline) meta = baseline;
|
|
28202
|
+
for (const [key, record] of snapshot) {
|
|
28203
|
+
if (edits.get(key) === record) edits.delete(key);
|
|
28204
|
+
}
|
|
28122
28205
|
},
|
|
28123
28206
|
dispose() {
|
|
28124
28207
|
disposed = true;
|
|
28125
28208
|
engine.dispose();
|
|
28209
|
+
},
|
|
28210
|
+
flush: async () => {
|
|
28211
|
+
await mutationTail;
|
|
28126
28212
|
}
|
|
28127
28213
|
};
|
|
28214
|
+
return {
|
|
28215
|
+
...session,
|
|
28216
|
+
get dirtyCount() {
|
|
28217
|
+
return session.dirtyCount;
|
|
28218
|
+
},
|
|
28219
|
+
commitFormula: (...args) => serial(() => session.commitFormula(...args)),
|
|
28220
|
+
noteValueEdit: (...args) => serial(() => session.noteValueEdit(...args)),
|
|
28221
|
+
discard: () => serial(() => session.discard())
|
|
28222
|
+
};
|
|
28128
28223
|
}
|
|
28129
28224
|
|
|
28130
|
-
// src/dataCard/
|
|
28131
|
-
|
|
28132
|
-
var XLSX_SESSION_LOCKED_REASON = "Date cells and shared-formula masters stay locked; other formulas are editable";
|
|
28133
|
-
var gridModulePromise = null;
|
|
28225
|
+
// src/dataCard/loadGridModule.ts
|
|
28226
|
+
var pending = null;
|
|
28134
28227
|
function loadGridModule() {
|
|
28135
|
-
|
|
28136
|
-
|
|
28228
|
+
pending ?? (pending = import("@bendyline/squisq-grid-react").catch(() => {
|
|
28229
|
+
pending = null;
|
|
28137
28230
|
return null;
|
|
28138
28231
|
}));
|
|
28139
|
-
return
|
|
28232
|
+
return pending;
|
|
28140
28233
|
}
|
|
28234
|
+
|
|
28235
|
+
// src/dataCard/DataCardWidget.tsx
|
|
28236
|
+
import { jsx as jsx54, jsxs as jsxs43 } from "react/jsx-runtime";
|
|
28237
|
+
var XLSX_SESSION_LOCKED_REASON = "Date cells and shared-formula masters stay locked; other formulas are editable";
|
|
28238
|
+
var pendingFormulas = /* @__PURE__ */ new WeakMap();
|
|
28141
28239
|
function useCardLink(editor, blockId) {
|
|
28142
28240
|
const [version, setVersion] = useState47(0);
|
|
28143
28241
|
useEffect38(() => {
|
|
@@ -28190,14 +28288,23 @@ function DataCardWidget({
|
|
|
28190
28288
|
const [view, setView] = useState47(EMPTY_TABLE_VIEW_STATE);
|
|
28191
28289
|
const [viewPersisted, setViewPersisted] = useState47(false);
|
|
28192
28290
|
const [saving, setSaving] = useState47(false);
|
|
28291
|
+
const savingRef = useRef39(false);
|
|
28193
28292
|
const [saveNotice, setSaveNotice] = useState47(null);
|
|
28194
28293
|
const [formulaDirty, setFormulaDirty] = useState47(0);
|
|
28195
28294
|
const gridRef = useRef39(null);
|
|
28196
28295
|
const href = link?.href ?? null;
|
|
28197
28296
|
const cardPos = link?.pos ?? null;
|
|
28297
|
+
const activeProvider = getMediaProvider();
|
|
28298
|
+
const activeContainer = getContainer?.() ?? null;
|
|
28299
|
+
const regionParams = href && cardPos !== null ? readHeadingViewBinding(editor, cardPos, href).params : {};
|
|
28300
|
+
const regionIdentity = JSON.stringify([
|
|
28301
|
+
regionParams.sheet,
|
|
28302
|
+
regionParams.anchor,
|
|
28303
|
+
regionParams.headerRow
|
|
28304
|
+
]);
|
|
28198
28305
|
useEffect38(() => {
|
|
28199
28306
|
if (!href || cardPos === null) return;
|
|
28200
|
-
const provider =
|
|
28307
|
+
const provider = activeProvider;
|
|
28201
28308
|
if (!provider) {
|
|
28202
28309
|
setState3({ kind: "meta", size: null, preview: null });
|
|
28203
28310
|
return;
|
|
@@ -28206,6 +28313,9 @@ function DataCardWidget({
|
|
|
28206
28313
|
setState3({ kind: "loading" });
|
|
28207
28314
|
void (async () => {
|
|
28208
28315
|
let size2 = null;
|
|
28316
|
+
let loadingStore = null;
|
|
28317
|
+
let loadingSession = null;
|
|
28318
|
+
let retained = false;
|
|
28209
28319
|
try {
|
|
28210
28320
|
const entries = await provider.listMedia();
|
|
28211
28321
|
const entry = entries.find((e2) => e2.name === href);
|
|
@@ -28249,26 +28359,61 @@ function DataCardWidget({
|
|
|
28249
28359
|
...binding.params.headerRow !== void 0 ? { headerRow: binding.params.headerRow !== "false" } : {}
|
|
28250
28360
|
});
|
|
28251
28361
|
if (cancelled) return;
|
|
28362
|
+
const container = activeContainer;
|
|
28363
|
+
const region = JSON.stringify(
|
|
28364
|
+
ingested.xlsx ? [
|
|
28365
|
+
ingested.xlsx.sheet,
|
|
28366
|
+
ingested.xlsx.anchorRow,
|
|
28367
|
+
ingested.xlsx.anchorCol,
|
|
28368
|
+
ingested.xlsx.hasHeader
|
|
28369
|
+
] : [ingested.csv?.hasHeader ?? true]
|
|
28370
|
+
);
|
|
28371
|
+
const journal = module.journalFor(href, revision, {
|
|
28372
|
+
owner: container ?? provider,
|
|
28373
|
+
region
|
|
28374
|
+
});
|
|
28375
|
+
let formulaEdits = pendingFormulas.get(journal);
|
|
28376
|
+
if (!formulaEdits) {
|
|
28377
|
+
formulaEdits = /* @__PURE__ */ new Map();
|
|
28378
|
+
pendingFormulas.set(journal, formulaEdits);
|
|
28379
|
+
}
|
|
28380
|
+
const restoredFormulas = new Map(formulaEdits);
|
|
28252
28381
|
let formulaSession = null;
|
|
28253
28382
|
if (ingested.xlsx) {
|
|
28254
28383
|
try {
|
|
28255
28384
|
const engineFactory = getCalcEngineFactory?.();
|
|
28256
|
-
formulaSession = await createXlsxFormulaSession(
|
|
28257
|
-
|
|
28258
|
-
|
|
28259
|
-
);
|
|
28385
|
+
formulaSession = await createXlsxFormulaSession(ingested.xlsx, {
|
|
28386
|
+
...engineFactory ? { engineFactory } : {},
|
|
28387
|
+
edits: formulaEdits
|
|
28388
|
+
});
|
|
28389
|
+
loadingSession = formulaSession;
|
|
28260
28390
|
} catch {
|
|
28261
28391
|
formulaSession = null;
|
|
28262
28392
|
}
|
|
28263
28393
|
}
|
|
28264
28394
|
if (cancelled) {
|
|
28265
|
-
formulaSession?.dispose();
|
|
28266
28395
|
return;
|
|
28267
28396
|
}
|
|
28268
|
-
gridRef.current?.formulaSession?.dispose();
|
|
28269
|
-
gridRef.current?.provider.dispose();
|
|
28270
28397
|
const storeProvider = new module.TableStoreClient(ingested.ingest);
|
|
28271
|
-
|
|
28398
|
+
loadingStore = storeProvider;
|
|
28399
|
+
await storeProvider.describe();
|
|
28400
|
+
const restoredValues = journal.entries().map(({ rowId, col, next }) => ({ rowId, col, value: next }));
|
|
28401
|
+
if (restoredValues.length) await storeProvider.applyEdits(restoredValues);
|
|
28402
|
+
if (formulaSession) {
|
|
28403
|
+
for (const edit of restoredValues) {
|
|
28404
|
+
if (restoredFormulas.has(`${edit.rowId}:${edit.col}`)) continue;
|
|
28405
|
+
const updates = await formulaSession.noteValueEdit(edit.rowId, edit.col, edit.value);
|
|
28406
|
+
if (updates.length) await storeProvider.applyEdits(updates);
|
|
28407
|
+
}
|
|
28408
|
+
for (const [key, record] of restoredFormulas) {
|
|
28409
|
+
const [row, col] = key.split(":").map(Number);
|
|
28410
|
+
const updates = record.formula === null ? await formulaSession.noteValueEdit(row, col, record.value ?? null) : (await formulaSession.commitFormula(row, col, record.formula)).updates ?? [];
|
|
28411
|
+
if (updates.length) await storeProvider.applyEdits(updates);
|
|
28412
|
+
}
|
|
28413
|
+
}
|
|
28414
|
+
if (cancelled) {
|
|
28415
|
+
return;
|
|
28416
|
+
}
|
|
28272
28417
|
const grid2 = {
|
|
28273
28418
|
module,
|
|
28274
28419
|
provider: storeProvider,
|
|
@@ -28276,13 +28421,19 @@ function DataCardWidget({
|
|
|
28276
28421
|
ingested,
|
|
28277
28422
|
bytes,
|
|
28278
28423
|
headers: ingested.ingest.headers,
|
|
28279
|
-
formulaSession
|
|
28424
|
+
formulaSession,
|
|
28425
|
+
mediaProvider: provider,
|
|
28426
|
+
container,
|
|
28427
|
+
path: href
|
|
28280
28428
|
};
|
|
28429
|
+
gridRef.current?.formulaSession?.dispose();
|
|
28430
|
+
gridRef.current?.provider.dispose();
|
|
28281
28431
|
gridRef.current = grid2;
|
|
28432
|
+
retained = true;
|
|
28282
28433
|
setView(viewStateFromBinding(binding, ingested.ingest.headers));
|
|
28283
28434
|
setViewPersisted(binding.persisted);
|
|
28284
28435
|
setSaveNotice(null);
|
|
28285
|
-
setFormulaDirty(0);
|
|
28436
|
+
setFormulaDirty(formulaSession?.dirtyCount ?? 0);
|
|
28286
28437
|
setState3({ kind: "grid", size: size2, grid: grid2 });
|
|
28287
28438
|
return;
|
|
28288
28439
|
}
|
|
@@ -28302,12 +28453,17 @@ function DataCardWidget({
|
|
|
28302
28453
|
reason: err instanceof Error ? err.message : String(err)
|
|
28303
28454
|
});
|
|
28304
28455
|
}
|
|
28456
|
+
} finally {
|
|
28457
|
+
if (!retained) {
|
|
28458
|
+
loadingStore?.dispose();
|
|
28459
|
+
loadingSession?.dispose();
|
|
28460
|
+
}
|
|
28305
28461
|
}
|
|
28306
28462
|
})();
|
|
28307
28463
|
return () => {
|
|
28308
28464
|
cancelled = true;
|
|
28309
28465
|
};
|
|
28310
|
-
}, [href, revision,
|
|
28466
|
+
}, [href, revision, activeProvider, activeContainer, regionIdentity, editor]);
|
|
28311
28467
|
useEffect38(
|
|
28312
28468
|
() => () => {
|
|
28313
28469
|
gridRef.current?.formulaSession?.dispose();
|
|
@@ -28327,34 +28483,61 @@ function DataCardWidget({
|
|
|
28327
28483
|
);
|
|
28328
28484
|
const handleSave = useCallback36(async () => {
|
|
28329
28485
|
const grid2 = gridRef.current;
|
|
28330
|
-
const provider =
|
|
28486
|
+
const provider = grid2?.mediaProvider;
|
|
28331
28487
|
if (!grid2 || !provider || !href || !grid2.ingested.csv && !grid2.ingested.xlsx) return;
|
|
28488
|
+
if (savingRef.current) return;
|
|
28489
|
+
savingRef.current = true;
|
|
28332
28490
|
setSaving(true);
|
|
28333
28491
|
try {
|
|
28492
|
+
await grid2.formulaSession?.flush();
|
|
28334
28493
|
const shared = {
|
|
28335
|
-
path:
|
|
28494
|
+
path: grid2.path,
|
|
28336
28495
|
originalBytes: grid2.bytes,
|
|
28337
28496
|
journal: grid2.journal,
|
|
28338
28497
|
mediaProvider: provider,
|
|
28339
|
-
container:
|
|
28498
|
+
container: grid2.container
|
|
28340
28499
|
};
|
|
28500
|
+
const formulaSnapshot = grid2.formulaSession?.formulaEdits();
|
|
28341
28501
|
const result = grid2.ingested.csv ? await saveCsvEdits({ ...shared, csv: grid2.ingested.csv }) : await saveXlsxEdits({
|
|
28342
28502
|
...shared,
|
|
28343
28503
|
xlsx: grid2.ingested.xlsx,
|
|
28344
|
-
...
|
|
28504
|
+
...formulaSnapshot ? { formulaEdits: formulaSnapshot } : {}
|
|
28345
28505
|
});
|
|
28346
|
-
|
|
28347
|
-
|
|
28348
|
-
|
|
28506
|
+
if (gridRef.current === grid2)
|
|
28507
|
+
setSaveNotice(
|
|
28508
|
+
result.ok ? result.notices.length > 0 ? `saved (${result.notices.join("; ")})` : null : result.error ?? "save failed"
|
|
28509
|
+
);
|
|
28349
28510
|
if (result.ok) {
|
|
28350
|
-
|
|
28351
|
-
|
|
28352
|
-
|
|
28511
|
+
if (result.bytes) {
|
|
28512
|
+
grid2.bytes = result.bytes;
|
|
28513
|
+
const baseline = await ingestSidecarBytes(
|
|
28514
|
+
result.bytes,
|
|
28515
|
+
dataExtensionOf(grid2.path),
|
|
28516
|
+
grid2.ingested.xlsx ? {
|
|
28517
|
+
sheet: grid2.ingested.xlsx.sheet,
|
|
28518
|
+
anchor: (await import("@bendyline/squisq-formats/xlsx")).formatCellRef(
|
|
28519
|
+
grid2.ingested.xlsx.anchorRow,
|
|
28520
|
+
grid2.ingested.xlsx.anchorCol
|
|
28521
|
+
),
|
|
28522
|
+
headerRow: grid2.ingested.xlsx.hasHeader
|
|
28523
|
+
} : { headerRow: grid2.ingested.csv?.hasHeader }
|
|
28524
|
+
);
|
|
28525
|
+
grid2.ingested = baseline;
|
|
28526
|
+
}
|
|
28527
|
+
grid2.formulaSession?.markSaved(formulaSnapshot, grid2.ingested.xlsx);
|
|
28528
|
+
if (gridRef.current === grid2) {
|
|
28529
|
+
setFormulaDirty(grid2.formulaSession?.dirtyCount ?? 0);
|
|
28530
|
+
onMediaSaved?.();
|
|
28531
|
+
}
|
|
28353
28532
|
}
|
|
28533
|
+
} catch (error) {
|
|
28534
|
+
if (gridRef.current === grid2)
|
|
28535
|
+
setSaveNotice(error instanceof Error ? error.message : String(error));
|
|
28354
28536
|
} finally {
|
|
28537
|
+
savingRef.current = false;
|
|
28355
28538
|
setSaving(false);
|
|
28356
28539
|
}
|
|
28357
|
-
}, [
|
|
28540
|
+
}, [href, onMediaSaved]);
|
|
28358
28541
|
if (!link || !href) return null;
|
|
28359
28542
|
const fileName = href.split("/").pop() ?? href;
|
|
28360
28543
|
const size = state.kind === "meta" || state.kind === "grid" ? state.size : null;
|
|
@@ -34764,8 +34947,8 @@ function playTimelineMediaAt(root, time) {
|
|
|
34764
34947
|
const end = Number(el.dataset.absEnd);
|
|
34765
34948
|
if (!Number.isFinite(start) || !Number.isFinite(end) || time < start || time >= end) return;
|
|
34766
34949
|
try {
|
|
34767
|
-
const
|
|
34768
|
-
|
|
34950
|
+
const pending2 = el.play();
|
|
34951
|
+
pending2?.catch(() => {
|
|
34769
34952
|
});
|
|
34770
34953
|
} catch {
|
|
34771
34954
|
}
|
|
@@ -37836,7 +38019,6 @@ import {
|
|
|
37836
38019
|
useState as useState68
|
|
37837
38020
|
} from "react";
|
|
37838
38021
|
import { parseTableViewState as parseTableViewState2 } from "@bendyline/squisq/table";
|
|
37839
|
-
import { DataGrid, TableStoreClient } from "@bendyline/squisq-grid-react";
|
|
37840
38022
|
|
|
37841
38023
|
// src/slideshow/slideshowDataSources.ts
|
|
37842
38024
|
import { isDataFilePath as isDataFilePath2, resolveTemplateName as resolveTemplateName3 } from "@bendyline/squisq/doc";
|
|
@@ -37938,8 +38120,18 @@ function SlideshowDataGridRenderer({
|
|
|
37938
38120
|
const source = sourceForBlock(sources, block);
|
|
37939
38121
|
const activeSourceKey = sourceKey(source);
|
|
37940
38122
|
const [remote, setRemote] = useState68({ key: "", status: "idle" });
|
|
38123
|
+
const [gridModule, setGridModule] = useState68(null);
|
|
37941
38124
|
useEffect59(() => {
|
|
37942
|
-
|
|
38125
|
+
let active = true;
|
|
38126
|
+
void loadGridModule().then((module) => {
|
|
38127
|
+
if (active) setGridModule(module);
|
|
38128
|
+
});
|
|
38129
|
+
return () => {
|
|
38130
|
+
active = false;
|
|
38131
|
+
};
|
|
38132
|
+
}, []);
|
|
38133
|
+
useEffect59(() => {
|
|
38134
|
+
if (!container || !source || !gridModule) {
|
|
37943
38135
|
setRemote({ key: activeSourceKey, status: "idle" });
|
|
37944
38136
|
return;
|
|
37945
38137
|
}
|
|
@@ -37955,7 +38147,8 @@ function SlideshowDataGridRenderer({
|
|
|
37955
38147
|
...source.anchor ? { anchor: source.anchor } : {},
|
|
37956
38148
|
...source.headerRow !== void 0 ? { headerRow: source.headerRow } : {}
|
|
37957
38149
|
});
|
|
37958
|
-
|
|
38150
|
+
if (cancelled) return;
|
|
38151
|
+
const provider2 = new gridModule.TableStoreClient(ingest2);
|
|
37959
38152
|
ownedProvider = provider2;
|
|
37960
38153
|
await provider2.describe();
|
|
37961
38154
|
if (cancelled) {
|
|
@@ -37973,7 +38166,7 @@ function SlideshowDataGridRenderer({
|
|
|
37973
38166
|
cancelled = true;
|
|
37974
38167
|
ownedProvider?.dispose();
|
|
37975
38168
|
};
|
|
37976
|
-
}, [activeSourceKey, container, mediaRevision]);
|
|
38169
|
+
}, [activeSourceKey, container, mediaRevision, gridModule]);
|
|
37977
38170
|
const currentRemote = remote.key === activeSourceKey ? remote : void 0;
|
|
37978
38171
|
const previewRows = useMemo52(
|
|
37979
38172
|
() => Array.isArray(layer.content.rows) ? layer.content.rows : [],
|
|
@@ -37985,8 +38178,8 @@ function SlideshowDataGridRenderer({
|
|
|
37985
38178
|
);
|
|
37986
38179
|
const useLocalGrid = (!source || currentRemote?.status === "error") && previewRows.length > (layer.content.maxVisibleRows ?? 10);
|
|
37987
38180
|
const localProvider = useMemo52(
|
|
37988
|
-
() => useLocalGrid ? new TableStoreClient({ headers: previewHeaders, cells: previewRows }) : null,
|
|
37989
|
-
[previewHeaders, previewRows, useLocalGrid]
|
|
38181
|
+
() => useLocalGrid && gridModule ? new gridModule.TableStoreClient({ headers: previewHeaders, cells: previewRows }) : null,
|
|
38182
|
+
[previewHeaders, previewRows, useLocalGrid, gridModule]
|
|
37990
38183
|
);
|
|
37991
38184
|
useEffect59(() => () => localProvider?.dispose(), [localProvider]);
|
|
37992
38185
|
const ready = currentRemote?.status === "ready" ? currentRemote : void 0;
|
|
@@ -37995,7 +38188,7 @@ function SlideshowDataGridRenderer({
|
|
|
37995
38188
|
const initialView = ready?.initialView ?? EMPTY_VIEW;
|
|
37996
38189
|
const [view, setView] = useState68(initialView);
|
|
37997
38190
|
useEffect59(() => setView(initialView), [initialView, provider]);
|
|
37998
|
-
if (!provider || !ingest) return /* @__PURE__ */ jsx77(Fragment22, { children: fallback });
|
|
38191
|
+
if (!provider || !ingest || !gridModule) return /* @__PURE__ */ jsx77(Fragment22, { children: fallback });
|
|
37999
38192
|
const { style } = layer.content;
|
|
38000
38193
|
const rowHeight = Math.max(32, style.fontSize * 2.1);
|
|
38001
38194
|
const footerHeight = Math.max(28, style.fontSize * 1.5);
|
|
@@ -38025,7 +38218,7 @@ function SlideshowDataGridRenderer({
|
|
|
38025
38218
|
"--squisq-grid-resize-handle": style.headerBackground
|
|
38026
38219
|
};
|
|
38027
38220
|
return /* @__PURE__ */ jsx77("div", { className: "squisq-slideshow-data-grid", style: gridStyle, children: /* @__PURE__ */ jsx77(
|
|
38028
|
-
DataGrid,
|
|
38221
|
+
gridModule.DataGrid,
|
|
38029
38222
|
{
|
|
38030
38223
|
provider,
|
|
38031
38224
|
view,
|