@underverse-ui/underverse 1.0.150 → 1.0.152
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/api-reference.json +1 -1
- package/dist/index.cjs +1183 -299
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +1184 -299
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1029,6 +1029,10 @@ var en_default = {
|
|
|
1029
1029
|
borderWidth: "Border Width",
|
|
1030
1030
|
borderColor: "Border Color",
|
|
1031
1031
|
clearBorder: "Clear Border",
|
|
1032
|
+
formula: "Formula",
|
|
1033
|
+
apply: "Apply",
|
|
1034
|
+
clear: "Clear",
|
|
1035
|
+
recalculate: "Recalculate",
|
|
1032
1036
|
done: "Done"
|
|
1033
1037
|
},
|
|
1034
1038
|
callout: {
|
|
@@ -1405,6 +1409,10 @@ var vi_default = {
|
|
|
1405
1409
|
borderWidth: "\u0110\u1ED9 d\xE0y vi\u1EC1n",
|
|
1406
1410
|
borderColor: "M\xE0u vi\u1EC1n",
|
|
1407
1411
|
clearBorder: "X\xF3a vi\u1EC1n",
|
|
1412
|
+
formula: "C\xF4ng th\u1EE9c",
|
|
1413
|
+
apply: "\xC1p d\u1EE5ng",
|
|
1414
|
+
clear: "X\xF3a",
|
|
1415
|
+
recalculate: "T\xEDnh l\u1EA1i",
|
|
1408
1416
|
done: "Xong"
|
|
1409
1417
|
},
|
|
1410
1418
|
callout: {
|
|
@@ -26140,6 +26148,10 @@ function getTableCellAttrs(cell, styles, defaultBackgroundColor) {
|
|
|
26140
26148
|
if (borderAttrs.borderColor) attrs.borderColor = borderAttrs.borderColor;
|
|
26141
26149
|
if (borderAttrs.borderStyle) attrs.borderStyle = borderAttrs.borderStyle;
|
|
26142
26150
|
if (borderAttrs.borderWidth) attrs.borderWidth = borderAttrs.borderWidth;
|
|
26151
|
+
if (cell.getAttribute("data-cell-id")) attrs.cellId = cell.getAttribute("data-cell-id") ?? void 0;
|
|
26152
|
+
if (cell.getAttribute("data-number-format")) attrs.numberFormat = cell.getAttribute("data-number-format") ?? void 0;
|
|
26153
|
+
if (cell.getAttribute("data-formula")) attrs.formula = cell.getAttribute("data-formula") ?? void 0;
|
|
26154
|
+
if (cell.getAttribute("data-computed-value")) attrs.computedValue = cell.getAttribute("data-computed-value") ?? void 0;
|
|
26143
26155
|
if (colspan > 1) attrs.colspan = colspan;
|
|
26144
26156
|
if (rowspan > 1) attrs.rowspan = rowspan;
|
|
26145
26157
|
if (colwidth) attrs.colwidth = colwidth;
|
|
@@ -27767,6 +27779,16 @@ var CodeBlockView = ({
|
|
|
27767
27779
|
};
|
|
27768
27780
|
|
|
27769
27781
|
// src/components/UEditor/extensions.ts
|
|
27782
|
+
function getFormulaStateAttributes(attributes) {
|
|
27783
|
+
const formula = attributes["data-formula"];
|
|
27784
|
+
if (!formula) {
|
|
27785
|
+
return {};
|
|
27786
|
+
}
|
|
27787
|
+
const computedValue = String(attributes["data-computed-value"] ?? "");
|
|
27788
|
+
return {
|
|
27789
|
+
"data-formula-state": computedValue.startsWith("#") ? "error" : "computed"
|
|
27790
|
+
};
|
|
27791
|
+
}
|
|
27770
27792
|
var CustomTableCell = import_extension_table_cell.default.extend({
|
|
27771
27793
|
addAttributes() {
|
|
27772
27794
|
return {
|
|
@@ -27812,6 +27834,46 @@ var CustomTableCell = import_extension_table_cell.default.extend({
|
|
|
27812
27834
|
"data-border-width": attributes.borderWidth
|
|
27813
27835
|
};
|
|
27814
27836
|
}
|
|
27837
|
+
},
|
|
27838
|
+
cellId: {
|
|
27839
|
+
default: null,
|
|
27840
|
+
parseHTML: (element) => element.getAttribute("data-cell-id") || null,
|
|
27841
|
+
renderHTML: (attributes) => {
|
|
27842
|
+
if (!attributes.cellId) return {};
|
|
27843
|
+
return {
|
|
27844
|
+
"data-cell-id": attributes.cellId
|
|
27845
|
+
};
|
|
27846
|
+
}
|
|
27847
|
+
},
|
|
27848
|
+
numberFormat: {
|
|
27849
|
+
default: null,
|
|
27850
|
+
parseHTML: (element) => element.getAttribute("data-number-format") || null,
|
|
27851
|
+
renderHTML: (attributes) => {
|
|
27852
|
+
if (!attributes.numberFormat) return {};
|
|
27853
|
+
return {
|
|
27854
|
+
"data-number-format": attributes.numberFormat
|
|
27855
|
+
};
|
|
27856
|
+
}
|
|
27857
|
+
},
|
|
27858
|
+
formula: {
|
|
27859
|
+
default: null,
|
|
27860
|
+
parseHTML: (element) => element.getAttribute("data-formula") || null,
|
|
27861
|
+
renderHTML: (attributes) => {
|
|
27862
|
+
if (!attributes.formula) return {};
|
|
27863
|
+
return {
|
|
27864
|
+
"data-formula": attributes.formula
|
|
27865
|
+
};
|
|
27866
|
+
}
|
|
27867
|
+
},
|
|
27868
|
+
computedValue: {
|
|
27869
|
+
default: null,
|
|
27870
|
+
parseHTML: (element) => element.getAttribute("data-computed-value") || null,
|
|
27871
|
+
renderHTML: (attributes) => {
|
|
27872
|
+
if (!attributes.computedValue) return {};
|
|
27873
|
+
return {
|
|
27874
|
+
"data-computed-value": attributes.computedValue
|
|
27875
|
+
};
|
|
27876
|
+
}
|
|
27815
27877
|
}
|
|
27816
27878
|
};
|
|
27817
27879
|
},
|
|
@@ -27829,7 +27891,7 @@ var CustomTableCell = import_extension_table_cell.default.extend({
|
|
|
27829
27891
|
mergedStyle = mergedStyle.replace(/^;/, "").trim();
|
|
27830
27892
|
return [
|
|
27831
27893
|
"td",
|
|
27832
|
-
(0, import_core13.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes, mergedStyle ? { style: mergedStyle } : {}),
|
|
27894
|
+
(0, import_core13.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes, getFormulaStateAttributes(HTMLAttributes), mergedStyle ? { style: mergedStyle } : {}),
|
|
27833
27895
|
0
|
|
27834
27896
|
];
|
|
27835
27897
|
}
|
|
@@ -27879,6 +27941,46 @@ var CustomTableHeader = import_extension_table_header.default.extend({
|
|
|
27879
27941
|
"data-border-width": attributes.borderWidth
|
|
27880
27942
|
};
|
|
27881
27943
|
}
|
|
27944
|
+
},
|
|
27945
|
+
cellId: {
|
|
27946
|
+
default: null,
|
|
27947
|
+
parseHTML: (element) => element.getAttribute("data-cell-id") || null,
|
|
27948
|
+
renderHTML: (attributes) => {
|
|
27949
|
+
if (!attributes.cellId) return {};
|
|
27950
|
+
return {
|
|
27951
|
+
"data-cell-id": attributes.cellId
|
|
27952
|
+
};
|
|
27953
|
+
}
|
|
27954
|
+
},
|
|
27955
|
+
numberFormat: {
|
|
27956
|
+
default: null,
|
|
27957
|
+
parseHTML: (element) => element.getAttribute("data-number-format") || null,
|
|
27958
|
+
renderHTML: (attributes) => {
|
|
27959
|
+
if (!attributes.numberFormat) return {};
|
|
27960
|
+
return {
|
|
27961
|
+
"data-number-format": attributes.numberFormat
|
|
27962
|
+
};
|
|
27963
|
+
}
|
|
27964
|
+
},
|
|
27965
|
+
formula: {
|
|
27966
|
+
default: null,
|
|
27967
|
+
parseHTML: (element) => element.getAttribute("data-formula") || null,
|
|
27968
|
+
renderHTML: (attributes) => {
|
|
27969
|
+
if (!attributes.formula) return {};
|
|
27970
|
+
return {
|
|
27971
|
+
"data-formula": attributes.formula
|
|
27972
|
+
};
|
|
27973
|
+
}
|
|
27974
|
+
},
|
|
27975
|
+
computedValue: {
|
|
27976
|
+
default: null,
|
|
27977
|
+
parseHTML: (element) => element.getAttribute("data-computed-value") || null,
|
|
27978
|
+
renderHTML: (attributes) => {
|
|
27979
|
+
if (!attributes.computedValue) return {};
|
|
27980
|
+
return {
|
|
27981
|
+
"data-computed-value": attributes.computedValue
|
|
27982
|
+
};
|
|
27983
|
+
}
|
|
27882
27984
|
}
|
|
27883
27985
|
};
|
|
27884
27986
|
},
|
|
@@ -27896,7 +27998,7 @@ var CustomTableHeader = import_extension_table_header.default.extend({
|
|
|
27896
27998
|
mergedStyle = mergedStyle.replace(/^;/, "").trim();
|
|
27897
27999
|
return [
|
|
27898
28000
|
"th",
|
|
27899
|
-
(0, import_core13.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes, mergedStyle ? { style: mergedStyle } : {}),
|
|
28001
|
+
(0, import_core13.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes, getFormulaStateAttributes(HTMLAttributes), mergedStyle ? { style: mergedStyle } : {}),
|
|
27900
28002
|
0
|
|
27901
28003
|
];
|
|
27902
28004
|
}
|
|
@@ -28591,6 +28693,34 @@ function collectChildren(node) {
|
|
|
28591
28693
|
function createEmptyCellNode(cellNode) {
|
|
28592
28694
|
return cellNode.type.createAndFill(cellNode.attrs) ?? cellNode;
|
|
28593
28695
|
}
|
|
28696
|
+
function createCellCopyForColumnDuplicate(cellNode) {
|
|
28697
|
+
return cellNode.type.create(cellNode.attrs, cellNode.content);
|
|
28698
|
+
}
|
|
28699
|
+
function getTableRows(tableNode) {
|
|
28700
|
+
const rows = [];
|
|
28701
|
+
tableNode.forEach((rowNode, rowOffset) => {
|
|
28702
|
+
const cells = [];
|
|
28703
|
+
rowNode.forEach((cellNode, cellOffset, index) => {
|
|
28704
|
+
cells.push({
|
|
28705
|
+
index,
|
|
28706
|
+
node: cellNode,
|
|
28707
|
+
relativePos: rowOffset + 1 + cellOffset
|
|
28708
|
+
});
|
|
28709
|
+
});
|
|
28710
|
+
rows.push({
|
|
28711
|
+
node: rowNode,
|
|
28712
|
+
cells
|
|
28713
|
+
});
|
|
28714
|
+
});
|
|
28715
|
+
return rows;
|
|
28716
|
+
}
|
|
28717
|
+
function safeFindCell(map, relativePos) {
|
|
28718
|
+
try {
|
|
28719
|
+
return map.findCell(relativePos);
|
|
28720
|
+
} catch {
|
|
28721
|
+
return null;
|
|
28722
|
+
}
|
|
28723
|
+
}
|
|
28594
28724
|
function getSelectedTableRect(editor) {
|
|
28595
28725
|
const cellSelection = getCellSelectionPositions(editor.state.selection);
|
|
28596
28726
|
if (cellSelection) {
|
|
@@ -28716,34 +28846,49 @@ function duplicateTableRowAt(editor, rowIndex, cellPos) {
|
|
|
28716
28846
|
}
|
|
28717
28847
|
function clearTableRowAt(editor, rowIndex, cellPos) {
|
|
28718
28848
|
return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
|
|
28719
|
-
const
|
|
28720
|
-
|
|
28721
|
-
|
|
28722
|
-
|
|
28723
|
-
|
|
28849
|
+
const map = import_tables.TableMap.get(tableNode);
|
|
28850
|
+
if (rowIndex < 0 || rowIndex >= map.height) return null;
|
|
28851
|
+
const rows = getTableRows(tableNode).map((rowInfo) => {
|
|
28852
|
+
const cells = collectChildren(rowInfo.node);
|
|
28853
|
+
for (const entry of rowInfo.cells) {
|
|
28854
|
+
const rect = safeFindCell(map, entry.relativePos);
|
|
28855
|
+
if (!rect || rect.top > rowIndex || rowIndex >= rect.bottom) continue;
|
|
28856
|
+
cells[entry.index] = createEmptyCellNode(entry.node);
|
|
28857
|
+
}
|
|
28858
|
+
return rowInfo.node.type.create(rowInfo.node.attrs, cells);
|
|
28859
|
+
});
|
|
28724
28860
|
return tableNode.type.create(tableNode.attrs, rows);
|
|
28725
28861
|
});
|
|
28726
28862
|
}
|
|
28727
28863
|
function duplicateTableColumnAt(editor, columnIndex, cellPos) {
|
|
28728
28864
|
return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
|
|
28729
|
-
const
|
|
28730
|
-
|
|
28731
|
-
|
|
28732
|
-
|
|
28733
|
-
|
|
28734
|
-
|
|
28865
|
+
const map = import_tables.TableMap.get(tableNode);
|
|
28866
|
+
if (columnIndex < 0 || columnIndex >= map.width) return null;
|
|
28867
|
+
const rows = getTableRows(tableNode).map((rowInfo, rowIndex) => {
|
|
28868
|
+
const cells = collectChildren(rowInfo.node);
|
|
28869
|
+
const sourceCell = rowInfo.cells.find((entry) => {
|
|
28870
|
+
const rect = safeFindCell(map, entry.relativePos);
|
|
28871
|
+
return rect && rect.top === rowIndex && rect.left <= columnIndex && columnIndex < rect.right;
|
|
28872
|
+
});
|
|
28873
|
+
if (!sourceCell) return rowInfo.node;
|
|
28874
|
+
cells.splice(sourceCell.index + 1, 0, createCellCopyForColumnDuplicate(sourceCell.node));
|
|
28875
|
+
return rowInfo.node.type.create(rowInfo.node.attrs, cells);
|
|
28735
28876
|
});
|
|
28736
28877
|
return tableNode.type.create(tableNode.attrs, rows);
|
|
28737
28878
|
});
|
|
28738
28879
|
}
|
|
28739
28880
|
function clearTableColumnAt(editor, columnIndex, cellPos) {
|
|
28740
28881
|
return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
|
|
28741
|
-
const
|
|
28742
|
-
|
|
28743
|
-
|
|
28744
|
-
|
|
28745
|
-
|
|
28746
|
-
|
|
28882
|
+
const map = import_tables.TableMap.get(tableNode);
|
|
28883
|
+
if (columnIndex < 0 || columnIndex >= map.width) return null;
|
|
28884
|
+
const rows = getTableRows(tableNode).map((rowInfo) => {
|
|
28885
|
+
const cells = collectChildren(rowInfo.node);
|
|
28886
|
+
for (const entry of rowInfo.cells) {
|
|
28887
|
+
const rect = safeFindCell(map, entry.relativePos);
|
|
28888
|
+
if (!rect || rect.left > columnIndex || columnIndex >= rect.right) continue;
|
|
28889
|
+
cells[entry.index] = createEmptyCellNode(entry.node);
|
|
28890
|
+
}
|
|
28891
|
+
return rowInfo.node.type.create(rowInfo.node.attrs, cells);
|
|
28747
28892
|
});
|
|
28748
28893
|
return tableNode.type.create(tableNode.attrs, rows);
|
|
28749
28894
|
});
|
|
@@ -29795,14 +29940,620 @@ var EditorToolbar = ({
|
|
|
29795
29940
|
// src/components/UEditor/menus.tsx
|
|
29796
29941
|
var import_react62 = require("react");
|
|
29797
29942
|
var import_react63 = require("@tiptap/react");
|
|
29798
|
-
var
|
|
29943
|
+
var import_tables3 = require("@tiptap/pm/tables");
|
|
29799
29944
|
var import_react_dom8 = require("react-dom");
|
|
29800
29945
|
var import_lucide_react49 = require("lucide-react");
|
|
29946
|
+
|
|
29947
|
+
// src/components/UEditor/table-formula-commands.ts
|
|
29948
|
+
var import_tables2 = require("@tiptap/pm/tables");
|
|
29949
|
+
|
|
29950
|
+
// src/components/UEditor/table-formula.ts
|
|
29951
|
+
var CELL_ADDRESS_RE = /^([A-Z]+)([1-9]\d*)$/i;
|
|
29952
|
+
var CELL_RANGE_RE = /^([A-Z]+[1-9]\d*):([A-Z]+[1-9]\d*)$/i;
|
|
29953
|
+
var SUPPORTED_FUNCTIONS = /* @__PURE__ */ new Set(["SUM", "AVG", "MIN", "MAX", "COUNT"]);
|
|
29954
|
+
function columnNameToIndex(columnName) {
|
|
29955
|
+
const normalized = columnName.trim().toUpperCase();
|
|
29956
|
+
if (!/^[A-Z]+$/.test(normalized)) {
|
|
29957
|
+
return -1;
|
|
29958
|
+
}
|
|
29959
|
+
let index = 0;
|
|
29960
|
+
for (const char of normalized) {
|
|
29961
|
+
index = index * 26 + char.charCodeAt(0) - 64;
|
|
29962
|
+
}
|
|
29963
|
+
return index - 1;
|
|
29964
|
+
}
|
|
29965
|
+
function indexToColumnName(index) {
|
|
29966
|
+
if (!Number.isInteger(index) || index < 0) {
|
|
29967
|
+
return "";
|
|
29968
|
+
}
|
|
29969
|
+
let value = index + 1;
|
|
29970
|
+
let name = "";
|
|
29971
|
+
while (value > 0) {
|
|
29972
|
+
const remainder = (value - 1) % 26;
|
|
29973
|
+
name = String.fromCharCode(65 + remainder) + name;
|
|
29974
|
+
value = Math.floor((value - 1) / 26);
|
|
29975
|
+
}
|
|
29976
|
+
return name;
|
|
29977
|
+
}
|
|
29978
|
+
function parseTableCellAddress(input) {
|
|
29979
|
+
const match = input.trim().match(CELL_ADDRESS_RE);
|
|
29980
|
+
if (!match) {
|
|
29981
|
+
return null;
|
|
29982
|
+
}
|
|
29983
|
+
const column = columnNameToIndex(match[1] ?? "");
|
|
29984
|
+
const row = Number.parseInt(match[2] ?? "", 10) - 1;
|
|
29985
|
+
if (column < 0 || row < 0) {
|
|
29986
|
+
return null;
|
|
29987
|
+
}
|
|
29988
|
+
return {
|
|
29989
|
+
column,
|
|
29990
|
+
row,
|
|
29991
|
+
label: `${indexToColumnName(column)}${row + 1}`
|
|
29992
|
+
};
|
|
29993
|
+
}
|
|
29994
|
+
function parseTableCellRange(input) {
|
|
29995
|
+
const match = input.trim().match(CELL_RANGE_RE);
|
|
29996
|
+
if (!match) {
|
|
29997
|
+
return null;
|
|
29998
|
+
}
|
|
29999
|
+
const from = parseTableCellAddress(match[1] ?? "");
|
|
30000
|
+
const to = parseTableCellAddress(match[2] ?? "");
|
|
30001
|
+
if (!from || !to) {
|
|
30002
|
+
return null;
|
|
30003
|
+
}
|
|
30004
|
+
return { from, to };
|
|
30005
|
+
}
|
|
30006
|
+
function getTableCellRangeLabels(range) {
|
|
30007
|
+
const startColumn = Math.min(range.from.column, range.to.column);
|
|
30008
|
+
const endColumn = Math.max(range.from.column, range.to.column);
|
|
30009
|
+
const startRow = Math.min(range.from.row, range.to.row);
|
|
30010
|
+
const endRow = Math.max(range.from.row, range.to.row);
|
|
30011
|
+
const labels = [];
|
|
30012
|
+
for (let row = startRow; row <= endRow; row += 1) {
|
|
30013
|
+
for (let column = startColumn; column <= endColumn; column += 1) {
|
|
30014
|
+
labels.push(`${indexToColumnName(column)}${row + 1}`);
|
|
30015
|
+
}
|
|
30016
|
+
}
|
|
30017
|
+
return labels;
|
|
30018
|
+
}
|
|
30019
|
+
function normalizeTableFormula(formula) {
|
|
30020
|
+
return formula.trim().replace(/^=/, "").trim();
|
|
30021
|
+
}
|
|
30022
|
+
function formatFormulaError(error) {
|
|
30023
|
+
return `#${error.toUpperCase()}`;
|
|
30024
|
+
}
|
|
30025
|
+
function getTableFormulaReferences(formula) {
|
|
30026
|
+
const normalized = normalizeTableFormula(formula);
|
|
30027
|
+
if (!normalized) return [];
|
|
30028
|
+
const tokens = tokenizeFormula(normalized);
|
|
30029
|
+
if (!tokens) return [];
|
|
30030
|
+
const references = /* @__PURE__ */ new Set();
|
|
30031
|
+
for (const token of tokens) {
|
|
30032
|
+
if (token.type === "cell") {
|
|
30033
|
+
references.add(token.value);
|
|
30034
|
+
} else if (token.type === "range") {
|
|
30035
|
+
const range = parseTableCellRange(token.value);
|
|
30036
|
+
if (!range) continue;
|
|
30037
|
+
for (const label of getTableCellRangeLabels(range)) {
|
|
30038
|
+
references.add(label);
|
|
30039
|
+
}
|
|
30040
|
+
}
|
|
30041
|
+
}
|
|
30042
|
+
return Array.from(references);
|
|
30043
|
+
}
|
|
30044
|
+
function buildTableFormulaDependencyGraph(cells) {
|
|
30045
|
+
const dependencies = /* @__PURE__ */ new Map();
|
|
30046
|
+
const dependents = /* @__PURE__ */ new Map();
|
|
30047
|
+
const formulas = /* @__PURE__ */ new Map();
|
|
30048
|
+
for (const cell of cells) {
|
|
30049
|
+
const label = cell.label.toUpperCase();
|
|
30050
|
+
formulas.set(label, cell.formula);
|
|
30051
|
+
dependencies.set(label, new Set(getTableFormulaReferences(cell.formula)));
|
|
30052
|
+
if (!dependents.has(label)) {
|
|
30053
|
+
dependents.set(label, /* @__PURE__ */ new Set());
|
|
30054
|
+
}
|
|
30055
|
+
}
|
|
30056
|
+
for (const [label, refs] of dependencies) {
|
|
30057
|
+
for (const ref of refs) {
|
|
30058
|
+
if (!dependents.has(ref)) {
|
|
30059
|
+
dependents.set(ref, /* @__PURE__ */ new Set());
|
|
30060
|
+
}
|
|
30061
|
+
dependents.get(ref)?.add(label);
|
|
30062
|
+
}
|
|
30063
|
+
}
|
|
30064
|
+
return { dependencies, dependents, formulas };
|
|
30065
|
+
}
|
|
30066
|
+
function getTableFormulaCircularReferences(graph) {
|
|
30067
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
30068
|
+
const visited = /* @__PURE__ */ new Set();
|
|
30069
|
+
const circular = /* @__PURE__ */ new Set();
|
|
30070
|
+
const stack = [];
|
|
30071
|
+
const visit = (label) => {
|
|
30072
|
+
if (visiting.has(label)) {
|
|
30073
|
+
const start = stack.indexOf(label);
|
|
30074
|
+
for (const cycleLabel of start >= 0 ? stack.slice(start) : [label]) {
|
|
30075
|
+
circular.add(cycleLabel);
|
|
30076
|
+
}
|
|
30077
|
+
return;
|
|
30078
|
+
}
|
|
30079
|
+
if (visited.has(label)) return;
|
|
30080
|
+
visiting.add(label);
|
|
30081
|
+
stack.push(label);
|
|
30082
|
+
for (const ref of graph.dependencies.get(label) ?? []) {
|
|
30083
|
+
if (graph.formulas.has(ref)) {
|
|
30084
|
+
visit(ref);
|
|
30085
|
+
}
|
|
30086
|
+
}
|
|
30087
|
+
stack.pop();
|
|
30088
|
+
visiting.delete(label);
|
|
30089
|
+
visited.add(label);
|
|
30090
|
+
};
|
|
30091
|
+
for (const label of graph.formulas.keys()) {
|
|
30092
|
+
visit(label);
|
|
30093
|
+
}
|
|
30094
|
+
return circular;
|
|
30095
|
+
}
|
|
30096
|
+
function getTableFormulaRecalculationOrder(graph) {
|
|
30097
|
+
const circular = getTableFormulaCircularReferences(graph);
|
|
30098
|
+
const visited = /* @__PURE__ */ new Set();
|
|
30099
|
+
const order = [];
|
|
30100
|
+
const visit = (label) => {
|
|
30101
|
+
if (visited.has(label) || circular.has(label)) return;
|
|
30102
|
+
visited.add(label);
|
|
30103
|
+
for (const ref of graph.dependencies.get(label) ?? []) {
|
|
30104
|
+
if (graph.formulas.has(ref)) {
|
|
30105
|
+
visit(ref);
|
|
30106
|
+
}
|
|
30107
|
+
}
|
|
30108
|
+
order.push(label);
|
|
30109
|
+
};
|
|
30110
|
+
for (const label of graph.formulas.keys()) {
|
|
30111
|
+
visit(label);
|
|
30112
|
+
}
|
|
30113
|
+
return { order, circular };
|
|
30114
|
+
}
|
|
30115
|
+
function evaluateBasicTableFormula(formula, getCellValue) {
|
|
30116
|
+
const normalized = normalizeTableFormula(formula);
|
|
30117
|
+
if (!normalized) {
|
|
30118
|
+
return { value: null, error: "empty" };
|
|
30119
|
+
}
|
|
30120
|
+
const tokens = tokenizeFormula(normalized);
|
|
30121
|
+
if (!tokens) {
|
|
30122
|
+
return { value: null, error: "invalid-formula" };
|
|
30123
|
+
}
|
|
30124
|
+
const parser = new FormulaParser(tokens, getCellValue);
|
|
30125
|
+
const result = parser.parseExpression();
|
|
30126
|
+
if (result.error) {
|
|
30127
|
+
return result;
|
|
30128
|
+
}
|
|
30129
|
+
if (!parser.isComplete()) {
|
|
30130
|
+
return { value: null, error: "invalid-formula" };
|
|
30131
|
+
}
|
|
30132
|
+
return result;
|
|
30133
|
+
}
|
|
30134
|
+
function tokenizeFormula(formula) {
|
|
30135
|
+
const tokens = [];
|
|
30136
|
+
let index = 0;
|
|
30137
|
+
while (index < formula.length) {
|
|
30138
|
+
const char = formula[index];
|
|
30139
|
+
if (!char) break;
|
|
30140
|
+
if (/\s/.test(char)) {
|
|
30141
|
+
index += 1;
|
|
30142
|
+
continue;
|
|
30143
|
+
}
|
|
30144
|
+
if (char === "," || char === "+" || char === "-" || char === "*" || char === "/" || char === "(" || char === ")") {
|
|
30145
|
+
if (char === ",") tokens.push({ type: "comma", value: char });
|
|
30146
|
+
else if (char === "(" || char === ")") tokens.push({ type: "paren", value: char });
|
|
30147
|
+
else tokens.push({ type: "operator", value: char });
|
|
30148
|
+
index += 1;
|
|
30149
|
+
continue;
|
|
30150
|
+
}
|
|
30151
|
+
const numberMatch = formula.slice(index).match(/^\d+(?:\.\d+)?/);
|
|
30152
|
+
if (numberMatch?.[0]) {
|
|
30153
|
+
tokens.push({ type: "number", value: Number.parseFloat(numberMatch[0]) });
|
|
30154
|
+
index += numberMatch[0].length;
|
|
30155
|
+
continue;
|
|
30156
|
+
}
|
|
30157
|
+
const identifierMatch = formula.slice(index).match(/^[A-Z]+[1-9]\d*(?::[A-Z]+[1-9]\d*)?|^[A-Z]+/i);
|
|
30158
|
+
if (identifierMatch?.[0]) {
|
|
30159
|
+
const value = identifierMatch[0].toUpperCase();
|
|
30160
|
+
if (CELL_RANGE_RE.test(value)) tokens.push({ type: "range", value });
|
|
30161
|
+
else if (parseTableCellAddress(value)) tokens.push({ type: "cell", value });
|
|
30162
|
+
else if (SUPPORTED_FUNCTIONS.has(value)) tokens.push({ type: "function", value });
|
|
30163
|
+
else return null;
|
|
30164
|
+
index += identifierMatch[0].length;
|
|
30165
|
+
continue;
|
|
30166
|
+
}
|
|
30167
|
+
return null;
|
|
30168
|
+
}
|
|
30169
|
+
return tokens;
|
|
30170
|
+
}
|
|
30171
|
+
var FormulaParser = class {
|
|
30172
|
+
constructor(tokens, getCellValue) {
|
|
30173
|
+
this.tokens = tokens;
|
|
30174
|
+
this.getCellValue = getCellValue;
|
|
30175
|
+
this.index = 0;
|
|
30176
|
+
}
|
|
30177
|
+
isComplete() {
|
|
30178
|
+
return this.index >= this.tokens.length;
|
|
30179
|
+
}
|
|
30180
|
+
parseExpression() {
|
|
30181
|
+
let left = this.parseTerm();
|
|
30182
|
+
while (!left.error) {
|
|
30183
|
+
const operator = this.peekOperator(["+", "-"]);
|
|
30184
|
+
if (!operator) break;
|
|
30185
|
+
this.index += 1;
|
|
30186
|
+
const right = this.parseTerm();
|
|
30187
|
+
if (right.error) return right;
|
|
30188
|
+
left = {
|
|
30189
|
+
value: operator.value === "+" ? left.value + right.value : left.value - right.value,
|
|
30190
|
+
error: null
|
|
30191
|
+
};
|
|
30192
|
+
}
|
|
30193
|
+
return left;
|
|
30194
|
+
}
|
|
30195
|
+
parseTerm() {
|
|
30196
|
+
let left = this.parseFactor();
|
|
30197
|
+
while (!left.error) {
|
|
30198
|
+
const operator = this.peekOperator(["*", "/"]);
|
|
30199
|
+
if (!operator) break;
|
|
30200
|
+
this.index += 1;
|
|
30201
|
+
const right = this.parseFactor();
|
|
30202
|
+
if (right.error) return right;
|
|
30203
|
+
if (operator.value === "/" && right.value === 0) {
|
|
30204
|
+
return { value: null, error: "division-by-zero" };
|
|
30205
|
+
}
|
|
30206
|
+
left = {
|
|
30207
|
+
value: operator.value === "*" ? left.value * right.value : left.value / right.value,
|
|
30208
|
+
error: null
|
|
30209
|
+
};
|
|
30210
|
+
}
|
|
30211
|
+
return left;
|
|
30212
|
+
}
|
|
30213
|
+
parseFactor() {
|
|
30214
|
+
const token = this.tokens[this.index];
|
|
30215
|
+
if (!token) {
|
|
30216
|
+
return { value: null, error: "invalid-formula" };
|
|
30217
|
+
}
|
|
30218
|
+
if (token.type === "operator" && token.value === "-") {
|
|
30219
|
+
this.index += 1;
|
|
30220
|
+
const value = this.parseFactor();
|
|
30221
|
+
if (value.error) return value;
|
|
30222
|
+
return { value: -value.value, error: null };
|
|
30223
|
+
}
|
|
30224
|
+
if (token.type === "number") {
|
|
30225
|
+
this.index += 1;
|
|
30226
|
+
return { value: token.value, error: null };
|
|
30227
|
+
}
|
|
30228
|
+
if (token.type === "cell") {
|
|
30229
|
+
this.index += 1;
|
|
30230
|
+
return this.readCellNumber(token.value);
|
|
30231
|
+
}
|
|
30232
|
+
if (token.type === "function") {
|
|
30233
|
+
return this.parseFunction(token.value);
|
|
30234
|
+
}
|
|
30235
|
+
if (token.type === "paren" && token.value === "(") {
|
|
30236
|
+
this.index += 1;
|
|
30237
|
+
const value = this.parseExpression();
|
|
30238
|
+
if (value.error) return value;
|
|
30239
|
+
if (!this.consumeParen(")")) {
|
|
30240
|
+
return { value: null, error: "invalid-formula" };
|
|
30241
|
+
}
|
|
30242
|
+
return value;
|
|
30243
|
+
}
|
|
30244
|
+
return { value: null, error: "invalid-formula" };
|
|
30245
|
+
}
|
|
30246
|
+
parseFunction(name) {
|
|
30247
|
+
this.index += 1;
|
|
30248
|
+
if (!this.consumeParen("(")) {
|
|
30249
|
+
return { value: null, error: "invalid-formula" };
|
|
30250
|
+
}
|
|
30251
|
+
const values = [];
|
|
30252
|
+
while (true) {
|
|
30253
|
+
const token = this.tokens[this.index];
|
|
30254
|
+
if (!token) {
|
|
30255
|
+
return { value: null, error: "invalid-formula" };
|
|
30256
|
+
}
|
|
30257
|
+
if (token.type === "range") {
|
|
30258
|
+
this.index += 1;
|
|
30259
|
+
const range = parseTableCellRange(token.value);
|
|
30260
|
+
if (!range) return { value: null, error: "invalid-reference" };
|
|
30261
|
+
for (const label of getTableCellRangeLabels(range)) {
|
|
30262
|
+
const cellValue = this.readCellNumber(label);
|
|
30263
|
+
if (cellValue.error) return cellValue;
|
|
30264
|
+
values.push(cellValue.value);
|
|
30265
|
+
}
|
|
30266
|
+
} else {
|
|
30267
|
+
const value = this.parseExpression();
|
|
30268
|
+
if (value.error) return value;
|
|
30269
|
+
values.push(value.value);
|
|
30270
|
+
}
|
|
30271
|
+
if (this.consumeComma()) {
|
|
30272
|
+
continue;
|
|
30273
|
+
}
|
|
30274
|
+
if (this.consumeParen(")")) {
|
|
30275
|
+
break;
|
|
30276
|
+
}
|
|
30277
|
+
return { value: null, error: "invalid-formula" };
|
|
30278
|
+
}
|
|
30279
|
+
if (values.length === 0) {
|
|
30280
|
+
return { value: null, error: "invalid-formula" };
|
|
30281
|
+
}
|
|
30282
|
+
if (name === "SUM") return { value: values.reduce((sum, value) => sum + value, 0), error: null };
|
|
30283
|
+
if (name === "AVG") return { value: values.reduce((sum, value) => sum + value, 0) / values.length, error: null };
|
|
30284
|
+
if (name === "MIN") return { value: Math.min(...values), error: null };
|
|
30285
|
+
if (name === "MAX") return { value: Math.max(...values), error: null };
|
|
30286
|
+
if (name === "COUNT") return { value: values.length, error: null };
|
|
30287
|
+
return { value: null, error: "invalid-formula" };
|
|
30288
|
+
}
|
|
30289
|
+
readCellNumber(label) {
|
|
30290
|
+
const value = this.getCellValue(label);
|
|
30291
|
+
const parsed = typeof value === "number" ? value : Number.parseFloat(String(value ?? "").trim());
|
|
30292
|
+
if (!Number.isFinite(parsed)) {
|
|
30293
|
+
return { value: null, error: "invalid-reference" };
|
|
30294
|
+
}
|
|
30295
|
+
return { value: parsed, error: null };
|
|
30296
|
+
}
|
|
30297
|
+
peekOperator(operators) {
|
|
30298
|
+
const token = this.tokens[this.index];
|
|
30299
|
+
return token?.type === "operator" && operators.includes(token.value) ? token : null;
|
|
30300
|
+
}
|
|
30301
|
+
consumeComma() {
|
|
30302
|
+
if (this.tokens[this.index]?.type !== "comma") {
|
|
30303
|
+
return false;
|
|
30304
|
+
}
|
|
30305
|
+
this.index += 1;
|
|
30306
|
+
return true;
|
|
30307
|
+
}
|
|
30308
|
+
consumeParen(value) {
|
|
30309
|
+
const token = this.tokens[this.index];
|
|
30310
|
+
if (token?.type !== "paren" || token.value !== value) {
|
|
30311
|
+
return false;
|
|
30312
|
+
}
|
|
30313
|
+
this.index += 1;
|
|
30314
|
+
return true;
|
|
30315
|
+
}
|
|
30316
|
+
};
|
|
30317
|
+
|
|
30318
|
+
// src/components/UEditor/table-formula-commands.ts
|
|
30319
|
+
var UEDITOR_TABLE_FORMULA_RECALCULATE_META = "ueditorTableFormulaRecalculate";
|
|
30320
|
+
function collectChildren2(node) {
|
|
30321
|
+
const children = [];
|
|
30322
|
+
node.forEach((child) => children.push(child));
|
|
30323
|
+
return children;
|
|
30324
|
+
}
|
|
30325
|
+
function getTableRows2(tableNode) {
|
|
30326
|
+
const rows = [];
|
|
30327
|
+
tableNode.forEach((rowNode, rowOffset) => {
|
|
30328
|
+
const cells = [];
|
|
30329
|
+
rowNode.forEach((cellNode, cellOffset, index) => {
|
|
30330
|
+
cells.push({
|
|
30331
|
+
index,
|
|
30332
|
+
node: cellNode,
|
|
30333
|
+
relativePos: rowOffset + 1 + cellOffset
|
|
30334
|
+
});
|
|
30335
|
+
});
|
|
30336
|
+
rows.push({ node: rowNode, cells });
|
|
30337
|
+
});
|
|
30338
|
+
return rows;
|
|
30339
|
+
}
|
|
30340
|
+
function safeFindCell2(map, relativePos) {
|
|
30341
|
+
try {
|
|
30342
|
+
return map.findCell(relativePos);
|
|
30343
|
+
} catch {
|
|
30344
|
+
return null;
|
|
30345
|
+
}
|
|
30346
|
+
}
|
|
30347
|
+
function getCellText(cellNode) {
|
|
30348
|
+
return cellNode.textBetween(0, cellNode.content.size, "\n").trim();
|
|
30349
|
+
}
|
|
30350
|
+
function createCellDisplayContent(cellNode, displayValue) {
|
|
30351
|
+
const paragraphType = cellNode.type.schema.nodes.paragraph;
|
|
30352
|
+
if (!paragraphType || !displayValue) {
|
|
30353
|
+
return paragraphType ? [paragraphType.create()] : cellNode.content;
|
|
30354
|
+
}
|
|
30355
|
+
return [paragraphType.create(null, cellNode.type.schema.text(displayValue))];
|
|
30356
|
+
}
|
|
30357
|
+
function buildTableValueGetter(tableNode) {
|
|
30358
|
+
const map = import_tables2.TableMap.get(tableNode);
|
|
30359
|
+
const values = /* @__PURE__ */ new Map();
|
|
30360
|
+
for (const rowInfo of getTableRows2(tableNode)) {
|
|
30361
|
+
for (const entry of rowInfo.cells) {
|
|
30362
|
+
const rect = safeFindCell2(map, entry.relativePos);
|
|
30363
|
+
if (!rect) continue;
|
|
30364
|
+
const label = `${indexToColumnName(rect.left)}${rect.top + 1}`;
|
|
30365
|
+
const computedValue = entry.node.attrs.computedValue;
|
|
30366
|
+
values.set(label, typeof computedValue === "string" && computedValue.trim() ? computedValue : getCellText(entry.node));
|
|
30367
|
+
}
|
|
30368
|
+
}
|
|
30369
|
+
return (label) => values.get(label.toUpperCase());
|
|
30370
|
+
}
|
|
30371
|
+
function buildTableValueMap(tableNode) {
|
|
30372
|
+
const map = import_tables2.TableMap.get(tableNode);
|
|
30373
|
+
const values = /* @__PURE__ */ new Map();
|
|
30374
|
+
for (const rowInfo of getTableRows2(tableNode)) {
|
|
30375
|
+
for (const entry of rowInfo.cells) {
|
|
30376
|
+
const rect = safeFindCell2(map, entry.relativePos);
|
|
30377
|
+
if (!rect) continue;
|
|
30378
|
+
const label = `${indexToColumnName(rect.left)}${rect.top + 1}`;
|
|
30379
|
+
const computedValue = entry.node.attrs.computedValue;
|
|
30380
|
+
values.set(label, typeof computedValue === "string" && computedValue.trim() ? computedValue : getCellText(entry.node));
|
|
30381
|
+
}
|
|
30382
|
+
}
|
|
30383
|
+
return values;
|
|
30384
|
+
}
|
|
30385
|
+
function getFormulaComputedValue(formula, tableNode) {
|
|
30386
|
+
const result = evaluateBasicTableFormula(formula, buildTableValueGetter(tableNode));
|
|
30387
|
+
return result.error ? `#${result.error.toUpperCase()}` : String(result.value);
|
|
30388
|
+
}
|
|
30389
|
+
function normalizeFormulaInput(formula) {
|
|
30390
|
+
const trimmed = formula.trim();
|
|
30391
|
+
if (!trimmed) return "";
|
|
30392
|
+
return trimmed.startsWith("=") ? trimmed : `=${trimmed}`;
|
|
30393
|
+
}
|
|
30394
|
+
function setSelectedTableCellFormula(editor, formula) {
|
|
30395
|
+
const normalized = normalizeFormulaInput(formula);
|
|
30396
|
+
const { state, view } = editor;
|
|
30397
|
+
if (!normalized) {
|
|
30398
|
+
const clearedFormula = (0, import_tables2.setCellAttr)("formula", null)(state, view.dispatch.bind(view));
|
|
30399
|
+
const clearedValue = (0, import_tables2.setCellAttr)("computedValue", null)(editor.state, view.dispatch.bind(view));
|
|
30400
|
+
if (clearedFormula || clearedValue) {
|
|
30401
|
+
view.focus();
|
|
30402
|
+
dispatchTableLayoutChange(editor);
|
|
30403
|
+
return true;
|
|
30404
|
+
}
|
|
30405
|
+
return false;
|
|
30406
|
+
}
|
|
30407
|
+
const rect = (0, import_tables2.selectedRect)(state);
|
|
30408
|
+
const computedValue = getFormulaComputedValue(normalized, rect.table);
|
|
30409
|
+
const appliedFormula = (0, import_tables2.setCellAttr)("formula", normalized)(state, view.dispatch.bind(view));
|
|
30410
|
+
const appliedValue = (0, import_tables2.setCellAttr)("computedValue", computedValue)(editor.state, view.dispatch.bind(view));
|
|
30411
|
+
if (appliedFormula || appliedValue) {
|
|
30412
|
+
view.focus();
|
|
30413
|
+
dispatchTableLayoutChange(editor);
|
|
30414
|
+
return true;
|
|
30415
|
+
}
|
|
30416
|
+
return false;
|
|
30417
|
+
}
|
|
30418
|
+
function clearSelectedTableCellFormula(editor) {
|
|
30419
|
+
return setSelectedTableCellFormula(editor, "");
|
|
30420
|
+
}
|
|
30421
|
+
function promoteFormulaTextInTableNode(tableNode) {
|
|
30422
|
+
let changed = false;
|
|
30423
|
+
const rows = getTableRows2(tableNode).map((rowInfo) => {
|
|
30424
|
+
const cells = collectChildren2(rowInfo.node);
|
|
30425
|
+
for (const entry of rowInfo.cells) {
|
|
30426
|
+
const text = getCellText(entry.node);
|
|
30427
|
+
const formula = text.startsWith("=") ? normalizeFormulaInput(text) : "";
|
|
30428
|
+
if (!formula || entry.node.attrs.formula === formula) continue;
|
|
30429
|
+
cells[entry.index] = entry.node.type.create(
|
|
30430
|
+
{
|
|
30431
|
+
...entry.node.attrs,
|
|
30432
|
+
formula,
|
|
30433
|
+
computedValue: null
|
|
30434
|
+
},
|
|
30435
|
+
entry.node.content,
|
|
30436
|
+
entry.node.marks
|
|
30437
|
+
);
|
|
30438
|
+
changed = true;
|
|
30439
|
+
}
|
|
30440
|
+
return rowInfo.node.type.create(rowInfo.node.attrs, cells);
|
|
30441
|
+
});
|
|
30442
|
+
return {
|
|
30443
|
+
tableNode: changed ? tableNode.type.create(tableNode.attrs, rows) : tableNode,
|
|
30444
|
+
changed
|
|
30445
|
+
};
|
|
30446
|
+
}
|
|
30447
|
+
function recalculateTableNode(tableNode) {
|
|
30448
|
+
const promoted = promoteFormulaTextInTableNode(tableNode);
|
|
30449
|
+
tableNode = promoted.tableNode;
|
|
30450
|
+
const map = import_tables2.TableMap.get(tableNode);
|
|
30451
|
+
const values = buildTableValueMap(tableNode);
|
|
30452
|
+
const formulaEntries = /* @__PURE__ */ new Map();
|
|
30453
|
+
let changed = false;
|
|
30454
|
+
const rowInfos = getTableRows2(tableNode);
|
|
30455
|
+
for (const [rowIndex, rowInfo] of rowInfos.entries()) {
|
|
30456
|
+
for (const entry of rowInfo.cells) {
|
|
30457
|
+
const formula = typeof entry.node.attrs.formula === "string" ? entry.node.attrs.formula.trim() : "";
|
|
30458
|
+
if (!formula) continue;
|
|
30459
|
+
const rectForCell = safeFindCell2(map, entry.relativePos);
|
|
30460
|
+
if (!rectForCell) continue;
|
|
30461
|
+
const label = `${indexToColumnName(rectForCell.left)}${rectForCell.top + 1}`;
|
|
30462
|
+
formulaEntries.set(label, {
|
|
30463
|
+
rowIndex,
|
|
30464
|
+
cellIndex: entry.index,
|
|
30465
|
+
node: entry.node,
|
|
30466
|
+
formula
|
|
30467
|
+
});
|
|
30468
|
+
}
|
|
30469
|
+
}
|
|
30470
|
+
const graph = buildTableFormulaDependencyGraph(
|
|
30471
|
+
Array.from(formulaEntries, ([label, entry]) => ({
|
|
30472
|
+
label,
|
|
30473
|
+
formula: entry.formula
|
|
30474
|
+
}))
|
|
30475
|
+
);
|
|
30476
|
+
const { order, circular } = getTableFormulaRecalculationOrder(graph);
|
|
30477
|
+
const computedValues = /* @__PURE__ */ new Map();
|
|
30478
|
+
const getCellValue = (label) => values.get(label.toUpperCase());
|
|
30479
|
+
for (const label of circular) {
|
|
30480
|
+
computedValues.set(label, formatFormulaError("circular-reference"));
|
|
30481
|
+
values.set(label, formatFormulaError("circular-reference"));
|
|
30482
|
+
}
|
|
30483
|
+
for (const label of order) {
|
|
30484
|
+
const entry = formulaEntries.get(label);
|
|
30485
|
+
if (!entry) continue;
|
|
30486
|
+
const result = evaluateBasicTableFormula(entry.formula, getCellValue);
|
|
30487
|
+
const computedValue = result.error ? formatFormulaError(result.error) : String(result.value);
|
|
30488
|
+
computedValues.set(label, computedValue);
|
|
30489
|
+
values.set(label, computedValue);
|
|
30490
|
+
}
|
|
30491
|
+
const rows = rowInfos.map((rowInfo) => {
|
|
30492
|
+
const cells = collectChildren2(rowInfo.node);
|
|
30493
|
+
for (const entry of rowInfo.cells) {
|
|
30494
|
+
const rectForCell = safeFindCell2(map, entry.relativePos);
|
|
30495
|
+
if (!rectForCell) continue;
|
|
30496
|
+
const label = `${indexToColumnName(rectForCell.left)}${rectForCell.top + 1}`;
|
|
30497
|
+
const computedValue = computedValues.get(label);
|
|
30498
|
+
if (computedValue == null) continue;
|
|
30499
|
+
const contentMatchesComputedValue = getCellText(entry.node) === computedValue;
|
|
30500
|
+
if (entry.node.attrs.computedValue === computedValue && contentMatchesComputedValue) continue;
|
|
30501
|
+
cells[entry.index] = entry.node.type.create(
|
|
30502
|
+
{
|
|
30503
|
+
...entry.node.attrs,
|
|
30504
|
+
computedValue
|
|
30505
|
+
},
|
|
30506
|
+
createCellDisplayContent(entry.node, computedValue),
|
|
30507
|
+
entry.node.marks
|
|
30508
|
+
);
|
|
30509
|
+
changed = true;
|
|
30510
|
+
}
|
|
30511
|
+
return rowInfo.node.type.create(rowInfo.node.attrs, cells);
|
|
30512
|
+
});
|
|
30513
|
+
if (!changed) return promoted.changed ? tableNode : null;
|
|
30514
|
+
return tableNode.type.create(tableNode.attrs, rows);
|
|
30515
|
+
}
|
|
30516
|
+
function recalculateSelectedTable(editor) {
|
|
30517
|
+
const rect = (0, import_tables2.selectedRect)(editor.state);
|
|
30518
|
+
const tableNode = rect.table;
|
|
30519
|
+
const nextTable = recalculateTableNode(tableNode);
|
|
30520
|
+
if (!nextTable) return false;
|
|
30521
|
+
editor.view.dispatch(
|
|
30522
|
+
editor.state.tr.replaceWith(rect.tableStart - 1, rect.tableStart - 1 + tableNode.nodeSize, nextTable).setMeta(UEDITOR_TABLE_FORMULA_RECALCULATE_META, true)
|
|
30523
|
+
);
|
|
30524
|
+
dispatchTableLayoutChange(editor);
|
|
30525
|
+
return true;
|
|
30526
|
+
}
|
|
30527
|
+
function recalculateAllTableFormulas(editor) {
|
|
30528
|
+
const replacements = [];
|
|
30529
|
+
editor.state.doc.descendants((node, pos) => {
|
|
30530
|
+
if (node.type.name !== "table") return true;
|
|
30531
|
+
const nextTable = recalculateTableNode(node);
|
|
30532
|
+
if (nextTable) {
|
|
30533
|
+
replacements.push({
|
|
30534
|
+
from: pos,
|
|
30535
|
+
to: pos + node.nodeSize,
|
|
30536
|
+
node: nextTable
|
|
30537
|
+
});
|
|
30538
|
+
}
|
|
30539
|
+
return false;
|
|
30540
|
+
});
|
|
30541
|
+
if (replacements.length === 0) return false;
|
|
30542
|
+
let tr = editor.state.tr;
|
|
30543
|
+
for (const replacement of replacements.reverse()) {
|
|
30544
|
+
tr = tr.replaceWith(replacement.from, replacement.to, replacement.node);
|
|
30545
|
+
}
|
|
30546
|
+
editor.view.dispatch(tr.setMeta(UEDITOR_TABLE_FORMULA_RECALCULATE_META, true));
|
|
30547
|
+
dispatchTableLayoutChange(editor);
|
|
30548
|
+
return true;
|
|
30549
|
+
}
|
|
30550
|
+
|
|
30551
|
+
// src/components/UEditor/menus.tsx
|
|
29801
30552
|
var import_jsx_runtime86 = require("react/jsx-runtime");
|
|
29802
30553
|
function applyTableCellBackground(editor, color) {
|
|
29803
30554
|
const value = color || null;
|
|
29804
30555
|
const { state, view } = editor;
|
|
29805
|
-
const applied = (0,
|
|
30556
|
+
const applied = (0, import_tables3.setCellAttr)("backgroundColor", value)(state, view.dispatch.bind(view));
|
|
29806
30557
|
if (applied) {
|
|
29807
30558
|
view.focus();
|
|
29808
30559
|
return;
|
|
@@ -29828,6 +30579,8 @@ var BubbleMenuContent = ({
|
|
|
29828
30579
|
setShowLinkInput(initialShowLinkInput);
|
|
29829
30580
|
}, [initialShowLinkInput]);
|
|
29830
30581
|
const [showTypographyPanel, setShowTypographyPanel] = (0, import_react62.useState)(false);
|
|
30582
|
+
const [showFormulaPanel, setShowFormulaPanel] = (0, import_react62.useState)(false);
|
|
30583
|
+
const [formulaDraft, setFormulaDraft] = (0, import_react62.useState)("");
|
|
29831
30584
|
const [showFontSizeOptions, setShowFontSizeOptions] = (0, import_react62.useState)(false);
|
|
29832
30585
|
const [fontSizeDraft, setFontSizeDraft] = (0, import_react62.useState)("");
|
|
29833
30586
|
const isImageSelected = editor.isActive("image");
|
|
@@ -29838,7 +30591,8 @@ var BubbleMenuContent = ({
|
|
|
29838
30591
|
const currentTextColor = normalizeStyleValue(textStyleAttrs.color) || "inherit";
|
|
29839
30592
|
const currentHighlightColor = normalizeStyleValue(editor.getAttributes("highlight").color) || "";
|
|
29840
30593
|
const currentCellBgColor = normalizeStyleValue(editor.getAttributes("tableCell").backgroundColor || editor.getAttributes("tableHeader").backgroundColor) || "";
|
|
29841
|
-
const
|
|
30594
|
+
const currentCellFormula = normalizeStyleValue(editor.getAttributes("tableCell").formula || editor.getAttributes("tableHeader").formula) || "";
|
|
30595
|
+
const isInTable2 = (0, import_tables3.isInTable)(editor.state);
|
|
29842
30596
|
const canMergeCells = isInTable2 && editor.can().mergeCells();
|
|
29843
30597
|
const canSplitCell = isInTable2 && editor.can().splitCell();
|
|
29844
30598
|
const currentFontSize = normalizeStyleValue(textStyleAttrs.fontSize);
|
|
@@ -29854,6 +30608,9 @@ var BubbleMenuContent = ({
|
|
|
29854
30608
|
(0, import_react62.useEffect)(() => {
|
|
29855
30609
|
setFontSizeDraft(currentFontSize.replace(/px$/i, ""));
|
|
29856
30610
|
}, [currentFontSize]);
|
|
30611
|
+
(0, import_react62.useEffect)(() => {
|
|
30612
|
+
setFormulaDraft(currentCellFormula);
|
|
30613
|
+
}, [currentCellFormula]);
|
|
29857
30614
|
const applyFontSizeDraft = () => {
|
|
29858
30615
|
const normalized = fontSizeDraft.trim();
|
|
29859
30616
|
if (!normalized) {
|
|
@@ -30056,6 +30813,82 @@ var BubbleMenuContent = ({
|
|
|
30056
30813
|
)
|
|
30057
30814
|
] });
|
|
30058
30815
|
}
|
|
30816
|
+
if (showFormulaPanel && isInTable2) {
|
|
30817
|
+
return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "w-72 p-2", children: [
|
|
30818
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "mb-2 flex items-center justify-between gap-2", children: [
|
|
30819
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "px-1 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: t("tableMenu.formula") || "Formula" }),
|
|
30820
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
|
|
30821
|
+
"button",
|
|
30822
|
+
{
|
|
30823
|
+
type: "button",
|
|
30824
|
+
onClick: () => {
|
|
30825
|
+
setShowFormulaPanel(false);
|
|
30826
|
+
onKeepOpenChange?.(false);
|
|
30827
|
+
},
|
|
30828
|
+
className: "rounded-md px-2 py-1 text-xs text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
30829
|
+
children: t("colors.done")
|
|
30830
|
+
}
|
|
30831
|
+
)
|
|
30832
|
+
] }),
|
|
30833
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "flex h-9 items-center overflow-hidden rounded-md border border-border/60 bg-muted/40", children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
|
|
30834
|
+
"input",
|
|
30835
|
+
{
|
|
30836
|
+
value: formulaDraft,
|
|
30837
|
+
onChange: (event) => setFormulaDraft(event.target.value),
|
|
30838
|
+
onMouseDown: (event) => event.stopPropagation(),
|
|
30839
|
+
onClick: (event) => event.stopPropagation(),
|
|
30840
|
+
onKeyDown: (event) => {
|
|
30841
|
+
event.stopPropagation();
|
|
30842
|
+
if (event.key === "Enter") {
|
|
30843
|
+
event.preventDefault();
|
|
30844
|
+
setSelectedTableCellFormula(editor, formulaDraft);
|
|
30845
|
+
setShowFormulaPanel(false);
|
|
30846
|
+
onKeepOpenChange?.(false);
|
|
30847
|
+
}
|
|
30848
|
+
},
|
|
30849
|
+
"aria-label": t("tableMenu.formula") || "Formula",
|
|
30850
|
+
placeholder: "=SUM(A1:A3)",
|
|
30851
|
+
className: "h-full min-w-0 flex-1 bg-transparent px-2 text-sm font-medium text-foreground outline-none"
|
|
30852
|
+
}
|
|
30853
|
+
) }),
|
|
30854
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "mt-2 grid grid-cols-3 gap-1", children: [
|
|
30855
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
|
|
30856
|
+
"button",
|
|
30857
|
+
{
|
|
30858
|
+
type: "button",
|
|
30859
|
+
onClick: () => {
|
|
30860
|
+
setSelectedTableCellFormula(editor, formulaDraft);
|
|
30861
|
+
setShowFormulaPanel(false);
|
|
30862
|
+
onKeepOpenChange?.(false);
|
|
30863
|
+
},
|
|
30864
|
+
className: "h-8 rounded-md bg-primary/10 text-xs font-semibold text-primary transition-colors hover:bg-primary/15",
|
|
30865
|
+
children: t("tableMenu.apply") || "Apply"
|
|
30866
|
+
}
|
|
30867
|
+
),
|
|
30868
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
|
|
30869
|
+
"button",
|
|
30870
|
+
{
|
|
30871
|
+
type: "button",
|
|
30872
|
+
onClick: () => {
|
|
30873
|
+
clearSelectedTableCellFormula(editor);
|
|
30874
|
+
setFormulaDraft("");
|
|
30875
|
+
},
|
|
30876
|
+
className: "h-8 rounded-md bg-muted/40 text-xs font-semibold text-foreground transition-colors hover:bg-muted",
|
|
30877
|
+
children: t("tableMenu.clear") || "Clear"
|
|
30878
|
+
}
|
|
30879
|
+
),
|
|
30880
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
|
|
30881
|
+
"button",
|
|
30882
|
+
{
|
|
30883
|
+
type: "button",
|
|
30884
|
+
onClick: () => recalculateSelectedTable(editor),
|
|
30885
|
+
className: "h-8 rounded-md bg-muted/40 text-xs font-semibold text-foreground transition-colors hover:bg-muted",
|
|
30886
|
+
children: t("tableMenu.recalculate") || "Recalc"
|
|
30887
|
+
}
|
|
30888
|
+
)
|
|
30889
|
+
] })
|
|
30890
|
+
] });
|
|
30891
|
+
}
|
|
30059
30892
|
if (showTypographyPanel) {
|
|
30060
30893
|
return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "w-72 p-2", children: [
|
|
30061
30894
|
/* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "mb-2 flex items-center justify-between gap-2", children: [
|
|
@@ -30269,6 +31102,21 @@ var BubbleMenuContent = ({
|
|
|
30269
31102
|
)
|
|
30270
31103
|
}
|
|
30271
31104
|
),
|
|
31105
|
+
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
|
|
31106
|
+
ToolbarButton,
|
|
31107
|
+
{
|
|
31108
|
+
onMouseDown: () => {
|
|
31109
|
+
onKeepOpenChange?.(true);
|
|
31110
|
+
},
|
|
31111
|
+
onClick: () => {
|
|
31112
|
+
setFormulaDraft(currentCellFormula);
|
|
31113
|
+
setShowFormulaPanel(true);
|
|
31114
|
+
},
|
|
31115
|
+
active: Boolean(currentCellFormula),
|
|
31116
|
+
title: t("tableMenu.formula") || "Formula",
|
|
31117
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(import_lucide_react49.Sigma, { className: "w-4 h-4" })
|
|
31118
|
+
}
|
|
31119
|
+
),
|
|
30272
31120
|
/* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
|
|
30273
31121
|
ToolbarButton,
|
|
30274
31122
|
{
|
|
@@ -34110,7 +34958,7 @@ if (typeof WeakMap != "undefined") {
|
|
|
34110
34958
|
return cache[cachePos++] = value;
|
|
34111
34959
|
};
|
|
34112
34960
|
}
|
|
34113
|
-
var
|
|
34961
|
+
var TableMap3 = class {
|
|
34114
34962
|
constructor(width, height, map, problems) {
|
|
34115
34963
|
this.width = width;
|
|
34116
34964
|
this.height = height;
|
|
@@ -34247,7 +35095,7 @@ function computeMap(table) {
|
|
|
34247
35095
|
pos++;
|
|
34248
35096
|
}
|
|
34249
35097
|
if (width === 0 || height === 0) (problems || (problems = [])).push({ type: "zero_sized" });
|
|
34250
|
-
const tableMap = new
|
|
35098
|
+
const tableMap = new TableMap3(width, height, map, problems);
|
|
34251
35099
|
let badWidths = false;
|
|
34252
35100
|
for (let i = 0; !badWidths && i < colWidths.length; i += 2) if (colWidths[i] != null && colWidths[i + 1] < height) badWidths = true;
|
|
34253
35101
|
if (badWidths) findBadColWidths(tableMap, colWidths, table);
|
|
@@ -34351,7 +35199,7 @@ function inSameTable($cellA, $cellB) {
|
|
|
34351
35199
|
}
|
|
34352
35200
|
function nextCell($pos, axis, dir) {
|
|
34353
35201
|
const table = $pos.node(-1);
|
|
34354
|
-
const map =
|
|
35202
|
+
const map = TableMap3.get(table);
|
|
34355
35203
|
const tableStart = $pos.start(-1);
|
|
34356
35204
|
const moved = map.nextCell($pos.pos - tableStart, axis, dir);
|
|
34357
35205
|
return moved == null ? null : $pos.node(0).resolve(tableStart + moved);
|
|
@@ -34371,7 +35219,7 @@ function removeColSpan(attrs, pos, n = 1) {
|
|
|
34371
35219
|
var CellSelection = class CellSelection2 extends Selection {
|
|
34372
35220
|
constructor($anchorCell, $headCell = $anchorCell) {
|
|
34373
35221
|
const table = $anchorCell.node(-1);
|
|
34374
|
-
const map =
|
|
35222
|
+
const map = TableMap3.get(table);
|
|
34375
35223
|
const tableStart = $anchorCell.start(-1);
|
|
34376
35224
|
const rect = map.rectBetween($anchorCell.pos - tableStart, $headCell.pos - tableStart);
|
|
34377
35225
|
const doc = $anchorCell.node(0);
|
|
@@ -34400,7 +35248,7 @@ var CellSelection = class CellSelection2 extends Selection {
|
|
|
34400
35248
|
}
|
|
34401
35249
|
content() {
|
|
34402
35250
|
const table = this.$anchorCell.node(-1);
|
|
34403
|
-
const map =
|
|
35251
|
+
const map = TableMap3.get(table);
|
|
34404
35252
|
const tableStart = this.$anchorCell.start(-1);
|
|
34405
35253
|
const rect = map.rectBetween(this.$anchorCell.pos - tableStart, this.$headCell.pos - tableStart);
|
|
34406
35254
|
const seen = {};
|
|
@@ -34454,7 +35302,7 @@ var CellSelection = class CellSelection2 extends Selection {
|
|
|
34454
35302
|
}
|
|
34455
35303
|
forEachCell(f) {
|
|
34456
35304
|
const table = this.$anchorCell.node(-1);
|
|
34457
|
-
const map =
|
|
35305
|
+
const map = TableMap3.get(table);
|
|
34458
35306
|
const tableStart = this.$anchorCell.start(-1);
|
|
34459
35307
|
const cells = map.cellsInRect(map.rectBetween(this.$anchorCell.pos - tableStart, this.$headCell.pos - tableStart));
|
|
34460
35308
|
for (let i = 0; i < cells.length; i++) f(table.nodeAt(cells[i]), tableStart + cells[i]);
|
|
@@ -34469,7 +35317,7 @@ var CellSelection = class CellSelection2 extends Selection {
|
|
|
34469
35317
|
}
|
|
34470
35318
|
static colSelection($anchorCell, $headCell = $anchorCell) {
|
|
34471
35319
|
const table = $anchorCell.node(-1);
|
|
34472
|
-
const map =
|
|
35320
|
+
const map = TableMap3.get(table);
|
|
34473
35321
|
const tableStart = $anchorCell.start(-1);
|
|
34474
35322
|
const anchorRect = map.findCell($anchorCell.pos - tableStart);
|
|
34475
35323
|
const headRect = map.findCell($headCell.pos - tableStart);
|
|
@@ -34485,7 +35333,7 @@ var CellSelection = class CellSelection2 extends Selection {
|
|
|
34485
35333
|
}
|
|
34486
35334
|
isRowSelection() {
|
|
34487
35335
|
const table = this.$anchorCell.node(-1);
|
|
34488
|
-
const map =
|
|
35336
|
+
const map = TableMap3.get(table);
|
|
34489
35337
|
const tableStart = this.$anchorCell.start(-1);
|
|
34490
35338
|
const anchorLeft = map.colCount(this.$anchorCell.pos - tableStart);
|
|
34491
35339
|
const headLeft = map.colCount(this.$headCell.pos - tableStart);
|
|
@@ -34499,7 +35347,7 @@ var CellSelection = class CellSelection2 extends Selection {
|
|
|
34499
35347
|
}
|
|
34500
35348
|
static rowSelection($anchorCell, $headCell = $anchorCell) {
|
|
34501
35349
|
const table = $anchorCell.node(-1);
|
|
34502
|
-
const map =
|
|
35350
|
+
const map = TableMap3.get(table);
|
|
34503
35351
|
const tableStart = $anchorCell.start(-1);
|
|
34504
35352
|
const anchorRect = map.findCell($anchorCell.pos - tableStart);
|
|
34505
35353
|
const headRect = map.findCell($headCell.pos - tableStart);
|
|
@@ -34548,7 +35396,7 @@ var CellBookmark = class CellBookmark2 {
|
|
|
34548
35396
|
};
|
|
34549
35397
|
var fixTablesKey = new PluginKey4("fix-tables");
|
|
34550
35398
|
function convertTableNodeToArrayOfRows(tableNode) {
|
|
34551
|
-
const map =
|
|
35399
|
+
const map = TableMap3.get(tableNode);
|
|
34552
35400
|
const rows = [];
|
|
34553
35401
|
const rowCount = map.height;
|
|
34554
35402
|
const colCount$1 = map.width;
|
|
@@ -34579,7 +35427,7 @@ function convertTableNodeToArrayOfRows(tableNode) {
|
|
|
34579
35427
|
}
|
|
34580
35428
|
function convertArrayOfRowsToTableNode(tableNode, arrayOfNodes) {
|
|
34581
35429
|
const newRows = [];
|
|
34582
|
-
const map =
|
|
35430
|
+
const map = TableMap3.get(tableNode);
|
|
34583
35431
|
const rowCount = map.height;
|
|
34584
35432
|
const colCount$1 = map.width;
|
|
34585
35433
|
for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
|
|
@@ -34628,7 +35476,7 @@ function findParentNode(predicate, $pos) {
|
|
|
34628
35476
|
function getCellsInColumn(columnIndex, selection) {
|
|
34629
35477
|
const table = findTable(selection.$from);
|
|
34630
35478
|
if (!table) return;
|
|
34631
|
-
const map =
|
|
35479
|
+
const map = TableMap3.get(table.node);
|
|
34632
35480
|
if (columnIndex < 0 || columnIndex > map.width - 1) return;
|
|
34633
35481
|
return map.cellsInRect({
|
|
34634
35482
|
left: columnIndex,
|
|
@@ -34649,7 +35497,7 @@ function getCellsInColumn(columnIndex, selection) {
|
|
|
34649
35497
|
function getCellsInRow(rowIndex, selection) {
|
|
34650
35498
|
const table = findTable(selection.$from);
|
|
34651
35499
|
if (!table) return;
|
|
34652
|
-
const map =
|
|
35500
|
+
const map = TableMap3.get(table.node);
|
|
34653
35501
|
if (rowIndex < 0 || rowIndex > map.height - 1) return;
|
|
34654
35502
|
return map.cellsInRect({
|
|
34655
35503
|
left: 0,
|
|
@@ -34778,7 +35626,7 @@ function moveColumn(moveColParams) {
|
|
|
34778
35626
|
const newTable = moveTableColumn$1(table.node, indexesOriginColumn, indexesTargetColumn, 0);
|
|
34779
35627
|
tr.replaceWith(table.pos, table.pos + table.node.nodeSize, newTable);
|
|
34780
35628
|
if (!select) return true;
|
|
34781
|
-
const map =
|
|
35629
|
+
const map = TableMap3.get(newTable);
|
|
34782
35630
|
const start = table.start;
|
|
34783
35631
|
const index = targetIndex;
|
|
34784
35632
|
const lastCell = map.positionAt(map.height - 1, index, newTable);
|
|
@@ -34806,7 +35654,7 @@ function moveRow(moveRowParams) {
|
|
|
34806
35654
|
const newTable = moveTableRow$1(table.node, indexesOriginRow, indexesTargetRow, 0);
|
|
34807
35655
|
tr.replaceWith(table.pos, table.pos + table.node.nodeSize, newTable);
|
|
34808
35656
|
if (!select) return true;
|
|
34809
|
-
const map =
|
|
35657
|
+
const map = TableMap3.get(newTable);
|
|
34810
35658
|
const start = table.start;
|
|
34811
35659
|
const index = targetIndex;
|
|
34812
35660
|
const lastCell = map.positionAt(index, map.width - 1, newTable);
|
|
@@ -34821,12 +35669,12 @@ function moveTableRow$1(table, indexesOrigin, indexesTarget, direction) {
|
|
|
34821
35669
|
rows = moveRowInArrayOfRows(rows, indexesOrigin, indexesTarget, direction);
|
|
34822
35670
|
return convertArrayOfRowsToTableNode(table, rows);
|
|
34823
35671
|
}
|
|
34824
|
-
function
|
|
35672
|
+
function selectedRect3(state) {
|
|
34825
35673
|
const sel = state.selection;
|
|
34826
35674
|
const $pos = selectionCell(state);
|
|
34827
35675
|
const table = $pos.node(-1);
|
|
34828
35676
|
const tableStart = $pos.start(-1);
|
|
34829
|
-
const map =
|
|
35677
|
+
const map = TableMap3.get(table);
|
|
34830
35678
|
return {
|
|
34831
35679
|
...sel instanceof CellSelection ? map.rectBetween(sel.$anchorCell.pos - tableStart, sel.$headCell.pos - tableStart) : map.findCell($pos.pos - tableStart),
|
|
34832
35680
|
tableStart,
|
|
@@ -34839,7 +35687,7 @@ function deprecated_toggleHeader(type) {
|
|
|
34839
35687
|
if (!isInTable(state)) return false;
|
|
34840
35688
|
if (dispatch) {
|
|
34841
35689
|
const types = tableNodeTypes(state.schema);
|
|
34842
|
-
const rect =
|
|
35690
|
+
const rect = selectedRect3(state), tr = state.tr;
|
|
34843
35691
|
const cells = rect.map.cellsInRect(type == "column" ? {
|
|
34844
35692
|
left: rect.left,
|
|
34845
35693
|
top: 0,
|
|
@@ -34879,7 +35727,7 @@ function toggleHeader(type, options) {
|
|
|
34879
35727
|
if (!isInTable(state)) return false;
|
|
34880
35728
|
if (dispatch) {
|
|
34881
35729
|
const types = tableNodeTypes(state.schema);
|
|
34882
|
-
const rect =
|
|
35730
|
+
const rect = selectedRect3(state), tr = state.tr;
|
|
34883
35731
|
const isHeaderRowEnabled = isHeaderEnabledByType("row", rect, types);
|
|
34884
35732
|
const isHeaderColumnEnabled = isHeaderEnabledByType("column", rect, types);
|
|
34885
35733
|
const selectionStartsAt = (type === "column" ? isHeaderRowEnabled : type === "row" ? isHeaderColumnEnabled : false) ? 1 : 0;
|
|
@@ -35029,6 +35877,262 @@ var columnResizingPluginKey = new PluginKey4("tableColumnResizing");
|
|
|
35029
35877
|
// src/components/UEditor/table-controls.tsx
|
|
35030
35878
|
var import_lucide_react52 = require("lucide-react");
|
|
35031
35879
|
|
|
35880
|
+
// src/components/UEditor/table-layout-model.ts
|
|
35881
|
+
var FALLBACK_TABLE_ROW_HEIGHT = 44;
|
|
35882
|
+
var FALLBACK_TABLE_COLUMN_WIDTH = 160;
|
|
35883
|
+
function getVisibleTableBounds(layout) {
|
|
35884
|
+
const left = Math.max(layout.tableLeft, layout.wrapperLeft);
|
|
35885
|
+
const top = Math.max(layout.tableTop, layout.wrapperTop);
|
|
35886
|
+
const right = Math.min(layout.tableLeft + layout.tableWidth, layout.wrapperLeft + layout.viewportWidth);
|
|
35887
|
+
const bottom = Math.min(layout.tableTop + layout.tableHeight, layout.wrapperTop + layout.viewportHeight);
|
|
35888
|
+
return {
|
|
35889
|
+
left,
|
|
35890
|
+
top,
|
|
35891
|
+
right,
|
|
35892
|
+
bottom,
|
|
35893
|
+
width: Math.max(0, right - left),
|
|
35894
|
+
height: Math.max(0, bottom - top)
|
|
35895
|
+
};
|
|
35896
|
+
}
|
|
35897
|
+
function metricOrFallback(value, fallback) {
|
|
35898
|
+
return Number.isFinite(value) && value > 0 ? value : fallback;
|
|
35899
|
+
}
|
|
35900
|
+
function parsePixelMetric(value) {
|
|
35901
|
+
if (!value) return null;
|
|
35902
|
+
const parsed = Number.parseFloat(value);
|
|
35903
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
35904
|
+
}
|
|
35905
|
+
function getPrimaryCell(table) {
|
|
35906
|
+
const cell = table.querySelector("th,td");
|
|
35907
|
+
return cell instanceof HTMLTableCellElement ? cell : null;
|
|
35908
|
+
}
|
|
35909
|
+
function getLastCell(table) {
|
|
35910
|
+
const lastRow = table.rows.item(table.rows.length - 1);
|
|
35911
|
+
if (!(lastRow instanceof HTMLTableRowElement)) return null;
|
|
35912
|
+
const cell = lastRow.cells.item(lastRow.cells.length - 1);
|
|
35913
|
+
return cell instanceof HTMLTableCellElement ? cell : null;
|
|
35914
|
+
}
|
|
35915
|
+
function getCellFromTarget(target) {
|
|
35916
|
+
const element = resolveEventElement(target);
|
|
35917
|
+
if (!element) return null;
|
|
35918
|
+
const directCell = element.closest("th,td");
|
|
35919
|
+
if (directCell instanceof HTMLTableCellElement) {
|
|
35920
|
+
return directCell;
|
|
35921
|
+
}
|
|
35922
|
+
const table = element.closest("table");
|
|
35923
|
+
if (table instanceof HTMLTableElement) {
|
|
35924
|
+
return getPrimaryCell(table);
|
|
35925
|
+
}
|
|
35926
|
+
return null;
|
|
35927
|
+
}
|
|
35928
|
+
function findTableInfo(editor, pos) {
|
|
35929
|
+
const $pos = editor.state.doc.resolve(pos);
|
|
35930
|
+
for (let depth = $pos.depth; depth > 0; depth -= 1) {
|
|
35931
|
+
const node = $pos.node(depth);
|
|
35932
|
+
if (node.type.name === "table") {
|
|
35933
|
+
return {
|
|
35934
|
+
node,
|
|
35935
|
+
pos: $pos.before(depth),
|
|
35936
|
+
start: $pos.start(depth)
|
|
35937
|
+
};
|
|
35938
|
+
}
|
|
35939
|
+
}
|
|
35940
|
+
return null;
|
|
35941
|
+
}
|
|
35942
|
+
function getCellRelativePosFromDomPos(map, tableStart, domPos) {
|
|
35943
|
+
const relativeDomPos = domPos - tableStart;
|
|
35944
|
+
const seen = /* @__PURE__ */ new Set();
|
|
35945
|
+
for (const relativeCellPos of map.map) {
|
|
35946
|
+
if (seen.has(relativeCellPos)) continue;
|
|
35947
|
+
seen.add(relativeCellPos);
|
|
35948
|
+
if (relativeDomPos === relativeCellPos || relativeDomPos === relativeCellPos + 1) {
|
|
35949
|
+
return relativeCellPos;
|
|
35950
|
+
}
|
|
35951
|
+
}
|
|
35952
|
+
return null;
|
|
35953
|
+
}
|
|
35954
|
+
function buildLogicalColumnMetrics({
|
|
35955
|
+
editor,
|
|
35956
|
+
surface,
|
|
35957
|
+
surfaceRect,
|
|
35958
|
+
tableElement,
|
|
35959
|
+
tableInfo,
|
|
35960
|
+
tableLeft,
|
|
35961
|
+
tableWidth
|
|
35962
|
+
}) {
|
|
35963
|
+
const map = TableMap3.get(tableInfo.node);
|
|
35964
|
+
const fallbackWidth = metricOrFallback(tableWidth / map.width, FALLBACK_TABLE_COLUMN_WIDTH);
|
|
35965
|
+
const firstRow = tableElement.rows.item(0);
|
|
35966
|
+
const visualColumns = [];
|
|
35967
|
+
if (firstRow) {
|
|
35968
|
+
for (const tableCell of Array.from(firstRow.cells)) {
|
|
35969
|
+
if (!(tableCell instanceof HTMLTableCellElement)) continue;
|
|
35970
|
+
const cellPos = editor.view.posAtDOM(tableCell, 0);
|
|
35971
|
+
const relativeCellPos = getCellRelativePosFromDomPos(map, tableInfo.start, cellPos);
|
|
35972
|
+
if (relativeCellPos == null) continue;
|
|
35973
|
+
const cellMapRect = map.findCell(relativeCellPos);
|
|
35974
|
+
const cellRect = tableCell.getBoundingClientRect();
|
|
35975
|
+
const cellStart = cellRect.width > 0 ? cellRect.left - surfaceRect.left + surface.scrollLeft : tableLeft + cellMapRect.left * fallbackWidth;
|
|
35976
|
+
const size = metricOrFallback(cellRect.width, fallbackWidth * Math.max(1, cellMapRect.right - cellMapRect.left));
|
|
35977
|
+
visualColumns.push({
|
|
35978
|
+
index: cellMapRect.left,
|
|
35979
|
+
cellPos: tableInfo.start + relativeCellPos,
|
|
35980
|
+
start: cellStart,
|
|
35981
|
+
size,
|
|
35982
|
+
center: cellStart + size / 2
|
|
35983
|
+
});
|
|
35984
|
+
}
|
|
35985
|
+
}
|
|
35986
|
+
if (visualColumns.length > 0) {
|
|
35987
|
+
return visualColumns.sort((a, b) => a.index - b.index);
|
|
35988
|
+
}
|
|
35989
|
+
const cols = Array.from(tableElement.querySelectorAll("colgroup > col"));
|
|
35990
|
+
const parsedWidths = cols.slice(0, map.width).map((col) => parsePixelMetric(col.style.width) ?? parsePixelMetric(col.getAttribute("width")));
|
|
35991
|
+
const hasCompleteColWidths = parsedWidths.length >= map.width && parsedWidths.every((width) => typeof width === "number");
|
|
35992
|
+
let cursor = tableLeft;
|
|
35993
|
+
return Array.from({ length: map.width }, (_, index) => {
|
|
35994
|
+
const size = hasCompleteColWidths ? parsedWidths[index] : fallbackWidth;
|
|
35995
|
+
const start = hasCompleteColWidths ? cursor : tableLeft + index * fallbackWidth;
|
|
35996
|
+
cursor += size;
|
|
35997
|
+
return {
|
|
35998
|
+
index,
|
|
35999
|
+
cellPos: tableInfo.start + map.positionAt(0, index, tableInfo.node),
|
|
36000
|
+
start,
|
|
36001
|
+
size,
|
|
36002
|
+
center: start + size / 2
|
|
36003
|
+
};
|
|
36004
|
+
});
|
|
36005
|
+
}
|
|
36006
|
+
function buildLogicalRowMetrics({
|
|
36007
|
+
editor,
|
|
36008
|
+
surface,
|
|
36009
|
+
surfaceRect,
|
|
36010
|
+
tableInfo,
|
|
36011
|
+
rows,
|
|
36012
|
+
tableTop,
|
|
36013
|
+
tableHeight,
|
|
36014
|
+
cornerCell
|
|
36015
|
+
}) {
|
|
36016
|
+
const map = TableMap3.get(tableInfo.node);
|
|
36017
|
+
const fallbackHeight = metricOrFallback(tableHeight / map.height, FALLBACK_TABLE_ROW_HEIGHT);
|
|
36018
|
+
const visualRows = [];
|
|
36019
|
+
const seenCellPositions = /* @__PURE__ */ new Set();
|
|
36020
|
+
for (let rowIndex = 0; rowIndex < map.height; rowIndex += 1) {
|
|
36021
|
+
const relativeCellPos = map.map[rowIndex * map.width];
|
|
36022
|
+
if (seenCellPositions.has(relativeCellPos)) continue;
|
|
36023
|
+
seenCellPositions.add(relativeCellPos);
|
|
36024
|
+
const cellMapRect = map.findCell(relativeCellPos);
|
|
36025
|
+
const cellDom = editor.view.nodeDOM(tableInfo.start + relativeCellPos);
|
|
36026
|
+
const tableCell = cellDom instanceof HTMLTableCellElement ? cellDom : null;
|
|
36027
|
+
if (tableCell) {
|
|
36028
|
+
const cellRect = tableCell.getBoundingClientRect();
|
|
36029
|
+
const start = cellRect.height > 0 ? cellRect.top - surfaceRect.top + surface.scrollTop : tableTop + cellMapRect.top * fallbackHeight;
|
|
36030
|
+
const size = metricOrFallback(cellRect.height, fallbackHeight * Math.max(1, cellMapRect.bottom - cellMapRect.top));
|
|
36031
|
+
visualRows.push({
|
|
36032
|
+
index: cellMapRect.top,
|
|
36033
|
+
cellPos: tableInfo.start + relativeCellPos,
|
|
36034
|
+
start,
|
|
36035
|
+
size,
|
|
36036
|
+
center: start + size / 2
|
|
36037
|
+
});
|
|
36038
|
+
}
|
|
36039
|
+
}
|
|
36040
|
+
if (visualRows.length > 0) {
|
|
36041
|
+
return visualRows.sort((a, b) => a.index - b.index);
|
|
36042
|
+
}
|
|
36043
|
+
return rows.map((tableRow, index) => {
|
|
36044
|
+
const rowRect = tableRow.getBoundingClientRect();
|
|
36045
|
+
const anchorCell = tableRow.cells.item(0) ?? cornerCell;
|
|
36046
|
+
const start = rowRect.height > 0 ? rowRect.top - surfaceRect.top + surface.scrollTop : tableTop + index * fallbackHeight;
|
|
36047
|
+
const size = metricOrFallback(rowRect.height, fallbackHeight);
|
|
36048
|
+
return {
|
|
36049
|
+
index,
|
|
36050
|
+
cellPos: editor.view.posAtDOM(anchorCell, 0),
|
|
36051
|
+
start,
|
|
36052
|
+
size,
|
|
36053
|
+
center: start + size / 2
|
|
36054
|
+
};
|
|
36055
|
+
});
|
|
36056
|
+
}
|
|
36057
|
+
function buildTableControlLayout(editor, surface, cell) {
|
|
36058
|
+
const row = cell.closest("tr");
|
|
36059
|
+
const table = cell.closest("table");
|
|
36060
|
+
if (!(row instanceof HTMLTableRowElement) || !(table instanceof HTMLTableElement)) {
|
|
36061
|
+
return null;
|
|
36062
|
+
}
|
|
36063
|
+
const rows = Array.from(table.rows).filter((item) => item instanceof HTMLTableRowElement);
|
|
36064
|
+
const cornerCell = getLastCell(table);
|
|
36065
|
+
const cellPos = editor.view.posAtDOM(cell, 0);
|
|
36066
|
+
const tableInfo = findTableInfo(editor, cellPos);
|
|
36067
|
+
if (rows.length === 0 || !tableInfo || !(cornerCell instanceof HTMLTableCellElement)) {
|
|
36068
|
+
return null;
|
|
36069
|
+
}
|
|
36070
|
+
const map = TableMap3.get(tableInfo.node);
|
|
36071
|
+
const surfaceRect = surface.getBoundingClientRect();
|
|
36072
|
+
const tableRect = table.getBoundingClientRect();
|
|
36073
|
+
const wrapperElement = table.closest(".tableWrapper");
|
|
36074
|
+
const wrapper = wrapperElement instanceof HTMLElement ? wrapperElement : null;
|
|
36075
|
+
const wrapperRect = wrapper?.getBoundingClientRect() ?? tableRect;
|
|
36076
|
+
const tableLeft = tableRect.left - surfaceRect.left + surface.scrollLeft;
|
|
36077
|
+
const tableTop = tableRect.top - surfaceRect.top + surface.scrollTop;
|
|
36078
|
+
const avgRowHeight = metricOrFallback(tableRect.height / rows.length, FALLBACK_TABLE_ROW_HEIGHT);
|
|
36079
|
+
const avgColumnWidth = metricOrFallback(tableRect.width / map.width, FALLBACK_TABLE_COLUMN_WIDTH);
|
|
36080
|
+
const tableWidth = metricOrFallback(tableRect.width, avgColumnWidth * map.width);
|
|
36081
|
+
const tableHeight = metricOrFallback(tableRect.height, avgRowHeight * rows.length);
|
|
36082
|
+
const wrapperLeft = wrapperRect.left - surfaceRect.left + surface.scrollLeft;
|
|
36083
|
+
const wrapperTop = wrapperRect.top - surfaceRect.top + surface.scrollTop;
|
|
36084
|
+
const wrapperWidth = metricOrFallback(wrapperRect.width, tableWidth);
|
|
36085
|
+
const wrapperHeight = metricOrFallback(wrapperRect.height, tableHeight);
|
|
36086
|
+
const viewportWidth = metricOrFallback(wrapper?.clientWidth ?? wrapperRect.width, tableWidth);
|
|
36087
|
+
const viewportHeight = metricOrFallback(wrapper?.clientHeight ?? wrapperRect.height, tableHeight);
|
|
36088
|
+
const verticalScrollbarWidth = Math.max(0, Math.round(wrapperWidth - viewportWidth));
|
|
36089
|
+
const horizontalScrollbarHeight = Math.max(0, Math.round(wrapperHeight - viewportHeight));
|
|
36090
|
+
const rowHandles = buildLogicalRowMetrics({
|
|
36091
|
+
editor,
|
|
36092
|
+
surface,
|
|
36093
|
+
surfaceRect,
|
|
36094
|
+
tableInfo,
|
|
36095
|
+
rows,
|
|
36096
|
+
tableTop,
|
|
36097
|
+
tableHeight,
|
|
36098
|
+
cornerCell
|
|
36099
|
+
});
|
|
36100
|
+
const columnHandles = buildLogicalColumnMetrics({
|
|
36101
|
+
editor,
|
|
36102
|
+
surface,
|
|
36103
|
+
surfaceRect,
|
|
36104
|
+
tableElement: table,
|
|
36105
|
+
tableInfo,
|
|
36106
|
+
tableLeft,
|
|
36107
|
+
tableWidth
|
|
36108
|
+
});
|
|
36109
|
+
const activeCellRelativePos = getCellRelativePosFromDomPos(map, tableInfo.start, cellPos);
|
|
36110
|
+
const activeCellRect = activeCellRelativePos != null ? map.findCell(activeCellRelativePos) : { left: cell.cellIndex, top: row.rowIndex };
|
|
36111
|
+
const normalizedCellPos = activeCellRelativePos != null ? tableInfo.start + activeCellRelativePos : cellPos;
|
|
36112
|
+
return {
|
|
36113
|
+
cellPos: normalizedCellPos,
|
|
36114
|
+
cornerCellPos: tableInfo.start + map.positionAt(map.height - 1, map.width - 1, tableInfo.node),
|
|
36115
|
+
activeRowIndex: activeCellRect.top,
|
|
36116
|
+
activeColumnIndex: activeCellRect.left,
|
|
36117
|
+
tableLeft,
|
|
36118
|
+
tableTop,
|
|
36119
|
+
tableWidth,
|
|
36120
|
+
tableHeight,
|
|
36121
|
+
wrapperLeft,
|
|
36122
|
+
wrapperTop,
|
|
36123
|
+
wrapperWidth,
|
|
36124
|
+
wrapperHeight,
|
|
36125
|
+
viewportWidth,
|
|
36126
|
+
viewportHeight,
|
|
36127
|
+
horizontalScrollbarHeight,
|
|
36128
|
+
verticalScrollbarWidth,
|
|
36129
|
+
avgRowHeight,
|
|
36130
|
+
avgColumnWidth,
|
|
36131
|
+
rowHandles,
|
|
36132
|
+
columnHandles
|
|
36133
|
+
};
|
|
36134
|
+
}
|
|
36135
|
+
|
|
35032
36136
|
// src/components/UEditor/table-hover-state.ts
|
|
35033
36137
|
var MENU_HOVER_PADDING = 18;
|
|
35034
36138
|
var ROW_HANDLE_HOVER_WIDTH = 28;
|
|
@@ -35062,18 +36166,18 @@ function buildTableHoverState({
|
|
|
35062
36166
|
const directAddRow = targetElement?.closest?.("[data-table-control='add-row']");
|
|
35063
36167
|
const directRowHandleIndex = directRowHandle instanceof HTMLElement ? Number.parseInt(directRowHandle.dataset.rowHandleIndex ?? "", 10) : Number.NaN;
|
|
35064
36168
|
const directColumnHandleIndex = directColumnHandle instanceof HTMLElement ? Number.parseInt(directColumnHandle.dataset.columnHandleIndex ?? "", 10) : Number.NaN;
|
|
35065
|
-
const
|
|
35066
|
-
const
|
|
36169
|
+
const visibleBounds = getVisibleTableBounds(layout);
|
|
36170
|
+
const rowRailTop = layout.wrapperTop + layout.wrapperHeight;
|
|
35067
36171
|
const isMouseInTable = relativeX >= layout.tableLeft && relativeX <= layout.tableLeft + layout.tableWidth && relativeY >= layout.tableTop && relativeY <= layout.tableTop + layout.tableHeight;
|
|
35068
36172
|
const rowHandleIndex = Number.isFinite(directRowHandleIndex) ? directRowHandleIndex : layout.rowHandles.find((rowHandle) => relativeX >= layout.tableLeft - ROW_HANDLE_HOVER_WIDTH && relativeX <= layout.tableLeft && Math.abs(relativeY - rowHandle.center) <= HANDLE_HOVER_RADIUS)?.index ?? null;
|
|
35069
36173
|
const columnHandleIndex = Number.isFinite(directColumnHandleIndex) ? directColumnHandleIndex : layout.columnHandles.find((columnHandle) => relativeY >= layout.tableTop - COLUMN_HANDLE_HOVER_HEIGHT && relativeY <= layout.tableTop && Math.abs(relativeX - columnHandle.center) <= HANDLE_HOVER_RADIUS)?.index ?? null;
|
|
35070
36174
|
const menuVisible = Boolean(directTableMenu) || isMouseInTable || relativeX >= layout.tableLeft - MENU_HOVER_PADDING && relativeX <= layout.tableLeft + 42 && relativeY >= layout.tableTop - COLUMN_HANDLE_HOVER_HEIGHT && relativeY <= layout.tableTop + MENU_HOVER_PADDING;
|
|
35071
36175
|
const lastRow = layout.rowHandles[layout.rowHandles.length - 1];
|
|
35072
36176
|
const lastCol = layout.columnHandles[layout.columnHandles.length - 1];
|
|
35073
|
-
const isMouseInLastColumn = lastCol ? relativeX >= lastCol.start && relativeX <= lastCol.start + lastCol.size && relativeY >=
|
|
35074
|
-
const addColumnVisible = Boolean(directAddColumn) || relativeX >=
|
|
35075
|
-
const isMouseInLastRow = lastRow ? relativeY >= lastRow.start && relativeY <= lastRow.start + lastRow.size && relativeX >=
|
|
35076
|
-
const addRowVisible = Boolean(directAddRow) || relativeY >=
|
|
36177
|
+
const isMouseInLastColumn = lastCol ? relativeX >= lastCol.start && relativeX <= lastCol.start + lastCol.size && relativeY >= visibleBounds.top && relativeY <= visibleBounds.bottom : false;
|
|
36178
|
+
const addColumnVisible = Boolean(directAddColumn) || relativeX >= visibleBounds.right && relativeX <= visibleBounds.right + ADD_COLUMN_HOVER_WIDTH && relativeY >= visibleBounds.top && relativeY <= visibleBounds.bottom || isMouseInLastColumn;
|
|
36179
|
+
const isMouseInLastRow = lastRow ? relativeY >= lastRow.start && relativeY <= lastRow.start + lastRow.size && relativeX >= visibleBounds.left && relativeX <= visibleBounds.right : false;
|
|
36180
|
+
const addRowVisible = Boolean(directAddRow) || relativeY >= rowRailTop && relativeY <= rowRailTop + ADD_ROW_HOVER_HEIGHT && relativeX >= visibleBounds.left && relativeX <= visibleBounds.right || isMouseInLastRow;
|
|
35077
36181
|
return {
|
|
35078
36182
|
menuVisible,
|
|
35079
36183
|
addColumnVisible,
|
|
@@ -35195,12 +36299,11 @@ function TableAddRails({
|
|
|
35195
36299
|
quickAddColumnLabel,
|
|
35196
36300
|
quickAddRowLabel
|
|
35197
36301
|
}) {
|
|
35198
|
-
const
|
|
35199
|
-
const
|
|
35200
|
-
const
|
|
35201
|
-
const columnRailLeft = layout.tableLeft + visibleTableWidth + ADD_COLUMN_RAIL_GAP;
|
|
36302
|
+
const visibleBounds = getVisibleTableBounds(layout);
|
|
36303
|
+
const columnRailTop = visibleBounds.top;
|
|
36304
|
+
const columnRailLeft = visibleBounds.right + ADD_COLUMN_RAIL_GAP;
|
|
35202
36305
|
const rowRailTop = layout.wrapperTop + layout.wrapperHeight + ADD_ROW_RAIL_GAP;
|
|
35203
|
-
const rowRailLeft =
|
|
36306
|
+
const rowRailLeft = visibleBounds.left;
|
|
35204
36307
|
const showColumnRail = controlsVisible || addColumnVisible;
|
|
35205
36308
|
const showRowRail = controlsVisible || addRowVisible;
|
|
35206
36309
|
return /* @__PURE__ */ (0, import_jsx_runtime89.jsxs)(import_jsx_runtime89.Fragment, { children: [
|
|
@@ -35228,10 +36331,10 @@ function TableAddRails({
|
|
|
35228
36331
|
"transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground disabled:opacity-50 disabled:cursor-not-allowed"
|
|
35229
36332
|
),
|
|
35230
36333
|
style: {
|
|
35231
|
-
top: showColumnRail ? columnRailTop : columnRailTop + Math.max(0,
|
|
36334
|
+
top: showColumnRail ? columnRailTop : columnRailTop + Math.max(0, visibleBounds.height / 2 - 24),
|
|
35232
36335
|
left: columnRailLeft,
|
|
35233
36336
|
width: showColumnRail ? 18 : 12,
|
|
35234
|
-
height: showColumnRail ?
|
|
36337
|
+
height: showColumnRail ? visibleBounds.height : 48,
|
|
35235
36338
|
opacity: showColumnRail ? 1 : 0,
|
|
35236
36339
|
transform: showColumnRail ? "scale(1)" : "scale(0.92)",
|
|
35237
36340
|
pointerEvents: showColumnRail ? "auto" : "none"
|
|
@@ -35266,8 +36369,8 @@ function TableAddRails({
|
|
|
35266
36369
|
),
|
|
35267
36370
|
style: {
|
|
35268
36371
|
top: rowRailTop,
|
|
35269
|
-
left: showRowRail ? rowRailLeft : rowRailLeft + Math.max(0,
|
|
35270
|
-
width: showRowRail ?
|
|
36372
|
+
left: showRowRail ? rowRailLeft : rowRailLeft + Math.max(0, visibleBounds.width / 2 - 24),
|
|
36373
|
+
width: showRowRail ? visibleBounds.width : 48,
|
|
35271
36374
|
height: showRowRail ? 16 : 12,
|
|
35272
36375
|
opacity: showRowRail ? 1 : 0,
|
|
35273
36376
|
transform: showRowRail ? "scale(1)" : "scale(0.92)",
|
|
@@ -35492,248 +36595,6 @@ function TableColumnHandles({
|
|
|
35492
36595
|
}) });
|
|
35493
36596
|
}
|
|
35494
36597
|
|
|
35495
|
-
// src/components/UEditor/table-layout-model.ts
|
|
35496
|
-
var FALLBACK_TABLE_ROW_HEIGHT = 44;
|
|
35497
|
-
var FALLBACK_TABLE_COLUMN_WIDTH = 160;
|
|
35498
|
-
function metricOrFallback(value, fallback) {
|
|
35499
|
-
return Number.isFinite(value) && value > 0 ? value : fallback;
|
|
35500
|
-
}
|
|
35501
|
-
function parsePixelMetric(value) {
|
|
35502
|
-
if (!value) return null;
|
|
35503
|
-
const parsed = Number.parseFloat(value);
|
|
35504
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
35505
|
-
}
|
|
35506
|
-
function getPrimaryCell(table) {
|
|
35507
|
-
const cell = table.querySelector("th,td");
|
|
35508
|
-
return cell instanceof HTMLTableCellElement ? cell : null;
|
|
35509
|
-
}
|
|
35510
|
-
function getLastCell(table) {
|
|
35511
|
-
const lastRow = table.rows.item(table.rows.length - 1);
|
|
35512
|
-
if (!(lastRow instanceof HTMLTableRowElement)) return null;
|
|
35513
|
-
const cell = lastRow.cells.item(lastRow.cells.length - 1);
|
|
35514
|
-
return cell instanceof HTMLTableCellElement ? cell : null;
|
|
35515
|
-
}
|
|
35516
|
-
function getCellFromTarget(target) {
|
|
35517
|
-
const element = resolveEventElement(target);
|
|
35518
|
-
if (!element) return null;
|
|
35519
|
-
const directCell = element.closest("th,td");
|
|
35520
|
-
if (directCell instanceof HTMLTableCellElement) {
|
|
35521
|
-
return directCell;
|
|
35522
|
-
}
|
|
35523
|
-
const table = element.closest("table");
|
|
35524
|
-
if (table instanceof HTMLTableElement) {
|
|
35525
|
-
return getPrimaryCell(table);
|
|
35526
|
-
}
|
|
35527
|
-
return null;
|
|
35528
|
-
}
|
|
35529
|
-
function findTableInfo(editor, pos) {
|
|
35530
|
-
const $pos = editor.state.doc.resolve(pos);
|
|
35531
|
-
for (let depth = $pos.depth; depth > 0; depth -= 1) {
|
|
35532
|
-
const node = $pos.node(depth);
|
|
35533
|
-
if (node.type.name === "table") {
|
|
35534
|
-
return {
|
|
35535
|
-
node,
|
|
35536
|
-
pos: $pos.before(depth),
|
|
35537
|
-
start: $pos.start(depth)
|
|
35538
|
-
};
|
|
35539
|
-
}
|
|
35540
|
-
}
|
|
35541
|
-
return null;
|
|
35542
|
-
}
|
|
35543
|
-
function getCellRelativePosFromDomPos(map, tableStart, domPos) {
|
|
35544
|
-
const relativeDomPos = domPos - tableStart;
|
|
35545
|
-
const seen = /* @__PURE__ */ new Set();
|
|
35546
|
-
for (const relativeCellPos of map.map) {
|
|
35547
|
-
if (seen.has(relativeCellPos)) continue;
|
|
35548
|
-
seen.add(relativeCellPos);
|
|
35549
|
-
if (relativeDomPos === relativeCellPos || relativeDomPos === relativeCellPos + 1) {
|
|
35550
|
-
return relativeCellPos;
|
|
35551
|
-
}
|
|
35552
|
-
}
|
|
35553
|
-
return null;
|
|
35554
|
-
}
|
|
35555
|
-
function buildLogicalColumnMetrics({
|
|
35556
|
-
editor,
|
|
35557
|
-
surface,
|
|
35558
|
-
surfaceRect,
|
|
35559
|
-
tableElement,
|
|
35560
|
-
tableInfo,
|
|
35561
|
-
tableLeft,
|
|
35562
|
-
tableWidth
|
|
35563
|
-
}) {
|
|
35564
|
-
const map = TableMap2.get(tableInfo.node);
|
|
35565
|
-
const fallbackWidth = metricOrFallback(tableWidth / map.width, FALLBACK_TABLE_COLUMN_WIDTH);
|
|
35566
|
-
const firstRow = tableElement.rows.item(0);
|
|
35567
|
-
const visualColumns = [];
|
|
35568
|
-
if (firstRow) {
|
|
35569
|
-
for (const tableCell of Array.from(firstRow.cells)) {
|
|
35570
|
-
if (!(tableCell instanceof HTMLTableCellElement)) continue;
|
|
35571
|
-
const cellPos = editor.view.posAtDOM(tableCell, 0);
|
|
35572
|
-
const relativeCellPos = getCellRelativePosFromDomPos(map, tableInfo.start, cellPos);
|
|
35573
|
-
if (relativeCellPos == null) continue;
|
|
35574
|
-
const cellMapRect = map.findCell(relativeCellPos);
|
|
35575
|
-
const cellRect = tableCell.getBoundingClientRect();
|
|
35576
|
-
const cellStart = cellRect.width > 0 ? cellRect.left - surfaceRect.left + surface.scrollLeft : tableLeft + cellMapRect.left * fallbackWidth;
|
|
35577
|
-
const size = metricOrFallback(cellRect.width, fallbackWidth * Math.max(1, cellMapRect.right - cellMapRect.left));
|
|
35578
|
-
visualColumns.push({
|
|
35579
|
-
index: cellMapRect.left,
|
|
35580
|
-
cellPos: tableInfo.start + relativeCellPos,
|
|
35581
|
-
start: cellStart,
|
|
35582
|
-
size,
|
|
35583
|
-
center: cellStart + size / 2
|
|
35584
|
-
});
|
|
35585
|
-
}
|
|
35586
|
-
}
|
|
35587
|
-
if (visualColumns.length > 0) {
|
|
35588
|
-
return visualColumns.sort((a, b) => a.index - b.index);
|
|
35589
|
-
}
|
|
35590
|
-
const cols = Array.from(tableElement.querySelectorAll("colgroup > col"));
|
|
35591
|
-
const parsedWidths = cols.slice(0, map.width).map((col) => parsePixelMetric(col.style.width) ?? parsePixelMetric(col.getAttribute("width")));
|
|
35592
|
-
const hasCompleteColWidths = parsedWidths.length >= map.width && parsedWidths.every((width) => typeof width === "number");
|
|
35593
|
-
let cursor = tableLeft;
|
|
35594
|
-
return Array.from({ length: map.width }, (_, index) => {
|
|
35595
|
-
const size = hasCompleteColWidths ? parsedWidths[index] : fallbackWidth;
|
|
35596
|
-
const start = hasCompleteColWidths ? cursor : tableLeft + index * fallbackWidth;
|
|
35597
|
-
cursor += size;
|
|
35598
|
-
return {
|
|
35599
|
-
index,
|
|
35600
|
-
cellPos: tableInfo.start + map.positionAt(0, index, tableInfo.node),
|
|
35601
|
-
start,
|
|
35602
|
-
size,
|
|
35603
|
-
center: start + size / 2
|
|
35604
|
-
};
|
|
35605
|
-
});
|
|
35606
|
-
}
|
|
35607
|
-
function buildLogicalRowMetrics({
|
|
35608
|
-
editor,
|
|
35609
|
-
surface,
|
|
35610
|
-
surfaceRect,
|
|
35611
|
-
tableInfo,
|
|
35612
|
-
rows,
|
|
35613
|
-
tableTop,
|
|
35614
|
-
tableHeight,
|
|
35615
|
-
cornerCell
|
|
35616
|
-
}) {
|
|
35617
|
-
const map = TableMap2.get(tableInfo.node);
|
|
35618
|
-
const fallbackHeight = metricOrFallback(tableHeight / map.height, FALLBACK_TABLE_ROW_HEIGHT);
|
|
35619
|
-
const visualRows = [];
|
|
35620
|
-
const seenCellPositions = /* @__PURE__ */ new Set();
|
|
35621
|
-
for (let rowIndex = 0; rowIndex < map.height; rowIndex += 1) {
|
|
35622
|
-
const relativeCellPos = map.map[rowIndex * map.width];
|
|
35623
|
-
if (seenCellPositions.has(relativeCellPos)) continue;
|
|
35624
|
-
seenCellPositions.add(relativeCellPos);
|
|
35625
|
-
const cellMapRect = map.findCell(relativeCellPos);
|
|
35626
|
-
const cellDom = editor.view.nodeDOM(tableInfo.start + relativeCellPos);
|
|
35627
|
-
const tableCell = cellDom instanceof HTMLTableCellElement ? cellDom : null;
|
|
35628
|
-
if (tableCell) {
|
|
35629
|
-
const cellRect = tableCell.getBoundingClientRect();
|
|
35630
|
-
const start = cellRect.height > 0 ? cellRect.top - surfaceRect.top + surface.scrollTop : tableTop + cellMapRect.top * fallbackHeight;
|
|
35631
|
-
const size = metricOrFallback(cellRect.height, fallbackHeight * Math.max(1, cellMapRect.bottom - cellMapRect.top));
|
|
35632
|
-
visualRows.push({
|
|
35633
|
-
index: cellMapRect.top,
|
|
35634
|
-
cellPos: tableInfo.start + relativeCellPos,
|
|
35635
|
-
start,
|
|
35636
|
-
size,
|
|
35637
|
-
center: start + size / 2
|
|
35638
|
-
});
|
|
35639
|
-
}
|
|
35640
|
-
}
|
|
35641
|
-
if (visualRows.length > 0) {
|
|
35642
|
-
return visualRows.sort((a, b) => a.index - b.index);
|
|
35643
|
-
}
|
|
35644
|
-
return rows.map((tableRow, index) => {
|
|
35645
|
-
const rowRect = tableRow.getBoundingClientRect();
|
|
35646
|
-
const anchorCell = tableRow.cells.item(0) ?? cornerCell;
|
|
35647
|
-
const start = rowRect.height > 0 ? rowRect.top - surfaceRect.top + surface.scrollTop : tableTop + index * fallbackHeight;
|
|
35648
|
-
const size = metricOrFallback(rowRect.height, fallbackHeight);
|
|
35649
|
-
return {
|
|
35650
|
-
index,
|
|
35651
|
-
cellPos: editor.view.posAtDOM(anchorCell, 0),
|
|
35652
|
-
start,
|
|
35653
|
-
size,
|
|
35654
|
-
center: start + size / 2
|
|
35655
|
-
};
|
|
35656
|
-
});
|
|
35657
|
-
}
|
|
35658
|
-
function buildTableControlLayout(editor, surface, cell) {
|
|
35659
|
-
const row = cell.closest("tr");
|
|
35660
|
-
const table = cell.closest("table");
|
|
35661
|
-
if (!(row instanceof HTMLTableRowElement) || !(table instanceof HTMLTableElement)) {
|
|
35662
|
-
return null;
|
|
35663
|
-
}
|
|
35664
|
-
const rows = Array.from(table.rows).filter((item) => item instanceof HTMLTableRowElement);
|
|
35665
|
-
const cornerCell = getLastCell(table);
|
|
35666
|
-
const cellPos = editor.view.posAtDOM(cell, 0);
|
|
35667
|
-
const tableInfo = findTableInfo(editor, cellPos);
|
|
35668
|
-
if (rows.length === 0 || !tableInfo || !(cornerCell instanceof HTMLTableCellElement)) {
|
|
35669
|
-
return null;
|
|
35670
|
-
}
|
|
35671
|
-
const map = TableMap2.get(tableInfo.node);
|
|
35672
|
-
const surfaceRect = surface.getBoundingClientRect();
|
|
35673
|
-
const tableRect = table.getBoundingClientRect();
|
|
35674
|
-
const wrapperElement = table.closest(".tableWrapper");
|
|
35675
|
-
const wrapper = wrapperElement instanceof HTMLElement ? wrapperElement : null;
|
|
35676
|
-
const wrapperRect = wrapper?.getBoundingClientRect() ?? tableRect;
|
|
35677
|
-
const tableLeft = tableRect.left - surfaceRect.left + surface.scrollLeft;
|
|
35678
|
-
const tableTop = tableRect.top - surfaceRect.top + surface.scrollTop;
|
|
35679
|
-
const avgRowHeight = metricOrFallback(tableRect.height / rows.length, FALLBACK_TABLE_ROW_HEIGHT);
|
|
35680
|
-
const avgColumnWidth = metricOrFallback(tableRect.width / map.width, FALLBACK_TABLE_COLUMN_WIDTH);
|
|
35681
|
-
const tableWidth = metricOrFallback(tableRect.width, avgColumnWidth * map.width);
|
|
35682
|
-
const tableHeight = metricOrFallback(tableRect.height, avgRowHeight * rows.length);
|
|
35683
|
-
const wrapperLeft = wrapperRect.left - surfaceRect.left + surface.scrollLeft;
|
|
35684
|
-
const wrapperTop = wrapperRect.top - surfaceRect.top + surface.scrollTop;
|
|
35685
|
-
const wrapperWidth = metricOrFallback(wrapperRect.width, tableWidth);
|
|
35686
|
-
const wrapperHeight = metricOrFallback(wrapperRect.height, tableHeight);
|
|
35687
|
-
const viewportWidth = metricOrFallback(wrapper?.clientWidth ?? wrapperRect.width, tableWidth);
|
|
35688
|
-
const viewportHeight = metricOrFallback(wrapper?.clientHeight ?? wrapperRect.height, tableHeight);
|
|
35689
|
-
const verticalScrollbarWidth = Math.max(0, Math.round(wrapperWidth - viewportWidth));
|
|
35690
|
-
const horizontalScrollbarHeight = Math.max(0, Math.round(wrapperHeight - viewportHeight));
|
|
35691
|
-
const rowHandles = buildLogicalRowMetrics({
|
|
35692
|
-
editor,
|
|
35693
|
-
surface,
|
|
35694
|
-
surfaceRect,
|
|
35695
|
-
tableInfo,
|
|
35696
|
-
rows,
|
|
35697
|
-
tableTop,
|
|
35698
|
-
tableHeight,
|
|
35699
|
-
cornerCell
|
|
35700
|
-
});
|
|
35701
|
-
const columnHandles = buildLogicalColumnMetrics({
|
|
35702
|
-
editor,
|
|
35703
|
-
surface,
|
|
35704
|
-
surfaceRect,
|
|
35705
|
-
tableElement: table,
|
|
35706
|
-
tableInfo,
|
|
35707
|
-
tableLeft,
|
|
35708
|
-
tableWidth
|
|
35709
|
-
});
|
|
35710
|
-
const activeCellRelativePos = getCellRelativePosFromDomPos(map, tableInfo.start, cellPos);
|
|
35711
|
-
const activeCellRect = activeCellRelativePos != null ? map.findCell(activeCellRelativePos) : { left: cell.cellIndex, top: row.rowIndex };
|
|
35712
|
-
const normalizedCellPos = activeCellRelativePos != null ? tableInfo.start + activeCellRelativePos : cellPos;
|
|
35713
|
-
return {
|
|
35714
|
-
cellPos: normalizedCellPos,
|
|
35715
|
-
cornerCellPos: tableInfo.start + map.positionAt(map.height - 1, map.width - 1, tableInfo.node),
|
|
35716
|
-
activeRowIndex: activeCellRect.top,
|
|
35717
|
-
activeColumnIndex: activeCellRect.left,
|
|
35718
|
-
tableLeft,
|
|
35719
|
-
tableTop,
|
|
35720
|
-
tableWidth,
|
|
35721
|
-
tableHeight,
|
|
35722
|
-
wrapperLeft,
|
|
35723
|
-
wrapperTop,
|
|
35724
|
-
wrapperWidth,
|
|
35725
|
-
wrapperHeight,
|
|
35726
|
-
viewportWidth,
|
|
35727
|
-
viewportHeight,
|
|
35728
|
-
horizontalScrollbarHeight,
|
|
35729
|
-
verticalScrollbarWidth,
|
|
35730
|
-
avgRowHeight,
|
|
35731
|
-
avgColumnWidth,
|
|
35732
|
-
rowHandles,
|
|
35733
|
-
columnHandles
|
|
35734
|
-
};
|
|
35735
|
-
}
|
|
35736
|
-
|
|
35737
36598
|
// src/components/UEditor/table-controls.tsx
|
|
35738
36599
|
var import_jsx_runtime92 = require("react/jsx-runtime");
|
|
35739
36600
|
var TABLE_MENU_TOP_OFFSET = 10;
|
|
@@ -37680,6 +38541,7 @@ var UEditor = import_react69.default.forwardRef(({
|
|
|
37680
38541
|
const effectivePlaceholder = placeholder ?? t("placeholder");
|
|
37681
38542
|
const inFlightPrepareRef = (0, import_react69.useRef)(null);
|
|
37682
38543
|
const lastAppliedContentRef = (0, import_react69.useRef)(content ?? "");
|
|
38544
|
+
const scheduledFormulaRecalculateRef = (0, import_react69.useRef)(false);
|
|
37683
38545
|
const resolvedUploadFile = (0, import_react69.useMemo)(() => {
|
|
37684
38546
|
if (uploadFile) return uploadFile;
|
|
37685
38547
|
if (uploadFileForSave) {
|
|
@@ -37743,7 +38605,16 @@ var UEditor = import_react69.default.forwardRef(({
|
|
|
37743
38605
|
class: UEDITOR_PROSEMIRROR_CLASS_NAME
|
|
37744
38606
|
}
|
|
37745
38607
|
},
|
|
37746
|
-
onUpdate: ({ editor: editor2 }) => {
|
|
38608
|
+
onUpdate: ({ editor: editor2, transaction }) => {
|
|
38609
|
+
if (!transaction.getMeta(UEDITOR_TABLE_FORMULA_RECALCULATE_META) && !scheduledFormulaRecalculateRef.current) {
|
|
38610
|
+
scheduledFormulaRecalculateRef.current = true;
|
|
38611
|
+
queueMicrotask(() => {
|
|
38612
|
+
scheduledFormulaRecalculateRef.current = false;
|
|
38613
|
+
if (!editor2.isDestroyed) {
|
|
38614
|
+
recalculateAllTableFormulas(editor2);
|
|
38615
|
+
}
|
|
38616
|
+
});
|
|
38617
|
+
}
|
|
37747
38618
|
const html = editor2.getHTML();
|
|
37748
38619
|
onChange?.(html);
|
|
37749
38620
|
onHtmlChange?.(html);
|
|
@@ -37781,6 +38652,14 @@ var UEditor = import_react69.default.forwardRef(({
|
|
|
37781
38652
|
}),
|
|
37782
38653
|
[content, editor, uploadImageForSave, uploadFileForSave, uploadImageConcurrency]
|
|
37783
38654
|
);
|
|
38655
|
+
(0, import_react69.useEffect)(() => {
|
|
38656
|
+
if (!editor) return;
|
|
38657
|
+
queueMicrotask(() => {
|
|
38658
|
+
if (!editor.isDestroyed) {
|
|
38659
|
+
recalculateAllTableFormulas(editor);
|
|
38660
|
+
}
|
|
38661
|
+
});
|
|
38662
|
+
}, [editor]);
|
|
37784
38663
|
(0, import_react69.useEffect)(() => {
|
|
37785
38664
|
if (!editor) return;
|
|
37786
38665
|
const nextContent = content ?? "";
|
|
@@ -37790,6 +38669,11 @@ var UEditor = import_react69.default.forwardRef(({
|
|
|
37790
38669
|
Promise.resolve().then(() => {
|
|
37791
38670
|
if (!editor.isDestroyed) {
|
|
37792
38671
|
editor.commands.setContent(nextContent, { emitUpdate: false });
|
|
38672
|
+
queueMicrotask(() => {
|
|
38673
|
+
if (!editor.isDestroyed) {
|
|
38674
|
+
recalculateAllTableFormulas(editor);
|
|
38675
|
+
}
|
|
38676
|
+
});
|
|
37793
38677
|
}
|
|
37794
38678
|
});
|
|
37795
38679
|
}
|