@underverse-ui/underverse 1.0.183 → 1.0.184
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 +592 -234
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +571 -213
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -27369,7 +27369,7 @@ function useLocale2() {
|
|
|
27369
27369
|
}
|
|
27370
27370
|
|
|
27371
27371
|
// src/components/UEditor/UEditor.tsx
|
|
27372
|
-
import React87, { useEffect as
|
|
27372
|
+
import React87, { useEffect as useEffect40, useImperativeHandle as useImperativeHandle4, useMemo as useMemo27, useRef as useRef39 } from "react";
|
|
27373
27373
|
import { useEditor, EditorContent } from "@tiptap/react";
|
|
27374
27374
|
|
|
27375
27375
|
// src/components/UEditor/extensions.ts
|
|
@@ -29905,11 +29905,17 @@ function isInTableCell(editor) {
|
|
|
29905
29905
|
}
|
|
29906
29906
|
function buildFormulaSuggestionItems({ query }) {
|
|
29907
29907
|
const normalizedQuery = query.trim().toUpperCase();
|
|
29908
|
+
if (!isFormulaFunctionSuggestionQuery(normalizedQuery)) {
|
|
29909
|
+
return [];
|
|
29910
|
+
}
|
|
29908
29911
|
if (!normalizedQuery) {
|
|
29909
29912
|
return FORMULA_FUNCTIONS;
|
|
29910
29913
|
}
|
|
29911
29914
|
return FORMULA_FUNCTIONS.filter((item) => item.name.startsWith(normalizedQuery));
|
|
29912
29915
|
}
|
|
29916
|
+
function isFormulaFunctionSuggestionQuery(query) {
|
|
29917
|
+
return /^[A-Z]*$/i.test(query.trim());
|
|
29918
|
+
}
|
|
29913
29919
|
var FormulaSuggestionList = forwardRef16((props, ref) => {
|
|
29914
29920
|
const t = useSmartTranslations("UEditor");
|
|
29915
29921
|
const [selectedIndex, setSelectedIndex] = React76.useState(0);
|
|
@@ -29980,7 +29986,11 @@ var FormulaSuggestion = Extension4.create({
|
|
|
29980
29986
|
editor: this.editor,
|
|
29981
29987
|
char: "=",
|
|
29982
29988
|
pluginKey: new PluginKey3("formulaSuggestion"),
|
|
29983
|
-
allow: ({ editor }) =>
|
|
29989
|
+
allow: ({ editor, range }) => {
|
|
29990
|
+
if (!isInTableCell(editor)) return false;
|
|
29991
|
+
const suggestionText = editor.state.doc.textBetween(range.from, range.to, "", "");
|
|
29992
|
+
return suggestionText.startsWith("=") && isFormulaFunctionSuggestionQuery(suggestionText.slice(1));
|
|
29993
|
+
},
|
|
29984
29994
|
command: ({ editor, range, props }) => {
|
|
29985
29995
|
insertFormulaFunction(editor, range, props);
|
|
29986
29996
|
},
|
|
@@ -33983,51 +33993,98 @@ function buildTableFormulaDependencyGraph(cells) {
|
|
|
33983
33993
|
return { dependencies, dependents, formulas };
|
|
33984
33994
|
}
|
|
33985
33995
|
function getTableFormulaCircularReferences(graph) {
|
|
33986
|
-
const visiting = /* @__PURE__ */ new Set();
|
|
33987
|
-
const visited = /* @__PURE__ */ new Set();
|
|
33988
33996
|
const circular = /* @__PURE__ */ new Set();
|
|
33989
|
-
const
|
|
33990
|
-
const
|
|
33991
|
-
|
|
33992
|
-
|
|
33993
|
-
|
|
33994
|
-
|
|
33997
|
+
const visited = /* @__PURE__ */ new Set();
|
|
33998
|
+
const finishOrder = [];
|
|
33999
|
+
for (const startLabel of graph.formulas.keys()) {
|
|
34000
|
+
if (visited.has(startLabel)) continue;
|
|
34001
|
+
visited.add(startLabel);
|
|
34002
|
+
const stack = [
|
|
34003
|
+
{
|
|
34004
|
+
label: startLabel,
|
|
34005
|
+
references: Array.from(graph.dependencies.get(startLabel) ?? []).filter((ref) => graph.formulas.has(ref)),
|
|
34006
|
+
nextIndex: 0
|
|
33995
34007
|
}
|
|
33996
|
-
|
|
33997
|
-
|
|
33998
|
-
|
|
33999
|
-
|
|
34000
|
-
|
|
34001
|
-
|
|
34002
|
-
|
|
34003
|
-
|
|
34008
|
+
];
|
|
34009
|
+
while (stack.length > 0) {
|
|
34010
|
+
const frame = stack[stack.length - 1];
|
|
34011
|
+
if (!frame) break;
|
|
34012
|
+
const reference = frame.references[frame.nextIndex];
|
|
34013
|
+
if (reference) {
|
|
34014
|
+
frame.nextIndex += 1;
|
|
34015
|
+
if (!visited.has(reference)) {
|
|
34016
|
+
visited.add(reference);
|
|
34017
|
+
stack.push({
|
|
34018
|
+
label: reference,
|
|
34019
|
+
references: Array.from(graph.dependencies.get(reference) ?? []).filter((ref) => graph.formulas.has(ref)),
|
|
34020
|
+
nextIndex: 0
|
|
34021
|
+
});
|
|
34022
|
+
}
|
|
34023
|
+
continue;
|
|
34004
34024
|
}
|
|
34025
|
+
stack.pop();
|
|
34026
|
+
finishOrder.push(frame.label);
|
|
34027
|
+
}
|
|
34028
|
+
}
|
|
34029
|
+
const assigned = /* @__PURE__ */ new Set();
|
|
34030
|
+
for (let index = finishOrder.length - 1; index >= 0; index -= 1) {
|
|
34031
|
+
const startLabel = finishOrder[index];
|
|
34032
|
+
if (!startLabel || assigned.has(startLabel)) continue;
|
|
34033
|
+
const component = [];
|
|
34034
|
+
const stack = [startLabel];
|
|
34035
|
+
assigned.add(startLabel);
|
|
34036
|
+
while (stack.length > 0) {
|
|
34037
|
+
const label = stack.pop();
|
|
34038
|
+
if (!label) continue;
|
|
34039
|
+
component.push(label);
|
|
34040
|
+
for (const dependent of graph.dependents.get(label) ?? []) {
|
|
34041
|
+
if (!graph.formulas.has(dependent) || assigned.has(dependent)) continue;
|
|
34042
|
+
assigned.add(dependent);
|
|
34043
|
+
stack.push(dependent);
|
|
34044
|
+
}
|
|
34045
|
+
}
|
|
34046
|
+
if (component.length > 1) {
|
|
34047
|
+
for (const label of component) circular.add(label);
|
|
34048
|
+
} else {
|
|
34049
|
+
const label = component[0];
|
|
34050
|
+
if (label && graph.dependencies.get(label)?.has(label)) circular.add(label);
|
|
34005
34051
|
}
|
|
34006
|
-
stack.pop();
|
|
34007
|
-
visiting.delete(label);
|
|
34008
|
-
visited.add(label);
|
|
34009
|
-
};
|
|
34010
|
-
for (const label of graph.formulas.keys()) {
|
|
34011
|
-
visit(label);
|
|
34012
34052
|
}
|
|
34013
34053
|
return circular;
|
|
34014
34054
|
}
|
|
34015
34055
|
function getTableFormulaRecalculationOrder(graph) {
|
|
34016
34056
|
const circular = getTableFormulaCircularReferences(graph);
|
|
34057
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
34017
34058
|
const visited = /* @__PURE__ */ new Set();
|
|
34018
34059
|
const order = [];
|
|
34019
|
-
const
|
|
34020
|
-
if (visited.has(
|
|
34021
|
-
|
|
34022
|
-
|
|
34023
|
-
|
|
34024
|
-
|
|
34060
|
+
for (const startLabel of graph.formulas.keys()) {
|
|
34061
|
+
if (visited.has(startLabel) || circular.has(startLabel)) continue;
|
|
34062
|
+
const stack = [];
|
|
34063
|
+
const push = (label) => {
|
|
34064
|
+
visiting.add(label);
|
|
34065
|
+
stack.push({
|
|
34066
|
+
label,
|
|
34067
|
+
references: Array.from(graph.dependencies.get(label) ?? []).filter((ref) => graph.formulas.has(ref) && !circular.has(ref)),
|
|
34068
|
+
nextIndex: 0
|
|
34069
|
+
});
|
|
34070
|
+
};
|
|
34071
|
+
push(startLabel);
|
|
34072
|
+
while (stack.length > 0) {
|
|
34073
|
+
const frame = stack[stack.length - 1];
|
|
34074
|
+
if (!frame) break;
|
|
34075
|
+
const reference = frame.references[frame.nextIndex];
|
|
34076
|
+
if (reference) {
|
|
34077
|
+
frame.nextIndex += 1;
|
|
34078
|
+
if (!visited.has(reference) && !visiting.has(reference)) {
|
|
34079
|
+
push(reference);
|
|
34080
|
+
}
|
|
34081
|
+
continue;
|
|
34025
34082
|
}
|
|
34083
|
+
stack.pop();
|
|
34084
|
+
visiting.delete(frame.label);
|
|
34085
|
+
visited.add(frame.label);
|
|
34086
|
+
order.push(frame.label);
|
|
34026
34087
|
}
|
|
34027
|
-
order.push(label);
|
|
34028
|
-
};
|
|
34029
|
-
for (const label of graph.formulas.keys()) {
|
|
34030
|
-
visit(label);
|
|
34031
34088
|
}
|
|
34032
34089
|
return { order, circular };
|
|
34033
34090
|
}
|
|
@@ -34086,9 +34143,11 @@ function tokenizeFormula(formula) {
|
|
|
34086
34143
|
index += 1;
|
|
34087
34144
|
continue;
|
|
34088
34145
|
}
|
|
34089
|
-
const numberMatch = formula.slice(index).match(
|
|
34146
|
+
const numberMatch = formula.slice(index).match(/^(?:\d+(?:\.\d*)?|\.\d+)/);
|
|
34090
34147
|
if (numberMatch?.[0]) {
|
|
34091
|
-
|
|
34148
|
+
const value = Number.parseFloat(numberMatch[0]);
|
|
34149
|
+
if (!Number.isFinite(value)) return null;
|
|
34150
|
+
tokens.push({ type: "number", value });
|
|
34092
34151
|
index += numberMatch[0].length;
|
|
34093
34152
|
continue;
|
|
34094
34153
|
}
|
|
@@ -34106,6 +34165,28 @@ function tokenizeFormula(formula) {
|
|
|
34106
34165
|
}
|
|
34107
34166
|
return tokens;
|
|
34108
34167
|
}
|
|
34168
|
+
function toFiniteFormulaResult(value) {
|
|
34169
|
+
return Number.isFinite(value) ? { value, error: null } : { value: null, error: "invalid-formula" };
|
|
34170
|
+
}
|
|
34171
|
+
function parseTableCellNumericValue(value) {
|
|
34172
|
+
if (typeof value === "number") {
|
|
34173
|
+
return Number.isFinite(value) ? value : null;
|
|
34174
|
+
}
|
|
34175
|
+
let normalized = String(value ?? "").trim();
|
|
34176
|
+
if (!normalized || normalized.startsWith("#")) return null;
|
|
34177
|
+
const isPercent = normalized.endsWith("%");
|
|
34178
|
+
if (isPercent) normalized = normalized.slice(0, -1).trim();
|
|
34179
|
+
const currencyMatch = normalized.match(/^([+-]?)\$(.+)$/);
|
|
34180
|
+
if (currencyMatch) {
|
|
34181
|
+
normalized = `${currencyMatch[1] ?? ""}${currencyMatch[2] ?? ""}`.trim();
|
|
34182
|
+
}
|
|
34183
|
+
const groupedNumber = /^[+-]?\d{1,3}(?:,\d{3})+(?:\.\d*)?(?:[eE][+-]?\d+)?$/;
|
|
34184
|
+
const plainNumber = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/;
|
|
34185
|
+
if (!groupedNumber.test(normalized) && !plainNumber.test(normalized)) return null;
|
|
34186
|
+
const parsed = Number(normalized.replace(/,/g, ""));
|
|
34187
|
+
if (!Number.isFinite(parsed)) return null;
|
|
34188
|
+
return isPercent ? parsed / 100 : parsed;
|
|
34189
|
+
}
|
|
34109
34190
|
var FormulaParser = class {
|
|
34110
34191
|
constructor(tokens, getCellValue) {
|
|
34111
34192
|
this.tokens = tokens;
|
|
@@ -34123,10 +34204,7 @@ var FormulaParser = class {
|
|
|
34123
34204
|
this.index += 1;
|
|
34124
34205
|
const right = this.parseTerm();
|
|
34125
34206
|
if (right.error) return right;
|
|
34126
|
-
left =
|
|
34127
|
-
value: operator.value === "+" ? left.value + right.value : left.value - right.value,
|
|
34128
|
-
error: null
|
|
34129
|
-
};
|
|
34207
|
+
left = toFiniteFormulaResult(operator.value === "+" ? left.value + right.value : left.value - right.value);
|
|
34130
34208
|
}
|
|
34131
34209
|
return left;
|
|
34132
34210
|
}
|
|
@@ -34141,10 +34219,7 @@ var FormulaParser = class {
|
|
|
34141
34219
|
if (operator.value === "/" && right.value === 0) {
|
|
34142
34220
|
return { value: null, error: "division-by-zero" };
|
|
34143
34221
|
}
|
|
34144
|
-
left =
|
|
34145
|
-
value: operator.value === "*" ? left.value * right.value : left.value / right.value,
|
|
34146
|
-
error: null
|
|
34147
|
-
};
|
|
34222
|
+
left = toFiniteFormulaResult(operator.value === "*" ? left.value * right.value : left.value / right.value);
|
|
34148
34223
|
}
|
|
34149
34224
|
return left;
|
|
34150
34225
|
}
|
|
@@ -34153,11 +34228,11 @@ var FormulaParser = class {
|
|
|
34153
34228
|
if (!token) {
|
|
34154
34229
|
return { value: null, error: "invalid-formula" };
|
|
34155
34230
|
}
|
|
34156
|
-
if (token.type === "operator" && token.value === "-") {
|
|
34231
|
+
if (token.type === "operator" && (token.value === "-" || token.value === "+")) {
|
|
34157
34232
|
this.index += 1;
|
|
34158
34233
|
const value = this.parseFactor();
|
|
34159
34234
|
if (value.error) return value;
|
|
34160
|
-
return
|
|
34235
|
+
return toFiniteFormulaResult(token.value === "-" ? -value.value : value.value);
|
|
34161
34236
|
}
|
|
34162
34237
|
if (token.type === "number") {
|
|
34163
34238
|
this.index += 1;
|
|
@@ -34202,11 +34277,10 @@ var FormulaParser = class {
|
|
|
34202
34277
|
if (cellValue2 != null) values.push(cellValue2);
|
|
34203
34278
|
continue;
|
|
34204
34279
|
}
|
|
34205
|
-
const cellValue = this.
|
|
34206
|
-
if (cellValue
|
|
34207
|
-
values.push(cellValue.value);
|
|
34280
|
+
const cellValue = this.readOptionalCellNumber(label);
|
|
34281
|
+
if (cellValue != null) values.push(cellValue);
|
|
34208
34282
|
}
|
|
34209
|
-
} else if (
|
|
34283
|
+
} else if (token.type === "cell") {
|
|
34210
34284
|
this.index += 1;
|
|
34211
34285
|
const cellValue = this.readOptionalCellNumber(token.value);
|
|
34212
34286
|
if (cellValue != null) values.push(cellValue);
|
|
@@ -34223,28 +34297,24 @@ var FormulaParser = class {
|
|
|
34223
34297
|
}
|
|
34224
34298
|
return { value: null, error: "invalid-formula" };
|
|
34225
34299
|
}
|
|
34226
|
-
if (values.
|
|
34227
|
-
|
|
34300
|
+
if (name === "SUM") return toFiniteFormulaResult(values.reduce((sum, value) => sum + value, 0));
|
|
34301
|
+
if (name === "AVG") {
|
|
34302
|
+
return values.length > 0 ? toFiniteFormulaResult(values.reduce((sum, value) => sum + value, 0) / values.length) : { value: null, error: "division-by-zero" };
|
|
34228
34303
|
}
|
|
34229
|
-
if (name === "
|
|
34230
|
-
if (name === "
|
|
34231
|
-
if (name === "MIN") return { value: Math.min(...values), error: null };
|
|
34232
|
-
if (name === "MAX") return { value: Math.max(...values), error: null };
|
|
34304
|
+
if (name === "MIN") return toFiniteFormulaResult(values.length > 0 ? Math.min(...values) : 0);
|
|
34305
|
+
if (name === "MAX") return toFiniteFormulaResult(values.length > 0 ? Math.max(...values) : 0);
|
|
34233
34306
|
if (name === "COUNT") return { value: values.length, error: null };
|
|
34234
34307
|
return { value: null, error: "invalid-formula" };
|
|
34235
34308
|
}
|
|
34236
34309
|
readCellNumber(label) {
|
|
34237
|
-
const
|
|
34238
|
-
|
|
34239
|
-
if (!Number.isFinite(parsed)) {
|
|
34310
|
+
const parsed = parseTableCellNumericValue(this.getCellValue(label));
|
|
34311
|
+
if (parsed == null) {
|
|
34240
34312
|
return { value: null, error: "invalid-reference" };
|
|
34241
34313
|
}
|
|
34242
34314
|
return { value: parsed, error: null };
|
|
34243
34315
|
}
|
|
34244
34316
|
readOptionalCellNumber(label) {
|
|
34245
|
-
|
|
34246
|
-
const parsed = typeof value === "number" ? value : Number.parseFloat(String(value ?? "").trim());
|
|
34247
|
-
return Number.isFinite(parsed) ? parsed : null;
|
|
34317
|
+
return parseTableCellNumericValue(this.getCellValue(label));
|
|
34248
34318
|
}
|
|
34249
34319
|
peekOperator(operators) {
|
|
34250
34320
|
const token = this.tokens[this.index];
|
|
@@ -35360,7 +35430,7 @@ var CustomBubbleMenu = ({
|
|
|
35360
35430
|
const BUBBLE_MENU_ESTIMATED_HEIGHT = 44;
|
|
35361
35431
|
const [isVisible, setIsVisible] = useState50(false);
|
|
35362
35432
|
const [linkInputOpen, setLinkInputOpen] = useState50(false);
|
|
35363
|
-
const [position,
|
|
35433
|
+
const [position, setPosition2] = useState50({
|
|
35364
35434
|
top: 0,
|
|
35365
35435
|
left: 0,
|
|
35366
35436
|
placement: "top"
|
|
@@ -35432,7 +35502,7 @@ var CustomBubbleMenu = ({
|
|
|
35432
35502
|
Math.max(viewportPadding, (start.left + end.left) / 2)
|
|
35433
35503
|
);
|
|
35434
35504
|
const top = placement === "top" ? Math.max(viewportPadding, selectionTop - BUBBLE_MENU_OFFSET) : Math.min(window.innerHeight - viewportPadding, selectionBottom + BUBBLE_MENU_OFFSET);
|
|
35435
|
-
|
|
35505
|
+
setPosition2({ top, left, placement });
|
|
35436
35506
|
if (keepOpenRef.current) {
|
|
35437
35507
|
clearShowTimeout();
|
|
35438
35508
|
setIsVisible(true);
|
|
@@ -41961,8 +42031,401 @@ function useUEditorTableInteractions(editor, editable = true) {
|
|
|
41961
42031
|
};
|
|
41962
42032
|
}
|
|
41963
42033
|
|
|
42034
|
+
// src/components/UEditor/use-formula-coordinate-overlay.ts
|
|
42035
|
+
import { useEffect as useEffect39, useRef as useRef37 } from "react";
|
|
42036
|
+
import { TableMap as TableMap6 } from "@tiptap/pm/tables";
|
|
42037
|
+
|
|
42038
|
+
// src/components/UEditor/table-formula-range-picker.ts
|
|
42039
|
+
import { TextSelection as TextSelection4 } from "@tiptap/pm/state";
|
|
42040
|
+
import { TableMap as TableMap5 } from "@tiptap/pm/tables";
|
|
42041
|
+
function getCellText2(cellNode) {
|
|
42042
|
+
return cellNode.textBetween(0, cellNode.content.size, "\n").trim();
|
|
42043
|
+
}
|
|
42044
|
+
function getFormulaEditingTableContext(view) {
|
|
42045
|
+
const { $from } = view.state.selection;
|
|
42046
|
+
for (let depth = $from.depth; depth > 0; depth -= 1) {
|
|
42047
|
+
const node = $from.node(depth);
|
|
42048
|
+
if (node.type.name !== "tableCell" && node.type.name !== "tableHeader") continue;
|
|
42049
|
+
if (!getCellText2(node).startsWith("=")) return null;
|
|
42050
|
+
const cellPos = $from.before(depth);
|
|
42051
|
+
const cellDom = view.nodeDOM(cellPos);
|
|
42052
|
+
if (!(cellDom instanceof HTMLTableCellElement)) return null;
|
|
42053
|
+
const tableDepth = depth - 2;
|
|
42054
|
+
const tableNode = tableDepth > 0 ? $from.node(tableDepth) : null;
|
|
42055
|
+
if (!tableNode || tableNode.type.name !== "table") return null;
|
|
42056
|
+
const tableDom = cellDom.closest("table");
|
|
42057
|
+
if (!(tableDom instanceof HTMLTableElement)) return null;
|
|
42058
|
+
return {
|
|
42059
|
+
cellContentEnd: $from.end(depth),
|
|
42060
|
+
cellContentStart: $from.start(depth),
|
|
42061
|
+
cellDom,
|
|
42062
|
+
formula: getCellText2(node),
|
|
42063
|
+
tableDom,
|
|
42064
|
+
tableNode,
|
|
42065
|
+
tablePos: $from.before(tableDepth)
|
|
42066
|
+
};
|
|
42067
|
+
}
|
|
42068
|
+
return null;
|
|
42069
|
+
}
|
|
42070
|
+
function cancelFormulaEditing(view) {
|
|
42071
|
+
const context = getFormulaEditingTableContext(view);
|
|
42072
|
+
if (!context) return false;
|
|
42073
|
+
let tr = view.state.tr.delete(context.cellContentStart, context.cellContentEnd);
|
|
42074
|
+
const selectionPos = Math.min(context.cellContentStart, tr.doc.content.size);
|
|
42075
|
+
tr = tr.setSelection(TextSelection4.near(tr.doc.resolve(selectionPos)));
|
|
42076
|
+
view.dispatch(tr);
|
|
42077
|
+
view.focus();
|
|
42078
|
+
return true;
|
|
42079
|
+
}
|
|
42080
|
+
function getReferenceInsertionPrefix(view, cellContentStart, insertionPos) {
|
|
42081
|
+
const textBeforeCursor = view.state.doc.textBetween(cellContentStart, insertionPos, "", "");
|
|
42082
|
+
const isInsideFunctionArguments = /[A-Z]+\([^)]*$/i.test(textBeforeCursor);
|
|
42083
|
+
const followsReference = /[A-Z]+[1-9]\d*(?::[A-Z]+[1-9]\d*)?\s*$/i.test(textBeforeCursor);
|
|
42084
|
+
return isInsideFunctionArguments && followsReference ? "," : "";
|
|
42085
|
+
}
|
|
42086
|
+
function findTableForPos(view, pos) {
|
|
42087
|
+
const $pos = view.state.doc.resolve(pos);
|
|
42088
|
+
for (let depth = $pos.depth; depth > 0; depth -= 1) {
|
|
42089
|
+
const node = $pos.node(depth);
|
|
42090
|
+
if (node.type.name === "table") {
|
|
42091
|
+
return {
|
|
42092
|
+
node,
|
|
42093
|
+
pos: $pos.before(depth),
|
|
42094
|
+
start: $pos.start(depth)
|
|
42095
|
+
};
|
|
42096
|
+
}
|
|
42097
|
+
}
|
|
42098
|
+
return null;
|
|
42099
|
+
}
|
|
42100
|
+
function getCellRelativePosFromDomPos2(map, tableStart, domPos) {
|
|
42101
|
+
const relativeDomPos = domPos - tableStart;
|
|
42102
|
+
const seen = /* @__PURE__ */ new Set();
|
|
42103
|
+
for (const relativeCellPos of map.map) {
|
|
42104
|
+
if (seen.has(relativeCellPos)) continue;
|
|
42105
|
+
seen.add(relativeCellPos);
|
|
42106
|
+
if (relativeDomPos === relativeCellPos || relativeDomPos === relativeCellPos + 1) {
|
|
42107
|
+
return relativeCellPos;
|
|
42108
|
+
}
|
|
42109
|
+
}
|
|
42110
|
+
return null;
|
|
42111
|
+
}
|
|
42112
|
+
function getFormulaTableCellInfo(view, target, tablePos) {
|
|
42113
|
+
const element = resolveEventElement(target);
|
|
42114
|
+
const cell = element?.closest?.("th,td");
|
|
42115
|
+
if (!(cell instanceof HTMLTableCellElement)) return null;
|
|
42116
|
+
const domPos = view.posAtDOM(cell, 0);
|
|
42117
|
+
const tableInfo = findTableForPos(view, domPos);
|
|
42118
|
+
if (!tableInfo || tableInfo.pos !== tablePos) return null;
|
|
42119
|
+
const map = TableMap5.get(tableInfo.node);
|
|
42120
|
+
const relativeCellPos = getCellRelativePosFromDomPos2(map, tableInfo.start, domPos);
|
|
42121
|
+
if (relativeCellPos == null) return null;
|
|
42122
|
+
const rect = map.findCell(relativeCellPos);
|
|
42123
|
+
return {
|
|
42124
|
+
cell,
|
|
42125
|
+
label: `${indexToColumnName(rect.left)}${rect.top + 1}`,
|
|
42126
|
+
rect
|
|
42127
|
+
};
|
|
42128
|
+
}
|
|
42129
|
+
function normalizeFormulaRangeLabel(fromLabel, toLabel) {
|
|
42130
|
+
return fromLabel === toLabel ? fromLabel : `${fromLabel}:${toLabel}`;
|
|
42131
|
+
}
|
|
42132
|
+
function replacePickedLabel(view, pickState, nextLabel, currentCell) {
|
|
42133
|
+
if (nextLabel === pickState.currentLabel && currentCell === pickState.currentCell) return pickState;
|
|
42134
|
+
if (nextLabel === pickState.currentLabel) {
|
|
42135
|
+
return {
|
|
42136
|
+
...pickState,
|
|
42137
|
+
currentCell
|
|
42138
|
+
};
|
|
42139
|
+
}
|
|
42140
|
+
let tr = view.state.tr.insertText(nextLabel, pickState.insertedFrom, pickState.insertedTo);
|
|
42141
|
+
const nextTo = pickState.insertedFrom + nextLabel.length;
|
|
42142
|
+
tr = tr.setSelection(TextSelection4.create(tr.doc, nextTo));
|
|
42143
|
+
view.dispatch(tr);
|
|
42144
|
+
return {
|
|
42145
|
+
...pickState,
|
|
42146
|
+
insertedTo: nextTo,
|
|
42147
|
+
currentLabel: nextLabel,
|
|
42148
|
+
currentCell
|
|
42149
|
+
};
|
|
42150
|
+
}
|
|
42151
|
+
function beginFormulaRangePick(view, event) {
|
|
42152
|
+
if (event.button !== 0) return null;
|
|
42153
|
+
const formulaCell = getFormulaEditingTableContext(view);
|
|
42154
|
+
if (!formulaCell) return null;
|
|
42155
|
+
const picked = getFormulaTableCellInfo(view, event.target, formulaCell.tablePos);
|
|
42156
|
+
if (!picked || picked.cell === formulaCell.cellDom) return null;
|
|
42157
|
+
const { from, to } = view.state.selection;
|
|
42158
|
+
const prefix = from === to ? getReferenceInsertionPrefix(view, formulaCell.cellContentStart, from) : "";
|
|
42159
|
+
const insertedText = `${prefix}${picked.label}`;
|
|
42160
|
+
const insertedFrom = from + prefix.length;
|
|
42161
|
+
let tr = view.state.tr.insertText(insertedText, from, to);
|
|
42162
|
+
tr = tr.setSelection(TextSelection4.create(tr.doc, from + insertedText.length));
|
|
42163
|
+
view.dispatch(tr);
|
|
42164
|
+
view.focus();
|
|
42165
|
+
event.preventDefault();
|
|
42166
|
+
event.stopPropagation();
|
|
42167
|
+
return {
|
|
42168
|
+
anchorLabel: picked.label,
|
|
42169
|
+
anchorCell: picked.cell,
|
|
42170
|
+
tablePos: formulaCell.tablePos,
|
|
42171
|
+
insertedFrom,
|
|
42172
|
+
insertedTo: insertedFrom + picked.label.length,
|
|
42173
|
+
currentLabel: picked.label,
|
|
42174
|
+
currentCell: picked.cell
|
|
42175
|
+
};
|
|
42176
|
+
}
|
|
42177
|
+
function updateFormulaRangePick(view, pickState, event) {
|
|
42178
|
+
const picked = getFormulaTableCellInfo(view, event.target, pickState.tablePos);
|
|
42179
|
+
if (!picked) return pickState;
|
|
42180
|
+
event.preventDefault();
|
|
42181
|
+
event.stopPropagation();
|
|
42182
|
+
return replacePickedLabel(
|
|
42183
|
+
view,
|
|
42184
|
+
pickState,
|
|
42185
|
+
normalizeFormulaRangeLabel(pickState.anchorLabel, picked.label),
|
|
42186
|
+
picked.cell
|
|
42187
|
+
);
|
|
42188
|
+
}
|
|
42189
|
+
function getFormulaRangePickHighlight(container, pickState) {
|
|
42190
|
+
if (!container.contains(pickState.anchorCell) || !container.contains(pickState.currentCell)) return null;
|
|
42191
|
+
const containerRect = container.getBoundingClientRect();
|
|
42192
|
+
const anchorRect = pickState.anchorCell.getBoundingClientRect();
|
|
42193
|
+
const currentRect = pickState.currentCell.getBoundingClientRect();
|
|
42194
|
+
const left = Math.min(anchorRect.left, currentRect.left) - containerRect.left + container.scrollLeft;
|
|
42195
|
+
const top = Math.min(anchorRect.top, currentRect.top) - containerRect.top + container.scrollTop;
|
|
42196
|
+
const right = Math.max(anchorRect.right, currentRect.right) - containerRect.left + container.scrollLeft;
|
|
42197
|
+
const bottom = Math.max(anchorRect.bottom, currentRect.bottom) - containerRect.top + container.scrollTop;
|
|
42198
|
+
return {
|
|
42199
|
+
left,
|
|
42200
|
+
top,
|
|
42201
|
+
width: Math.max(0, right - left),
|
|
42202
|
+
height: Math.max(0, bottom - top)
|
|
42203
|
+
};
|
|
42204
|
+
}
|
|
42205
|
+
|
|
42206
|
+
// src/components/UEditor/use-formula-coordinate-overlay.ts
|
|
42207
|
+
function setPosition(element, left, top, width, height) {
|
|
42208
|
+
element.style.left = `${left}px`;
|
|
42209
|
+
element.style.top = `${top}px`;
|
|
42210
|
+
if (width != null) element.style.width = `${Math.max(0, width)}px`;
|
|
42211
|
+
if (height != null) element.style.height = `${Math.max(0, height)}px`;
|
|
42212
|
+
}
|
|
42213
|
+
function createCoordinateLabel(kind, label) {
|
|
42214
|
+
const element = document.createElement("span");
|
|
42215
|
+
element.dataset.ueditorFormulaCoordinate = kind;
|
|
42216
|
+
element.textContent = label;
|
|
42217
|
+
element.className = "pointer-events-none absolute z-30 flex items-center justify-center rounded-[3px] border border-primary/35 bg-primary/90 px-1 font-mono text-[10px] font-semibold leading-none text-primary-foreground shadow-sm";
|
|
42218
|
+
return element;
|
|
42219
|
+
}
|
|
42220
|
+
function createReferenceHighlight(label) {
|
|
42221
|
+
const element = document.createElement("span");
|
|
42222
|
+
element.dataset.ueditorFormulaReference = label;
|
|
42223
|
+
element.className = "pointer-events-none absolute z-[21] rounded-[2px] border-2 border-emerald-500 bg-emerald-500/15";
|
|
42224
|
+
return element;
|
|
42225
|
+
}
|
|
42226
|
+
function useFormulaCoordinateOverlay(editor, containerRef, labels) {
|
|
42227
|
+
const overlayRef = useRef37(null);
|
|
42228
|
+
useEffect39(() => {
|
|
42229
|
+
if (!editor) return void 0;
|
|
42230
|
+
const overlay = overlayRef.current;
|
|
42231
|
+
const container = containerRef.current;
|
|
42232
|
+
if (!overlay || !container) return void 0;
|
|
42233
|
+
let animationFrame = null;
|
|
42234
|
+
let activeTable = null;
|
|
42235
|
+
let activeTablePos = null;
|
|
42236
|
+
let hoverLabel = null;
|
|
42237
|
+
const clearOverlay = () => {
|
|
42238
|
+
activeTable = null;
|
|
42239
|
+
activeTablePos = null;
|
|
42240
|
+
hoverLabel = null;
|
|
42241
|
+
overlay.replaceChildren();
|
|
42242
|
+
overlay.style.display = "none";
|
|
42243
|
+
};
|
|
42244
|
+
const syncOverlay = () => {
|
|
42245
|
+
animationFrame = null;
|
|
42246
|
+
if (editor.isDestroyed) return;
|
|
42247
|
+
const context = getFormulaEditingTableContext(editor.view);
|
|
42248
|
+
if (!context) {
|
|
42249
|
+
clearOverlay();
|
|
42250
|
+
return;
|
|
42251
|
+
}
|
|
42252
|
+
const containerRect = container.getBoundingClientRect();
|
|
42253
|
+
const tableRect = context.tableDom.getBoundingClientRect();
|
|
42254
|
+
const tableLeft = tableRect.left - containerRect.left + container.scrollLeft;
|
|
42255
|
+
const tableTop = tableRect.top - containerRect.top + container.scrollTop;
|
|
42256
|
+
const map = TableMap6.get(context.tableNode);
|
|
42257
|
+
const columnSegments = Array(map.width);
|
|
42258
|
+
const rowSegments = Array(map.height);
|
|
42259
|
+
const cellInfos = [];
|
|
42260
|
+
for (const cell of context.tableDom.querySelectorAll("th,td")) {
|
|
42261
|
+
if (!(cell instanceof HTMLTableCellElement)) continue;
|
|
42262
|
+
const info = getFormulaTableCellInfo(editor.view, cell, context.tablePos);
|
|
42263
|
+
if (!info) continue;
|
|
42264
|
+
cellInfos.push(info);
|
|
42265
|
+
const cellRect = cell.getBoundingClientRect();
|
|
42266
|
+
const columnSpan = Math.max(1, info.rect.right - info.rect.left);
|
|
42267
|
+
const rowSpan = Math.max(1, info.rect.bottom - info.rect.top);
|
|
42268
|
+
const columnWidth = cellRect.width / columnSpan;
|
|
42269
|
+
const rowHeight = cellRect.height / rowSpan;
|
|
42270
|
+
for (let column = info.rect.left; column < info.rect.right; column += 1) {
|
|
42271
|
+
if (!columnSegments[column] || columnSpan < columnSegments[column].span) {
|
|
42272
|
+
columnSegments[column] = {
|
|
42273
|
+
start: cellRect.left - containerRect.left + container.scrollLeft + (column - info.rect.left) * columnWidth,
|
|
42274
|
+
size: columnWidth,
|
|
42275
|
+
span: columnSpan
|
|
42276
|
+
};
|
|
42277
|
+
}
|
|
42278
|
+
}
|
|
42279
|
+
for (let row = info.rect.top; row < info.rect.bottom; row += 1) {
|
|
42280
|
+
if (!rowSegments[row] || rowSpan < rowSegments[row].span) {
|
|
42281
|
+
rowSegments[row] = {
|
|
42282
|
+
start: cellRect.top - containerRect.top + container.scrollTop + (row - info.rect.top) * rowHeight,
|
|
42283
|
+
size: rowHeight,
|
|
42284
|
+
span: rowSpan
|
|
42285
|
+
};
|
|
42286
|
+
}
|
|
42287
|
+
}
|
|
42288
|
+
}
|
|
42289
|
+
const fallbackColumnWidth = map.width > 0 ? tableRect.width / map.width : 0;
|
|
42290
|
+
const fallbackRowHeight = map.height > 0 ? tableRect.height / map.height : 0;
|
|
42291
|
+
const children = [];
|
|
42292
|
+
const actions = document.createElement("div");
|
|
42293
|
+
actions.dataset.ueditorFormulaActions = "";
|
|
42294
|
+
actions.className = "pointer-events-auto absolute z-50 flex items-center gap-1 rounded-md border border-border bg-background p-1 shadow-md";
|
|
42295
|
+
const formulaCellRect = context.cellDom.getBoundingClientRect();
|
|
42296
|
+
setPosition(
|
|
42297
|
+
actions,
|
|
42298
|
+
formulaCellRect.left - containerRect.left + container.scrollLeft,
|
|
42299
|
+
formulaCellRect.bottom - containerRect.top + container.scrollTop + 4
|
|
42300
|
+
);
|
|
42301
|
+
const applyButton = document.createElement("button");
|
|
42302
|
+
applyButton.type = "button";
|
|
42303
|
+
applyButton.dataset.ueditorFormulaApply = "";
|
|
42304
|
+
applyButton.disabled = isDraftTableFormula(context.formula);
|
|
42305
|
+
applyButton.textContent = `${applyButton.disabled ? "" : "\u2713 "}${labels.apply} (Enter)`;
|
|
42306
|
+
applyButton.className = "rounded bg-primary px-2.5 py-1 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-45";
|
|
42307
|
+
const cancelButton = document.createElement("button");
|
|
42308
|
+
cancelButton.type = "button";
|
|
42309
|
+
cancelButton.dataset.ueditorFormulaCancel = "";
|
|
42310
|
+
cancelButton.textContent = `${labels.cancel} (Esc)`;
|
|
42311
|
+
cancelButton.className = "rounded px-2.5 py-1 text-xs font-medium text-foreground hover:bg-muted";
|
|
42312
|
+
const preserveSelection = (event) => {
|
|
42313
|
+
event.preventDefault();
|
|
42314
|
+
event.stopPropagation();
|
|
42315
|
+
};
|
|
42316
|
+
applyButton.addEventListener("mousedown", preserveSelection);
|
|
42317
|
+
cancelButton.addEventListener("mousedown", preserveSelection);
|
|
42318
|
+
applyButton.addEventListener("click", (event) => {
|
|
42319
|
+
event.preventDefault();
|
|
42320
|
+
event.stopPropagation();
|
|
42321
|
+
if (!applyButton.disabled) recalculateActiveTableFormulas(editor);
|
|
42322
|
+
});
|
|
42323
|
+
cancelButton.addEventListener("click", (event) => {
|
|
42324
|
+
event.preventDefault();
|
|
42325
|
+
event.stopPropagation();
|
|
42326
|
+
cancelFormulaEditing(editor.view);
|
|
42327
|
+
});
|
|
42328
|
+
actions.append(applyButton, cancelButton);
|
|
42329
|
+
children.push(actions);
|
|
42330
|
+
for (let column = 0; column < map.width; column += 1) {
|
|
42331
|
+
const segment = columnSegments[column] ?? {
|
|
42332
|
+
start: tableLeft + column * fallbackColumnWidth,
|
|
42333
|
+
size: fallbackColumnWidth,
|
|
42334
|
+
span: map.width
|
|
42335
|
+
};
|
|
42336
|
+
const label = createCoordinateLabel("column", indexToColumnName(column));
|
|
42337
|
+
setPosition(label, segment.start, Math.max(0, tableTop - 22), segment.size, 20);
|
|
42338
|
+
children.push(label);
|
|
42339
|
+
}
|
|
42340
|
+
for (let row = 0; row < map.height; row += 1) {
|
|
42341
|
+
const segment = rowSegments[row] ?? {
|
|
42342
|
+
start: tableTop + row * fallbackRowHeight,
|
|
42343
|
+
size: fallbackRowHeight,
|
|
42344
|
+
span: map.height
|
|
42345
|
+
};
|
|
42346
|
+
const label = createCoordinateLabel("row", String(row + 1));
|
|
42347
|
+
setPosition(label, Math.max(0, tableLeft - 28), segment.start, 26, segment.size);
|
|
42348
|
+
children.push(label);
|
|
42349
|
+
}
|
|
42350
|
+
const references = new Set(getTableFormulaReferences(context.formula));
|
|
42351
|
+
for (const info of cellInfos) {
|
|
42352
|
+
if (!info || !references.has(info.label)) continue;
|
|
42353
|
+
const cellRect = info.cell.getBoundingClientRect();
|
|
42354
|
+
const highlight = createReferenceHighlight(info.label);
|
|
42355
|
+
setPosition(
|
|
42356
|
+
highlight,
|
|
42357
|
+
cellRect.left - containerRect.left + container.scrollLeft + 2,
|
|
42358
|
+
cellRect.top - containerRect.top + container.scrollTop + 2,
|
|
42359
|
+
cellRect.width - 4,
|
|
42360
|
+
cellRect.height - 4
|
|
42361
|
+
);
|
|
42362
|
+
children.push(highlight);
|
|
42363
|
+
}
|
|
42364
|
+
hoverLabel = document.createElement("span");
|
|
42365
|
+
hoverLabel.dataset.ueditorFormulaHoverLabel = "";
|
|
42366
|
+
hoverLabel.className = "pointer-events-none absolute z-40 hidden rounded bg-foreground px-1.5 py-1 font-mono text-[10px] font-semibold leading-none text-background shadow-md";
|
|
42367
|
+
children.push(hoverLabel);
|
|
42368
|
+
overlay.replaceChildren(...children);
|
|
42369
|
+
overlay.style.display = "block";
|
|
42370
|
+
activeTable = context.tableDom;
|
|
42371
|
+
activeTablePos = context.tablePos;
|
|
42372
|
+
};
|
|
42373
|
+
const scheduleSync = () => {
|
|
42374
|
+
if (animationFrame != null) return;
|
|
42375
|
+
animationFrame = window.requestAnimationFrame(syncOverlay);
|
|
42376
|
+
};
|
|
42377
|
+
const handleMouseMove2 = (event) => {
|
|
42378
|
+
if (!activeTable || activeTablePos == null || !hoverLabel) return;
|
|
42379
|
+
const target = event.target instanceof Element ? event.target.closest("th,td") : null;
|
|
42380
|
+
if (!(target instanceof HTMLTableCellElement) || target.closest("table") !== activeTable) {
|
|
42381
|
+
hoverLabel.style.display = "none";
|
|
42382
|
+
return;
|
|
42383
|
+
}
|
|
42384
|
+
const info = getFormulaTableCellInfo(editor.view, target, activeTablePos);
|
|
42385
|
+
if (!info) {
|
|
42386
|
+
hoverLabel.style.display = "none";
|
|
42387
|
+
return;
|
|
42388
|
+
}
|
|
42389
|
+
const containerRect = container.getBoundingClientRect();
|
|
42390
|
+
const cellRect = target.getBoundingClientRect();
|
|
42391
|
+
hoverLabel.textContent = info.label;
|
|
42392
|
+
hoverLabel.style.display = "block";
|
|
42393
|
+
setPosition(
|
|
42394
|
+
hoverLabel,
|
|
42395
|
+
cellRect.left - containerRect.left + container.scrollLeft + 4,
|
|
42396
|
+
cellRect.top - containerRect.top + container.scrollTop + 4
|
|
42397
|
+
);
|
|
42398
|
+
};
|
|
42399
|
+
const handleMouseLeave2 = () => {
|
|
42400
|
+
if (hoverLabel) hoverLabel.style.display = "none";
|
|
42401
|
+
};
|
|
42402
|
+
editor.on("selectionUpdate", scheduleSync);
|
|
42403
|
+
editor.on("update", scheduleSync);
|
|
42404
|
+
editor.on("focus", scheduleSync);
|
|
42405
|
+
editor.on("blur", scheduleSync);
|
|
42406
|
+
editor.view.dom.addEventListener("mousemove", handleMouseMove2);
|
|
42407
|
+
editor.view.dom.addEventListener("mouseleave", handleMouseLeave2);
|
|
42408
|
+
container.addEventListener(UEDITOR_TABLE_LAYOUT_CHANGE_EVENT, scheduleSync);
|
|
42409
|
+
window.addEventListener("resize", scheduleSync);
|
|
42410
|
+
scheduleSync();
|
|
42411
|
+
return () => {
|
|
42412
|
+
editor.off("selectionUpdate", scheduleSync);
|
|
42413
|
+
editor.off("update", scheduleSync);
|
|
42414
|
+
editor.off("focus", scheduleSync);
|
|
42415
|
+
editor.off("blur", scheduleSync);
|
|
42416
|
+
editor.view.dom.removeEventListener("mousemove", handleMouseMove2);
|
|
42417
|
+
editor.view.dom.removeEventListener("mouseleave", handleMouseLeave2);
|
|
42418
|
+
container.removeEventListener(UEDITOR_TABLE_LAYOUT_CHANGE_EVENT, scheduleSync);
|
|
42419
|
+
window.removeEventListener("resize", scheduleSync);
|
|
42420
|
+
if (animationFrame != null) window.cancelAnimationFrame(animationFrame);
|
|
42421
|
+
clearOverlay();
|
|
42422
|
+
};
|
|
42423
|
+
}, [containerRef, editor, labels.apply, labels.cancel]);
|
|
42424
|
+
return overlayRef;
|
|
42425
|
+
}
|
|
42426
|
+
|
|
41964
42427
|
// src/components/UEditor/menu-bar.tsx
|
|
41965
|
-
import React86, { useMemo as useMemo26, useRef as
|
|
42428
|
+
import React86, { useMemo as useMemo26, useRef as useRef38, useState as useState51 } from "react";
|
|
41966
42429
|
import { useEditorState as useEditorState3 } from "@tiptap/react";
|
|
41967
42430
|
import {
|
|
41968
42431
|
AlignCenter as AlignCenter4,
|
|
@@ -42586,7 +43049,7 @@ var MenuBar = ({
|
|
|
42586
43049
|
editor,
|
|
42587
43050
|
selector: ({ transactionNumber }) => transactionNumber
|
|
42588
43051
|
});
|
|
42589
|
-
const fileInputRef =
|
|
43052
|
+
const fileInputRef = useRef38(null);
|
|
42590
43053
|
const [showImageInput, setShowImageInput] = useState51(false);
|
|
42591
43054
|
const [showLinkInput, setShowLinkInput] = useState51(false);
|
|
42592
43055
|
const [isInsertMenuOpen, setIsInsertMenuOpen] = useState51(false);
|
|
@@ -42875,146 +43338,6 @@ var MenuBar = ({
|
|
|
42875
43338
|
] });
|
|
42876
43339
|
};
|
|
42877
43340
|
|
|
42878
|
-
// src/components/UEditor/table-formula-range-picker.ts
|
|
42879
|
-
import { TextSelection as TextSelection4 } from "@tiptap/pm/state";
|
|
42880
|
-
import { TableMap as TableMap5 } from "@tiptap/pm/tables";
|
|
42881
|
-
function getCellText2(cellNode) {
|
|
42882
|
-
return cellNode.textBetween(0, cellNode.content.size, "\n").trim();
|
|
42883
|
-
}
|
|
42884
|
-
function findSelectionFormulaCell(view) {
|
|
42885
|
-
const { $from } = view.state.selection;
|
|
42886
|
-
for (let depth = $from.depth; depth > 0; depth -= 1) {
|
|
42887
|
-
const node = $from.node(depth);
|
|
42888
|
-
if (node.type.name !== "tableCell" && node.type.name !== "tableHeader") continue;
|
|
42889
|
-
if (!getCellText2(node).startsWith("=")) return null;
|
|
42890
|
-
const cellPos = $from.before(depth);
|
|
42891
|
-
const cellDom = view.nodeDOM(cellPos);
|
|
42892
|
-
const tableDepth = depth - 2;
|
|
42893
|
-
const tableNode = tableDepth > 0 ? $from.node(tableDepth) : null;
|
|
42894
|
-
if (!tableNode || tableNode.type.name !== "table") return null;
|
|
42895
|
-
return {
|
|
42896
|
-
cellDom: cellDom instanceof HTMLTableCellElement ? cellDom : null,
|
|
42897
|
-
tablePos: $from.before(tableDepth)
|
|
42898
|
-
};
|
|
42899
|
-
}
|
|
42900
|
-
return null;
|
|
42901
|
-
}
|
|
42902
|
-
function findTableForPos(view, pos) {
|
|
42903
|
-
const $pos = view.state.doc.resolve(pos);
|
|
42904
|
-
for (let depth = $pos.depth; depth > 0; depth -= 1) {
|
|
42905
|
-
const node = $pos.node(depth);
|
|
42906
|
-
if (node.type.name === "table") {
|
|
42907
|
-
return {
|
|
42908
|
-
node,
|
|
42909
|
-
pos: $pos.before(depth),
|
|
42910
|
-
start: $pos.start(depth)
|
|
42911
|
-
};
|
|
42912
|
-
}
|
|
42913
|
-
}
|
|
42914
|
-
return null;
|
|
42915
|
-
}
|
|
42916
|
-
function getCellRelativePosFromDomPos2(map, tableStart, domPos) {
|
|
42917
|
-
const relativeDomPos = domPos - tableStart;
|
|
42918
|
-
const seen = /* @__PURE__ */ new Set();
|
|
42919
|
-
for (const relativeCellPos of map.map) {
|
|
42920
|
-
if (seen.has(relativeCellPos)) continue;
|
|
42921
|
-
seen.add(relativeCellPos);
|
|
42922
|
-
if (relativeDomPos === relativeCellPos || relativeDomPos === relativeCellPos + 1) {
|
|
42923
|
-
return relativeCellPos;
|
|
42924
|
-
}
|
|
42925
|
-
}
|
|
42926
|
-
return null;
|
|
42927
|
-
}
|
|
42928
|
-
function getPickedCellLabel(view, target, tablePos) {
|
|
42929
|
-
const element = resolveEventElement(target);
|
|
42930
|
-
const cell = element?.closest?.("th,td");
|
|
42931
|
-
if (!(cell instanceof HTMLTableCellElement)) return null;
|
|
42932
|
-
const domPos = view.posAtDOM(cell, 0);
|
|
42933
|
-
const tableInfo = findTableForPos(view, domPos);
|
|
42934
|
-
if (!tableInfo || tableInfo.pos !== tablePos) return null;
|
|
42935
|
-
const map = TableMap5.get(tableInfo.node);
|
|
42936
|
-
const relativeCellPos = getCellRelativePosFromDomPos2(map, tableInfo.start, domPos);
|
|
42937
|
-
if (relativeCellPos == null) return null;
|
|
42938
|
-
const rect = map.findCell(relativeCellPos);
|
|
42939
|
-
return {
|
|
42940
|
-
cell,
|
|
42941
|
-
label: `${indexToColumnName(rect.left)}${rect.top + 1}`
|
|
42942
|
-
};
|
|
42943
|
-
}
|
|
42944
|
-
function normalizeFormulaRangeLabel(fromLabel, toLabel) {
|
|
42945
|
-
return fromLabel === toLabel ? fromLabel : `${fromLabel}:${toLabel}`;
|
|
42946
|
-
}
|
|
42947
|
-
function replacePickedLabel(view, pickState, nextLabel, currentCell) {
|
|
42948
|
-
if (nextLabel === pickState.currentLabel && currentCell === pickState.currentCell) return pickState;
|
|
42949
|
-
if (nextLabel === pickState.currentLabel) {
|
|
42950
|
-
return {
|
|
42951
|
-
...pickState,
|
|
42952
|
-
currentCell
|
|
42953
|
-
};
|
|
42954
|
-
}
|
|
42955
|
-
let tr = view.state.tr.insertText(nextLabel, pickState.insertedFrom, pickState.insertedTo);
|
|
42956
|
-
const nextTo = pickState.insertedFrom + nextLabel.length;
|
|
42957
|
-
tr = tr.setSelection(TextSelection4.create(tr.doc, nextTo));
|
|
42958
|
-
view.dispatch(tr);
|
|
42959
|
-
return {
|
|
42960
|
-
...pickState,
|
|
42961
|
-
insertedTo: nextTo,
|
|
42962
|
-
currentLabel: nextLabel,
|
|
42963
|
-
currentCell
|
|
42964
|
-
};
|
|
42965
|
-
}
|
|
42966
|
-
function beginFormulaRangePick(view, event) {
|
|
42967
|
-
if (event.button !== 0) return null;
|
|
42968
|
-
const formulaCell = findSelectionFormulaCell(view);
|
|
42969
|
-
if (!formulaCell) return null;
|
|
42970
|
-
const picked = getPickedCellLabel(view, event.target, formulaCell.tablePos);
|
|
42971
|
-
if (!picked || picked.cell === formulaCell.cellDom) return null;
|
|
42972
|
-
const { from, to } = view.state.selection;
|
|
42973
|
-
let tr = view.state.tr.insertText(picked.label, from, to);
|
|
42974
|
-
tr = tr.setSelection(TextSelection4.create(tr.doc, from + picked.label.length));
|
|
42975
|
-
view.dispatch(tr);
|
|
42976
|
-
view.focus();
|
|
42977
|
-
event.preventDefault();
|
|
42978
|
-
event.stopPropagation();
|
|
42979
|
-
return {
|
|
42980
|
-
anchorLabel: picked.label,
|
|
42981
|
-
anchorCell: picked.cell,
|
|
42982
|
-
tablePos: formulaCell.tablePos,
|
|
42983
|
-
insertedFrom: from,
|
|
42984
|
-
insertedTo: from + picked.label.length,
|
|
42985
|
-
currentLabel: picked.label,
|
|
42986
|
-
currentCell: picked.cell
|
|
42987
|
-
};
|
|
42988
|
-
}
|
|
42989
|
-
function updateFormulaRangePick(view, pickState, event) {
|
|
42990
|
-
const picked = getPickedCellLabel(view, event.target, pickState.tablePos);
|
|
42991
|
-
if (!picked) return pickState;
|
|
42992
|
-
event.preventDefault();
|
|
42993
|
-
event.stopPropagation();
|
|
42994
|
-
return replacePickedLabel(
|
|
42995
|
-
view,
|
|
42996
|
-
pickState,
|
|
42997
|
-
normalizeFormulaRangeLabel(pickState.anchorLabel, picked.label),
|
|
42998
|
-
picked.cell
|
|
42999
|
-
);
|
|
43000
|
-
}
|
|
43001
|
-
function getFormulaRangePickHighlight(container, pickState) {
|
|
43002
|
-
if (!container.contains(pickState.anchorCell) || !container.contains(pickState.currentCell)) return null;
|
|
43003
|
-
const containerRect = container.getBoundingClientRect();
|
|
43004
|
-
const anchorRect = pickState.anchorCell.getBoundingClientRect();
|
|
43005
|
-
const currentRect = pickState.currentCell.getBoundingClientRect();
|
|
43006
|
-
const left = Math.min(anchorRect.left, currentRect.left) - containerRect.left + container.scrollLeft;
|
|
43007
|
-
const top = Math.min(anchorRect.top, currentRect.top) - containerRect.top + container.scrollTop;
|
|
43008
|
-
const right = Math.max(anchorRect.right, currentRect.right) - containerRect.left + container.scrollLeft;
|
|
43009
|
-
const bottom = Math.max(anchorRect.bottom, currentRect.bottom) - containerRect.top + container.scrollTop;
|
|
43010
|
-
return {
|
|
43011
|
-
left,
|
|
43012
|
-
top,
|
|
43013
|
-
width: Math.max(0, right - left),
|
|
43014
|
-
height: Math.max(0, bottom - top)
|
|
43015
|
-
};
|
|
43016
|
-
}
|
|
43017
|
-
|
|
43018
43341
|
// src/components/UEditor/UEditor.tsx
|
|
43019
43342
|
import { jsx as jsx99, jsxs as jsxs82 } from "react/jsx-runtime";
|
|
43020
43343
|
var UEditor = React87.forwardRef(({
|
|
@@ -43058,11 +43381,12 @@ var UEditor = React87.forwardRef(({
|
|
|
43058
43381
|
}, ref) => {
|
|
43059
43382
|
const t = useSmartTranslations("UEditor");
|
|
43060
43383
|
const effectivePlaceholder = placeholder ?? t("placeholder");
|
|
43061
|
-
const inFlightPrepareRef =
|
|
43062
|
-
const lastAppliedContentRef =
|
|
43063
|
-
const scheduledFormulaRecalculateRef =
|
|
43064
|
-
const
|
|
43065
|
-
const
|
|
43384
|
+
const inFlightPrepareRef = useRef39(null);
|
|
43385
|
+
const lastAppliedContentRef = useRef39(content ?? "");
|
|
43386
|
+
const scheduledFormulaRecalculateRef = useRef39(false);
|
|
43387
|
+
const editorInstanceRef = useRef39(null);
|
|
43388
|
+
const formulaRangePickRef = useRef39(null);
|
|
43389
|
+
const formulaRangeSurfaceRef = useRef39(null);
|
|
43066
43390
|
const [formulaRangeHighlight, setFormulaRangeHighlight] = React87.useState(null);
|
|
43067
43391
|
const scheduleFormulaRecalculate = React87.useCallback((editor2, options) => {
|
|
43068
43392
|
if (editor2.isDestroyed || scheduledFormulaRecalculateRef.current) return;
|
|
@@ -43149,6 +43473,22 @@ var UEditor = React87.forwardRef(({
|
|
|
43149
43473
|
},
|
|
43150
43474
|
keydown: (_view, event) => {
|
|
43151
43475
|
if (!(event instanceof KeyboardEvent)) return false;
|
|
43476
|
+
const formulaContext = getFormulaEditingTableContext(_view);
|
|
43477
|
+
if (formulaContext && event.key === "Enter") {
|
|
43478
|
+
event.preventDefault();
|
|
43479
|
+
event.stopPropagation();
|
|
43480
|
+
const activeEditor = editorInstanceRef.current;
|
|
43481
|
+
if (activeEditor && !isDraftTableFormula(formulaContext.formula)) {
|
|
43482
|
+
recalculateActiveTableFormulas(activeEditor);
|
|
43483
|
+
}
|
|
43484
|
+
return true;
|
|
43485
|
+
}
|
|
43486
|
+
if (formulaContext && event.key === "Escape") {
|
|
43487
|
+
event.preventDefault();
|
|
43488
|
+
event.stopPropagation();
|
|
43489
|
+
cancelFormulaEditing(_view);
|
|
43490
|
+
return true;
|
|
43491
|
+
}
|
|
43152
43492
|
if (event.key === "ArrowLeft" || event.key === "ArrowRight" || event.key === "ArrowUp" || event.key === "ArrowDown") {
|
|
43153
43493
|
event.stopPropagation();
|
|
43154
43494
|
}
|
|
@@ -43189,12 +43529,22 @@ var UEditor = React87.forwardRef(({
|
|
|
43189
43529
|
scheduleFormulaRecalculate(editor2, { force: true });
|
|
43190
43530
|
}
|
|
43191
43531
|
});
|
|
43532
|
+
useEffect40(() => {
|
|
43533
|
+
editorInstanceRef.current = editor;
|
|
43534
|
+
return () => {
|
|
43535
|
+
if (editorInstanceRef.current === editor) editorInstanceRef.current = null;
|
|
43536
|
+
};
|
|
43537
|
+
}, [editor]);
|
|
43192
43538
|
const {
|
|
43193
43539
|
editorContentRef,
|
|
43194
43540
|
tableColumnGuideRef,
|
|
43195
43541
|
tableRowGuideRef,
|
|
43196
43542
|
activeTableCellHighlightRef
|
|
43197
43543
|
} = useUEditorTableInteractions(editor, editable);
|
|
43544
|
+
const formulaCoordinateOverlayRef = useFormulaCoordinateOverlay(editor, editorContentRef, {
|
|
43545
|
+
apply: t("tableMenu.apply"),
|
|
43546
|
+
cancel: t("imageInput.cancelBtn")
|
|
43547
|
+
});
|
|
43198
43548
|
useImperativeHandle4(
|
|
43199
43549
|
ref,
|
|
43200
43550
|
() => ({
|
|
@@ -43220,7 +43570,7 @@ var UEditor = React87.forwardRef(({
|
|
|
43220
43570
|
}),
|
|
43221
43571
|
[content, editor, uploadImageForSave, uploadFileForSave, uploadImageConcurrency]
|
|
43222
43572
|
);
|
|
43223
|
-
|
|
43573
|
+
useEffect40(() => {
|
|
43224
43574
|
if (!editor) return;
|
|
43225
43575
|
queueMicrotask(() => {
|
|
43226
43576
|
if (!editor.isDestroyed) {
|
|
@@ -43228,7 +43578,7 @@ var UEditor = React87.forwardRef(({
|
|
|
43228
43578
|
}
|
|
43229
43579
|
});
|
|
43230
43580
|
}, [editor]);
|
|
43231
|
-
|
|
43581
|
+
useEffect40(() => {
|
|
43232
43582
|
if (!editor) return;
|
|
43233
43583
|
const nextContent = content ?? "";
|
|
43234
43584
|
if (lastAppliedContentRef.current === nextContent) return;
|
|
@@ -43348,6 +43698,14 @@ var UEditor = React87.forwardRef(({
|
|
|
43348
43698
|
className: "pointer-events-none hidden absolute z-20 rounded-[2px] border-2 border-primary bg-primary/10"
|
|
43349
43699
|
}
|
|
43350
43700
|
),
|
|
43701
|
+
/* @__PURE__ */ jsx99(
|
|
43702
|
+
"div",
|
|
43703
|
+
{
|
|
43704
|
+
ref: formulaCoordinateOverlayRef,
|
|
43705
|
+
"data-ueditor-formula-coordinate-overlay": "",
|
|
43706
|
+
className: "pointer-events-none absolute inset-0 z-[21] hidden overflow-visible"
|
|
43707
|
+
}
|
|
43708
|
+
),
|
|
43351
43709
|
formulaRangeHighlight && /* @__PURE__ */ jsx99(
|
|
43352
43710
|
"span",
|
|
43353
43711
|
{
|