@underverse-ui/underverse 1.0.151 → 1.0.153

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.d.cts CHANGED
@@ -3619,6 +3619,9 @@ declare const underverseMessages: {
3619
3619
  borderColor: string;
3620
3620
  clearBorder: string;
3621
3621
  formula: string;
3622
+ numberFormat: string;
3623
+ formatText: string;
3624
+ formatDate: string;
3622
3625
  apply: string;
3623
3626
  clear: string;
3624
3627
  recalculate: string;
@@ -3997,6 +4000,9 @@ declare const underverseMessages: {
3997
4000
  borderColor: string;
3998
4001
  clearBorder: string;
3999
4002
  formula: string;
4003
+ numberFormat: string;
4004
+ formatText: string;
4005
+ formatDate: string;
4000
4006
  apply: string;
4001
4007
  clear: string;
4002
4008
  recalculate: string;
@@ -5124,6 +5130,9 @@ declare function getUnderverseMessages(locale?: UnderverseLocale): {
5124
5130
  borderColor: string;
5125
5131
  clearBorder: string;
5126
5132
  formula: string;
5133
+ numberFormat: string;
5134
+ formatText: string;
5135
+ formatDate: string;
5127
5136
  apply: string;
5128
5137
  clear: string;
5129
5138
  recalculate: string;
@@ -5501,6 +5510,9 @@ declare function getUnderverseMessages(locale?: UnderverseLocale): {
5501
5510
  borderColor: string;
5502
5511
  clearBorder: string;
5503
5512
  formula: string;
5513
+ numberFormat: string;
5514
+ formatText: string;
5515
+ formatDate: string;
5504
5516
  apply: string;
5505
5517
  clear: string;
5506
5518
  recalculate: string;
package/dist/index.d.ts CHANGED
@@ -3619,6 +3619,9 @@ declare const underverseMessages: {
3619
3619
  borderColor: string;
3620
3620
  clearBorder: string;
3621
3621
  formula: string;
3622
+ numberFormat: string;
3623
+ formatText: string;
3624
+ formatDate: string;
3622
3625
  apply: string;
3623
3626
  clear: string;
3624
3627
  recalculate: string;
@@ -3997,6 +4000,9 @@ declare const underverseMessages: {
3997
4000
  borderColor: string;
3998
4001
  clearBorder: string;
3999
4002
  formula: string;
4003
+ numberFormat: string;
4004
+ formatText: string;
4005
+ formatDate: string;
4000
4006
  apply: string;
4001
4007
  clear: string;
4002
4008
  recalculate: string;
@@ -5124,6 +5130,9 @@ declare function getUnderverseMessages(locale?: UnderverseLocale): {
5124
5130
  borderColor: string;
5125
5131
  clearBorder: string;
5126
5132
  formula: string;
5133
+ numberFormat: string;
5134
+ formatText: string;
5135
+ formatDate: string;
5127
5136
  apply: string;
5128
5137
  clear: string;
5129
5138
  recalculate: string;
@@ -5501,6 +5510,9 @@ declare function getUnderverseMessages(locale?: UnderverseLocale): {
5501
5510
  borderColor: string;
5502
5511
  clearBorder: string;
5503
5512
  formula: string;
5513
+ numberFormat: string;
5514
+ formatText: string;
5515
+ formatDate: string;
5504
5516
  apply: string;
5505
5517
  clear: string;
5506
5518
  recalculate: string;
package/dist/index.js CHANGED
@@ -844,6 +844,9 @@ var en_default = {
844
844
  borderColor: "Border Color",
845
845
  clearBorder: "Clear Border",
846
846
  formula: "Formula",
847
+ numberFormat: "Number Format",
848
+ formatText: "Text",
849
+ formatDate: "Date",
847
850
  apply: "Apply",
848
851
  clear: "Clear",
849
852
  recalculate: "Recalculate",
@@ -1224,6 +1227,9 @@ var vi_default = {
1224
1227
  borderColor: "M\xE0u vi\u1EC1n",
1225
1228
  clearBorder: "X\xF3a vi\u1EC1n",
1226
1229
  formula: "C\xF4ng th\u1EE9c",
1230
+ numberFormat: "\u0110\u1ECBnh d\u1EA1ng s\u1ED1",
1231
+ formatText: "Ch\u1EEF",
1232
+ formatDate: "Ng\xE0y",
1227
1233
  apply: "\xC1p d\u1EE5ng",
1228
1234
  clear: "X\xF3a",
1229
1235
  recalculate: "T\xEDnh l\u1EA1i",
@@ -25993,6 +25999,10 @@ function getTableCellAttrs(cell, styles, defaultBackgroundColor) {
25993
25999
  if (borderAttrs.borderColor) attrs.borderColor = borderAttrs.borderColor;
25994
26000
  if (borderAttrs.borderStyle) attrs.borderStyle = borderAttrs.borderStyle;
25995
26001
  if (borderAttrs.borderWidth) attrs.borderWidth = borderAttrs.borderWidth;
26002
+ if (cell.getAttribute("data-cell-id")) attrs.cellId = cell.getAttribute("data-cell-id") ?? void 0;
26003
+ if (cell.getAttribute("data-number-format")) attrs.numberFormat = cell.getAttribute("data-number-format") ?? void 0;
26004
+ if (cell.getAttribute("data-formula")) attrs.formula = cell.getAttribute("data-formula") ?? void 0;
26005
+ if (cell.getAttribute("data-computed-value")) attrs.computedValue = cell.getAttribute("data-computed-value") ?? void 0;
25996
26006
  if (colspan > 1) attrs.colspan = colspan;
25997
26007
  if (rowspan > 1) attrs.rowspan = rowspan;
25998
26008
  if (colwidth) attrs.colwidth = colwidth;
@@ -27620,6 +27630,16 @@ var CodeBlockView = ({
27620
27630
  };
27621
27631
 
27622
27632
  // src/components/UEditor/extensions.ts
27633
+ function getFormulaStateAttributes(attributes) {
27634
+ const formula = attributes["data-formula"];
27635
+ if (!formula) {
27636
+ return {};
27637
+ }
27638
+ const computedValue = String(attributes["data-computed-value"] ?? "");
27639
+ return {
27640
+ "data-formula-state": computedValue.startsWith("#") ? "error" : "computed"
27641
+ };
27642
+ }
27623
27643
  var CustomTableCell = TableCell2.extend({
27624
27644
  addAttributes() {
27625
27645
  return {
@@ -27722,7 +27742,7 @@ var CustomTableCell = TableCell2.extend({
27722
27742
  mergedStyle = mergedStyle.replace(/^;/, "").trim();
27723
27743
  return [
27724
27744
  "td",
27725
- mergeAttributes5(this.options.HTMLAttributes, HTMLAttributes, mergedStyle ? { style: mergedStyle } : {}),
27745
+ mergeAttributes5(this.options.HTMLAttributes, HTMLAttributes, getFormulaStateAttributes(HTMLAttributes), mergedStyle ? { style: mergedStyle } : {}),
27726
27746
  0
27727
27747
  ];
27728
27748
  }
@@ -27829,7 +27849,7 @@ var CustomTableHeader = TableHeader2.extend({
27829
27849
  mergedStyle = mergedStyle.replace(/^;/, "").trim();
27830
27850
  return [
27831
27851
  "th",
27832
- mergeAttributes5(this.options.HTMLAttributes, HTMLAttributes, mergedStyle ? { style: mergedStyle } : {}),
27852
+ mergeAttributes5(this.options.HTMLAttributes, HTMLAttributes, getFormulaStateAttributes(HTMLAttributes), mergedStyle ? { style: mergedStyle } : {}),
27833
27853
  0
27834
27854
  ];
27835
27855
  }
@@ -29910,6 +29930,143 @@ function getTableCellRangeLabels(range) {
29910
29930
  function normalizeTableFormula(formula) {
29911
29931
  return formula.trim().replace(/^=/, "").trim();
29912
29932
  }
29933
+ function formatFormulaError(error) {
29934
+ return `#${error.toUpperCase()}`;
29935
+ }
29936
+ function normalizeTableNumberFormat(format) {
29937
+ return format === "text" || format === "number" || format === "currency" || format === "percent" || format === "date" ? format : "text";
29938
+ }
29939
+ function formatTableFormulaDisplayValue(value, numberFormat) {
29940
+ const stringValue = String(value);
29941
+ if (stringValue.startsWith("#")) {
29942
+ return stringValue;
29943
+ }
29944
+ const normalizedFormat = normalizeTableNumberFormat(numberFormat);
29945
+ if (normalizedFormat === "text") {
29946
+ return stringValue;
29947
+ }
29948
+ const numericValue = typeof value === "number" ? value : Number.parseFloat(stringValue.replace(/,/g, ""));
29949
+ if (!Number.isFinite(numericValue)) {
29950
+ return stringValue;
29951
+ }
29952
+ if (normalizedFormat === "number") {
29953
+ return new Intl.NumberFormat("en-US", { maximumFractionDigits: 6 }).format(numericValue);
29954
+ }
29955
+ if (normalizedFormat === "currency") {
29956
+ return new Intl.NumberFormat("en-US", {
29957
+ style: "currency",
29958
+ currency: "USD",
29959
+ maximumFractionDigits: 2
29960
+ }).format(numericValue);
29961
+ }
29962
+ if (normalizedFormat === "percent") {
29963
+ return new Intl.NumberFormat("en-US", {
29964
+ style: "percent",
29965
+ maximumFractionDigits: 2
29966
+ }).format(numericValue);
29967
+ }
29968
+ const excelEpochMs = Date.UTC(1899, 11, 30);
29969
+ const date = new Date(excelEpochMs + numericValue * 24 * 60 * 60 * 1e3);
29970
+ if (Number.isNaN(date.getTime())) {
29971
+ return stringValue;
29972
+ }
29973
+ return new Intl.DateTimeFormat("en-US", {
29974
+ year: "numeric",
29975
+ month: "2-digit",
29976
+ day: "2-digit",
29977
+ timeZone: "UTC"
29978
+ }).format(date);
29979
+ }
29980
+ function getTableFormulaReferences(formula) {
29981
+ const normalized = normalizeTableFormula(formula);
29982
+ if (!normalized) return [];
29983
+ const tokens = tokenizeFormula(normalized);
29984
+ if (!tokens) return [];
29985
+ const references = /* @__PURE__ */ new Set();
29986
+ for (const token of tokens) {
29987
+ if (token.type === "cell") {
29988
+ references.add(token.value);
29989
+ } else if (token.type === "range") {
29990
+ const range = parseTableCellRange(token.value);
29991
+ if (!range) continue;
29992
+ for (const label of getTableCellRangeLabels(range)) {
29993
+ references.add(label);
29994
+ }
29995
+ }
29996
+ }
29997
+ return Array.from(references);
29998
+ }
29999
+ function buildTableFormulaDependencyGraph(cells) {
30000
+ const dependencies = /* @__PURE__ */ new Map();
30001
+ const dependents = /* @__PURE__ */ new Map();
30002
+ const formulas = /* @__PURE__ */ new Map();
30003
+ for (const cell of cells) {
30004
+ const label = cell.label.toUpperCase();
30005
+ formulas.set(label, cell.formula);
30006
+ dependencies.set(label, new Set(getTableFormulaReferences(cell.formula)));
30007
+ if (!dependents.has(label)) {
30008
+ dependents.set(label, /* @__PURE__ */ new Set());
30009
+ }
30010
+ }
30011
+ for (const [label, refs] of dependencies) {
30012
+ for (const ref of refs) {
30013
+ if (!dependents.has(ref)) {
30014
+ dependents.set(ref, /* @__PURE__ */ new Set());
30015
+ }
30016
+ dependents.get(ref)?.add(label);
30017
+ }
30018
+ }
30019
+ return { dependencies, dependents, formulas };
30020
+ }
30021
+ function getTableFormulaCircularReferences(graph) {
30022
+ const visiting = /* @__PURE__ */ new Set();
30023
+ const visited = /* @__PURE__ */ new Set();
30024
+ const circular = /* @__PURE__ */ new Set();
30025
+ const stack = [];
30026
+ const visit = (label) => {
30027
+ if (visiting.has(label)) {
30028
+ const start = stack.indexOf(label);
30029
+ for (const cycleLabel of start >= 0 ? stack.slice(start) : [label]) {
30030
+ circular.add(cycleLabel);
30031
+ }
30032
+ return;
30033
+ }
30034
+ if (visited.has(label)) return;
30035
+ visiting.add(label);
30036
+ stack.push(label);
30037
+ for (const ref of graph.dependencies.get(label) ?? []) {
30038
+ if (graph.formulas.has(ref)) {
30039
+ visit(ref);
30040
+ }
30041
+ }
30042
+ stack.pop();
30043
+ visiting.delete(label);
30044
+ visited.add(label);
30045
+ };
30046
+ for (const label of graph.formulas.keys()) {
30047
+ visit(label);
30048
+ }
30049
+ return circular;
30050
+ }
30051
+ function getTableFormulaRecalculationOrder(graph) {
30052
+ const circular = getTableFormulaCircularReferences(graph);
30053
+ const visited = /* @__PURE__ */ new Set();
30054
+ const order = [];
30055
+ const visit = (label) => {
30056
+ if (visited.has(label) || circular.has(label)) return;
30057
+ visited.add(label);
30058
+ for (const ref of graph.dependencies.get(label) ?? []) {
30059
+ if (graph.formulas.has(ref)) {
30060
+ visit(ref);
30061
+ }
30062
+ }
30063
+ order.push(label);
30064
+ };
30065
+ for (const label of graph.formulas.keys()) {
30066
+ visit(label);
30067
+ }
30068
+ return { order, circular };
30069
+ }
29913
30070
  function evaluateBasicTableFormula(formula, getCellValue) {
29914
30071
  const normalized = normalizeTableFormula(formula);
29915
30072
  if (!normalized) {
@@ -30114,6 +30271,7 @@ var FormulaParser = class {
30114
30271
  };
30115
30272
 
30116
30273
  // src/components/UEditor/table-formula-commands.ts
30274
+ var UEDITOR_TABLE_FORMULA_RECALCULATE_META = "ueditorTableFormulaRecalculate";
30117
30275
  function collectChildren2(node) {
30118
30276
  const children = [];
30119
30277
  node.forEach((child) => children.push(child));
@@ -30144,6 +30302,13 @@ function safeFindCell2(map, relativePos) {
30144
30302
  function getCellText(cellNode) {
30145
30303
  return cellNode.textBetween(0, cellNode.content.size, "\n").trim();
30146
30304
  }
30305
+ function createCellDisplayContent(cellNode, displayValue) {
30306
+ const paragraphType = cellNode.type.schema.nodes.paragraph;
30307
+ if (!paragraphType || !displayValue) {
30308
+ return paragraphType ? [paragraphType.create()] : cellNode.content;
30309
+ }
30310
+ return [paragraphType.create(null, cellNode.type.schema.text(displayValue))];
30311
+ }
30147
30312
  function buildTableValueGetter(tableNode) {
30148
30313
  const map = TableMap2.get(tableNode);
30149
30314
  const values = /* @__PURE__ */ new Map();
@@ -30158,6 +30323,20 @@ function buildTableValueGetter(tableNode) {
30158
30323
  }
30159
30324
  return (label) => values.get(label.toUpperCase());
30160
30325
  }
30326
+ function buildTableValueMap(tableNode) {
30327
+ const map = TableMap2.get(tableNode);
30328
+ const values = /* @__PURE__ */ new Map();
30329
+ for (const rowInfo of getTableRows2(tableNode)) {
30330
+ for (const entry of rowInfo.cells) {
30331
+ const rect = safeFindCell2(map, entry.relativePos);
30332
+ if (!rect) continue;
30333
+ const label = `${indexToColumnName(rect.left)}${rect.top + 1}`;
30334
+ const computedValue = entry.node.attrs.computedValue;
30335
+ values.set(label, typeof computedValue === "string" && computedValue.trim() ? computedValue : getCellText(entry.node));
30336
+ }
30337
+ }
30338
+ return values;
30339
+ }
30161
30340
  function getFormulaComputedValue(formula, tableNode) {
30162
30341
  const result = evaluateBasicTableFormula(formula, buildTableValueGetter(tableNode));
30163
30342
  return result.error ? `#${result.error.toUpperCase()}` : String(result.value);
@@ -30194,37 +30373,143 @@ function setSelectedTableCellFormula(editor, formula) {
30194
30373
  function clearSelectedTableCellFormula(editor) {
30195
30374
  return setSelectedTableCellFormula(editor, "");
30196
30375
  }
30197
- function recalculateSelectedTable(editor) {
30198
- const rect = selectedRect2(editor.state);
30199
- const tableNode = rect.table;
30200
- const map = TableMap2.get(tableNode);
30201
- const getCellValue = buildTableValueGetter(tableNode);
30376
+ function setSelectedTableCellNumberFormat(editor, numberFormat) {
30377
+ const value = numberFormat && numberFormat !== "text" ? numberFormat : null;
30378
+ const { state, view } = editor;
30379
+ const applied = setCellAttr("numberFormat", value)(state, view.dispatch.bind(view));
30380
+ if (!applied) return false;
30381
+ recalculateSelectedTable(editor);
30382
+ view.focus();
30383
+ dispatchTableLayoutChange(editor);
30384
+ return true;
30385
+ }
30386
+ function promoteFormulaTextInTableNode(tableNode) {
30202
30387
  let changed = false;
30203
30388
  const rows = getTableRows2(tableNode).map((rowInfo) => {
30204
30389
  const cells = collectChildren2(rowInfo.node);
30390
+ for (const entry of rowInfo.cells) {
30391
+ const text = getCellText(entry.node);
30392
+ const formula = text.startsWith("=") ? normalizeFormulaInput(text) : "";
30393
+ if (!formula || entry.node.attrs.formula === formula) continue;
30394
+ cells[entry.index] = entry.node.type.create(
30395
+ {
30396
+ ...entry.node.attrs,
30397
+ formula,
30398
+ computedValue: null
30399
+ },
30400
+ entry.node.content,
30401
+ entry.node.marks
30402
+ );
30403
+ changed = true;
30404
+ }
30405
+ return rowInfo.node.type.create(rowInfo.node.attrs, cells);
30406
+ });
30407
+ return {
30408
+ tableNode: changed ? tableNode.type.create(tableNode.attrs, rows) : tableNode,
30409
+ changed
30410
+ };
30411
+ }
30412
+ function recalculateTableNode(tableNode) {
30413
+ const promoted = promoteFormulaTextInTableNode(tableNode);
30414
+ tableNode = promoted.tableNode;
30415
+ const map = TableMap2.get(tableNode);
30416
+ const values = buildTableValueMap(tableNode);
30417
+ const formulaEntries = /* @__PURE__ */ new Map();
30418
+ let changed = false;
30419
+ const rowInfos = getTableRows2(tableNode);
30420
+ for (const [rowIndex, rowInfo] of rowInfos.entries()) {
30205
30421
  for (const entry of rowInfo.cells) {
30206
30422
  const formula = typeof entry.node.attrs.formula === "string" ? entry.node.attrs.formula.trim() : "";
30207
30423
  if (!formula) continue;
30208
30424
  const rectForCell = safeFindCell2(map, entry.relativePos);
30209
30425
  if (!rectForCell) continue;
30210
- const result = evaluateBasicTableFormula(formula, getCellValue);
30211
- const computedValue = result.error ? `#${result.error.toUpperCase()}` : String(result.value);
30212
- if (entry.node.attrs.computedValue === computedValue) continue;
30426
+ const label = `${indexToColumnName(rectForCell.left)}${rectForCell.top + 1}`;
30427
+ formulaEntries.set(label, {
30428
+ rowIndex,
30429
+ cellIndex: entry.index,
30430
+ node: entry.node,
30431
+ formula
30432
+ });
30433
+ }
30434
+ }
30435
+ const graph = buildTableFormulaDependencyGraph(
30436
+ Array.from(formulaEntries, ([label, entry]) => ({
30437
+ label,
30438
+ formula: entry.formula
30439
+ }))
30440
+ );
30441
+ const { order, circular } = getTableFormulaRecalculationOrder(graph);
30442
+ const computedValues = /* @__PURE__ */ new Map();
30443
+ const getCellValue = (label) => values.get(label.toUpperCase());
30444
+ for (const label of circular) {
30445
+ computedValues.set(label, formatFormulaError("circular-reference"));
30446
+ values.set(label, formatFormulaError("circular-reference"));
30447
+ }
30448
+ for (const label of order) {
30449
+ const entry = formulaEntries.get(label);
30450
+ if (!entry) continue;
30451
+ const result = evaluateBasicTableFormula(entry.formula, getCellValue);
30452
+ const computedValue = result.error ? formatFormulaError(result.error) : String(result.value);
30453
+ computedValues.set(label, computedValue);
30454
+ values.set(label, computedValue);
30455
+ }
30456
+ const rows = rowInfos.map((rowInfo) => {
30457
+ const cells = collectChildren2(rowInfo.node);
30458
+ for (const entry of rowInfo.cells) {
30459
+ const rectForCell = safeFindCell2(map, entry.relativePos);
30460
+ if (!rectForCell) continue;
30461
+ const label = `${indexToColumnName(rectForCell.left)}${rectForCell.top + 1}`;
30462
+ const computedValue = computedValues.get(label);
30463
+ if (computedValue == null) continue;
30464
+ const displayValue = formatTableFormulaDisplayValue(computedValue, entry.node.attrs.numberFormat);
30465
+ const contentMatchesComputedValue = getCellText(entry.node) === displayValue;
30466
+ if (entry.node.attrs.computedValue === computedValue && contentMatchesComputedValue) continue;
30213
30467
  cells[entry.index] = entry.node.type.create(
30214
30468
  {
30215
30469
  ...entry.node.attrs,
30216
30470
  computedValue
30217
30471
  },
30218
- entry.node.content,
30472
+ createCellDisplayContent(entry.node, displayValue),
30219
30473
  entry.node.marks
30220
30474
  );
30221
30475
  changed = true;
30222
30476
  }
30223
30477
  return rowInfo.node.type.create(rowInfo.node.attrs, cells);
30224
30478
  });
30225
- if (!changed) return false;
30226
- const nextTable = tableNode.type.create(tableNode.attrs, rows);
30227
- editor.view.dispatch(editor.state.tr.replaceWith(rect.tableStart - 1, rect.tableStart - 1 + tableNode.nodeSize, nextTable));
30479
+ if (!changed) return promoted.changed ? tableNode : null;
30480
+ return tableNode.type.create(tableNode.attrs, rows);
30481
+ }
30482
+ function recalculateSelectedTable(editor) {
30483
+ const rect = selectedRect2(editor.state);
30484
+ const tableNode = rect.table;
30485
+ const nextTable = recalculateTableNode(tableNode);
30486
+ if (!nextTable) return false;
30487
+ editor.view.dispatch(
30488
+ editor.state.tr.replaceWith(rect.tableStart - 1, rect.tableStart - 1 + tableNode.nodeSize, nextTable).setMeta(UEDITOR_TABLE_FORMULA_RECALCULATE_META, true)
30489
+ );
30490
+ dispatchTableLayoutChange(editor);
30491
+ return true;
30492
+ }
30493
+ function recalculateAllTableFormulas(editor) {
30494
+ const replacements = [];
30495
+ editor.state.doc.descendants((node, pos) => {
30496
+ if (node.type.name !== "table") return true;
30497
+ const nextTable = recalculateTableNode(node);
30498
+ if (nextTable) {
30499
+ replacements.push({
30500
+ from: pos,
30501
+ to: pos + node.nodeSize,
30502
+ node: nextTable
30503
+ });
30504
+ }
30505
+ return false;
30506
+ });
30507
+ if (replacements.length === 0) return false;
30508
+ let tr = editor.state.tr;
30509
+ for (const replacement of replacements.reverse()) {
30510
+ tr = tr.replaceWith(replacement.from, replacement.to, replacement.node);
30511
+ }
30512
+ editor.view.dispatch(tr.setMeta(UEDITOR_TABLE_FORMULA_RECALCULATE_META, true));
30228
30513
  dispatchTableLayoutChange(editor);
30229
30514
  return true;
30230
30515
  }
@@ -30273,6 +30558,7 @@ var BubbleMenuContent = ({
30273
30558
  const currentHighlightColor = normalizeStyleValue(editor.getAttributes("highlight").color) || "";
30274
30559
  const currentCellBgColor = normalizeStyleValue(editor.getAttributes("tableCell").backgroundColor || editor.getAttributes("tableHeader").backgroundColor) || "";
30275
30560
  const currentCellFormula = normalizeStyleValue(editor.getAttributes("tableCell").formula || editor.getAttributes("tableHeader").formula) || "";
30561
+ const currentCellNumberFormat = normalizeStyleValue(editor.getAttributes("tableCell").numberFormat || editor.getAttributes("tableHeader").numberFormat) || "text";
30276
30562
  const isInTable2 = isSelectionInTable(editor.state);
30277
30563
  const canMergeCells = isInTable2 && editor.can().mergeCells();
30278
30564
  const canSplitCell = isInTable2 && editor.can().splitCell();
@@ -30532,6 +30818,28 @@ var BubbleMenuContent = ({
30532
30818
  className: "h-full min-w-0 flex-1 bg-transparent px-2 text-sm font-medium text-foreground outline-none"
30533
30819
  }
30534
30820
  ) }),
30821
+ /* @__PURE__ */ jsxs72("div", { className: "mt-2", children: [
30822
+ /* @__PURE__ */ jsx86("div", { className: "mb-1 px-1 text-[11px] font-medium text-muted-foreground", children: t("tableMenu.numberFormat") || "Number format" }),
30823
+ /* @__PURE__ */ jsx86("div", { className: "grid grid-cols-5 gap-1", children: [
30824
+ ["text", "Text"],
30825
+ ["number", "123"],
30826
+ ["currency", "$"],
30827
+ ["percent", "%"],
30828
+ ["date", "Date"]
30829
+ ].map(([format, label]) => /* @__PURE__ */ jsx86(
30830
+ "button",
30831
+ {
30832
+ type: "button",
30833
+ onClick: () => setSelectedTableCellNumberFormat(editor, format),
30834
+ className: cn(
30835
+ "h-8 rounded-md text-[11px] font-semibold transition-colors hover:bg-muted",
30836
+ currentCellNumberFormat === format || format === "text" && !currentCellNumberFormat ? "bg-primary/10 text-primary" : "bg-muted/40 text-foreground"
30837
+ ),
30838
+ children: format === "text" ? t("tableMenu.formatText") || label : format === "date" ? t("tableMenu.formatDate") || label : label
30839
+ },
30840
+ format
30841
+ )) })
30842
+ ] }),
30535
30843
  /* @__PURE__ */ jsxs72("div", { className: "mt-2 grid grid-cols-3 gap-1", children: [
30536
30844
  /* @__PURE__ */ jsx86(
30537
30845
  "button",
@@ -38261,6 +38569,7 @@ var UEditor = React82.forwardRef(({
38261
38569
  const effectivePlaceholder = placeholder ?? t("placeholder");
38262
38570
  const inFlightPrepareRef = useRef37(null);
38263
38571
  const lastAppliedContentRef = useRef37(content ?? "");
38572
+ const scheduledFormulaRecalculateRef = useRef37(false);
38264
38573
  const resolvedUploadFile = useMemo24(() => {
38265
38574
  if (uploadFile) return uploadFile;
38266
38575
  if (uploadFileForSave) {
@@ -38324,7 +38633,16 @@ var UEditor = React82.forwardRef(({
38324
38633
  class: UEDITOR_PROSEMIRROR_CLASS_NAME
38325
38634
  }
38326
38635
  },
38327
- onUpdate: ({ editor: editor2 }) => {
38636
+ onUpdate: ({ editor: editor2, transaction }) => {
38637
+ if (!transaction.getMeta(UEDITOR_TABLE_FORMULA_RECALCULATE_META) && !scheduledFormulaRecalculateRef.current) {
38638
+ scheduledFormulaRecalculateRef.current = true;
38639
+ queueMicrotask(() => {
38640
+ scheduledFormulaRecalculateRef.current = false;
38641
+ if (!editor2.isDestroyed) {
38642
+ recalculateAllTableFormulas(editor2);
38643
+ }
38644
+ });
38645
+ }
38328
38646
  const html = editor2.getHTML();
38329
38647
  onChange?.(html);
38330
38648
  onHtmlChange?.(html);
@@ -38362,6 +38680,14 @@ var UEditor = React82.forwardRef(({
38362
38680
  }),
38363
38681
  [content, editor, uploadImageForSave, uploadFileForSave, uploadImageConcurrency]
38364
38682
  );
38683
+ useEffect38(() => {
38684
+ if (!editor) return;
38685
+ queueMicrotask(() => {
38686
+ if (!editor.isDestroyed) {
38687
+ recalculateAllTableFormulas(editor);
38688
+ }
38689
+ });
38690
+ }, [editor]);
38365
38691
  useEffect38(() => {
38366
38692
  if (!editor) return;
38367
38693
  const nextContent = content ?? "";
@@ -38371,6 +38697,11 @@ var UEditor = React82.forwardRef(({
38371
38697
  Promise.resolve().then(() => {
38372
38698
  if (!editor.isDestroyed) {
38373
38699
  editor.commands.setContent(nextContent, { emitUpdate: false });
38700
+ queueMicrotask(() => {
38701
+ if (!editor.isDestroyed) {
38702
+ recalculateAllTableFormulas(editor);
38703
+ }
38704
+ });
38374
38705
  }
38375
38706
  });
38376
38707
  }