@cj-tech-master/excelts 5.1.0 → 5.1.1

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.
@@ -283,6 +283,10 @@ declare class Worksheet {
283
283
  mergeCellsWithoutStyle(...cells: RangeInput[]): void;
284
284
  _mergeCellsInternal(dimensions: Range, ignoreStyle?: boolean): void;
285
285
  _unMergeMaster(master: Cell): void;
286
+ /**
287
+ * Update _merges dictionary and cell-level merge references after a row or column splice.
288
+ */
289
+ private _spliceMerges;
286
290
  get hasMerges(): boolean;
287
291
  /**
288
292
  * Scan the range and if any cell is part of a merge, un-merge the group.
@@ -245,6 +245,19 @@ class Worksheet {
245
245
  * the rows will still be shifted as if the values existed
246
246
  */
247
247
  spliceColumns(start, count, ...inserts) {
248
+ // Before splicing cells, release all cell-level merge references so that
249
+ // row.splice copies plain values instead of merge proxies.
250
+ // _spliceMerges (called later) will rebuild cell-level refs at new coordinates.
251
+ for (const merge of Object.values(this._merges)) {
252
+ for (let r = merge.top; r <= merge.bottom; r++) {
253
+ for (let c = merge.left; c <= merge.right; c++) {
254
+ const cell = this.findCell(r, c);
255
+ if (cell && cell.type === Enums.ValueType.Merge) {
256
+ cell.unmerge();
257
+ }
258
+ }
259
+ }
260
+ }
248
261
  const rows = this._rows;
249
262
  const nRows = rows.length;
250
263
  if (inserts.length > 0) {
@@ -296,6 +309,8 @@ class Worksheet {
296
309
  }
297
310
  }
298
311
  }
312
+ // account for merges
313
+ this._spliceMerges("col", start, count, inserts.length);
299
314
  }
300
315
  /**
301
316
  * Get the last column in a worksheet
@@ -469,6 +484,14 @@ class Worksheet {
469
484
  // either inserting new or overwriting existing rows
470
485
  const rSrc = this._rows[rowNum - 1];
471
486
  const inserts = Array.from({ length: count }).fill(rSrc.values);
487
+ // Collect single-row merges from the source row before splicing
488
+ // (only merges where top == bottom == rowNum, i.e. horizontal merges within one row)
489
+ const srcMerges = [];
490
+ for (const merge of Object.values(this._merges)) {
491
+ if (merge.top === rowNum && merge.bottom === rowNum) {
492
+ srcMerges.push(merge);
493
+ }
494
+ }
472
495
  this.spliceRows(rowNum + 1, insert ? 0 : count, ...inserts);
473
496
  // now copy styles...
474
497
  for (let i = 0; i < count; i++) {
@@ -479,6 +502,27 @@ class Worksheet {
479
502
  rDst.getCell(colNumber).style = cell.style;
480
503
  });
481
504
  }
505
+ // Duplicate single-row merges from source row into each new row
506
+ if (srcMerges.length > 0) {
507
+ for (let i = 0; i < count; i++) {
508
+ const dstRow = rowNum + 1 + i;
509
+ // In overwrite mode, clear any existing merges in the target row
510
+ if (!insert) {
511
+ const toRemove = [];
512
+ for (const [key, merge] of Object.entries(this._merges)) {
513
+ if (merge.top <= dstRow && merge.bottom >= dstRow) {
514
+ toRemove.push(key);
515
+ }
516
+ }
517
+ for (const key of toRemove) {
518
+ this._unMergeMaster(this.getCell(key));
519
+ }
520
+ }
521
+ for (const srcMerge of srcMerges) {
522
+ this.mergeCellsWithoutStyle(dstRow, srcMerge.left, dstRow, srcMerge.right);
523
+ }
524
+ }
525
+ }
482
526
  }
483
527
  /**
484
528
  * Cut one or more rows (rows below are shifted up)
@@ -488,6 +532,19 @@ class Worksheet {
488
532
  */
