@revolist/revogrid 4.27.0 → 4.27.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 (55) hide show
  1. package/dist/cjs/{cell-renderer-C7rdgaov.js → cell-renderer-BDIx0xys.js} +1 -1
  2. package/dist/cjs/{column.service-Bbml5C2j.js → column.service-D-ENzqyb.js} +2 -0
  3. package/dist/cjs/{header-cell-renderer-BljFI6wj.js → header-cell-renderer-B5Y4fdZC.js} +1 -1
  4. package/dist/cjs/index.cjs.js +5 -4
  5. package/dist/cjs/loader.cjs.js +1 -1
  6. package/dist/cjs/revo-grid.cjs.entry.js +61 -41
  7. package/dist/cjs/revo-grid.cjs.js +1 -1
  8. package/dist/cjs/revogr-attribution_7.cjs.entry.js +1 -1
  9. package/dist/cjs/revogr-data_4.cjs.entry.js +3 -3
  10. package/dist/cjs/{row-resize.plugin-BRQy_qNn.js → row-resize.plugin-sK9_rcUN.js} +299 -180
  11. package/dist/collection/components/revoGrid/revo-grid.js +37 -21
  12. package/dist/collection/plugins/groupingRow/grouping.const.js +1 -0
  13. package/dist/collection/plugins/groupingRow/grouping.row.plugin.js +84 -54
  14. package/dist/collection/plugins/groupingRow/grouping.sorting.service.js +58 -0
  15. package/dist/collection/plugins/groupingRow/grouping.trimmed.service.js +5 -3
  16. package/dist/collection/plugins/row-resize/row-resize.plugin.js +144 -113
  17. package/dist/collection/plugins/sorting/sorting.plugin.js +16 -13
  18. package/dist/collection/plugins/wcag/index.js +5 -4
  19. package/dist/collection/services/dimension.provider.js +17 -1
  20. package/dist/esm/{cell-renderer-BFpmdV8H.js → cell-renderer-D9ze8OJw.js} +1 -1
  21. package/dist/esm/{column.service-CM-wgGs8.js → column.service-pu_fdQ0S.js} +2 -1
  22. package/dist/{revo-grid/header-cell-renderer-Bqh1PrgH.js → esm/header-cell-renderer-YCiVIQ2E.js} +1 -1
  23. package/dist/esm/index.js +5 -5
  24. package/dist/esm/loader.js +1 -1
  25. package/dist/esm/revo-grid.entry.js +61 -41
  26. package/dist/esm/revo-grid.js +1 -1
  27. package/dist/esm/revogr-attribution_7.entry.js +1 -1
  28. package/dist/esm/revogr-data_4.entry.js +3 -3
  29. package/dist/esm/{row-resize.plugin-BRiaHlHA.js → row-resize.plugin-DBOgjLdE.js} +300 -181
  30. package/dist/revo-grid/{cell-renderer-BFpmdV8H.js → cell-renderer-D9ze8OJw.js} +1 -1
  31. package/dist/revo-grid/{column.service-CM-wgGs8.js → column.service-pu_fdQ0S.js} +2 -1
  32. package/dist/{esm/header-cell-renderer-Bqh1PrgH.js → revo-grid/header-cell-renderer-YCiVIQ2E.js} +1 -1
  33. package/dist/revo-grid/index.esm.js +5 -5
  34. package/dist/revo-grid/revo-grid.entry.js +61 -41
  35. package/dist/revo-grid/revo-grid.esm.js +1 -1
  36. package/dist/revo-grid/revogr-attribution_7.entry.js +1 -1
  37. package/dist/revo-grid/revogr-data_4.entry.js +3 -3
  38. package/dist/revo-grid/{row-resize.plugin-BRiaHlHA.js → row-resize.plugin-DBOgjLdE.js} +300 -181
  39. package/dist/types/components/revoGrid/revo-grid.d.ts +2 -0
  40. package/dist/types/plugins/groupingRow/grouping.const.d.ts +1 -0
  41. package/dist/types/plugins/groupingRow/grouping.row.plugin.d.ts +5 -7
  42. package/dist/types/plugins/groupingRow/grouping.sorting.service.d.ts +7 -0
  43. package/dist/types/plugins/groupingRow/grouping.trimmed.service.d.ts +9 -0
  44. package/dist/types/plugins/row-resize/row-resize.plugin.d.ts +14 -12
  45. package/dist/types/plugins/sorting/sorting.plugin.d.ts +5 -0
  46. package/dist/types/services/dimension.provider.d.ts +7 -1
  47. package/hydrate/index.js +358 -218
  48. package/hydrate/index.mjs +358 -218
  49. package/package.json +1 -1
  50. package/standalone/column.service.js +1 -1
  51. package/standalone/index.js +1 -1
  52. package/standalone/revo-grid.js +1 -1
  53. package/standalone/revogr-data2.js +1 -1
  54. package/standalone/revogr-header2.js +1 -1
  55. package/standalone/revogr-overlay-selection2.js +1 -1
@@ -1,14 +1,14 @@
1
1
  /*!
2
2
  * Built by Revolist OU ❤️
3
3
  */
4
- import { J as reduce, g as getRange, K as baseEach, C as getColumnType, c as columnTypes, L as toInteger, u as isGrouping, t as getGroupingName, r as rowTypes, A as getCellRaw, j as GROUP_COLUMN_PROP, I as getColumnByProp, h as GROUP_EXPANDED, x as getParsedGroup, y as isSameGroup, G as GROUP_DEPTH, e as PSEUDO_GROUP_ITEM_VALUE, d as PSEUDO_GROUP_ITEM_ID, o as GROUPING_ROW_TYPE, p as getSource, f as PSEUDO_GROUP_COLUMN, s as gatherGrouping, m as GROUP_EXPAND_EVENT, v as isGroupingColumn, q as getExpanded, E as isColGrouping } from './column.service-CM-wgGs8.js';
4
+ import { K as reduce, g as getRange, L as baseEach, D as getColumnType, c as columnTypes, M as toInteger, u as isGrouping, t as getGroupingName, r as rowTypes, G as GROUP_DEPTH, A as getCellRaw, j as GROUP_COLUMN_PROP, J as getColumnByProp, h as GROUP_EXPANDED, x as getParsedGroup, y as isSameGroup, e as PSEUDO_GROUP_ITEM_VALUE, d as PSEUDO_GROUP_ITEM_ID, o as GROUPING_ROW_TYPE, f as PSEUDO_GROUP_COLUMN, p as getSource, s as gatherGrouping, B as BEFORE_GROUPING_APPLY_EVENT, m as GROUP_EXPAND_EVENT, v as isGroupingColumn, q as getExpanded, F as isColGrouping } from './column.service-pu_fdQ0S.js';
5
5
  import { L as createStore, m as setStore, j as calculateDimensionData, N as identity, O as isArray, b as getSourceItem, g as getPhysical, e as setItems, k as getItemByPosition, l as getItemByIndex } from './dimension.helpers-Cln9sALu.js';
