@revolist/revogrid 4.23.0 → 4.23.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.
Files changed (39) hide show
  1. package/dist/cjs/{cell-renderer-DWJ9Px9f.js → cell-renderer-Dcz022q7.js} +1 -1
  2. package/dist/cjs/{column.drag.plugin-CaEBDG-Q.js → column.drag.plugin-DJueWxN_.js} +2 -2
  3. package/dist/cjs/{column.service-f612L4ql.js → column.service-C1Qvcf5l.js} +9 -0
  4. package/dist/cjs/{header-cell-renderer-4yq9_WbM.js → header-cell-renderer-QrcXXSkF.js} +1 -1
  5. package/dist/cjs/index.cjs.js +4 -4
  6. package/dist/cjs/revo-grid.cjs.entry.js +92 -6
  7. package/dist/cjs/revogr-attribution_7.cjs.entry.js +1 -1
  8. package/dist/cjs/revogr-data_4.cjs.entry.js +51 -18
  9. package/dist/collection/components/header/revogr-header.js +49 -16
  10. package/dist/collection/components/revoGrid/revo-grid.js +63 -0
  11. package/dist/collection/plugins/groupingRow/grouping.service.js +9 -0
  12. package/dist/collection/services/selection.store.connector.js +26 -3
  13. package/dist/esm/{cell-renderer-8UiGd-s7.js → cell-renderer-BtN-NGCk.js} +1 -1
  14. package/dist/esm/{column.drag.plugin-BsfhsfmB.js → column.drag.plugin-DCZW62Uc.js} +2 -2
  15. package/dist/esm/{column.service-DbpulTog.js → column.service-CC_SD8W3.js} +9 -0
  16. package/dist/esm/{header-cell-renderer-DGI2FAD8.js → header-cell-renderer-BsvUQ8GS.js} +1 -1
  17. package/dist/esm/index.js +5 -5
  18. package/dist/esm/revo-grid.entry.js +92 -6
  19. package/dist/esm/revogr-attribution_7.entry.js +1 -1
  20. package/dist/esm/revogr-data_4.entry.js +51 -18
  21. package/dist/revo-grid/{cell-renderer-8UiGd-s7.js → cell-renderer-BtN-NGCk.js} +1 -1
  22. package/dist/revo-grid/{column.drag.plugin-BsfhsfmB.js → column.drag.plugin-DCZW62Uc.js} +2 -2
  23. package/dist/revo-grid/{column.service-DbpulTog.js → column.service-CC_SD8W3.js} +9 -0
  24. package/dist/revo-grid/{header-cell-renderer-DGI2FAD8.js → header-cell-renderer-BsvUQ8GS.js} +1 -1
  25. package/dist/revo-grid/index.esm.js +5 -5
  26. package/dist/revo-grid/revo-grid.entry.js +92 -6
  27. package/dist/revo-grid/revogr-attribution_7.entry.js +1 -1
  28. package/dist/revo-grid/revogr-data_4.entry.js +51 -18
  29. package/dist/types/components/header/header-group-renderer.d.ts +1 -0
  30. package/dist/types/components/header/revogr-header.d.ts +2 -0
  31. package/dist/types/components/revoGrid/revo-grid.d.ts +12 -0
  32. package/dist/types/services/selection.store.connector.d.ts +6 -0
  33. package/dist/types/types/selection.d.ts +13 -0
  34. package/hydrate/index.js +146 -18
  35. package/hydrate/index.mjs +146 -18
  36. package/package.json +1 -1
  37. package/standalone/column.service.js +1 -1
  38. package/standalone/revo-grid.js +1 -1
  39. package/standalone/revogr-header2.js +1 -1
@@ -2,11 +2,11 @@
2
2
  * Built by Revolist OU ❤️
3
3
  */
4
4
  import { r as registerInstance, d as createEvent, h, e as Host, g as getElement } from './index-Chp_81rd.js';
5
- import { M as ColumnService, u as isGrouping } from './column.service-DbpulTog.js';
5
+ import { M as ColumnService, u as isGrouping } from './column.service-CC_SD8W3.js';
6
6
  import { B as ROW_FOCUSED_CLASS, b as getSourceItem, n as DATA_ROW, m as DATA_COL, M as MIN_COL_SIZE, r as HEADER_SORTABLE_CLASS, H as HEADER_CLASS, F as FOCUS_CLASS, k as getItemByIndex, u as HEADER_ROW_CLASS, v as HEADER_ACTUAL_ROW_CLASS } from './dimension.helpers-CGKwSvw6.js';
7
- import { G as GroupingRowRenderer, C as CellRenderer, R as RowRenderer, P as PADDING_DEPTH, S as SortingSign } from './cell-renderer-8UiGd-s7.js';
7
+ import { G as GroupingRowRenderer, C as CellRenderer, R as RowRenderer, P as PADDING_DEPTH, S as SortingSign } from './cell-renderer-BtN-NGCk.js';
8
8
  import { c as FilterButton } from './filter.button-C8XTWPU2.js';