489
533
  spliceRows(start, count, ...inserts) {
490
534
  // same problem as row.splice, except worse.
535
+ // Before splicing rows, release all cell-level merge references so that
536
+ // row value copies work on plain values instead of merge proxies.
537
+ // _spliceMerges (called later) will rebuild cell-level refs at new coordinates.
538
+ for (const merge of Object.values(this._merges)) {
539
+ for (let r = merge.top; r <= merge.bottom; r++) {
540
+ for (let c = merge.left; c <= merge.right; c++) {
541
+ const cell = this.findCell(r, c);
542
+ if (cell && cell.type === Enums.ValueType.Merge) {
543
+ cell.unmerge();
544
+ }
545
+ }
546
+ }
547
+ }
491
548
  const nKeep = start + count;
492
549
  const nInserts = inserts.length;
493
550
  const nExpand = nInserts - count;
@@ -527,13 +584,6 @@ class Worksheet {
527
584
  rDst.height = rSrc.height;
528
585
  rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
529
586
  rDst.getCell(colNumber).style = cell.style;
530
- // remerge cells accounting for insert offset
531
- if (cell.type === Enums.ValueType.Merge) {
532
- const cellToBeMerged = this.getRow(cell.row + nInserts).getCell(colNumber);
533
- const prevMaster = cell.master;
534
- const newMaster = this.getRow(prevMaster.row + nInserts).getCell(prevMaster.col);
535
- cellToBeMerged.merge(newMaster);
536
- }
537
587
  });
538
588
  }
539
589
  else {
@@ -563,6 +613,8 @@ class Worksheet {
563
613
  }
564
614
  }
565
615
  }
616
+ // account for merges
617
+ this._spliceMerges("row", start, count, nInserts);
566
618
  }
567
619
  eachRow(optOrCallback, maybeCallback) {
568
620
  let options;
@@ -669,6 +721,102 @@ class Worksheet {
669
721
  delete this._merges[master.address];
670
722
  }
671
723
  }
