@underverse-ui/underverse 1.0.185 → 1.0.186

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
@@ -42384,6 +42384,9 @@ function getFormulaEditingTableContext(view) {
42384
42384
  if (!tableNode || tableNode.type.name !== "table") return null;
42385
42385
  const tableDom = cellDom.closest("table");
42386
42386
  if (!(tableDom instanceof HTMLTableElement)) return null;
42387
+ const tableMap = TableMap5.get(tableNode);
42388
+ const tableStart = $from.start(tableDepth);
42389
+ const formulaCellRect = tableMap.findCell(cellPos - tableStart);
42387
42390
  return {
42388
42391
  cellContentEnd: $from.end(depth),
42389
42392
  cellContentStart: $from.start(depth),
@@ -42391,11 +42394,50 @@ function getFormulaEditingTableContext(view) {
42391
42394
  formula: getCellText2(node),
42392
42395
  tableDom,
42393
42396
  tableNode,
42394
- tablePos: $from.before(tableDepth)
42397
+ tablePos: $from.before(tableDepth),
42398
+ formulaCellLabel: `${indexToColumnName(formulaCellRect.left)}${formulaCellRect.top + 1}`
42395
42399
  };
42396
42400
  }
42397
42401
  return null;
42398
42402
  }
42403
+ function collectTableFormulaCells(tableNode) {
42404
+ const tableMap = TableMap5.get(tableNode);
42405
+ const formulas = [];
42406
+ tableNode.forEach((rowNode, rowOffset) => {
42407
+ rowNode.forEach((cellNode, cellOffset) => {
42408
+ const formula = typeof cellNode.attrs.formula === "string" ? cellNode.attrs.formula.trim() : "";
42409
+ if (!formula) return;
42410
+ const rect = tableMap.findCell(rowOffset + 1 + cellOffset);
42411
+ formulas.push({
42412
+ label: `${indexToColumnName(rect.left)}${rect.top + 1}`,
42413
+ formula
42414
+ });
42415
+ });
42416
+ });
42417
+ return formulas;
42418
+ }
42419
+ function getFormulaCycleBlockedLabels(tableNode, formulaCellLabel) {
42420
+ const graph = buildTableFormulaDependencyGraph(collectTableFormulaCells(tableNode));
42421
+ const blocked = /* @__PURE__ */ new Set();
42422
+ const queue = [formulaCellLabel.toUpperCase()];
42423
+ for (let index = 0; index < queue.length; index += 1) {
42424
+ const label = queue[index];
42425
+ if (!label || blocked.has(label)) continue;
42426
+ blocked.add(label);
42427
+ for (const dependent of graph.dependents.get(label) ?? []) {
42428
+ if (!blocked.has(dependent)) queue.push(dependent);
42429
+ }
42430
+ }
42431
+ return blocked;
42432
+ }
42433
+ function getReferenceLabels(reference) {
42434
+ const range = parseTableCellRange(reference);
42435
+ return range ? getTableCellRangeLabels(range) : [reference.toUpperCase()];
42436
+ }
42437
+ function isBlockedFormulaReference(tableNode, formulaCellLabel, reference) {
42438
+ const blockedLabels = getFormulaCycleBlockedLabels(tableNode, formulaCellLabel);
42439
+ return getReferenceLabels(reference).some((label) => blockedLabels.has(label));
42440
+ }
42399
42441
  function cancelFormulaEditing(view) {
42400
42442
  const context = getFormulaEditingTableContext(view);
42401
42443
  if (!context) return false;
@@ -42459,10 +42501,20 @@ function normalizeFormulaRangeLabel(fromLabel, toLabel) {
42459
42501
  return fromLabel === toLabel ? fromLabel : `${fromLabel}:${toLabel}`;
42460
42502
  }
42461
42503
  function replacePickedLabel(view, pickState, nextLabel, currentCell) {
42462
- if (nextLabel === pickState.currentLabel && currentCell === pickState.currentCell) return pickState;
42504
+ const formulaContext = getFormulaEditingTableContext(view);
42505
+ const blocked = formulaContext ? isBlockedFormulaReference(formulaContext.tableNode, pickState.formulaCellLabel, nextLabel) : false;
42506
+ if (blocked) {
42507
+ return {
42508
+ ...pickState,
42509
+ blocked: true,
42510
+ currentCell
42511
+ };
42512
+ }
42513
+ if (nextLabel === pickState.currentLabel && currentCell === pickState.currentCell && !pickState.blocked) return pickState;
42463
42514
  if (nextLabel === pickState.currentLabel) {
42464
42515
  return {
42465
42516
  ...pickState,
42517
+ blocked: false,
42466
42518
  currentCell
42467
42519
  };
42468
42520
  }
@@ -42472,6 +42524,7 @@ function replacePickedLabel(view, pickState, nextLabel, currentCell) {
42472
42524
  view.dispatch(tr);
42473
42525
  return {
42474
42526
  ...pickState,
42527
+ blocked: false,
42475
42528
  insertedTo: nextTo,
42476
42529
  currentLabel: nextLabel,
42477
42530
  currentCell
@@ -42483,6 +42536,22 @@ function beginFormulaRangePick(view, event) {
42483
42536
  if (!formulaCell) return null;
42484
42537
  const picked = getFormulaTableCellInfo(view, event.target, formulaCell.tablePos);
42485
42538
  if (!picked || picked.cell === formulaCell.cellDom) return null;
42539
+ const blocked = isBlockedFormulaReference(formulaCell.tableNode, formulaCell.formulaCellLabel, picked.label);
42540
+ if (blocked) {
42541
+ event.preventDefault();
42542
+ event.stopPropagation();
42543
+ return {
42544
+ anchorLabel: picked.label,
42545
+ anchorCell: picked.cell,
42546
+ tablePos: formulaCell.tablePos,
42547
+ insertedFrom: view.state.selection.from,
42548
+ insertedTo: view.state.selection.from,
42549
+ currentLabel: "",
42550
+ currentCell: picked.cell,
42551
+ blocked: true,
42552
+ formulaCellLabel: formulaCell.formulaCellLabel
42553
+ };
42554
+ }
42486
42555
  const { from, to } = view.state.selection;
42487
42556
  const prefix = from === to ? getReferenceInsertionPrefix(view, formulaCell.cellContentStart, from) : "";
42488
42557
  const insertedText = `${prefix}${picked.label}`;
@@ -42500,7 +42569,9 @@ function beginFormulaRangePick(view, event) {
42500
42569
  insertedFrom,
42501
42570
  insertedTo: insertedFrom + picked.label.length,
42502
42571
  currentLabel: picked.label,
42503
- currentCell: picked.cell
42572
+ currentCell: picked.cell,
42573
+ blocked: false,
42574
+ formulaCellLabel: formulaCell.formulaCellLabel
42504
42575
  };
42505
42576
  }
42506
42577
  function updateFormulaRangePick(view, pickState, event) {
@@ -42528,7 +42599,8 @@ function getFormulaRangePickHighlight(container, pickState) {
42528
42599
  left,
42529
42600
  top,
42530
42601
  width: Math.max(0, right - left),
42531
- height: Math.max(0, bottom - top)
42602
+ height: Math.max(0, bottom - top),
42603
+ blocked: pickState.blocked
42532
42604
  };
42533
42605
  }
42534
42606
 
@@ -42552,6 +42624,12 @@ function createReferenceHighlight(label) {
42552
42624
  element.className = "pointer-events-none absolute z-[21] rounded-[2px] border-2 border-emerald-500 bg-emerald-500/15";
42553
42625
  return element;
42554
42626
  }
42627
+ function createBlockedReferenceHighlight(label) {
42628
+ const element = document.createElement("span");
42629
+ element.dataset.ueditorFormulaBlockedReference = label;
42630
+ element.className = "pointer-events-none absolute z-[22] rounded-[2px] border-2 border-destructive/80 bg-destructive/10";
42631
+ return element;
42632
+ }
42555
42633
  function useFormulaCoordinateOverlay(editor, containerRef, labels) {
42556
42634
  const overlayRef = useRef37(null);
42557
42635
  useEffect39(() => {
@@ -42563,6 +42641,7 @@ function useFormulaCoordinateOverlay(editor, containerRef, labels) {
42563
42641
  let activeTable = null;
42564
42642
  let activeTablePos = null;
42565
42643
  let hoverLabel = null;
42644
+ const scrollListenerOptions = { passive: true, capture: true };
42566
42645
  const clearOverlay = () => {
42567
42646
  activeTable = null;
42568
42647
  activeTablePos = null;
@@ -42622,10 +42701,12 @@ function useFormulaCoordinateOverlay(editor, containerRef, labels) {
42622
42701
  actions.dataset.ueditorFormulaActions = "";
42623
42702
  actions.className = "pointer-events-auto absolute z-50 flex items-center gap-1 rounded-md border border-border bg-background p-1 shadow-md";
42624
42703
  const formulaCellRect = context.cellDom.getBoundingClientRect();
42704
+ const formulaActionsHeight = 34;
42705
+ const formulaActionsTop = formulaCellRect.bottom + 4 + formulaActionsHeight > tableRect.bottom ? Math.max(containerRect.top + 4, formulaCellRect.top - formulaActionsHeight - 4) : formulaCellRect.bottom + 4;
42625
42706
  setPosition(
42626
42707
  actions,
42627
42708
  formulaCellRect.left - containerRect.left + container.scrollLeft,
42628
- formulaCellRect.bottom - containerRect.top + container.scrollTop + 4
42709
+ formulaActionsTop - containerRect.top + container.scrollTop
42629
42710
  );
42630
42711
  const applyButton = document.createElement("button");
42631
42712
  applyButton.type = "button";
@@ -42677,10 +42758,12 @@ function useFormulaCoordinateOverlay(editor, containerRef, labels) {
42677
42758
  children.push(label);
42678
42759
  }
42679
42760
  const references = new Set(getTableFormulaReferences(context.formula));
42761
+ const blockedReferences = getFormulaCycleBlockedLabels(context.tableNode, context.formulaCellLabel);
42680
42762
  for (const info of cellInfos) {
42681
- if (!info || !references.has(info.label)) continue;
42763
+ if (!info) continue;
42682
42764
  const cellRect = info.cell.getBoundingClientRect();
42683
- const highlight = createReferenceHighlight(info.label);
42765
+ const highlight = info.label !== context.formulaCellLabel && blockedReferences.has(info.label) ? createBlockedReferenceHighlight(info.label) : references.has(info.label) ? createReferenceHighlight(info.label) : null;
42766
+ if (!highlight) continue;
42684
42767
  setPosition(
42685
42768
  highlight,
42686
42769
  cellRect.left - containerRect.left + container.scrollLeft + 2,
@@ -42735,6 +42818,7 @@ function useFormulaCoordinateOverlay(editor, containerRef, labels) {
42735
42818
  editor.view.dom.addEventListener("mousemove", handleMouseMove2);
42736
42819
  editor.view.dom.addEventListener("mouseleave", handleMouseLeave2);
42737
42820
  container.addEventListener(UEDITOR_TABLE_LAYOUT_CHANGE_EVENT, scheduleSync);
42821
+ container.addEventListener("scroll", scheduleSync, scrollListenerOptions);
42738
42822
  window.addEventListener("resize", scheduleSync);
42739
42823
  scheduleSync();
42740
42824
  return () => {
@@ -42745,6 +42829,7 @@ function useFormulaCoordinateOverlay(editor, containerRef, labels) {
42745
42829
  editor.view.dom.removeEventListener("mousemove", handleMouseMove2);
42746
42830
  editor.view.dom.removeEventListener("mouseleave", handleMouseLeave2);
42747
42831
  container.removeEventListener(UEDITOR_TABLE_LAYOUT_CHANGE_EVENT, scheduleSync);
42832
+ container.removeEventListener("scroll", scheduleSync, scrollListenerOptions);
42748
42833
  window.removeEventListener("resize", scheduleSync);
42749
42834
  if (animationFrame != null) window.cancelAnimationFrame(animationFrame);
42750
42835
  clearOverlay();
@@ -44191,7 +44276,7 @@ var UEditor = React88.forwardRef(({
44191
44276
  {
44192
44277
  ref: formulaCoordinateOverlayRef,
44193
44278
  "data-ueditor-formula-coordinate-overlay": "",
44194
- className: "pointer-events-none absolute inset-0 z-[21] hidden overflow-visible"
44279
+ className: "pointer-events-none absolute inset-0 z-[35] hidden overflow-visible"
44195
44280
  }
44196
44281
  ),
44197
44282
  formulaRangeHighlight && /* @__PURE__ */ jsx100(
@@ -44199,7 +44284,11 @@ var UEditor = React88.forwardRef(({
44199
44284
  {
44200
44285
  "aria-hidden": "true",
44201
44286
  "data-ueditor-formula-range-highlight": "",
44202
- className: "pointer-events-none absolute z-20 rounded-[2px] border-2 border-primary bg-primary/10",
44287
+ "data-ueditor-formula-range-blocked": formulaRangeHighlight.blocked ? "true" : void 0,
44288
+ className: cn(
44289
+ "pointer-events-none absolute z-20 rounded-[2px] border-2",
44290
+ formulaRangeHighlight.blocked ? "border-destructive bg-destructive/15" : "border-primary bg-primary/10"
44291
+ ),
44203
44292
  style: {
44204
44293
  left: formulaRangeHighlight.left,
44205
44294
  top: formulaRangeHighlight.top,