6
- import { j as calculateRowHeaderSize } from './viewport.store-DWMKRDSH.js';
6
+ import { j as calculateRowHeaderSize, g as getViewportMaxCoordinate } from './viewport.store-DWMKRDSH.js';
7
7
  import { g as getScrollbarSize, t as timeout } from './index-BvMNbQyq.js';
8
8
  import { h } from './index-CtimkLsB.js';
9
9
  import { b as FILTER_PROP, i as isFilterBtn } from './filter.button-DMhpuAiw.js';
10
10
  import { d as debounce } from './debounce-PCRWZliA.js';
11
- import { O as ON_COLUMN_CLICK, d as dispatch } from './header-cell-renderer-Bqh1PrgH.js';
11
+ import { O as ON_COLUMN_CLICK, d as dispatch } from './header-cell-renderer-YCiVIQ2E.js';
12
12
 
13
13
  /**
14
14
  * Public theme tokens and their CSS custom-property counterparts.
@@ -1907,6 +1907,60 @@ function allAndConditionsSatisfied(pendingResults) {
1907
1907
  return !pendingResults.includes(true);
1908
1908
  }
1909
1909
 
1910
+ /**
1911
+ * Restores group headers around already-sorted data indexes without rebuilding
1912
+ * the physical source. Group insertion order follows the first sorted member,
1913
+ * matching the order produced by regrouping a sorted source.
1914
+ */
1915
+ function gatherGroupedRowIndexes(source, sortedDataIndexes) {
1916
+ const groupPathByDataIndex = new Map();
1917
+ const currentGroupPath = [];
1918
+ source.forEach((model, physicalIndex) => {
1919
+ if (isGrouping(model)) {
1920
+ const depth = model[GROUP_DEPTH];
1921
+ if (typeof depth !== 'number') {
1922
+ return;
1923
+ }
1924
+ currentGroupPath.length = depth;
1925
+ currentGroupPath[depth] = physicalIndex;
1926
+ return;
1927
+ }
1928
+ if (model != null) {
1929
+ groupPathByDataIndex.set(physicalIndex, [...currentGroupPath]);
1930
+ }
1931
+ });
1932
+ const root = {
1933
+ children: new Map(),
1934
+ items: [],
1935
+ };
1936
+ for (const physicalIndex of sortedDataIndexes) {
1937
+ const groupPath = groupPathByDataIndex.get(physicalIndex);
1938
+ if (!(groupPath === null || groupPath === void 0 ? void 0 : groupPath.length)) {
1939
+ return undefined;
1940
+ }
1941
+ let node = root;
1942
+ for (const groupIndex of groupPath) {
1943
+ let child = node.children.get(groupIndex);
1944
+ if (!child) {
1945
+ child = { children: new Map(), items: [] };
1946
+ node.children.set(groupIndex, child);
1947
+ }
1948
+ node = child;
1949
+ }
1950
+ node.items.push(physicalIndex);
1951
+ }
1952
+ const groupedIndexes = [];
1953
+ const appendNode = (node) => {
1954
+ node.children.forEach((child, groupIndex) => {
1955
+ groupedIndexes.push(groupIndex);
1956
+ appendNode(child);
1957
+ });
1958
+ groupedIndexes.push(...node.items);
1959
+ };
1960
+ appendNode(root);
1961
+ return groupedIndexes;
1962
+ }
1963
+
1910
1964
  /**
1911
1965
  * Checks whether a sorting map contains at least one active order.
1912
1966
  *
@@ -2144,18 +2198,6 @@ function getComparer(column, order) {
2144
2198
  function getSortableRowIndexes(indexes, source) {
2145
2199
  return indexes.filter(index => !isGrouping(source[index]));
2146
2200
  }
2147
- function mergeSortedRowsWithGroups(indexes, source, sortedRows) {
2148
- if (sortedRows.length === indexes.length) {
2149
- return sortedRows;
2150
- }
2151
- let rowIndex = 0;
2152
- return indexes.map(index => {
2153
- if (isGrouping(source[index])) {
2154
- return index;
2155
- }
2156
- return sortedRows[rowIndex++];
2157
- });
2158
- }
2159
2201
  /**
2160
2202
  * Lifecycle
2161
2203
  * 1. @event `beforesorting` - Triggered when sorting just starts. Nothing has happened yet. This can be triggered from a column or from the source. If the type is from rows, the column will be undefined.
@@ -2315,6 +2357,7 @@ class SortingPlugin extends BasePlugin {
2315
2357
  storeService.setData({ proxyItems: newItemsOrder });
2316
2358
  }
2317
2359
  applySortingForStore(type, sorting, sortingFunc, sortingColumns, sortingOrder, ignoreViewportUpdate) {
2360
+ var _a;
2318
2361
  const storeService = this.providers.data.stores[type];
2319
2362
  // row data
2320
2363
  const source = storeService.store.get('source');
@@ -2322,7 +2365,10 @@ class SortingPlugin extends BasePlugin {
2322
2365
  const proxyItems = storeService.store.get('proxyItems');
2323
2366
  const sortItems = getSortableRowIndexes(proxyItems, source);
2324
2367
  const sortedItems = sortIndexByItems([...sortItems], source, sortingFunc, sorting, sortingColumns, sortingOrder);
2325
- const newItemsOrder = mergeSortedRowsWithGroups(proxyItems, source, sortedItems);
2368
+ const hasGroupingRows = sortedItems.length !== proxyItems.length;
2369
+ const newItemsOrder = hasGroupingRows
2370
+ ? (_a = gatherGroupedRowIndexes(source, sortedItems)) !== null && _a !== void 0 ? _a : proxyItems
2371
+ : sortedItems;
2326
2372
  // take row indexes before trim applied and proxy items
2327
2373
  const prevItems = storeService.store.get('items');
2328
2374
  storeService.setData({
@@ -2348,6 +2394,16 @@ class SortingPlugin extends BasePlugin {
2348
2394
  }
2349
2395
  this.postponeSort(order, sortingFunc, sortingColumns, sortingOrder, ignoreViewportUpdate);
2350
2396
  }
2397
+ /**
2398
+ * Schedules the current active sort again after another plugin rebuilds row
2399
+ * proxy indexes while keeping the physical source unchanged.
2400
+ */
2401
+ reapplySorting() {
2402
+ if (!hasActiveSorting(this.sorting) || !this.sortingFunc) {
2403
+ return;
2404
+ }
2405
+ this.startSorting(this.sorting, this.sortingFunc, this.sortingColumns, this.sortingOrder);
2406
+ }
2351
2407
  /**
2352
2408
  * Applies sorting requested by a sortable header click.
2353
2409
  *
@@ -2531,8 +2587,10 @@ const TRIMMED_GROUPING = 'grouping';
2531
2587
  * against the grouped physical source can still be remapped. If neither path
2532
2588
  * resolves to a number, the caller drops the stale trim entry.
2533
2589
  */