724
+ /**
725
+ * Update _merges dictionary and cell-level merge references after a row or column splice.
726
+ */
727
+ _spliceMerges(axis, start, count, nInserts) {
728
+ const nExpand = nInserts - count;
729
+ if (nExpand === 0 && count === 0) {
730
+ return;
731
+ }
732
+ const nKeep = start + count;
733
+ const isRow = axis === "row";
734
+ const newMerges = {};
735
+ for (const merge of Object.values(this._merges)) {
736
+ const { top, left, bottom, right } = merge.model;
737
+ // For row axis: lo=top, hi=bottom. For col axis: lo=left, hi=right.
738
+ const lo = isRow ? top : left;
739
+ const hi = isRow ? bottom : right;
740
+ if (nExpand <= 0 && count > 0) {
741
+ // Deleting rows/columns
742
+ const deleteEnd = nKeep - 1;
743
+ if (lo > deleteEnd) {
744
+ // Entirely after deleted range — shift
745
+ const newRange = isRow
746
+ ? new Range(top + nExpand, left, bottom + nExpand, right)
747
+ : new Range(top, left + nExpand, bottom, right + nExpand);
748
+ newMerges[colCache.encodeAddress(newRange.top, newRange.left)] = newRange;
749
+ }
750
+ else if (hi < start) {
751
+ // Entirely before deleted range — unchanged
752
+ newMerges[colCache.encodeAddress(top, left)] = merge;
753
+ }
754
+ else if (lo >= start && hi <= deleteEnd) {
755
+ // Entirely within deleted range — remove
756
+ }
757
+ else {
758
+ // Spans splice boundary — shrink
759
+ let newTop = top;
760
+ let newLeft = left;
761
+ let newBottom = bottom;
762
+ let newRight = right;
763
+ if (isRow) {
764
+ newTop = top < start ? top : start;
765
+ newBottom = Math.max(newTop, bottom + nExpand);
766
+ }
767
+ else {
768
+ newLeft = left < start ? left : start;
769
+ newRight = Math.max(newLeft, right + nExpand);
770
+ }
771
+ const newRange = new Range(newTop, newLeft, newBottom, newRight);
772
+ if (newTop === newBottom && newLeft === newRight) {
773
+ // Degenerate 1x1 merge — remove instead of keeping
774
+ }
775
+ else {
776
+ newMerges[colCache.encodeAddress(newRange.top, newRange.left)] = newRange;
777
+ }
778
+ }
779
+ }
780
+ else {
781
+ // Inserting rows/columns: shift items at/after nKeep
782
+ if (lo >= nKeep) {
783
+ // Entirely at or after splice — shift
784
+ const newRange = isRow
785
+ ? new Range(top + nExpand, left, bottom + nExpand, right)
786
+ : new Range(top, left + nExpand, bottom, right + nExpand);
787
+ newMerges[colCache.encodeAddress(newRange.top, newRange.left)] = newRange;
788
+ }
789
+ else if (hi < nKeep) {
790
+ // Entirely before splice — unchanged
791
+ newMerges[colCache.encodeAddress(top, left)] = merge;
792
+ }
793
+ else {
794
+ // Spans splice boundary — stretch
795
+ if (isRow) {
796
+ merge.model.bottom = bottom + nExpand;
797
+ }
798
+ else {
799
+ merge.model.right = right + nExpand;
800
+ }
801
+ newMerges[colCache.encodeAddress(top, left)] = merge;
802
+ }
803
+ }
804
+ }
805
+ this._merges = newMerges;
806
+ // Rebuild cell-level merge references for all merges.
807
+ // Pre-unmerge in spliceRows/spliceColumns clears all cell refs,
808
+ // so we must rebuild every merge, not just moved/resized ones.
809
+ for (const m of Object.values(newMerges)) {
810
+ const master = this.getCell(m.top, m.left);
811
+ for (let r = m.top; r <= m.bottom; r++) {
812
+ for (let c = m.left; c <= m.right; c++) {
813
+ if (r > m.top || c > m.left) {
814
+ this.getCell(r, c).merge(master, true);
815
+ }
816
+ }
817
+ }
818
+ }
819
+ }
672
820
  get hasMerges() {
673
821
  // return true if this._merges has a merge object
674
822
  return Object.values(this._merges).some(Boolean);
@@ -248,6 +248,19 @@ class Worksheet {
248
248
  * the rows will still be shifted as if the values existed
249
249
  */
250
250
  spliceColumns(start, count, ...inserts) {
251
+ // Before splicing cells, release all cell-level merge references so that
252
+ // row.splice copies plain values instead of merge proxies.
253
+ // _spliceMerges (called later) will rebuild cell-level refs at new coordinates.
254
+ for (const merge of Object.values(this._merges)) {
255
+ for (let r = merge.top; r <= merge.bottom; r++) {
256
+ for (let c = merge.left; c <= merge.right; c++) {
257
+ const cell = this.findCell(r, c);
258
+ if (cell && cell.type === enums_1.Enums.ValueType.Merge) {
259
+ cell.unmerge();
260
+ }
261
+ }
262
+ }
263
+ }
251
264
  const rows = this._rows;
252
265
  const nRows = rows.length;
253
266
  if (inserts.length > 0) {
@@ -299,6 +312,8 @@ class Worksheet {
299
312
  }
300
313
  }
301
314
  }
315
+ // account for merges
316
+ this._spliceMerges("col", start, count, inserts.length);
302
317
  }
303
318
  /**
304
319
  * Get the last column in a worksheet
@@ -472,6 +487,14 @@ class Worksheet {
472
487
  // either inserting new or overwriting existing rows
473
488
  const rSrc = this._rows[rowNum - 1];
474
489
  const inserts = Array.from({ length: count }).fill(rSrc.values);
490
+ // Collect single-row merges from the source row before splicing
491
+ // (only merges where top == bottom == rowNum, i.e. horizontal merges within one row)
492
+ const srcMerges = [];
493
+ for (const merge of Object.values(this._merges)) {
494
+ if (merge.top === rowNum && merge.bottom === rowNum) {
495
+ srcMerges.push(merge);
496
+ }
497
+ }
475
498
  this.spliceRows(rowNum + 1, insert ? 0 : count, ...inserts);
476
499
  // now copy styles...
477
500
  for (let i = 0; i < count; i++) {
@@ -482,6 +505,27 @@ class Worksheet {
482
505
  rDst.getCell(colNumber).style = cell.style;
483
506
  });
484
507
  }
508
+ // Duplicate single-row merges from source row into each new row
509
+ if (srcMerges.length > 0) {
510
+ for (let i = 0; i < count; i++) {
511
+ const dstRow = rowNum + 1 + i;
512
+ // In overwrite mode, clear any existing merges in the target row
513
+ if (!insert) {
514
+ const toRemove = [];
515
+ for (const [key, merge] of Object.entries(this._merges)) {
516
+ if (merge.top <= dstRow && merge.bottom >= dstRow) {
517
+ toRemove.push(key);
518
+ }
519
+ }
520
+ for (const key of toRemove) {
521
+ this._unMergeMaster(this.getCell(key));
522
+ }
523
+ }
524
+ for (const srcMerge of srcMerges) {
525
+ this.mergeCellsWithoutStyle(dstRow, srcMerge.left, dstRow, srcMerge.right);
526
+ }
527
+ }
528
+ }
485
529
  }
486
530
  /**
487
531
  * Cut one or more rows (rows below are shifted up)
@@ -491,6 +535,19 @@ class Worksheet {
491
535
  */
492
536
  spliceRows(start, count, ...inserts) {
493
537
  // same problem as row.splice, except worse.
538
+ // Before splicing rows, release all cell-level merge references so that
539
+ // row value copies work on plain values instead of merge proxies.
540
+ // _spliceMerges (called later) will rebuild cell-level refs at new coordinates.
541
+ for (const merge of Object.values(this._merges)) {
542
+ for (let r = merge.top; r <= merge.bottom; r++) {
543
+ for (let c = merge.left; c <= merge.right; c++) {
544
+ const cell = this.findCell(r, c);
545
+ if (cell && cell.type === enums_1.Enums.ValueType.Merge) {
546
+ cell.unmerge();
547
+ }
548
+ }
549
+ }
550
+ }
494
551
  const nKeep = start + count;
495
552
  const nInserts = inserts.length;
496
553
  const nExpand = nInserts - count;
@@ -530,13 +587,6 @@ class Worksheet {
530
587
  rDst.height = rSrc.height;
531
588
  rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
532
589
  rDst.getCell(colNumber).style = cell.style;
533
- // remerge cells accounting for insert offset
534
- if (cell.type === enums_1.Enums.ValueType.Merge) {
535
- const cellToBeMerged = this.getRow(cell.row + nInserts).getCell(colNumber);
536
- const prevMaster = cell.master;
537
- const newMaster = this.getRow(prevMaster.row + nInserts).getCell(prevMaster.col);
538
- cellToBeMerged.merge(newMaster);
539
- }
540
590
  });
541
591
  }
