@underverse-ui/underverse 1.0.202 → 1.0.203

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/dist/index.js CHANGED
@@ -801,6 +801,8 @@ var en_default = {
801
801
  alignCenter: "Align Center",
802
802
  alignRight: "Align Right",
803
803
  justify: "Justify",
804
+ decreaseIndent: "Decrease Indent",
805
+ increaseIndent: "Increase Indent",
804
806
  bulletList: "Bullet List",
805
807
  orderedList: "Numbered List",
806
808
  taskList: "Task List",
@@ -1250,6 +1252,8 @@ var vi_default = {
1250
1252
  alignCenter: "C\u0103n gi\u1EEFa",
1251
1253
  alignRight: "C\u0103n ph\u1EA3i",
1252
1254
  justify: "C\u0103n \u0111\u1EC1u",
1255
+ decreaseIndent: "Gi\u1EA3m l\u1EC1",
1256
+ increaseIndent: "T\u0103ng l\u1EC1",
1253
1257
  bulletList: "Danh s\xE1ch d\u1EA5u ch\u1EA5m",
1254
1258
  orderedList: "Danh s\xE1ch s\u1ED1",
1255
1259
  taskList: "Danh s\xE1ch c\xF4ng vi\u1EC7c",
@@ -1699,6 +1703,8 @@ var ko_default = {
1699
1703
  alignCenter: "\uAC00\uC6B4\uB370 \uC815\uB82C",
1700
1704
  alignRight: "\uC624\uB978\uCABD \uC815\uB82C",
1701
1705
  justify: "\uC591\uCABD \uB9DE\uCDA4",
1706
+ decreaseIndent: "\uB0B4\uC5B4\uC4F0\uAE30",
1707
+ increaseIndent: "\uB4E4\uC5EC\uC4F0\uAE30",
1702
1708
  bulletList: "\uAE00\uBA38\uB9AC \uAE30\uD638 \uBAA9\uB85D",
1703
1709
  orderedList: "\uBC88\uD638 \uB9E4\uAE30\uAE30 \uBAA9\uB85D",
1704
1710
  taskList: "\uD560 \uC77C \uBAA9\uB85D",
@@ -2148,6 +2154,8 @@ var ja_default = {
2148
2154
  alignCenter: "\u4E2D\u592E\u63C3\u3048",
2149
2155
  alignRight: "\u53F3\u63C3\u3048",
2150
2156
  justify: "\u4E21\u7AEF\u63C3\u3048",
2157
+ decreaseIndent: "\u30A4\u30F3\u30C7\u30F3\u30C8\u3092\u6E1B\u3089\u3059",
2158
+ increaseIndent: "\u30A4\u30F3\u30C7\u30F3\u30C8\u3092\u5897\u3084\u3059",
2151
2159
  bulletList: "\u7B87\u6761\u66F8\u304D",
2152
2160
  orderedList: "\u756A\u53F7\u4ED8\u304D\u30EA\u30B9\u30C8",
2153
2161
  taskList: "\u30BF\u30B9\u30AF\u30EA\u30B9\u30C8",
@@ -31497,6 +31505,199 @@ var LetterSpacing = Extension9.create({
31497
31505
  });
31498
31506
  var letter_spacing_default = LetterSpacing;
31499
31507
 
31508
+ // src/components/UEditor/indent.ts
31509
+ import { Extension as Extension10 } from "@tiptap/core";
31510
+ import { isInTable } from "@tiptap/pm/tables";
31511
+ var DEFAULT_MAX_LEVEL = 6;
31512
+ var DEFAULT_MIN_LEVEL = 0;
31513
+ var DEFAULT_STEP_REM = 2;
31514
+ var INLINE_TAB_SPACES = "\xA0".repeat(4);
31515
+ var LIST_ITEM_TYPES = /* @__PURE__ */ new Set(["listItem", "taskItem"]);
31516
+ var TABLE_CELL_TYPES = /* @__PURE__ */ new Set(["tableCell", "tableHeader"]);
31517
+ function clampIndentLevel(value, minLevel, maxLevel) {
31518
+ const numericValue = typeof value === "number" ? value : Number.parseInt(String(value ?? ""), 10);
31519
+ if (!Number.isFinite(numericValue)) return minLevel;
31520
+ return Math.min(maxLevel, Math.max(minLevel, Math.round(numericValue)));
31521
+ }
31522
+ function parseIndentLevel(element, options) {
31523
+ const dataIndent = element.getAttribute("data-indent");
31524
+ if (dataIndent !== null) {
31525
+ return clampIndentLevel(dataIndent, options.minLevel, options.maxLevel);
31526
+ }
31527
+ const marginLeft = element.style.marginLeft.trim();
31528
+ const match = marginLeft.match(/^(-?\d+(?:\.\d+)?)(rem|em|px)$/i);
31529
+ if (!match) return options.minLevel;
31530
+ const value = Number.parseFloat(match[1] ?? "0");
31531
+ const unit = match[2]?.toLowerCase();
31532
+ const remValue = unit === "px" ? value / 16 : value;
31533
+ return clampIndentLevel(remValue / options.stepRem, options.minLevel, options.maxLevel);
31534
+ }
31535
+ function getNodePos($pos, depth) {
31536
+ return depth > 0 ? $pos.before(depth) : 0;
31537
+ }
31538
+ function getIndentTargetAt($pos, indentTypes) {
31539
+ for (let depth = $pos.depth; depth > 0; depth -= 1) {
31540
+ const nodeName = $pos.node(depth).type.name;
31541
+ if (LIST_ITEM_TYPES.has(nodeName) || TABLE_CELL_TYPES.has(nodeName)) return null;
31542
+ }
31543
+ if (indentTypes.has("blockquote")) {
31544
+ for (let depth = $pos.depth; depth > 0; depth -= 1) {
31545
+ const node = $pos.node(depth);
31546
+ if (node.type.name === "blockquote") {
31547
+ return { node, pos: getNodePos($pos, depth) };
31548
+ }
31549
+ }
31550
+ }
31551
+ for (let depth = $pos.depth; depth > 0; depth -= 1) {
31552
+ const node = $pos.node(depth);
31553
+ if (indentTypes.has(node.type.name)) {
31554
+ return { node, pos: getNodePos($pos, depth) };
31555
+ }
31556
+ }
31557
+ return null;
31558
+ }
31559
+ function getIndentTargets(state, types) {
31560
+ if (isInTable(state)) return [];
31561
+ const indentTypes = new Set(types);
31562
+ const targets = /* @__PURE__ */ new Map();
31563
+ const addTarget = (target) => {
31564
+ if (target) targets.set(target.pos, target);
31565
+ };
31566
+ addTarget(getIndentTargetAt(state.selection.$from, indentTypes));
31567
+ addTarget(getIndentTargetAt(state.selection.$to, indentTypes));
31568
+ if (!state.selection.empty) {
31569
+ state.doc.nodesBetween(state.selection.from, state.selection.to, (node, pos) => {
31570
+ if (!indentTypes.has(node.type.name)) return true;
31571
+ const resolvedPos = state.doc.resolve(Math.min(pos + 1, state.doc.content.size));
31572
+ addTarget(getIndentTargetAt(resolvedPos, indentTypes));
31573
+ return node.type.name !== "blockquote";
31574
+ });
31575
+ }
31576
+ return Array.from(targets.values()).sort((a, b) => a.pos - b.pos);
31577
+ }
31578
+ function updateBlockIndent({
31579
+ state,
31580
+ dispatch,
31581
+ options,
31582
+ delta
31583
+ }) {
31584
+ const targets = getIndentTargets(state, options.types);
31585
+ let transaction = state.tr;
31586
+ let changed = false;
31587
+ for (const target of targets) {
31588
+ const currentLevel = clampIndentLevel(target.node.attrs.indent, options.minLevel, options.maxLevel);
31589
+ const nextLevel = clampIndentLevel(currentLevel + delta, options.minLevel, options.maxLevel);
31590
+ if (nextLevel === currentLevel) continue;
31591
+ transaction = transaction.setNodeMarkup(target.pos, void 0, {
31592
+ ...target.node.attrs,
31593
+ indent: nextLevel
31594
+ });
31595
+ changed = true;
31596
+ }
31597
+ if (changed && dispatch) dispatch(transaction.scrollIntoView());
31598
+ return changed;
31599
+ }
31600
+ function insertTabAtCursor(state, dispatch) {
31601
+ if (!state.selection.empty) return false;
31602
+ if (dispatch) {
31603
+ dispatch(state.tr.insertText(INLINE_TAB_SPACES, state.selection.from).scrollIntoView());
31604
+ }
31605
+ return true;
31606
+ }
31607
+ function removeTabBeforeCursor(state, dispatch) {
31608
+ if (!state.selection.empty || state.selection.$from.parentOffset <= 0) return false;
31609
+ const cursorPos = state.selection.from;
31610
+ const tabStartPos = cursorPos - INLINE_TAB_SPACES.length;
31611
+ if (tabStartPos < 0 || state.doc.textBetween(tabStartPos, cursorPos) !== INLINE_TAB_SPACES) return false;
31612
+ if (dispatch) {
31613
+ dispatch(state.tr.delete(tabStartPos, cursorPos).scrollIntoView());
31614
+ }
31615
+ return true;
31616
+ }
31617
+ var Indent = Extension10.create({
31618
+ name: "indent",
31619
+ addOptions() {
31620
+ return {
31621
+ maxLevel: DEFAULT_MAX_LEVEL,
31622
+ minLevel: DEFAULT_MIN_LEVEL,
31623
+ stepRem: DEFAULT_STEP_REM,
31624
+ types: ["paragraph", "blockquote"]
31625
+ };
31626
+ },
31627
+ addGlobalAttributes() {
31628
+ return [
31629
+ {
31630
+ types: this.options.types,
31631
+ attributes: {
31632
+ indent: {
31633
+ default: this.options.minLevel,
31634
+ parseHTML: (element) => parseIndentLevel(element, this.options),
31635
+ renderHTML: (attributes) => {
31636
+ const level = clampIndentLevel(attributes.indent, this.options.minLevel, this.options.maxLevel);
31637
+ if (level <= this.options.minLevel) return {};
31638
+ return {
31639
+ "data-indent": String(level),
31640
+ style: `margin-left: ${level * this.options.stepRem}rem`
31641
+ };
31642
+ }
31643
+ }
31644
+ }
31645
+ }
31646
+ ];
31647
+ },
31648
+ addCommands() {
31649
+ return {
31650
+ increaseIndent: () => ({ editor, commands, state, dispatch }) => {
31651
+ if (editor.isActive("taskItem")) return commands.sinkListItem("taskItem");
31652
+ if (editor.isActive("listItem")) return commands.sinkListItem("listItem");
31653
+ return updateBlockIndent({
31654
+ state,
31655
+ dispatch,
31656
+ options: this.options,
31657
+ delta: 1
31658
+ });
31659
+ },
31660
+ decreaseIndent: () => ({ editor, commands, state, dispatch }) => {
31661
+ if (editor.isActive("taskItem")) return commands.liftListItem("taskItem");
31662
+ if (editor.isActive("listItem")) return commands.liftListItem("listItem");
31663
+ return updateBlockIndent({
31664
+ state,
31665
+ dispatch,
31666
+ options: this.options,
31667
+ delta: -1
31668
+ });
31669
+ }
31670
+ };
31671
+ },
31672
+ addKeyboardShortcuts() {
31673
+ const handleBlockIndent = (delta) => {
31674
+ const { state } = this.editor;
31675
+ const hasBlockTarget = getIndentTargets(state, this.options.types).length > 0;
31676
+ if (!hasBlockTarget) {
31677
+ return delta > 0 ? this.editor.commands.increaseIndent() : this.editor.commands.decreaseIndent();
31678
+ }
31679
+ if (state.selection.empty && state.selection.$from.parentOffset > 0) {
31680
+ if (delta > 0) {
31681
+ return insertTabAtCursor(state, (transaction) => this.editor.view.dispatch(transaction));
31682
+ }
31683
+ removeTabBeforeCursor(state, (transaction) => this.editor.view.dispatch(transaction));
31684
+ return true;
31685
+ }
31686
+ if (delta > 0) {
31687
+ this.editor.commands.increaseIndent();
31688
+ } else {
31689
+ this.editor.commands.decreaseIndent();
31690
+ }
31691
+ return true;
31692
+ };
31693
+ return {
31694
+ Tab: () => handleBlockIndent(1),
31695
+ "Shift-Tab": () => handleBlockIndent(-1)
31696
+ };
31697
+ }
31698
+ });
31699
+ var indent_default = Indent;
31700
+
31500
31701
  // src/components/UEditor/table-align.ts
31501
31702
  import { Table as Table3 } from "@tiptap/extension-table";
31502
31703
  import { Plugin as Plugin5 } from "@tiptap/pm/state";
@@ -32517,6 +32718,7 @@ function buildUEditorExtensions({
32517
32718
  font_size_default,
32518
32719
  line_height_default,
32519
32720
  letter_spacing_default,
32721
+ indent_default,
32520
32722
  Color,
32521
32723
  Highlight.configure({
32522
32724
  multicolor: true
@@ -32597,6 +32799,8 @@ import {
32597
32799
  Heading1 as Heading1Icon,
32598
32800
  Heading2 as Heading2Icon,
32599
32801
  Heading3 as Heading3Icon,
32802
+ IndentDecrease,
32803
+ IndentIncrease,
32600
32804
  Link as LinkIcon,
32601
32805
  List as ListIcon,
32602
32806
  ListOrdered as ListOrderedIcon,
@@ -33649,6 +33853,77 @@ function getTableAnchorPos(editor) {
33649
33853
  const firstCell = tables[0]?.querySelector("th,td");
33650
33854
  return firstCell instanceof HTMLTableCellElement ? editor.view.posAtDOM(firstCell, 0) + 1 : null;
33651
33855
  }
33856
+ var EDITOR_UI_ACTIVE_MARKS = [
33857
+ "blockquote",
33858
+ "bold",
33859
+ "bulletList",
33860
+ "code",
33861
+ "codeBlock",
33862
+ "formCheckbox",
33863
+ "highlight",
33864
+ "image",
33865
+ "italic",
33866
+ "link",
33867
+ "orderedList",
33868
+ "paragraph",
33869
+ "strike",
33870
+ "subscript",
33871
+ "superscript",
33872
+ "taskList",
33873
+ "underline"
33874
+ ];
33875
+ function getEditorUiRenderState(editor) {
33876
+ const textStyle = editor.getAttributes("textStyle");
33877
+ const highlight = editor.getAttributes("highlight");
33878
+ const image = editor.getAttributes("image");
33879
+ const link = editor.getAttributes("link");
33880
+ const tableCell = editor.getAttributes("tableCell");
33881
+ const tableHeader = editor.getAttributes("tableHeader");
33882
+ const hasTableContext = getTableAnchorPos(editor) !== null;
33883
+ const can = editor.can();
33884
+ return {
33885
+ active: EDITOR_UI_ACTIVE_MARKS.map((name) => editor.isActive(name)),
33886
+ alignment: ["left", "center", "right", "justify"].map((textAlign) => editor.isActive({ textAlign })),
33887
+ heading: [1, 2, 3].map((level) => editor.isActive("heading", { level })),
33888
+ textStyle: {
33889
+ color: textStyle.color ?? null,
33890
+ fontFamily: textStyle.fontFamily ?? null,
33891
+ fontSize: textStyle.fontSize ?? null,
33892
+ letterSpacing: textStyle.letterSpacing ?? null,
33893
+ lineHeight: textStyle.lineHeight ?? null
33894
+ },
33895
+ highlightColor: highlight.color ?? null,
33896
+ image: {
33897
+ imageLayout: image.imageLayout ?? null,
33898
+ imageWidthPreset: image.imageWidthPreset ?? null
33899
+ },
33900
+ linkHref: link.href ?? null,
33901
+ tableCell: {
33902
+ backgroundColor: tableCell.backgroundColor ?? tableHeader.backgroundColor ?? null,
33903
+ borderColor: tableCell.borderColor ?? tableHeader.borderColor ?? null,
33904
+ borderStyle: tableCell.borderStyle ?? tableHeader.borderStyle ?? null,
33905
+ borderWidth: tableCell.borderWidth ?? tableHeader.borderWidth ?? null,
33906
+ formula: tableCell.formula ?? tableHeader.formula ?? null,
33907
+ numberFormat: tableCell.numberFormat ?? tableHeader.numberFormat ?? null,
33908
+ textDirection: tableCell.textDirection ?? tableHeader.textDirection ?? null,
33909
+ verticalAlign: tableCell.verticalAlign ?? tableHeader.verticalAlign ?? null
33910
+ },
33911
+ can: {
33912
+ addColumnAfter: hasTableContext && can.addColumnAfter(),
33913
+ addColumnBefore: hasTableContext && can.addColumnBefore(),
33914
+ addRowAfter: hasTableContext && can.addRowAfter(),
33915
+ addRowBefore: hasTableContext && can.addRowBefore(),
33916
+ decreaseIndent: can.decreaseIndent(),
33917
+ increaseIndent: can.increaseIndent(),
33918
+ mergeCells: hasTableContext && can.mergeCells(),
33919
+ redo: can.redo(),
33920
+ splitCell: hasTableContext && can.splitCell(),
33921
+ undo: can.undo()
33922
+ },
33923
+ hasTableContext,
33924
+ isEmpty: editor.isEmpty
33925
+ };
33926
+ }
33652
33927
  function fileToDataUrl2(file) {
33653
33928
  return new Promise((resolve, reject) => {
33654
33929
  const reader = new FileReader();
@@ -33702,7 +33977,7 @@ var TableInsertGrid = ({
33702
33977
  const maxCols = 8;
33703
33978
  return /* @__PURE__ */ jsxs75("div", { className: "mb-2 rounded-xl border border-border/60 bg-muted/20 p-2", children: [
33704
33979
  /* @__PURE__ */ jsx93("div", { className: "mb-2 text-sm font-medium text-foreground", children: formatTableInsertLabel(previewTemplate, selection.rows, selection.cols) }),
33705
- /* @__PURE__ */ jsx93("div", { className: "grid grid-cols-8 gap-1", onMouseLeave: () => setSelection((prev) => prev), children: Array.from({ length: maxRows }).map(
33980
+ /* @__PURE__ */ jsx93("div", { className: "grid grid-cols-8 gap-1", children: Array.from({ length: maxRows }).map(
33706
33981
  (_, rowIndex) => Array.from({ length: maxCols }).map((__, colIndex) => {
33707
33982
  const rows = rowIndex + 1;
33708
33983
  const cols = colIndex + 1;
@@ -33750,9 +34025,9 @@ var EditorToolbar = ({
33750
34025
  letterSpacings
33751
34026
  }) => {
33752
34027
  const t = useSmartTranslations("UEditor");
33753
- useEditorState({
34028
+ const editorUiState = useEditorState({
33754
34029
  editor,
33755
- selector: ({ transactionNumber }) => transactionNumber
34030
+ selector: ({ editor: currentEditor }) => getEditorUiRenderState(currentEditor)
33756
34031
  });
33757
34032
  const { textColors, highlightColors } = useEditorColors();
33758
34033
  const [showImageInput, setShowImageInput] = useState50(false);
@@ -33834,6 +34109,24 @@ var EditorToolbar = ({
33834
34109
  children: /* @__PURE__ */ jsx93(FigmaListIcon, { className: "h-4 w-4" })
33835
34110
  }
33836
34111
  ),
34112
+ /* @__PURE__ */ jsx93(
34113
+ ToolbarButton,
34114
+ {
34115
+ onClick: () => editor.chain().focus().decreaseIndent().run(),
34116
+ disabled: !editorUiState.can.decreaseIndent,
34117
+ title: t("toolbar.decreaseIndent"),
34118
+ children: /* @__PURE__ */ jsx93(IndentDecrease, { className: "h-4 w-4" })
34119
+ }
34120
+ ),
34121
+ /* @__PURE__ */ jsx93(
34122
+ ToolbarButton,
34123
+ {
34124
+ onClick: () => editor.chain().focus().increaseIndent().run(),
34125
+ disabled: !editorUiState.can.increaseIndent,
34126
+ title: t("toolbar.increaseIndent"),
34127
+ children: /* @__PURE__ */ jsx93(IndentIncrease, { className: "h-4 w-4" })
34128
+ }
34129
+ ),
33837
34130
  /* @__PURE__ */ jsxs75(
33838
34131
  DropdownMenu,
33839
34132
  {
@@ -34334,6 +34627,24 @@ var EditorToolbar = ({
34334
34627
  ]
34335
34628
  }
34336
34629
  ),
34630
+ /* @__PURE__ */ jsx93(
34631
+ ToolbarButton,
34632
+ {
34633
+ onClick: () => editor.chain().focus().decreaseIndent().run(),
34634
+ disabled: !editorUiState.can.decreaseIndent,
34635
+ title: t("toolbar.decreaseIndent"),
34636
+ children: /* @__PURE__ */ jsx93(IndentDecrease, { className: "h-4 w-4" })
34637
+ }
34638
+ ),
34639
+ /* @__PURE__ */ jsx93(
34640
+ ToolbarButton,
34641
+ {
34642
+ onClick: () => editor.chain().focus().increaseIndent().run(),
34643
+ disabled: !editorUiState.can.increaseIndent,
34644
+ title: t("toolbar.increaseIndent"),
34645
+ children: /* @__PURE__ */ jsx93(IndentIncrease, { className: "h-4 w-4" })
34646
+ }
34647
+ ),
34337
34648
  /* @__PURE__ */ jsxs75(
34338
34649
  DropdownMenu,
34339
34650
  {
@@ -35842,7 +36153,7 @@ var BubbleMenuContent = ({
35842
36153
  const t = useSmartTranslations("UEditor");
35843
36154
  useEditorState2({
35844
36155
  editor,
35845
- selector: ({ transactionNumber }) => transactionNumber
36156
+ selector: ({ editor: currentEditor }) => getEditorUiRenderState(currentEditor)
35846
36157
  });
35847
36158
  const { textColors, highlightColors } = useEditorColors();
35848
36159
  const [showLinkInput, setShowLinkInput] = useState51(initialShowLinkInput);
@@ -35878,9 +36189,9 @@ var BubbleMenuContent = ({
35878
36189
  const [activeBorderPosition, setActiveBorderPosition] = useState51("all");
35879
36190
  const currentCellVerticalAlign = normalizeStyleValue(editor.getAttributes("tableCell").verticalAlign || editor.getAttributes("tableHeader").verticalAlign) || "";
35880
36191
  const currentCellTextDirection = normalizeStyleValue(editor.getAttributes("tableCell").textDirection || editor.getAttributes("tableHeader").textDirection) || "horizontal";
35881
- const isInTable2 = isSelectionInTable(editor.state);
35882
- const canMergeCells = isInTable2 && editor.can().mergeCells();
35883
- const canSplitCell = isInTable2 && editor.can().splitCell();
36192
+ const isInTable3 = isSelectionInTable(editor.state);
36193
+ const canMergeCells = isInTable3 && editor.can().mergeCells();
36194
+ const canSplitCell = isInTable3 && editor.can().splitCell();
35884
36195
  const currentFontSize = normalizeStyleValue(textStyleAttrs.fontSize);
35885
36196
  const currentLineHeight = normalizeStyleValue(textStyleAttrs.lineHeight);
35886
36197
  const quickFontSizes = useMemo25(
@@ -36226,7 +36537,7 @@ var BubbleMenuContent = ({
36226
36537
  )
36227
36538
  ] });
36228
36539
  }
36229
- if (showFormulaPanel && isInTable2) {
36540
+ if (showFormulaPanel && isInTable3) {
36230
36541
  return /* @__PURE__ */ jsxs76("div", { className: "w-72 p-2", children: [
36231
36542
  /* @__PURE__ */ jsxs76("div", { className: "mb-2 flex items-center justify-between gap-2", children: [
36232
36543
  /* @__PURE__ */ jsx94("span", { className: "px-1 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: t("tableMenu.formula") || "Formula" }),
@@ -36790,20 +37101,24 @@ var CustomBubbleMenu = ({
36790
37101
  setIsVisible(false);
36791
37102
  }
36792
37103
  };
36793
- editor.on("selectionUpdate", updatePosition);
36794
- editor.on("focus", updatePosition);
37104
+ let animationFrameId = null;
37105
+ const schedulePositionUpdate = () => {
37106
+ if (animationFrameId !== null) return;
37107
+ animationFrameId = requestAnimationFrame(() => {
37108
+ animationFrameId = null;
37109
+ updatePosition();
37110
+ });
37111
+ };
37112
+ editor.on("transaction", schedulePositionUpdate);
37113
+ editor.on("focus", schedulePositionUpdate);
36795
37114
  editor.on("blur", handleBlur);
36796
- editor.on("transaction", updatePosition);
36797
- editor.on("update", updatePosition);
36798
- const animationFrameId = requestAnimationFrame(updatePosition);
37115
+ schedulePositionUpdate();
36799
37116
  return () => {
36800
- cancelAnimationFrame(animationFrameId);
37117
+ if (animationFrameId !== null) cancelAnimationFrame(animationFrameId);
36801
37118
  clearShowTimeout();
36802
- editor.off("selectionUpdate", updatePosition);
36803
- editor.off("focus", updatePosition);
37119
+ editor.off("transaction", schedulePositionUpdate);
37120
+ editor.off("focus", schedulePositionUpdate);
36804
37121
  editor.off("blur", handleBlur);
36805
- editor.off("transaction", updatePosition);
36806
- editor.off("update", updatePosition);
36807
37122
  };
36808
37123
  }, [editor]);
36809
37124
  useEffect38(() => {
@@ -36893,15 +37208,23 @@ var CustomFloatingMenu = ({ editor }) => {
36893
37208
  setIsVisible(true);
36894
37209
  };
36895
37210
  const handleBlur = () => setIsVisible(false);
36896
- editor.on("selectionUpdate", updatePosition);
36897
- editor.on("focus", updatePosition);
37211
+ let animationFrameId = null;
37212
+ const schedulePositionUpdate = () => {
37213
+ if (animationFrameId !== null) return;
37214
+ animationFrameId = requestAnimationFrame(() => {
37215
+ animationFrameId = null;
37216
+ updatePosition();
37217
+ });
37218
+ };
37219
+ editor.on("transaction", schedulePositionUpdate);
37220
+ editor.on("focus", schedulePositionUpdate);
36898
37221
  editor.on("blur", handleBlur);
36899
- editor.on("update", updatePosition);
37222
+ schedulePositionUpdate();
36900
37223
  return () => {
36901
- editor.off("selectionUpdate", updatePosition);
36902
- editor.off("focus", updatePosition);
37224
+ if (animationFrameId !== null) cancelAnimationFrame(animationFrameId);
37225
+ editor.off("transaction", schedulePositionUpdate);
37226
+ editor.off("focus", schedulePositionUpdate);
36903
37227
  editor.off("blur", handleBlur);
36904
- editor.off("update", updatePosition);
36905
37228
  };
36906
37229
  }, [editor]);
36907
37230
  if (!isVisible) return null;
@@ -36925,12 +37248,20 @@ var CustomFloatingMenu = ({ editor }) => {
36925
37248
  };
36926
37249
 
36927
37250
  // src/components/UEditor/CharacterCount.tsx
37251
+ import { useEditorState as useEditorState3 } from "@tiptap/react";
36928
37252
  import { jsxs as jsxs77 } from "react/jsx-runtime";
36929
37253
  var CharacterCountDisplay = ({ editor, maxCharacters }) => {
36930
37254
  const t = useSmartTranslations("UEditor");
36931
- const storage = editor.storage;
36932
- const characterCount = storage.characterCount?.characters?.() ?? 0;
36933
- const wordCount = storage.characterCount?.words?.() ?? 0;
37255
+ const { characterCount, wordCount } = useEditorState3({
37256
+ editor,
37257
+ selector: ({ editor: currentEditor }) => {
37258
+ const storage = currentEditor.storage;
37259
+ return {
37260
+ characterCount: storage.characterCount?.characters?.() ?? 0,
37261
+ wordCount: storage.characterCount?.words?.() ?? 0
37262
+ };
37263
+ }
37264
+ });
36934
37265
  const percentage = maxCharacters ? Math.round(characterCount / maxCharacters * 100) : 0;
36935
37266
  return /* @__PURE__ */ jsxs77("div", { className: "flex items-center gap-3 px-3 py-2 text-xs text-muted-foreground border-t border-border/30 bg-muted/20", children: [
36936
37267
  /* @__PURE__ */ jsxs77("span", { children: [
@@ -40818,7 +41149,7 @@ function cellAround2($pos) {
40818
41149
  for (let d = $pos.depth - 1; d > 0; d--) if ($pos.node(d).type.spec.tableRole == "row") return $pos.node(0).resolve($pos.before(d + 1));
40819
41150
  return null;
40820
41151
  }
40821
- function isInTable(state) {
41152
+ function isInTable2(state) {
40822
41153
  const $head = state.selection.$head;
40823
41154
  for (let d = $head.depth; d > 0; d--) if ($head.node(d).type.spec.tableRole == "row") return true;
40824
41155
  return false;
@@ -41334,7 +41665,7 @@ function selectedRect4(state) {
41334
41665
  }
41335
41666
  function deprecated_toggleHeader(type) {
41336
41667
  return function(state, dispatch) {
41337
- if (!isInTable(state)) return false;
41668
+ if (!isInTable2(state)) return false;
41338
41669
  if (dispatch) {
41339
41670
  const types = tableNodeTypes2(state.schema);
41340
41671
  const rect = selectedRect4(state), tr = state.tr;
@@ -41374,7 +41705,7 @@ function toggleHeader(type, options) {
41374
41705
  options = options || { useDeprecatedLogic: false };
41375
41706
  if (options.useDeprecatedLogic) return deprecated_toggleHeader(type);
41376
41707
  return function(state, dispatch) {
41377
- if (!isInTable(state)) return false;
41708
+ if (!isInTable2(state)) return false;
41378
41709
  if (dispatch) {
41379
41710
  const types = tableNodeTypes2(state.schema);
41380
41711
  const rect = selectedRect4(state), tr = state.tr;
@@ -44290,7 +44621,7 @@ function useFormulaCoordinateOverlay(editor, containerRef, labels) {
44290
44621
 
44291
44622
  // src/components/UEditor/menu-bar.tsx
44292
44623
  import React89, { useMemo as useMemo26, useRef as useRef39, useState as useState52 } from "react";
44293
- import { useEditorState as useEditorState3 } from "@tiptap/react";
44624
+ import { useEditorState as useEditorState4 } from "@tiptap/react";
44294
44625
  import {
44295
44626
  AlignCenter as AlignCenter4,
44296
44627
  AlignJustify as AlignJustify2,
@@ -44910,9 +45241,9 @@ var MenuBar = ({
44910
45241
  onPreview
44911
45242
  }) => {
44912
45243
  const t = useSmartTranslations("UEditor");
44913
- useEditorState3({
45244
+ useEditorState4({
44914
45245
  editor,
44915
- selector: ({ transactionNumber }) => transactionNumber
45246
+ selector: ({ editor: currentEditor }) => getEditorUiRenderState(currentEditor)
44916
45247
  });
44917
45248
  const fileInputRef = useRef39(null);
44918
45249
  const [showImageInput, setShowImageInput] = useState52(false);
@@ -45208,18 +45539,31 @@ var MenuBar = ({
45208
45539
 
45209
45540
  // src/components/UEditor/table-formula-bar.tsx
45210
45541
  import { useEffect as useEffect41, useRef as useRef40, useState as useState53 } from "react";
45211
- import { useEditorState as useEditorState4 } from "@tiptap/react";
45542
+ import { useEditorState as useEditorState5 } from "@tiptap/react";
45212
45543
  import { AlertCircle as AlertCircle5, Check as Check14, Hash as Hash2, Sigma as Sigma3, Trash2 as Trash26 } from "lucide-react";
45213
45544
  import { jsx as jsx102, jsxs as jsxs83 } from "react/jsx-runtime";
45214
45545
  function TableFormulaBar({ editor }) {
45215
45546
  const t = useSmartTranslations("UEditor");
45216
45547
  const inputRef = useRef40(null);
45217
45548
  const [draftState, setDraftState] = useState53(null);
45218
- useEditorState4({
45549
+ const selectedFormulaState = useEditorState5({
45219
45550
  editor,
45220
- selector: ({ transactionNumber }) => transactionNumber
45551
+ selector: ({ editor: currentEditor }) => {
45552
+ const cell = getSelectedTableFormulaCell(currentEditor);
45553
+ if (!cell) return null;
45554
+ return {
45555
+ cellPos: cell.cellPos,
45556
+ column: cell.column,
45557
+ computedValue: cell.computedValue,
45558
+ formula: cell.formula,
45559
+ formulaState: cell.formulaState,
45560
+ label: cell.label,
45561
+ row: cell.row,
45562
+ tablePos: cell.tablePos
45563
+ };
45564
+ }
45221
45565
  });
45222
- const selectedCell = getSelectedTableFormulaCell(editor);
45566
+ const selectedCell = selectedFormulaState ? getSelectedTableFormulaCell(editor) : null;
45223
45567
  useEffect41(() => {
45224
45568
  const focusFormulaInput = () => {
45225
45569
  inputRef.current?.focus();
@@ -45400,6 +45744,7 @@ var UEditor = React91.forwardRef(({
45400
45744
  const inFlightPrepareRef = useRef41(null);
45401
45745
  const lastAppliedContentRef = useRef41(content ?? "");
45402
45746
  const scheduledFormulaRecalculateRef = useRef41(false);
45747
+ const pendingFormulaTextRecalculateRef = useRef41(false);
45403
45748
  const editorInstanceRef = useRef41(null);
45404
45749
  const formulaRangePickRef = useRef41(null);
45405
45750
  const formulaRangeSurfaceRef = useRef41(null);
@@ -45538,19 +45883,32 @@ var UEditor = React91.forwardRef(({
45538
45883
  },
45539
45884
  onUpdate: ({ editor: editor2, transaction }) => {
45540
45885
  if (!transaction.getMeta(UEDITOR_TABLE_FORMULA_RECALCULATE_META)) {
45541
- scheduleFormulaRecalculate(editor2);
45886
+ if (isEditingTableFormulaText(editor2)) {
45887
+ pendingFormulaTextRecalculateRef.current = true;
45888
+ } else {
45889
+ pendingFormulaTextRecalculateRef.current = false;
45890
+ scheduleFormulaRecalculate(editor2);
45891
+ }
45892
+ }
45893
+ if (onChange || onHtmlChange) {
45894
+ const html = editor2.getHTML();
45895
+ onChange?.(html);
45896
+ onHtmlChange?.(html);
45897
+ }
45898
+ if (onJsonChange) {
45899
+ onJsonChange(editor2.getJSON());
45542
45900
  }
45543
- const html = editor2.getHTML();
45544
- onChange?.(html);
45545
- onHtmlChange?.(html);
45546
- onJsonChange?.(editor2.getJSON());
45547
45901
  },
45548
45902
  onSelectionUpdate: ({ editor: editor2 }) => {
45549
- scheduleFormulaRecalculate(editor2);
45903
+ if (pendingFormulaTextRecalculateRef.current && !isEditingTableFormulaText(editor2)) {
45904
+ pendingFormulaTextRecalculateRef.current = false;
45905
+ scheduleFormulaRecalculate(editor2);
45906
+ }
45550
45907
  },
45551
45908
  onBlur: ({ editor: editor2, event }) => {
45552
45909
  const nextTarget = event.relatedTarget;
45553
45910
  if (nextTarget instanceof Element && nextTarget.closest("[data-ueditor-formula-bar]")) return;
45911
+ pendingFormulaTextRecalculateRef.current = false;
45554
45912
  scheduleFormulaRecalculate(editor2, { force: true });
45555
45913
  }
45556
45914
  });