@underverse-ui/underverse 1.0.185 → 1.0.187
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 +204 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +205 -51
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/api-reference.json
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -1010,7 +1010,8 @@ var en_default = {
|
|
|
1010
1010
|
addBlock: "Add block"
|
|
1011
1011
|
},
|
|
1012
1012
|
linkInput: {
|
|
1013
|
-
placeholder: "Paste or type a link..."
|
|
1013
|
+
placeholder: "Paste or type a link...",
|
|
1014
|
+
invalid: "Enter a valid link, such as https://example.com."
|
|
1014
1015
|
},
|
|
1015
1016
|
imageInput: {
|
|
1016
1017
|
urlTab: "URL",
|
|
@@ -1437,7 +1438,8 @@ var vi_default = {
|
|
|
1437
1438
|
addBlock: "Th\xEAm kh\u1ED1i"
|
|
1438
1439
|
},
|
|
1439
1440
|
linkInput: {
|
|
1440
|
-
placeholder: "D\xE1n ho\u1EB7c nh\u1EADp li\xEAn k\u1EBFt..."
|
|
1441
|
+
placeholder: "D\xE1n ho\u1EB7c nh\u1EADp li\xEAn k\u1EBFt...",
|
|
1442
|
+
invalid: "Vui l\xF2ng nh\u1EADp li\xEAn k\u1EBFt h\u1EE3p l\u1EC7, v\xED d\u1EE5: https://example.com."
|
|
1441
1443
|
},
|
|
1442
1444
|
imageInput: {
|
|
1443
1445
|
urlTab: "URL",
|
|
@@ -1864,7 +1866,8 @@ var ko_default = {
|
|
|
1864
1866
|
addBlock: "\uBE14\uB85D \uCD94\uAC00"
|
|
1865
1867
|
},
|
|
1866
1868
|
linkInput: {
|
|
1867
|
-
placeholder: "\uB9C1\uD06C \uBD99\uC5EC\uB123\uAE30 \uB610\uB294 \uC785\uB825..."
|
|
1869
|
+
placeholder: "\uB9C1\uD06C \uBD99\uC5EC\uB123\uAE30 \uB610\uB294 \uC785\uB825...",
|
|
1870
|
+
invalid: "https://example.com\uACFC \uAC19\uC740 \uC62C\uBC14\uB978 \uB9C1\uD06C\uB97C \uC785\uB825\uD574 \uC8FC\uC138\uC694."
|
|
1868
1871
|
},
|
|
1869
1872
|
imageInput: {
|
|
1870
1873
|
urlTab: "URL",
|
|
@@ -2291,7 +2294,8 @@ var ja_default = {
|
|
|
2291
2294
|
addBlock: "\u30D6\u30ED\u30C3\u30AF\u3092\u8FFD\u52A0"
|
|
2292
2295
|
},
|
|
2293
2296
|
linkInput: {
|
|
2294
|
-
placeholder: "\u30EA\u30F3\u30AF\u3092\u8CBC\u308A\u4ED8\u3051\u307E\u305F\u306F\u5165\u529B..."
|
|
2297
|
+
placeholder: "\u30EA\u30F3\u30AF\u3092\u8CBC\u308A\u4ED8\u3051\u307E\u305F\u306F\u5165\u529B...",
|
|
2298
|
+
invalid: "https://example.com \u306E\u3088\u3046\u306A\u6709\u52B9\u306A\u30EA\u30F3\u30AF\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
|
|
2295
2299
|
},
|
|
2296
2300
|
imageInput: {
|
|
2297
2301
|
urlTab: "URL",
|
|
@@ -27745,6 +27749,32 @@ function isProtocolRelativeUrl(value) {
|
|
|
27745
27749
|
function isRelativeUrl(value) {
|
|
27746
27750
|
return value.startsWith("/") || value.startsWith("./") || value.startsWith("../") || value.startsWith("#");
|
|
27747
27751
|
}
|
|
27752
|
+
function isValidIpv4Hostname(hostname) {
|
|
27753
|
+
const parts = hostname.split(".");
|
|
27754
|
+
return parts.length === 4 && parts.every((part) => /^\d{1,3}$/.test(part) && Number(part) <= 255);
|
|
27755
|
+
}
|
|
27756
|
+
function isValidWebHostname(hostname) {
|
|
27757
|
+
const normalized = hostname.toLowerCase();
|
|
27758
|
+
if (normalized === "localhost" || isValidIpv4Hostname(normalized)) return true;
|
|
27759
|
+
if (normalized.startsWith("[") && normalized.endsWith("]") && normalized.includes(":")) return true;
|
|
27760
|
+
const labels = normalized.split(".");
|
|
27761
|
+
if (labels.length < 2) return false;
|
|
27762
|
+
const validLabel = /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)$/;
|
|
27763
|
+
return labels.every((label) => validLabel.test(label)) && /[a-z]/.test(labels.at(-1) ?? "");
|
|
27764
|
+
}
|
|
27765
|
+
function isValidLinkUrl(parsed) {
|
|
27766
|
+
if (parsed.protocol === "http:" || parsed.protocol === "https:") {
|
|
27767
|
+
return isValidWebHostname(parsed.hostname);
|
|
27768
|
+
}
|
|
27769
|
+
if (parsed.protocol === "mailto:") {
|
|
27770
|
+
return /^[^@]+@[^@]+\.[^@]+$/.test(decodeURIComponent(parsed.pathname));
|
|
27771
|
+
}
|
|
27772
|
+
if (parsed.protocol === "tel:") {
|
|
27773
|
+
const number = decodeURIComponent(parsed.pathname);
|
|
27774
|
+
return /^\+?[\d().-]+$/.test(number) && (number.match(/\d/g)?.length ?? 0) >= 3;
|
|
27775
|
+
}
|
|
27776
|
+
return false;
|
|
27777
|
+
}
|
|
27748
27778
|
function isDataImageUrl(value) {
|
|
27749
27779
|
return /^data:image\/(?:png|jpe?g|gif|webp|svg\+xml|bmp|x-icon|avif);base64,/i.test(value);
|
|
27750
27780
|
}
|
|
@@ -27762,7 +27792,7 @@ function isSafeUEditorUrl(raw, kind) {
|
|
|
27762
27792
|
const parsed = new URL(value);
|
|
27763
27793
|
if (kind === "image") return IMAGE_PROTOCOLS.has(parsed.protocol);
|
|
27764
27794
|
if (kind === "file") return FILE_PROTOCOLS.has(parsed.protocol);
|
|
27765
|
-
return LINK_PROTOCOLS.has(parsed.protocol);
|
|
27795
|
+
return LINK_PROTOCOLS.has(parsed.protocol) && isValidLinkUrl(parsed);
|
|
27766
27796
|
} catch {
|
|
27767
27797
|
return false;
|
|
27768
27798
|
}
|
|
@@ -32505,7 +32535,9 @@ var LinkInput = ({
|
|
|
32505
32535
|
}) => {
|
|
32506
32536
|
const t = useSmartTranslations("UEditor");
|
|
32507
32537
|
const [url, setUrl] = (0, import_react69.useState)(initialUrl);
|
|
32538
|
+
const [error, setError] = (0, import_react69.useState)("");
|
|
32508
32539
|
const inputRef = (0, import_react69.useRef)(null);
|
|
32540
|
+
const errorId = (0, import_react69.useId)();
|
|
32509
32541
|
(0, import_react69.useEffect)(() => {
|
|
32510
32542
|
inputRef.current?.focus();
|
|
32511
32543
|
inputRef.current?.select();
|
|
@@ -32513,22 +32545,35 @@ var LinkInput = ({
|
|
|
32513
32545
|
const handleSubmit = (e) => {
|
|
32514
32546
|
e.preventDefault();
|
|
32515
32547
|
const normalized = normalizeUrl(url);
|
|
32516
|
-
if (normalized)
|
|
32548
|
+
if (!normalized) {
|
|
32549
|
+
setError(t("linkInput.invalid"));
|
|
32550
|
+
return;
|
|
32551
|
+
}
|
|
32552
|
+
setError("");
|
|
32553
|
+
onSubmit(normalized);
|
|
32517
32554
|
};
|
|
32518
|
-
return /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("form", { onSubmit: handleSubmit, className: "
|
|
32519
|
-
/* @__PURE__ */ (0, import_jsx_runtime90.
|
|
32520
|
-
|
|
32521
|
-
|
|
32522
|
-
|
|
32523
|
-
|
|
32524
|
-
|
|
32525
|
-
|
|
32526
|
-
|
|
32527
|
-
|
|
32528
|
-
|
|
32529
|
-
|
|
32530
|
-
|
|
32531
|
-
|
|
32555
|
+
return /* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("form", { onSubmit: handleSubmit, className: "p-2", children: [
|
|
32556
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
32557
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)(
|
|
32558
|
+
"input",
|
|
32559
|
+
{
|
|
32560
|
+
ref: inputRef,
|
|
32561
|
+
type: "text",
|
|
32562
|
+
value: url,
|
|
32563
|
+
onChange: (e) => {
|
|
32564
|
+
setUrl(e.target.value);
|
|
32565
|
+
if (error) setError("");
|
|
32566
|
+
},
|
|
32567
|
+
placeholder: t("linkInput.placeholder"),
|
|
32568
|
+
"aria-invalid": Boolean(error),
|
|
32569
|
+
"aria-describedby": error ? errorId : void 0,
|
|
32570
|
+
className: "flex-1 px-3 py-2 text-sm bg-muted/50 border-0 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary/20 aria-invalid:ring-2 aria-invalid:ring-destructive/40"
|
|
32571
|
+
}
|
|
32572
|
+
),
|
|
32573
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("button", { type: "submit", className: "p-2 rounded-lg bg-primary text-primary-foreground hover:bg-primary/90 transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(import_lucide_react52.Check, { className: "w-4 h-4" }) }),
|
|
32574
|
+
/* @__PURE__ */ (0, import_jsx_runtime90.jsx)("button", { type: "button", onClick: onCancel, className: "p-2 rounded-lg hover:bg-muted transition-colors text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime90.jsx)(import_lucide_react52.X, { className: "w-4 h-4" }) })
|
|
32575
|
+
] }),
|
|
32576
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime90.jsx)("p", { id: errorId, role: "alert", className: "mt-1.5 px-1 text-xs text-destructive", children: error }) : null
|
|
32532
32577
|
] });
|
|
32533
32578
|
};
|
|
32534
32579
|
var ImageInput = ({ onSubmit, onCancel }) => {
|
|
@@ -32589,8 +32634,28 @@ var ImageInput = ({ onSubmit, onCancel }) => {
|
|
|
32589
32634
|
] });
|
|
32590
32635
|
};
|
|
32591
32636
|
|
|
32592
|
-
// src/components/UEditor/
|
|
32637
|
+
// src/components/UEditor/link-commands.ts
|
|
32593
32638
|
var import_state9 = require("@tiptap/pm/state");
|
|
32639
|
+
function applyEditorLink(editor, href) {
|
|
32640
|
+
const isEditingLink = editor.isActive("link");
|
|
32641
|
+
const hasSelectedText = !editor.state.selection.empty;
|
|
32642
|
+
const chain = editor.chain().focus();
|
|
32643
|
+
if (isEditingLink) {
|
|
32644
|
+
chain.extendMarkRange("link");
|
|
32645
|
+
}
|
|
32646
|
+
chain.setLink({ href });
|
|
32647
|
+
if (!hasSelectedText && !isEditingLink) {
|
|
32648
|
+
chain.insertContent(href);
|
|
32649
|
+
}
|
|
32650
|
+
return chain.command(({ tr }) => {
|
|
32651
|
+
tr.setSelection(import_state9.TextSelection.create(tr.doc, tr.selection.to));
|
|
32652
|
+
tr.removeStoredMark(editor.schema.marks.link);
|
|
32653
|
+
return true;
|
|
32654
|
+
}).run();
|
|
32655
|
+
}
|
|
32656
|
+
|
|
32657
|
+
// src/components/UEditor/table-cell-commands.ts
|
|
32658
|
+
var import_state10 = require("@tiptap/pm/state");
|
|
32594
32659
|
var import_tables3 = require("@tiptap/pm/tables");
|
|
32595
32660
|
function getCellSelectionPositions(selection) {
|
|
32596
32661
|
const value = selection;
|
|
@@ -32624,7 +32689,7 @@ function getFocusableCellPos(editor, cellPos) {
|
|
|
32624
32689
|
return node?.isTextblock ? offset + 1 : cellPos + 1;
|
|
32625
32690
|
}
|
|
32626
32691
|
function focusCell(editor, cellPos) {
|
|
32627
|
-
const selection =
|
|
32692
|
+
const selection = import_state10.TextSelection.near(editor.state.doc.resolve(getFocusableCellPos(editor, cellPos)));
|
|
32628
32693
|
editor.view.dispatch(editor.state.tr.setSelection(selection));
|
|
32629
32694
|
editor.view.focus();
|
|
32630
32695
|
}
|
|
@@ -33170,7 +33235,7 @@ var EditorToolbar = ({
|
|
|
33170
33235
|
{
|
|
33171
33236
|
initialUrl: String(editor.getAttributes("link").href ?? ""),
|
|
33172
33237
|
onSubmit: (url) => {
|
|
33173
|
-
editor
|
|
33238
|
+
applyEditorLink(editor, url);
|
|
33174
33239
|
setShowLinkInput(false);
|
|
33175
33240
|
},
|
|
33176
33241
|
onCancel: () => setShowLinkInput(false)
|
|
@@ -33407,7 +33472,7 @@ var EditorToolbar = ({
|
|
|
33407
33472
|
{
|
|
33408
33473
|
initialUrl: String(editor.getAttributes("link").href ?? ""),
|
|
33409
33474
|
onSubmit: (url) => {
|
|
33410
|
-
editor
|
|
33475
|
+
applyEditorLink(editor, url);
|
|
33411
33476
|
setShowLinkInput(false);
|
|
33412
33477
|
},
|
|
33413
33478
|
onCancel: () => setShowLinkInput(false)
|
|
@@ -34004,7 +34069,7 @@ var import_react_dom8 = require("react-dom");
|
|
|
34004
34069
|
var import_lucide_react54 = require("lucide-react");
|
|
34005
34070
|
|
|
34006
34071
|
// src/components/UEditor/table-formula-commands.ts
|
|
34007
|
-
var
|
|
34072
|
+
var import_state11 = require("@tiptap/pm/state");
|
|
34008
34073
|
var import_tables5 = require("@tiptap/pm/tables");
|
|
34009
34074
|
|
|
34010
34075
|
// src/components/UEditor/table-formula.ts
|
|
@@ -34620,7 +34685,7 @@ function restoreSelectionAtTableCell(editor, anchor) {
|
|
|
34620
34685
|
if (!cellNode || cellNode.type.name !== "tableCell" && cellNode.type.name !== "tableHeader") return false;
|
|
34621
34686
|
const selectionPos = Math.min(cellPos + 2, editor.state.doc.content.size);
|
|
34622
34687
|
editor.view.dispatch(
|
|
34623
|
-
editor.state.tr.setSelection(
|
|
34688
|
+
editor.state.tr.setSelection(import_state11.TextSelection.near(editor.state.doc.resolve(selectionPos))).setMeta("addToHistory", false)
|
|
34624
34689
|
);
|
|
34625
34690
|
return true;
|
|
34626
34691
|
}
|
|
@@ -34697,7 +34762,7 @@ function removeSelectedTableCellFormula(editor, clearContent) {
|
|
|
34697
34762
|
);
|
|
34698
34763
|
let transaction = editor.state.tr.replaceWith(selectedCell.cellPos, selectedCell.cellPos + selectedCell.node.nodeSize, nextCell2).setMeta(UEDITOR_TABLE_FORMULA_RECALCULATE_META, true);
|
|
34699
34764
|
const selectionPos = Math.min(selectedCell.cellPos + 2, transaction.doc.content.size);
|
|
34700
|
-
transaction = transaction.setSelection(
|
|
34765
|
+
transaction = transaction.setSelection(import_state11.TextSelection.near(transaction.doc.resolve(selectionPos)));
|
|
34701
34766
|
editor.view.dispatch(transaction);
|
|
34702
34767
|
recalculateActiveTableFormulas(editor);
|
|
34703
34768
|
restoreSelectionAtTableCell(editor, selectedCell);
|
|
@@ -35183,7 +35248,7 @@ var BubbleMenuContent = ({
|
|
|
35183
35248
|
{
|
|
35184
35249
|
initialUrl: editor.getAttributes("link").href || "",
|
|
35185
35250
|
onSubmit: (url) => {
|
|
35186
|
-
editor
|
|
35251
|
+
applyEditorLink(editor, url);
|
|
35187
35252
|
setShowLinkInput(false);
|
|
35188
35253
|
requestAnimationFrame(() => editor.commands.focus());
|
|
35189
35254
|
},
|
|
@@ -39040,7 +39105,7 @@ var Selection = class {
|
|
|
39040
39105
|
found.
|
|
39041
39106
|
*/
|
|
39042
39107
|
static findFrom($pos, dir, textOnly = false) {
|
|
39043
|
-
let inner = $pos.parent.inlineContent ? new
|
|
39108
|
+
let inner = $pos.parent.inlineContent ? new TextSelection5($pos) : findSelectionIn($pos.node(0), $pos.parent, $pos.pos, $pos.index(), dir, textOnly);
|
|
39044
39109
|
if (inner)
|
|
39045
39110
|
return inner;
|
|
39046
39111
|
for (let depth = $pos.depth - 1; depth >= 0; depth--) {
|
|
@@ -39109,7 +39174,7 @@ var Selection = class {
|
|
|
39109
39174
|
returns the bookmark for that.
|
|
39110
39175
|
*/
|
|
39111
39176
|
getBookmark() {
|
|
39112
|
-
return
|
|
39177
|
+
return TextSelection5.between(this.$anchor, this.$head).getBookmark();
|
|
39113
39178
|
}
|
|
39114
39179
|
};
|
|
39115
39180
|
Selection.prototype.visible = true;
|
|
@@ -39129,7 +39194,7 @@ function checkTextSelection($pos) {
|
|
|
39129
39194
|
console["warn"]("TextSelection endpoint not pointing into a node with inline content (" + $pos.parent.type.name + ")");
|
|
39130
39195
|
}
|
|
39131
39196
|
}
|
|
39132
|
-
var
|
|
39197
|
+
var TextSelection5 = class _TextSelection extends Selection {
|
|
39133
39198
|
/**
|
|
39134
39199
|
Construct a text selection between the given points.
|
|
39135
39200
|
*/
|
|
@@ -39215,7 +39280,7 @@ var TextSelection4 = class _TextSelection extends Selection {
|
|
|
39215
39280
|
return new _TextSelection($anchor, $head);
|
|
39216
39281
|
}
|
|
39217
39282
|
};
|
|
39218
|
-
Selection.jsonID("text",
|
|
39283
|
+
Selection.jsonID("text", TextSelection5);
|
|
39219
39284
|
var TextBookmark = class _TextBookmark {
|
|
39220
39285
|
constructor(anchor, head) {
|
|
39221
39286
|
this.anchor = anchor;
|
|
@@ -39225,7 +39290,7 @@ var TextBookmark = class _TextBookmark {
|
|
|
39225
39290
|
return new _TextBookmark(mapping.map(this.anchor), mapping.map(this.head));
|
|
39226
39291
|
}
|
|
39227
39292
|
resolve(doc) {
|
|
39228
|
-
return
|
|
39293
|
+
return TextSelection5.between(doc.resolve(this.anchor), doc.resolve(this.head));
|
|
39229
39294
|
}
|
|
39230
39295
|
};
|
|
39231
39296
|
var NodeSelection2 = class _NodeSelection extends Selection {
|
|
@@ -39344,7 +39409,7 @@ var AllBookmark = {
|
|
|
39344
39409
|
};
|
|
39345
39410
|
function findSelectionIn(doc, node, pos, index, dir, text = false) {
|
|
39346
39411
|
if (node.inlineContent)
|
|
39347
|
-
return
|
|
39412
|
+
return TextSelection5.create(doc, pos);
|
|
39348
39413
|
for (let i = index - (dir > 0 ? 0 : 1); dir > 0 ? i < node.childCount : i >= 0; i += dir) {
|
|
39349
39414
|
let child = node.child(i);
|
|
39350
39415
|
if (!child.isAtom) {
|
|
@@ -39936,7 +40001,7 @@ var CellSelection = class CellSelection2 extends Selection {
|
|
|
39936
40001
|
else if (tableChanged && this.isColSelection()) return CellSelection2.colSelection($anchorCell, $headCell);
|
|
39937
40002
|
else return new CellSelection2($anchorCell, $headCell);
|
|
39938
40003
|
}
|
|
39939
|
-
return
|
|
40004
|
+
return TextSelection5.between($anchorCell, $headCell);
|
|
39940
40005
|
}
|
|
39941
40006
|
content() {
|
|
39942
40007
|
const table = this.$anchorCell.node(-1);
|
|
@@ -40551,7 +40616,7 @@ function shiftArrow(axis, dir) {
|
|
|
40551
40616
|
};
|
|
40552
40617
|
}
|
|
40553
40618
|
function atEndOfCell(view, axis, dir) {
|
|
40554
|
-
if (!(view.state.selection instanceof
|
|
40619
|
+
if (!(view.state.selection instanceof TextSelection5)) return null;
|
|
40555
40620
|
const { $head } = view.state.selection;
|
|
40556
40621
|
for (let d = $head.depth - 1; d >= 0; d--) {
|
|
40557
40622
|
const parent = $head.node(d);
|
|
@@ -42442,7 +42507,7 @@ var import_react77 = require("react");
|
|
|
42442
42507
|
var import_tables8 = require("@tiptap/pm/tables");
|
|
42443
42508
|
|
|
42444
42509
|
// src/components/UEditor/table-formula-range-picker.ts
|
|
42445
|
-
var
|
|
42510
|
+
var import_state12 = require("@tiptap/pm/state");
|
|
42446
42511
|
var import_tables7 = require("@tiptap/pm/tables");
|
|
42447
42512
|
function getCellText2(cellNode) {
|
|
42448
42513
|
return cellNode.textBetween(0, cellNode.content.size, "\n").trim();
|
|
@@ -42461,6 +42526,9 @@ function getFormulaEditingTableContext(view) {
|
|
|
42461
42526
|
if (!tableNode || tableNode.type.name !== "table") return null;
|
|
42462
42527
|
const tableDom = cellDom.closest("table");
|
|
42463
42528
|
if (!(tableDom instanceof HTMLTableElement)) return null;
|
|
42529
|
+
const tableMap = import_tables7.TableMap.get(tableNode);
|
|
42530
|
+
const tableStart = $from.start(tableDepth);
|
|
42531
|
+
const formulaCellRect = tableMap.findCell(cellPos - tableStart);
|
|
42464
42532
|
return {
|
|
42465
42533
|
cellContentEnd: $from.end(depth),
|
|
42466
42534
|
cellContentStart: $from.start(depth),
|
|
@@ -42468,17 +42536,56 @@ function getFormulaEditingTableContext(view) {
|
|
|
42468
42536
|
formula: getCellText2(node),
|
|
42469
42537
|
tableDom,
|
|
42470
42538
|
tableNode,
|
|
42471
|
-
tablePos: $from.before(tableDepth)
|
|
42539
|
+
tablePos: $from.before(tableDepth),
|
|
42540
|
+
formulaCellLabel: `${indexToColumnName(formulaCellRect.left)}${formulaCellRect.top + 1}`
|
|
42472
42541
|
};
|
|
42473
42542
|
}
|
|
42474
42543
|
return null;
|
|
42475
42544
|
}
|
|
42545
|
+
function collectTableFormulaCells(tableNode) {
|
|
42546
|
+
const tableMap = import_tables7.TableMap.get(tableNode);
|
|
42547
|
+
const formulas = [];
|
|
42548
|
+
tableNode.forEach((rowNode, rowOffset) => {
|
|
42549
|
+
rowNode.forEach((cellNode, cellOffset) => {
|
|
42550
|
+
const formula = typeof cellNode.attrs.formula === "string" ? cellNode.attrs.formula.trim() : "";
|
|
42551
|
+
if (!formula) return;
|
|
42552
|
+
const rect = tableMap.findCell(rowOffset + 1 + cellOffset);
|
|
42553
|
+
formulas.push({
|
|
42554
|
+
label: `${indexToColumnName(rect.left)}${rect.top + 1}`,
|
|
42555
|
+
formula
|
|
42556
|
+
});
|
|
42557
|
+
});
|
|
42558
|
+
});
|
|
42559
|
+
return formulas;
|
|
42560
|
+
}
|
|
42561
|
+
function getFormulaCycleBlockedLabels(tableNode, formulaCellLabel) {
|
|
42562
|
+
const graph = buildTableFormulaDependencyGraph(collectTableFormulaCells(tableNode));
|
|
42563
|
+
const blocked = /* @__PURE__ */ new Set();
|
|
42564
|
+
const queue = [formulaCellLabel.toUpperCase()];
|
|
42565
|
+
for (let index = 0; index < queue.length; index += 1) {
|
|
42566
|
+
const label = queue[index];
|
|
42567
|
+
if (!label || blocked.has(label)) continue;
|
|
42568
|
+
blocked.add(label);
|
|
42569
|
+
for (const dependent of graph.dependents.get(label) ?? []) {
|
|
42570
|
+
if (!blocked.has(dependent)) queue.push(dependent);
|
|
42571
|
+
}
|
|
42572
|
+
}
|
|
42573
|
+
return blocked;
|
|
42574
|
+
}
|
|
42575
|
+
function getReferenceLabels(reference) {
|
|
42576
|
+
const range = parseTableCellRange(reference);
|
|
42577
|
+
return range ? getTableCellRangeLabels(range) : [reference.toUpperCase()];
|
|
42578
|
+
}
|
|
42579
|
+
function isBlockedFormulaReference(tableNode, formulaCellLabel, reference) {
|
|
42580
|
+
const blockedLabels = getFormulaCycleBlockedLabels(tableNode, formulaCellLabel);
|
|
42581
|
+
return getReferenceLabels(reference).some((label) => blockedLabels.has(label));
|
|
42582
|
+
}
|
|
42476
42583
|
function cancelFormulaEditing(view) {
|
|
42477
42584
|
const context = getFormulaEditingTableContext(view);
|
|
42478
42585
|
if (!context) return false;
|
|
42479
42586
|
let tr = view.state.tr.delete(context.cellContentStart, context.cellContentEnd);
|
|
42480
42587
|
const selectionPos = Math.min(context.cellContentStart, tr.doc.content.size);
|
|
42481
|
-
tr = tr.setSelection(
|
|
42588
|
+
tr = tr.setSelection(import_state12.TextSelection.near(tr.doc.resolve(selectionPos)));
|
|
42482
42589
|
view.dispatch(tr);
|
|
42483
42590
|
view.focus();
|
|
42484
42591
|
return true;
|
|
@@ -42536,19 +42643,30 @@ function normalizeFormulaRangeLabel(fromLabel, toLabel) {
|
|
|
42536
42643
|
return fromLabel === toLabel ? fromLabel : `${fromLabel}:${toLabel}`;
|
|
42537
42644
|
}
|
|
42538
42645
|
function replacePickedLabel(view, pickState, nextLabel, currentCell) {
|
|
42539
|
-
|
|
42646
|
+
const formulaContext = getFormulaEditingTableContext(view);
|
|
42647
|
+
const blocked = formulaContext ? isBlockedFormulaReference(formulaContext.tableNode, pickState.formulaCellLabel, nextLabel) : false;
|
|
42648
|
+
if (blocked) {
|
|
42649
|
+
return {
|
|
42650
|
+
...pickState,
|
|
42651
|
+
blocked: true,
|
|
42652
|
+
currentCell
|
|
42653
|
+
};
|
|
42654
|
+
}
|
|
42655
|
+
if (nextLabel === pickState.currentLabel && currentCell === pickState.currentCell && !pickState.blocked) return pickState;
|
|
42540
42656
|
if (nextLabel === pickState.currentLabel) {
|
|
42541
42657
|
return {
|
|
42542
42658
|
...pickState,
|
|
42659
|
+
blocked: false,
|
|
42543
42660
|
currentCell
|
|
42544
42661
|
};
|
|
42545
42662
|
}
|
|
42546
42663
|
let tr = view.state.tr.insertText(nextLabel, pickState.insertedFrom, pickState.insertedTo);
|
|
42547
42664
|
const nextTo = pickState.insertedFrom + nextLabel.length;
|
|
42548
|
-
tr = tr.setSelection(
|
|
42665
|
+
tr = tr.setSelection(import_state12.TextSelection.create(tr.doc, nextTo));
|
|
42549
42666
|
view.dispatch(tr);
|
|
42550
42667
|
return {
|
|
42551
42668
|
...pickState,
|
|
42669
|
+
blocked: false,
|
|
42552
42670
|
insertedTo: nextTo,
|
|
42553
42671
|
currentLabel: nextLabel,
|
|
42554
42672
|
currentCell
|
|
@@ -42560,12 +42678,28 @@ function beginFormulaRangePick(view, event) {
|
|
|
42560
42678
|
if (!formulaCell) return null;
|
|
42561
42679
|
const picked = getFormulaTableCellInfo(view, event.target, formulaCell.tablePos);
|
|
42562
42680
|
if (!picked || picked.cell === formulaCell.cellDom) return null;
|
|
42681
|
+
const blocked = isBlockedFormulaReference(formulaCell.tableNode, formulaCell.formulaCellLabel, picked.label);
|
|
42682
|
+
if (blocked) {
|
|
42683
|
+
event.preventDefault();
|
|
42684
|
+
event.stopPropagation();
|
|
42685
|
+
return {
|
|
42686
|
+
anchorLabel: picked.label,
|
|
42687
|
+
anchorCell: picked.cell,
|
|
42688
|
+
tablePos: formulaCell.tablePos,
|
|
42689
|
+
insertedFrom: view.state.selection.from,
|
|
42690
|
+
insertedTo: view.state.selection.from,
|
|
42691
|
+
currentLabel: "",
|
|
42692
|
+
currentCell: picked.cell,
|
|
42693
|
+
blocked: true,
|
|
42694
|
+
formulaCellLabel: formulaCell.formulaCellLabel
|
|
42695
|
+
};
|
|
42696
|
+
}
|
|
42563
42697
|
const { from, to } = view.state.selection;
|
|
42564
42698
|
const prefix = from === to ? getReferenceInsertionPrefix(view, formulaCell.cellContentStart, from) : "";
|
|
42565
42699
|
const insertedText = `${prefix}${picked.label}`;
|
|
42566
42700
|
const insertedFrom = from + prefix.length;
|
|
42567
42701
|
let tr = view.state.tr.insertText(insertedText, from, to);
|
|
42568
|
-
tr = tr.setSelection(
|
|
42702
|
+
tr = tr.setSelection(import_state12.TextSelection.create(tr.doc, from + insertedText.length));
|
|
42569
42703
|
view.dispatch(tr);
|
|
42570
42704
|
view.focus();
|
|
42571
42705
|
event.preventDefault();
|
|
@@ -42577,7 +42711,9 @@ function beginFormulaRangePick(view, event) {
|
|
|
42577
42711
|
insertedFrom,
|
|
42578
42712
|
insertedTo: insertedFrom + picked.label.length,
|
|
42579
42713
|
currentLabel: picked.label,
|
|
42580
|
-
currentCell: picked.cell
|
|
42714
|
+
currentCell: picked.cell,
|
|
42715
|
+
blocked: false,
|
|
42716
|
+
formulaCellLabel: formulaCell.formulaCellLabel
|
|
42581
42717
|
};
|
|
42582
42718
|
}
|
|
42583
42719
|
function updateFormulaRangePick(view, pickState, event) {
|
|
@@ -42605,7 +42741,8 @@ function getFormulaRangePickHighlight(container, pickState) {
|
|
|
42605
42741
|
left,
|
|
42606
42742
|
top,
|
|
42607
42743
|
width: Math.max(0, right - left),
|
|
42608
|
-
height: Math.max(0, bottom - top)
|
|
42744
|
+
height: Math.max(0, bottom - top),
|
|
42745
|
+
blocked: pickState.blocked
|
|
42609
42746
|
};
|
|
42610
42747
|
}
|
|
42611
42748
|
|
|
@@ -42629,6 +42766,12 @@ function createReferenceHighlight(label) {
|
|
|
42629
42766
|
element.className = "pointer-events-none absolute z-[21] rounded-[2px] border-2 border-emerald-500 bg-emerald-500/15";
|
|
42630
42767
|
return element;
|
|
42631
42768
|
}
|
|
42769
|
+
function createBlockedReferenceHighlight(label) {
|
|
42770
|
+
const element = document.createElement("span");
|
|
42771
|
+
element.dataset.ueditorFormulaBlockedReference = label;
|
|
42772
|
+
element.className = "pointer-events-none absolute z-[22] rounded-[2px] border-2 border-destructive/80 bg-destructive/10";
|
|
42773
|
+
return element;
|
|
42774
|
+
}
|
|
42632
42775
|
function useFormulaCoordinateOverlay(editor, containerRef, labels) {
|
|
42633
42776
|
const overlayRef = (0, import_react77.useRef)(null);
|
|
42634
42777
|
(0, import_react77.useEffect)(() => {
|
|
@@ -42640,6 +42783,7 @@ function useFormulaCoordinateOverlay(editor, containerRef, labels) {
|
|
|
42640
42783
|
let activeTable = null;
|
|
42641
42784
|
let activeTablePos = null;
|
|
42642
42785
|
let hoverLabel = null;
|
|
42786
|
+
const scrollListenerOptions = { passive: true, capture: true };
|
|
42643
42787
|
const clearOverlay = () => {
|
|
42644
42788
|
activeTable = null;
|
|
42645
42789
|
activeTablePos = null;
|
|
@@ -42699,10 +42843,12 @@ function useFormulaCoordinateOverlay(editor, containerRef, labels) {
|
|
|
42699
42843
|
actions.dataset.ueditorFormulaActions = "";
|
|
42700
42844
|
actions.className = "pointer-events-auto absolute z-50 flex items-center gap-1 rounded-md border border-border bg-background p-1 shadow-md";
|
|
42701
42845
|
const formulaCellRect = context.cellDom.getBoundingClientRect();
|
|
42846
|
+
const formulaActionsHeight = 34;
|
|
42847
|
+
const formulaActionsTop = formulaCellRect.bottom + 4 + formulaActionsHeight > tableRect.bottom ? Math.max(containerRect.top + 4, formulaCellRect.top - formulaActionsHeight - 4) : formulaCellRect.bottom + 4;
|
|
42702
42848
|
setPosition(
|
|
42703
42849
|
actions,
|
|
42704
42850
|
formulaCellRect.left - containerRect.left + container.scrollLeft,
|
|
42705
|
-
|
|
42851
|
+
formulaActionsTop - containerRect.top + container.scrollTop
|
|
42706
42852
|
);
|
|
42707
42853
|
const applyButton = document.createElement("button");
|
|
42708
42854
|
applyButton.type = "button";
|
|
@@ -42754,10 +42900,12 @@ function useFormulaCoordinateOverlay(editor, containerRef, labels) {
|
|
|
42754
42900
|
children.push(label);
|
|
42755
42901
|
}
|
|
42756
42902
|
const references = new Set(getTableFormulaReferences(context.formula));
|
|
42903
|
+
const blockedReferences = getFormulaCycleBlockedLabels(context.tableNode, context.formulaCellLabel);
|
|
42757
42904
|
for (const info of cellInfos) {
|
|
42758
|
-
if (!info
|
|
42905
|
+
if (!info) continue;
|
|
42759
42906
|
const cellRect = info.cell.getBoundingClientRect();
|
|
42760
|
-
const highlight = createReferenceHighlight(info.label);
|
|
42907
|
+
const highlight = info.label !== context.formulaCellLabel && blockedReferences.has(info.label) ? createBlockedReferenceHighlight(info.label) : references.has(info.label) ? createReferenceHighlight(info.label) : null;
|
|
42908
|
+
if (!highlight) continue;
|
|
42761
42909
|
setPosition(
|
|
42762
42910
|
highlight,
|
|
42763
42911
|
cellRect.left - containerRect.left + container.scrollLeft + 2,
|
|
@@ -42812,6 +42960,7 @@ function useFormulaCoordinateOverlay(editor, containerRef, labels) {
|
|
|
42812
42960
|
editor.view.dom.addEventListener("mousemove", handleMouseMove2);
|
|
42813
42961
|
editor.view.dom.addEventListener("mouseleave", handleMouseLeave2);
|
|
42814
42962
|
container.addEventListener(UEDITOR_TABLE_LAYOUT_CHANGE_EVENT, scheduleSync);
|
|
42963
|
+
container.addEventListener("scroll", scheduleSync, scrollListenerOptions);
|
|
42815
42964
|
window.addEventListener("resize", scheduleSync);
|
|
42816
42965
|
scheduleSync();
|
|
42817
42966
|
return () => {
|
|
@@ -42822,6 +42971,7 @@ function useFormulaCoordinateOverlay(editor, containerRef, labels) {
|
|
|
42822
42971
|
editor.view.dom.removeEventListener("mousemove", handleMouseMove2);
|
|
42823
42972
|
editor.view.dom.removeEventListener("mouseleave", handleMouseLeave2);
|
|
42824
42973
|
container.removeEventListener(UEDITOR_TABLE_LAYOUT_CHANGE_EVENT, scheduleSync);
|
|
42974
|
+
container.removeEventListener("scroll", scheduleSync, scrollListenerOptions);
|
|
42825
42975
|
window.removeEventListener("resize", scheduleSync);
|
|
42826
42976
|
if (animationFrame != null) window.cancelAnimationFrame(animationFrame);
|
|
42827
42977
|
clearOverlay();
|
|
@@ -43486,7 +43636,7 @@ var MenuBar = ({
|
|
|
43486
43636
|
closeInsertMenu();
|
|
43487
43637
|
};
|
|
43488
43638
|
const handleLinkSubmit = (url) => {
|
|
43489
|
-
editor
|
|
43639
|
+
applyEditorLink(editor, url);
|
|
43490
43640
|
closeInsertMenu();
|
|
43491
43641
|
};
|
|
43492
43642
|
const insertMenuItems = [
|
|
@@ -44238,7 +44388,7 @@ var UEditor = import_react82.default.forwardRef(({
|
|
|
44238
44388
|
{
|
|
44239
44389
|
ref: formulaCoordinateOverlayRef,
|
|
44240
44390
|
"data-ueditor-formula-coordinate-overlay": "",
|
|
44241
|
-
className: "pointer-events-none absolute inset-0 z-[
|
|
44391
|
+
className: "pointer-events-none absolute inset-0 z-[35] hidden overflow-visible"
|
|
44242
44392
|
}
|
|
44243
44393
|
),
|
|
44244
44394
|
formulaRangeHighlight && /* @__PURE__ */ (0, import_jsx_runtime101.jsx)(
|
|
@@ -44246,7 +44396,11 @@ var UEditor = import_react82.default.forwardRef(({
|
|
|
44246
44396
|
{
|
|
44247
44397
|
"aria-hidden": "true",
|
|
44248
44398
|
"data-ueditor-formula-range-highlight": "",
|
|
44249
|
-
|
|
44399
|
+
"data-ueditor-formula-range-blocked": formulaRangeHighlight.blocked ? "true" : void 0,
|
|
44400
|
+
className: cn(
|
|
44401
|
+
"pointer-events-none absolute z-20 rounded-[2px] border-2",
|
|
44402
|
+
formulaRangeHighlight.blocked ? "border-destructive bg-destructive/15" : "border-primary bg-primary/10"
|
|
44403
|
+
),
|
|
44250
44404
|
style: {
|
|
44251
44405
|
left: formulaRangeHighlight.left,
|
|
44252
44406
|
top: formulaRangeHighlight.top,
|