542
592
  else {
@@ -566,6 +616,8 @@ class Worksheet {
566
616
  }
567
617
  }
568
618
  }
619
+ // account for merges
620
+ this._spliceMerges("row", start, count, nInserts);
569
621
  }
570
622
  eachRow(optOrCallback, maybeCallback) {
571
623
  let options;
@@ -672,6 +724,102 @@ class Worksheet {
672
724
  delete this._merges[master.address];
673
725
  }
674
726
  }
727
+ /**
728
+ * Update _merges dictionary and cell-level merge references after a row or column splice.
729
+ */
730
+ _spliceMerges(axis, start, count, nInserts) {
731
+ const nExpand = nInserts - count;
732
+ if (nExpand === 0 && count === 0) {
733
+ return;
734
+ }
735
+ const nKeep = start + count;
736
+ const isRow = axis === "row";
737
+ const newMerges = {};
738
+ for (const merge of Object.values(this._merges)) {
739
+ const { top, left, bottom, right } = merge.model;
740
+ // For row axis: lo=top, hi=bottom. For col axis: lo=left, hi=right.
741
+ const lo = isRow ? top : left;
742
+ const hi = isRow ? bottom : right;
743
+ if (nExpand <= 0 && count > 0) {
744
+ // Deleting rows/columns
745
+ const deleteEnd = nKeep - 1;
746
+ if (lo > deleteEnd) {
747
+ // Entirely after deleted range — shift
748
+ const newRange = isRow
749
+ ? new range_1.Range(top + nExpand, left, bottom + nExpand, right)
750
+ : new range_1.Range(top, left + nExpand, bottom, right + nExpand);
751
+ newMerges[col_cache_1.colCache.encodeAddress(newRange.top, newRange.left)] = newRange;
752
+ }
753
+ else if (hi < start) {
754
+ // Entirely before deleted range — unchanged
755
+ newMerges[col_cache_1.colCache.encodeAddress(top, left)] = merge;
756
+ }
757
+ else if (lo >= start && hi <= deleteEnd) {
758
+ // Entirely within deleted range — remove
759
+ }
760
+ else {
761
+ // Spans splice boundary — shrink
762
+ let newTop = top;
763
+ let newLeft = left;
764
+ let newBottom = bottom;
765
+ let newRight = right;
766
+ if (isRow) {
767
+ newTop = top < start ? top : start;
768
+ newBottom = Math.max(newTop, bottom + nExpand);
769
+ }
770
+ else {
771
+ newLeft = left < start ? left : start;
772
+ newRight = Math.max(newLeft, right + nExpand);
773
+ }
774
+ const newRange = new range_1.Range(newTop, newLeft, newBottom, newRight);
775
+ if (newTop === newBottom && newLeft === newRight) {
776
+ // Degenerate 1x1 merge — remove instead of keeping
777
+ }
778
+ else {
779
+ newMerges[col_cache_1.colCache.encodeAddress(newRange.top, newRange.left)] = newRange;
780
+ }
781
+ }
782
+ }
783
+ else {
784
+ // Inserting rows/columns: shift items at/after nKeep
785
+ if (lo >= nKeep) {
786
+ // Entirely at or after splice — shift
787
+ const newRange = isRow
788
+ ? new range_1.Range(top + nExpand, left, bottom + nExpand, right)
789
+ : new range_1.Range(top, left + nExpand, bottom, right + nExpand);
790
+ newMerges[col_cache_1.colCache.encodeAddress(newRange.top, newRange.left)] = newRange;
791
+ }
792
+ else if (hi < nKeep) {
793
+ // Entirely before splice — unchanged
794
+ newMerges[col_cache_1.colCache.encodeAddress(top, left)] = merge;
795
+ }
796
+ else {
797
+ // Spans splice boundary — stretch
798
+ if (isRow) {
799
+ merge.model.bottom = bottom + nExpand;
800
+ }
801
+ else {
802
+ merge.model.right = right + nExpand;
803
+ }
804
+ newMerges[col_cache_1.colCache.encodeAddress(top, left)] = merge;
805
+ }
806
+ }
807
+ }
808
+ this._merges = newMerges;
809
+ // Rebuild cell-level merge references for all merges.
810
+ // Pre-unmerge in spliceRows/spliceColumns clears all cell refs,
811
+ // so we must rebuild every merge, not just moved/resized ones.
812
+ for (const m of Object.values(newMerges)) {
813
+ const master = this.getCell(m.top, m.left);
814
+ for (let r = m.top; r <= m.bottom; r++) {
815
+ for (let c = m.left; c <= m.right; c++) {
816
+ if (r > m.top || c > m.left) {
817
+ this.getCell(r, c).merge(master, true);
818
+ }
819
+ }
820
+ }
821
+ }
822
+ }
675
823
  get hasMerges() {
676
824
  // return true if this._merges has a merge object
677
825
  return Object.values(this._merges).some(Boolean);
@@ -245,6 +245,19 @@ class Worksheet {
245
245
  * the rows will still be shifted as if the values existed
246
246
  */
247
247
  spliceColumns(start, count, ...inserts) {
248
+ // Before splicing cells, release all cell-level merge references so that
249
+ // row.splice copies plain values instead of merge proxies.
250
+ // _spliceMerges (called later) will rebuild cell-level refs at new coordinates.
251
+ for (const merge of Object.values(this._merges)) {
252
+ for (let r = merge.top; r <= merge.bottom; r++) {
253
+ for (let c = merge.left; c <= merge.right; c++) {
254
+ const cell = this.findCell(r, c);
255
+ if (cell && cell.type === Enums.ValueType.Merge) {
256
+ cell.unmerge();
257
+ }
258
+ }
259
+ }
260
+ }
248
261
  const rows = this._rows;
249
262
  const nRows = rows.length;
250
263
  if (inserts.length > 0) {
@@ -296,6 +309,8 @@ class Worksheet {
296
309
  }
297
310
  }
298
311
  }
312
+ // account for merges
313
+ this._spliceMerges("col", start, count, inserts.length);
299
314
  }
300
315
  /**
301
316
  * Get the last column in a worksheet
@@ -469,6 +484,14 @@ class Worksheet {
469
484
  // either inserting new or overwriting existing rows
470
485
  const rSrc = this._rows[rowNum - 1];
471
486
  const inserts = Array.from({ length: count }).fill(rSrc.values);
487
+ // Collect single-row merges from the source row before splicing
488
+ // (only merges where top == bottom == rowNum, i.e. horizontal merges within one row)
489
+ const srcMerges = [];
490
+ for (const merge of Object.values(this._merges)) {
491
+ if (merge.top === rowNum && merge.bottom === rowNum) {
492
+ srcMerges.push(merge);
493
+ }
494
+ }
472
495
  this.spliceRows(rowNum + 1, insert ? 0 : count, ...inserts);
473
496
  // now copy styles...
474
497
  for (let i = 0; i < count; i++) {
@@ -479,6 +502,27 @@ class Worksheet {
479
502
  rDst.getCell(colNumber).style = cell.style;
480
503
  });
481
504
  }
505
+ // Duplicate single-row merges from source row into each new row
506
+ if (srcMerges.length > 0) {
507
+ for (let i = 0; i < count; i++) {
508
+ const dstRow = rowNum + 1 + i;
509
+ // In overwrite mode, clear any existing merges in the target row
510
+ if (!insert) {
511
+ const toRemove = [];
512
+ for (const [key, merge] of Object.entries(this._merges)) {
513
+ if (merge.top <= dstRow && merge.bottom >= dstRow) {
514
+ toRemove.push(key);
515
+ }
516
+ }
517
+ for (const key of toRemove) {
518
+ this._unMergeMaster(this.getCell(key));
519
+ }
520
+ }
521
+ for (const srcMerge of srcMerges) {
522
+ this.mergeCellsWithoutStyle(dstRow, srcMerge.left, dstRow, srcMerge.right);
523
+ }
524
+ }
525
+ }
482
526
  }
483
527
  /**
484
528
  * Cut one or more rows (rows below are shifted up)
@@ -488,6 +532,19 @@ class Worksheet {
488
532
  */
489
533
  spliceRows(start, count, ...inserts) {
490
534
  // same problem as row.splice, except worse.
535
+ // Before splicing rows, release all cell-level merge references so that
536
+ // row value copies work on plain values instead of merge proxies.
537
+ // _spliceMerges (called later) will rebuild cell-level refs at new coordinates.
538
+ for (const merge of Object.values(this._merges)) {
539
+ for (let r = merge.top; r <= merge.bottom; r++) {
540
+ for (let c = merge.left; c <= merge.right; c++) {
541
+ const cell = this.findCell(r, c);
542
+ if (cell && cell.type === Enums.ValueType.Merge) {
543
+ cell.unmerge();
544
+ }
545
+ }
546
+ }
547
+ }
491
548
  const nKeep = start + count;
492
549
  const nInserts = inserts.length;
493
550
  const nExpand = nInserts - count;
@@ -527,13 +584,6 @@ class Worksheet {
527
584
  rDst.height = rSrc.height;
528
585
  rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
529
586
  rDst.getCell(colNumber).style = cell.style;
530
- // remerge cells accounting for insert offset
531
- if (cell.type === Enums.ValueType.Merge) {
532
- const cellToBeMerged = this.getRow(cell.row + nInserts).getCell(colNumber);
533
- const prevMaster = cell.master;
534
- const newMaster = this.getRow(prevMaster.row + nInserts).getCell(prevMaster.col);
535
- cellToBeMerged.merge(newMaster);
536
- }
537
587
  });
538
588
  }
