@underverse-ui/underverse 1.0.149 → 1.0.151
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 +1516 -322
- 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 +1517 -322
- 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: {
|
|
@@ -25681,6 +25689,8 @@ import { Extension as Extension2 } from "@tiptap/core";
|
|
|
25681
25689
|
import { Plugin as Plugin2 } from "@tiptap/pm/state";
|
|
25682
25690
|
|
|
25683
25691
|
// src/components/UEditor/clipboard-tables.ts
|
|
25692
|
+
var DEFAULT_HTML_TABLE_CELL_BACKGROUND_COLOR = "#ffffff";
|
|
25693
|
+
var DEFAULT_HTML_TABLE_TEXT_COLOR = "#000000";
|
|
25684
25694
|
function getClipboardData(dataTransfer, type) {
|
|
25685
25695
|
try {
|
|
25686
25696
|
return dataTransfer.getData(type) ?? "";
|
|
@@ -25701,6 +25711,411 @@ function extractClipboardHtmlFragment(html) {
|
|
|
25701
25711
|
function normalizeClipboardCellText(value) {
|
|
25702
25712
|
return value.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\u00a0/g, " ").replace(/[ \t]+\n/g, "\n").replace(/\n[ \t]+/g, "\n").replace(/\n+$/g, "").replace(/^\n+/g, "").trim();
|
|
25703
25713
|
}
|
|
25714
|
+
function parseStyleDeclarations(styleText) {
|
|
25715
|
+
const declarations = /* @__PURE__ */ new Map();
|
|
25716
|
+
if (!styleText) return declarations;
|
|
25717
|
+
for (const declaration of styleText.split(";")) {
|
|
25718
|
+
const separatorIndex = declaration.indexOf(":");
|
|
25719
|
+
if (separatorIndex <= 0) continue;
|
|
25720
|
+
const property = declaration.slice(0, separatorIndex).trim().toLowerCase();
|
|
25721
|
+
const value = cleanStyleValue(declaration.slice(separatorIndex + 1));
|
|
25722
|
+
if (!property || !value) continue;
|
|
25723
|
+
declarations.set(property, value);
|
|
25724
|
+
}
|
|
25725
|
+
return declarations;
|
|
25726
|
+
}
|
|
25727
|
+
function mergeStyleDeclarations(...sources) {
|
|
25728
|
+
const declarations = /* @__PURE__ */ new Map();
|
|
25729
|
+
for (const source of sources) {
|
|
25730
|
+
if (!source) continue;
|
|
25731
|
+
for (const [property, value] of source.entries()) {
|
|
25732
|
+
declarations.set(property, value);
|
|
25733
|
+
}
|
|
25734
|
+
}
|
|
25735
|
+
return declarations;
|
|
25736
|
+
}
|
|
25737
|
+
function extractCssClassNames(selectorText) {
|
|
25738
|
+
const classNames = /* @__PURE__ */ new Set();
|
|
25739
|
+
const classNamePattern = /\.([_a-zA-Z-][\w-]*)/g;
|
|
25740
|
+
let match;
|
|
25741
|
+
while ((match = classNamePattern.exec(selectorText)) !== null) {
|
|
25742
|
+
classNames.add(match[1]);
|
|
25743
|
+
}
|
|
25744
|
+
return classNames;
|
|
25745
|
+
}
|
|
25746
|
+
function parseClipboardCssClassStyles(doc) {
|
|
25747
|
+
const styleMap = /* @__PURE__ */ new Map();
|
|
25748
|
+
for (const styleElement of Array.from(doc.querySelectorAll("style"))) {
|
|
25749
|
+
const cssText = (styleElement.textContent ?? "").replace(/<!--|-->/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
25750
|
+
const rulePattern = /([^{}]+)\{([^{}]*)\}/g;
|
|
25751
|
+
let match;
|
|
25752
|
+
while ((match = rulePattern.exec(cssText)) !== null) {
|
|
25753
|
+
const classNames = extractCssClassNames(match[1]);
|
|
25754
|
+
if (classNames.size === 0) continue;
|
|
25755
|
+
const declarations = parseStyleDeclarations(match[2]);
|
|
25756
|
+
if (declarations.size === 0) continue;
|
|
25757
|
+
for (const className of classNames) {
|
|
25758
|
+
styleMap.set(className, mergeStyleDeclarations(styleMap.get(className), declarations));
|
|
25759
|
+
}
|
|
25760
|
+
}
|
|
25761
|
+
}
|
|
25762
|
+
return styleMap;
|
|
25763
|
+
}
|
|
25764
|
+
function getElementStyleDeclarations(element, styleMap) {
|
|
25765
|
+
const classDeclarations = Array.from(element.classList).map((className) => styleMap.get(className));
|
|
25766
|
+
const inlineDeclarations = parseStyleDeclarations(element.getAttribute("style"));
|
|
25767
|
+
return mergeStyleDeclarations(...classDeclarations, inlineDeclarations);
|
|
25768
|
+
}
|
|
25769
|
+
function cleanStyleValue(value) {
|
|
25770
|
+
const normalized = value?.trim();
|
|
25771
|
+
if (!normalized) return null;
|
|
25772
|
+
if (/[\0<>;{}]/.test(normalized)) return null;
|
|
25773
|
+
if (/\b(?:expression|url|(?:repeating-)?(?:linear|radial|conic)-gradient)\s*\(/i.test(normalized)) return null;
|
|
25774
|
+
return normalized;
|
|
25775
|
+
}
|
|
25776
|
+
function normalizeColorValue(value) {
|
|
25777
|
+
const normalized = cleanStyleValue(value);
|
|
25778
|
+
if (!normalized) return null;
|
|
25779
|
+
if (/^(?:auto|inherit|initial|none|transparent|unset)$/i.test(normalized)) return null;
|
|
25780
|
+
return normalized;
|
|
25781
|
+
}
|
|
25782
|
+
function normalizeTextColorValue(value) {
|
|
25783
|
+
const normalized = normalizeColorValue(value);
|
|
25784
|
+
if (!normalized) return null;
|
|
25785
|
+
if (/^(?:automatic|windowtext|black|#000|#000000|rgb\(\s*0\s*,\s*0\s*,\s*0\s*\))$/i.test(normalized)) {
|
|
25786
|
+
return DEFAULT_HTML_TABLE_TEXT_COLOR;
|
|
25787
|
+
}
|
|
25788
|
+
return normalized;
|
|
25789
|
+
}
|
|
25790
|
+
function isWhiteColor(value) {
|
|
25791
|
+
if (!value) return false;
|
|
25792
|
+
return /^(?:white|#fff|#ffffff|rgb\(\s*255\s*,\s*255\s*,\s*255\s*\))$/i.test(value.trim());
|
|
25793
|
+
}
|
|
25794
|
+
function parseCssColorRgb(value) {
|
|
25795
|
+
const normalized = normalizeColorValue(value);
|
|
25796
|
+
if (!normalized) return null;
|
|
25797
|
+
const lowerColor = normalized.toLowerCase();
|
|
25798
|
+
if (lowerColor === "white") return { r: 255, g: 255, b: 255 };
|
|
25799
|
+
if (lowerColor === "black") return { r: 0, g: 0, b: 0 };
|
|
25800
|
+
const hexMatch = lowerColor.match(/^#([\da-f]{3}|[\da-f]{6})$/i);
|
|
25801
|
+
if (hexMatch) {
|
|
25802
|
+
const hex = hexMatch[1];
|
|
25803
|
+
const fullHex = hex.length === 3 ? hex.split("").map((part) => part + part).join("") : hex;
|
|
25804
|
+
return {
|
|
25805
|
+
r: Number.parseInt(fullHex.slice(0, 2), 16),
|
|
25806
|
+
g: Number.parseInt(fullHex.slice(2, 4), 16),
|
|
25807
|
+
b: Number.parseInt(fullHex.slice(4, 6), 16)
|
|
25808
|
+
};
|
|
25809
|
+
}
|
|
25810
|
+
const rgbMatch = lowerColor.match(/^rgba?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)/);
|
|
25811
|
+
if (rgbMatch) {
|
|
25812
|
+
return {
|
|
25813
|
+
r: Math.max(0, Math.min(255, Number.parseFloat(rgbMatch[1]))),
|
|
25814
|
+
g: Math.max(0, Math.min(255, Number.parseFloat(rgbMatch[2]))),
|
|
25815
|
+
b: Math.max(0, Math.min(255, Number.parseFloat(rgbMatch[3])))
|
|
25816
|
+
};
|
|
25817
|
+
}
|
|
25818
|
+
return null;
|
|
25819
|
+
}
|
|
25820
|
+
function getRelativeLuminance(value) {
|
|
25821
|
+
const rgb = parseCssColorRgb(value);
|
|
25822
|
+
if (!rgb) return null;
|
|
25823
|
+
const toLinear = (channel) => {
|
|
25824
|
+
const normalized = channel / 255;
|
|
25825
|
+
return normalized <= 0.03928 ? normalized / 12.92 : ((normalized + 0.055) / 1.055) ** 2.4;
|
|
25826
|
+
};
|
|
25827
|
+
return 0.2126 * toLinear(rgb.r) + 0.7152 * toLinear(rgb.g) + 0.0722 * toLinear(rgb.b);
|
|
25828
|
+
}
|
|
25829
|
+
function isLightTextColor(value) {
|
|
25830
|
+
const luminance = getRelativeLuminance(value);
|
|
25831
|
+
return luminance !== null && luminance >= 0.72;
|
|
25832
|
+
}
|
|
25833
|
+
function isDarkReadableBackground(value) {
|
|
25834
|
+
const luminance = getRelativeLuminance(value);
|
|
25835
|
+
return luminance !== null && luminance <= 0.45;
|
|
25836
|
+
}
|
|
25837
|
+
function splitCssTokens(value) {
|
|
25838
|
+
const tokens = [];
|
|
25839
|
+
let current = "";
|
|
25840
|
+
let depth = 0;
|
|
25841
|
+
for (const char of value) {
|
|
25842
|
+
if (char === "(") depth += 1;
|
|
25843
|
+
if (char === ")") depth = Math.max(0, depth - 1);
|
|
25844
|
+
if (/\s/.test(char) && depth === 0) {
|
|
25845
|
+
if (current) {
|
|
25846
|
+
tokens.push(current);
|
|
25847
|
+
current = "";
|
|
25848
|
+
}
|
|
25849
|
+
continue;
|
|
25850
|
+
}
|
|
25851
|
+
current += char;
|
|
25852
|
+
}
|
|
25853
|
+
if (current) tokens.push(current);
|
|
25854
|
+
return tokens;
|
|
25855
|
+
}
|
|
25856
|
+
function extractColorFromShorthand(value) {
|
|
25857
|
+
const normalized = cleanStyleValue(value);
|
|
25858
|
+
if (!normalized) return null;
|
|
25859
|
+
const explicitColor = normalized.match(/#[\da-f]{3,8}\b|rgba?\([^)]+\)|hsla?\([^)]+\)/i);
|
|
25860
|
+
if (explicitColor) return explicitColor[0];
|
|
25861
|
+
const ignoredKeywords = /* @__PURE__ */ new Set([
|
|
25862
|
+
"border-box",
|
|
25863
|
+
"center",
|
|
25864
|
+
"contain",
|
|
25865
|
+
"content-box",
|
|
25866
|
+
"cover",
|
|
25867
|
+
"fixed",
|
|
25868
|
+
"inherit",
|
|
25869
|
+
"initial",
|
|
25870
|
+
"left",
|
|
25871
|
+
"local",
|
|
25872
|
+
"none",
|
|
25873
|
+
"no-repeat",
|
|
25874
|
+
"padding-box",
|
|
25875
|
+
"repeat",
|
|
25876
|
+
"repeat-x",
|
|
25877
|
+
"repeat-y",
|
|
25878
|
+
"right",
|
|
25879
|
+
"scroll",
|
|
25880
|
+
"top",
|
|
25881
|
+
"transparent",
|
|
25882
|
+
"unset"
|
|
25883
|
+
]);
|
|
25884
|
+
return splitCssTokens(normalized).find((token) => !ignoredKeywords.has(token.toLowerCase())) ?? null;
|
|
25885
|
+
}
|
|
25886
|
+
function getBackgroundColor(styles) {
|
|
25887
|
+
return normalizeColorValue(styles.get("background-color")) ?? normalizeColorValue(extractColorFromShorthand(styles.get("background")));
|
|
25888
|
+
}
|
|
25889
|
+
var BORDER_STYLES = /* @__PURE__ */ new Set([
|
|
25890
|
+
"dashed",
|
|
25891
|
+
"dotted",
|
|
25892
|
+
"double",
|
|
25893
|
+
"groove",
|
|
25894
|
+
"hidden",
|
|
25895
|
+
"inset",
|
|
25896
|
+
"none",
|
|
25897
|
+
"outset",
|
|
25898
|
+
"ridge",
|
|
25899
|
+
"solid"
|
|
25900
|
+
]);
|
|
25901
|
+
var BORDER_WIDTH_KEYWORDS = /* @__PURE__ */ new Set(["medium", "thick", "thin"]);
|
|
25902
|
+
function normalizeBorderStyle(value) {
|
|
25903
|
+
const normalized = cleanStyleValue(value);
|
|
25904
|
+
if (!normalized) return null;
|
|
25905
|
+
const styles = splitCssTokens(normalized).filter((token) => BORDER_STYLES.has(token.toLowerCase()));
|
|
25906
|
+
const usefulStyles = styles.filter((style) => !/^(?:hidden|none)$/i.test(style));
|
|
25907
|
+
return usefulStyles.length > 0 ? usefulStyles.join(" ") : null;
|
|
25908
|
+
}
|
|
25909
|
+
function normalizeBorderWidth(value) {
|
|
25910
|
+
const normalized = cleanStyleValue(value);
|
|
25911
|
+
if (!normalized) return null;
|
|
25912
|
+
const widths = splitCssTokens(normalized).filter((token) => {
|
|
25913
|
+
const lowerToken = token.toLowerCase();
|
|
25914
|
+
return BORDER_WIDTH_KEYWORDS.has(lowerToken) || /^\d*\.?\d+(?:px|pt|pc|in|cm|mm|em|rem)?$/i.test(token);
|
|
25915
|
+
});
|
|
25916
|
+
return widths.length > 0 ? widths.join(" ") : null;
|
|
25917
|
+
}
|
|
25918
|
+
function parseBorderShorthand(value) {
|
|
25919
|
+
const normalized = cleanStyleValue(value);
|
|
25920
|
+
if (!normalized) return null;
|
|
25921
|
+
const tokens = splitCssTokens(normalized);
|
|
25922
|
+
let borderStyle = null;
|
|
25923
|
+
let borderWidth = null;
|
|
25924
|
+
const colorTokens = [];
|
|
25925
|
+
for (const token of tokens) {
|
|
25926
|
+
const lowerToken = token.toLowerCase();
|
|
25927
|
+
if (!borderStyle && BORDER_STYLES.has(lowerToken)) {
|
|
25928
|
+
borderStyle = lowerToken;
|
|
25929
|
+
continue;
|
|
25930
|
+
}
|
|
25931
|
+
if (!borderWidth && (BORDER_WIDTH_KEYWORDS.has(lowerToken) || /^\d*\.?\d+(?:px|pt|pc|in|cm|mm|em|rem)?$/i.test(token))) {
|
|
25932
|
+
borderWidth = token;
|
|
25933
|
+
continue;
|
|
25934
|
+
}
|
|
25935
|
+
colorTokens.push(token);
|
|
25936
|
+
}
|
|
25937
|
+
if (borderStyle && /^(?:hidden|none)$/i.test(borderStyle)) return null;
|
|
25938
|
+
return {
|
|
25939
|
+
borderColor: normalizeColorValue(colorTokens.join(" ")),
|
|
25940
|
+
borderStyle,
|
|
25941
|
+
borderWidth
|
|
25942
|
+
};
|
|
25943
|
+
}
|
|
25944
|
+
function getFirstParsedBorder(styles) {
|
|
25945
|
+
for (const property of ["border", "border-top", "border-right", "border-bottom", "border-left"]) {
|
|
25946
|
+
const border = parseBorderShorthand(styles.get(property));
|
|
25947
|
+
if (border) return border;
|
|
25948
|
+
}
|
|
25949
|
+
return null;
|
|
25950
|
+
}
|
|
25951
|
+
function getBorderAttrs(styles) {
|
|
25952
|
+
const parsedBorder = getFirstParsedBorder(styles);
|
|
25953
|
+
return {
|
|
25954
|
+
borderColor: normalizeColorValue(styles.get("border-color")) ?? parsedBorder?.borderColor ?? void 0,
|
|
25955
|
+
borderStyle: normalizeBorderStyle(styles.get("border-style")) ?? parsedBorder?.borderStyle ?? void 0,
|
|
25956
|
+
borderWidth: normalizeBorderWidth(styles.get("border-width")) ?? parsedBorder?.borderWidth ?? void 0
|
|
25957
|
+
};
|
|
25958
|
+
}
|
|
25959
|
+
function parsePositiveInteger(value, max = 100) {
|
|
25960
|
+
if (!value) return null;
|
|
25961
|
+
const parsed = Number.parseInt(value, 10);
|
|
25962
|
+
if (!Number.isFinite(parsed) || parsed < 1) return null;
|
|
25963
|
+
return Math.min(parsed, max);
|
|
25964
|
+
}
|
|
25965
|
+
function parseCssSize(value) {
|
|
25966
|
+
const normalized = cleanStyleValue(value);
|
|
25967
|
+
if (!normalized) return null;
|
|
25968
|
+
const match = normalized.match(/^(\d+(?:\.\d+)?)(px|pt)?$/i);
|
|
25969
|
+
if (!match) return null;
|
|
25970
|
+
const amount = Number.parseFloat(match[1]);
|
|
25971
|
+
if (!Number.isFinite(amount) || amount <= 0) return null;
|
|
25972
|
+
return Math.round(match[2]?.toLowerCase() === "pt" ? amount * (4 / 3) : amount);
|
|
25973
|
+
}
|
|
25974
|
+
function getCellWidth(cell, styles, colspan) {
|
|
25975
|
+
if (colspan !== 1) return null;
|
|
25976
|
+
const width = parseCssSize(cell.getAttribute("data-colwidth") ?? cell.getAttribute("width") ?? styles.get("width"));
|
|
25977
|
+
return width ? [width] : null;
|
|
25978
|
+
}
|
|
25979
|
+
function getTableRowAttrs(row, styles) {
|
|
25980
|
+
const rowHeight = parseCssSize(
|
|
25981
|
+
row.getAttribute("data-row-height") ?? row.getAttribute("height") ?? styles.get("height")
|
|
25982
|
+
);
|
|
25983
|
+
return rowHeight ? { rowHeight } : void 0;
|
|
25984
|
+
}
|
|
25985
|
+
function getTableCellAttrs(cell, styles, defaultBackgroundColor) {
|
|
25986
|
+
const colspan = parsePositiveInteger(cell.getAttribute("colspan")) ?? 1;
|
|
25987
|
+
const rowspan = parsePositiveInteger(cell.getAttribute("rowspan")) ?? 1;
|
|
25988
|
+
const backgroundColor = getBackgroundColor(styles) ?? normalizeColorValue(cell.getAttribute("data-background-color")) ?? normalizeColorValue(cell.getAttribute("bgcolor")) ?? defaultBackgroundColor;
|
|
25989
|
+
const borderAttrs = getBorderAttrs(styles);
|
|
25990
|
+
const colwidth = getCellWidth(cell, styles, colspan);
|
|
25991
|
+
const attrs = {};
|
|
25992
|
+
if (backgroundColor) attrs.backgroundColor = backgroundColor;
|
|
25993
|
+
if (borderAttrs.borderColor) attrs.borderColor = borderAttrs.borderColor;
|
|
25994
|
+
if (borderAttrs.borderStyle) attrs.borderStyle = borderAttrs.borderStyle;
|
|
25995
|
+
if (borderAttrs.borderWidth) attrs.borderWidth = borderAttrs.borderWidth;
|
|
25996
|
+
if (colspan > 1) attrs.colspan = colspan;
|
|
25997
|
+
if (rowspan > 1) attrs.rowspan = rowspan;
|
|
25998
|
+
if (colwidth) attrs.colwidth = colwidth;
|
|
25999
|
+
return Object.keys(attrs).length > 0 ? attrs : void 0;
|
|
26000
|
+
}
|
|
26001
|
+
function marksEqual(left, right) {
|
|
26002
|
+
return JSON.stringify(left ?? []) === JSON.stringify(right ?? []);
|
|
26003
|
+
}
|
|
26004
|
+
function mergeMarks(base2, additions) {
|
|
26005
|
+
const next = [...base2 ?? []];
|
|
26006
|
+
for (const addition of additions ?? []) {
|
|
26007
|
+
const existingIndex = next.findIndex((mark) => mark.type === addition.type);
|
|
26008
|
+
if (existingIndex >= 0) {
|
|
26009
|
+
const existingMark = next[existingIndex];
|
|
26010
|
+
next[existingIndex] = {
|
|
26011
|
+
...existingMark,
|
|
26012
|
+
attrs: {
|
|
26013
|
+
...existingMark.attrs ?? {},
|
|
26014
|
+
...addition.attrs ?? {}
|
|
26015
|
+
}
|
|
26016
|
+
};
|
|
26017
|
+
continue;
|
|
26018
|
+
}
|
|
26019
|
+
next.push(addition);
|
|
26020
|
+
}
|
|
26021
|
+
return next.length > 0 ? next : void 0;
|
|
26022
|
+
}
|
|
26023
|
+
function getMarkColor(marks, markType) {
|
|
26024
|
+
const mark = marks?.find((candidate) => candidate.type === markType);
|
|
26025
|
+
const color = mark?.attrs?.color;
|
|
26026
|
+
return typeof color === "string" ? color : null;
|
|
26027
|
+
}
|
|
26028
|
+
function replaceTextStyleColor(marks, color) {
|
|
26029
|
+
let replaced = false;
|
|
26030
|
+
const next = (marks ?? []).map((mark) => {
|
|
26031
|
+
if (mark.type !== "textStyle") return mark;
|
|
26032
|
+
replaced = true;
|
|
26033
|
+
return {
|
|
26034
|
+
...mark,
|
|
26035
|
+
attrs: {
|
|
26036
|
+
...mark.attrs ?? {},
|
|
26037
|
+
color
|
|
26038
|
+
}
|
|
26039
|
+
};
|
|
26040
|
+
});
|
|
26041
|
+
if (!replaced) {
|
|
26042
|
+
next.unshift({ type: "textStyle", attrs: { color } });
|
|
26043
|
+
}
|
|
26044
|
+
return next;
|
|
26045
|
+
}
|
|
26046
|
+
function ensureReadableSpreadsheetSegments(segments, cellBackgroundColor) {
|
|
26047
|
+
return segments.map((segment) => {
|
|
26048
|
+
const textColor = getMarkColor(segment.marks, "textStyle");
|
|
26049
|
+
if (!isLightTextColor(textColor)) return segment;
|
|
26050
|
+
const inlineBackgroundColor = getMarkColor(segment.marks, "highlight");
|
|
26051
|
+
if (isDarkReadableBackground(inlineBackgroundColor) || isDarkReadableBackground(cellBackgroundColor)) {
|
|
26052
|
+
return segment;
|
|
26053
|
+
}
|
|
26054
|
+
return {
|
|
26055
|
+
...segment,
|
|
26056
|
+
marks: replaceTextStyleColor(segment.marks, DEFAULT_HTML_TABLE_TEXT_COLOR)
|
|
26057
|
+
};
|
|
26058
|
+
});
|
|
26059
|
+
}
|
|
26060
|
+
function getElementInlineMarks(element, styles) {
|
|
26061
|
+
const marks = [];
|
|
26062
|
+
const tagName = element.tagName;
|
|
26063
|
+
const color = normalizeTextColorValue(styles.get("color") ?? element.getAttribute("color"));
|
|
26064
|
+
const backgroundColor = getBackgroundColor(styles);
|
|
26065
|
+
const fontWeight = styles.get("font-weight")?.toLowerCase();
|
|
26066
|
+
const fontStyle = styles.get("font-style")?.toLowerCase();
|
|
26067
|
+
const textDecoration = styles.get("text-decoration")?.toLowerCase();
|
|
26068
|
+
if (color) {
|
|
26069
|
+
marks.push({ type: "textStyle", attrs: { color } });
|
|
26070
|
+
}
|
|
26071
|
+
if (backgroundColor && !isWhiteColor(backgroundColor)) {
|
|
26072
|
+
marks.push({ type: "highlight", attrs: { color: backgroundColor } });
|
|
26073
|
+
}
|
|
26074
|
+
if (tagName === "B" || tagName === "STRONG" || fontWeight === "bold" || /^\d+$/.test(fontWeight ?? "") && Number(fontWeight) >= 600) {
|
|
26075
|
+
marks.push({ type: "bold" });
|
|
26076
|
+
}
|
|
26077
|
+
if (tagName === "I" || tagName === "EM" || fontStyle === "italic") {
|
|
26078
|
+
marks.push({ type: "italic" });
|
|
26079
|
+
}
|
|
26080
|
+
if (tagName === "U" || textDecoration?.includes("underline")) {
|
|
26081
|
+
marks.push({ type: "underline" });
|
|
26082
|
+
}
|
|
26083
|
+
return marks.length > 0 ? marks : void 0;
|
|
26084
|
+
}
|
|
26085
|
+
function appendTextSegment(segments, segment) {
|
|
26086
|
+
if (!segment.text) return;
|
|
26087
|
+
const lastSegment = segments[segments.length - 1];
|
|
26088
|
+
if (lastSegment && marksEqual(lastSegment.marks, segment.marks)) {
|
|
26089
|
+
lastSegment.text += segment.text;
|
|
26090
|
+
return;
|
|
26091
|
+
}
|
|
26092
|
+
segments.push(segment);
|
|
26093
|
+
}
|
|
26094
|
+
function segmentsEndWithNewline(segments) {
|
|
26095
|
+
return segments.length > 0 && segments[segments.length - 1].text.endsWith("\n");
|
|
26096
|
+
}
|
|
26097
|
+
function normalizeClipboardTextSegments(segments) {
|
|
26098
|
+
const normalizedSegments = [];
|
|
26099
|
+
for (const segment of segments) {
|
|
26100
|
+
appendTextSegment(normalizedSegments, {
|
|
26101
|
+
text: segment.text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\u00a0/g, " "),
|
|
26102
|
+
marks: segment.marks
|
|
26103
|
+
});
|
|
26104
|
+
}
|
|
26105
|
+
while (normalizedSegments.length > 0) {
|
|
26106
|
+
const firstSegment = normalizedSegments[0];
|
|
26107
|
+
firstSegment.text = firstSegment.text.replace(/^\s+/, "");
|
|
26108
|
+
if (firstSegment.text) break;
|
|
26109
|
+
normalizedSegments.shift();
|
|
26110
|
+
}
|
|
26111
|
+
while (normalizedSegments.length > 0) {
|
|
26112
|
+
const lastSegment = normalizedSegments[normalizedSegments.length - 1];
|
|
26113
|
+
lastSegment.text = lastSegment.text.replace(/\s+$/, "");
|
|
26114
|
+
if (lastSegment.text) break;
|
|
26115
|
+
normalizedSegments.pop();
|
|
26116
|
+
}
|
|
26117
|
+
return normalizedSegments;
|
|
26118
|
+
}
|
|
25704
26119
|
function getClipboardCellText(node) {
|
|
25705
26120
|
if (node.nodeType === Node.TEXT_NODE) {
|
|
25706
26121
|
return node.textContent ?? "";
|
|
@@ -25718,57 +26133,205 @@ function getClipboardCellText(node) {
|
|
|
25718
26133
|
}
|
|
25719
26134
|
return childText;
|
|
25720
26135
|
}
|
|
25721
|
-
function
|
|
26136
|
+
function getClipboardCellSegments(node, styleMap, inheritedMarks) {
|
|
26137
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
26138
|
+
return [{ text: node.textContent ?? "", marks: inheritedMarks }];
|
|
26139
|
+
}
|
|
26140
|
+
if (!(node instanceof HTMLElement)) {
|
|
26141
|
+
return [];
|
|
26142
|
+
}
|
|
26143
|
+
if (node.tagName === "BR") {
|
|
26144
|
+
return [{ text: "\n", marks: inheritedMarks }];
|
|
26145
|
+
}
|
|
26146
|
+
const styles = getElementStyleDeclarations(node, styleMap);
|
|
26147
|
+
const marks = mergeMarks(inheritedMarks, getElementInlineMarks(node, styles));
|
|
26148
|
+
const segments = [];
|
|
26149
|
+
for (const childNode of Array.from(node.childNodes)) {
|
|
26150
|
+
for (const segment of getClipboardCellSegments(childNode, styleMap, marks)) {
|
|
26151
|
+
appendTextSegment(segments, segment);
|
|
26152
|
+
}
|
|
26153
|
+
}
|
|
26154
|
+
if ((node.tagName === "P" || node.tagName === "DIV" || node.tagName === "LI") && segments.length > 0 && !segmentsEndWithNewline(segments)) {
|
|
26155
|
+
appendTextSegment(segments, { text: "\n" });
|
|
26156
|
+
}
|
|
26157
|
+
return segments;
|
|
26158
|
+
}
|
|
26159
|
+
function getClipboardCellChildSegments(cell, styleMap, inheritedMarks) {
|
|
26160
|
+
const segments = [];
|
|
26161
|
+
for (const childNode of Array.from(cell.childNodes)) {
|
|
26162
|
+
for (const segment of getClipboardCellSegments(childNode, styleMap, inheritedMarks)) {
|
|
26163
|
+
appendTextSegment(segments, segment);
|
|
26164
|
+
}
|
|
26165
|
+
}
|
|
26166
|
+
return normalizeClipboardTextSegments(segments);
|
|
26167
|
+
}
|
|
26168
|
+
function getHtmlTableRows(table, styleMap) {
|
|
25722
26169
|
const rows = Array.from(table.querySelectorAll("tr")).map(
|
|
25723
|
-
(row) =>
|
|
25724
|
-
|
|
25725
|
-
|
|
25726
|
-
|
|
26170
|
+
(row) => ({
|
|
26171
|
+
attrs: getTableRowAttrs(row, getElementStyleDeclarations(row, styleMap)),
|
|
26172
|
+
cells: Array.from(row.children).filter((cell) => cell instanceof HTMLTableCellElement).map((cell) => {
|
|
26173
|
+
const styles = getElementStyleDeclarations(cell, styleMap);
|
|
26174
|
+
const textColor = normalizeTextColorValue(styles.get("color")) ?? DEFAULT_HTML_TABLE_TEXT_COLOR;
|
|
26175
|
+
const inheritedMarks = [{ type: "textStyle", attrs: { color: textColor } }];
|
|
26176
|
+
const attrs = getTableCellAttrs(cell, styles, DEFAULT_HTML_TABLE_CELL_BACKGROUND_COLOR);
|
|
26177
|
+
const segments = ensureReadableSpreadsheetSegments(
|
|
26178
|
+
getClipboardCellChildSegments(cell, styleMap, inheritedMarks),
|
|
26179
|
+
attrs?.backgroundColor
|
|
26180
|
+
);
|
|
26181
|
+
return {
|
|
26182
|
+
text: normalizeClipboardCellText(getClipboardCellText(cell)),
|
|
26183
|
+
isHeader: cell.tagName === "TH",
|
|
26184
|
+
attrs,
|
|
26185
|
+
segments: segments.length > 0 ? segments : void 0,
|
|
26186
|
+
textColor
|
|
26187
|
+
};
|
|
26188
|
+
})
|
|
26189
|
+
})
|
|
25727
26190
|
);
|
|
25728
|
-
return rows.filter((row) => row.length > 0);
|
|
26191
|
+
return rows.filter((row) => row.cells.length > 0);
|
|
26192
|
+
}
|
|
26193
|
+
function createTextMarks(cell) {
|
|
26194
|
+
return cell.textColor ? [{ type: "textStyle", attrs: { color: cell.textColor } }] : void 0;
|
|
25729
26195
|
}
|
|
25730
|
-
function createParagraphContent(text) {
|
|
26196
|
+
function createParagraphContent(text, marks) {
|
|
25731
26197
|
return text ? {
|
|
25732
26198
|
type: "paragraph",
|
|
25733
|
-
content: [{ type: "text", text }]
|
|
26199
|
+
content: [{ type: "text", text, ...marks ? { marks } : {} }]
|
|
25734
26200
|
} : { type: "paragraph" };
|
|
25735
26201
|
}
|
|
26202
|
+
function createParagraphContentFromSegments(segments) {
|
|
26203
|
+
const paragraphs = [[]];
|
|
26204
|
+
for (const segment of segments) {
|
|
26205
|
+
const parts = segment.text.split("\n");
|
|
26206
|
+
parts.forEach((part, index) => {
|
|
26207
|
+
if (part) {
|
|
26208
|
+
paragraphs[paragraphs.length - 1].push({ text: part, marks: segment.marks });
|
|
26209
|
+
}
|
|
26210
|
+
if (index < parts.length - 1) {
|
|
26211
|
+
paragraphs.push([]);
|
|
26212
|
+
}
|
|
26213
|
+
});
|
|
26214
|
+
}
|
|
26215
|
+
return paragraphs.map((paragraphSegments) => {
|
|
26216
|
+
const content = paragraphSegments.map((segment) => ({
|
|
26217
|
+
type: "text",
|
|
26218
|
+
text: segment.text,
|
|
26219
|
+
...segment.marks ? { marks: segment.marks } : {}
|
|
26220
|
+
}));
|
|
26221
|
+
return content.length > 0 ? { type: "paragraph", content } : { type: "paragraph" };
|
|
26222
|
+
});
|
|
26223
|
+
}
|
|
25736
26224
|
function createTableCellContent(cell) {
|
|
25737
26225
|
const lines = cell.text.split("\n");
|
|
25738
|
-
const
|
|
26226
|
+
const marks = createTextMarks(cell);
|
|
26227
|
+
const paragraphs = cell.segments && cell.segments.length > 0 ? createParagraphContentFromSegments(cell.segments) : (lines.length > 0 ? lines : [""]).map((line) => createParagraphContent(line, marks));
|
|
25739
26228
|
return {
|
|
25740
26229
|
type: cell.isHeader ? "tableHeader" : "tableCell",
|
|
26230
|
+
...cell.attrs ? { attrs: cell.attrs } : {},
|
|
25741
26231
|
content: paragraphs.length > 0 ? paragraphs : [{ type: "paragraph" }]
|
|
25742
26232
|
};
|
|
25743
26233
|
}
|
|
25744
|
-
function
|
|
25745
|
-
const
|
|
26234
|
+
function getRowspanLimitedCell(cell, remainingRowCount) {
|
|
26235
|
+
const attrs = cell.attrs;
|
|
26236
|
+
if (!attrs?.rowspan || attrs.rowspan <= remainingRowCount) return cell;
|
|
26237
|
+
if (remainingRowCount <= 1) {
|
|
26238
|
+
const { rowspan: _rowspan, ...nextAttrs } = attrs;
|
|
26239
|
+
return {
|
|
26240
|
+
...cell,
|
|
26241
|
+
attrs: Object.keys(nextAttrs).length > 0 ? nextAttrs : void 0
|
|
26242
|
+
};
|
|
26243
|
+
}
|
|
26244
|
+
return {
|
|
26245
|
+
...cell,
|
|
26246
|
+
attrs: {
|
|
26247
|
+
...attrs,
|
|
26248
|
+
rowspan: remainingRowCount
|
|
26249
|
+
}
|
|
26250
|
+
};
|
|
26251
|
+
}
|
|
26252
|
+
function normalizeTableRows(rows) {
|
|
26253
|
+
const positionedRows = [];
|
|
26254
|
+
let rowspans = [];
|
|
26255
|
+
let columnCount = 0;
|
|
26256
|
+
rows.forEach((row, rowIndex) => {
|
|
26257
|
+
const coveredColumns = rowspans.map((span) => span > 0);
|
|
26258
|
+
const nextRowspans = rowspans.map((span) => Math.max(0, span - 1));
|
|
26259
|
+
const positionedCells = [];
|
|
26260
|
+
let columnIndex = 0;
|
|
26261
|
+
for (const rawCell of row.cells) {
|
|
26262
|
+
while (coveredColumns[columnIndex]) columnIndex += 1;
|
|
26263
|
+
const remainingRowCount = rows.length - rowIndex;
|
|
26264
|
+
const cell = getRowspanLimitedCell(rawCell, remainingRowCount);
|
|
26265
|
+
const colspan = Math.max(1, cell.attrs?.colspan ?? 1);
|
|
26266
|
+
const rowspan = Math.max(1, cell.attrs?.rowspan ?? 1);
|
|
26267
|
+
positionedCells.push({ startColumn: columnIndex, colspan, cell });
|
|
26268
|
+
if (rowspan > 1) {
|
|
26269
|
+
for (let offset = 0; offset < colspan; offset += 1) {
|
|
26270
|
+
const spannedColumn = columnIndex + offset;
|
|
26271
|
+
nextRowspans[spannedColumn] = Math.max(nextRowspans[spannedColumn] ?? 0, rowspan - 1);
|
|
26272
|
+
}
|
|
26273
|
+
}
|
|
26274
|
+
columnIndex += colspan;
|
|
26275
|
+
}
|
|
26276
|
+
const lastCoveredColumn = coveredColumns.reduce((lastIndex, covered, index) => covered ? index : lastIndex, -1);
|
|
26277
|
+
const lastFutureRowspanColumn = nextRowspans.reduce((lastIndex, span, index) => span > 0 ? index : lastIndex, -1);
|
|
26278
|
+
columnCount = Math.max(columnCount, columnIndex, lastCoveredColumn + 1, lastFutureRowspanColumn + 1);
|
|
26279
|
+
positionedRows.push({
|
|
26280
|
+
attrs: row.attrs,
|
|
26281
|
+
cells: positionedCells,
|
|
26282
|
+
coveredColumns
|
|
26283
|
+
});
|
|
26284
|
+
rowspans = nextRowspans;
|
|
26285
|
+
});
|
|
26286
|
+
return { positionedRows, columnCount };
|
|
26287
|
+
}
|
|
26288
|
+
function createNormalizedRowContent(row, columnCount, fillerCellAttrs) {
|
|
26289
|
+
const content = [];
|
|
26290
|
+
const cellByStartColumn = new Map(row.cells.map((cell) => [cell.startColumn, cell]));
|
|
26291
|
+
let columnIndex = 0;
|
|
26292
|
+
while (columnIndex < columnCount) {
|
|
26293
|
+
if (row.coveredColumns[columnIndex]) {
|
|
26294
|
+
columnIndex += 1;
|
|
26295
|
+
continue;
|
|
26296
|
+
}
|
|
26297
|
+
const positionedCell = cellByStartColumn.get(columnIndex);
|
|
26298
|
+
if (positionedCell) {
|
|
26299
|
+
content.push(createTableCellContent(positionedCell.cell));
|
|
26300
|
+
columnIndex += positionedCell.colspan;
|
|
26301
|
+
continue;
|
|
26302
|
+
}
|
|
26303
|
+
content.push(createTableCellContent({ text: "", isHeader: false, attrs: fillerCellAttrs }));
|
|
26304
|
+
columnIndex += 1;
|
|
26305
|
+
}
|
|
26306
|
+
return content;
|
|
26307
|
+
}
|
|
26308
|
+
function createTableContent(rows, minColumnCount = 1, fillerCellAttrs) {
|
|
26309
|
+
const tableRows = rows.filter((row) => row.cells.length > 0);
|
|
25746
26310
|
if (tableRows.length === 0) return null;
|
|
25747
|
-
const
|
|
26311
|
+
const { positionedRows, columnCount } = normalizeTableRows(tableRows);
|
|
25748
26312
|
if (columnCount < minColumnCount) return null;
|
|
25749
26313
|
return {
|
|
25750
26314
|
type: "table",
|
|
25751
|
-
content:
|
|
25752
|
-
|
|
25753
|
-
|
|
25754
|
-
|
|
25755
|
-
|
|
25756
|
-
return {
|
|
25757
|
-
type: "tableRow",
|
|
25758
|
-
content: normalizedRow.map(createTableCellContent)
|
|
25759
|
-
};
|
|
25760
|
-
})
|
|
26315
|
+
content: positionedRows.map((row) => ({
|
|
26316
|
+
type: "tableRow",
|
|
26317
|
+
...row.attrs ? { attrs: row.attrs } : {},
|
|
26318
|
+
content: createNormalizedRowContent(row, columnCount, fillerCellAttrs)
|
|
26319
|
+
}))
|
|
25761
26320
|
};
|
|
25762
26321
|
}
|
|
25763
26322
|
function getClipboardTableContent(dataTransfer) {
|
|
25764
26323
|
const html = getClipboardData(dataTransfer, "text/html");
|
|
25765
26324
|
if (!/<table(?:\s|>)/i.test(html)) return null;
|
|
25766
26325
|
if (typeof DOMParser === "undefined") return null;
|
|
26326
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
25767
26327
|
const fragment = extractClipboardHtmlFragment(html);
|
|
25768
|
-
const
|
|
25769
|
-
const
|
|
26328
|
+
const fragmentDoc = new DOMParser().parseFromString(fragment, "text/html");
|
|
26329
|
+
const styleMap = parseClipboardCssClassStyles(doc);
|
|
26330
|
+
const table = fragmentDoc.querySelector("table") ?? doc.querySelector("table");
|
|
25770
26331
|
if (!(table instanceof HTMLTableElement)) return null;
|
|
25771
|
-
return createTableContent(getHtmlTableRows(table)
|
|
26332
|
+
return createTableContent(getHtmlTableRows(table, styleMap), 1, {
|
|
26333
|
+
backgroundColor: DEFAULT_HTML_TABLE_CELL_BACKGROUND_COLOR
|
|
26334
|
+
});
|
|
25772
26335
|
}
|
|
25773
26336
|
function parseClipboardTsvRows(text) {
|
|
25774
26337
|
const rows = [];
|
|
@@ -25825,7 +26388,9 @@ function getClipboardTsvTableContent(dataTransfer) {
|
|
|
25825
26388
|
if (!text.includes(" ")) return null;
|
|
25826
26389
|
const rows = parseClipboardTsvRows(text);
|
|
25827
26390
|
return createTableContent(
|
|
25828
|
-
rows.map((row) =>
|
|
26391
|
+
rows.map((row) => ({
|
|
26392
|
+
cells: row.map((cell) => ({ text: normalizeClipboardCellText(cell), isHeader: false }))
|
|
26393
|
+
})),
|
|
25829
26394
|
2
|
|
25830
26395
|
);
|
|
25831
26396
|
}
|
|
@@ -27100,6 +27665,46 @@ var CustomTableCell = TableCell2.extend({
|
|
|
27100
27665
|
"data-border-width": attributes.borderWidth
|
|
27101
27666
|
};
|
|
27102
27667
|
}
|
|
27668
|
+
},
|
|
27669
|
+
cellId: {
|
|
27670
|
+
default: null,
|
|
27671
|
+
parseHTML: (element) => element.getAttribute("data-cell-id") || null,
|
|
27672
|
+
renderHTML: (attributes) => {
|
|
27673
|
+
if (!attributes.cellId) return {};
|
|
27674
|
+
return {
|
|
27675
|
+
"data-cell-id": attributes.cellId
|
|
27676
|
+
};
|
|
27677
|
+
}
|
|
27678
|
+
},
|
|
27679
|
+
numberFormat: {
|
|
27680
|
+
default: null,
|
|
27681
|
+
parseHTML: (element) => element.getAttribute("data-number-format") || null,
|
|
27682
|
+
renderHTML: (attributes) => {
|
|
27683
|
+
if (!attributes.numberFormat) return {};
|
|
27684
|
+
return {
|
|
27685
|
+
"data-number-format": attributes.numberFormat
|
|
27686
|
+
};
|
|
27687
|
+
}
|
|
27688
|
+
},
|
|
27689
|
+
formula: {
|
|
27690
|
+
default: null,
|
|
27691
|
+
parseHTML: (element) => element.getAttribute("data-formula") || null,
|
|
27692
|
+
renderHTML: (attributes) => {
|
|
27693
|
+
if (!attributes.formula) return {};
|
|
27694
|
+
return {
|
|
27695
|
+
"data-formula": attributes.formula
|
|
27696
|
+
};
|
|
27697
|
+
}
|
|
27698
|
+
},
|
|
27699
|
+
computedValue: {
|
|
27700
|
+
default: null,
|
|
27701
|
+
parseHTML: (element) => element.getAttribute("data-computed-value") || null,
|
|
27702
|
+
renderHTML: (attributes) => {
|
|
27703
|
+
if (!attributes.computedValue) return {};
|
|
27704
|
+
return {
|
|
27705
|
+
"data-computed-value": attributes.computedValue
|
|
27706
|
+
};
|
|
27707
|
+
}
|
|
27103
27708
|
}
|
|
27104
27709
|
};
|
|
27105
27710
|
},
|
|
@@ -27167,6 +27772,46 @@ var CustomTableHeader = TableHeader2.extend({
|
|
|
27167
27772
|
"data-border-width": attributes.borderWidth
|
|
27168
27773
|
};
|
|
27169
27774
|
}
|
|
27775
|
+
},
|
|
27776
|
+
cellId: {
|
|
27777
|
+
default: null,
|
|
27778
|
+
parseHTML: (element) => element.getAttribute("data-cell-id") || null,
|
|
27779
|
+
renderHTML: (attributes) => {
|
|
27780
|
+
if (!attributes.cellId) return {};
|
|
27781
|
+
return {
|
|
27782
|
+
"data-cell-id": attributes.cellId
|
|
27783
|
+
};
|
|
27784
|
+
}
|
|
27785
|
+
},
|
|
27786
|
+
numberFormat: {
|
|
27787
|
+
default: null,
|
|
27788
|
+
parseHTML: (element) => element.getAttribute("data-number-format") || null,
|
|
27789
|
+
renderHTML: (attributes) => {
|
|
27790
|
+
if (!attributes.numberFormat) return {};
|
|
27791
|
+
return {
|
|
27792
|
+
"data-number-format": attributes.numberFormat
|
|
27793
|
+
};
|
|
27794
|
+
}
|
|
27795
|
+
},
|
|
27796
|
+
formula: {
|
|
27797
|
+
default: null,
|
|
27798
|
+
parseHTML: (element) => element.getAttribute("data-formula") || null,
|
|
27799
|
+
renderHTML: (attributes) => {
|
|
27800
|
+
if (!attributes.formula) return {};
|
|
27801
|
+
return {
|
|
27802
|
+
"data-formula": attributes.formula
|
|
27803
|
+
};
|
|
27804
|
+
}
|
|
27805
|
+
},
|
|
27806
|
+
computedValue: {
|
|
27807
|
+
default: null,
|
|
27808
|
+
parseHTML: (element) => element.getAttribute("data-computed-value") || null,
|
|
27809
|
+
renderHTML: (attributes) => {
|
|
27810
|
+
if (!attributes.computedValue) return {};
|
|
27811
|
+
return {
|
|
27812
|
+
"data-computed-value": attributes.computedValue
|
|
27813
|
+
};
|
|
27814
|
+
}
|
|
27170
27815
|
}
|
|
27171
27816
|
};
|
|
27172
27817
|
},
|
|
@@ -27917,6 +28562,34 @@ function collectChildren(node) {
|
|
|
27917
28562
|
function createEmptyCellNode(cellNode) {
|
|
27918
28563
|
return cellNode.type.createAndFill(cellNode.attrs) ?? cellNode;
|
|
27919
28564
|
}
|
|
28565
|
+
function createCellCopyForColumnDuplicate(cellNode) {
|
|
28566
|
+
return cellNode.type.create(cellNode.attrs, cellNode.content);
|
|
28567
|
+
}
|
|
28568
|
+
function getTableRows(tableNode) {
|
|
28569
|
+
const rows = [];
|
|
28570
|
+
tableNode.forEach((rowNode, rowOffset) => {
|
|
28571
|
+
const cells = [];
|
|
28572
|
+
rowNode.forEach((cellNode, cellOffset, index) => {
|
|
28573
|
+
cells.push({
|
|
28574
|
+
index,
|
|
28575
|
+
node: cellNode,
|
|
28576
|
+
relativePos: rowOffset + 1 + cellOffset
|
|
28577
|
+
});
|
|
28578
|
+
});
|
|
28579
|
+
rows.push({
|
|
28580
|
+
node: rowNode,
|
|
28581
|
+
cells
|
|
28582
|
+
});
|
|
28583
|
+
});
|
|
28584
|
+
return rows;
|
|
28585
|
+
}
|
|
28586
|
+
function safeFindCell(map, relativePos) {
|
|
28587
|
+
try {
|
|
28588
|
+
return map.findCell(relativePos);
|
|
28589
|
+
} catch {
|
|
28590
|
+
return null;
|
|
28591
|
+
}
|
|
28592
|
+
}
|
|
27920
28593
|
function getSelectedTableRect(editor) {
|
|
27921
28594
|
const cellSelection = getCellSelectionPositions(editor.state.selection);
|
|
27922
28595
|
if (cellSelection) {
|
|
@@ -28042,34 +28715,49 @@ function duplicateTableRowAt(editor, rowIndex, cellPos) {
|
|
|
28042
28715
|
}
|
|
28043
28716
|
function clearTableRowAt(editor, rowIndex, cellPos) {
|
|
28044
28717
|
return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
|
|
28045
|
-
const
|
|
28046
|
-
|
|
28047
|
-
|
|
28048
|
-
|
|
28049
|
-
|
|
28718
|
+
const map = TableMap.get(tableNode);
|
|
28719
|
+
if (rowIndex < 0 || rowIndex >= map.height) return null;
|
|
28720
|
+
const rows = getTableRows(tableNode).map((rowInfo) => {
|
|
28721
|
+
const cells = collectChildren(rowInfo.node);
|
|
28722
|
+
for (const entry of rowInfo.cells) {
|
|
28723
|
+
const rect = safeFindCell(map, entry.relativePos);
|
|
28724
|
+
if (!rect || rect.top > rowIndex || rowIndex >= rect.bottom) continue;
|
|
28725
|
+
cells[entry.index] = createEmptyCellNode(entry.node);
|
|
28726
|
+
}
|
|
28727
|
+
return rowInfo.node.type.create(rowInfo.node.attrs, cells);
|
|
28728
|
+
});
|
|
28050
28729
|
return tableNode.type.create(tableNode.attrs, rows);
|
|
28051
28730
|
});
|
|
28052
28731
|
}
|
|
28053
28732
|
function duplicateTableColumnAt(editor, columnIndex, cellPos) {
|
|
28054
28733
|
return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
|
|
28055
|
-
const
|
|
28056
|
-
|
|
28057
|
-
|
|
28058
|
-
|
|
28059
|
-
|
|
28060
|
-
|
|
28734
|
+
const map = TableMap.get(tableNode);
|
|
28735
|
+
if (columnIndex < 0 || columnIndex >= map.width) return null;
|
|
28736
|
+
const rows = getTableRows(tableNode).map((rowInfo, rowIndex) => {
|
|
28737
|
+
const cells = collectChildren(rowInfo.node);
|
|
28738
|
+
const sourceCell = rowInfo.cells.find((entry) => {
|
|
28739
|
+
const rect = safeFindCell(map, entry.relativePos);
|
|
28740
|
+
return rect && rect.top === rowIndex && rect.left <= columnIndex && columnIndex < rect.right;
|
|
28741
|
+
});
|
|
28742
|
+
if (!sourceCell) return rowInfo.node;
|
|
28743
|
+
cells.splice(sourceCell.index + 1, 0, createCellCopyForColumnDuplicate(sourceCell.node));
|
|
28744
|
+
return rowInfo.node.type.create(rowInfo.node.attrs, cells);
|
|
28061
28745
|
});
|
|
28062
28746
|
return tableNode.type.create(tableNode.attrs, rows);
|
|
28063
28747
|
});
|
|
28064
28748
|
}
|
|
28065
28749
|
function clearTableColumnAt(editor, columnIndex, cellPos) {
|
|
28066
28750
|
return replaceTableAtCellPos(editor, cellPos, (tableNode) => {
|
|
28067
|
-
const
|
|
28068
|
-
|
|
28069
|
-
|
|
28070
|
-
|
|
28071
|
-
|
|
28072
|
-
|
|
28751
|
+
const map = TableMap.get(tableNode);
|
|
28752
|
+
if (columnIndex < 0 || columnIndex >= map.width) return null;
|
|
28753
|
+
const rows = getTableRows(tableNode).map((rowInfo) => {
|
|
28754
|
+
const cells = collectChildren(rowInfo.node);
|
|
28755
|
+
for (const entry of rowInfo.cells) {
|
|
28756
|
+
const rect = safeFindCell(map, entry.relativePos);
|
|
28757
|
+
if (!rect || rect.left > columnIndex || columnIndex >= rect.right) continue;
|
|
28758
|
+
cells[entry.index] = createEmptyCellNode(entry.node);
|
|
28759
|
+
}
|
|
28760
|
+
return rowInfo.node.type.create(rowInfo.node.attrs, cells);
|
|
28073
28761
|
});
|
|
28074
28762
|
return tableNode.type.create(tableNode.attrs, rows);
|
|
28075
28763
|
});
|
|
@@ -29121,7 +29809,7 @@ var EditorToolbar = ({
|
|
|
29121
29809
|
// src/components/UEditor/menus.tsx
|
|
29122
29810
|
import { useCallback as useCallback22, useEffect as useEffect36, useMemo as useMemo23, useRef as useRef33, useState as useState48 } from "react";
|
|
29123
29811
|
import { useEditorState as useEditorState2 } from "@tiptap/react";
|
|
29124
|
-
import { isInTable as isSelectionInTable, setCellAttr } from "@tiptap/pm/tables";
|
|
29812
|
+
import { isInTable as isSelectionInTable, setCellAttr as setCellAttr2 } from "@tiptap/pm/tables";
|
|
29125
29813
|
import { createPortal as createPortal8 } from "react-dom";
|
|
29126
29814
|
import {
|
|
29127
29815
|
AlignCenter as AlignCenter2,
|
|
@@ -29143,13 +29831,410 @@ import {
|
|
|
29143
29831
|
Strikethrough as StrikethroughIcon2,
|
|
29144
29832
|
Edit2,
|
|
29145
29833
|
Unlink,
|
|
29146
|
-
ExternalLink as ExternalLink3
|
|
29834
|
+
ExternalLink as ExternalLink3,
|
|
29835
|
+
Sigma
|
|
29147
29836
|
} from "lucide-react";
|
|
29837
|
+
|
|
29838
|
+
// src/components/UEditor/table-formula-commands.ts
|
|
29839
|
+
import { selectedRect as selectedRect2, setCellAttr, TableMap as TableMap2 } from "@tiptap/pm/tables";
|
|
29840
|
+
|
|
29841
|
+
// src/components/UEditor/table-formula.ts
|
|
29842
|
+
var CELL_ADDRESS_RE = /^([A-Z]+)([1-9]\d*)$/i;
|
|
29843
|
+
var CELL_RANGE_RE = /^([A-Z]+[1-9]\d*):([A-Z]+[1-9]\d*)$/i;
|
|
29844
|
+
var SUPPORTED_FUNCTIONS = /* @__PURE__ */ new Set(["SUM", "AVG", "MIN", "MAX", "COUNT"]);
|
|
29845
|
+
function columnNameToIndex(columnName) {
|
|
29846
|
+
const normalized = columnName.trim().toUpperCase();
|
|
29847
|
+
if (!/^[A-Z]+$/.test(normalized)) {
|
|
29848
|
+
return -1;
|
|
29849
|
+
}
|
|
29850
|
+
let index = 0;
|
|
29851
|
+
for (const char of normalized) {
|
|
29852
|
+
index = index * 26 + char.charCodeAt(0) - 64;
|
|
29853
|
+
}
|
|
29854
|
+
return index - 1;
|
|
29855
|
+
}
|
|
29856
|
+
function indexToColumnName(index) {
|
|
29857
|
+
if (!Number.isInteger(index) || index < 0) {
|
|
29858
|
+
return "";
|
|
29859
|
+
}
|
|
29860
|
+
let value = index + 1;
|
|
29861
|
+
let name = "";
|
|
29862
|
+
while (value > 0) {
|
|
29863
|
+
const remainder = (value - 1) % 26;
|
|
29864
|
+
name = String.fromCharCode(65 + remainder) + name;
|
|
29865
|
+
value = Math.floor((value - 1) / 26);
|
|
29866
|
+
}
|
|
29867
|
+
return name;
|
|
29868
|
+
}
|
|
29869
|
+
function parseTableCellAddress(input) {
|
|
29870
|
+
const match = input.trim().match(CELL_ADDRESS_RE);
|
|
29871
|
+
if (!match) {
|
|
29872
|
+
return null;
|
|
29873
|
+
}
|
|
29874
|
+
const column = columnNameToIndex(match[1] ?? "");
|
|
29875
|
+
const row = Number.parseInt(match[2] ?? "", 10) - 1;
|
|
29876
|
+
if (column < 0 || row < 0) {
|
|
29877
|
+
return null;
|
|
29878
|
+
}
|
|
29879
|
+
return {
|
|
29880
|
+
column,
|
|
29881
|
+
row,
|
|
29882
|
+
label: `${indexToColumnName(column)}${row + 1}`
|
|
29883
|
+
};
|
|
29884
|
+
}
|
|
29885
|
+
function parseTableCellRange(input) {
|
|
29886
|
+
const match = input.trim().match(CELL_RANGE_RE);
|
|
29887
|
+
if (!match) {
|
|
29888
|
+
return null;
|
|
29889
|
+
}
|
|
29890
|
+
const from = parseTableCellAddress(match[1] ?? "");
|
|
29891
|
+
const to = parseTableCellAddress(match[2] ?? "");
|
|
29892
|
+
if (!from || !to) {
|
|
29893
|
+
return null;
|
|
29894
|
+
}
|
|
29895
|
+
return { from, to };
|
|
29896
|
+
}
|
|
29897
|
+
function getTableCellRangeLabels(range) {
|
|
29898
|
+
const startColumn = Math.min(range.from.column, range.to.column);
|
|
29899
|
+
const endColumn = Math.max(range.from.column, range.to.column);
|
|
29900
|
+
const startRow = Math.min(range.from.row, range.to.row);
|
|
29901
|
+
const endRow = Math.max(range.from.row, range.to.row);
|
|
29902
|
+
const labels = [];
|
|
29903
|
+
for (let row = startRow; row <= endRow; row += 1) {
|
|
29904
|
+
for (let column = startColumn; column <= endColumn; column += 1) {
|
|
29905
|
+
labels.push(`${indexToColumnName(column)}${row + 1}`);
|
|
29906
|
+
}
|
|
29907
|
+
}
|
|
29908
|
+
return labels;
|
|
29909
|
+
}
|
|
29910
|
+
function normalizeTableFormula(formula) {
|
|
29911
|
+
return formula.trim().replace(/^=/, "").trim();
|
|
29912
|
+
}
|
|
29913
|
+
function evaluateBasicTableFormula(formula, getCellValue) {
|
|
29914
|
+
const normalized = normalizeTableFormula(formula);
|
|
29915
|
+
if (!normalized) {
|
|
29916
|
+
return { value: null, error: "empty" };
|
|
29917
|
+
}
|
|
29918
|
+
const tokens = tokenizeFormula(normalized);
|
|
29919
|
+
if (!tokens) {
|
|
29920
|
+
return { value: null, error: "invalid-formula" };
|
|
29921
|
+
}
|
|
29922
|
+
const parser = new FormulaParser(tokens, getCellValue);
|
|
29923
|
+
const result = parser.parseExpression();
|
|
29924
|
+
if (result.error) {
|
|
29925
|
+
return result;
|
|
29926
|
+
}
|
|
29927
|
+
if (!parser.isComplete()) {
|
|
29928
|
+
return { value: null, error: "invalid-formula" };
|
|
29929
|
+
}
|
|
29930
|
+
return result;
|
|
29931
|
+
}
|
|
29932
|
+
function tokenizeFormula(formula) {
|
|
29933
|
+
const tokens = [];
|
|
29934
|
+
let index = 0;
|
|
29935
|
+
while (index < formula.length) {
|
|
29936
|
+
const char = formula[index];
|
|
29937
|
+
if (!char) break;
|
|
29938
|
+
if (/\s/.test(char)) {
|
|
29939
|
+
index += 1;
|
|
29940
|
+
continue;
|
|
29941
|
+
}
|
|
29942
|
+
if (char === "," || char === "+" || char === "-" || char === "*" || char === "/" || char === "(" || char === ")") {
|
|
29943
|
+
if (char === ",") tokens.push({ type: "comma", value: char });
|
|
29944
|
+
else if (char === "(" || char === ")") tokens.push({ type: "paren", value: char });
|
|
29945
|
+
else tokens.push({ type: "operator", value: char });
|
|
29946
|
+
index += 1;
|
|
29947
|
+
continue;
|
|
29948
|
+
}
|
|
29949
|
+
const numberMatch = formula.slice(index).match(/^\d+(?:\.\d+)?/);
|
|
29950
|
+
if (numberMatch?.[0]) {
|
|
29951
|
+
tokens.push({ type: "number", value: Number.parseFloat(numberMatch[0]) });
|
|
29952
|
+
index += numberMatch[0].length;
|
|
29953
|
+
continue;
|
|
29954
|
+
}
|
|
29955
|
+
const identifierMatch = formula.slice(index).match(/^[A-Z]+[1-9]\d*(?::[A-Z]+[1-9]\d*)?|^[A-Z]+/i);
|
|
29956
|
+
if (identifierMatch?.[0]) {
|
|
29957
|
+
const value = identifierMatch[0].toUpperCase();
|
|
29958
|
+
if (CELL_RANGE_RE.test(value)) tokens.push({ type: "range", value });
|
|
29959
|
+
else if (parseTableCellAddress(value)) tokens.push({ type: "cell", value });
|
|
29960
|
+
else if (SUPPORTED_FUNCTIONS.has(value)) tokens.push({ type: "function", value });
|
|
29961
|
+
else return null;
|
|
29962
|
+
index += identifierMatch[0].length;
|
|
29963
|
+
continue;
|
|
29964
|
+
}
|
|
29965
|
+
return null;
|
|
29966
|
+
}
|
|
29967
|
+
return tokens;
|
|
29968
|
+
}
|
|
29969
|
+
var FormulaParser = class {
|
|
29970
|
+
constructor(tokens, getCellValue) {
|
|
29971
|
+
this.tokens = tokens;
|
|
29972
|
+
this.getCellValue = getCellValue;
|
|
29973
|
+
this.index = 0;
|
|
29974
|
+
}
|
|
29975
|
+
isComplete() {
|
|
29976
|
+
return this.index >= this.tokens.length;
|
|
29977
|
+
}
|
|
29978
|
+
parseExpression() {
|
|
29979
|
+
let left = this.parseTerm();
|
|
29980
|
+
while (!left.error) {
|
|
29981
|
+
const operator = this.peekOperator(["+", "-"]);
|
|
29982
|
+
if (!operator) break;
|
|
29983
|
+
this.index += 1;
|
|
29984
|
+
const right = this.parseTerm();
|
|
29985
|
+
if (right.error) return right;
|
|
29986
|
+
left = {
|
|
29987
|
+
value: operator.value === "+" ? left.value + right.value : left.value - right.value,
|
|
29988
|
+
error: null
|
|
29989
|
+
};
|
|
29990
|
+
}
|
|
29991
|
+
return left;
|
|
29992
|
+
}
|
|
29993
|
+
parseTerm() {
|
|
29994
|
+
let left = this.parseFactor();
|
|
29995
|
+
while (!left.error) {
|
|
29996
|
+
const operator = this.peekOperator(["*", "/"]);
|
|
29997
|
+
if (!operator) break;
|
|
29998
|
+
this.index += 1;
|
|
29999
|
+
const right = this.parseFactor();
|
|
30000
|
+
if (right.error) return right;
|
|
30001
|
+
if (operator.value === "/" && right.value === 0) {
|
|
30002
|
+
return { value: null, error: "division-by-zero" };
|
|
30003
|
+
}
|
|
30004
|
+
left = {
|
|
30005
|
+
value: operator.value === "*" ? left.value * right.value : left.value / right.value,
|
|
30006
|
+
error: null
|
|
30007
|
+
};
|
|
30008
|
+
}
|
|
30009
|
+
return left;
|
|
30010
|
+
}
|
|
30011
|
+
parseFactor() {
|
|
30012
|
+
const token = this.tokens[this.index];
|
|
30013
|
+
if (!token) {
|
|
30014
|
+
return { value: null, error: "invalid-formula" };
|
|
30015
|
+
}
|
|
30016
|
+
if (token.type === "operator" && token.value === "-") {
|
|
30017
|
+
this.index += 1;
|
|
30018
|
+
const value = this.parseFactor();
|
|
30019
|
+
if (value.error) return value;
|
|
30020
|
+
return { value: -value.value, error: null };
|
|
30021
|
+
}
|
|
30022
|
+
if (token.type === "number") {
|
|
30023
|
+
this.index += 1;
|
|
30024
|
+
return { value: token.value, error: null };
|
|
30025
|
+
}
|
|
30026
|
+
if (token.type === "cell") {
|
|
30027
|
+
this.index += 1;
|
|
30028
|
+
return this.readCellNumber(token.value);
|
|
30029
|
+
}
|
|
30030
|
+
if (token.type === "function") {
|
|
30031
|
+
return this.parseFunction(token.value);
|
|
30032
|
+
}
|
|
30033
|
+
if (token.type === "paren" && token.value === "(") {
|
|
30034
|
+
this.index += 1;
|
|
30035
|
+
const value = this.parseExpression();
|
|
30036
|
+
if (value.error) return value;
|
|
30037
|
+
if (!this.consumeParen(")")) {
|
|
30038
|
+
return { value: null, error: "invalid-formula" };
|
|
30039
|
+
}
|
|
30040
|
+
return value;
|
|
30041
|
+
}
|
|
30042
|
+
return { value: null, error: "invalid-formula" };
|
|
30043
|
+
}
|
|
30044
|
+
parseFunction(name) {
|
|
30045
|
+
this.index += 1;
|
|
30046
|
+
if (!this.consumeParen("(")) {
|
|
30047
|
+
return { value: null, error: "invalid-formula" };
|
|
30048
|
+
}
|
|
30049
|
+
const values = [];
|
|
30050
|
+
while (true) {
|
|
30051
|
+
const token = this.tokens[this.index];
|
|
30052
|
+
if (!token) {
|
|
30053
|
+
return { value: null, error: "invalid-formula" };
|
|
30054
|
+
}
|
|
30055
|
+
if (token.type === "range") {
|
|
30056
|
+
this.index += 1;
|
|
30057
|
+
const range = parseTableCellRange(token.value);
|
|
30058
|
+
if (!range) return { value: null, error: "invalid-reference" };
|
|
30059
|
+
for (const label of getTableCellRangeLabels(range)) {
|
|
30060
|
+
const cellValue = this.readCellNumber(label);
|
|
30061
|
+
if (cellValue.error) return cellValue;
|
|
30062
|
+
values.push(cellValue.value);
|
|
30063
|
+
}
|
|
30064
|
+
} else {
|
|
30065
|
+
const value = this.parseExpression();
|
|
30066
|
+
if (value.error) return value;
|
|
30067
|
+
values.push(value.value);
|
|
30068
|
+
}
|
|
30069
|
+
if (this.consumeComma()) {
|
|
30070
|
+
continue;
|
|
30071
|
+
}
|
|
30072
|
+
if (this.consumeParen(")")) {
|
|
30073
|
+
break;
|
|
30074
|
+
}
|
|
30075
|
+
return { value: null, error: "invalid-formula" };
|
|
30076
|
+
}
|
|
30077
|
+
if (values.length === 0) {
|
|
30078
|
+
return { value: null, error: "invalid-formula" };
|
|
30079
|
+
}
|
|
30080
|
+
if (name === "SUM") return { value: values.reduce((sum, value) => sum + value, 0), error: null };
|
|
30081
|
+
if (name === "AVG") return { value: values.reduce((sum, value) => sum + value, 0) / values.length, error: null };
|
|
30082
|
+
if (name === "MIN") return { value: Math.min(...values), error: null };
|
|
30083
|
+
if (name === "MAX") return { value: Math.max(...values), error: null };
|
|
30084
|
+
if (name === "COUNT") return { value: values.length, error: null };
|
|
30085
|
+
return { value: null, error: "invalid-formula" };
|
|
30086
|
+
}
|
|
30087
|
+
readCellNumber(label) {
|
|
30088
|
+
const value = this.getCellValue(label);
|
|
30089
|
+
const parsed = typeof value === "number" ? value : Number.parseFloat(String(value ?? "").trim());
|
|
30090
|
+
if (!Number.isFinite(parsed)) {
|
|
30091
|
+
return { value: null, error: "invalid-reference" };
|
|
30092
|
+
}
|
|
30093
|
+
return { value: parsed, error: null };
|
|
30094
|
+
}
|
|
30095
|
+
peekOperator(operators) {
|
|
30096
|
+
const token = this.tokens[this.index];
|
|
30097
|
+
return token?.type === "operator" && operators.includes(token.value) ? token : null;
|
|
30098
|
+
}
|
|
30099
|
+
consumeComma() {
|
|
30100
|
+
if (this.tokens[this.index]?.type !== "comma") {
|
|
30101
|
+
return false;
|
|
30102
|
+
}
|
|
30103
|
+
this.index += 1;
|
|
30104
|
+
return true;
|
|
30105
|
+
}
|
|
30106
|
+
consumeParen(value) {
|
|
30107
|
+
const token = this.tokens[this.index];
|
|
30108
|
+
if (token?.type !== "paren" || token.value !== value) {
|
|
30109
|
+
return false;
|
|
30110
|
+
}
|
|
30111
|
+
this.index += 1;
|
|
30112
|
+
return true;
|
|
30113
|
+
}
|
|
30114
|
+
};
|
|
30115
|
+
|
|
30116
|
+
// src/components/UEditor/table-formula-commands.ts
|
|
30117
|
+
function collectChildren2(node) {
|
|
30118
|
+
const children = [];
|
|
30119
|
+
node.forEach((child) => children.push(child));
|
|
30120
|
+
return children;
|
|
30121
|
+
}
|
|
30122
|
+
function getTableRows2(tableNode) {
|
|
30123
|
+
const rows = [];
|
|
30124
|
+
tableNode.forEach((rowNode, rowOffset) => {
|
|
30125
|
+
const cells = [];
|
|
30126
|
+
rowNode.forEach((cellNode, cellOffset, index) => {
|
|
30127
|
+
cells.push({
|
|
30128
|
+
index,
|
|
30129
|
+
node: cellNode,
|
|
30130
|
+
relativePos: rowOffset + 1 + cellOffset
|
|
30131
|
+
});
|
|
30132
|
+
});
|
|
30133
|
+
rows.push({ node: rowNode, cells });
|
|
30134
|
+
});
|
|
30135
|
+
return rows;
|
|
30136
|
+
}
|
|
30137
|
+
function safeFindCell2(map, relativePos) {
|
|
30138
|
+
try {
|
|
30139
|
+
return map.findCell(relativePos);
|
|
30140
|
+
} catch {
|
|
30141
|
+
return null;
|
|
30142
|
+
}
|
|
30143
|
+
}
|
|
30144
|
+
function getCellText(cellNode) {
|
|
30145
|
+
return cellNode.textBetween(0, cellNode.content.size, "\n").trim();
|
|
30146
|
+
}
|
|
30147
|
+
function buildTableValueGetter(tableNode) {
|
|
30148
|
+
const map = TableMap2.get(tableNode);
|
|
30149
|
+
const values = /* @__PURE__ */ new Map();
|
|
30150
|
+
for (const rowInfo of getTableRows2(tableNode)) {
|
|
30151
|
+
for (const entry of rowInfo.cells) {
|
|
30152
|
+
const rect = safeFindCell2(map, entry.relativePos);
|
|
30153
|
+
if (!rect) continue;
|
|
30154
|
+
const label = `${indexToColumnName(rect.left)}${rect.top + 1}`;
|
|
30155
|
+
const computedValue = entry.node.attrs.computedValue;
|
|
30156
|
+
values.set(label, typeof computedValue === "string" && computedValue.trim() ? computedValue : getCellText(entry.node));
|
|
30157
|
+
}
|
|
30158
|
+
}
|
|
30159
|
+
return (label) => values.get(label.toUpperCase());
|
|
30160
|
+
}
|
|
30161
|
+
function getFormulaComputedValue(formula, tableNode) {
|
|
30162
|
+
const result = evaluateBasicTableFormula(formula, buildTableValueGetter(tableNode));
|
|
30163
|
+
return result.error ? `#${result.error.toUpperCase()}` : String(result.value);
|
|
30164
|
+
}
|
|
30165
|
+
function normalizeFormulaInput(formula) {
|
|
30166
|
+
const trimmed = formula.trim();
|
|
30167
|
+
if (!trimmed) return "";
|
|
30168
|
+
return trimmed.startsWith("=") ? trimmed : `=${trimmed}`;
|
|
30169
|
+
}
|
|
30170
|
+
function setSelectedTableCellFormula(editor, formula) {
|
|
30171
|
+
const normalized = normalizeFormulaInput(formula);
|
|
30172
|
+
const { state, view } = editor;
|
|
30173
|
+
if (!normalized) {
|
|
30174
|
+
const clearedFormula = setCellAttr("formula", null)(state, view.dispatch.bind(view));
|
|
30175
|
+
const clearedValue = setCellAttr("computedValue", null)(editor.state, view.dispatch.bind(view));
|
|
30176
|
+
if (clearedFormula || clearedValue) {
|
|
30177
|
+
view.focus();
|
|
30178
|
+
dispatchTableLayoutChange(editor);
|
|
30179
|
+
return true;
|
|
30180
|
+
}
|
|
30181
|
+
return false;
|
|
30182
|
+
}
|
|
30183
|
+
const rect = selectedRect2(state);
|
|
30184
|
+
const computedValue = getFormulaComputedValue(normalized, rect.table);
|
|
30185
|
+
const appliedFormula = setCellAttr("formula", normalized)(state, view.dispatch.bind(view));
|
|
30186
|
+
const appliedValue = setCellAttr("computedValue", computedValue)(editor.state, view.dispatch.bind(view));
|
|
30187
|
+
if (appliedFormula || appliedValue) {
|
|
30188
|
+
view.focus();
|
|
30189
|
+
dispatchTableLayoutChange(editor);
|
|
30190
|
+
return true;
|
|
30191
|
+
}
|
|
30192
|
+
return false;
|
|
30193
|
+
}
|
|
30194
|
+
function clearSelectedTableCellFormula(editor) {
|
|
30195
|
+
return setSelectedTableCellFormula(editor, "");
|
|
30196
|
+
}
|
|
30197
|
+
function recalculateSelectedTable(editor) {
|
|
30198
|
+
const rect = selectedRect2(editor.state);
|
|
30199
|
+
const tableNode = rect.table;
|
|
30200
|
+
const map = TableMap2.get(tableNode);
|
|
30201
|
+
const getCellValue = buildTableValueGetter(tableNode);
|
|
30202
|
+
let changed = false;
|
|
30203
|
+
const rows = getTableRows2(tableNode).map((rowInfo) => {
|
|
30204
|
+
const cells = collectChildren2(rowInfo.node);
|
|
30205
|
+
for (const entry of rowInfo.cells) {
|
|
30206
|
+
const formula = typeof entry.node.attrs.formula === "string" ? entry.node.attrs.formula.trim() : "";
|
|
30207
|
+
if (!formula) continue;
|
|
30208
|
+
const rectForCell = safeFindCell2(map, entry.relativePos);
|
|
30209
|
+
if (!rectForCell) continue;
|
|
30210
|
+
const result = evaluateBasicTableFormula(formula, getCellValue);
|
|
30211
|
+
const computedValue = result.error ? `#${result.error.toUpperCase()}` : String(result.value);
|
|
30212
|
+
if (entry.node.attrs.computedValue === computedValue) continue;
|
|
30213
|
+
cells[entry.index] = entry.node.type.create(
|
|
30214
|
+
{
|
|
30215
|
+
...entry.node.attrs,
|
|
30216
|
+
computedValue
|
|
30217
|
+
},
|
|
30218
|
+
entry.node.content,
|
|
30219
|
+
entry.node.marks
|
|
30220
|
+
);
|
|
30221
|
+
changed = true;
|
|
30222
|
+
}
|
|
30223
|
+
return rowInfo.node.type.create(rowInfo.node.attrs, cells);
|
|
30224
|
+
});
|
|
30225
|
+
if (!changed) return false;
|
|
30226
|
+
const nextTable = tableNode.type.create(tableNode.attrs, rows);
|
|
30227
|
+
editor.view.dispatch(editor.state.tr.replaceWith(rect.tableStart - 1, rect.tableStart - 1 + tableNode.nodeSize, nextTable));
|
|
30228
|
+
dispatchTableLayoutChange(editor);
|
|
30229
|
+
return true;
|
|
30230
|
+
}
|
|
30231
|
+
|
|
30232
|
+
// src/components/UEditor/menus.tsx
|
|
29148
30233
|
import { Fragment as Fragment29, jsx as jsx86, jsxs as jsxs72 } from "react/jsx-runtime";
|
|
29149
30234
|
function applyTableCellBackground(editor, color) {
|
|
29150
30235
|
const value = color || null;
|
|
29151
30236
|
const { state, view } = editor;
|
|
29152
|
-
const applied =
|
|
30237
|
+
const applied = setCellAttr2("backgroundColor", value)(state, view.dispatch.bind(view));
|
|
29153
30238
|
if (applied) {
|
|
29154
30239
|
view.focus();
|
|
29155
30240
|
return;
|
|
@@ -29175,6 +30260,8 @@ var BubbleMenuContent = ({
|
|
|
29175
30260
|
setShowLinkInput(initialShowLinkInput);
|
|
29176
30261
|
}, [initialShowLinkInput]);
|
|
29177
30262
|
const [showTypographyPanel, setShowTypographyPanel] = useState48(false);
|
|
30263
|
+
const [showFormulaPanel, setShowFormulaPanel] = useState48(false);
|
|
30264
|
+
const [formulaDraft, setFormulaDraft] = useState48("");
|
|
29178
30265
|
const [showFontSizeOptions, setShowFontSizeOptions] = useState48(false);
|
|
29179
30266
|
const [fontSizeDraft, setFontSizeDraft] = useState48("");
|
|
29180
30267
|
const isImageSelected = editor.isActive("image");
|
|
@@ -29185,6 +30272,7 @@ var BubbleMenuContent = ({
|
|
|
29185
30272
|
const currentTextColor = normalizeStyleValue(textStyleAttrs.color) || "inherit";
|
|
29186
30273
|
const currentHighlightColor = normalizeStyleValue(editor.getAttributes("highlight").color) || "";
|
|
29187
30274
|
const currentCellBgColor = normalizeStyleValue(editor.getAttributes("tableCell").backgroundColor || editor.getAttributes("tableHeader").backgroundColor) || "";
|
|
30275
|
+
const currentCellFormula = normalizeStyleValue(editor.getAttributes("tableCell").formula || editor.getAttributes("tableHeader").formula) || "";
|
|
29188
30276
|
const isInTable2 = isSelectionInTable(editor.state);
|
|
29189
30277
|
const canMergeCells = isInTable2 && editor.can().mergeCells();
|
|
29190
30278
|
const canSplitCell = isInTable2 && editor.can().splitCell();
|
|
@@ -29201,6 +30289,9 @@ var BubbleMenuContent = ({
|
|
|
29201
30289
|
useEffect36(() => {
|
|
29202
30290
|
setFontSizeDraft(currentFontSize.replace(/px$/i, ""));
|
|
29203
30291
|
}, [currentFontSize]);
|
|
30292
|
+
useEffect36(() => {
|
|
30293
|
+
setFormulaDraft(currentCellFormula);
|
|
30294
|
+
}, [currentCellFormula]);
|
|
29204
30295
|
const applyFontSizeDraft = () => {
|
|
29205
30296
|
const normalized = fontSizeDraft.trim();
|
|
29206
30297
|
if (!normalized) {
|
|
@@ -29403,6 +30494,82 @@ var BubbleMenuContent = ({
|
|
|
29403
30494
|
)
|
|
29404
30495
|
] });
|
|
29405
30496
|
}
|
|
30497
|
+
if (showFormulaPanel && isInTable2) {
|
|
30498
|
+
return /* @__PURE__ */ jsxs72("div", { className: "w-72 p-2", children: [
|
|
30499
|
+
/* @__PURE__ */ jsxs72("div", { className: "mb-2 flex items-center justify-between gap-2", children: [
|
|
30500
|
+
/* @__PURE__ */ jsx86("span", { className: "px-1 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: t("tableMenu.formula") || "Formula" }),
|
|
30501
|
+
/* @__PURE__ */ jsx86(
|
|
30502
|
+
"button",
|
|
30503
|
+
{
|
|
30504
|
+
type: "button",
|
|
30505
|
+
onClick: () => {
|
|
30506
|
+
setShowFormulaPanel(false);
|
|
30507
|
+
onKeepOpenChange?.(false);
|
|
30508
|
+
},
|
|
30509
|
+
className: "rounded-md px-2 py-1 text-xs text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
30510
|
+
children: t("colors.done")
|
|
30511
|
+
}
|
|
30512
|
+
)
|
|
30513
|
+
] }),
|
|
30514
|
+
/* @__PURE__ */ jsx86("div", { className: "flex h-9 items-center overflow-hidden rounded-md border border-border/60 bg-muted/40", children: /* @__PURE__ */ jsx86(
|
|
30515
|
+
"input",
|
|
30516
|
+
{
|
|
30517
|
+
value: formulaDraft,
|
|
30518
|
+
onChange: (event) => setFormulaDraft(event.target.value),
|
|
30519
|
+
onMouseDown: (event) => event.stopPropagation(),
|
|
30520
|
+
onClick: (event) => event.stopPropagation(),
|
|
30521
|
+
onKeyDown: (event) => {
|
|
30522
|
+
event.stopPropagation();
|
|
30523
|
+
if (event.key === "Enter") {
|
|
30524
|
+
event.preventDefault();
|
|
30525
|
+
setSelectedTableCellFormula(editor, formulaDraft);
|
|
30526
|
+
setShowFormulaPanel(false);
|
|
30527
|
+
onKeepOpenChange?.(false);
|
|
30528
|
+
}
|
|
30529
|
+
},
|
|
30530
|
+
"aria-label": t("tableMenu.formula") || "Formula",
|
|
30531
|
+
placeholder: "=SUM(A1:A3)",
|
|
30532
|
+
className: "h-full min-w-0 flex-1 bg-transparent px-2 text-sm font-medium text-foreground outline-none"
|
|
30533
|
+
}
|
|
30534
|
+
) }),
|
|
30535
|
+
/* @__PURE__ */ jsxs72("div", { className: "mt-2 grid grid-cols-3 gap-1", children: [
|
|
30536
|
+
/* @__PURE__ */ jsx86(
|
|
30537
|
+
"button",
|
|
30538
|
+
{
|
|
30539
|
+
type: "button",
|
|
30540
|
+
onClick: () => {
|
|
30541
|
+
setSelectedTableCellFormula(editor, formulaDraft);
|
|
30542
|
+
setShowFormulaPanel(false);
|
|
30543
|
+
onKeepOpenChange?.(false);
|
|
30544
|
+
},
|
|
30545
|
+
className: "h-8 rounded-md bg-primary/10 text-xs font-semibold text-primary transition-colors hover:bg-primary/15",
|
|
30546
|
+
children: t("tableMenu.apply") || "Apply"
|
|
30547
|
+
}
|
|
30548
|
+
),
|
|
30549
|
+
/* @__PURE__ */ jsx86(
|
|
30550
|
+
"button",
|
|
30551
|
+
{
|
|
30552
|
+
type: "button",
|
|
30553
|
+
onClick: () => {
|
|
30554
|
+
clearSelectedTableCellFormula(editor);
|
|
30555
|
+
setFormulaDraft("");
|
|
30556
|
+
},
|
|
30557
|
+
className: "h-8 rounded-md bg-muted/40 text-xs font-semibold text-foreground transition-colors hover:bg-muted",
|
|
30558
|
+
children: t("tableMenu.clear") || "Clear"
|
|
30559
|
+
}
|
|
30560
|
+
),
|
|
30561
|
+
/* @__PURE__ */ jsx86(
|
|
30562
|
+
"button",
|
|
30563
|
+
{
|
|
30564
|
+
type: "button",
|
|
30565
|
+
onClick: () => recalculateSelectedTable(editor),
|
|
30566
|
+
className: "h-8 rounded-md bg-muted/40 text-xs font-semibold text-foreground transition-colors hover:bg-muted",
|
|
30567
|
+
children: t("tableMenu.recalculate") || "Recalc"
|
|
30568
|
+
}
|
|
30569
|
+
)
|
|
30570
|
+
] })
|
|
30571
|
+
] });
|
|
30572
|
+
}
|
|
29406
30573
|
if (showTypographyPanel) {
|
|
29407
30574
|
return /* @__PURE__ */ jsxs72("div", { className: "w-72 p-2", children: [
|
|
29408
30575
|
/* @__PURE__ */ jsxs72("div", { className: "mb-2 flex items-center justify-between gap-2", children: [
|
|
@@ -29616,6 +30783,21 @@ var BubbleMenuContent = ({
|
|
|
29616
30783
|
)
|
|
29617
30784
|
}
|
|
29618
30785
|
),
|
|
30786
|
+
/* @__PURE__ */ jsx86(
|
|
30787
|
+
ToolbarButton,
|
|
30788
|
+
{
|
|
30789
|
+
onMouseDown: () => {
|
|
30790
|
+
onKeepOpenChange?.(true);
|
|
30791
|
+
},
|
|
30792
|
+
onClick: () => {
|
|
30793
|
+
setFormulaDraft(currentCellFormula);
|
|
30794
|
+
setShowFormulaPanel(true);
|
|
30795
|
+
},
|
|
30796
|
+
active: Boolean(currentCellFormula),
|
|
30797
|
+
title: t("tableMenu.formula") || "Formula",
|
|
30798
|
+
children: /* @__PURE__ */ jsx86(Sigma, { className: "w-4 h-4" })
|
|
30799
|
+
}
|
|
30800
|
+
),
|
|
29619
30801
|
/* @__PURE__ */ jsx86(
|
|
29620
30802
|
ToolbarButton,
|
|
29621
30803
|
{
|
|
@@ -33457,7 +34639,7 @@ if (typeof WeakMap != "undefined") {
|
|
|
33457
34639
|
return cache[cachePos++] = value;
|
|
33458
34640
|
};
|
|
33459
34641
|
}
|
|
33460
|
-
var
|
|
34642
|
+
var TableMap3 = class {
|
|
33461
34643
|
constructor(width, height, map, problems) {
|
|
33462
34644
|
this.width = width;
|
|
33463
34645
|
this.height = height;
|
|
@@ -33594,7 +34776,7 @@ function computeMap(table) {
|
|
|
33594
34776
|
pos++;
|
|
33595
34777
|
}
|
|
33596
34778
|
if (width === 0 || height === 0) (problems || (problems = [])).push({ type: "zero_sized" });
|
|
33597
|
-
const tableMap = new
|
|
34779
|
+
const tableMap = new TableMap3(width, height, map, problems);
|
|
33598
34780
|
let badWidths = false;
|
|
33599
34781
|
for (let i = 0; !badWidths && i < colWidths.length; i += 2) if (colWidths[i] != null && colWidths[i + 1] < height) badWidths = true;
|
|
33600
34782
|
if (badWidths) findBadColWidths(tableMap, colWidths, table);
|
|
@@ -33698,7 +34880,7 @@ function inSameTable($cellA, $cellB) {
|
|
|
33698
34880
|
}
|
|
33699
34881
|
function nextCell($pos, axis, dir) {
|
|
33700
34882
|
const table = $pos.node(-1);
|
|
33701
|
-
const map =
|
|
34883
|
+
const map = TableMap3.get(table);
|
|
33702
34884
|
const tableStart = $pos.start(-1);
|
|
33703
34885
|
const moved = map.nextCell($pos.pos - tableStart, axis, dir);
|
|
33704
34886
|
return moved == null ? null : $pos.node(0).resolve(tableStart + moved);
|
|
@@ -33718,7 +34900,7 @@ function removeColSpan(attrs, pos, n = 1) {
|
|
|
33718
34900
|
var CellSelection = class CellSelection2 extends Selection {
|
|
33719
34901
|
constructor($anchorCell, $headCell = $anchorCell) {
|
|
33720
34902
|
const table = $anchorCell.node(-1);
|
|
33721
|
-
const map =
|
|
34903
|
+
const map = TableMap3.get(table);
|
|
33722
34904
|
const tableStart = $anchorCell.start(-1);
|
|
33723
34905
|
const rect = map.rectBetween($anchorCell.pos - tableStart, $headCell.pos - tableStart);
|
|
33724
34906
|
const doc = $anchorCell.node(0);
|
|
@@ -33747,7 +34929,7 @@ var CellSelection = class CellSelection2 extends Selection {
|
|
|
33747
34929
|
}
|
|
33748
34930
|
content() {
|
|
33749
34931
|
const table = this.$anchorCell.node(-1);
|
|
33750
|
-
const map =
|
|
34932
|
+
const map = TableMap3.get(table);
|
|
33751
34933
|
const tableStart = this.$anchorCell.start(-1);
|
|
33752
34934
|
const rect = map.rectBetween(this.$anchorCell.pos - tableStart, this.$headCell.pos - tableStart);
|
|
33753
34935
|
const seen = {};
|
|
@@ -33801,7 +34983,7 @@ var CellSelection = class CellSelection2 extends Selection {
|
|
|
33801
34983
|
}
|
|
33802
34984
|
forEachCell(f) {
|
|
33803
34985
|
const table = this.$anchorCell.node(-1);
|
|
33804
|
-
const map =
|
|
34986
|
+
const map = TableMap3.get(table);
|
|
33805
34987
|
const tableStart = this.$anchorCell.start(-1);
|
|
33806
34988
|
const cells = map.cellsInRect(map.rectBetween(this.$anchorCell.pos - tableStart, this.$headCell.pos - tableStart));
|
|
33807
34989
|
for (let i = 0; i < cells.length; i++) f(table.nodeAt(cells[i]), tableStart + cells[i]);
|
|
@@ -33816,7 +34998,7 @@ var CellSelection = class CellSelection2 extends Selection {
|
|
|
33816
34998
|
}
|
|
33817
34999
|
static colSelection($anchorCell, $headCell = $anchorCell) {
|
|
33818
35000
|
const table = $anchorCell.node(-1);
|
|
33819
|
-
const map =
|
|
35001
|
+
const map = TableMap3.get(table);
|
|
33820
35002
|
const tableStart = $anchorCell.start(-1);
|
|
33821
35003
|
const anchorRect = map.findCell($anchorCell.pos - tableStart);
|
|
33822
35004
|
const headRect = map.findCell($headCell.pos - tableStart);
|
|
@@ -33832,7 +35014,7 @@ var CellSelection = class CellSelection2 extends Selection {
|
|
|
33832
35014
|
}
|
|
33833
35015
|
isRowSelection() {
|
|
33834
35016
|
const table = this.$anchorCell.node(-1);
|
|
33835
|
-
const map =
|
|
35017
|
+
const map = TableMap3.get(table);
|
|
33836
35018
|
const tableStart = this.$anchorCell.start(-1);
|
|
33837
35019
|
const anchorLeft = map.colCount(this.$anchorCell.pos - tableStart);
|
|
33838
35020
|
const headLeft = map.colCount(this.$headCell.pos - tableStart);
|
|
@@ -33846,7 +35028,7 @@ var CellSelection = class CellSelection2 extends Selection {
|
|
|
33846
35028
|
}
|
|
33847
35029
|
static rowSelection($anchorCell, $headCell = $anchorCell) {
|
|
33848
35030
|
const table = $anchorCell.node(-1);
|
|
33849
|
-
const map =
|
|
35031
|
+
const map = TableMap3.get(table);
|
|
33850
35032
|
const tableStart = $anchorCell.start(-1);
|
|
33851
35033
|
const anchorRect = map.findCell($anchorCell.pos - tableStart);
|
|
33852
35034
|
const headRect = map.findCell($headCell.pos - tableStart);
|
|
@@ -33895,7 +35077,7 @@ var CellBookmark = class CellBookmark2 {
|
|
|
33895
35077
|
};
|
|
33896
35078
|
var fixTablesKey = new PluginKey4("fix-tables");
|
|
33897
35079
|
function convertTableNodeToArrayOfRows(tableNode) {
|
|
33898
|
-
const map =
|
|
35080
|
+
const map = TableMap3.get(tableNode);
|
|
33899
35081
|
const rows = [];
|
|
33900
35082
|
const rowCount = map.height;
|
|
33901
35083
|
const colCount$1 = map.width;
|
|
@@ -33926,7 +35108,7 @@ function convertTableNodeToArrayOfRows(tableNode) {
|
|
|
33926
35108
|
}
|
|
33927
35109
|
function convertArrayOfRowsToTableNode(tableNode, arrayOfNodes) {
|
|
33928
35110
|
const newRows = [];
|
|
33929
|
-
const map =
|
|
35111
|
+
const map = TableMap3.get(tableNode);
|
|
33930
35112
|
const rowCount = map.height;
|
|
33931
35113
|
const colCount$1 = map.width;
|
|
33932
35114
|
for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
|
|
@@ -33975,7 +35157,7 @@ function findParentNode(predicate, $pos) {
|
|
|
33975
35157
|
function getCellsInColumn(columnIndex, selection) {
|
|
33976
35158
|
const table = findTable(selection.$from);
|
|
33977
35159
|
if (!table) return;
|
|
33978
|
-
const map =
|
|
35160
|
+
const map = TableMap3.get(table.node);
|
|
33979
35161
|
if (columnIndex < 0 || columnIndex > map.width - 1) return;
|
|
33980
35162
|
return map.cellsInRect({
|
|
33981
35163
|
left: columnIndex,
|
|
@@ -33996,7 +35178,7 @@ function getCellsInColumn(columnIndex, selection) {
|
|
|
33996
35178
|
function getCellsInRow(rowIndex, selection) {
|
|
33997
35179
|
const table = findTable(selection.$from);
|
|
33998
35180
|
if (!table) return;
|
|
33999
|
-
const map =
|
|
35181
|
+
const map = TableMap3.get(table.node);
|
|
34000
35182
|
if (rowIndex < 0 || rowIndex > map.height - 1) return;
|
|
34001
35183
|
return map.cellsInRect({
|
|
34002
35184
|
left: 0,
|
|
@@ -34125,7 +35307,7 @@ function moveColumn(moveColParams) {
|
|
|
34125
35307
|
const newTable = moveTableColumn$1(table.node, indexesOriginColumn, indexesTargetColumn, 0);
|
|
34126
35308
|
tr.replaceWith(table.pos, table.pos + table.node.nodeSize, newTable);
|
|
34127
35309
|
if (!select) return true;
|
|
34128
|
-
const map =
|
|
35310
|
+
const map = TableMap3.get(newTable);
|
|
34129
35311
|
const start = table.start;
|
|
34130
35312
|
const index = targetIndex;
|
|
34131
35313
|
const lastCell = map.positionAt(map.height - 1, index, newTable);
|
|
@@ -34153,7 +35335,7 @@ function moveRow(moveRowParams) {
|
|
|
34153
35335
|
const newTable = moveTableRow$1(table.node, indexesOriginRow, indexesTargetRow, 0);
|
|
34154
35336
|
tr.replaceWith(table.pos, table.pos + table.node.nodeSize, newTable);
|
|
34155
35337
|
if (!select) return true;
|
|
34156
|
-
const map =
|
|
35338
|
+
const map = TableMap3.get(newTable);
|
|
34157
35339
|
const start = table.start;
|
|
34158
35340
|
const index = targetIndex;
|
|
34159
35341
|
const lastCell = map.positionAt(index, map.width - 1, newTable);
|
|
@@ -34168,12 +35350,12 @@ function moveTableRow$1(table, indexesOrigin, indexesTarget, direction) {
|
|
|
34168
35350
|
rows = moveRowInArrayOfRows(rows, indexesOrigin, indexesTarget, direction);
|
|
34169
35351
|
return convertArrayOfRowsToTableNode(table, rows);
|
|
34170
35352
|
}
|
|
34171
|
-
function
|
|
35353
|
+
function selectedRect3(state) {
|
|
34172
35354
|
const sel = state.selection;
|
|
34173
35355
|
const $pos = selectionCell(state);
|
|
34174
35356
|
const table = $pos.node(-1);
|
|
34175
35357
|
const tableStart = $pos.start(-1);
|
|
34176
|
-
const map =
|
|
35358
|
+
const map = TableMap3.get(table);
|
|
34177
35359
|
return {
|
|
34178
35360
|
...sel instanceof CellSelection ? map.rectBetween(sel.$anchorCell.pos - tableStart, sel.$headCell.pos - tableStart) : map.findCell($pos.pos - tableStart),
|
|
34179
35361
|
tableStart,
|
|
@@ -34186,7 +35368,7 @@ function deprecated_toggleHeader(type) {
|
|
|
34186
35368
|
if (!isInTable(state)) return false;
|
|
34187
35369
|
if (dispatch) {
|
|
34188
35370
|
const types = tableNodeTypes(state.schema);
|
|
34189
|
-
const rect =
|
|
35371
|
+
const rect = selectedRect3(state), tr = state.tr;
|
|
34190
35372
|
const cells = rect.map.cellsInRect(type == "column" ? {
|
|
34191
35373
|
left: rect.left,
|
|
34192
35374
|
top: 0,
|
|
@@ -34226,7 +35408,7 @@ function toggleHeader(type, options) {
|
|
|
34226
35408
|
if (!isInTable(state)) return false;
|
|
34227
35409
|
if (dispatch) {
|
|
34228
35410
|
const types = tableNodeTypes(state.schema);
|
|
34229
|
-
const rect =
|
|
35411
|
+
const rect = selectedRect3(state), tr = state.tr;
|
|
34230
35412
|
const isHeaderRowEnabled = isHeaderEnabledByType("row", rect, types);
|
|
34231
35413
|
const isHeaderColumnEnabled = isHeaderEnabledByType("column", rect, types);
|
|
34232
35414
|
const selectionStartsAt = (type === "column" ? isHeaderRowEnabled : type === "row" ? isHeaderColumnEnabled : false) ? 1 : 0;
|
|
@@ -34387,6 +35569,262 @@ import {
|
|
|
34387
35569
|
Trash2 as Trash24
|
|
34388
35570
|
} from "lucide-react";
|
|
34389
35571
|
|
|
35572
|
+
// src/components/UEditor/table-layout-model.ts
|
|
35573
|
+
var FALLBACK_TABLE_ROW_HEIGHT = 44;
|
|
35574
|
+
var FALLBACK_TABLE_COLUMN_WIDTH = 160;
|
|
35575
|
+
function getVisibleTableBounds(layout) {
|
|
35576
|
+
const left = Math.max(layout.tableLeft, layout.wrapperLeft);
|
|
35577
|
+
const top = Math.max(layout.tableTop, layout.wrapperTop);
|
|
35578
|
+
const right = Math.min(layout.tableLeft + layout.tableWidth, layout.wrapperLeft + layout.viewportWidth);
|
|
35579
|
+
const bottom = Math.min(layout.tableTop + layout.tableHeight, layout.wrapperTop + layout.viewportHeight);
|
|
35580
|
+
return {
|
|
35581
|
+
left,
|
|
35582
|
+
top,
|
|
35583
|
+
right,
|
|
35584
|
+
bottom,
|
|
35585
|
+
width: Math.max(0, right - left),
|
|
35586
|
+
height: Math.max(0, bottom - top)
|
|
35587
|
+
};
|
|
35588
|
+
}
|
|
35589
|
+
function metricOrFallback(value, fallback) {
|
|
35590
|
+
return Number.isFinite(value) && value > 0 ? value : fallback;
|
|
35591
|
+
}
|
|
35592
|
+
function parsePixelMetric(value) {
|
|
35593
|
+
if (!value) return null;
|
|
35594
|
+
const parsed = Number.parseFloat(value);
|
|
35595
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
35596
|
+
}
|
|
35597
|
+
function getPrimaryCell(table) {
|
|
35598
|
+
const cell = table.querySelector("th,td");
|
|
35599
|
+
return cell instanceof HTMLTableCellElement ? cell : null;
|
|
35600
|
+
}
|
|
35601
|
+
function getLastCell(table) {
|
|
35602
|
+
const lastRow = table.rows.item(table.rows.length - 1);
|
|
35603
|
+
if (!(lastRow instanceof HTMLTableRowElement)) return null;
|
|
35604
|
+
const cell = lastRow.cells.item(lastRow.cells.length - 1);
|
|
35605
|
+
return cell instanceof HTMLTableCellElement ? cell : null;
|
|
35606
|
+
}
|
|
35607
|
+
function getCellFromTarget(target) {
|
|
35608
|
+
const element = resolveEventElement(target);
|
|
35609
|
+
if (!element) return null;
|
|
35610
|
+
const directCell = element.closest("th,td");
|
|
35611
|
+
if (directCell instanceof HTMLTableCellElement) {
|
|
35612
|
+
return directCell;
|
|
35613
|
+
}
|
|
35614
|
+
const table = element.closest("table");
|
|
35615
|
+
if (table instanceof HTMLTableElement) {
|
|
35616
|
+
return getPrimaryCell(table);
|
|
35617
|
+
}
|
|
35618
|
+
return null;
|
|
35619
|
+
}
|
|
35620
|
+
function findTableInfo(editor, pos) {
|
|
35621
|
+
const $pos = editor.state.doc.resolve(pos);
|
|
35622
|
+
for (let depth = $pos.depth; depth > 0; depth -= 1) {
|
|
35623
|
+
const node = $pos.node(depth);
|
|
35624
|
+
if (node.type.name === "table") {
|
|
35625
|
+
return {
|
|
35626
|
+
node,
|
|
35627
|
+
pos: $pos.before(depth),
|
|
35628
|
+
start: $pos.start(depth)
|
|
35629
|
+
};
|
|
35630
|
+
}
|
|
35631
|
+
}
|
|
35632
|
+
return null;
|
|
35633
|
+
}
|
|
35634
|
+
function getCellRelativePosFromDomPos(map, tableStart, domPos) {
|
|
35635
|
+
const relativeDomPos = domPos - tableStart;
|
|
35636
|
+
const seen = /* @__PURE__ */ new Set();
|
|
35637
|
+
for (const relativeCellPos of map.map) {
|
|
35638
|
+
if (seen.has(relativeCellPos)) continue;
|
|
35639
|
+
seen.add(relativeCellPos);
|
|
35640
|
+
if (relativeDomPos === relativeCellPos || relativeDomPos === relativeCellPos + 1) {
|
|
35641
|
+
return relativeCellPos;
|
|
35642
|
+
}
|
|
35643
|
+
}
|
|
35644
|
+
return null;
|
|
35645
|
+
}
|
|
35646
|
+
function buildLogicalColumnMetrics({
|
|
35647
|
+
editor,
|
|
35648
|
+
surface,
|
|
35649
|
+
surfaceRect,
|
|
35650
|
+
tableElement,
|
|
35651
|
+
tableInfo,
|
|
35652
|
+
tableLeft,
|
|
35653
|
+
tableWidth
|
|
35654
|
+
}) {
|
|
35655
|
+
const map = TableMap3.get(tableInfo.node);
|
|
35656
|
+
const fallbackWidth = metricOrFallback(tableWidth / map.width, FALLBACK_TABLE_COLUMN_WIDTH);
|
|
35657
|
+
const firstRow = tableElement.rows.item(0);
|
|
35658
|
+
const visualColumns = [];
|
|
35659
|
+
if (firstRow) {
|
|
35660
|
+
for (const tableCell of Array.from(firstRow.cells)) {
|
|
35661
|
+
if (!(tableCell instanceof HTMLTableCellElement)) continue;
|
|
35662
|
+
const cellPos = editor.view.posAtDOM(tableCell, 0);
|
|
35663
|
+
const relativeCellPos = getCellRelativePosFromDomPos(map, tableInfo.start, cellPos);
|
|
35664
|
+
if (relativeCellPos == null) continue;
|
|
35665
|
+
const cellMapRect = map.findCell(relativeCellPos);
|
|
35666
|
+
const cellRect = tableCell.getBoundingClientRect();
|
|
35667
|
+
const cellStart = cellRect.width > 0 ? cellRect.left - surfaceRect.left + surface.scrollLeft : tableLeft + cellMapRect.left * fallbackWidth;
|
|
35668
|
+
const size = metricOrFallback(cellRect.width, fallbackWidth * Math.max(1, cellMapRect.right - cellMapRect.left));
|
|
35669
|
+
visualColumns.push({
|
|
35670
|
+
index: cellMapRect.left,
|
|
35671
|
+
cellPos: tableInfo.start + relativeCellPos,
|
|
35672
|
+
start: cellStart,
|
|
35673
|
+
size,
|
|
35674
|
+
center: cellStart + size / 2
|
|
35675
|
+
});
|
|
35676
|
+
}
|
|
35677
|
+
}
|
|
35678
|
+
if (visualColumns.length > 0) {
|
|
35679
|
+
return visualColumns.sort((a, b) => a.index - b.index);
|
|
35680
|
+
}
|
|
35681
|
+
const cols = Array.from(tableElement.querySelectorAll("colgroup > col"));
|
|
35682
|
+
const parsedWidths = cols.slice(0, map.width).map((col) => parsePixelMetric(col.style.width) ?? parsePixelMetric(col.getAttribute("width")));
|
|
35683
|
+
const hasCompleteColWidths = parsedWidths.length >= map.width && parsedWidths.every((width) => typeof width === "number");
|
|
35684
|
+
let cursor = tableLeft;
|
|
35685
|
+
return Array.from({ length: map.width }, (_, index) => {
|
|
35686
|
+
const size = hasCompleteColWidths ? parsedWidths[index] : fallbackWidth;
|
|
35687
|
+
const start = hasCompleteColWidths ? cursor : tableLeft + index * fallbackWidth;
|
|
35688
|
+
cursor += size;
|
|
35689
|
+
return {
|
|
35690
|
+
index,
|
|
35691
|
+
cellPos: tableInfo.start + map.positionAt(0, index, tableInfo.node),
|
|
35692
|
+
start,
|
|
35693
|
+
size,
|
|
35694
|
+
center: start + size / 2
|
|
35695
|
+
};
|
|
35696
|
+
});
|
|
35697
|
+
}
|
|
35698
|
+
function buildLogicalRowMetrics({
|
|
35699
|
+
editor,
|
|
35700
|
+
surface,
|
|
35701
|
+
surfaceRect,
|
|
35702
|
+
tableInfo,
|
|
35703
|
+
rows,
|
|
35704
|
+
tableTop,
|
|
35705
|
+
tableHeight,
|
|
35706
|
+
cornerCell
|
|
35707
|
+
}) {
|
|
35708
|
+
const map = TableMap3.get(tableInfo.node);
|
|
35709
|
+
const fallbackHeight = metricOrFallback(tableHeight / map.height, FALLBACK_TABLE_ROW_HEIGHT);
|
|
35710
|
+
const visualRows = [];
|
|
35711
|
+
const seenCellPositions = /* @__PURE__ */ new Set();
|
|
35712
|
+
for (let rowIndex = 0; rowIndex < map.height; rowIndex += 1) {
|
|
35713
|
+
const relativeCellPos = map.map[rowIndex * map.width];
|
|
35714
|
+
if (seenCellPositions.has(relativeCellPos)) continue;
|
|
35715
|
+
seenCellPositions.add(relativeCellPos);
|
|
35716
|
+
const cellMapRect = map.findCell(relativeCellPos);
|
|
35717
|
+
const cellDom = editor.view.nodeDOM(tableInfo.start + relativeCellPos);
|
|
35718
|
+
const tableCell = cellDom instanceof HTMLTableCellElement ? cellDom : null;
|
|
35719
|
+
if (tableCell) {
|
|
35720
|
+
const cellRect = tableCell.getBoundingClientRect();
|
|
35721
|
+
const start = cellRect.height > 0 ? cellRect.top - surfaceRect.top + surface.scrollTop : tableTop + cellMapRect.top * fallbackHeight;
|
|
35722
|
+
const size = metricOrFallback(cellRect.height, fallbackHeight * Math.max(1, cellMapRect.bottom - cellMapRect.top));
|
|
35723
|
+
visualRows.push({
|
|
35724
|
+
index: cellMapRect.top,
|
|
35725
|
+
cellPos: tableInfo.start + relativeCellPos,
|
|
35726
|
+
start,
|
|
35727
|
+
size,
|
|
35728
|
+
center: start + size / 2
|
|
35729
|
+
});
|
|
35730
|
+
}
|
|
35731
|
+
}
|
|
35732
|
+
if (visualRows.length > 0) {
|
|
35733
|
+
return visualRows.sort((a, b) => a.index - b.index);
|
|
35734
|
+
}
|
|
35735
|
+
return rows.map((tableRow, index) => {
|
|
35736
|
+
const rowRect = tableRow.getBoundingClientRect();
|
|
35737
|
+
const anchorCell = tableRow.cells.item(0) ?? cornerCell;
|
|
35738
|
+
const start = rowRect.height > 0 ? rowRect.top - surfaceRect.top + surface.scrollTop : tableTop + index * fallbackHeight;
|
|
35739
|
+
const size = metricOrFallback(rowRect.height, fallbackHeight);
|
|
35740
|
+
return {
|
|
35741
|
+
index,
|
|
35742
|
+
cellPos: editor.view.posAtDOM(anchorCell, 0),
|
|
35743
|
+
start,
|
|
35744
|
+
size,
|
|
35745
|
+
center: start + size / 2
|
|
35746
|
+
};
|
|
35747
|
+
});
|
|
35748
|
+
}
|
|
35749
|
+
function buildTableControlLayout(editor, surface, cell) {
|
|
35750
|
+
const row = cell.closest("tr");
|
|
35751
|
+
const table = cell.closest("table");
|
|
35752
|
+
if (!(row instanceof HTMLTableRowElement) || !(table instanceof HTMLTableElement)) {
|
|
35753
|
+
return null;
|
|
35754
|
+
}
|
|
35755
|
+
const rows = Array.from(table.rows).filter((item) => item instanceof HTMLTableRowElement);
|
|
35756
|
+
const cornerCell = getLastCell(table);
|
|
35757
|
+
const cellPos = editor.view.posAtDOM(cell, 0);
|
|
35758
|
+
const tableInfo = findTableInfo(editor, cellPos);
|
|
35759
|
+
if (rows.length === 0 || !tableInfo || !(cornerCell instanceof HTMLTableCellElement)) {
|
|
35760
|
+
return null;
|
|
35761
|
+
}
|
|
35762
|
+
const map = TableMap3.get(tableInfo.node);
|
|
35763
|
+
const surfaceRect = surface.getBoundingClientRect();
|
|
35764
|
+
const tableRect = table.getBoundingClientRect();
|
|
35765
|
+
const wrapperElement = table.closest(".tableWrapper");
|
|
35766
|
+
const wrapper = wrapperElement instanceof HTMLElement ? wrapperElement : null;
|
|
35767
|
+
const wrapperRect = wrapper?.getBoundingClientRect() ?? tableRect;
|
|
35768
|
+
const tableLeft = tableRect.left - surfaceRect.left + surface.scrollLeft;
|
|
35769
|
+
const tableTop = tableRect.top - surfaceRect.top + surface.scrollTop;
|
|
35770
|
+
const avgRowHeight = metricOrFallback(tableRect.height / rows.length, FALLBACK_TABLE_ROW_HEIGHT);
|
|
35771
|
+
const avgColumnWidth = metricOrFallback(tableRect.width / map.width, FALLBACK_TABLE_COLUMN_WIDTH);
|
|
35772
|
+
const tableWidth = metricOrFallback(tableRect.width, avgColumnWidth * map.width);
|
|
35773
|
+
const tableHeight = metricOrFallback(tableRect.height, avgRowHeight * rows.length);
|
|
35774
|
+
const wrapperLeft = wrapperRect.left - surfaceRect.left + surface.scrollLeft;
|
|
35775
|
+
const wrapperTop = wrapperRect.top - surfaceRect.top + surface.scrollTop;
|
|
35776
|
+
const wrapperWidth = metricOrFallback(wrapperRect.width, tableWidth);
|
|
35777
|
+
const wrapperHeight = metricOrFallback(wrapperRect.height, tableHeight);
|
|
35778
|
+
const viewportWidth = metricOrFallback(wrapper?.clientWidth ?? wrapperRect.width, tableWidth);
|
|
35779
|
+
const viewportHeight = metricOrFallback(wrapper?.clientHeight ?? wrapperRect.height, tableHeight);
|
|
35780
|
+
const verticalScrollbarWidth = Math.max(0, Math.round(wrapperWidth - viewportWidth));
|
|
35781
|
+
const horizontalScrollbarHeight = Math.max(0, Math.round(wrapperHeight - viewportHeight));
|
|
35782
|
+
const rowHandles = buildLogicalRowMetrics({
|
|
35783
|
+
editor,
|
|
35784
|
+
surface,
|
|
35785
|
+
surfaceRect,
|
|
35786
|
+
tableInfo,
|
|
35787
|
+
rows,
|
|
35788
|
+
tableTop,
|
|
35789
|
+
tableHeight,
|
|
35790
|
+
cornerCell
|
|
35791
|
+
});
|
|
35792
|
+
const columnHandles = buildLogicalColumnMetrics({
|
|
35793
|
+
editor,
|
|
35794
|
+
surface,
|
|
35795
|
+
surfaceRect,
|
|
35796
|
+
tableElement: table,
|
|
35797
|
+
tableInfo,
|
|
35798
|
+
tableLeft,
|
|
35799
|
+
tableWidth
|
|
35800
|
+
});
|
|
35801
|
+
const activeCellRelativePos = getCellRelativePosFromDomPos(map, tableInfo.start, cellPos);
|
|
35802
|
+
const activeCellRect = activeCellRelativePos != null ? map.findCell(activeCellRelativePos) : { left: cell.cellIndex, top: row.rowIndex };
|
|
35803
|
+
const normalizedCellPos = activeCellRelativePos != null ? tableInfo.start + activeCellRelativePos : cellPos;
|
|
35804
|
+
return {
|
|
35805
|
+
cellPos: normalizedCellPos,
|
|
35806
|
+
cornerCellPos: tableInfo.start + map.positionAt(map.height - 1, map.width - 1, tableInfo.node),
|
|
35807
|
+
activeRowIndex: activeCellRect.top,
|
|
35808
|
+
activeColumnIndex: activeCellRect.left,
|
|
35809
|
+
tableLeft,
|
|
35810
|
+
tableTop,
|
|
35811
|
+
tableWidth,
|
|
35812
|
+
tableHeight,
|
|
35813
|
+
wrapperLeft,
|
|
35814
|
+
wrapperTop,
|
|
35815
|
+
wrapperWidth,
|
|
35816
|
+
wrapperHeight,
|
|
35817
|
+
viewportWidth,
|
|
35818
|
+
viewportHeight,
|
|
35819
|
+
horizontalScrollbarHeight,
|
|
35820
|
+
verticalScrollbarWidth,
|
|
35821
|
+
avgRowHeight,
|
|
35822
|
+
avgColumnWidth,
|
|
35823
|
+
rowHandles,
|
|
35824
|
+
columnHandles
|
|
35825
|
+
};
|
|
35826
|
+
}
|
|
35827
|
+
|
|
34390
35828
|
// src/components/UEditor/table-hover-state.ts
|
|
34391
35829
|
var MENU_HOVER_PADDING = 18;
|
|
34392
35830
|
var ROW_HANDLE_HOVER_WIDTH = 28;
|
|
@@ -34420,18 +35858,18 @@ function buildTableHoverState({
|
|
|
34420
35858
|
const directAddRow = targetElement?.closest?.("[data-table-control='add-row']");
|
|
34421
35859
|
const directRowHandleIndex = directRowHandle instanceof HTMLElement ? Number.parseInt(directRowHandle.dataset.rowHandleIndex ?? "", 10) : Number.NaN;
|
|
34422
35860
|
const directColumnHandleIndex = directColumnHandle instanceof HTMLElement ? Number.parseInt(directColumnHandle.dataset.columnHandleIndex ?? "", 10) : Number.NaN;
|
|
34423
|
-
const
|
|
34424
|
-
const
|
|
35861
|
+
const visibleBounds = getVisibleTableBounds(layout);
|
|
35862
|
+
const rowRailTop = layout.wrapperTop + layout.wrapperHeight;
|
|
34425
35863
|
const isMouseInTable = relativeX >= layout.tableLeft && relativeX <= layout.tableLeft + layout.tableWidth && relativeY >= layout.tableTop && relativeY <= layout.tableTop + layout.tableHeight;
|
|
34426
35864
|
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;
|
|
34427
35865
|
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;
|
|
34428
35866
|
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;
|
|
34429
35867
|
const lastRow = layout.rowHandles[layout.rowHandles.length - 1];
|
|
34430
35868
|
const lastCol = layout.columnHandles[layout.columnHandles.length - 1];
|
|
34431
|
-
const isMouseInLastColumn = lastCol ? relativeX >= lastCol.start && relativeX <= lastCol.start + lastCol.size && relativeY >=
|
|
34432
|
-
const addColumnVisible = Boolean(directAddColumn) || relativeX >=
|
|
34433
|
-
const isMouseInLastRow = lastRow ? relativeY >= lastRow.start && relativeY <= lastRow.start + lastRow.size && relativeX >=
|
|
34434
|
-
const addRowVisible = Boolean(directAddRow) || relativeY >=
|
|
35869
|
+
const isMouseInLastColumn = lastCol ? relativeX >= lastCol.start && relativeX <= lastCol.start + lastCol.size && relativeY >= visibleBounds.top && relativeY <= visibleBounds.bottom : false;
|
|
35870
|
+
const addColumnVisible = Boolean(directAddColumn) || relativeX >= visibleBounds.right && relativeX <= visibleBounds.right + ADD_COLUMN_HOVER_WIDTH && relativeY >= visibleBounds.top && relativeY <= visibleBounds.bottom || isMouseInLastColumn;
|
|
35871
|
+
const isMouseInLastRow = lastRow ? relativeY >= lastRow.start && relativeY <= lastRow.start + lastRow.size && relativeX >= visibleBounds.left && relativeX <= visibleBounds.right : false;
|
|
35872
|
+
const addRowVisible = Boolean(directAddRow) || relativeY >= rowRailTop && relativeY <= rowRailTop + ADD_ROW_HOVER_HEIGHT && relativeX >= visibleBounds.left && relativeX <= visibleBounds.right || isMouseInLastRow;
|
|
34435
35873
|
return {
|
|
34436
35874
|
menuVisible,
|
|
34437
35875
|
addColumnVisible,
|
|
@@ -34553,12 +35991,11 @@ function TableAddRails({
|
|
|
34553
35991
|
quickAddColumnLabel,
|
|
34554
35992
|
quickAddRowLabel
|
|
34555
35993
|
}) {
|
|
34556
|
-
const
|
|
34557
|
-
const
|
|
34558
|
-
const
|
|
34559
|
-
const columnRailLeft = layout.tableLeft + visibleTableWidth + ADD_COLUMN_RAIL_GAP;
|
|
35994
|
+
const visibleBounds = getVisibleTableBounds(layout);
|
|
35995
|
+
const columnRailTop = visibleBounds.top;
|
|
35996
|
+
const columnRailLeft = visibleBounds.right + ADD_COLUMN_RAIL_GAP;
|
|
34560
35997
|
const rowRailTop = layout.wrapperTop + layout.wrapperHeight + ADD_ROW_RAIL_GAP;
|
|
34561
|
-
const rowRailLeft =
|
|
35998
|
+
const rowRailLeft = visibleBounds.left;
|
|
34562
35999
|
const showColumnRail = controlsVisible || addColumnVisible;
|
|
34563
36000
|
const showRowRail = controlsVisible || addRowVisible;
|
|
34564
36001
|
return /* @__PURE__ */ jsxs75(Fragment32, { children: [
|
|
@@ -34586,10 +36023,10 @@ function TableAddRails({
|
|
|
34586
36023
|
"transition-[opacity,transform,colors] duration-150 hover:bg-accent hover:text-foreground disabled:opacity-50 disabled:cursor-not-allowed"
|
|
34587
36024
|
),
|
|
34588
36025
|
style: {
|
|
34589
|
-
top: showColumnRail ? columnRailTop : columnRailTop + Math.max(0,
|
|
36026
|
+
top: showColumnRail ? columnRailTop : columnRailTop + Math.max(0, visibleBounds.height / 2 - 24),
|
|
34590
36027
|
left: columnRailLeft,
|
|
34591
36028
|
width: showColumnRail ? 18 : 12,
|
|
34592
|
-
height: showColumnRail ?
|
|
36029
|
+
height: showColumnRail ? visibleBounds.height : 48,
|
|
34593
36030
|
opacity: showColumnRail ? 1 : 0,
|
|
34594
36031
|
transform: showColumnRail ? "scale(1)" : "scale(0.92)",
|
|
34595
36032
|
pointerEvents: showColumnRail ? "auto" : "none"
|
|
@@ -34624,8 +36061,8 @@ function TableAddRails({
|
|
|
34624
36061
|
),
|
|
34625
36062
|
style: {
|
|
34626
36063
|
top: rowRailTop,
|
|
34627
|
-
left: showRowRail ? rowRailLeft : rowRailLeft + Math.max(0,
|
|
34628
|
-
width: showRowRail ?
|
|
36064
|
+
left: showRowRail ? rowRailLeft : rowRailLeft + Math.max(0, visibleBounds.width / 2 - 24),
|
|
36065
|
+
width: showRowRail ? visibleBounds.width : 48,
|
|
34629
36066
|
height: showRowRail ? 16 : 12,
|
|
34630
36067
|
opacity: showRowRail ? 1 : 0,
|
|
34631
36068
|
transform: showRowRail ? "scale(1)" : "scale(0.92)",
|
|
@@ -34850,248 +36287,6 @@ function TableColumnHandles({
|
|
|
34850
36287
|
}) });
|
|
34851
36288
|
}
|
|
34852
36289
|
|
|
34853
|
-
// src/components/UEditor/table-layout-model.ts
|
|
34854
|
-
var FALLBACK_TABLE_ROW_HEIGHT = 44;
|
|
34855
|
-
var FALLBACK_TABLE_COLUMN_WIDTH = 160;
|
|
34856
|
-
function metricOrFallback(value, fallback) {
|
|
34857
|
-
return Number.isFinite(value) && value > 0 ? value : fallback;
|
|
34858
|
-
}
|
|
34859
|
-
function parsePixelMetric(value) {
|
|
34860
|
-
if (!value) return null;
|
|
34861
|
-
const parsed = Number.parseFloat(value);
|
|
34862
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
34863
|
-
}
|
|
34864
|
-
function getPrimaryCell(table) {
|
|
34865
|
-
const cell = table.querySelector("th,td");
|
|
34866
|
-
return cell instanceof HTMLTableCellElement ? cell : null;
|
|
34867
|
-
}
|
|
34868
|
-
function getLastCell(table) {
|
|
34869
|
-
const lastRow = table.rows.item(table.rows.length - 1);
|
|
34870
|
-
if (!(lastRow instanceof HTMLTableRowElement)) return null;
|
|
34871
|
-
const cell = lastRow.cells.item(lastRow.cells.length - 1);
|
|
34872
|
-
return cell instanceof HTMLTableCellElement ? cell : null;
|
|
34873
|
-
}
|
|
34874
|
-
function getCellFromTarget(target) {
|
|
34875
|
-
const element = resolveEventElement(target);
|
|
34876
|
-
if (!element) return null;
|
|
34877
|
-
const directCell = element.closest("th,td");
|
|
34878
|
-
if (directCell instanceof HTMLTableCellElement) {
|
|
34879
|
-
return directCell;
|
|
34880
|
-
}
|
|
34881
|
-
const table = element.closest("table");
|
|
34882
|
-
if (table instanceof HTMLTableElement) {
|
|
34883
|
-
return getPrimaryCell(table);
|
|
34884
|
-
}
|
|
34885
|
-
return null;
|
|
34886
|
-
}
|
|
34887
|
-
function findTableInfo(editor, pos) {
|
|
34888
|
-
const $pos = editor.state.doc.resolve(pos);
|
|
34889
|
-
for (let depth = $pos.depth; depth > 0; depth -= 1) {
|
|
34890
|
-
const node = $pos.node(depth);
|
|
34891
|
-
if (node.type.name === "table") {
|
|
34892
|
-
return {
|
|
34893
|
-
node,
|
|
34894
|
-
pos: $pos.before(depth),
|
|
34895
|
-
start: $pos.start(depth)
|
|
34896
|
-
};
|
|
34897
|
-
}
|
|
34898
|
-
}
|
|
34899
|
-
return null;
|
|
34900
|
-
}
|
|
34901
|
-
function getCellRelativePosFromDomPos(map, tableStart, domPos) {
|
|
34902
|
-
const relativeDomPos = domPos - tableStart;
|
|
34903
|
-
const seen = /* @__PURE__ */ new Set();
|
|
34904
|
-
for (const relativeCellPos of map.map) {
|
|
34905
|
-
if (seen.has(relativeCellPos)) continue;
|
|
34906
|
-
seen.add(relativeCellPos);
|
|
34907
|
-
if (relativeDomPos === relativeCellPos || relativeDomPos === relativeCellPos + 1) {
|
|
34908
|
-
return relativeCellPos;
|
|
34909
|
-
}
|
|
34910
|
-
}
|
|
34911
|
-
return null;
|
|
34912
|
-
}
|
|
34913
|
-
function buildLogicalColumnMetrics({
|
|
34914
|
-
editor,
|
|
34915
|
-
surface,
|
|
34916
|
-
surfaceRect,
|
|
34917
|
-
tableElement,
|
|
34918
|
-
tableInfo,
|
|
34919
|
-
tableLeft,
|
|
34920
|
-
tableWidth
|
|
34921
|
-
}) {
|
|
34922
|
-
const map = TableMap2.get(tableInfo.node);
|
|
34923
|
-
const fallbackWidth = metricOrFallback(tableWidth / map.width, FALLBACK_TABLE_COLUMN_WIDTH);
|
|
34924
|
-
const firstRow = tableElement.rows.item(0);
|
|
34925
|
-
const visualColumns = [];
|
|
34926
|
-
if (firstRow) {
|
|
34927
|
-
for (const tableCell of Array.from(firstRow.cells)) {
|
|
34928
|
-
if (!(tableCell instanceof HTMLTableCellElement)) continue;
|
|
34929
|
-
const cellPos = editor.view.posAtDOM(tableCell, 0);
|
|
34930
|
-
const relativeCellPos = getCellRelativePosFromDomPos(map, tableInfo.start, cellPos);
|
|
34931
|
-
if (relativeCellPos == null) continue;
|
|
34932
|
-
const cellMapRect = map.findCell(relativeCellPos);
|
|
34933
|
-
const cellRect = tableCell.getBoundingClientRect();
|
|
34934
|
-
const cellStart = cellRect.width > 0 ? cellRect.left - surfaceRect.left + surface.scrollLeft : tableLeft + cellMapRect.left * fallbackWidth;
|
|
34935
|
-
const size = metricOrFallback(cellRect.width, fallbackWidth * Math.max(1, cellMapRect.right - cellMapRect.left));
|
|
34936
|
-
visualColumns.push({
|
|
34937
|
-
index: cellMapRect.left,
|
|
34938
|
-
cellPos: tableInfo.start + relativeCellPos,
|
|
34939
|
-
start: cellStart,
|
|
34940
|
-
size,
|
|
34941
|
-
center: cellStart + size / 2
|
|
34942
|
-
});
|
|
34943
|
-
}
|
|
34944
|
-
}
|
|
34945
|
-
if (visualColumns.length > 0) {
|
|
34946
|
-
return visualColumns.sort((a, b) => a.index - b.index);
|
|
34947
|
-
}
|
|
34948
|
-
const cols = Array.from(tableElement.querySelectorAll("colgroup > col"));
|
|
34949
|
-
const parsedWidths = cols.slice(0, map.width).map((col) => parsePixelMetric(col.style.width) ?? parsePixelMetric(col.getAttribute("width")));
|
|
34950
|
-
const hasCompleteColWidths = parsedWidths.length >= map.width && parsedWidths.every((width) => typeof width === "number");
|
|
34951
|
-
let cursor = tableLeft;
|
|
34952
|
-
return Array.from({ length: map.width }, (_, index) => {
|
|
34953
|
-
const size = hasCompleteColWidths ? parsedWidths[index] : fallbackWidth;
|
|
34954
|
-
const start = hasCompleteColWidths ? cursor : tableLeft + index * fallbackWidth;
|
|
34955
|
-
cursor += size;
|
|
34956
|
-
return {
|
|
34957
|
-
index,
|
|
34958
|
-
cellPos: tableInfo.start + map.positionAt(0, index, tableInfo.node),
|
|
34959
|
-
start,
|
|
34960
|
-
size,
|
|
34961
|
-
center: start + size / 2
|
|
34962
|
-
};
|
|
34963
|
-
});
|
|
34964
|
-
}
|
|
34965
|
-
function buildLogicalRowMetrics({
|
|
34966
|
-
editor,
|
|
34967
|
-
surface,
|
|
34968
|
-
surfaceRect,
|
|
34969
|
-
tableInfo,
|
|
34970
|
-
rows,
|
|
34971
|
-
tableTop,
|
|
34972
|
-
tableHeight,
|
|
34973
|
-
cornerCell
|
|
34974
|
-
}) {
|
|
34975
|
-
const map = TableMap2.get(tableInfo.node);
|
|
34976
|
-
const fallbackHeight = metricOrFallback(tableHeight / map.height, FALLBACK_TABLE_ROW_HEIGHT);
|
|
34977
|
-
const visualRows = [];
|
|
34978
|
-
const seenCellPositions = /* @__PURE__ */ new Set();
|
|
34979
|
-
for (let rowIndex = 0; rowIndex < map.height; rowIndex += 1) {
|
|
34980
|
-
const relativeCellPos = map.map[rowIndex * map.width];
|
|
34981
|
-
if (seenCellPositions.has(relativeCellPos)) continue;
|
|
34982
|
-
seenCellPositions.add(relativeCellPos);
|
|
34983
|
-
const cellMapRect = map.findCell(relativeCellPos);
|
|
34984
|
-
const cellDom = editor.view.nodeDOM(tableInfo.start + relativeCellPos);
|
|
34985
|
-
const tableCell = cellDom instanceof HTMLTableCellElement ? cellDom : null;
|
|
34986
|
-
if (tableCell) {
|
|
34987
|
-
const cellRect = tableCell.getBoundingClientRect();
|
|
34988
|
-
const start = cellRect.height > 0 ? cellRect.top - surfaceRect.top + surface.scrollTop : tableTop + cellMapRect.top * fallbackHeight;
|
|
34989
|
-
const size = metricOrFallback(cellRect.height, fallbackHeight * Math.max(1, cellMapRect.bottom - cellMapRect.top));
|
|
34990
|
-
visualRows.push({
|
|
34991
|
-
index: cellMapRect.top,
|
|
34992
|
-
cellPos: tableInfo.start + relativeCellPos,
|
|
34993
|
-
start,
|
|
34994
|
-
size,
|
|
34995
|
-
center: start + size / 2
|
|
34996
|
-
});
|
|
34997
|
-
}
|
|
34998
|
-
}
|
|
34999
|
-
if (visualRows.length > 0) {
|
|
35000
|
-
return visualRows.sort((a, b) => a.index - b.index);
|
|
35001
|
-
}
|
|
35002
|
-
return rows.map((tableRow, index) => {
|
|
35003
|
-
const rowRect = tableRow.getBoundingClientRect();
|
|
35004
|
-
const anchorCell = tableRow.cells.item(0) ?? cornerCell;
|
|
35005
|
-
const start = rowRect.height > 0 ? rowRect.top - surfaceRect.top + surface.scrollTop : tableTop + index * fallbackHeight;
|
|
35006
|
-
const size = metricOrFallback(rowRect.height, fallbackHeight);
|
|
35007
|
-
return {
|
|
35008
|
-
index,
|
|
35009
|
-
cellPos: editor.view.posAtDOM(anchorCell, 0),
|
|
35010
|
-
start,
|
|
35011
|
-
size,
|
|
35012
|
-
center: start + size / 2
|
|
35013
|
-
};
|
|
35014
|
-
});
|
|
35015
|
-
}
|
|
35016
|
-
function buildTableControlLayout(editor, surface, cell) {
|
|
35017
|
-
const row = cell.closest("tr");
|
|
35018
|
-
const table = cell.closest("table");
|
|
35019
|
-
if (!(row instanceof HTMLTableRowElement) || !(table instanceof HTMLTableElement)) {
|
|
35020
|
-
return null;
|
|
35021
|
-
}
|
|
35022
|
-
const rows = Array.from(table.rows).filter((item) => item instanceof HTMLTableRowElement);
|
|
35023
|
-
const cornerCell = getLastCell(table);
|
|
35024
|
-
const cellPos = editor.view.posAtDOM(cell, 0);
|
|
35025
|
-
const tableInfo = findTableInfo(editor, cellPos);
|
|
35026
|
-
if (rows.length === 0 || !tableInfo || !(cornerCell instanceof HTMLTableCellElement)) {
|
|
35027
|
-
return null;
|
|
35028
|
-
}
|
|
35029
|
-
const map = TableMap2.get(tableInfo.node);
|
|
35030
|
-
const surfaceRect = surface.getBoundingClientRect();
|
|
35031
|
-
const tableRect = table.getBoundingClientRect();
|
|
35032
|
-
const wrapperElement = table.closest(".tableWrapper");
|
|
35033
|
-
const wrapper = wrapperElement instanceof HTMLElement ? wrapperElement : null;
|
|
35034
|
-
const wrapperRect = wrapper?.getBoundingClientRect() ?? tableRect;
|
|
35035
|
-
const tableLeft = tableRect.left - surfaceRect.left + surface.scrollLeft;
|
|
35036
|
-
const tableTop = tableRect.top - surfaceRect.top + surface.scrollTop;
|
|
35037
|
-
const avgRowHeight = metricOrFallback(tableRect.height / rows.length, FALLBACK_TABLE_ROW_HEIGHT);
|
|
35038
|
-
const avgColumnWidth = metricOrFallback(tableRect.width / map.width, FALLBACK_TABLE_COLUMN_WIDTH);
|
|
35039
|
-
const tableWidth = metricOrFallback(tableRect.width, avgColumnWidth * map.width);
|
|
35040
|
-
const tableHeight = metricOrFallback(tableRect.height, avgRowHeight * rows.length);
|
|
35041
|
-
const wrapperLeft = wrapperRect.left - surfaceRect.left + surface.scrollLeft;
|
|
35042
|
-
const wrapperTop = wrapperRect.top - surfaceRect.top + surface.scrollTop;
|
|
35043
|
-
const wrapperWidth = metricOrFallback(wrapperRect.width, tableWidth);
|
|
35044
|
-
const wrapperHeight = metricOrFallback(wrapperRect.height, tableHeight);
|
|
35045
|
-
const viewportWidth = metricOrFallback(wrapper?.clientWidth ?? wrapperRect.width, tableWidth);
|
|
35046
|
-
const viewportHeight = metricOrFallback(wrapper?.clientHeight ?? wrapperRect.height, tableHeight);
|
|
35047
|
-
const verticalScrollbarWidth = Math.max(0, Math.round(wrapperWidth - viewportWidth));
|
|
35048
|
-
const horizontalScrollbarHeight = Math.max(0, Math.round(wrapperHeight - viewportHeight));
|
|
35049
|
-
const rowHandles = buildLogicalRowMetrics({
|
|
35050
|
-
editor,
|
|
35051
|
-
surface,
|
|
35052
|
-
surfaceRect,
|
|
35053
|
-
tableInfo,
|
|
35054
|
-
rows,
|
|
35055
|
-
tableTop,
|
|
35056
|
-
tableHeight,
|
|
35057
|
-
cornerCell
|
|
35058
|
-
});
|
|
35059
|
-
const columnHandles = buildLogicalColumnMetrics({
|
|
35060
|
-
editor,
|
|
35061
|
-
surface,
|
|
35062
|
-
surfaceRect,
|
|
35063
|
-
tableElement: table,
|
|
35064
|
-
tableInfo,
|
|
35065
|
-
tableLeft,
|
|
35066
|
-
tableWidth
|
|
35067
|
-
});
|
|
35068
|
-
const activeCellRelativePos = getCellRelativePosFromDomPos(map, tableInfo.start, cellPos);
|
|
35069
|
-
const activeCellRect = activeCellRelativePos != null ? map.findCell(activeCellRelativePos) : { left: cell.cellIndex, top: row.rowIndex };
|
|
35070
|
-
const normalizedCellPos = activeCellRelativePos != null ? tableInfo.start + activeCellRelativePos : cellPos;
|
|
35071
|
-
return {
|
|
35072
|
-
cellPos: normalizedCellPos,
|
|
35073
|
-
cornerCellPos: tableInfo.start + map.positionAt(map.height - 1, map.width - 1, tableInfo.node),
|
|
35074
|
-
activeRowIndex: activeCellRect.top,
|
|
35075
|
-
activeColumnIndex: activeCellRect.left,
|
|
35076
|
-
tableLeft,
|
|
35077
|
-
tableTop,
|
|
35078
|
-
tableWidth,
|
|
35079
|
-
tableHeight,
|
|
35080
|
-
wrapperLeft,
|
|
35081
|
-
wrapperTop,
|
|
35082
|
-
wrapperWidth,
|
|
35083
|
-
wrapperHeight,
|
|
35084
|
-
viewportWidth,
|
|
35085
|
-
viewportHeight,
|
|
35086
|
-
horizontalScrollbarHeight,
|
|
35087
|
-
verticalScrollbarWidth,
|
|
35088
|
-
avgRowHeight,
|
|
35089
|
-
avgColumnWidth,
|
|
35090
|
-
rowHandles,
|
|
35091
|
-
columnHandles
|
|
35092
|
-
};
|
|
35093
|
-
}
|
|
35094
|
-
|
|
35095
36290
|
// src/components/UEditor/table-controls.tsx
|
|
35096
36291
|
import { Fragment as Fragment34, jsx as jsx91, jsxs as jsxs76 } from "react/jsx-runtime";
|
|
35097
36292
|
var TABLE_MENU_TOP_OFFSET = 10;
|