9
- import { H as HeaderCellRenderer } from './header-cell-renderer-DGI2FAD8.js';
9
+ import { H as HeaderCellRenderer } from './header-cell-renderer-BsvUQ8GS.js';
10
10
  import { t as throttle, L as LocalScrollTimer, a as LocalScrollService, g as getContentSize } from './throttle-CaUDyxyU.js';
11
11
  import { H as HEADER_SLOT, C as CONTENT_SLOT, F as FOOTER_SLOT } from './viewport.helpers-CoCAvmZs.js';
12
12
  import './debounce-PCRWZliA.js';
@@ -434,22 +434,13 @@ const RevogrHeaderComponent = class {
434
434
  ];
435
435
  }
436
436
  renderGroupColumn(group, level, visibleGroupRange) {
437
- var _a;
438
- const groupStartIndex = (_a = group.indexes[0]) !== null && _a !== void 0 ? _a : -1;
439
- if (groupStartIndex < 0) {
440
- return;
441
- }
442
- const groupEndIndex = groupStartIndex + group.indexes.length - 1;
443
- if (!visibleGroupRange ||
444
- !isGroupInVisibleRange(groupStartIndex, groupEndIndex, visibleGroupRange)) {
445
- return;
446
- }
447
- const groupStart = getItemByIndex(this.dimensionCol.state, groupStartIndex).start;
448
- const groupEnd = getItemByIndex(this.dimensionCol.state, groupEndIndex).end;
437
+ const groupRange = this.getGroupIndexRange(group);
438
+ const groupBounds = this.getGroupBounds(groupRange);
449
439
  const props = {
440
+ level,
450
441
  providers: this.providers,
451
- start: groupStart,
452
- end: groupEnd,
442
+ start: groupBounds.start,
443
+ end: groupBounds.end,
453
444
  group,
454
445
  renderOffset: this.viewportCol.get('renderOffset') || 0,
455
446
  active: this.resizeHandler,
@@ -457,15 +448,57 @@ const RevogrHeaderComponent = class {
457
448
  additionalData: this.additionalData,
458
449
  onResize: e => {
459
450
  var _a;
460
- return this.onResizeGroup((_a = e.changedX) !== null && _a !== void 0 ? _a : 0, groupStartIndex, groupEndIndex);
451
+ return groupRange
452
+ ? this.onResizeGroup((_a = e.changedX) !== null && _a !== void 0 ? _a : 0, groupRange.startIndex, groupRange.endIndex)
453
+ : undefined;
461
454
  },
462
455
  };
463
456
  const event = this.beforeGroupHeaderRender.emit(props);
464
457
  if (event.defaultPrevented) {
465
458
  return;
466
459
  }
460
+ const renderRange = this.getGroupIndexRange(event.detail.group);
461
+ if (!renderRange ||
462
+ !visibleGroupRange ||
463
+ !isGroupInVisibleRange(renderRange.startIndex, renderRange.endIndex, visibleGroupRange)) {
464
+ return;
465
+ }
466
+ if (event.detail.onResize === props.onResize) {
467
+ event.detail.onResize = e => {
468
+ var _a;
469
+ return this.onResizeGroup((_a = e.changedX) !== null && _a !== void 0 ? _a : 0, renderRange.startIndex, renderRange.endIndex);
470
+ };
471
+ }
472
+ const renderBounds = this.getGroupBounds(renderRange);
473
+ if (event.detail.start === props.start) {
474
+ event.detail.start = renderBounds.start;
475
+ }
476
+ if (event.detail.end === props.end) {
477
+ event.detail.end = renderBounds.end;
478
+ }
467
479
  return h(HeaderGroupRenderer, Object.assign({ key: this.getGroupHeaderCellKey(event.detail.group, level) }, event.detail));
468
480
  }
481
+ getGroupIndexRange(group) {
482
+ var _a;
483
+ const startIndex = (_a = group.indexes[0]) !== null && _a !== void 0 ? _a : -1;
484
+ if (startIndex < 0) {
485
+ return;
486
+ }
487
+ const endIndex = group.indexes[group.indexes.length - 1];
488
+ return {
489
+ startIndex,
490
+ endIndex,
491
+ };
492
+ }
493
+ getGroupBounds(range) {
494
+ if (!range) {
495
+ return { start: 0, end: 0 };
496
+ }
497
+ return {
498
+ start: getItemByIndex(this.dimensionCol.state, range.startIndex).start,
499
+ end: getItemByIndex(this.dimensionCol.state, range.endIndex).end,
500
+ };
501
+ }
469
502
  getVisibleGroupRange() {
470
503
  const visibleColumns = this.viewportCol.get('items');
471
504
  if (!visibleColumns.length) {
@@ -3,6 +3,7 @@ import { Group } from "../../store/index";
3
3
  import type { ProvidersColumns } from "../../types/index";
4
4
  import { ResizeEvent, ResizeProps } from './resizable.directive';
5
5
  export type HeaderGroupRendererProps = {
6
+ level: number;
6
7
  start: number;
7
8
  end: number;
8
9
  group: Group;
@@ -88,6 +88,8 @@ export declare class RevogrHeaderComponent {
88
88
  private renderGroupingColumns;
89
89
  private renderGroupRow;
90
90
  private renderGroupColumn;
91
+ private getGroupIndexRange;
92
+ private getGroupBounds;
91
93
  private getVisibleGroupRange;
92
94
  private getHeaderCellKey;
93
95
  private getDuplicateHeaderProps;
@@ -626,8 +626,20 @@ export declare class RevoGridComponent {
626
626
  orderService: OrdererService;
627
627
  selectionStoreConnector?: SelectionStoreConnector;
628
628
  scrollingService: GridScrollingService;
629
+ private pendingColumnFocusRestore?;
629
630
  columnTypesChanged(): void;
630
631
  columnChanged(newVal?: (ColumnGrouping | ColumnRegular)[], _prevVal?: (ColumnGrouping | ColumnRegular)[] | undefined, __watchName?: string, init?: boolean): void;
632
+ /**
633
+ * Capture logical focus before columns are repartitioned by pin state.
634
+ * Regression case: selecting a regular cell, then pinning that column left,
635
+ * used to let the new pinned viewport reuse the old rgCol selection store.
636
+ */
637
+ private getColumnFocusRestore;
638
+ /**
639
+ * Reapply focus by column prop after render, once pinning has moved the
640
+ * column to its new viewport and virtual index.
641
+ */
642
+ private restoreColumnFocusAfterRender;
631
643
  disableVirtualXChanged(newVal?: boolean, prevVal?: boolean): void;
632
644
  rowSizeChanged(s: number): void;
633
645
  themeChanged(t: Theme, _?: Theme, __?: string, init?: boolean): void;
@@ -70,5 +70,11 @@ export declare class SelectionStoreConnector {
70
70
  selectAll(): void;
71
71
  private getXStores;
72
72
  private getYStores;
73
+ /**
74
+ * Keep column viewport positions and types in sync across pin/unpin rerenders.
75
+ * Regression case: when a selected rgCol cell was pinned left, colPinStart
76
+ * could take over x=0 and render the stale rgCol focus store in the pinned area.
77
+ */
78
+ private updateColumnTypeMapping;
73
79
  }
74
80
  export {};
@@ -65,6 +65,19 @@ export type ChangedRange = {
65
65
  [newRowIndex: number]: DataType;
66
66
  };
67
67
  };
68
+ /**
69
+ * Logical focus marker captured before column viewport ownership changes.
70
+ * Used when a selected column is pinned/unpinned so focus can be restored by
71
+ * column prop after the column moves between rgCol, colPinStart, or colPinEnd.
72
+ */
73
+ export type PendingColumnFocusRestore = {
74
+ prop: ColumnProp;
75
+ colType: DimensionCols;
76
+ colIndex: ColIndex;
77
+ prevStoreX: ColIndex;
78
+ rowType: DimensionRows;
79
+ rowIndex: RowIndex;
80
+ };
68
81
  /**
69
82
  * Cell coordinates
70
83
  */
package/hydrate/index.js CHANGED
@@ -12645,6 +12645,9 @@ const GROUPING_ROW_TYPE = 'rgRow';
12645
12645
  function getGroupValueDefault(item, prop) {
12646
12646
  return item[prop] || null;
12647
12647
  }
12648
+ function isDataRow(item) {
12649
+ return item != null;
12650
+ }
12648
12651
  // get source based on proxy item collection to preserve rgRow order
12649
12652
  function getSource(source, items, withoutGrouping = false) {
12650
12653
  let index = 0;
@@ -12666,6 +12669,9 @@ function getSource(source, items, withoutGrouping = false) {
12666
12669
  result.prevExpanded[model[PSEUDO_GROUP_ITEM_VALUE]] = true;
12667
12670
  }
12668
12671
  }
12672
+ else if (!isDataRow(model)) {
12673
+ return;
12674
+ }
12669
12675
  else {
12670
12676
  result.source.push(model);
12671
12677
  result.oldNewIndexes[i] = index;
@@ -12746,6 +12752,9 @@ function flattenGroupMaps({ groupedValues, parentIds, isExpanded, itemIndex, exp
12746
12752
  function gatherGrouping(array, columnProps, { prevExpanded = {}, expandedAll = false, getGroupValue = getGroupValueDefault, }) {
12747
12753
  const groupedItems = new Map();
12748
12754
  array.forEach((item, originalIndex) => {
12755
+ if (!isDataRow(item)) {
12756
+ return;
12757
+ }
12749
12758
  const groupLevelValues = columnProps.map(groupId => getGroupValue(item, groupId));
12750
12759
  const lastLevelValue = groupLevelValues.pop();
12751
12760
  let currentGroupLevel = groupedItems;
@@ -17654,13 +17663,11 @@ class SelectionStoreConnector {
17654
17663
  return (_a = this.focusedStore) === null || _a === void 0 ? void 0 : _a.entity.store.get('range');
17655
17664
  }
17656
17665
  registerColumn(x, type) {
17666
+ this.updateColumnTypeMapping(x, type);
17657
17667
  if (this.columnStores[x]) {
17658
17668
  return this.columnStores[x];
17659
17669
  }
17660
17670
  this.columnStores[x] = new SelectionStore();
17661
- // build cross-linking type to position
17662
- this.storesByType[type] = x;
17663
- this.storesXToType[x] = type;
17664
17671
  return this.columnStores[x];
17665
17672
  }
17666
17673
  registerRow(y, type) {
@@ -17881,6 +17888,31 @@ class SelectionStoreConnector {
17881
17888
  }
17882
17889
  return stores;
17883
17890
  }
17891
+ /**
17892
+ * Keep column viewport positions and types in sync across pin/unpin rerenders.
17893
+ * Regression case: when a selected rgCol cell was pinned left, colPinStart
17894
+ * could take over x=0 and render the stale rgCol focus store in the pinned area.
17895
+ */
17896
+ updateColumnTypeMapping(x, type) {
17897
+ const previousType = this.storesXToType[x];
17898
+ const previousX = this.storesByType[type];
17899
+ let shouldClearFocus = false;
17900
+ this.storesByType[type] = x;
17901
+ this.storesXToType[x] = type;
17902
+ if (previousType && previousType !== type) {
17903
+ shouldClearFocus = true;
17904
+ if (this.storesByType[previousType] === x) {
17905
+ delete this.storesByType[previousType];
17906
+ }
17907
+ }
17908
+ if (typeof previousX === 'number' && previousX !== x && this.storesXToType[previousX] === type) {
17909
+ delete this.storesXToType[previousX];
17910
+ shouldClearFocus = true;
17911
+ }
17912
+ if (shouldClearFocus) {
17913
+ this.clearAll();
17914
+ }
17915
+ }
17884
17916
  }
17885
17917
 
17886
17918
  /**
@@ -19477,6 +19509,7 @@ class RevoGridComponent {
19477
19509
  if (!this.dimensionProvider || !this.columnProvider) {
19478
19510
  return;
19479
19511
  }
19512
+ const focusToRestore = init ? undefined : this.getColumnFocusRestore();
19480
19513
  const beforeGatherEvent = this.beforecolumnsgather.emit({
19481
19514
  columns: [...newVal],
19482
19515
  });
@@ -19494,6 +19527,9 @@ class RevoGridComponent {
19494
19527
  return;
19495
19528
  }
19496
19529
  const columns = this.columnProvider.setColumns(beforeApplyEvent.detail);
19530
+ if (focusToRestore) {
19531
+ this.pendingColumnFocusRestore = focusToRestore;
19532
+ }
19497
19533
  const order = {};
19498
19534
  for (const prop of Object.keys(beforeApplyEvent.detail.sort)) {
19499
19535
  order[prop] = beforeApplyEvent.detail.sort[prop].order;
@@ -19503,6 +19539,64 @@ class RevoGridComponent {
19503
19539
  order,
19504
19540
  });
19505
19541
  }
19542
+ /**
19543
+ * Capture logical focus before columns are repartitioned by pin state.
19544
+ * Regression case: selecting a regular cell, then pinning that column left,
19545
+ * used to let the new pinned viewport reuse the old rgCol selection store.
19546
+ */
19547
+ getColumnFocusRestore() {
19548
+ var _a, _b, _c, _d;
19549
+ const focused = (_a = this.viewport) === null || _a === void 0 ? void 0 : _a.getFocused();
19550
+ const prevStoreX = (_c = (_b = this.selectionStoreConnector) === null || _b === void 0 ? void 0 : _b.focusedStore) === null || _c === void 0 ? void 0 : _c.position.x;
19551
+ const prop = (_d = focused === null || focused === void 0 ? void 0 : focused.column) === null || _d === void 0 ? void 0 : _d.prop;
19552
+ if (!focused || prop === undefined || prevStoreX === undefined) {
19553
+ return;
19554
+ }
19555
+ return {
19556
+ prop,
19557
+ colType: focused.colType,
19558
+ colIndex: focused.cell.x,
19559
+ prevStoreX,
19560
+ rowType: focused.rowType,
19561
+ rowIndex: focused.cell.y,
19562
+ };
19563
+ }
19564
+ /**
19565
+ * Reapply focus by column prop after render, once pinning has moved the
19566
+ * column to its new viewport and virtual index.
19567
+ */
19568
+ restoreColumnFocusAfterRender() {
19569
+ var _a, _b, _c, _d;
19570
+ const pending = this.pendingColumnFocusRestore;
19571
+ if (!pending) {
19572
+ return;
19573
+ }
19574
+ this.pendingColumnFocusRestore = undefined;
19575
+ if (!this.viewport || !this.columnProvider) {
19576
+ return;
19577
+ }
19578
+ const column = (_b = (_a = this.columnProvider.getColumnByProp(pending.prop)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : getColumnByProp(this.columns, pending.prop);
19579
+ if (!column) {
19580
+ return;
19581
+ }
19582
+ const colType = column.pin || 'rgCol';
19583
+ const columnIndex = this.columnProvider.getColumnIndexByProp(pending.prop, colType);
19584
+ if (columnIndex < 0) {
19585
+ return;
19586
+ }
19587
+ // Header-only column refreshes should not collapse an existing range.
19588
+ // Replay focus only when pin/unpin or repartitioning moved the logical column.
19589
+ if (colType === pending.colType &&
19590
+ columnIndex === pending.colIndex &&
19591
+ pending.prevStoreX === ((_d = (_c = this.selectionStoreConnector) === null || _c === void 0 ? void 0 : _c.focusedStore) === null || _d === void 0 ? void 0 : _d.position.x)) {
19592
+ return;
19593
+ }
19594
+ const cell = {
19595
+ x: columnIndex,
19596
+ y: pending.rowIndex,
19597
+ };
19598
+ this.viewport.setFocus(colType, pending.rowType, cell, cell);
19599
+ }
19506
19600
  disableVirtualXChanged(newVal = false, prevVal = false) {
19507
19601
  if (newVal === prevVal) {
19508
19602
  return;
@@ -19815,6 +19909,7 @@ class RevoGridComponent {
19815
19909
  return Promise.all(this.jobsBeforeRender);
19816
19910
  }
19817
19911
  componentDidRender() {
19912
+ this.restoreColumnFocusAfterRender();
19818
19913
  this.aftergridrender.emit();
19819
19914
  }
19820
19915
  render() {
@@ -20836,22 +20931,13 @@ class RevogrHeaderComponent {
20836
20931
  ];
20837
20932
  }
20838
20933
  renderGroupColumn(group, level, visibleGroupRange) {
20839
- var _a;
20840
- const groupStartIndex = (_a = group.indexes[0]) !== null && _a !== void 0 ? _a : -1;
20841
- if (groupStartIndex < 0) {
20842
- return;
20843
- }
20844
- const groupEndIndex = groupStartIndex + group.indexes.length - 1;
20845
- if (!visibleGroupRange ||
20846
- !isGroupInVisibleRange(groupStartIndex, groupEndIndex, visibleGroupRange)) {
20847
- return;
20848
- }
20849
- const groupStart = getItemByIndex(this.dimensionCol.state, groupStartIndex).start;
20850
- const groupEnd = getItemByIndex(this.dimensionCol.state, groupEndIndex).end;
20934
+ const groupRange = this.getGroupIndexRange(group);
20935
+ const groupBounds = this.getGroupBounds(groupRange);
20851
20936
  const props = {
20937
+ level,
20852
20938
  providers: this.providers,
20853
- start: groupStart,
20854
- end: groupEnd,
20939
+ start: groupBounds.start,
20940
+ end: groupBounds.end,
20855
20941
  group,
20856
20942
  renderOffset: this.viewportCol.get('renderOffset') || 0,
20857
20943
  active: this.resizeHandler,
@@ -20859,15 +20945,57 @@ class RevogrHeaderComponent {
20859
20945
  additionalData: this.additionalData,
20860
20946
  onResize: e => {
20861
20947
  var _a;
20862
- return this.onResizeGroup((_a = e.changedX) !== null && _a !== void 0 ? _a : 0, groupStartIndex, groupEndIndex);
20948
+ return groupRange
20949
+ ? this.onResizeGroup((_a = e.changedX) !== null && _a !== void 0 ? _a : 0, groupRange.startIndex, groupRange.endIndex)
20950
+ : undefined;
20863
20951
  },
20864
20952
  };
20865
20953
  const event = this.beforeGroupHeaderRender.emit(props);
20866
20954
  if (event.defaultPrevented) {
20867
20955
  return;
20868
20956
  }
20957
+ const renderRange = this.getGroupIndexRange(event.detail.group);
20958
+ if (!renderRange ||
20959
+ !visibleGroupRange ||
20960
+ !isGroupInVisibleRange(renderRange.startIndex, renderRange.endIndex, visibleGroupRange)) {
20961
+ return;
20962
+ }
20963
+ if (event.detail.onResize === props.onResize) {
20964
+ event.detail.onResize = e => {
20965
+ var _a;
20966
+ return this.onResizeGroup((_a = e.changedX) !== null && _a !== void 0 ? _a : 0, renderRange.startIndex, renderRange.endIndex);
20967
+ };
20968
+ }
20969
+ const renderBounds = this.getGroupBounds(renderRange);
20970
+ if (event.detail.start === props.start) {
20971
+ event.detail.start = renderBounds.start;
20972
+ }
20973
+ if (event.detail.end === props.end) {
20974
+ event.detail.end = renderBounds.end;
20975
+ }
20869
20976
  return hAsync(HeaderGroupRenderer, Object.assign({ key: this.getGroupHeaderCellKey(event.detail.group, level) }, event.detail));
20870
20977
  }
20978
+ getGroupIndexRange(group) {
20979
+ var _a;
20980
+ const startIndex = (_a = group.indexes[0]) !== null && _a !== void 0 ? _a : -1;
20981
+ if (startIndex < 0) {
20982
+ return;
20983
+ }
20984
+ const endIndex = group.indexes[group.indexes.length - 1];
20985
+ return {
20986
+ startIndex,
20987
+ endIndex,
20988
+ };
20989
+ }
20990
+ getGroupBounds(range) {
20991
+ if (!range) {
20992
+ return { start: 0, end: 0 };
20993
+ }
20994
+ return {
20995
+ start: getItemByIndex(this.dimensionCol.state, range.startIndex).start,
20996
+ end: getItemByIndex(this.dimensionCol.state, range.endIndex).end,
20997
+ };
20998
+ }
20871
20999
  getVisibleGroupRange() {
20872
21000
  const visibleColumns = this.viewportCol.get('items');
20873
21001
  if (!visibleColumns.length) {
package/hydrate/index.mjs CHANGED
@@ -12643,6 +12643,9 @@ const GROUPING_ROW_TYPE = 'rgRow';
12643
12643
  function getGroupValueDefault(item, prop) {
12644
12644
  return item[prop] || null;
12645
12645
  }
12646
+ function isDataRow(item) {
12647
+ return item != null;
12648
+ }
12646
12649
  // get source based on proxy item collection to preserve rgRow order
12647
12650
  function getSource(source, items, withoutGrouping = false) {
12648
12651
  let index = 0;
@@ -12664,6 +12667,9 @@ function getSource(source, items, withoutGrouping = false) {
12664
12667
  result.prevExpanded[model[PSEUDO_GROUP_ITEM_VALUE]] = true;
12665
12668
  }
12666
12669
  }
12670
+ else if (!isDataRow(model)) {
12671
+ return;
12672
+ }
12667
12673
  else {
12668
12674
  result.source.push(model);
12669
12675
  result.oldNewIndexes[i] = index;
@@ -12744,6 +12750,9 @@ function flattenGroupMaps({ groupedValues, parentIds, isExpanded, itemIndex, exp
12744
12750
  function gatherGrouping(array, columnProps, { prevExpanded = {}, expandedAll = false, getGroupValue = getGroupValueDefault, }) {
12745
12751
  const groupedItems = new Map();
12746
12752
  array.forEach((item, originalIndex) => {
12753
+ if (!isDataRow(item)) {
12754
+ return;
12755
+ }
12747
12756
  const groupLevelValues = columnProps.map(groupId => getGroupValue(item, groupId));
12748
12757
  const lastLevelValue = groupLevelValues.pop();
12749
12758
  let currentGroupLevel = groupedItems;
@@ -17652,13 +17661,11 @@ class SelectionStoreConnector {
17652
17661
  return (_a = this.focusedStore) === null || _a === void 0 ? void 0 : _a.entity.store.get('range');
17653
17662
  }
17654
17663
  registerColumn(x, type) {
17664
+ this.updateColumnTypeMapping(x, type);
17655
17665
  if (this.columnStores[x]) {
17656
17666
  return this.columnStores[x];
17657
17667
  }
17658
17668
  this.columnStores[x] = new SelectionStore();
17659
- // build cross-linking type to position
17660
- this.storesByType[type] = x;
17661
- this.storesXToType[x] = type;
17662
17669
  return this.columnStores[x];
17663
17670
  }
17664
17671
  registerRow(y, type) {
@@ -17879,6 +17886,31 @@ class SelectionStoreConnector {
17879
17886
  }
17880
17887
  return stores;
17881
17888
  }
17889
+ /**
17890
+ * Keep column viewport positions and types in sync across pin/unpin rerenders.
17891
+ * Regression case: when a selected rgCol cell was pinned left, colPinStart
17892
+ * could take over x=0 and render the stale rgCol focus store in the pinned area.
17893
+ */
17894
+ updateColumnTypeMapping(x, type) {
17895
+ const previousType = this.storesXToType[x];
17896
+ const previousX = this.storesByType[type];
17897
+ let shouldClearFocus = false;
17898
+ this.storesByType[type] = x;
17899
+ this.storesXToType[x] = type;
17900
+ if (previousType && previousType !== type) {
17901
+ shouldClearFocus = true;
17902
+ if (this.storesByType[previousType] === x) {
17903
+ delete this.storesByType[previousType];
17904
+ }
17905
+ }
17906
+ if (typeof previousX === 'number' && previousX !== x && this.storesXToType[previousX] === type) {
17907
+ delete this.storesXToType[previousX];
17908
+ shouldClearFocus = true;
17909
+ }
17910
+ if (shouldClearFocus) {
17911
+ this.clearAll();
17912
+ }
17913
+ }
17882
17914
  }
17883
17915
 
17884
17916
  /**
@@ -19475,6 +19507,7 @@ class RevoGridComponent {
19475
19507
  if (!this.dimensionProvider || !this.columnProvider) {
19476
19508
  return;
19477
19509
  }
19510
+ const focusToRestore = init ? undefined : this.getColumnFocusRestore();
19478
19511
  const beforeGatherEvent = this.beforecolumnsgather.emit({
19479
19512
  columns: [...newVal],
19480
19513
  });
@@ -19492,6 +19525,9 @@ class RevoGridComponent {
19492
19525
  return;
19493
19526
  }
19494
19527
  const columns = this.columnProvider.setColumns(beforeApplyEvent.detail);
19528
+ if (focusToRestore) {
19529
+ this.pendingColumnFocusRestore = focusToRestore;
19530
+ }
19495
19531
  const order = {};
19496
19532
  for (const prop of Object.keys(beforeApplyEvent.detail.sort)) {
19497
19533
  order[prop] = beforeApplyEvent.detail.sort[prop].order;
@@ -19501,6 +19537,64 @@ class RevoGridComponent {
19501
19537
  order,
19502
19538
  });
19503
19539
  }
19540
+ /**
19541
+ * Capture logical focus before columns are repartitioned by pin state.
19542
+ * Regression case: selecting a regular cell, then pinning that column left,
19543
+ * used to let the new pinned viewport reuse the old rgCol selection store.
19544
+ */
19545
+ getColumnFocusRestore() {
19546
+ var _a, _b, _c, _d;
19547
+ const focused = (_a = this.viewport) === null || _a === void 0 ? void 0 : _a.getFocused();
19548
+ const prevStoreX = (_c = (_b = this.selectionStoreConnector) === null || _b === void 0 ? void 0 : _b.focusedStore) === null || _c === void 0 ? void 0 : _c.position.x;
19549
+ const prop = (_d = focused === null || focused === void 0 ? void 0 : focused.column) === null || _d === void 0 ? void 0 : _d.prop;
19550
+ if (!focused || prop === undefined || prevStoreX === undefined) {
19551
+ return;
19552
+ }
19553
+ return {
19554
+ prop,
19555
+ colType: focused.colType,
19556
+ colIndex: focused.cell.x,
19557
+ prevStoreX,
19558
+ rowType: focused.rowType,
19559
+ rowIndex: focused.cell.y,
19560
+ };
19561
+ }
19562
+ /**
19563
+ * Reapply focus by column prop after render, once pinning has moved the
19564
+ * column to its new viewport and virtual index.
19565
+ */
19566
+ restoreColumnFocusAfterRender() {
19567
+ var _a, _b, _c, _d;
19568
+ const pending = this.pendingColumnFocusRestore;
19569
+ if (!pending) {
19570
+ return;
19571
+ }
19572
+ this.pendingColumnFocusRestore = undefined;
19573
+ if (!this.viewport || !this.columnProvider) {
19574
+ return;
19575
+ }
19576
+ const column = (_b = (_a = this.columnProvider.getColumnByProp(pending.prop)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : getColumnByProp(this.columns, pending.prop);
19577
+ if (!column) {
19578
+ return;
19579
+ }
19580
+ const colType = column.pin || 'rgCol';
19581
+ const columnIndex = this.columnProvider.getColumnIndexByProp(pending.prop, colType);
19582
+ if (columnIndex < 0) {
19583
+ return;
19584
+ }
19585
+ // Header-only column refreshes should not collapse an existing range.
19586
+ // Replay focus only when pin/unpin or repartitioning moved the logical column.
19587
+ if (colType === pending.colType &&
19588
+ columnIndex === pending.colIndex &&
19589
+ pending.prevStoreX === ((_d = (_c = this.selectionStoreConnector) === null || _c === void 0 ? void 0 : _c.focusedStore) === null || _d === void 0 ? void 0 : _d.position.x)) {
19590
+ return;
19591
+ }
19592
+ const cell = {
19593
+ x: columnIndex,
19594
+ y: pending.rowIndex,
19595
+ };
19596
+ this.viewport.setFocus(colType, pending.rowType, cell, cell);
19597
+ }
19504
19598
  disableVirtualXChanged(newVal = false, prevVal = false) {
19505
19599
  if (newVal === prevVal) {
19506
19600
  return;
@@ -19813,6 +19907,7 @@ class RevoGridComponent {
19813
19907
  return Promise.all(this.jobsBeforeRender);
19814
19908
  }
19815
19909
  componentDidRender() {
19910
+ this.restoreColumnFocusAfterRender();
19816
19911
  this.aftergridrender.emit();
19817
19912
  }
19818
19913
  render() {
@@ -20834,22 +20929,13 @@ class RevogrHeaderComponent {
20834
20929
  ];
20835
20930
  }
20836
20931
  renderGroupColumn(group, level, visibleGroupRange) {
20837
- var _a;
20838
- const groupStartIndex = (_a = group.indexes[0]) !== null && _a !== void 0 ? _a : -1;
20839
- if (groupStartIndex < 0) {
20840
- return;
20841
- }
20842
- const groupEndIndex = groupStartIndex + group.indexes.length - 1;
20843
- if (!visibleGroupRange ||
20844
- !isGroupInVisibleRange(groupStartIndex, groupEndIndex, visibleGroupRange)) {
20845
- return;
20846
- }
20847
- const groupStart = getItemByIndex(this.dimensionCol.state, groupStartIndex).start;
20848
- const groupEnd = getItemByIndex(this.dimensionCol.state, groupEndIndex).end;
20932
+ const groupRange = this.getGroupIndexRange(group);
20933
+ const groupBounds = this.getGroupBounds(groupRange);
20849
20934
  const props = {
20935
+ level,
20850
20936
  providers: this.providers,
20851
- start: groupStart,
20852
- end: groupEnd,
20937
+ start: groupBounds.start,
20938
+ end: groupBounds.end,
20853
20939
  group,
20854
20940
  renderOffset: this.viewportCol.get('renderOffset') || 0,
20855
20941
  active: this.resizeHandler,
@@ -20857,15 +20943,57 @@ class RevogrHeaderComponent {
20857
20943
  additionalData: this.additionalData,
20858
20944
  onResize: e => {
20859
20945
  var _a;
20860
- return this.onResizeGroup((_a = e.changedX) !== null && _a !== void 0 ? _a : 0, groupStartIndex, groupEndIndex);
20946
+ return groupRange
20947
+ ? this.onResizeGroup((_a = e.changedX) !== null && _a !== void 0 ? _a : 0, groupRange.startIndex, groupRange.endIndex)
20948
+ : undefined;
20861
20949
  },
20862
20950
  };
20863
20951
  const event = this.beforeGroupHeaderRender.emit(props);
20864
20952
  if (event.defaultPrevented) {
20865
20953
  return;
20866
20954
  }
20955
+ const renderRange = this.getGroupIndexRange(event.detail.group);
20956
+ if (!renderRange ||
20957
+ !visibleGroupRange ||
20958
+ !isGroupInVisibleRange(renderRange.startIndex, renderRange.endIndex, visibleGroupRange)) {
20959
+ return;
20960
+ }
20961
+ if (event.detail.onResize === props.onResize) {
20962
+ event.detail.onResize = e => {
20963
+ var _a;
20964
+ return this.onResizeGroup((_a = e.changedX) !== null && _a !== void 0 ? _a : 0, renderRange.startIndex, renderRange.endIndex);
20965
+ };
20966
+ }
20967
+ const renderBounds = this.getGroupBounds(renderRange);
20968
+ if (event.detail.start === props.start) {
20969
+ event.detail.start = renderBounds.start;
20970
+ }
20971
+ if (event.detail.end === props.end) {
20972
+ event.detail.end = renderBounds.end;
20973
+ }
20867
20974
  return hAsync(HeaderGroupRenderer, Object.assign({ key: this.getGroupHeaderCellKey(event.detail.group, level) }, event.detail));
20868
20975
  }
20976
+ getGroupIndexRange(group) {
20977
+ var _a;
20978
+ const startIndex = (_a = group.indexes[0]) !== null && _a !== void 0 ? _a : -1;
20979
+ if (startIndex < 0) {
20980
+ return;
20981
+ }
20982
+ const endIndex = group.indexes[group.indexes.length - 1];
20983
+ return {
20984
+ startIndex,
20985
+ endIndex,
20986
+ };
20987
+ }
20988
+ getGroupBounds(range) {
20989
+ if (!range) {
20990
+ return { start: 0, end: 0 };
20991
+ }
20992
+ return {
20993
+ start: getItemByIndex(this.dimensionCol.state, range.startIndex).start,
20994
+ end: getItemByIndex(this.dimensionCol.state, range.endIndex).end,
20995
+ };
20996
+ }
20869
20997
  getVisibleGroupRange() {
20870
20998
  const visibleColumns = this.viewportCol.get('items');
20871
20999
  if (!visibleColumns.length) {