539
589
  else {
@@ -563,6 +613,8 @@ class Worksheet {
563
613
  }
564
614
  }
565
615
  }
616
+ // account for merges
617
+ this._spliceMerges("row", start, count, nInserts);
566
618
  }
567
619
  eachRow(optOrCallback, maybeCallback) {
568
620
  let options;
@@ -669,6 +721,102 @@ class Worksheet {
669
721
  delete this._merges[master.address];
670
722
  }
671
723
  }
724
+ /**
725
+ * Update _merges dictionary and cell-level merge references after a row or column splice.
726
+ */
727
+ _spliceMerges(axis, start, count, nInserts) {
728
+ const nExpand = nInserts - count;
729
+ if (nExpand === 0 && count === 0) {
730
+ return;
731
+ }
732
+ const nKeep = start + count;
733
+ const isRow = axis === "row";
734
+ const newMerges = {};
735
+ for (const merge of Object.values(this._merges)) {
736
+ const { top, left, bottom, right } = merge.model;
737
+ // For row axis: lo=top, hi=bottom. For col axis: lo=left, hi=right.
738
+ const lo = isRow ? top : left;
739
+ const hi = isRow ? bottom : right;
740
+ if (nExpand <= 0 && count > 0) {
741
+ // Deleting rows/columns
742
+ const deleteEnd = nKeep - 1;
743
+ if (lo > deleteEnd) {
744
+ // Entirely after deleted range — shift
745
+ const newRange = isRow
746
+ ? new Range(top + nExpand, left, bottom + nExpand, right)
747
+ : new Range(top, left + nExpand, bottom, right + nExpand);
748
+ newMerges[colCache.encodeAddress(newRange.top, newRange.left)] = newRange;
749
+ }
750
+ else if (hi < start) {
751
+ // Entirely before deleted range — unchanged
752
+ newMerges[colCache.encodeAddress(top, left)] = merge;
753
+ }
754
+ else if (lo >= start && hi <= deleteEnd) {
755
+ // Entirely within deleted range — remove
756
+ }
757
+ else {
758
+ // Spans splice boundary — shrink
759
+ let newTop = top;
760
+ let newLeft = left;
761
+ let newBottom = bottom;
762
+ let newRight = right;
763
+ if (isRow) {
764
+ newTop = top < start ? top : start;
765
+ newBottom = Math.max(newTop, bottom + nExpand);
766
+ }
767
+ else {
768
+ newLeft = left < start ? left : start;
769
+ newRight = Math.max(newLeft, right + nExpand);
770
+ }
771
+ const newRange = new Range(newTop, newLeft, newBottom, newRight);
772
+ if (newTop === newBottom && newLeft === newRight) {
773
+ // Degenerate 1x1 merge — remove instead of keeping
774
+ }
775
+ else {
776
+ newMerges[colCache.encodeAddress(newRange.top, newRange.left)] = newRange;
777
+ }
778
+ }
779
+ }
780
+ else {
781
+ // Inserting rows/columns: shift items at/after nKeep
782
+ if (lo >= nKeep) {
783
+ // Entirely at or after splice — shift
784
+ const newRange = isRow
785
+ ? new Range(top + nExpand, left, bottom + nExpand, right)
786
+ : new Range(top, left + nExpand, bottom, right + nExpand);
787
+ newMerges[colCache.encodeAddress(newRange.top, newRange.left)] = newRange;
788
+ }
789
+ else if (hi < nKeep) {
790
+ // Entirely before splice — unchanged
791
+ newMerges[colCache.encodeAddress(top, left)] = merge;
792
+ }
793
+ else {
794
+ // Spans splice boundary — stretch
795
+ if (isRow) {
796
+ merge.model.bottom = bottom + nExpand;
797
+ }
798
+ else {
799
+ merge.model.right = right + nExpand;
800
+ }
801
+ newMerges[colCache.encodeAddress(top, left)] = merge;
802
+ }
803
+ }
804
+ }
805
+ this._merges = newMerges;
806
+ // Rebuild cell-level merge references for all merges.
807
+ // Pre-unmerge in spliceRows/spliceColumns clears all cell refs,
808
+ // so we must rebuild every merge, not just moved/resized ones.
809
+ for (const m of Object.values(newMerges)) {
810
+ const master = this.getCell(m.top, m.left);
811
+ for (let r = m.top; r <= m.bottom; r++) {
812
+ for (let c = m.left; c <= m.right; c++) {
813
+ if (r > m.top || c > m.left) {
814
+ this.getCell(r, c).merge(master, true);
815
+ }
816
+ }
817
+ }
818
+ }
819
+ }
672
820
  get hasMerges() {
673
821
  // return true if this._merges has a merge object
674
822
  return Object.values(this._merges).some(Boolean);