2534
- function convertTrimmedIndex(initialIndex, firstLevelMap, secondLevelMap) {
2535
- const sourceIndex = Number.parseInt(initialIndex, 10);
2590
+ function convertGroupingIndex(initialIndex, firstLevelMap, secondLevelMap) {
2591
+ const sourceIndex = typeof initialIndex === 'number'
2592
+ ? initialIndex
2593
+ : Number.parseInt(initialIndex, 10);
2536
2594
  const firstConversionIndex = firstLevelMap[sourceIndex];
2537
2595
  if (!secondLevelMap) {
2538
2596
  return firstConversionIndex;
@@ -2565,7 +2623,7 @@ function processDoubleConversionTrimmed(initiallyTrimed, firstLevelMap, secondLe
2565
2623
  * if item exists we find it in collection
2566
2624
  * we support 2 level of conversions
2567
2625
  */
2568
- const newConversionIndex = convertTrimmedIndex(initialIndex, firstLevelMap, secondLevelMap);
2626
+ const newConversionIndex = convertGroupingIndex(initialIndex, firstLevelMap, secondLevelMap);
2569
2627
  // Group rows do not exist in the ungrouped index map and must not leak into new trims.
2570
2628
  if (typeof newConversionIndex !== 'number') {
2571
2629
  continue;
@@ -2626,18 +2684,6 @@ function filterOutEmptyGroupRows(source, filterTrimmed) {
2626
2684
  return trimmed;
2627
2685
  }
2628
2686
 
2629
- var __rest = (undefined && undefined.__rest) || function (s, e) {
2630
- var t = {};
2631
- for (var p in s)
2632
- if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
2633
- t[p] = s[p];
2634
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
2635
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
2636
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
2637
- t[p[i]] = s[p[i]];
2638
- }
2639
- return t;
2640
- };
2641
2687
  class GroupingRowPlugin extends BasePlugin {
2642
2688
  getStore(type = GROUPING_ROW_TYPE) {
2643
2689
  return this.providers.data.stores[type].store;
@@ -2653,15 +2699,16 @@ class GroupingRowPlugin extends BasePlugin {
2653
2699
  }
2654
2700
  // expand event triggered
2655
2701
  onExpand({ virtualIndex }) {
2656
- const { source } = getSource(this.getStore().get('source'), this.getStore().get('proxyItems'));
2657
- let newTrimmed = this.getStore().get('trimmed')[TRIMMED_GROUPING];
2658
- let i = getPhysical(this.getStore(), virtualIndex);
2702
+ const store = this.getStore();
2703
+ const source = store.get('source');
2704
+ let newTrimmed = store.get('trimmed')[TRIMMED_GROUPING];
2705
+ const i = getPhysical(store, virtualIndex);
2659
2706
  const isExpanded = getExpanded(source[i]);
2660
2707
  if (!isExpanded) {
2661
- const { trimmed, items } = doExpand(virtualIndex, source, this.getStore().get('items'));
2708
+ const { trimmed, items: expandedItems } = doExpand(virtualIndex, source, store.get('items'));
2662
2709
  newTrimmed = Object.assign(Object.assign({}, newTrimmed), trimmed);
2663
- if (items) {
2664
- setItems(this.getStore(), items);
2710
+ if (expandedItems) {
2711
+ setItems(store, expandedItems);
2665
2712
  }
2666
2713
  }
2667
2714
  else {
@@ -2669,7 +2716,7 @@ class GroupingRowPlugin extends BasePlugin {
2669
2716
  newTrimmed = Object.assign(Object.assign({}, newTrimmed), trimmed);
2670
2717
  this.revogrid.clearFocus();
2671
2718
  }
2672
- this.getStore().set('source', source);
2719
+ store.set('source', source);
2673
2720
  this.revogrid.addTrimmed(newTrimmed, TRIMMED_GROUPING);
2674
2721
  }
2675
2722
  setColumnGrouping(cols) {
@@ -2691,7 +2738,7 @@ class GroupingRowPlugin extends BasePlugin {
2691
2738
  onDrag(e) {
2692
2739
  const { from, to } = e.detail;
2693
2740
  const isDown = to - from >= 0;
2694
- const { source } = getSource(this.getStore().get('source'), this.getStore().get('proxyItems'));
2741
+ const source = this.getStore().get('source');
2695
2742
  const items = this.getStore().get('items');
2696
2743
  let i = isDown ? from : to;
2697
2744
  const end = isDown ? to : from;
@@ -2717,21 +2764,13 @@ class GroupingRowPlugin extends BasePlugin {
2717
2764
  const source = this.getStore().get('source');
2718
2765
  return filterOutEmptyGroupRows(source, trimmed);
2719
2766
  }
2720
- isSortingRunning() {
2721
- const sortingPlugin = this.providers.plugins.getByClass(SortingPlugin);
2722
- return !!(sortingPlugin === null || sortingPlugin === void 0 ? void 0 : sortingPlugin.sortingPromise);
2723
- }
2724
2767
  /**
2725
- * Returns grouping options for regrouping that must preserve current UI state.
2726
- *
2727
- * `expandedAll` and config `prevExpanded` are initial/config instructions.
2728
- * Reusing them after sorting would reopen groups the user collapsed before
2729
- * sorting instead of using the current grouped source state.
2768
+ * Sorting changes proxy order without changing the physical source baseline.
2769
+ * Other proxy changes, such as row dragging, are user-authored source order
2770
+ * and must be retained when grouping is rebuilt.
2730
2771
  */
2731
- getCurrentExpandedOptions() {
2732
- var _a;
2733
- const _b = (_a = this.options) !== null && _a !== void 0 ? _a : {}, options = __rest(_b, ["expandedAll", "prevExpanded"]);
2734
- return options;
2772
+ isSortingActiveOrPending(sortingPlugin) {
2773
+ return !!(sortingPlugin === null || sortingPlugin === void 0 ? void 0 : sortingPlugin.sortingPromise) || hasActiveSorting(sortingPlugin === null || sortingPlugin === void 0 ? void 0 : sortingPlugin.sorting);
2735
2774
  }
2736
2775
  /**
2737
2776
  * Starts global source update with group clearing and applying new one
@@ -2744,7 +2783,12 @@ class GroupingRowPlugin extends BasePlugin {
2744
2783
  * @param newOldIndexMap - provides us mapping with new indexes vs old indexes, we would use it for trimmed mapping
2745
2784
  */
2746
2785
  const store = this.getStore();
2747
- const { source, prevExpanded, oldNewIndexes } = getSource(store.get('source'), store.get('proxyItems'), true);
2786
+ const sortingPlugin = this.providers.plugins.getByClass(SortingPlugin);
2787
+ const currentSource = store.get('source');
2788
+ const sourceItems = this.isSortingActiveOrPending(sortingPlugin)
2789
+ ? currentSource.map((_, index) => index)
2790
+ : store.get('proxyItems');
2791
+ const { source, prevExpanded, oldNewIndexes } = getSource(currentSource, sourceItems, true);
2748
2792
  const expanded = Object.assign({ prevExpanded }, options);
2749
2793
  /**
2750
2794
  * Group again
@@ -2754,8 +2798,13 @@ class GroupingRowPlugin extends BasePlugin {
2754
2798
  const customRenderer = options === null || options === void 0 ? void 0 : options.groupLabelTemplate;
2755
2799
  const cellRenderer = options === null || options === void 0 ? void 0 : options.groupCellTemplate;
2756
2800
  // setup source
2801
+ this.revogrid.dispatchEvent(new CustomEvent(BEFORE_GROUPING_APPLY_EVENT));
2757
2802
  this.providers.data.setData(sourceWithGroups, GROUPING_ROW_TYPE, this.revogrid.disableVirtualY, { depth, customRenderer, cellRenderer }, true);
2803
+ this.remapRowDefinitions(oldNewIndexes !== null && oldNewIndexes !== void 0 ? oldNewIndexes : {}, oldNewIndexMap, currentSource, sourceWithGroups);
2758
2804
  this.updateTrimmed(trimmed, oldNewIndexes !== null && oldNewIndexes !== void 0 ? oldNewIndexes : {}, oldNewIndexMap, sourceWithGroups);
2805
+ if (hasActiveSorting(sortingPlugin === null || sortingPlugin === void 0 ? void 0 : sortingPlugin.sorting)) {
2806
+ sortingPlugin === null || sortingPlugin === void 0 ? void 0 : sortingPlugin.reapplySorting();
2807
+ }
2759
2808
  }
2760
2809
  /**
2761
2810
  * Apply grouping on data set
@@ -2764,9 +2813,14 @@ class GroupingRowPlugin extends BasePlugin {
2764
2813
  */
2765
2814
  onDataSet(data) {
2766
2815
  var _a, _b, _c;
2816
+ const currentSource = this.getStore().get('source');
2817
+ const sortingPlugin = this.providers.plugins.getByClass(SortingPlugin);
2818
+ const currentItems = this.isSortingActiveOrPending(sortingPlugin)
2819
+ ? currentSource.map((_, index) => index)
2820
+ : this.getStore().get('proxyItems');
2821
+ const { prevExpanded, oldNewIndexes } = getSource(currentSource, currentItems, true);
2767
2822
  let preservedExpanded = {};
2768
2823
  if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.preserveGroupingOnUpdate) !== false) {
2769
- let { prevExpanded } = getSource(this.getStore().get('source'), this.getStore().get('proxyItems'), true);
2770
2824
  preservedExpanded = prevExpanded;
2771
2825
  }
2772
2826
  const source = data.source.filter(s => !isGrouping(s));
@@ -2778,6 +2832,7 @@ class GroupingRowPlugin extends BasePlugin {
2778
2832
  customRenderer: options.groupLabelTemplate,
2779
2833
  cellRenderer: options.groupCellTemplate,
2780
2834
  });
2835
+ queueMicrotask(() => this.remapRowDefinitions(oldNewIndexes !== null && oldNewIndexes !== void 0 ? oldNewIndexes : {}, oldNewIndexMap, currentSource, sourceWithGroups));
2781
2836
  this.updateTrimmed(trimmed, oldNewIndexMap, undefined, sourceWithGroups, { filterTrimmedMode: 'recompute-after-source-set' });
2782
2837
  }
2783
2838
  /**
@@ -2813,10 +2868,6 @@ class GroupingRowPlugin extends BasePlugin {
2813
2868
  if (!(((_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b.length) && ((_c = detail === null || detail === void 0 ? void 0 : detail.source) === null || _c === void 0 ? void 0 : _c.length))) {
2814
2869
  return;
2815
2870
  }
2816
- // if sorting is running don't apply grouping, wait for sorting, then it'll apply in @aftersortingapply
2817
- if (this.isSortingRunning()) {
2818
- return;
2819
- }
2820
2871
  this.onDataSet(detail);
2821
2872
  });
2822
2873
  this.addEventListener('beforecolumnsset', ({ detail }) => {
@@ -2831,17 +2882,6 @@ class GroupingRowPlugin extends BasePlugin {
2831
2882
  this.addEventListener('beforefiltertrimmed', ({ detail }) => {
2832
2883
  detail.itemsToFilter = this.beforeFilterTrimmed(detail.itemsToFilter);
2833
2884
  });
2834
- /**
2835
- * sorting applied need to clear grouping and apply again
2836
- * based on new results whole grouping order will changed
2837
- */
2838
- this.addEventListener('aftersortingapply', () => {
2839
- var _a, _b;
2840
- if (!((_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.props) === null || _b === void 0 ? void 0 : _b.length)) {
2841
- return;
2842
- }
2843
- this.doSourceUpdate(this.getCurrentExpandedOptions());
2844
- });
2845
2885
  /**
2846
2886
  * Apply logic for focus inside of grouping
2847
2887
  * We can't focus on grouping rows, navigation only inside of groups for now
@@ -2874,9 +2914,57 @@ class GroupingRowPlugin extends BasePlugin {
2874
2914
  }
2875
2915
  });
2876
2916
  // clear rows
2877
- const { source, oldNewIndexes } = getSource(this.getStore().get('source'), this.getStore().get('proxyItems'), true);
2917
+ const store = this.getStore();
2918
+ const sortingPlugin = this.providers.plugins.getByClass(SortingPlugin);
2919
+ const currentSource = store.get('source');
2920
+ const sourceItems = this.isSortingActiveOrPending(sortingPlugin)
2921
+ ? currentSource.map((_, index) => index)
2922
+ : store.get('proxyItems');
2923
+ const { source, oldNewIndexes } = getSource(currentSource, sourceItems, true);
2924
+ this.revogrid.dispatchEvent(new CustomEvent(BEFORE_GROUPING_APPLY_EVENT));
2878
2925
  this.providers.data.setData(source, GROUPING_ROW_TYPE, this.revogrid.disableVirtualY, undefined, true);
2926
+ this.remapRowDefinitions(oldNewIndexes !== null && oldNewIndexes !== void 0 ? oldNewIndexes : {}, undefined, currentSource, source);
2879
2927
  this.updateTrimmed(undefined, undefined, oldNewIndexes, source);
2928
+ if (hasActiveSorting(sortingPlugin === null || sortingPlugin === void 0 ? void 0 : sortingPlugin.sorting)) {
2929
+ sortingPlugin === null || sortingPlugin === void 0 ? void 0 : sortingPlugin.reapplySorting();
2930
+ }
2931
+ }
2932
+ remapRowDefinitions(firstLevelMap, secondLevelMap, previousSource, nextSource) {
2933
+ const definitions = this.providers.dimension.getRowDefinitions();
2934
+ const nextGroupIndexes = new Map();
2935
+ nextSource === null || nextSource === void 0 ? void 0 : nextSource.forEach((row, index) => {
2936
+ const groupId = row[PSEUDO_GROUP_ITEM_ID];
2937
+ if (groupId && !nextGroupIndexes.has(groupId)) {
2938
+ nextGroupIndexes.set(groupId, index);
2939
+ }
2940
+ });
2941
+ let changed = false;
2942
+ const remapped = definitions.flatMap(definition => {
2943
+ if (definition.type !== GROUPING_ROW_TYPE) {
2944
+ return [definition];
2945
+ }
2946
+ const previousRow = previousSource === null || previousSource === void 0 ? void 0 : previousSource[definition.index];
2947
+ const groupId = previousRow === null || previousRow === void 0 ? void 0 : previousRow[PSEUDO_GROUP_ITEM_ID];
2948
+ const index = groupId
2949
+ ? nextGroupIndexes.get(groupId)
2950
+ : convertGroupingIndex(definition.index, firstLevelMap, secondLevelMap);
2951
+ if (typeof index !== 'number') {
2952
+ changed = true;
2953
+ return [];
2954
+ }
2955
+ if (index < 0) {
2956
+ changed = true;
2957
+ return [];
2958
+ }
2959
+ if (index === definition.index) {
2960
+ return [definition];
2961
+ }
2962
+ changed = true;
2963
+ return [Object.assign(Object.assign({}, definition), { index })];
2964
+ });
2965
+ if (changed) {
2966
+ this.providers.dimension.setRowDefinitions(remapped);
2967
+ }
2880
2968
  }
2881
2969
  updateTrimmed(trimmedGroup = {}, firstLevelMap = {}, secondLevelMap, source = this.getStore().get('source'), { filterTrimmedMode = 'remap', } = {}) {
2882
2970
  // map previously trimmed data
@@ -3217,18 +3305,14 @@ const ROW_RESIZE_EVENT = 'rowresize';
3217
3305
  const AFTER_ROW_RESIZE_EVENT = 'afterrowresize';
3218
3306
  const ROW_RESIZE_CANCEL_EVENT = 'rowresizecancel';
3219
3307
  class RowResizePlugin extends BasePlugin {
3220
- static fromGridProperty(revogrid, providers) {
3221
- const plugin = new RowResizePlugin(revogrid, providers);
3222
- plugin.controlFromGridProperty();
3223
- return plugin;
3224
- }
3225
3308
  constructor(revogrid, providers, config = {}) {
3226
3309
  super(revogrid, providers);
3227
3310
  this.enabled = false;
3228
- this.gridResizeRow = false;
3229
- this.gridPlugins = [];
3230
- this.committedSizes = new Map();
3231
- this.appliedIndexes = new Map();
3311
+ this.appliedDefinitionIndexes = new Map();
3312
+ this.pendingBottomAnchor = false;
3313
+ this.keepBottomAnchor = false;
3314
+ this.rowDefinitionRemapQueued = false;
3315
+ this.pendingSourceCounts = new Map();
3232
3316
  this.previousBodyCursor = '';
3233
3317
  this.decorateRow = ({ detail, }) => {
3234
3318
  if (!this.enabled ||
@@ -3292,22 +3376,72 @@ class RowResizePlugin extends BasePlugin {
3292
3376
  }
3293
3377
  };
3294
3378
  this.onWindowBlur = () => this.cancel('blur');
3295
- this.reapplyCommittedSizes = () => this.applyCommittedSizes(false);
3296
- this.rebuildCommittedSizes = () => this.applyCommittedSizes(true);
3297
- this.syncAppliedIndexes = () => {
3298
- for (const [rowType, committed] of this.committedSizes) {
3379
+ this.updateBottomAnchorState = ({ detail, }) => {
3380
+ if (detail.dimension !== 'rgRow') {
3381
+ return;
3382
+ }
3383
+ this.keepBottomAnchor = this.isMainViewportAtBottom(detail.coordinate);
3384
+ };
3385
+ this.applyPendingBottomAnchor = () => {
3386
+ if (!this.pendingBottomAnchor) {
3387
+ return;
3388
+ }
3389
+ this.pendingBottomAnchor = false;
3390
+ const dimension = this.providers.dimension.stores.rgRow.store;
3391
+ // Scroll surfaces have slightly different client sizes. Give the shared
3392
+ // scrolling service the content end and let each surface clamp to its own
3393
+ // exact bottom coordinate.
3394
+ void this.revogrid.scrollToCoordinate({ y: dimension.get('realSize') });
3395
+ };
3396
+ this.scheduleRowDefinitionRemap = () => {
3397
+ if (this.rowDefinitionRemapQueued) {
3398
+ return;
3399
+ }
3400
+ this.rowDefinitionRemapQueued = true;
3401
+ queueMicrotask(() => {
3402
+ if (!this.rowDefinitionRemapQueued) {
3403
+ return;
3404
+ }
3405
+ this.pruneRowDefinitions();
3406
+ this.reapplyRowDefinitionSizes();
3407
+ this.rowDefinitionRemapQueued = false;
3408
+ });
3409
+ };
3410
+ /** Map source-indexed row definitions back onto the current virtual order. */
3411
+ this.reapplyRowDefinitionSizes = () => {
3412
+ const rowDefinitions = this.providers.dimension.getRowDefinitions();
3413
+ for (const rowType of rowTypes) {
3299
3414
  const items = this.providers.data.stores[rowType].store.get('items');
3415
+ const definitions = new Map(rowDefinitions
3416
+ .filter(definition => definition.type === rowType)
3417
+ .map(definition => [definition.index, definition.size]));
3418
+ const appliedIndexes = this.appliedDefinitionIndexes.get(rowType);
3419
+ if (!definitions.size && !(appliedIndexes === null || appliedIndexes === void 0 ? void 0 : appliedIndexes.size)) {
3420
+ continue;
3421
+ }
3422
+ const dimension = this.providers.dimension.stores[rowType];
3423
+ const currentSizes = dimension.store.get('sizes');
3424
+ const sizes = Object.assign({}, currentSizes);
3425
+ for (const index of appliedIndexes || []) {
3426
+ delete sizes[index];
3427
+ }
3300
3428
  const indexes = new Set();
3301
3429
  items.forEach((physicalIndex, virtualIndex) => {
3302
- if (committed.has(physicalIndex)) {
3430
+ const size = definitions.get(physicalIndex);
3431
+ if (size !== undefined) {
3432
+ sizes[virtualIndex] = size;
3303
3433
  indexes.add(virtualIndex);
3304
3434
  }
3305
3435
  });
3306
- this.appliedIndexes.set(rowType, indexes);
3436
+ this.appliedDefinitionIndexes.set(rowType, indexes);
3437
+ const sizeKeys = Object.keys(sizes);
3438
+ if (sizeKeys.length !== Object.keys(currentSizes).length ||
3439
+ sizeKeys.some(index => sizes[index] !== currentSizes[index])) {
3440
+ this.providers.dimension.setCustomSizes(rowType, sizes);
3441
+ }
3307
3442
  }
3308
3443
  };
3309
3444
  this.config = resolveRowResizeConfig(config);
3310
- this.rowDefinitionsRef = revogrid.rowDefinitions;
3311
3445
  if (new.target !== RowResizePlugin) {
3312
3446
  this.enabled = true;
3313
3447
  this.registerEventListeners();
@@ -3315,77 +3449,53 @@ class RowResizePlugin extends BasePlugin {
3315
3449
  }
3316
3450
  registerEventListeners() {
3317
3451
  this.addEventListener('beforerowrender', this.decorateRow);
3318
- this.addEventListener('beforeanysource', ({ detail }) => {
3452
+ this.addEventListener('beforeanysource', () => {
3319
3453
  this.cancel('data-change');
3320
- const committed = this.committedSizes.get(detail.type);
3321
- if (!committed) {
3322
- return;
3323
- }
3324
- const removedIndexes = new Set();
3325
- for (const index of committed.keys()) {
3326
- if (index >= detail.source.length) {
3327
- committed.delete(index);
3328
- removedIndexes.add(index);
3329
- }
3330
- }
3331
- if (removedIndexes.size) {
3332
- const rowDefinitions = this.revogrid.rowDefinitions.filter(definition => definition.type !== detail.type ||
3333
- !removedIndexes.has(definition.index));
3334
- this.rowDefinitionsRef = rowDefinitions;
3335
- this.revogrid.rowDefinitions = rowDefinitions;
3336
- }
3454
+ this.keepBottomAnchor = false;
3455
+ });
3456
+ this.addEventListener('afteranysource', ({ detail }) => {
3457
+ this.pendingSourceCounts.set(detail.type, detail.source.length);
3458
+ this.scheduleRowDefinitionRemap();
3337
3459
  });
3338
- this.addEventListener('afteranysource', this.rebuildCommittedSizes);
3339
3460
  this.addEventListener('beforesourcesortingapply', this.cancelForDataChange);
3340
- this.addEventListener('aftersortingapply', this.reapplyCommittedSizes);
3461
+ this.addEventListener('beforesortingapply', this.cancelForDataChange);
3462
+ this.addEventListener('sortingconfigchanged', this.cancelForDataChange);
3463
+ this.addEventListener(BEFORE_GROUPING_APPLY_EVENT, this.cancelForDataChange);
3464
+ this.addEventListener('aftersortingapply', this.scheduleRowDefinitionRemap);
3341
3465
  this.addEventListener('beforefilterapply', this.cancelForDataChange);
3342
- this.addEventListener('beforerowdefinition', ({ detail }) => {
3466
+ this.addEventListener('afterfilterapply', this.scheduleRowDefinitionRemap);
3467
+ this.addEventListener('beforerowdefinition', () => {
3343
3468
  this.cancel('data-change');
3344
- if (detail.vals !== this.rowDefinitionsRef) {
3345
- this.committedSizes.clear();
3346
- this.appliedIndexes.clear();
3347
- this.rowDefinitionsRef = detail.vals;
3348
- }
3349
- });
3350
- this.addEventListener('afterthemechanged', this.reapplyCommittedSizes);
3351
- this.addEventListener('aftertrimmed', this.syncAppliedIndexes);
3352
- this.addEventListener('roworderchange', () => {
3353
- queueMicrotask(this.reapplyCommittedSizes);
3469
+ this.scheduleRowDefinitionRemap();
3354
3470
  });
3471
+ this.addEventListener('afterthemechanged', this.scheduleRowDefinitionRemap);
3472
+ this.addEventListener('aftertrimmed', this.scheduleRowDefinitionRemap);
3473
+ this.addEventListener('roworderchange', this.scheduleRowDefinitionRemap);
3355
3474
  this.addEventListener(GROUP_EXPAND_EVENT, () => {
3356
- queueMicrotask(this.reapplyCommittedSizes);
3475
+ if (this.keepBottomAnchor) {
3476
+ this.pendingBottomAnchor = true;
3477
+ }
3478
+ this.scheduleRowDefinitionRemap();
3357
3479
  });
3480
+ this.addEventListener('aftergridrender', this.applyPendingBottomAnchor);
3481
+ this.addEventListener('viewportscroll', this.updateBottomAnchorState);
3358
3482
  this.addEventListener('rowheaderschanged', ({ detail }) => {
3359
3483
  if (!detail && !this.config.fullRow) {
3360
3484
  this.cancel('row-headers-hidden');
3361
3485
  }
3362
3486
  });
3363
3487
  }
3364
- controlFromGridProperty() {
3365
- this.gridResizeRow = this.revogrid.resizeRow;
3366
- this.gridPlugins = this.revogrid.plugins;
3367
- this.syncGridProperty(false);
3368
- this.watch('resizeRow', value => {
3369
- this.gridResizeRow = value;
3370
- this.syncGridProperty();
3371
- });
3372
- this.watch('plugins', value => {
3373
- this.gridPlugins = value || [];
3374
- this.syncGridProperty();
3375
- });
3376
- }
3377
- syncGridProperty(refresh = true) {
3378
- const hasConfiguredPlugin = this.gridPlugins.some(plugin => plugin !== RowResizePlugin &&
3488
+ syncGridConfig(refresh = true) {
3489
+ const { plugins = [], resizeRow } = this.revogrid;
3490
+ const isCorePlugin = this.constructor === RowResizePlugin;
3491
+ const hasConfiguredPlugin = plugins.some(plugin => plugin !== RowResizePlugin &&
3379
3492
  plugin.prototype instanceof RowResizePlugin);
3380
- const explicitlyEnabled = this.gridPlugins.includes(RowResizePlugin);
3381
- const enabled = hasConfiguredPlugin
3382
- ? false
3383
- : explicitlyEnabled || !!this.gridResizeRow;
3384
- const config = resolveRowResizeConfig(!hasConfiguredPlugin &&
3385
- !explicitlyEnabled &&
3386
- typeof this.gridResizeRow === 'object'
3387
- ? this.gridResizeRow
3388
- : undefined);
3493
+ const enabled = !isCorePlugin ||
3494
+ (!hasConfiguredPlugin && !!resizeRow);
3495
+ const resizeConfig = typeof resizeRow === 'object' ? resizeRow : undefined;
3496
+ const config = isCorePlugin
3497
+ ? resolveRowResizeConfig(resizeConfig)
3498
+ : this.config;
3389
3499
  const configChanged = config.minHeight !== this.config.minHeight ||
3390
3500
  config.maxHeight !== this.config.maxHeight ||
3391
3501
  config.fullRow !== this.config.fullRow;
@@ -3397,10 +3507,13 @@ class RowResizePlugin extends BasePlugin {
3397
3507
  if (enabled !== this.enabled) {
3398
3508
  this.enabled = enabled;
3399
3509
  if (enabled) {
3400
- this.rowDefinitionsRef = this.revogrid.rowDefinitions;
3401
3510
  this.registerEventListeners();
3402
3511
  }
3403
3512
  else {
3513
+ this.pendingBottomAnchor = false;
3514
+ this.keepBottomAnchor = false;
3515
+ this.rowDefinitionRemapQueued = false;
3516
+ this.pendingSourceCounts.clear();
3404
3517
  this.clearSubscriptions();
3405
3518
  }
3406
3519
  }
@@ -3419,6 +3532,7 @@ class RowResizePlugin extends BasePlugin {
3419
3532
  }
3420
3533
  const dimension = this.providers.dimension.stores[rowType];
3421
3534
  const dimensionState = dimension.getCurrentState();
3535
+ const viewport = this.providers.viewport.stores[rowType];
3422
3536
  const item = getItemByIndex(dimensionState, index);
3423
3537
  const focusedStore = this.providers.selection.focusedStore;
3424
3538
  const selectedRowType = focusedStore
@@ -3450,16 +3564,23 @@ class RowResizePlugin extends BasePlugin {
3450
3564
  currentHeight: startHeight,
3451
3565
  previousSizes,
3452
3566
  originalCustomSizes: Object.assign({}, dimensionState.sizes),
3453
- startEvent: event,
3567
+ bottomAnchored: rowType === 'rgRow' &&
3568
+ this.isMainViewportAtBottom(viewport.lastCoordinate),
3454
3569
  lastEvent: event,
3455
3570
  };
3571
+ this.active = active;
3456
3572
  const beforeEvent = this.emit(BEFORE_ROW_RESIZE_EVENT, this.eventDetail(active, event, startHeight));
3457
3573
  if (beforeEvent.defaultPrevented) {
3574
+ if (this.active === active) {
3575
+ this.active = undefined;
3576
+ }
3577
+ return;
3578
+ }
3579
+ if (!this.enabled || this.active !== active) {
3458
3580
  return;
3459
3581
  }
3460
3582
  event.preventDefault();
3461
3583
  event.stopPropagation();
3462
- this.active = active;
3463
3584
  const doc = this.revogrid.ownerDocument;
3464
3585
  this.previousBodyCursor = ((_a = doc.body) === null || _a === void 0 ? void 0 : _a.style.cursor) || '';
3465
3586
  if (doc.body) {
@@ -3482,6 +3603,7 @@ class RowResizePlugin extends BasePlugin {
3482
3603
  return;
3483
3604
  }
3484
3605
  this.providers.dimension.setCustomSizes(active.rowType, createRowResizePatch(active.indexes, size), true);
3606
+ this.requestBottomAnchor(active);
3485
3607
  active.currentHeight = size;
3486
3608
  this.emit(ROW_RESIZE_EVENT, this.eventDetail(active, active.lastEvent, size));
3487
3609
  }
@@ -3500,7 +3622,8 @@ class RowResizePlugin extends BasePlugin {
3500
3622
  }
3501
3623
  }
3502
3624
  this.providers.dimension.setCustomSizes(active.rowType, currentSizes);
3503
- const detail = Object.assign(Object.assign({}, this.eventDetail(active, active.lastEvent || active.startEvent, active.startHeight)), { reason });
3625
+ this.requestBottomAnchor(active);
3626
+ const detail = Object.assign(Object.assign({}, this.eventDetail(active, active.lastEvent, active.startHeight)), { reason });
3504
3627
  this.finishGesture();
3505
3628
  this.emit(ROW_RESIZE_CANCEL_EVENT, detail);
3506
3629
  }
@@ -3519,51 +3642,44 @@ class RowResizePlugin extends BasePlugin {
3519
3642
  return;
3520
3643
  }
3521
3644
  const items = this.providers.data.stores[active.rowType].store.get('items');
3522
- let committed = this.committedSizes.get(active.rowType);
3523
- if (!committed) {
3524
- committed = new Map();
3525
- this.committedSizes.set(active.rowType, committed);
3526
- }
3527
- let applied = this.appliedIndexes.get(active.rowType);
3528
- if (!applied) {
3529
- applied = new Set();
3530
- this.appliedIndexes.set(active.rowType, applied);
3531
- }
3532
3645
  const physicalIndexes = active.indexes.reduce((result, index) => {
3533
3646
  const physicalIndex = items[index];
3534
3647
  if (physicalIndex !== undefined) {
3535
- committed.set(physicalIndex, active.currentHeight);
3536
- applied.add(index);
3537
3648
  result.push(physicalIndex);
3538
3649
  }
3539
3650
  return result;
3540
3651
  }, []);
3541
3652
  if (physicalIndexes.length) {
3542
- const rowDefinitions = mergeRowResizeDefinitions(this.revogrid.rowDefinitions, active.rowType, physicalIndexes, active.currentHeight);
3543
- this.rowDefinitionsRef = rowDefinitions;
3544
- this.revogrid.rowDefinitions = rowDefinitions;
3653
+ const rowDefinitions = mergeRowResizeDefinitions(this.providers.dimension.getRowDefinitions(), active.rowType, physicalIndexes, active.currentHeight);
3654
+ this.providers.dimension.setRowDefinitions(rowDefinitions);
3655
+ this.scheduleRowDefinitionRemap();
3656
+ this.keepBottomAnchor = active.bottomAnchored;
3657
+ this.requestBottomAnchor(active);
3545
3658
  }
3546
3659
  }
3547
- applyCommittedSizes(clearAppliedIndexes) {
3548
- for (const [rowType, committed] of this.committedSizes) {
3549
- const dimension = this.providers.dimension.stores[rowType];
3550
- const sizes = Object.assign({}, dimension.store.get('sizes'));
3551
- if (clearAppliedIndexes) {
3552
- for (const index of this.appliedIndexes.get(rowType) || []) {
3553
- delete sizes[index];
3554
- }
3555
- }
3556
- const items = this.providers.data.stores[rowType].store.get('items');
3557
- const indexes = new Set();
3558
- items.forEach((physicalIndex, virtualIndex) => {
3559
- const size = committed.get(physicalIndex);
3560
- if (size !== undefined) {
3561
- sizes[virtualIndex] = size;
3562
- indexes.add(virtualIndex);
3563
- }
3564
- });
3565
- this.appliedIndexes.set(rowType, indexes);
3566
- this.providers.dimension.setCustomSizes(rowType, sizes);
3660
+ requestBottomAnchor(active) {
3661
+ if (active.bottomAnchored) {
3662
+ this.pendingBottomAnchor = true;
3663
+ }
3664
+ }
3665
+ isMainViewportAtBottom(coordinate) {
3666
+ const dimension = this.providers.dimension.stores.rgRow.getCurrentState();
3667
+ const viewport = this.providers.viewport.stores.rgRow.store.state;
3668
+ return (dimension.realSize > viewport.clientSize &&
3669
+ coordinate >= getViewportMaxCoordinate(dimension, viewport.virtualSize));
3670
+ }
3671
+ pruneRowDefinitions() {
3672
+ if (!this.pendingSourceCounts.size) {
3673
+ return;
3674
+ }
3675
+ const definitions = this.providers.dimension.getRowDefinitions();
3676
+ const rowDefinitions = definitions.filter(definition => {
3677
+ const count = this.pendingSourceCounts.get(definition.type);
3678
+ return count === undefined || definition.index < count;
3679
+ });
3680
+ this.pendingSourceCounts.clear();
3681
+ if (rowDefinitions.length !== definitions.length) {
3682
+ this.providers.dimension.setRowDefinitions(rowDefinitions);
3567
3683
  }
3568
3684
  }
3569
3685
  finishGesture() {
@@ -3586,6 +3702,9 @@ class RowResizePlugin extends BasePlugin {
3586
3702
  }
3587
3703
  destroy() {
3588
3704
  this.cancel('destroy');
3705
+ this.keepBottomAnchor = false;
3706
+ this.rowDefinitionRemapQueued = false;
3707
+ this.pendingSourceCounts.clear();
3589
3708
  super.destroy();
3590
3709
  }
3591
3710
  }