@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.js
CHANGED
|
@@ -843,6 +843,10 @@ var en_default = {
|
|
|
843
843
|
borderWidth: "Border Width",
|
|
844
844
|
borderColor: "Border Color",
|
|
845
845
|
clearBorder: "Clear Border",
|
|
846
|
+
formula: "Formula",
|
|
847
|
+
apply: "Apply",
|
|
848
|
+
clear: "Clear",
|
|
849
|
+
recalculate: "Recalculate",
|
|
846
850
|
done: "Done"
|
|
847
851
|
},
|
|
848
852
|
callout: {
|
|
@@ -1219,6 +1223,10 @@ var vi_default = {
|
|
|
1219
1223
|
borderWidth: "\u0110\u1ED9 d\xE0y vi\u1EC1n",
|
|
1220
1224
|
borderColor: "M\xE0u vi\u1EC1n",
|
|
1221
1225
|
clearBorder: "X\xF3a vi\u1EC1n",
|
|
1226
|
+
formula: "C\xF4ng th\u1EE9c",
|
|
1227
|
+
apply: "\xC1p d\u1EE5ng",
|
|
1228
|
+
clear: "X\xF3a",
|
|
1229
|
+
recalculate: "T\xEDnh l\u1EA1i",
|
|
1222
1230
|
done: "Xong"
|
|
1223
1231
|
},
|
|
1224
1232
|
callout: {
|
|
@@ -25985,6 +25993,10 @@ function getTableCellAttrs(cell, styles, defaultBackgroundColor) {
|
|
|
25985
25993
|
if (borderAttrs.borderColor) attrs.borderColor = borderAttrs.borderColor;
|
|
25986
25994
|
if (borderAttrs.borderStyle) attrs.borderStyle = borderAttrs.borderStyle;
|
|
25987
25995
|
if (borderAttrs.borderWidth) attrs.borderWidth = borderAttrs.borderWidth;
|
|
25996
|
+
if (cell.getAttribute("data-cell-id")) attrs.cellId = cell.getAttribute("data-cell-id") ?? void 0;
|
|
25997
|
+
if (cell.getAttribute("data-number-format")) attrs.numberFormat = cell.getAttribute("data-number-format") ?? void 0;
|
|
25998
|
+
if (cell.getAttribute("data-formula")) attrs.formula = cell.getAttribute("data-formula") ?? void 0;
|
|
25999
|
+
if (cell.getAttribute("data-computed-value")) attrs.computedValue = cell.getAttribute("data-computed-value") ?? void 0;
|
|
25988
26000
|
if (colspan > 1) attrs.colspan = colspan;
|
|
25989
26001
|
if (rowspan > 1) attrs.rowspan = rowspan;
|
|
25990
26002
|
if (colwidth) attrs.colwidth = colwidth;
|
|
@@ -27612,6 +27624,16 @@ var CodeBlockView = ({
|
|
|
27612
27624
|
};
|
|
27613
27625
|
|
|
27614
27626
|
// src/components/UEditor/extensions.ts
|
|
27627
|
+
function getFormulaStateAttributes(attributes) {
|
|
27628
|
+
const formula = attributes["data-formula"];
|
|
27629
|
+
if (!formula) {
|
|
27630
|
+
return {};
|
|
27631
|
+
}
|
|
27632
|
+
const computedValue = String(attributes["data-computed-value"] ?? "");
|
|
27633
|
+
return {
|
|
27634
|
+
"data-formula-state": computedValue.startsWith("#") ? "error" : "computed"
|
|
27635
|
+
};
|
|
27636
|
+
}
|
|
27615
27637
|
var CustomTableCell = TableCell2.extend({
|
|
27616
27638
|
addAttributes() {
|
|
27617
27639
|
return {
|
|
@@ -27657,6 +27679,46 @@ var CustomTableCell = TableCell2.extend({
|
|
|
27657
27679
|
"data-border-width": attributes.borderWidth
|
|
27658
27680
|
};
|
|
27659
27681
|
}
|
|
27682
|
+
},
|
|
27683
|
+
cellId: {
|
|
27684
|
+
default: null,
|
|
27685
|
+
parseHTML: (element) => element.getAttribute("data-cell-id") || null,
|
|
27686
|
+
renderHTML: (attributes) => {
|
|
27687
|
+
if (!attributes.cellId) return {};
|
|
27688
|
+
return {
|
|
27689
|
+
"data-cell-id": attributes.cellId
|
|
27690
|
+
};
|
|
27691
|
+
}
|
|
27692
|
+
},
|
|
27693
|
+
numberFormat: {
|
|
27694
|
+
default: null,
|
|
27695
|
+
parseHTML: (element) => element.getAttribute("data-number-format") || null,
|
|
27696
|
+
renderHTML: (attributes) => {
|
|
27697
|
+
if (!attributes.numberFormat) return {};
|
|
27698
|
+
return {
|
|
27699
|
+
"data-number-format": attributes.numberFormat
|
|
27700
|
+
};
|
|
27701
|
+
}
|
|
27702
|
+
},
|
|
27703
|
+
formula: {
|
|
27704
|
+
default: null,
|
|
27705
|
+
parseHTML: (element) => element.getAttribute("data-formula") || null,
|
|
27706
|
+
renderHTML: (attributes) => {
|
|
27707
|
+
if (!attributes.formula) return {};
|
|
27708
|
+
return {
|
|
27709
|
+
"data-formula": attributes.formula
|
|
27710
|
+
};
|
|
27711
|
+
}
|
|
27712
|
+
},
|
|
27713
|
+
computedValue: {
|
|
27714
|
+
default: null,
|
|
27715
|
+
parseHTML: (element) => element.getAttribute("data-computed-value") || null,
|
|
27716
|
+
renderHTML: (attributes) => {
|
|
27717
|
+
if (!attributes.computedValue) return {};
|
|
27718
|
+
return {
|
|
27719
|
+
"data-computed-value": attributes.computedValue
|
|
27720
|
+
};
|
|
27721
|
+
}
|
|
27660
27722
|
}
|
|
27661
27723
|
};
|
|
27662
27724
|
},
|
|
@@ -27674,7 +27736,7 @@ var CustomTableCell = TableCell2.extend({
|
|
|
27674
27736
|
mergedStyle = mergedStyle.replace(/^;/, "").trim();
|
|
27675
27737
|
return [
|
|
27676
27738
|
"td",
|
|
27677
|
-
mergeAttributes5(this.options.HTMLAttributes, HTMLAttributes, mergedStyle ? { style: mergedStyle } : {}),
|
|
27739
|
+
mergeAttributes5(this.options.HTMLAttributes, HTMLAttributes, getFormulaStateAttributes(HTMLAttributes), mergedStyle ? { style: mergedStyle } : {}),
|
|
27678
27740
|
0
|
|
27679
27741
|
];
|
|
27680
27742
|
}
|
|
@@ -27724,6 +27786,46 @@ var CustomTableHeader = TableHeader2.extend({
|
|
|
27724
27786
|
"data-border-width": attributes.borderWidth
|
|
27725
27787
|
};
|
|
27726
27788
|
}
|
|
27789
|
+
},
|
|
27790
|
+
cellId: {
|
|
27791
|
+
default: null,
|
|
27792
|
+
parseHTML: (element) => element.getAttribute("data-cell-id") || null,
|
|
27793
|
+
renderHTML: (attributes) => {
|
|
27794
|
+
if (!attributes.cellId) return {};
|
|
27795
|
+
return {
|
|
27796
|
+
"data-cell-id": attributes.cellId
|
|
27797
|
+
};
|
|
27798
|
+
}
|
|
27799
|
+
},
|
|
27800
|
+
numberFormat: {
|
|
27801
|
+
default: null,
|
|
27802
|
+
parseHTML: (element) => element.getAttribute("data-number-format") || null,
|
|
27803
|
+
renderHTML: (attributes) => {
|
|
27804
|
+
if (!attributes.numberFormat) return {};
|
|
27805
|
+
return {
|
|
27806
|
+
"data-number-format": attributes.numberFormat
|
|
27807
|
+
};
|
|
27808
|
+
}
|
|
27809
|
+
},
|
|
27810
|
+
formula: {
|
|
27811
|
+
default: null,
|
|
27812
|
+
parseHTML: (element) => element.getAttribute("data-formula") || null,
|
|
27813
|
+
renderHTML: (attributes) => {
|
|
27814
|
+
if (!attributes.formula) return {};
|
|
27815
|
+
return {
|
|
27816
|
+
"data-formula": attributes.formula
|
|
27817
|
+
};
|
|
27818
|
+
}
|
|
27819
|
+
},
|
|
27820
|
+
computedValue: {
|
|
27821
|
+
default: null,
|
|
27822
|
+
parseHTML: (element) => element.getAttribute("data-computed-value") || null,
|
|
27823
|
+
renderHTML: (attributes) => {
|
|
27824
|
+
if (!attributes.computedValue) return {};
|
|
27825
|
+
return {
|
|
27826
|
+
"data-computed-value": attributes.computedValue
|
|
27827
|
+
};
|
|
27828
|
+
}
|
|
27727
27829
|
}
|
|
27728
27830
|
};
|
|
27729
27831
|
},
|
|
@@ -27741,7 +27843,7 @@ var CustomTableHeader = TableHeader2.extend({
|
|
|
27741
27843
|
mergedStyle = mergedStyle.replace(/^;/, "").trim();
|
|
27742
27844
|
return [
|
|
27743
27845
|
"th",
|
|
27744
|
-
mergeAttributes5(this.options.HTMLAttributes, HTMLAttributes, mergedStyle ? { style: mergedStyle } : {}),
|
|
27846
|
+
mergeAttributes5(this.options.HTMLAttributes, HTMLAttributes, getFormulaStateAttributes(HTMLAttributes), mergedStyle ? { style: mergedStyle } : {}),
|
|
27745
27847
|
0
|
|
27746
27848
|
];
|
|
27747
27849
|
}
|
|
@@ -28474,6 +28576,34 @@ function collectChildren(node) {
|
|
|
28474
28576
|
function createEmptyCellNode(cellNode) {
|
|
28475
28577
|
return cellNode.type.createAndFill(cellNode.attrs) ?? cellNode;
|
|
28476
28578
|
}
|
|
28579
|
+
function createCellCopyForColumnDuplicate(cellNode) {
|
|
28580
|
+
return cellNode.type.create(cellNode.attrs, cellNode.content);
|
|
28581
|
+
}
|
|
28582
|
+
function getTableRows(tableNode) {
|
|
28583
|
+
const rows = [];
|
|
28584
|
+
tableNode.forEach((rowNode, rowOffset) => {
|
|
28585
|
+
const cells = [];
|
|
28586
|
+
rowNode.forEach((cellNode, cellOffset, index) => {
|
|
28587
|
+
cells.push({
|
|
28588
|
+
index,
|
|
28589
|
+
node: cellNode,
|
|
28590
|
+
relativePos: rowOffset + 1 + cellOffset
|
|
28591
|
+
});
|
|
28592
|
+
});
|
|
28593
|
+
rows.push({
|
|
28594
|
+
node: rowNode,
|
|
28595
|
+
cells
|
|
28596
|
+
});
|
|
28597
|
+
});
|
|
28598
|
+
return rows;
|
|
28599
|
+
}
|
|
28600
|
+
function safeFindCell(map, relativePos) {
|
|
28601
|
+
try {
|
|
28602
|
+
return map.findCell(relativePos);
|
|
28603
|
+
} catch {
|
|
28604
|
+
return null;
|
|
28605
|
+
}
|
|
28606
|
+
}
|
|
28477
28607
|
function getSelectedTableRect(editor) {
|
|
28478
28608
|
const cellSelection = getCellSelectionPositions(editor.state.selection);
|
|
28479
28609
|
if (cellSelection) {
|
|
@@ -28599,34 +28729,49 @@ function duplicateTableRowAt(editor, rowIndex, cellPos) {
|
|
|
28599
28729
|
}
|
|
28600
28730
|
function clearTableRowAt(editor, rowIndex, cellPos) {
|
|
28601
28731
|
return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
|
|
28602
|
-
const
|
|
28603
|
-
|
|
28604
|
-
|
|
28605
|
-
|
|
28606
|
-
|
|
28732
|
+
const map = TableMap.get(tableNode);
|
|
28733
|
+
if (rowIndex < 0 || rowIndex >= map.height) return null;
|
|
28734
|
+
const rows = getTableRows(tableNode).map((rowInfo) => {
|
|
28735
|
+
const cells = collectChildren(rowInfo.node);
|
|
28736
|
+
for (const entry of rowInfo.cells) {
|
|
28737
|
+
const rect = safeFindCell(map, entry.relativePos);
|
|
28738
|
+
if (!rect || rect.top > rowIndex || rowIndex >= rect.bottom) continue;
|
|
28739
|
+
cells[entry.index] = createEmptyCellNode(entry.node);
|
|
28740
|
+
}
|
|
28741
|
+
return rowInfo.node.type.create(rowInfo.node.attrs, cells);
|
|
28742
|
+
});
|
|
28607
28743
|
return tableNode.type.create(tableNode.attrs, rows);
|
|
28608
28744
|
});
|
|
28609
28745
|
}
|
|
28610
28746
|
function duplicateTableColumnAt(editor, columnIndex, cellPos) {
|
|
28611
28747
|
return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
|
|
28612
|
-
const
|
|
28613
|
-
|
|
28614
|
-
|
|
28615
|
-
|
|
28616
|
-
|
|
28617
|
-
|
|
28748
|
+
const map = TableMap.get(tableNode);
|
|
28749
|
+
if (columnIndex < 0 || columnIndex >= map.width) return null;
|
|
28750
|
+
const rows = getTableRows(tableNode).map((rowInfo, rowIndex) => {
|
|
28751
|
+
const cells = collectChildren(rowInfo.node);
|
|
28752
|
+
const sourceCell = rowInfo.cells.find((entry) => {
|
|
28753
|
+
const rect = safeFindCell(map, entry.relativePos);
|
|
28754
|
+
return rect && rect.top === rowIndex && rect.left <= columnIndex && columnIndex < rect.right;
|
|
28755
|
+
});
|
|
28756
|
+
if (!sourceCell) return rowInfo.node;
|
|
28757
|
+
cells.splice(sourceCell.index + 1, 0, createCellCopyForColumnDuplicate(sourceCell.node));
|
|
28758
|
+
return rowInfo.node.type.create(rowInfo.node.attrs, cells);
|
|
28618
28759
|
});
|
|
28619
28760
|
return tableNode.type.create(tableNode.attrs, rows);
|
|
28620
28761
|
});
|
|
28621
28762
|
}
|
|
28622
28763
|
function clearTableColumnAt(editor, columnIndex, cellPos) {
|
|
28623
28764
|
return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
|
|
28624
|
-
const
|
|
28625
|
-
|
|
28626
|
-
|
|
28627
|
-
|
|
28628
|
-
|
|
28629
|
-
|
|
28765
|
+
const map = TableMap.get(tableNode);
|
|
28766
|
+
if (columnIndex < 0 || columnIndex >= map.width) return null;
|
|
28767
|
+
const rows = getTableRows(tableNode).map((rowInfo) => {
|
|
28768
|
+
const cells = collectChildren(rowInfo.node);
|
|
28769
|
+
for (const entry of rowInfo.cells) {
|
|
28770
|
+
const rect = safeFindCell(map, entry.relativePos);
|
|
28771
|
+
if (!rect || rect.left > columnIndex || columnIndex >= rect.right) continue;
|
|
28772
|
+
cells[entry.index] = createEmptyCellNode(entry.node);
|
|
28773
|
+
}
|
|
28774
|
+
return rowInfo.node.type.create(rowInfo.node.attrs, cells);
|
|
28630
28775
|
});
|
|
28631
28776
|
return tableNode.type.create(tableNode.attrs, rows);
|
|
28632
28777
|
});
|
|
@@ -29678,7 +29823,7 @@ var EditorToolbar = ({
|
|
|
29678
29823
|
// src/components/UEditor/menus.tsx
|
|
29679
29824
|
import { useCallback as useCallback22, useEffect as useEffect36, useMemo as useMemo23, useRef as useRef33, useState as useState48 } from "react";
|
|
29680
29825
|
import { useEditorState as useEditorState2 } from "@tiptap/react";
|
|
29681
|
-
import { isInTable as isSelectionInTable, setCellAttr } from "@tiptap/pm/tables";
|
|
29826
|
+
import { isInTable as isSelectionInTable, setCellAttr as setCellAttr2 } from "@tiptap/pm/tables";
|
|
29682
29827
|
import { createPortal as createPortal8 } from "react-dom";
|
|
29683
29828
|
import {
|
|
29684
29829
|
AlignCenter as AlignCenter2,
|
|
@@ -29700,13 +29845,620 @@ import {
|
|
|
29700
29845
|
Strikethrough as StrikethroughIcon2,
|
|
29701
29846
|
Edit2,
|
|
29702
29847
|
Unlink,
|
|
29703
|
-
ExternalLink as ExternalLink3
|
|
29848
|
+
ExternalLink as ExternalLink3,
|
|
29849
|
+
Sigma
|
|
29704
29850
|
} from "lucide-react";
|
|
29851
|
+
|
|
29852
|
+
// src/components/UEditor/table-formula-commands.ts
|
|
29853
|
+
import { selectedRect as selectedRect2, setCellAttr, TableMap as TableMap2 } from "@tiptap/pm/tables";
|
|
29854
|
+
|
|
29855
|
+
// src/components/UEditor/table-formula.ts
|
|
29856
|
+
var CELL_ADDRESS_RE = /^([A-Z]+)([1-9]\d*)$/i;
|
|
29857
|
+
var CELL_RANGE_RE = /^([A-Z]+[1-9]\d*):([A-Z]+[1-9]\d*)$/i;
|
|
29858
|
+
var SUPPORTED_FUNCTIONS = /* @__PURE__ */ new Set(["SUM", "AVG", "MIN", "MAX", "COUNT"]);
|
|
29859
|
+
function columnNameToIndex(columnName) {
|
|
29860
|
+
const normalized = columnName.trim().toUpperCase();
|
|
29861
|
+
if (!/^[A-Z]+$/.test(normalized)) {
|
|
29862
|
+
return -1;
|
|
29863
|
+
}
|
|
29864
|
+
let index = 0;
|
|
29865
|
+
for (const char of normalized) {
|
|
29866
|
+
index = index * 26 + char.charCodeAt(0) - 64;
|
|
29867
|
+
}
|
|
29868
|
+
return index - 1;
|
|
29869
|
+
}
|
|
29870
|
+
function indexToColumnName(index) {
|
|
29871
|
+
if (!Number.isInteger(index) || index < 0) {
|
|
29872
|
+
return "";
|
|
29873
|
+
}
|
|
29874
|
+
let value = index + 1;
|
|
29875
|
+
let name = "";
|
|
29876
|
+
while (value > 0) {
|
|
29877
|
+
const remainder = (value - 1) % 26;
|
|
29878
|
+
name = String.fromCharCode(65 + remainder) + name;
|
|
29879
|
+
value = Math.floor((value - 1) / 26);
|
|
29880
|
+
}
|
|
29881
|
+
return name;
|
|
29882
|
+
}
|
|
29883
|
+
function parseTableCellAddress(input) {
|
|
29884
|
+
const match = input.trim().match(CELL_ADDRESS_RE);
|
|
29885
|
+
if (!match) {
|
|
29886
|
+
return null;
|
|
29887
|
+
}
|
|
29888
|
+
const column = columnNameToIndex(match[1] ?? "");
|
|
29889
|
+
const row = Number.parseInt(match[2] ?? "", 10) - 1;
|
|
29890
|
+
if (column < 0 || row < 0) {
|
|
29891
|
+
return null;
|
|
29892
|
+
}
|
|
29893
|
+
return {
|
|
29894
|
+
column,
|
|
29895
|
+
row,
|
|
29896
|
+
label: `${indexToColumnName(column)}${row + 1}`
|
|
29897
|
+
};
|
|
29898
|
+
}
|
|
29899
|
+
function parseTableCellRange(input) {
|
|
29900
|
+
const match = input.trim().match(CELL_RANGE_RE);
|
|
29901
|
+
if (!match) {
|
|
29902
|
+
return null;
|
|
29903
|
+
}
|
|
29904
|
+
const from = parseTableCellAddress(match[1] ?? "");
|
|
29905
|
+
const to = parseTableCellAddress(match[2] ?? "");
|
|
29906
|
+
if (!from || !to) {
|
|
29907
|
+
return null;
|
|
29908
|
+
}
|
|
29909
|
+
return { from, to };
|
|
29910
|
+
}
|
|
29911
|
+
function getTableCellRangeLabels(range) {
|
|
29912
|
+
const startColumn = Math.min(range.from.column, range.to.column);
|
|
29913
|
+
const endColumn = Math.max(range.from.column, range.to.column);
|
|
29914
|
+
const startRow = Math.min(range.from.row, range.to.row);
|
|
29915
|
+
const endRow = Math.max(range.from.row, range.to.row);
|
|
29916
|
+
const labels = [];
|
|
29917
|
+
for (let row = startRow; row <= endRow; row += 1) {
|
|
29918
|
+
for (let column = startColumn; column <= endColumn; column += 1) {
|
|
29919
|
+
labels.push(`${indexToColumnName(column)}${row + 1}`);
|
|
29920
|
+
}
|
|
29921
|
+
}
|
|
29922
|
+
return labels;
|
|
29923
|
+
}
|
|
29924
|
+
function normalizeTableFormula(formula) {
|
|
29925
|
+
return formula.trim().replace(/^=/, "").trim();
|
|
29926
|
+
}
|
|
29927
|
+
function formatFormulaError(error) {
|
|
29928
|
+
return `#${error.toUpperCase()}`;
|
|
29929
|
+
}
|
|
29930
|
+
function getTableFormulaReferences(formula) {
|
|
29931
|
+
const normalized = normalizeTableFormula(formula);
|
|
29932
|
+
if (!normalized) return [];
|
|
29933
|
+
const tokens = tokenizeFormula(normalized);
|
|
29934
|
+
if (!tokens) return [];
|
|
29935
|
+
const references = /* @__PURE__ */ new Set();
|
|
29936
|
+
for (const token of tokens) {
|
|
29937
|
+
if (token.type === "cell") {
|
|
29938
|
+
references.add(token.value);
|
|
29939
|
+
} else if (token.type === "range") {
|
|
29940
|
+
const range = parseTableCellRange(token.value);
|
|
29941
|
+
if (!range) continue;
|
|
29942
|
+
for (const label of getTableCellRangeLabels(range)) {
|
|
29943
|
+
references.add(label);
|
|
29944
|
+
}
|
|
29945
|
+
}
|
|
29946
|
+
}
|
|
29947
|
+
return Array.from(references);
|
|
29948
|
+
}
|
|
29949
|
+
function buildTableFormulaDependencyGraph(cells) {
|
|
29950
|
+
const dependencies = /* @__PURE__ */ new Map();
|
|
29951
|
+
const dependents = /* @__PURE__ */ new Map();
|
|
29952
|
+
const formulas = /* @__PURE__ */ new Map();
|
|
29953
|
+
for (const cell of cells) {
|
|
29954
|
+
const label = cell.label.toUpperCase();
|
|
29955
|
+
formulas.set(label, cell.formula);
|
|
29956
|
+
dependencies.set(label, new Set(getTableFormulaReferences(cell.formula)));
|
|
29957
|
+
if (!dependents.has(label)) {
|
|
29958
|
+
dependents.set(label, /* @__PURE__ */ new Set());
|
|
29959
|
+
}
|
|
29960
|
+
}
|
|
29961
|
+
for (const [label, refs] of dependencies) {
|
|
29962
|
+
for (const ref of refs) {
|
|
29963
|
+
if (!dependents.has(ref)) {
|
|
29964
|
+
dependents.set(ref, /* @__PURE__ */ new Set());
|
|
29965
|
+
}
|
|
29966
|
+
dependents.get(ref)?.add(label);
|
|
29967
|
+
}
|
|
29968
|
+
}
|
|
29969
|
+
return { dependencies, dependents, formulas };
|
|
29970
|
+
}
|
|
29971
|
+
function getTableFormulaCircularReferences(graph) {
|
|
29972
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
29973
|
+
const visited = /* @__PURE__ */ new Set();
|
|
29974
|
+
const circular = /* @__PURE__ */ new Set();
|
|
29975
|
+
const stack = [];
|
|
29976
|
+
const visit = (label) => {
|
|
29977
|
+
if (visiting.has(label)) {
|
|
29978
|
+
const start = stack.indexOf(label);
|
|
29979
|
+
for (const cycleLabel of start >= 0 ? stack.slice(start) : [label]) {
|
|
29980
|
+
circular.add(cycleLabel);
|
|
29981
|
+
}
|
|
29982
|
+
return;
|
|
29983
|
+
}
|
|
29984
|
+
if (visited.has(label)) return;
|
|
29985
|
+
visiting.add(label);
|
|
29986
|
+
stack.push(label);
|
|
29987
|
+
for (const ref of graph.dependencies.get(label) ?? []) {
|
|
29988
|
+
if (graph.formulas.has(ref)) {
|
|
29989
|
+
visit(ref);
|
|
29990
|
+
}
|
|
29991
|
+
}
|
|
29992
|
+
stack.pop();
|
|
29993
|
+
visiting.delete(label);
|
|
29994
|
+
visited.add(label);
|
|
29995
|
+
};
|
|
29996
|
+
for (const label of graph.formulas.keys()) {
|
|
29997
|
+
visit(label);
|
|
29998
|
+
}
|
|
29999
|
+
return circular;
|
|
30000
|
+
}
|
|
30001
|
+
function getTableFormulaRecalculationOrder(graph) {
|
|
30002
|
+
const circular = getTableFormulaCircularReferences(graph);
|
|
30003
|
+
const visited = /* @__PURE__ */ new Set();
|
|
30004
|
+
const order = [];
|
|
30005
|
+
const visit = (label) => {
|
|
30006
|
+
if (visited.has(label) || circular.has(label)) return;
|
|
30007
|
+
visited.add(label);
|
|
30008
|
+
for (const ref of graph.dependencies.get(label) ?? []) {
|
|
30009
|
+
if (graph.formulas.has(ref)) {
|
|
30010
|
+
visit(ref);
|
|
30011
|
+
}
|
|
30012
|
+
}
|
|
30013
|
+
order.push(label);
|
|
30014
|
+
};
|
|
30015
|
+
for (const label of graph.formulas.keys()) {
|
|
30016
|
+
visit(label);
|
|
30017
|
+
}
|
|
30018
|
+
return { order, circular };
|
|
30019
|
+
}
|
|
30020
|
+
function evaluateBasicTableFormula(formula, getCellValue) {
|
|
30021
|
+
const normalized = normalizeTableFormula(formula);
|
|
30022
|
+
if (!normalized) {
|
|
30023
|
+
return { value: null, error: "empty" };
|
|
30024
|
+
}
|
|
30025
|
+
const tokens = tokenizeFormula(normalized);
|
|
30026
|
+
if (!tokens) {
|
|
30027
|
+
return { value: null, error: "invalid-formula" };
|
|
30028
|
+
}
|
|
30029
|
+
const parser = new FormulaParser(tokens, getCellValue);
|
|
30030
|
+
const result = parser.parseExpression();
|
|
30031
|
+
if (result.error) {
|
|
30032
|
+
return result;
|
|
30033
|
+
}
|
|
30034
|
+
if (!parser.isComplete()) {
|
|
30035
|
+
return { value: null, error: "invalid-formula" };
|
|
30036
|
+
}
|
|
30037
|
+
return result;
|
|
30038
|
+
}
|
|
30039
|
+
function tokenizeFormula(formula) {
|
|
30040
|
+
const tokens = [];
|
|
30041
|
+
let index = 0;
|
|
30042
|
+
while (index < formula.length) {
|
|
30043
|
+
const char = formula[index];
|
|
30044
|
+
if (!char) break;
|
|
30045
|
+
if (/\s/.test(char)) {
|
|
30046
|
+
index += 1;
|
|
30047
|
+
continue;
|
|
30048
|
+
}
|
|
30049
|
+
if (char === "," || char === "+" || char === "-" || char === "*" || char === "/" || char === "(" || char === ")") {
|
|
30050
|
+
if (char === ",") tokens.push({ type: "comma", value: char });
|
|
30051
|
+
else if (char === "(" || char === ")") tokens.push({ type: "paren", value: char });
|
|
30052
|
+
else tokens.push({ type: "operator", value: char });
|
|
30053
|
+
index += 1;
|
|
30054
|
+
continue;
|
|
30055
|
+
}
|
|
30056
|
+
const numberMatch = formula.slice(index).match(/^\d+(?:\.\d+)?/);
|
|
30057
|
+
if (numberMatch?.[0]) {
|
|
30058
|
+
tokens.push({ type: "number", value: Number.parseFloat(numberMatch[0]) });
|
|
30059
|
+
index += numberMatch[0].length;
|
|
30060
|
+
continue;
|
|
30061
|
+
}
|
|
30062
|
+
const identifierMatch = formula.slice(index).match(/^[A-Z]+[1-9]\d*(?::[A-Z]+[1-9]\d*)?|^[A-Z]+/i);
|
|
30063
|
+
if (identifierMatch?.[0]) {
|
|
30064
|
+
const value = identifierMatch[0].toUpperCase();
|
|
30065
|
+
if (CELL_RANGE_RE.test(value)) tokens.push({ type: "range", value });
|
|
30066
|
+
else if (parseTableCellAddress(value)) tokens.push({ type: "cell", value });
|
|
30067
|
+
else if (SUPPORTED_FUNCTIONS.has(value)) tokens.push({ type: "function", value });
|
|
30068
|
+
else return null;
|
|
30069
|
+
index += identifierMatch[0].length;
|
|
30070
|
+
continue;
|
|
30071
|
+
}
|
|
30072
|
+
return null;
|
|
30073
|
+
}
|
|
30074
|
+
return tokens;
|
|
30075
|
+
}
|
|
30076
|
+
var FormulaParser = class {
|
|
30077
|
+
constructor(tokens, getCellValue) {
|
|
30078
|
+
this.tokens = tokens;
|
|
30079
|
+
this.getCellValue = getCellValue;
|
|
30080
|
+
this.index = 0;
|
|
30081
|
+
}
|
|
30082
|
+
isComplete() {
|
|
30083
|
+
return this.index >= this.tokens.length;
|
|
30084
|
+
}
|
|
30085
|
+
parseExpression() {
|
|
30086
|
+
let left = this.parseTerm();
|
|
30087
|
+
while (!left.error) {
|
|
30088
|
+
const operator = this.peekOperator(["+", "-"]);
|
|
30089
|
+
if (!operator) break;
|
|
30090
|
+
this.index += 1;
|
|
30091
|
+
const right = this.parseTerm();
|
|
30092
|
+
if (right.error) return right;
|
|
30093
|
+
left = {
|
|
30094
|
+
value: operator.value === "+" ? left.value + right.value : left.value - right.value,
|
|
30095
|
+
error: null
|
|
30096
|
+
};
|
|
30097
|
+
}
|
|
30098
|
+
return left;
|
|
30099
|
+
}
|
|
30100
|
+
parseTerm() {
|
|
30101
|
+
let left = this.parseFactor();
|
|
30102
|
+
while (!left.error) {
|
|
30103
|
+
const operator = this.peekOperator(["*", "/"]);
|
|
30104
|
+
if (!operator) break;
|
|
30105
|
+
this.index += 1;
|
|
30106
|
+
const right = this.parseFactor();
|
|
30107
|
+
if (right.error) return right;
|
|
30108
|
+
if (operator.value === "/" && right.value === 0) {
|
|
30109
|
+
return { value: null, error: "division-by-zero" };
|
|
30110
|
+
}
|
|
30111
|
+
left = {
|
|
30112
|
+
value: operator.value === "*" ? left.value * right.value : left.value / right.value,
|
|
30113
|
+
error: null
|
|
30114
|
+
};
|
|
30115
|
+
}
|
|
30116
|
+
return left;
|
|
30117
|
+
}
|
|
30118
|
+
parseFactor() {
|
|
30119
|
+
const token = this.tokens[this.index];
|
|
30120
|
+
if (!token) {
|
|
30121
|
+
return { value: null, error: "invalid-formula" };
|
|
30122
|
+
}
|
|
30123
|
+
if (token.type === "operator" && token.value === "-") {
|
|
30124
|
+
this.index += 1;
|
|
30125
|
+
const value = this.parseFactor();
|
|
30126
|
+
if (value.error) return value;
|
|
30127
|
+
return { value: -value.value, error: null };
|
|
30128
|
+
}
|
|
30129
|
+
if (token.type === "number") {
|
|
30130
|
+
this.index += 1;
|
|
30131
|
+
return { value: token.value, error: null };
|
|
30132
|
+
}
|
|
30133
|
+
if (token.type === "cell") {
|
|
30134
|
+
this.index += 1;
|
|
30135
|
+
return this.readCellNumber(token.value);
|
|
30136
|
+
}
|
|
30137
|
+
if (token.type === "function") {
|
|
30138
|
+
return this.parseFunction(token.value);
|
|
30139
|
+
}
|
|
30140
|
+
if (token.type === "paren" && token.value === "(") {
|
|
30141
|
+
this.index += 1;
|
|
30142
|
+
const value = this.parseExpression();
|
|
30143
|
+
if (value.error) return value;
|
|
30144
|
+
if (!this.consumeParen(")")) {
|
|
30145
|
+
return { value: null, error: "invalid-formula" };
|
|
30146
|
+
}
|
|
30147
|
+
return value;
|
|
30148
|
+
}
|
|
30149
|
+
return { value: null, error: "invalid-formula" };
|
|
30150
|
+
}
|
|
30151
|
+
parseFunction(name) {
|
|
30152
|
+
this.index += 1;
|
|
30153
|
+
if (!this.consumeParen("(")) {
|
|
30154
|
+
return { value: null, error: "invalid-formula" };
|
|
30155
|
+
}
|
|
30156
|
+
const values = [];
|
|
30157
|
+
while (true) {
|
|
30158
|
+
const token = this.tokens[this.index];
|
|
30159
|
+
if (!token) {
|
|
30160
|
+
return { value: null, error: "invalid-formula" };
|
|
30161
|
+
}
|
|
30162
|
+
if (token.type === "range") {
|
|
30163
|
+
this.index += 1;
|
|
30164
|
+
const range = parseTableCellRange(token.value);
|
|
30165
|
+
if (!range) return { value: null, error: "invalid-reference" };
|
|
30166
|
+
for (const label of getTableCellRangeLabels(range)) {
|
|
30167
|
+
const cellValue = this.readCellNumber(label);
|
|
30168
|
+
if (cellValue.error) return cellValue;
|
|
30169
|
+
values.push(cellValue.value);
|
|
30170
|
+
}
|
|
30171
|
+
} else {
|
|
30172
|
+
const value = this.parseExpression();
|
|
30173
|
+
if (value.error) return value;
|
|
30174
|
+
values.push(value.value);
|
|
30175
|
+
}
|
|
30176
|
+
if (this.consumeComma()) {
|
|
30177
|
+
continue;
|
|
30178
|
+
}
|
|
30179
|
+
if (this.consumeParen(")")) {
|
|
30180
|
+
break;
|
|
30181
|
+
}
|
|
30182
|
+
return { value: null, error: "invalid-formula" };
|
|
30183
|
+
}
|
|
30184
|
+
if (values.length === 0) {
|
|
30185
|
+
return { value: null, error: "invalid-formula" };
|
|
30186
|
+
}
|
|
30187
|
+
if (name === "SUM") return { value: values.reduce((sum, value) => sum + value, 0), error: null };
|
|
30188
|
+
if (name === "AVG") return { value: values.reduce((sum, value) => sum + value, 0) / values.length, error: null };
|
|
30189
|
+
if (name === "MIN") return { value: Math.min(...values), error: null };
|
|
30190
|
+
if (name === "MAX") return { value: Math.max(...values), error: null };
|
|
30191
|
+
if (name === "COUNT") return { value: values.length, error: null };
|
|
30192
|
+
return { value: null, error: "invalid-formula" };
|
|
30193
|
+
}
|
|
30194
|
+
readCellNumber(label) {
|
|
30195
|
+
const value = this.getCellValue(label);
|
|
30196
|
+
const parsed = typeof value === "number" ? value : Number.parseFloat(String(value ?? "").trim());
|
|
30197
|
+
if (!Number.isFinite(parsed)) {
|
|
30198
|
+
return { value: null, error: "invalid-reference" };
|
|
30199
|
+
}
|
|
30200
|
+
return { value: parsed, error: null };
|
|
30201
|
+
}
|
|
30202
|
+
peekOperator(operators) {
|
|
30203
|
+
const token = this.tokens[this.index];
|
|
30204
|
+
return token?.type === "operator" && operators.includes(token.value) ? token : null;
|
|
30205
|
+
}
|
|
30206
|
+
consumeComma() {
|
|
30207
|
+
if (this.tokens[this.index]?.type !== "comma") {
|
|
30208
|
+
return false;
|
|
30209
|
+
}
|
|
30210
|
+
this.index += 1;
|
|
30211
|
+
return true;
|
|
30212
|
+
}
|
|
30213
|
+
consumeParen(value) {
|
|
30214
|
+
const token = this.tokens[this.index];
|
|
30215
|
+
if (token?.type !== "paren" || token.value !== value) {
|
|
30216
|
+
return false;
|
|
30217
|
+
}
|
|
30218
|
+
this.index += 1;
|
|
30219
|
+
return true;
|
|
30220
|
+
}
|
|
30221
|
+
};
|
|
30222
|
+
|
|
30223
|
+
// src/components/UEditor/table-formula-commands.ts
|
|
30224
|
+
var UEDITOR_TABLE_FORMULA_RECALCULATE_META = "ueditorTableFormulaRecalculate";
|
|
30225
|
+
function collectChildren2(node) {
|
|
30226
|
+
const children = [];
|
|
30227
|
+
node.forEach((child) => children.push(child));
|
|
30228
|
+
return children;
|
|
30229
|
+
}
|
|
30230
|
+
function getTableRows2(tableNode) {
|
|
30231
|
+
const rows = [];
|
|
30232
|
+
tableNode.forEach((rowNode, rowOffset) => {
|
|
30233
|
+
const cells = [];
|
|
30234
|
+
rowNode.forEach((cellNode, cellOffset, index) => {
|
|
30235
|
+
cells.push({
|
|
30236
|
+
index,
|
|
30237
|
+
node: cellNode,
|
|
30238
|
+
relativePos: rowOffset + 1 + cellOffset
|
|
30239
|
+
});
|
|
30240
|
+
});
|
|
30241
|
+
rows.push({ node: rowNode, cells });
|
|
30242
|
+
});
|
|
30243
|
+
return rows;
|
|
30244
|
+
}
|
|
30245
|
+
function safeFindCell2(map, relativePos) {
|
|
30246
|
+
try {
|
|
30247
|
+
return map.findCell(relativePos);
|
|
30248
|
+
} catch {
|
|
30249
|
+
return null;
|
|
30250
|
+
}
|
|
30251
|
+
}
|
|
30252
|
+
function getCellText(cellNode) {
|
|
30253
|
+
return cellNode.textBetween(0, cellNode.content.size, "\n").trim();
|
|
30254
|
+
}
|
|
30255
|
+
function createCellDisplayContent(cellNode, displayValue) {
|
|
30256
|
+
const paragraphType = cellNode.type.schema.nodes.paragraph;
|
|
30257
|
+
if (!paragraphType || !displayValue) {
|
|
30258
|
+
return paragraphType ? [paragraphType.create()] : cellNode.content;
|
|
30259
|
+
}
|
|
30260
|
+
return [paragraphType.create(null, cellNode.type.schema.text(displayValue))];
|
|
30261
|
+
}
|
|
30262
|
+
function buildTableValueGetter(tableNode) {
|
|
30263
|
+
const map = TableMap2.get(tableNode);
|
|
30264
|
+
const values = /* @__PURE__ */ new Map();
|
|
30265
|
+
for (const rowInfo of getTableRows2(tableNode)) {
|
|
30266
|
+
for (const entry of rowInfo.cells) {
|
|
30267
|
+
const rect = safeFindCell2(map, entry.relativePos);
|
|
30268
|
+
if (!rect) continue;
|
|
30269
|
+
const label = `${indexToColumnName(rect.left)}${rect.top + 1}`;
|
|
30270
|
+
const computedValue = entry.node.attrs.computedValue;
|
|
30271
|
+
values.set(label, typeof computedValue === "string" && computedValue.trim() ? computedValue : getCellText(entry.node));
|
|
30272
|
+
}
|
|
30273
|
+
}
|
|
30274
|
+
return (label) => values.get(label.toUpperCase());
|
|
30275
|
+
}
|
|
30276
|
+
function buildTableValueMap(tableNode) {
|
|
30277
|
+
const map = TableMap2.get(tableNode);
|
|
30278
|
+
const values = /* @__PURE__ */ new Map();
|
|
30279
|
+
for (const rowInfo of getTableRows2(tableNode)) {
|
|
30280
|
+
for (const entry of rowInfo.cells) {
|
|
30281
|
+
const rect = safeFindCell2(map, entry.relativePos);
|
|
30282
|
+
if (!rect) continue;
|
|
30283
|
+
const label = `${indexToColumnName(rect.left)}${rect.top + 1}`;
|
|
30284
|
+
const computedValue = entry.node.attrs.computedValue;
|
|
30285
|
+
values.set(label, typeof computedValue === "string" && computedValue.trim() ? computedValue : getCellText(entry.node));
|
|
30286
|
+
}
|
|
30287
|
+
}
|
|
30288
|
+
return values;
|
|
30289
|
+
}
|
|
30290
|
+
function getFormulaComputedValue(formula, tableNode) {
|
|
30291
|
+
const result = evaluateBasicTableFormula(formula, buildTableValueGetter(tableNode));
|
|
30292
|
+
return result.error ? `#${result.error.toUpperCase()}` : String(result.value);
|
|
30293
|
+
}
|
|
30294
|
+
function normalizeFormulaInput(formula) {
|
|
30295
|
+
const trimmed = formula.trim();
|
|
30296
|
+
if (!trimmed) return "";
|
|
30297
|
+
return trimmed.startsWith("=") ? trimmed : `=${trimmed}`;
|
|
30298
|
+
}
|
|
30299
|
+
function setSelectedTableCellFormula(editor, formula) {
|
|
30300
|
+
const normalized = normalizeFormulaInput(formula);
|
|
30301
|
+
const { state, view } = editor;
|
|
30302
|
+
if (!normalized) {
|
|
30303
|
+
const clearedFormula = setCellAttr("formula", null)(state, view.dispatch.bind(view));
|
|
30304
|
+
const clearedValue = setCellAttr("computedValue", null)(editor.state, view.dispatch.bind(view));
|
|
30305
|
+
if (clearedFormula || clearedValue) {
|
|
30306
|
+
view.focus();
|
|
30307
|
+
dispatchTableLayoutChange(editor);
|
|
30308
|
+
return true;
|
|
30309
|
+
}
|
|
30310
|
+
return false;
|
|
30311
|
+
}
|
|
30312
|
+
const rect = selectedRect2(state);
|
|
30313
|
+
const computedValue = getFormulaComputedValue(normalized, rect.table);
|
|
30314
|
+
const appliedFormula = setCellAttr("formula", normalized)(state, view.dispatch.bind(view));
|
|
30315
|
+
const appliedValue = setCellAttr("computedValue", computedValue)(editor.state, view.dispatch.bind(view));
|
|
30316
|
+
if (appliedFormula || appliedValue) {
|
|
30317
|
+
view.focus();
|
|
30318
|
+
dispatchTableLayoutChange(editor);
|
|
30319
|
+
return true;
|
|
30320
|
+
}
|
|
30321
|
+
return false;
|
|
30322
|
+
}
|
|
30323
|
+
function clearSelectedTableCellFormula(editor) {
|
|
30324
|
+
return setSelectedTableCellFormula(editor, "");
|
|
30325
|
+
}
|
|
30326
|
+
function promoteFormulaTextInTableNode(tableNode) {
|
|
30327
|
+
let changed = false;
|
|
30328
|
+
const rows = getTableRows2(tableNode).map((rowInfo) => {
|
|
30329
|
+
const cells = collectChildren2(rowInfo.node);
|
|
30330
|
+
for (const entry of rowInfo.cells) {
|
|
30331
|
+
const text = getCellText(entry.node);
|
|
30332
|
+
const formula = text.startsWith("=") ? normalizeFormulaInput(text) : "";
|
|
30333
|
+
if (!formula || entry.node.attrs.formula === formula) continue;
|
|
30334
|
+
cells[entry.index] = entry.node.type.create(
|
|
30335
|
+
{
|
|
30336
|
+
...entry.node.attrs,
|
|
30337
|
+
formula,
|
|
30338
|
+
computedValue: null
|
|
30339
|
+
},
|
|
30340
|
+
entry.node.content,
|
|
30341
|
+
entry.node.marks
|
|
30342
|
+
);
|
|
30343
|
+
changed = true;
|
|
30344
|
+
}
|
|
30345
|
+
return rowInfo.node.type.create(rowInfo.node.attrs, cells);
|
|
30346
|
+
});
|
|
30347
|
+
return {
|
|
30348
|
+
tableNode: changed ? tableNode.type.create(tableNode.attrs, rows) : tableNode,
|
|
30349
|
+
changed
|
|
30350
|
+
};
|
|
30351
|
+
}
|
|
30352
|
+
function recalculateTableNode(tableNode) {
|
|
30353
|
+
const promoted = promoteFormulaTextInTableNode(tableNode);
|
|
30354
|
+
tableNode = promoted.tableNode;
|
|
30355
|
+
const map = TableMap2.get(tableNode);
|
|
30356
|
+
const values = buildTableValueMap(tableNode);
|
|
30357
|
+
const formulaEntries = /* @__PURE__ */ new Map();
|
|
30358
|
+
let changed = false;
|
|
30359
|
+
const rowInfos = getTableRows2(tableNode);
|
|
30360
|
+
for (const [rowIndex, rowInfo] of rowInfos.entries()) {
|
|
30361
|
+
for (const entry of rowInfo.cells) {
|
|
30362
|
+
const formula = typeof entry.node.attrs.formula === "string" ? entry.node.attrs.formula.trim() : "";
|
|
30363
|
+
if (!formula) continue;
|
|
30364
|
+
const rectForCell = safeFindCell2(map, entry.relativePos);
|
|
30365
|
+
if (!rectForCell) continue;
|
|
30366
|
+
const label = `${indexToColumnName(rectForCell.left)}${rectForCell.top + 1}`;
|
|
30367
|
+
formulaEntries.set(label, {
|
|
30368
|
+
rowIndex,
|
|
30369
|
+
cellIndex: entry.index,
|
|
30370
|
+
node: entry.node,
|
|
30371
|
+
formula
|
|
30372
|
+
});
|
|
30373
|
+
}
|
|
30374
|
+
}
|
|
30375
|
+
const graph = buildTableFormulaDependencyGraph(
|
|
30376
|
+
Array.from(formulaEntries, ([label, entry]) => ({
|
|
30377
|
+
label,
|
|
30378
|
+
formula: entry.formula
|
|
30379
|
+
}))
|
|
30380
|
+
);
|
|
30381
|
+
const { order, circular } = getTableFormulaRecalculationOrder(graph);
|
|
30382
|
+
const computedValues = /* @__PURE__ */ new Map();
|
|
30383
|
+
const getCellValue = (label) => values.get(label.toUpperCase());
|
|
30384
|
+
for (const label of circular) {
|
|
30385
|
+
computedValues.set(label, formatFormulaError("circular-reference"));
|
|
30386
|
+
values.set(label, formatFormulaError("circular-reference"));
|
|
30387
|
+
}
|
|
30388
|
+
for (const label of order) {
|
|
30389
|
+
const entry = formulaEntries.get(label);
|
|
30390
|
+
if (!entry) continue;
|
|
30391
|
+
const result = evaluateBasicTableFormula(entry.formula, getCellValue);
|
|
30392
|
+
const computedValue = result.error ? formatFormulaError(result.error) : String(result.value);
|
|
30393
|
+
computedValues.set(label, computedValue);
|
|
30394
|
+
values.set(label, computedValue);
|
|
30395
|
+
}
|
|
30396
|
+
const rows = rowInfos.map((rowInfo) => {
|
|
30397
|
+
const cells = collectChildren2(rowInfo.node);
|
|
30398
|
+
for (const entry of rowInfo.cells) {
|
|
30399
|
+
const rectForCell = safeFindCell2(map, entry.relativePos);
|
|
30400
|
+
if (!rectForCell) continue;
|
|
30401
|
+
const label = `${indexToColumnName(rectForCell.left)}${rectForCell.top + 1}`;
|
|
30402
|
+
const computedValue = computedValues.get(label);
|
|
30403
|
+
if (computedValue == null) continue;
|
|
30404
|
+
const contentMatchesComputedValue = getCellText(entry.node) === computedValue;
|
|
30405
|
+
if (entry.node.attrs.computedValue === computedValue && contentMatchesComputedValue) continue;
|
|
30406
|
+
cells[entry.index] = entry.node.type.create(
|
|
30407
|
+
{
|
|
30408
|
+
...entry.node.attrs,
|
|
30409
|
+
computedValue
|
|
30410
|
+
},
|
|
30411
|
+
createCellDisplayContent(entry.node, computedValue),
|
|
30412
|
+
entry.node.marks
|
|
30413
|
+
);
|
|
30414
|
+
changed = true;
|
|
30415
|
+
}
|
|
30416
|
+
return rowInfo.node.type.create(rowInfo.node.attrs, cells);
|
|
30417
|
+
});
|
|
30418
|
+
if (!changed) return promoted.changed ? tableNode : null;
|
|
30419
|
+
return tableNode.type.create(tableNode.attrs, rows);
|
|
30420
|
+
}
|
|
30421
|
+
function recalculateSelectedTable(editor) {
|
|
30422
|
+
const rect = selectedRect2(editor.state);
|
|
30423
|
+
const tableNode = rect.table;
|
|
30424
|
+
const nextTable = recalculateTableNode(tableNode);
|
|
30425
|
+
if (!nextTable) return false;
|
|
30426
|
+
editor.view.dispatch(
|
|
30427
|
+
editor.state.tr.replaceWith(rect.tableStart - 1, rect.tableStart - 1 + tableNode.nodeSize, nextTable).setMeta(UEDITOR_TABLE_FORMULA_RECALCULATE_META, true)
|
|
30428
|
+
);
|
|
30429
|
+
dispatchTableLayoutChange(editor);
|
|
30430
|
+
return true;
|
|
30431
|
+
}
|
|
30432
|
+
function recalculateAllTableFormulas(editor) {
|
|
30433
|
+
const replacements = [];
|
|
30434
|
+
editor.state.doc.descendants((node, pos) => {
|
|
30435
|
+
if (node.type.name !== "table") return true;
|
|
30436
|
+
const nextTable = recalculateTableNode(node);
|
|
30437
|
+
if (nextTable) {
|
|
30438
|
+
replacements.push({
|
|
30439
|
+
from: pos,
|
|
30440
|
+
to: pos + node.nodeSize,
|
|
30441
|
+
node: nextTable
|
|
30442
|
+
});
|
|
30443
|
+
}
|
|
30444
|
+
return false;
|
|
30445
|
+
});
|
|
30446
|
+
if (replacements.length === 0) return false;
|
|
30447
|
+
let tr = editor.state.tr;
|
|
30448
|
+
for (const replacement of replacements.reverse()) {
|
|
30449
|
+
tr = tr.replaceWith(replacement.from, replacement.to, replacement.node);
|
|
30450
|
+
}
|
|
30451
|
+
editor.view.dispatch(tr.setMeta(UEDITOR_TABLE_FORMULA_RECALCULATE_META, true));
|
|
30452
|
+
dispatchTableLayoutChange(editor);
|
|
30453
|
+
return true;
|
|
30454
|
+
}
|
|
30455
|
+
|
|
30456
|
+
// src/components/UEditor/menus.tsx
|
|
29705
30457
|
import { Fragment as Fragment29, jsx as jsx86, jsxs as jsxs72 } from "react/jsx-runtime";
|
|
29706
30458
|
function applyTableCellBackground(editor, color) {
|
|
29707
30459
|
const value = color || null;
|
|
29708
30460
|
const { state, view } = editor;
|
|
29709
|
-
const applied =
|
|
30461
|
+
const applied = setCellAttr2("backgroundColor", value)(state, view.dispatch.bind(view));
|
|
29710
30462
|
if (applied) {
|
|
29711
30463
|
view.focus();
|
|
29712
30464
|
return;
|
|
@@ -29732,6 +30484,8 @@ var BubbleMenuContent = ({
|
|
|
29732
30484
|
setShowLinkInput(initialShowLinkInput);
|
|
29733
30485
|
}, [initialShowLinkInput]);
|
|
29734
30486
|
const [showTypographyPanel, setShowTypographyPanel] = useState48(false);
|
|
30487
|
+
const [showFormulaPanel, setShowFormulaPanel] = useState48(false);
|
|
30488
|
+
const [formulaDraft, setFormulaDraft] = useState48("");
|
|
29735
30489
|
const [showFontSizeOptions, setShowFontSizeOptions] = useState48(false);
|
|
29736
30490
|
const [fontSizeDraft, setFontSizeDraft] = useState48("");
|
|
29737
30491
|
const isImageSelected = editor.isActive("image");
|
|
@@ -29742,6 +30496,7 @@ var BubbleMenuContent = ({
|
|
|
29742
30496
|
const currentTextColor = normalizeStyleValue(textStyleAttrs.color) || "inherit";
|
|
29743
30497
|
const currentHighlightColor = normalizeStyleValue(editor.getAttributes("highlight").color) || "";
|
|
29744
30498
|
const currentCellBgColor = normalizeStyleValue(editor.getAttributes("tableCell").backgroundColor || editor.getAttributes("tableHeader").backgroundColor) || "";
|
|
30499
|
+
const currentCellFormula = normalizeStyleValue(editor.getAttributes("tableCell").formula || editor.getAttributes("tableHeader").formula) || "";
|
|
29745
30500
|
const isInTable2 = isSelectionInTable(editor.state);
|
|
29746
30501
|
const canMergeCells = isInTable2 && editor.can().mergeCells();
|
|
29747
30502
|
const canSplitCell = isInTable2 && editor.can().splitCell();
|
|
@@ -29758,6 +30513,9 @@ var BubbleMenuContent = ({
|
|
|
29758
30513
|
useEffect36(() => {
|
|
29759
30514
|
setFontSizeDraft(currentFontSize.replace(/px$/i, ""));
|
|
29760
30515
|
}, [currentFontSize]);
|
|
30516
|
+
useEffect36(() => {
|
|
30517
|
+
setFormulaDraft(currentCellFormula);
|
|
30518
|
+
}, [currentCellFormula]);
|
|
29761
30519
|
const applyFontSizeDraft = () => {
|
|
29762
30520
|
const normalized = fontSizeDraft.trim();
|
|
29763
30521
|
if (!normalized) {
|
|
@@ -29960,6 +30718,82 @@ var BubbleMenuContent = ({
|
|
|
29960
30718
|
)
|
|
29961
30719
|
] });
|
|
29962
30720
|
}
|
|
30721
|
+
if (showFormulaPanel && isInTable2) {
|
|
30722
|
+
return /* @__PURE__ */ jsxs72("div", { className: "w-72 p-2", children: [
|
|
30723
|
+
/* @__PURE__ */ jsxs72("div", { className: "mb-2 flex items-center justify-between gap-2", children: [
|
|
30724
|
+
/* @__PURE__ */ jsx86("span", { className: "px-1 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: t("tableMenu.formula") || "Formula" }),
|
|
30725
|
+
/* @__PURE__ */ jsx86(
|
|
30726
|
+
"button",
|
|
30727
|
+
{
|
|
30728
|
+
type: "button",
|
|
30729
|
+
onClick: () => {
|
|
30730
|
+
setShowFormulaPanel(false);
|
|
30731
|
+
onKeepOpenChange?.(false);
|
|
30732
|
+
},
|
|
30733
|
+
className: "rounded-md px-2 py-1 text-xs text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
30734
|
+
children: t("colors.done")
|
|
30735
|
+
}
|
|
30736
|
+
)
|
|
30737
|
+
] }),
|
|
30738
|
+
/* @__PURE__ */ jsx86("div", { className: "flex h-9 items-center overflow-hidden rounded-md border border-border/60 bg-muted/40", children: /* @__PURE__ */ jsx86(
|
|
30739
|
+
"input",
|
|
30740
|
+
{
|
|
30741
|
+
value: formulaDraft,
|
|
30742
|
+
onChange: (event) => setFormulaDraft(event.target.value),
|
|
30743
|
+
onMouseDown: (event) => event.stopPropagation(),
|
|
30744
|
+
onClick: (event) => event.stopPropagation(),
|
|
30745
|
+
onKeyDown: (event) => {
|
|
30746
|
+
event.stopPropagation();
|
|
30747
|
+
if (event.key === "Enter") {
|
|
30748
|
+
event.preventDefault();
|
|
30749
|
+
setSelectedTableCellFormula(editor, formulaDraft);
|
|
30750
|
+
setShowFormulaPanel(false);
|
|
30751
|
+
onKeepOpenChange?.(false);
|
|
30752
|
+
}
|
|
30753
|
+
},
|
|
30754
|
+
"aria-label": t("tableMenu.formula") || "Formula",
|
|
30755
|
+
placeholder: "=SUM(A1:A3)",
|
|
30756
|
+
className: "h-full min-w-0 flex-1 bg-transparent px-2 text-sm font-medium text-foreground outline-none"
|
|
30757
|
+
}
|
|
30758
|
+
) }),
|
|
30759
|
+
/* @__PURE__ */ jsxs72("div", { className: "mt-2 grid grid-cols-3 gap-1", children: [
|
|
30760
|
+
/* @__PURE__ */ jsx86(
|
|
30761
|
+
"button",
|
|
30762
|
+
{
|
|
30763
|
+
type: "button",
|
|
30764
|
+
onClick: () => {
|
|
30765
|
+
setSelectedTableCellFormula(editor, formulaDraft);
|
|
30766
|
+
setShowFormulaPanel(false);
|
|
30767
|
+
onKeepOpenChange?.(false);
|
|
30768
|
+
},
|
|
30769
|
+
className: "h-8 rounded-md bg-primary/10 text-xs font-semibold text-primary transition-colors hover:bg-primary/15",
|
|
30770
|
+
children: t("tableMenu.apply") || "Apply"
|
|
30771
|
+
}
|
|
30772
|
+
),
|
|
30773
|
+
/* @__PURE__ */ jsx86(
|
|
30774
|
+
"button",
|
|
30775
|
+
{
|
|
30776
|
+
type: "button",
|
|
30777
|
+
onClick: () => {
|
|
30778
|
+
clearSelectedTableCellFormula(editor);
|
|
30779
|
+
setFormulaDraft("");
|
|
30780
|
+
},
|
|
30781
|
+
className: "h-8 rounded-md bg-muted/40 text-xs font-semibold text-foreground transition-colors hover:bg-muted",
|
|
30782
|
+
children: t("tableMenu.clear") || "Clear"
|
|
30783
|
+
}
|
|
30784
|
+
),
|
|
30785
|
+
/* @__PURE__ */ jsx86(
|
|
30786
|
+
"button",
|
|
30787
|
+
{
|
|
30788
|
+
type: "button",
|
|
30789
|
+
onClick: () => recalculateSelectedTable(editor),
|
|
30790
|
+
className: "h-8 rounded-md bg-muted/40 text-xs font-semibold text-foreground transition-colors hover:bg-muted",
|
|
30791
|
+
children: t("tableMenu.recalculate") || "Recalc"
|
|
30792
|
+
}
|
|
30793
|
+
)
|
|
30794
|
+
] })
|
|
30795
|
+
] });
|
|
30796
|
+
}
|
|
29963
30797
|
if (showTypographyPanel) {
|
|
29964
30798
|
return /* @__PURE__ */ jsxs72("div", { className: "w-72 p-2", children: [
|
|
29965
30799
|
/* @__PURE__ */ jsxs72("div", { className: "mb-2 flex items-center justify-between gap-2", children: [
|
|
@@ -30173,6 +31007,21 @@ var BubbleMenuContent = ({
|
|
|
30173
31007
|
)
|
|
30174
31008
|
}
|
|
30175
31009
|
),
|
|
31010
|
+
/* @__PURE__ */ jsx86(
|
|
31011
|
+
ToolbarButton,
|
|
31012
|
+
{
|
|
31013
|
+
onMouseDown: () => {
|
|
31014
|
+
onKeepOpenChange?.(true);
|
|
31015
|
+
},
|
|
31016
|
+
onClick: () => {
|
|
31017
|
+
setFormulaDraft(currentCellFormula);
|
|
31018
|
+
setShowFormulaPanel(true);
|
|
31019
|
+
},
|
|
31020
|
+
active: Boolean(currentCellFormula),
|
|
31021
|
+
title: t("tableMenu.formula") || "Formula",
|
|
31022
|
+
children: /* @__PURE__ */ jsx86(Sigma, { className: "w-4 h-4" })
|
|
31023
|
+
}
|
|
31024
|
+
),
|
|
30176
31025
|
/* @__PURE__ */ jsx86(
|
|
30177
31026
|
ToolbarButton,
|
|
30178
31027
|
{
|
|
@@ -34014,7 +34863,7 @@ if (typeof WeakMap != "undefined") {
|
|
|
34014
34863
|
return cache[cachePos++] = value;
|
|
34015
34864
|
};
|
|
34016
34865
|
}
|
|
34017
|
-
var
|
|
34866
|
+
var TableMap3 = class {
|
|
34018
34867
|
constructor(width, height, map, problems) {
|
|
34019
34868
|
this.width = width;
|
|
34020
34869
|
this.height = height;
|
|
@@ -34151,7 +35000,7 @@ function computeMap(table) {
|
|
|
34151
35000
|
pos++;
|
|
34152
35001
|
}
|
|
34153
35002
|
if (width === 0 || height === 0) (problems || (problems = [])).push({ type: "zero_sized" });
|
|
34154
|
-
const tableMap = new
|
|
35003
|
+
const tableMap = new TableMap3(width, height, map, problems);
|
|
34155
35004
|
let badWidths = false;
|
|
34156
35005
|
for (let i = 0; !badWidths && i < colWidths.length; i += 2) if (colWidths[i] != null && colWidths[i + 1] < height) badWidths = true;
|
|
34157
35006
|
if (badWidths) findBadColWidths(tableMap, colWidths, table);
|
|
@@ -34255,7 +35104,7 @@ function inSameTable($cellA, $cellB) {
|
|
|
34255
35104
|
}
|
|
34256
35105
|
function nextCell($pos, axis, dir) {
|
|
34257
35106
|
const table = $pos.node(-1);
|
|
34258
|
-
const map =
|
|
35107
|
+
const map = TableMap3.get(table);
|
|
34259
35108
|
const tableStart = $pos.start(-1);
|
|
34260
35109
|
const moved = map.nextCell($pos.pos - tableStart, axis, dir);
|
|
34261
35110
|
return moved == null ? null : $pos.node(0).resolve(tableStart + moved);
|
|
@@ -34275,7 +35124,7 @@ function removeColSpan(attrs, pos, n = 1) {
|
|
|
34275
35124
|
var CellSelection = class CellSelection2 extends Selection {
|
|
34276
35125
|
constructor($anchorCell, $headCell = $anchorCell) {
|
|
34277
35126
|
const table = $anchorCell.node(-1);
|
|
34278
|
-
const map =
|
|
35127
|
+
const map = TableMap3.get(table);
|
|
34279
35128
|
const tableStart = $anchorCell.start(-1);
|
|
34280
35129
|
const rect = map.rectBetween($anchorCell.pos - tableStart, $headCell.pos - tableStart);
|
|
34281
35130
|
const doc = $anchorCell.node(0);
|
|
@@ -34304,7 +35153,7 @@ var CellSelection = class CellSelection2 extends Selection {
|
|
|
34304
35153
|
}
|
|
34305
35154
|
content() {
|
|
34306
35155
|
const table = this.$anchorCell.node(-1);
|
|
34307
|
-
const map =
|
|
35156
|
+
const map = TableMap3.get(table);
|
|
34308
35157
|
const tableStart = this.$anchorCell.start(-1);
|
|
34309
35158
|
const rect = map.rectBetween(this.$anchorCell.pos - tableStart, this.$headCell.pos - tableStart);
|
|
34310
35159
|
const seen = {};
|
|
@@ -34358,7 +35207,7 @@ var CellSelection = class CellSelection2 extends Selection {
|
|
|
34358
35207
|
}
|
|
34359
35208
|
forEachCell(f) {
|
|
34360
35209
|
const table = this.$anchorCell.node(-1);
|
|
34361
|
-
const map =
|
|
35210
|
+
const map = TableMap3.get(table);
|
|
34362
35211
|
const tableStart = this.$anchorCell.start(-1);
|
|
34363
35212
|
const cells = map.cellsInRect(map.rectBetween(this.$anchorCell.pos - tableStart, this.$headCell.pos - tableStart));
|
|
34364
35213
|
for (let i = 0; i < cells.length; i++) f(table.nodeAt(cells[i]), tableStart + cells[i]);
|
|
@@ -34373,7 +35222,7 @@ var CellSelection = class CellSelection2 extends Selection {
|
|
|
34373
35222
|
}
|
|
34374
35223
|
static colSelection($anchorCell, $headCell = $anchorCell) {
|
|
34375
35224
|
const table = $anchorCell.node(-1);
|
|
34376
|
-
const map =
|
|
35225
|
+
const map = TableMap3.get(table);
|
|
34377
35226
|
const tableStart = $anchorCell.start(-1);
|
|
34378
35227
|
const anchorRect = map.findCell($anchorCell.pos - tableStart);
|
|
34379
35228
|
const headRect = map.findCell($headCell.pos - tableStart);
|
|
@@ -34389,7 +35238,7 @@ var CellSelection = class CellSelection2 extends Selection {
|
|
|
34389
35238
|
}
|
|
34390
35239
|
isRowSelection() {
|
|
34391
35240
|
const table = this.$anchorCell.node(-1);
|
|
34392
|
-
const map =
|
|
35241
|
+
const map = TableMap3.get(table);
|
|
34393
35242
|
const tableStart = this.$anchorCell.start(-1);
|
|
34394
35243
|
const anchorLeft = map.colCount(this.$anchorCell.pos - tableStart);
|
|
34395
35244
|
const headLeft = map.colCount(this.$headCell.pos - tableStart);
|
|
@@ -34403,7 +35252,7 @@ var CellSelection = class CellSelection2 extends Selection {
|
|
|
34403
35252
|
}
|
|
34404
35253
|
static rowSelection($anchorCell, $headCell = $anchorCell) {
|
|
34405
35254
|
const table = $anchorCell.node(-1);
|
|
34406
|
-
const map =
|
|
35255
|
+
const map = TableMap3.get(table);
|
|
34407
35256
|
const tableStart = $anchorCell.start(-1);
|
|
34408
35257
|
const anchorRect = map.findCell($anchorCell.pos - tableStart);
|
|
34409
35258
|
const headRect = map.findCell($headCell.pos - tableStart);
|
|
@@ -34452,7 +35301,7 @@ var CellBookmark = class CellBookmark2 {
|
|
|
34452
35301
|
};
|
|
34453
35302
|
var fixTablesKey = new PluginKey4("fix-tables");
|
|
34454
35303
|
function convertTableNodeToArrayOfRows(tableNode) {
|
|
34455
|
-
const map =
|
|
35304
|
+
const map = TableMap3.get(tableNode);
|
|
34456
35305
|
const rows = [];
|
|
34457
35306
|
const rowCount = map.height;
|
|
34458
35307
|
const colCount$1 = map.width;
|
|
@@ -34483,7 +35332,7 @@ function convertTableNodeToArrayOfRows(tableNode) {
|
|
|
34483
35332
|
}
|
|
34484
35333
|
function convertArrayOfRowsToTableNode(tableNode, arrayOfNodes) {
|
|
34485
35334
|
const newRows = [];
|
|
34486
|
-
const map =
|
|
35335
|
+
const map = TableMap3.get(tableNode);
|
|
34487
35336
|
const rowCount = map.height;
|
|
34488
35337
|
const colCount$1 = map.width;
|
|
34489
35338
|
for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
|
|
@@ -34532,7 +35381,7 @@ function findParentNode(predicate, $pos) {
|
|
|
34532
35381
|
function getCellsInColumn(columnIndex, selection) {
|
|
34533
35382
|
const table = findTable(selection.$from);
|
|
34534
35383
|
if (!table) return;
|
|
34535
|
-
const map =
|
|
35384
|
+
const map = TableMap3.get(table.node);
|
|
34536
35385
|
if (columnIndex < 0 || columnIndex > map.width - 1) return;
|
|
34537
35386
|
return map.cellsInRect({
|
|
34538
35387
|
left: columnIndex,
|
|
@@ -34553,7 +35402,7 @@ function getCellsInColumn(columnIndex, selection) {
|
|
|
34553
35402
|
function getCellsInRow(rowIndex, selection) {
|
|
34554
35403
|
const table = findTable(selection.$from);
|
|
34555
35404
|
if (!table) return;
|
|
34556
|
-
const map =
|
|
35405
|
+
const map = TableMap3.get(table.node);
|
|
34557
35406
|
if (rowIndex < 0 || rowIndex > map.height - 1) return;
|
|
34558
35407
|
return map.cellsInRect({
|
|
34559
35408
|
left: 0,
|
|
@@ -34682,7 +35531,7 @@ function moveColumn(moveColParams) {
|
|
|
34682
35531
|
const newTable = moveTableColumn$1(table.node, indexesOriginColumn, indexesTargetColumn, 0);
|
|
34683
35532
|
tr.replaceWith(table.pos, table.pos + table.node.nodeSize, newTable);
|
|
34684
35533
|
if (!select) return true;
|
|
34685
|
-
const map =
|
|
35534
|
+
const map = TableMap3.get(newTable);
|
|
34686
35535
|
const start = table.start;
|
|
34687
35536
|
const index = targetIndex;
|
|
34688
35537
|
const lastCell = map.positionAt(map.height - 1, index, newTable);
|
|
@@ -34710,7 +35559,7 @@ function moveRow(moveRowParams) {
|
|
|
34710
35559
|
const newTable = moveTableRow$1(table.node, indexesOriginRow, indexesTargetRow, 0);
|
|
34711
35560
|
tr.replaceWith(table.pos, table.pos + table.node.nodeSize, newTable);
|
|
34712
35561
|
if (!select) return true;
|
|
34713
|
-
const map =
|
|
35562
|
+
const map = TableMap3.get(newTable);
|
|
34714
35563
|
const start = table.start;
|
|
34715
35564
|
const index = targetIndex;
|
|
34716
35565
|
const lastCell = map.positionAt(index, map.width - 1, newTable);
|
|
@@ -34725,12 +35574,12 @@ function moveTableRow$1(table, indexesOrigin, indexesTarget, direction) {
|
|
|
34725
35574
|
rows = moveRowInArrayOfRows(rows, indexesOrigin, indexesTarget, direction);
|
|
34726
35575
|
return convertArrayOfRowsToTableNode(table, rows);
|
|
34727
35576
|
}
|
|
34728
|
-
function
|
|
35577
|
+
function selectedRect3(state) {
|
|
34729
35578
|
const sel = state.selection;
|
|
34730
35579
|
const $pos = selectionCell(state);
|
|
34731
35580
|
const table = $pos.node(-1);
|
|
34732
35581
|
const tableStart = $pos.start(-1);
|
|
34733
|
-
const map =
|
|
35582
|
+
const map = TableMap3.get(table);
|
|
34734
35583
|
return {
|
|
34735
35584
|
...sel instanceof CellSelection ? map.rectBetween(sel.$anchorCell.pos - tableStart, sel.$headCell.pos - tableStart) : map.findCell($pos.pos - tableStart),
|
|
34736
35585
|
tableStart,
|
|
@@ -34743,7 +35592,7 @@ function deprecated_toggleHeader(type) {
|
|
|
34743
35592
|
if (!isInTable(state)) return false;
|
|
34744
35593
|
if (dispatch) {
|
|
34745
35594
|
const types = tableNodeTypes(state.schema);
|
|
34746
|
-
const rect =
|
|
35595
|
+
const rect = selectedRect3(state), tr = state.tr;
|
|
34747
35596
|
const cells = rect.map.cellsInRect(type == "column" ? {
|
|
34748
35597
|
left: rect.left,
|
|
34749
35598
|
top: 0,
|
|
@@ -34783,7 +35632,7 @@ function toggleHeader(type, options) {
|
|
|
34783
35632
|
if (!isInTable(state)) return false;
|
|
34784
35633
|
if (dispatch) {
|
|
34785
35634
|
const types = tableNodeTypes(state.schema);
|
|
34786
|
-
const rect =
|
|
35635
|
+
const rect = selectedRect3(state), tr = state.tr;
|
|
34787
35636
|
const isHeaderRowEnabled = isHeaderEnabledByType("row", rect, types);
|
|
34788
35637
|
const isHeaderColumnEnabled = isHeaderEnabledByType("column", rect, types);
|
|
34789
35638
|
const selectionStartsAt = (type === "column" ? isHeaderRowEnabled : type === "row" ? isHeaderColumnEnabled : false) ? 1 : 0;
|
|
@@ -34944,6 +35793,262 @@ import {
|
|
|
34944
35793
|
Trash2 as Trash24
|
|
34945
35794
|
} from "lucide-react";
|
|
34946
35795
|
|
|
35796
|
+
// src/components/UEditor/table-layout-model.ts
|
|
35797
|
+
var FALLBACK_TABLE_ROW_HEIGHT = 44;
|
|
35798
|
+
var FALLBACK_TABLE_COLUMN_WIDTH = 160;
|
|
35799
|
+
function getVisibleTableBounds(layout) {
|
|
35800
|
+
const left = Math.max(layout.tableLeft, layout.wrapperLeft);
|
|
35801
|
+
const top = Math.max(layout.tableTop, layout.wrapperTop);
|
|
35802
|
+
const right = Math.min(layout.tableLeft + layout.tableWidth, layout.wrapperLeft + layout.viewportWidth);
|
|
35803
|
+
const bottom = Math.min(layout.tableTop + layout.tableHeight, layout.wrapperTop + layout.viewportHeight);
|
|
35804
|
+
return {
|
|
35805
|
+
left,
|
|
35806
|
+
top,
|
|
35807
|
+
right,
|
|
35808
|
+
bottom,
|
|
35809
|
+
width: Math.max(0, right - left),
|
|
35810
|
+
height: Math.max(0, bottom - top)
|
|
35811
|
+
};
|
|
35812
|
+
}
|
|
35813
|
+
function metricOrFallback(value, fallback) {
|
|
35814
|
+
return Number.isFinite(value) && value > 0 ? value : fallback;
|
|
35815
|
+
}
|
|
35816
|
+
function parsePixelMetric(value) {
|
|
35817
|
+
if (!value) return null;
|
|
35818
|
+
const parsed = Number.parseFloat(value);
|
|
35819
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
35820
|
+
}
|
|
35821
|
+
function getPrimaryCell(table) {
|
|
35822
|
+
const cell = table.querySelector("th,td");
|
|
35823
|
+
return cell instanceof HTMLTableCellElement ? cell : null;
|
|
35824
|
+
}
|
|
35825
|
+
function getLastCell(table) {
|
|
35826
|
+
const lastRow = table.rows.item(table.rows.length - 1);
|
|
35827
|
+
if (!(lastRow instanceof HTMLTableRowElement)) return null;
|
|
35828
|
+
const cell = lastRow.cells.item(lastRow.cells.length - 1);
|
|
35829
|
+
return cell instanceof HTMLTableCellElement ? cell : null;
|
|
35830
|
+
}
|
|
35831
|
+
function getCellFromTarget(target) {
|
|
35832
|
+
const element = resolveEventElement(target);
|
|
35833
|
+
if (!element) return null;
|
|
35834
|
+
const directCell = element.closest("th,td");
|
|
35835
|
+
if (directCell instanceof HTMLTableCellElement) {
|
|
35836
|
+
return directCell;
|
|
35837
|
+
}
|
|
35838
|
+
const table = element.closest("table");
|
|
35839
|
+
if (table instanceof HTMLTableElement) {
|
|
35840
|
+
return getPrimaryCell(table);
|
|
35841
|
+
}
|
|
35842
|
+
return null;
|
|
35843
|
+
}
|
|
35844
|
+
function findTableInfo(editor, pos) {
|
|
35845
|
+
const $pos = editor.state.doc.resolve(pos);
|
|
35846
|
+
for (let depth = $pos.depth; depth > 0; depth -= 1) {
|
|
35847
|
+
const node = $pos.node(depth);
|
|
35848
|
+
if (node.type.name === "table") {
|
|
35849
|
+
return {
|
|
35850
|
+
node,
|
|
35851
|
+
pos: $pos.before(depth),
|
|
35852
|
+
start: $pos.start(depth)
|
|
35853
|
+
};
|
|
35854
|
+
}
|
|
35855
|
+
}
|
|
35856
|
+
return null;
|
|
35857
|
+
}
|
|
35858
|
+
function getCellRelativePosFromDomPos(map, tableStart, domPos) {
|
|
35859
|
+
const relativeDomPos = domPos - tableStart;
|
|
35860
|
+
const seen = /* @__PURE__ */ new Set();
|
|
35861
|
+
for (const relativeCellPos of map.map) {
|
|
35862
|
+
if (seen.has(relativeCellPos)) continue;
|
|
35863
|
+
seen.add(relativeCellPos);
|
|
35864
|
+
if (relativeDomPos === relativeCellPos || relativeDomPos === relativeCellPos + 1) {
|
|
35865
|
+
return relativeCellPos;
|
|
35866
|
+
}
|
|
35867
|
+
}
|
|
35868
|
+
return null;
|
|
35869
|
+
}
|
|
35870
|
+
function buildLogicalColumnMetrics({
|
|
35871
|
+
editor,
|
|
35872
|
+
surface,
|
|
35873
|
+
surfaceRect,
|
|
35874
|
+
tableElement,
|
|
35875
|
+
tableInfo,
|
|
35876
|
+
tableLeft,
|
|
35877
|
+
tableWidth
|
|
35878
|
+
}) {
|
|
35879
|
+
const map = TableMap3.get(tableInfo.node);
|
|
35880
|
+
const fallbackWidth = metricOrFallback(tableWidth / map.width, FALLBACK_TABLE_COLUMN_WIDTH);
|
|
35881
|
+
const firstRow = tableElement.rows.item(0);
|
|
35882
|
+
const visualColumns = [];
|
|
35883
|
+
if (firstRow) {
|
|
35884
|
+
for (const tableCell of Array.from(firstRow.cells)) {
|
|
35885
|
+
if (!(tableCell instanceof HTMLTableCellElement)) continue;
|
|
35886
|
+
const cellPos = editor.view.posAtDOM(tableCell, 0);
|
|
35887
|
+
const relativeCellPos = getCellRelativePosFromDomPos(map, tableInfo.start, cellPos);
|
|
35888
|
+
if (relativeCellPos == null) continue;
|
|
35889
|
+
const cellMapRect = map.findCell(relativeCellPos);
|
|
35890
|
+
const cellRect = tableCell.getBoundingClientRect();
|
|
35891
|
+
const cellStart = cellRect.width > 0 ? cellRect.left - surfaceRect.left + surface.scrollLeft : tableLeft + cellMapRect.left * fallbackWidth;
|
|
35892
|
+
const size = metricOrFallback(cellRect.width, fallbackWidth * Math.max(1, cellMapRect.right - cellMapRect.left));
|
|
35893
|
+
visualColumns.push({
|
|
35894
|
+
index: cellMapRect.left,
|
|
35895
|
+
cellPos: tableInfo.start + relativeCellPos,
|
|
35896
|
+
start: cellStart,
|
|
35897
|
+
size,
|
|
35898
|
+
center: cellStart + size / 2
|
|
35899
|
+
});
|
|
35900
|
+
}
|
|
35901
|
+
}
|
|
35902
|
+
if (visualColumns.length > 0) {
|
|
35903
|
+
return visualColumns.sort((a, b) => a.index - b.index);
|
|
35904
|
+
}
|
|
35905
|
+
const cols = Array.from(tableElement.querySelectorAll("colgroup > col"));
|
|
35906
|
+
const parsedWidths = cols.slice(0, map.width).map((col) => parsePixelMetric(col.style.width) ?? parsePixelMetric(col.getAttribute("width")));
|
|
35907
|
+
const hasCompleteColWidths = parsedWidths.length >= map.width && parsedWidths.every((width) => typeof width === "number");
|
|
35908
|
+
let cursor = tableLeft;
|
|
35909
|
+
return Array.from({ length: map.width }, (_, index) => {
|
|
35910
|
+
const size = hasCompleteColWidths ? parsedWidths[index] : fallbackWidth;
|
|
35911
|
+
const start = hasCompleteColWidths ? cursor : tableLeft + index * fallbackWidth;
|
|
35912
|
+
cursor += size;
|
|
35913
|
+
return {
|
|
35914
|
+
index,
|
|
35915
|
+
cellPos: tableInfo.start + map.positionAt(0, index, tableInfo.node),
|
|
35916
|
+
start,
|
|
35917
|
+
size,
|
|
35918
|
+
center: start + size / 2
|
|
35919
|
+
};
|
|
35920
|
+
});
|
|
35921
|
+
}
|
|
35922
|
+
function buildLogicalRowMetrics({
|
|
35923
|
+
editor,
|
|
35924
|
+
surface,
|
|
35925
|
+
surfaceRect,
|
|
35926
|
+
tableInfo,
|
|
35927
|
+
rows,
|
|
35928
|
+
tableTop,
|
|
35929
|
+
tableHeight,
|
|
35930
|
+
cornerCell
|
|
35931
|
+
}) {
|
|
35932
|
+
const map = TableMap3.get(tableInfo.node);
|
|
35933
|
+
const fallbackHeight = metricOrFallback(tableHeight / map.height, FALLBACK_TABLE_ROW_HEIGHT);
|
|
35934
|
+
const visualRows = [];
|
|
35935
|
+
const seenCellPositions = /* @__PURE__ */ new Set();
|
|
35936
|
+
for (let rowIndex = 0; rowIndex < map.height; rowIndex += 1) {
|
|
35937
|
+
const relativeCellPos = map.map[rowIndex * map.width];
|
|
35938
|
+
if (seenCellPositions.has(relativeCellPos)) continue;
|
|
35939
|
+
seenCellPositions.add(relativeCellPos);
|
|
35940
|
+
const cellMapRect = map.findCell(relativeCellPos);
|
|
35941
|
+
const cellDom = editor.view.nodeDOM(tableInfo.start + relativeCellPos);
|
|
35942
|
+
const tableCell = cellDom instanceof HTMLTableCellElement ? cellDom : null;
|
|
35943
|
+
if (tableCell) {
|
|
35944
|
+
const cellRect = tableCell.getBoundingClientRect();
|
|
35945
|
+
const start = cellRect.height > 0 ? cellRect.top - surfaceRect.top + surface.scrollTop : tableTop + cellMapRect.top * fallbackHeight;
|
|
35946
|
+
const size = metricOrFallback(cellRect.height, fallbackHeight * Math.max(1, cellMapRect.bottom - cellMapRect.top));
|
|
35947
|
+
visualRows.push({
|
|
35948
|
+
index: cellMapRect.top,
|
|
35949
|
+
cellPos: tableInfo.start + relativeCellPos,
|
|
35950
|
+
start,
|
|
35951
|
+
size,
|
|
35952
|
+
center: start + size / 2
|
|
35953
|
+
});
|
|
35954
|
+
}
|
|
35955
|
+
}
|
|
35956
|
+
if (visualRows.length > 0) {
|
|
35957
|
+
return visualRows.sort((a, b) => a.index - b.index);
|
|
35958
|
+
}
|
|
35959
|
+
return rows.map((tableRow, index) => {
|
|
35960
|
+
const rowRect = tableRow.getBoundingClientRect();
|
|
35961
|
+
const anchorCell = tableRow.cells.item(0) ?? cornerCell;
|
|
35962
|
+
const start = rowRect.height > 0 ? rowRect.top - surfaceRect.top + surface.scrollTop : tableTop + index * fallbackHeight;
|
|
35963
|
+
const size = metricOrFallback(rowRect.height, fallbackHeight);
|
|
35964
|
+
return {
|
|
35965
|
+
index,
|
|
35966
|
+
cellPos: editor.view.posAtDOM(anchorCell, 0),
|
|
35967
|
+
start,
|
|
35968
|
+
size,
|
|
35969
|
+
center: start + size / 2
|
|
35970
|
+
};
|
|
35971
|
+
});
|
|
35972
|
+
}
|
|
35973
|
+
function buildTableControlLayout(editor, surface, cell) {
|
|
35974
|
+
const row = cell.closest("tr");
|
|
35975
|
+
const table = cell.closest("table");
|
|
35976
|
+
if (!(row instanceof HTMLTableRowElement) || !(table instanceof HTMLTableElement)) {
|
|
35977
|
+
return null;
|
|
35978
|
+
}
|
|
35979
|
+
const rows = Array.from(table.rows).filter((item) => item instanceof HTMLTableRowElement);
|
|
35980
|
+
const cornerCell = getLastCell(table);
|
|
35981
|
+
const cellPos = editor.view.posAtDOM(cell, 0);
|
|
35982
|
+
const tableInfo = findTableInfo(editor, cellPos);
|
|
35983
|
+
if (rows.length === 0 || !tableInfo || !(cornerCell instanceof HTMLTableCellElement)) {
|
|
35984
|
+
return null;
|
|
35985
|
+
}
|
|
35986
|
+
const map = TableMap3.get(tableInfo.node);
|
|
35987
|
+
const surfaceRect = surface.getBoundingClientRect();
|
|
35988
|
+
const tableRect = table.getBoundingClientRect();
|
|
35989
|
+
const wrapperElement = table.closest(".tableWrapper");
|
|
35990
|
+
const wrapper = wrapperElement instanceof HTMLElement ? wrapperElement : null;
|
|
35991
|
+
const wrapperRect = wrapper?.getBoundingClientRect() ?? tableRect;
|
|
35992
|
+
const tableLeft = tableRect.left - surfaceRect.left + surface.scrollLeft;
|
|
35993
|
+
const tableTop = tableRect.top - surfaceRect.top + surface.scrollTop;
|
|
35994
|
+
const avgRowHeight = metricOrFallback(tableRect.height / rows.length, FALLBACK_TABLE_ROW_HEIGHT);
|
|
35995
|
+
const avgColumnWidth = metricOrFallback(tableRect.width / map.width, FALLBACK_TABLE_COLUMN_WIDTH);
|
|
35996
|
+
const tableWidth = metricOrFallback(tableRect.width, avgColumnWidth * map.width);
|
|
35997
|
+
const tableHeight = metricOrFallback(tableRect.height, avgRowHeight * rows.length);
|
|
35998
|
+
const wrapperLeft = wrapperRect.left - surfaceRect.left + surface.scrollLeft;
|
|
35999
|
+
const wrapperTop = wrapperRect.top - surfaceRect.top + surface.scrollTop;
|
|
36000
|
+
const wrapperWidth = metricOrFallback(wrapperRect.width, tableWidth);
|
|
36001
|
+
const wrapperHeight = metricOrFallback(wrapperRect.height, tableHeight);
|
|
36002
|
+
const viewportWidth = metricOrFallback(wrapper?.clientWidth ?? wrapperRect.width, tableWidth);
|
|
36003
|
+
const viewportHeight = metricOrFallback(wrapper?.clientHeight ?? wrapperRect.height, tableHeight);
|
|
36004
|
+
const verticalScrollbarWidth = Math.max(0, Math.round(wrapperWidth - viewportWidth));
|
|
36005
|
+
const horizontalScrollbarHeight = Math.max(0, Math.round(wrapperHeight - viewportHeight));
|
|
36006
|
+
const rowHandles = buildLogicalRowMetrics({
|
|
36007
|
+
editor,
|
|
36008
|
+
surface,
|
|
36009
|
+
surfaceRect,
|
|
36010
|
+
tableInfo,
|
|
36011
|
+
rows,
|
|
36012
|
+
tableTop,
|
|
36013
|
+
tableHeight,
|
|
36014
|
+
cornerCell
|
|
36015
|
+
});
|
|
36016
|
+
const columnHandles = buildLogicalColumnMetrics({
|
|
36017
|
+
editor,
|
|
36018
|
+
surface,
|
|
36019
|
+
surfaceRect,
|
|
36020
|
+
tableElement: table,
|
|
36021
|
+
tableInfo,
|
|
36022
|
+
tableLeft,
|
|
36023
|
+
tableWidth
|
|
36024
|
+
});
|
|
36025
|
+
const activeCellRelativePos = getCellRelativePosFromDomPos(map, tableInfo.start, cellPos);
|
|
36026
|
+
const activeCellRect = activeCellRelativePos != null ? map.findCell(activeCellRelativePos) : { left: cell.cellIndex, top: row.rowIndex };
|
|
36027
|
+
const normalizedCellPos = activeCellRelativePos != null ? tableInfo.start + activeCellRelativePos : cellPos;
|
|
36028
|
+
return {
|
|
36029
|
+
cellPos: normalizedCellPos,
|
|
36030
|
+
cornerCellPos: tableInfo.start + map.positionAt(map.height - 1, map.width - 1, tableInfo.node),
|
|
36031
|
+
activeRowIndex: activeCellRect.top,
|
|
36032
|
+
activeColumnIndex: activeCellRect.left,
|
|
36033
|
+
tableLeft,
|
|
36034
|
+
tableTop,
|
|
36035
|
+
tableWidth,
|
|
36036
|
+
tableHeight,
|
|
36037
|
+
wrapperLeft,
|
|
36038
|
+
wrapperTop,
|
|
36039
|
+
wrapperWidth,
|
|
36040
|
+
wrapperHeight,
|
|
36041
|
+
viewportWidth,
|
|
36042
|
+
viewportHeight,
|
|
36043
|
+
horizontalScrollbarHeight,
|
|
36044
|
+
verticalScrollbarWidth,
|
|
36045
|
+
avgRowHeight,
|
|
36046
|
+
avgColumnWidth,
|
|
36047
|
+
rowHandles,
|
|
36048
|
+
columnHandles
|
|
36049
|
+
};
|
|
36050
|
+
}
|
|
36051
|
+
|
|
34947
36052
|
// src/components/UEditor/table-hover-state.ts
|
|
34948
36053
|
var MENU_HOVER_PADDING = 18;
|
|
34949
36054
|
var ROW_HANDLE_HOVER_WIDTH = 28;
|
|
@@ -34977,18 +36082,18 @@ function buildTableHoverState({
|
|
|
34977
36082
|
const directAddRow = targetElement?.closest?.("[data-table-control='add-row']");
|
|
34978
36083
|
const directRowHandleIndex = directRowHandle instanceof HTMLElement ? Number.parseInt(directRowHandle.dataset.rowHandleIndex ?? "", 10) : Number.NaN;
|
|
34979
36084
|
const directColumnHandleIndex = directColumnHandle instanceof HTMLElement ? Number.parseInt(directColumnHandle.dataset.columnHandleIndex ?? "", 10) : Number.NaN;
|
|
34980
|
-
const
|
|
34981
|
-
const
|
|
36085
|
+
const visibleBounds = getVisibleTableBounds(layout);
|
|
36086
|
+
const rowRailTop = layout.wrapperTop + layout.wrapperHeight;
|
|
34982
36087
|
const isMouseInTable = relativeX >= layout.tableLeft && relativeX <= layout.tableLeft + layout.tableWidth && relativeY >= layout.tableTop && relativeY <= layout.tableTop + layout.tableHeight;
|
|
34983
36088
|
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;
|
|
34984
36089
|
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;
|
|
34985
36090
|
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;
|
|
34986
36091
|
const lastRow = layout.rowHandles[layout.rowHandles.length - 1];
|
|
34987
36092
|
const lastCol = layout.columnHandles[layout.columnHandles.length - 1];
|
|
34988
|
-
const isMouseInLastColumn = lastCol ? relativeX >= lastCol.start && relativeX <= lastCol.start + lastCol.size && relativeY >=
|
|
34989
|
-
const addColumnVisible = Boolean(directAddColumn) || relativeX >=
|
|
34990
|
-
const isMouseInLastRow = lastRow ? relativeY >= lastRow.start && relativeY <= lastRow.start + lastRow.size && relativeX >=
|
|
34991
|
-
const addRowVisible = Boolean(directAddRow) || relativeY >=
|
|
36093
|
+
const isMouseInLastColumn = lastCol ? relativeX >= lastCol.start && relativeX <= lastCol.start + lastCol.size && relativeY >= visibleBounds.top && relativeY <= visibleBounds.bottom : false;
|
|
36094
|
+
const addColumnVisible = Boolean(directAddColumn) || relativeX >= visibleBounds.right && relativeX <= visibleBounds.right + ADD_COLUMN_HOVER_WIDTH && relativeY >= visibleBounds.top && relativeY <= visibleBounds.bottom || isMouseInLastColumn;
|
|
36095
|
+
const isMouseInLastRow = lastRow ? relativeY >= lastRow.start && relativeY <= lastRow.start + lastRow.size && relativeX >= visibleBounds.left && relativeX <= visibleBounds.right : false;
|
|
36096
|
+
const addRowVisible = Boolean(directAddRow) || relativeY >= rowRailTop && relativeY <= rowRailTop + ADD_ROW_HOVER_HEIGHT && relativeX >= visibleBounds.left && relativeX <= visibleBounds.right || isMouseInLastRow;
|
|
34992
36097
|
return {
|
|
34993
36098
|
menuVisible,
|
|
34994
36099
|
addColumnVisible,
|
|
@@ -35110,12 +36215,11 @@ function TableAddRails({
|
|
|
35110
36215
|
quickAddColumnLabel,
|
|
35111
36216
|
quickAddRowLabel
|
|
35112
36217
|
}) {
|
|
35113
|
-
const
|
|
35114
|
-
const
|
|
35115
|
-
const
|
|
35116
|
-
const columnRailLeft = layout.tableLeft + visibleTableWidth + ADD_COLUMN_RAIL_GAP;
|
|
36218
|
+
const visibleBounds = getVisibleTableBounds(layout);
|
|
36219
|
+
const columnRailTop = visibleBounds.top;
|
|
36220
|
+
const columnRailLeft = visibleBounds.right + ADD_COLUMN_RAIL_GAP;
|
|
35117
36221
|
const rowRailTop = layout.wrapperTop + layout.wrapperHeight + ADD_ROW_RAIL_GAP;
|
|
35118
|
-
const rowRailLeft =
|
|
36222
|
+
const rowRailLeft = visibleBounds.left;
|
|
35119
36223
|
const showColumnRail = controlsVisible || addColumnVisible;
|
|
35120
36224
|
const showRowRail = controlsVisible || addRowVisible;
|
|
35121
36225
|
return /* @__PURE__ */ jsxs75(Fragment32, { children: [
|
|
@@ -35143,10 +36247,10 @@ function TableAddRails({
|
|
|
35143
36247
|
"transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground disabled:opacity-50 disabled:cursor-not-allowed"
|
|
35144
36248
|
),
|
|
35145
36249
|
style: {
|
|
35146
|
-
top: showColumnRail ? columnRailTop : columnRailTop + Math.max(0,
|
|
36250
|
+
top: showColumnRail ? columnRailTop : columnRailTop + Math.max(0, visibleBounds.height / 2 - 24),
|
|
35147
36251
|
left: columnRailLeft,
|
|
35148
36252
|
width: showColumnRail ? 18 : 12,
|
|
35149
|
-
height: showColumnRail ?
|
|
36253
|
+
height: showColumnRail ? visibleBounds.height : 48,
|
|
35150
36254
|
opacity: showColumnRail ? 1 : 0,
|
|
35151
36255
|
transform: showColumnRail ? "scale(1)" : "scale(0.92)",
|
|
35152
36256
|
pointerEvents: showColumnRail ? "auto" : "none"
|
|
@@ -35181,8 +36285,8 @@ function TableAddRails({
|
|
|
35181
36285
|
),
|
|
35182
36286
|
style: {
|
|
35183
36287
|
top: rowRailTop,
|
|
35184
|
-
left: showRowRail ? rowRailLeft : rowRailLeft + Math.max(0,
|
|
35185
|
-
width: showRowRail ?
|
|
36288
|
+
left: showRowRail ? rowRailLeft : rowRailLeft + Math.max(0, visibleBounds.width / 2 - 24),
|
|
36289
|
+
width: showRowRail ? visibleBounds.width : 48,
|
|
35186
36290
|
height: showRowRail ? 16 : 12,
|
|
35187
36291
|
opacity: showRowRail ? 1 : 0,
|
|
35188
36292
|
transform: showRowRail ? "scale(1)" : "scale(0.92)",
|
|
@@ -35407,248 +36511,6 @@ function TableColumnHandles({
|
|
|
35407
36511
|
}) });
|
|
35408
36512
|
}
|
|
35409
36513
|
|
|
35410
|
-
// src/components/UEditor/table-layout-model.ts
|
|
35411
|
-
var FALLBACK_TABLE_ROW_HEIGHT = 44;
|
|
35412
|
-
var FALLBACK_TABLE_COLUMN_WIDTH = 160;
|
|
35413
|
-
function metricOrFallback(value, fallback) {
|
|
35414
|
-
return Number.isFinite(value) && value > 0 ? value : fallback;
|
|
35415
|
-
}
|
|
35416
|
-
function parsePixelMetric(value) {
|
|
35417
|
-
if (!value) return null;
|
|
35418
|
-
const parsed = Number.parseFloat(value);
|
|
35419
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
35420
|
-
}
|
|
35421
|
-
function getPrimaryCell(table) {
|
|
35422
|
-
const cell = table.querySelector("th,td");
|
|
35423
|
-
return cell instanceof HTMLTableCellElement ? cell : null;
|
|
35424
|
-
}
|
|
35425
|
-
function getLastCell(table) {
|
|
35426
|
-
const lastRow = table.rows.item(table.rows.length - 1);
|
|
35427
|
-
if (!(lastRow instanceof HTMLTableRowElement)) return null;
|
|
35428
|
-
const cell = lastRow.cells.item(lastRow.cells.length - 1);
|
|
35429
|
-
return cell instanceof HTMLTableCellElement ? cell : null;
|
|
35430
|
-
}
|
|
35431
|
-
function getCellFromTarget(target) {
|
|
35432
|
-
const element = resolveEventElement(target);
|
|
35433
|
-
if (!element) return null;
|
|
35434
|
-
const directCell = element.closest("th,td");
|
|
35435
|
-
if (directCell instanceof HTMLTableCellElement) {
|
|
35436
|
-
return directCell;
|
|
35437
|
-
}
|
|
35438
|
-
const table = element.closest("table");
|
|
35439
|
-
if (table instanceof HTMLTableElement) {
|
|
35440
|
-
return getPrimaryCell(table);
|
|
35441
|
-
}
|
|
35442
|
-
return null;
|
|
35443
|
-
}
|
|
35444
|
-
function findTableInfo(editor, pos) {
|
|
35445
|
-
const $pos = editor.state.doc.resolve(pos);
|
|
35446
|
-
for (let depth = $pos.depth; depth > 0; depth -= 1) {
|
|
35447
|
-
const node = $pos.node(depth);
|
|
35448
|
-
if (node.type.name === "table") {
|
|
35449
|
-
return {
|
|
35450
|
-
node,
|
|
35451
|
-
pos: $pos.before(depth),
|
|
35452
|
-
start: $pos.start(depth)
|
|
35453
|
-
};
|
|
35454
|
-
}
|
|
35455
|
-
}
|
|
35456
|
-
return null;
|
|
35457
|
-
}
|
|
35458
|
-
function getCellRelativePosFromDomPos(map, tableStart, domPos) {
|
|
35459
|
-
const relativeDomPos = domPos - tableStart;
|
|
35460
|
-
const seen = /* @__PURE__ */ new Set();
|
|
35461
|
-
for (const relativeCellPos of map.map) {
|
|
35462
|
-
if (seen.has(relativeCellPos)) continue;
|
|
35463
|
-
seen.add(relativeCellPos);
|
|
35464
|
-
if (relativeDomPos === relativeCellPos || relativeDomPos === relativeCellPos + 1) {
|
|
35465
|
-
return relativeCellPos;
|
|
35466
|
-
}
|
|
35467
|
-
}
|
|
35468
|
-
return null;
|
|
35469
|
-
}
|
|
35470
|
-
function buildLogicalColumnMetrics({
|
|
35471
|
-
editor,
|
|
35472
|
-
surface,
|
|
35473
|
-
surfaceRect,
|
|
35474
|
-
tableElement,
|
|
35475
|
-
tableInfo,
|
|
35476
|
-
tableLeft,
|
|
35477
|
-
tableWidth
|
|
35478
|
-
}) {
|
|
35479
|
-
const map = TableMap2.get(tableInfo.node);
|
|
35480
|
-
const fallbackWidth = metricOrFallback(tableWidth / map.width, FALLBACK_TABLE_COLUMN_WIDTH);
|
|
35481
|
-
const firstRow = tableElement.rows.item(0);
|
|
35482
|
-
const visualColumns = [];
|
|
35483
|
-
if (firstRow) {
|
|
35484
|
-
for (const tableCell of Array.from(firstRow.cells)) {
|
|
35485
|
-
if (!(tableCell instanceof HTMLTableCellElement)) continue;
|
|
35486
|
-
const cellPos = editor.view.posAtDOM(tableCell, 0);
|
|
35487
|
-
const relativeCellPos = getCellRelativePosFromDomPos(map, tableInfo.start, cellPos);
|
|
35488
|
-
if (relativeCellPos == null) continue;
|
|
35489
|
-
const cellMapRect = map.findCell(relativeCellPos);
|
|
35490
|
-
const cellRect = tableCell.getBoundingClientRect();
|
|
35491
|
-
const cellStart = cellRect.width > 0 ? cellRect.left - surfaceRect.left + surface.scrollLeft : tableLeft + cellMapRect.left * fallbackWidth;
|
|
35492
|
-
const size = metricOrFallback(cellRect.width, fallbackWidth * Math.max(1, cellMapRect.right - cellMapRect.left));
|
|
35493
|
-
visualColumns.push({
|
|
35494
|
-
index: cellMapRect.left,
|
|
35495
|
-
cellPos: tableInfo.start + relativeCellPos,
|
|
35496
|
-
start: cellStart,
|
|
35497
|
-
size,
|
|
35498
|
-
center: cellStart + size / 2
|
|
35499
|
-
});
|
|
35500
|
-
}
|
|
35501
|
-
}
|
|
35502
|
-
if (visualColumns.length > 0) {
|
|
35503
|
-
return visualColumns.sort((a, b) => a.index - b.index);
|
|
35504
|
-
}
|
|
35505
|
-
const cols = Array.from(tableElement.querySelectorAll("colgroup > col"));
|
|
35506
|
-
const parsedWidths = cols.slice(0, map.width).map((col) => parsePixelMetric(col.style.width) ?? parsePixelMetric(col.getAttribute("width")));
|
|
35507
|
-
const hasCompleteColWidths = parsedWidths.length >= map.width && parsedWidths.every((width) => typeof width === "number");
|
|
35508
|
-
let cursor = tableLeft;
|
|
35509
|
-
return Array.from({ length: map.width }, (_, index) => {
|
|
35510
|
-
const size = hasCompleteColWidths ? parsedWidths[index] : fallbackWidth;
|
|
35511
|
-
const start = hasCompleteColWidths ? cursor : tableLeft + index * fallbackWidth;
|
|
35512
|
-
cursor += size;
|
|
35513
|
-
return {
|
|
35514
|
-
index,
|
|
35515
|
-
cellPos: tableInfo.start + map.positionAt(0, index, tableInfo.node),
|
|
35516
|
-
start,
|
|
35517
|
-
size,
|
|
35518
|
-
center: start + size / 2
|
|
35519
|
-
};
|
|
35520
|
-
});
|
|
35521
|
-
}
|
|
35522
|
-
function buildLogicalRowMetrics({
|
|
35523
|
-
editor,
|
|
35524
|
-
surface,
|
|
35525
|
-
surfaceRect,
|
|
35526
|
-
tableInfo,
|
|
35527
|
-
rows,
|
|
35528
|
-
tableTop,
|
|
35529
|
-
tableHeight,
|
|
35530
|
-
cornerCell
|
|
35531
|
-
}) {
|
|
35532
|
-
const map = TableMap2.get(tableInfo.node);
|
|
35533
|
-
const fallbackHeight = metricOrFallback(tableHeight / map.height, FALLBACK_TABLE_ROW_HEIGHT);
|
|
35534
|
-
const visualRows = [];
|
|
35535
|
-
const seenCellPositions = /* @__PURE__ */ new Set();
|
|
35536
|
-
for (let rowIndex = 0; rowIndex < map.height; rowIndex += 1) {
|
|
35537
|
-
const relativeCellPos = map.map[rowIndex * map.width];
|
|
35538
|
-
if (seenCellPositions.has(relativeCellPos)) continue;
|
|
35539
|
-
seenCellPositions.add(relativeCellPos);
|
|
35540
|
-
const cellMapRect = map.findCell(relativeCellPos);
|
|
35541
|
-
const cellDom = editor.view.nodeDOM(tableInfo.start + relativeCellPos);
|
|
35542
|
-
const tableCell = cellDom instanceof HTMLTableCellElement ? cellDom : null;
|
|
35543
|
-
if (tableCell) {
|
|
35544
|
-
const cellRect = tableCell.getBoundingClientRect();
|
|
35545
|
-
const start = cellRect.height > 0 ? cellRect.top - surfaceRect.top + surface.scrollTop : tableTop + cellMapRect.top * fallbackHeight;
|
|
35546
|
-
const size = metricOrFallback(cellRect.height, fallbackHeight * Math.max(1, cellMapRect.bottom - cellMapRect.top));
|
|
35547
|
-
visualRows.push({
|
|
35548
|
-
index: cellMapRect.top,
|
|
35549
|
-
cellPos: tableInfo.start + relativeCellPos,
|
|
35550
|
-
start,
|
|
35551
|
-
size,
|
|
35552
|
-
center: start + size / 2
|
|
35553
|
-
});
|
|
35554
|
-
}
|
|
35555
|
-
}
|
|
35556
|
-
if (visualRows.length > 0) {
|
|
35557
|
-
return visualRows.sort((a, b) => a.index - b.index);
|
|
35558
|
-
}
|
|
35559
|
-
return rows.map((tableRow, index) => {
|
|
35560
|
-
const rowRect = tableRow.getBoundingClientRect();
|
|
35561
|
-
const anchorCell = tableRow.cells.item(0) ?? cornerCell;
|
|
35562
|
-
const start = rowRect.height > 0 ? rowRect.top - surfaceRect.top + surface.scrollTop : tableTop + index * fallbackHeight;
|
|
35563
|
-
const size = metricOrFallback(rowRect.height, fallbackHeight);
|
|
35564
|
-
return {
|
|
35565
|
-
index,
|
|
35566
|
-
cellPos: editor.view.posAtDOM(anchorCell, 0),
|
|
35567
|
-
start,
|
|
35568
|
-
size,
|
|
35569
|
-
center: start + size / 2
|
|
35570
|
-
};
|
|
35571
|
-
});
|
|
35572
|
-
}
|
|
35573
|
-
function buildTableControlLayout(editor, surface, cell) {
|
|
35574
|
-
const row = cell.closest("tr");
|
|
35575
|
-
const table = cell.closest("table");
|
|
35576
|
-
if (!(row instanceof HTMLTableRowElement) || !(table instanceof HTMLTableElement)) {
|
|
35577
|
-
return null;
|
|
35578
|
-
}
|
|
35579
|
-
const rows = Array.from(table.rows).filter((item) => item instanceof HTMLTableRowElement);
|
|
35580
|
-
const cornerCell = getLastCell(table);
|
|
35581
|
-
const cellPos = editor.view.posAtDOM(cell, 0);
|
|
35582
|
-
const tableInfo = findTableInfo(editor, cellPos);
|
|
35583
|
-
if (rows.length === 0 || !tableInfo || !(cornerCell instanceof HTMLTableCellElement)) {
|
|
35584
|
-
return null;
|
|
35585
|
-
}
|
|
35586
|
-
const map = TableMap2.get(tableInfo.node);
|
|
35587
|
-
const surfaceRect = surface.getBoundingClientRect();
|
|
35588
|
-
const tableRect = table.getBoundingClientRect();
|
|
35589
|
-
const wrapperElement = table.closest(".tableWrapper");
|
|
35590
|
-
const wrapper = wrapperElement instanceof HTMLElement ? wrapperElement : null;
|
|
35591
|
-
const wrapperRect = wrapper?.getBoundingClientRect() ?? tableRect;
|
|
35592
|
-
const tableLeft = tableRect.left - surfaceRect.left + surface.scrollLeft;
|
|
35593
|
-
const tableTop = tableRect.top - surfaceRect.top + surface.scrollTop;
|
|
35594
|
-
const avgRowHeight = metricOrFallback(tableRect.height / rows.length, FALLBACK_TABLE_ROW_HEIGHT);
|
|
35595
|
-
const avgColumnWidth = metricOrFallback(tableRect.width / map.width, FALLBACK_TABLE_COLUMN_WIDTH);
|
|
35596
|
-
const tableWidth = metricOrFallback(tableRect.width, avgColumnWidth * map.width);
|
|
35597
|
-
const tableHeight = metricOrFallback(tableRect.height, avgRowHeight * rows.length);
|
|
35598
|
-
const wrapperLeft = wrapperRect.left - surfaceRect.left + surface.scrollLeft;
|
|
35599
|
-
const wrapperTop = wrapperRect.top - surfaceRect.top + surface.scrollTop;
|
|
35600
|
-
const wrapperWidth = metricOrFallback(wrapperRect.width, tableWidth);
|
|
35601
|
-
const wrapperHeight = metricOrFallback(wrapperRect.height, tableHeight);
|
|
35602
|
-
const viewportWidth = metricOrFallback(wrapper?.clientWidth ?? wrapperRect.width, tableWidth);
|
|
35603
|
-
const viewportHeight = metricOrFallback(wrapper?.clientHeight ?? wrapperRect.height, tableHeight);
|
|
35604
|
-
const verticalScrollbarWidth = Math.max(0, Math.round(wrapperWidth - viewportWidth));
|
|
35605
|
-
const horizontalScrollbarHeight = Math.max(0, Math.round(wrapperHeight - viewportHeight));
|
|
35606
|
-
const rowHandles = buildLogicalRowMetrics({
|
|
35607
|
-
editor,
|
|
35608
|
-
surface,
|
|
35609
|
-
surfaceRect,
|
|
35610
|
-
tableInfo,
|
|
35611
|
-
rows,
|
|
35612
|
-
tableTop,
|
|
35613
|
-
tableHeight,
|
|
35614
|
-
cornerCell
|
|
35615
|
-
});
|
|
35616
|
-
const columnHandles = buildLogicalColumnMetrics({
|
|
35617
|
-
editor,
|
|
35618
|
-
surface,
|
|
35619
|
-
surfaceRect,
|
|
35620
|
-
tableElement: table,
|
|
35621
|
-
tableInfo,
|
|
35622
|
-
tableLeft,
|
|
35623
|
-
tableWidth
|
|
35624
|
-
});
|
|
35625
|
-
const activeCellRelativePos = getCellRelativePosFromDomPos(map, tableInfo.start, cellPos);
|
|
35626
|
-
const activeCellRect = activeCellRelativePos != null ? map.findCell(activeCellRelativePos) : { left: cell.cellIndex, top: row.rowIndex };
|
|
35627
|
-
const normalizedCellPos = activeCellRelativePos != null ? tableInfo.start + activeCellRelativePos : cellPos;
|
|
35628
|
-
return {
|
|
35629
|
-
cellPos: normalizedCellPos,
|
|
35630
|
-
cornerCellPos: tableInfo.start + map.positionAt(map.height - 1, map.width - 1, tableInfo.node),
|
|
35631
|
-
activeRowIndex: activeCellRect.top,
|
|
35632
|
-
activeColumnIndex: activeCellRect.left,
|
|
35633
|
-
tableLeft,
|
|
35634
|
-
tableTop,
|
|
35635
|
-
tableWidth,
|
|
35636
|
-
tableHeight,
|
|
35637
|
-
wrapperLeft,
|
|
35638
|
-
wrapperTop,
|
|
35639
|
-
wrapperWidth,
|
|
35640
|
-
wrapperHeight,
|
|
35641
|
-
viewportWidth,
|
|
35642
|
-
viewportHeight,
|
|
35643
|
-
horizontalScrollbarHeight,
|
|
35644
|
-
verticalScrollbarWidth,
|
|
35645
|
-
avgRowHeight,
|
|
35646
|
-
avgColumnWidth,
|
|
35647
|
-
rowHandles,
|
|
35648
|
-
columnHandles
|
|
35649
|
-
};
|
|
35650
|
-
}
|
|
35651
|
-
|
|
35652
36514
|
// src/components/UEditor/table-controls.tsx
|
|
35653
36515
|
import { Fragment as Fragment34, jsx as jsx91, jsxs as jsxs76 } from "react/jsx-runtime";
|
|
35654
36516
|
var TABLE_MENU_TOP_OFFSET = 10;
|
|
@@ -37623,6 +38485,7 @@ var UEditor = React82.forwardRef(({
|
|
|
37623
38485
|
const effectivePlaceholder = placeholder ?? t("placeholder");
|
|
37624
38486
|
const inFlightPrepareRef = useRef37(null);
|
|
37625
38487
|
const lastAppliedContentRef = useRef37(content ?? "");
|
|
38488
|
+
const scheduledFormulaRecalculateRef = useRef37(false);
|
|
37626
38489
|
const resolvedUploadFile = useMemo24(() => {
|
|
37627
38490
|
if (uploadFile) return uploadFile;
|
|
37628
38491
|
if (uploadFileForSave) {
|
|
@@ -37686,7 +38549,16 @@ var UEditor = React82.forwardRef(({
|
|
|
37686
38549
|
class: UEDITOR_PROSEMIRROR_CLASS_NAME
|
|
37687
38550
|
}
|
|
37688
38551
|
},
|
|
37689
|
-
onUpdate: ({ editor: editor2 }) => {
|
|
38552
|
+
onUpdate: ({ editor: editor2, transaction }) => {
|
|
38553
|
+
if (!transaction.getMeta(UEDITOR_TABLE_FORMULA_RECALCULATE_META) && !scheduledFormulaRecalculateRef.current) {
|
|
38554
|
+
scheduledFormulaRecalculateRef.current = true;
|
|
38555
|
+
queueMicrotask(() => {
|
|
38556
|
+
scheduledFormulaRecalculateRef.current = false;
|
|
38557
|
+
if (!editor2.isDestroyed) {
|
|
38558
|
+
recalculateAllTableFormulas(editor2);
|
|
38559
|
+
}
|
|
38560
|
+
});
|
|
38561
|
+
}
|
|
37690
38562
|
const html = editor2.getHTML();
|
|
37691
38563
|
onChange?.(html);
|
|
37692
38564
|
onHtmlChange?.(html);
|
|
@@ -37724,6 +38596,14 @@ var UEditor = React82.forwardRef(({
|
|
|
37724
38596
|
}),
|
|
37725
38597
|
[content, editor, uploadImageForSave, uploadFileForSave, uploadImageConcurrency]
|
|
37726
38598
|
);
|
|
38599
|
+
useEffect38(() => {
|
|
38600
|
+
if (!editor) return;
|
|
38601
|
+
queueMicrotask(() => {
|
|
38602
|
+
if (!editor.isDestroyed) {
|
|
38603
|
+
recalculateAllTableFormulas(editor);
|
|
38604
|
+
}
|
|
38605
|
+
});
|
|
38606
|
+
}, [editor]);
|
|
37727
38607
|
useEffect38(() => {
|
|
37728
38608
|
if (!editor) return;
|
|
37729
38609
|
const nextContent = content ?? "";
|
|
@@ -37733,6 +38613,11 @@ var UEditor = React82.forwardRef(({
|
|
|
37733
38613
|
Promise.resolve().then(() => {
|
|
37734
38614
|
if (!editor.isDestroyed) {
|
|
37735
38615
|
editor.commands.setContent(nextContent, { emitUpdate: false });
|
|
38616
|
+
queueMicrotask(() => {
|
|
38617
|
+
if (!editor.isDestroyed) {
|
|
38618
|
+
recalculateAllTableFormulas(editor);
|
|
38619
|
+
}
|
|
38620
|
+
});
|
|
37736
38621
|
}
|
|
37737
38622
|
});
|
|
37738
38623
|
}
|