@revolist/revogrid 4.22.0 → 4.23.0

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 (130) hide show
  1. package/dist/cjs/{cell-renderer-uZmDBXz7.js → cell-renderer-DWJ9Px9f.js} +9 -3
  2. package/dist/cjs/{column.drag.plugin-CM_5mKV3.js → column.drag.plugin-CaEBDG-Q.js} +409 -267
  3. package/dist/cjs/{column.service-DvQDqxxx.js → column.service-f612L4ql.js} +1 -1
  4. package/dist/cjs/{dimension.helpers-CaIsYC99.js → dimension.helpers-B9HgANnM.js} +14 -146
  5. package/dist/cjs/{edit.utils-CwMzSIVF.js → edit.utils-pKeiYFLJ.js} +22 -1
  6. package/dist/cjs/{header-cell-renderer-B1dJwgTO.js → header-cell-renderer-4yq9_WbM.js} +1 -1
  7. package/dist/cjs/index-DxaSE5uZ.js +136 -0
  8. package/dist/cjs/index.cjs.js +45 -31
  9. package/dist/cjs/revo-grid.cjs.entry.js +35 -15
  10. package/dist/cjs/revogr-attribution_7.cjs.entry.js +44 -26
  11. package/dist/cjs/revogr-clipboard_3.cjs.entry.js +11 -9
  12. package/dist/cjs/revogr-data_4.cjs.entry.js +132 -178
  13. package/dist/cjs/revogr-filter-panel.cjs.entry.js +2 -1
  14. package/dist/cjs/{text-editor-BTnGaIl3.js → text-editor-B4W-m-r-.js} +3 -3
  15. package/dist/cjs/{throttle-CI4MsAqs.js → throttle-BCwEuJJq.js} +59 -24
  16. package/dist/cjs/viewport.helpers-BND76K2j.js +140 -0
  17. package/dist/cjs/{viewport.store-Dcjud-a-.js → viewport.store-BlKQ4x9H.js} +16 -16
  18. package/dist/collection/components/clipboard/revogr-clipboard.js +1 -1
  19. package/dist/collection/components/data/revogr-data.js +5 -3
  20. package/dist/collection/components/header/header-group-renderer.js +2 -1
  21. package/dist/collection/components/header/header-renderer.js +6 -5
  22. package/dist/collection/components/header/revogr-header-style.css +13 -3
  23. package/dist/collection/components/header/revogr-header.js +105 -42
  24. package/dist/collection/components/order/order-row.service.js +6 -5
  25. package/dist/collection/components/overlay/keyboard.service.js +25 -3
  26. package/dist/collection/components/overlay/selection.utils.js +8 -6
  27. package/dist/collection/components/revoGrid/revo-grid.js +6 -5
  28. package/dist/collection/components/revoGrid/viewport.service.js +2 -1
  29. package/dist/collection/components/scroll/revogr-viewport-scroll.js +10 -6
  30. package/dist/collection/components/scrollable/revogr-scroll-virtual.js +4 -10
  31. package/dist/collection/plugins/filter/filter.panel.js +2 -1
  32. package/dist/collection/plugins/filter/filter.plugin.js +11 -4
  33. package/dist/collection/plugins/groupingRow/grouping.row.plugin.js +25 -1
  34. package/dist/collection/plugins/moveColumn/column.drag.plugin.js +18 -15
  35. package/dist/collection/plugins/sorting/sorting.func.js +173 -15
  36. package/dist/collection/plugins/sorting/sorting.plugin.js +167 -84
  37. package/dist/collection/plugins/sorting/sorting.sign.js +7 -1
  38. package/dist/collection/serve/controller.js +98 -37
  39. package/dist/collection/serve/data.js +273 -144
  40. package/dist/collection/services/dimension.provider.js +16 -1
  41. package/dist/collection/services/local.scroll.service.js +59 -24
  42. package/dist/collection/services/scroll.dimension.helpers.js +83 -0
  43. package/dist/collection/services/selection.store.connector.js +4 -1
  44. package/dist/collection/store/dimension/dimension.recalculate.plugin.js +22 -9
  45. package/dist/collection/store/dimension/dimension.store.js +4 -2
  46. package/dist/collection/store/vp/viewport.helpers.js +9 -0
  47. package/dist/collection/store/vp/viewport.store.js +5 -16
  48. package/dist/collection/types/events.js +4 -0
  49. package/dist/collection/utils/key.utils.js +20 -0
  50. package/dist/collection/utils/store.utils.js +3 -3
  51. package/dist/{revo-grid/cell-renderer-K_BKH7Kx.js → esm/cell-renderer-8UiGd-s7.js} +9 -3
  52. package/dist/esm/{column.drag.plugin-DEqZ2qXJ.js → column.drag.plugin-BsfhsfmB.js} +402 -266
  53. package/dist/esm/{column.service-Cdz3dYqZ.js → column.service-DbpulTog.js} +1 -1
  54. package/dist/{revo-grid/debounce-BfO9dz9v.js → esm/debounce-PCRWZliA.js} +1 -1
  55. package/dist/{revo-grid/dimension.helpers-DzxqJQqN.js → esm/dimension.helpers-CGKwSvw6.js} +7 -128
  56. package/dist/esm/{edit.utils-CzfeG98N.js → edit.utils-Dnnbd0xG.js} +22 -2
  57. package/dist/{revo-grid/header-cell-renderer-DXhxZMly.js → esm/header-cell-renderer-DGI2FAD8.js} +1 -1
  58. package/dist/esm/index-Db3qZoW5.js +127 -0
  59. package/dist/esm/index.js +15 -10
  60. package/dist/esm/revo-grid.entry.js +34 -14
  61. package/dist/esm/revogr-attribution_7.entry.js +43 -25
  62. package/dist/esm/revogr-clipboard_3.entry.js +12 -10
  63. package/dist/esm/revogr-data_4.entry.js +133 -179
  64. package/dist/esm/revogr-filter-panel.entry.js +3 -2
  65. package/dist/esm/{text-editor-C1ks5eQ4.js → text-editor-C3RUSwH5.js} +2 -2
  66. package/dist/esm/{throttle-BEjFQa2l.js → throttle-CaUDyxyU.js} +60 -25
  67. package/dist/esm/viewport.helpers-CoCAvmZs.js +133 -0
  68. package/dist/{revo-grid/viewport.store-saAZJHRo.js → esm/viewport.store-COAfzAyu.js} +15 -17
  69. package/dist/{esm/cell-renderer-K_BKH7Kx.js → revo-grid/cell-renderer-8UiGd-s7.js} +9 -3
  70. package/dist/revo-grid/{column.drag.plugin-DEqZ2qXJ.js → column.drag.plugin-BsfhsfmB.js} +402 -266
  71. package/dist/revo-grid/{column.service-Cdz3dYqZ.js → column.service-DbpulTog.js} +1 -1
  72. package/dist/{esm/debounce-BfO9dz9v.js → revo-grid/debounce-PCRWZliA.js} +1 -1
  73. package/dist/{esm/dimension.helpers-DzxqJQqN.js → revo-grid/dimension.helpers-CGKwSvw6.js} +7 -128
  74. package/dist/revo-grid/{edit.utils-CzfeG98N.js → edit.utils-Dnnbd0xG.js} +22 -2
  75. package/dist/{esm/header-cell-renderer-DXhxZMly.js → revo-grid/header-cell-renderer-DGI2FAD8.js} +1 -1
  76. package/dist/revo-grid/index-Db3qZoW5.js +127 -0
  77. package/dist/revo-grid/index.esm.js +15 -10
  78. package/dist/revo-grid/revo-grid.entry.js +34 -14
  79. package/dist/revo-grid/revogr-attribution_7.entry.js +43 -25
  80. package/dist/revo-grid/revogr-clipboard_3.entry.js +12 -10
  81. package/dist/revo-grid/revogr-data_4.entry.js +133 -179
  82. package/dist/revo-grid/revogr-filter-panel.entry.js +3 -2
  83. package/dist/revo-grid/{text-editor-C1ks5eQ4.js → text-editor-C3RUSwH5.js} +2 -2
  84. package/dist/revo-grid/{throttle-BEjFQa2l.js → throttle-CaUDyxyU.js} +60 -25
  85. package/dist/revo-grid/viewport.helpers-CoCAvmZs.js +133 -0
  86. package/dist/{esm/viewport.store-saAZJHRo.js → revo-grid/viewport.store-COAfzAyu.js} +15 -17
  87. package/dist/types/components/header/header-group-renderer.d.ts +1 -0
  88. package/dist/types/components/header/header-renderer.d.ts +1 -0
  89. package/dist/types/components/header/revogr-header.d.ts +6 -0
  90. package/dist/types/components/overlay/keyboard.service.d.ts +5 -0
  91. package/dist/types/plugins/groupingRow/grouping.row.plugin.d.ts +8 -0
  92. package/dist/types/plugins/moveColumn/column.drag.plugin.d.ts +29 -3
  93. package/dist/types/plugins/sorting/sorting.func.d.ts +25 -2
  94. package/dist/types/plugins/sorting/sorting.plugin.d.ts +84 -9
  95. package/dist/types/plugins/sorting/sorting.sign.d.ts +5 -1
  96. package/dist/types/plugins/sorting/sorting.types.d.ts +46 -1
  97. package/dist/types/services/local.scroll.service.d.ts +10 -2
  98. package/dist/types/services/scroll.dimension.helpers.d.ts +20 -0
  99. package/dist/types/store/vp/viewport.helpers.d.ts +2 -0
  100. package/dist/types/types/events.d.ts +1 -1
  101. package/dist/types/types/interfaces.d.ts +11 -0
  102. package/dist/types/utils/key.utils.d.ts +8 -0
  103. package/hydrate/index.js +791 -539
  104. package/hydrate/index.mjs +791 -539
  105. package/package.json +1 -1
  106. package/standalone/column.service.js +1 -1
  107. package/standalone/data.store.js +1 -1
  108. package/standalone/debounce.js +1 -1
  109. package/standalone/dimension.helpers.js +1 -1
  110. package/standalone/index.js +1 -1
  111. package/standalone/local.scroll.timer.js +1 -1
  112. package/standalone/revo-grid.js +1 -1
  113. package/standalone/revogr-clipboard2.js +1 -1
  114. package/standalone/revogr-data2.js +1 -1
  115. package/standalone/revogr-edit.js +1 -1
  116. package/standalone/revogr-edit2.js +1 -1
  117. package/standalone/revogr-filter-panel.js +1 -1
  118. package/standalone/revogr-header2.js +1 -1
  119. package/standalone/revogr-order-editor2.js +1 -1
  120. package/standalone/revogr-overlay-selection2.js +1 -1
  121. package/standalone/revogr-row-headers.js +1 -1
  122. package/standalone/revogr-row-headers2.js +1 -1
  123. package/standalone/revogr-scroll-virtual2.js +1 -1
  124. package/standalone/revogr-viewport-scroll2.js +1 -1
  125. package/standalone/selection.utils.js +1 -1
  126. package/standalone/throttle.js +1 -1
  127. package/standalone/toNumber.js +1 -1
  128. package/dist/cjs/viewport.helpers-BAovztDd.js +0 -58
  129. package/dist/esm/viewport.helpers-VXhsJZtn.js +0 -52
  130. package/dist/revo-grid/viewport.helpers-VXhsJZtn.js +0 -52
@@ -0,0 +1,140 @@
1
+ /*!
2
+ * Built by Revolist OU ❤️
3
+ */
4
+ 'use strict';
5
+
6
+ const FALLBACK_MAX_SCROLL_SIZE = 16000000;
7
+ const SCROLL_SIZE_GUARD = 1000000;
8
+ let detectedMaxScrollSize;
9
+ function getMaxScrollSize(doc = typeof document === 'undefined' ? undefined : document) {
10
+ if (typeof detectedMaxScrollSize === 'number') {
11
+ return detectedMaxScrollSize;
12
+ }
13
+ const body = doc === null || doc === void 0 ? void 0 : doc.body;
14
+ if (body) {
15
+ const ownerDocument = body.ownerDocument;
16
+ const element = ownerDocument.createElement('div');
17
+ element.style.cssText = [
18
+ 'height:1px',
19
+ 'left:-10000px',
20
+ 'overflow:scroll',
21
+ 'position:absolute',
22
+ 'top:-10000px',
23
+ 'visibility:hidden',
24
+ 'width:1px',
25
+ ].join(';');
26
+ const content = ownerDocument.createElement('div');
27
+ content.style.height = `${FALLBACK_MAX_SCROLL_SIZE * 4}px`;
28
+ element.appendChild(content);
29
+ body.appendChild(element);
30
+ detectedMaxScrollSize = Math.max(0, Math.min(element.scrollHeight, FALLBACK_MAX_SCROLL_SIZE * 4) - SCROLL_SIZE_GUARD);
31
+ element.remove();
32
+ if (detectedMaxScrollSize > SCROLL_SIZE_GUARD) {
33
+ return detectedMaxScrollSize;
34
+ }
35
+ detectedMaxScrollSize = FALLBACK_MAX_SCROLL_SIZE;
36
+ return detectedMaxScrollSize;
37
+ }
38
+ return FALLBACK_MAX_SCROLL_SIZE;
39
+ }
40
+ function getScrollDimension({ contentSize, clientSize, virtualSize = 0, maxScrollSize = getMaxScrollSize(), }) {
41
+ const safeContentSize = Math.max(0, maxScrollSize - SCROLL_SIZE_GUARD);
42
+ const size = Math.max(0, contentSize);
43
+ const client = Math.max(0, clientSize);
44
+ const viewport = Math.max(0, virtualSize || client);
45
+ const logicalScrollSize = Math.max(0, size - viewport);
46
+ const maxPhysicalScrollSize = Math.max(0, safeContentSize - client);
47
+ const physicalScrollSize = Math.min(logicalScrollSize, maxPhysicalScrollSize);
48
+ const physicalContentSize = client + physicalScrollSize;
49
+ const isCompressed = logicalScrollSize > physicalScrollSize && physicalScrollSize > 0;
50
+ const clampLogical = (coordinate) => Math.min(Math.max(0, coordinate || 0), logicalScrollSize);
51
+ const clampPhysical = (coordinate) => Math.min(Math.max(0, coordinate || 0), physicalScrollSize);
52
+ const toLogicalCoordinate = (coordinate) => {
53
+ if (!logicalScrollSize || !physicalScrollSize) {
54
+ return 0;
55
+ }
56
+ if (!isCompressed) {
57
+ return clampLogical(coordinate);
58
+ }
59
+ return clampLogical((clampPhysical(coordinate) / physicalScrollSize) * logicalScrollSize);
60
+ };
61
+ const toPhysicalCoordinate = (coordinate) => {
62
+ if (!logicalScrollSize || !physicalScrollSize) {
63
+ return 0;
64
+ }
65
+ if (!isCompressed) {
66
+ return clampPhysical(coordinate);
67
+ }
68
+ return clampPhysical((clampLogical(coordinate) / logicalScrollSize) * physicalScrollSize);
69
+ };
70
+ return {
71
+ contentSize: size,
72
+ clientSize: client,
73
+ viewportSize: viewport,
74
+ physicalContentSize,
75
+ logicalScrollSize,
76
+ physicalScrollSize,
77
+ isCompressed,
78
+ toLogicalCoordinate,
79
+ toPhysicalCoordinate,
80
+ getRenderOffset(coordinate) {
81
+ const logical = clampLogical(coordinate);
82
+ return logical - toPhysicalCoordinate(logical);
83
+ },
84
+ };
85
+ }
86
+
87
+ /**
88
+ * Collects data for pinned columns in the required @ViewportProps format.
89
+ */
90
+ /**
91
+ * Represents the slot names for the viewport slots.
92
+ */
93
+ const HEADER_SLOT = 'header'; // Slot name for the header slot
94
+ const FOOTER_SLOT = 'footer'; // Slot name for the footer slot
95
+ const CONTENT_SLOT = 'content'; // Slot name for the content slot
96
+ const DATA_SLOT = 'data'; // Slot name for the data slot
97
+ /**
98
+ * Returns the last visible cell in the viewport for a given row type.
99
+ * Coordinates are not zero-based and are relative to the viewport.
100
+ * If needed to be zero-based they can be adjusted by subtracting 1.
101
+ */
102
+ function getLastCell(data, rowType) {
103
+ // Get the last visible column count from the viewport column data.
104
+ const lastVisibleColumnCount = data.viewports[data.colType].store.get('realCount');
105
+ // Get the last visible row count for the given row type from the viewport column data.
106
+ const lastVisibleRowCount = data.viewports[rowType].store.get('realCount');
107
+ // Return the last visible cell with the last visible column count and row count.
108
+ return {
109
+ x: lastVisibleColumnCount,
110
+ y: lastVisibleRowCount,
111
+ };
112
+ }
113
+ function viewportDataPartition(data, type, slot, fixed) {
114
+ return {
115
+ colData: data.colStore,
116
+ viewportCol: data.viewports[data.colType].store,
117
+ viewportRow: data.viewports[type].store,
118
+ /**
119
+ * lastCell is the last real coordinate + 1, saved to selection store
120
+ */
121
+ lastCell: getLastCell(data, type),
122
+ slot,
123
+ type,
124
+ canDrag: !fixed,
125
+ position: data.position,
126
+ dataStore: data.rowStores[type].store,
127
+ dimensionCol: data.dimensions[data.colType].store,
128
+ dimensionRow: data.dimensions[type].store,
129
+ style: fixed
130
+ ? { height: `${data.dimensions[type].store.get('realSize')}px` }
131
+ : undefined,
132
+ };
133
+ }
134
+
135
+ exports.CONTENT_SLOT = CONTENT_SLOT;
136
+ exports.DATA_SLOT = DATA_SLOT;
137
+ exports.FOOTER_SLOT = FOOTER_SLOT;
138
+ exports.HEADER_SLOT = HEADER_SLOT;
139
+ exports.getScrollDimension = getScrollDimension;
140
+ exports.viewportDataPartition = viewportDataPartition;
@@ -3,7 +3,7 @@
3
3
  */
4
4
  'use strict';
5
5
 
6
- var dimension_helpers = require('./dimension.helpers-CaIsYC99.js');
6
+ var dimension_helpers = require('./dimension.helpers-B9HgANnM.js');
7
7
 
8
8
  const LETTER_BLOCK_SIZE = 10;
9
9
  const calculateRowHeaderSize = (itemsLength, rowHeaderColumn, minWidth = 50) => {
@@ -11,6 +11,15 @@ const calculateRowHeaderSize = (itemsLength, rowHeaderColumn, minWidth = 50) =>
11
11
  Math.max((itemsLength.toString().length + 1) * LETTER_BLOCK_SIZE, minWidth));
12
12
  };
13
13
 
14
+ function getViewportMaxCoordinate(dimension, viewportSize, frameOffset = 1) {
15
+ if (!viewportSize || dimension.realSize <= viewportSize) {
16
+ return 0;
17
+ }
18
+ return Math.max(0, dimension.realSize - viewportSize - dimension.originItemSize * frameOffset);
19
+ }
20
+ function clampViewportCoordinate(coordinate, dimension, viewportSize, frameOffset = 1) {
21
+ return Math.min(Math.max(0, coordinate), getViewportMaxCoordinate(dimension, viewportSize, frameOffset));
22
+ }
14
23
  /**
15
24
  * Update items based on new scroll position
16
25
  * If viewport wasn't changed fully simple recombination of positions
@@ -276,6 +285,8 @@ function initialState() {
276
285
  realCount: 0,
277
286
  // size of viewport in px
278
287
  clientSize: 0,
288
+ // logical-to-physical render offset used when scroll space is compressed
289
+ renderOffset: 0,
279
290
  };
280
291
  }
281
292
  /**
@@ -311,21 +322,8 @@ class ViewportStore {
311
322
  const outsize = singleOffsetInPx * 2;
312
323
  // math virtual size is based on visible area + 2 items outside of visible area
313
324
  const virtualSize = viewportSize + outsize;
314
- // expected no scroll if real size less than virtual size, position is 0
315
- let maxCoordinate = 0;
316
- // if there is nodes outside of viewport, max coordinate has to be adjusted
317
- if (dimension.realSize > viewportSize) {
318
- // max coordinate is real size minus virtual/rendered space
319
- maxCoordinate = dimension.realSize - viewportSize - singleOffsetInPx;
320
- }
321
- let pos = position;
322
- // limit position to max and min coordinates
323
- if (pos < 0) {
324
- pos = 0;
325
- }
326
- else if (pos > maxCoordinate) {
327
- pos = maxCoordinate;
328
- }
325
+ const maxCoordinate = getViewportMaxCoordinate(dimension, viewportSize, frameOffset);
326
+ let pos = clampViewportCoordinate(position, dimension, viewportSize, frameOffset);
329
327
  // store last coordinate for further restore on redraw
330
328
  this.lastCoordinate = pos;
331
329
  // actual position is less than first item start based on offset
@@ -406,10 +404,12 @@ class ViewportStore {
406
404
  exports.ViewportStore = ViewportStore;
407
405
  exports.addMissingItems = addMissingItems;
408
406
  exports.calculateRowHeaderSize = calculateRowHeaderSize;
407
+ exports.clampViewportCoordinate = clampViewportCoordinate;
409
408
  exports.getFirstItem = getFirstItem;
410
409
  exports.getItems = getItems;
411
410
  exports.getLastItem = getLastItem;
412
411
  exports.getUpdatedItemsByPosition = getUpdatedItemsByPosition;
412
+ exports.getViewportMaxCoordinate = getViewportMaxCoordinate;
413
413
  exports.isActiveRange = isActiveRange;
414
414
  exports.isActiveRangeOutsideLastItem = isActiveRangeOutsideLastItem;
415
415
  exports.recombineByOffset = recombineByOffset;
@@ -66,8 +66,8 @@ export class Clipboard {
66
66
  return;
67
67
  }
68
68
  const data = this.getData(beforeCopy.detail.event);
69
- this.copyRegion.emit(data || undefined);
70
69
  e.preventDefault();
70
+ this.copyRegion.emit(data || undefined);
71
71
  }
72
72
  /**
73
73
  * Listen to copy event and emit copy region event
@@ -102,11 +102,13 @@ export class RevogrData {
102
102
  const depth = this.dataStore.get('groupingDepth');
103
103
  const groupingCustomRenderer = this.dataStore.get('groupingCustomRenderer');
104
104
  const groupDepth = this.columnService.hasGrouping ? depth : 0;
105
+ const rowRenderOffset = this.viewportRow.get('renderOffset') || 0;
106
+ const colRenderOffset = this.viewportCol.get('renderOffset') || 0;
105
107
  for (let rgRow of rows) {
106
108
  const dataItem = getSourceItem(this.dataStore, rgRow.itemIndex);
107
109
  // #region Grouping
108
110
  if (isGrouping(dataItem)) {
109
- const gmodel = Object.assign(Object.assign({}, rgRow), { index: rgRow.itemIndex, model: dataItem, groupingCustomRenderer,
111
+ const gmodel = Object.assign(Object.assign({}, rgRow), { start: rgRow.start - rowRenderOffset, index: rgRow.itemIndex, model: dataItem, groupingCustomRenderer,
110
112
  // Only show expand button if grouping is enabled and not in row headers
111
113
  hasExpand: this.columnService.hasGrouping && this.colType !== 'rowHeaders', columnItems: cols, providers: this.providers });
112
114
  rowsEls.push(h(GroupingRowRenderer, Object.assign({}, gmodel)));
@@ -129,7 +131,7 @@ export class RevogrData {
129
131
  [DATA_ROW]: rowProps.itemIndex,
130
132
  style: {
131
133
  width: `${columnProps.size}px`,
132
- transform: `translateX(${columnProps.start}px)`,
134
+ transform: `translateX(${columnProps.start - colRenderOffset}px)`,
133
135
  height: rowProps.size ? `${rowProps.size}px` : undefined,
134
136
  },
135
137
  };
@@ -157,7 +159,7 @@ export class RevogrData {
157
159
  if (this.rowHighlightPlugin.isRowFocused(rgRow.itemIndex)) {
158
160
  rowClass += ` ${ROW_FOCUSED_CLASS}`;
159
161
  }
160
- const row = (h(RowRenderer, { index: rgRow.itemIndex, rowClass: rowClass, size: rgRow.size, start: rgRow.start, groupingLevel: groupDepth || undefined }, cells));
162
+ const row = (h(RowRenderer, { index: rgRow.itemIndex, rowClass: rowClass, size: rgRow.size, start: rgRow.start - rowRenderOffset, groupingLevel: groupDepth || undefined }, cells));
161
163
  this.beforerowrender.emit({
162
164
  node: row,
163
165
  item: rgRow,
@@ -6,6 +6,7 @@ import { HEADER_CLASS, MIN_COL_SIZE } from "../../utils/consts";
6
6
  import { HeaderCellRenderer } from "./header-cell-renderer";
7
7
  const HeaderGroupRenderer = (p) => {
8
8
  const groupProps = {
9
+ key: `${p.group.name}-${p.group.indexes.join('-')}`,
9
10
  canResize: p.canResize,
10
11
  minWidth: p.group.indexes.length * MIN_COL_SIZE,
11
12
  maxWidth: 0,
@@ -14,7 +15,7 @@ const HeaderGroupRenderer = (p) => {
14
15
  [HEADER_CLASS]: true,
15
16
  },
16
17
  style: {
17
- transform: `translateX(${p.start}px)`,
18
+ transform: `translateX(${p.start - (p.renderOffset || 0)}px)`,
18
19
  width: `${p.end - p.start}px`,
19
20
  },
20
21
  onResize: p.onResize,
@@ -7,7 +7,7 @@ import { SortingSign } from "../../plugins/sorting/sorting.sign";
7
7
  import { DATA_COL, FOCUS_CLASS, HEADER_CLASS, HEADER_SORTABLE_CLASS, MIN_COL_SIZE, } from "../../utils/consts";
8
8
  import { HeaderCellRenderer } from "./header-cell-renderer";
9
9
  const HeaderRenderer = (p) => {
10
- var _a, _b, _c, _d, _e;
10
+ var _a, _b, _c, _d, _e, _f, _g;
11
11
  const cellClass = {
12
12
  [HEADER_CLASS]: true,
13
13
  [HEADER_SORTABLE_CLASS]: !!((_a = p.data) === null || _a === void 0 ? void 0 : _a.sortable),
@@ -16,15 +16,16 @@ const HeaderRenderer = (p) => {
16
16
  cellClass[p.data.order] = true;
17
17
  }
18
18
  const dataProps = {
19
+ key: String((_d = (_c = p.data) === null || _c === void 0 ? void 0 : _c.prop) !== null && _d !== void 0 ? _d : p.column.itemIndex),
19
20
  [DATA_COL]: p.column.itemIndex,
20
21
  canResize: p.canResize,
21
- minWidth: ((_c = p.data) === null || _c === void 0 ? void 0 : _c.minSize) || MIN_COL_SIZE,
22
- maxWidth: (_d = p.data) === null || _d === void 0 ? void 0 : _d.maxSize,
22
+ minWidth: ((_e = p.data) === null || _e === void 0 ? void 0 : _e.minSize) || MIN_COL_SIZE,
23
+ maxWidth: (_f = p.data) === null || _f === void 0 ? void 0 : _f.maxSize,
23
24
  active: p.active || ['r'],
24
25
  class: cellClass,
25
26
  style: {
26
27
  width: `${p.column.size}px`,
27
- transform: `translateX(${p.column.start}px)`,
28
+ transform: `translateX(${p.column.start - (p.renderOffset || 0)}px)`,
28
29
  },
29
30
  onResize: p.onResize,
30
31
  onDblClick(originalEvent) {
@@ -55,6 +56,6 @@ const HeaderRenderer = (p) => {
55
56
  }
56
57
  }
57
58
  }
58
- return (h(HeaderCellRenderer, { data: p.data, props: dataProps, additionalData: p.additionalData }, h(SortingSign, { column: p.data }), p.canFilter && ((_e = p.data) === null || _e === void 0 ? void 0 : _e.filter) !== false ? (h(FilterButton, { column: p.data })) : ('')));
59
+ return (h(HeaderCellRenderer, { data: p.data, props: dataProps, additionalData: p.additionalData }, h(SortingSign, { column: p.data }), p.canFilter && ((_g = p.data) === null || _g === void 0 ? void 0 : _g.filter) !== false ? (h(FilterButton, { column: p.data })) : ('')));
59
60
  };
60
61
  export default HeaderRenderer;
@@ -34,15 +34,25 @@ revogr-header .rgHeaderCell.align-right {
34
34
  revogr-header .rgHeaderCell.sortable {
35
35
  cursor: pointer;
36
36
  }
37
- revogr-header .rgHeaderCell i.asc:after, revogr-header .rgHeaderCell i.desc:after {
37
+ revogr-header .rgHeaderCell .sort-indicator {
38
+ display: inline-flex;
39
+ align-items: flex-start;
40
+ gap: 1px;
41
+ }
42
+ revogr-header .rgHeaderCell .sort-indicator i.asc:after, revogr-header .rgHeaderCell .sort-indicator i.desc:after {
38
43
  font-size: 13px;
39
44
  }
40
- revogr-header .rgHeaderCell i.asc:after {
45
+ revogr-header .rgHeaderCell .sort-indicator i.asc:after {
41
46
  content: "↑";
42
47
  }
43
- revogr-header .rgHeaderCell i.desc:after {
48
+ revogr-header .rgHeaderCell .sort-indicator i.desc:after {
44
49
  content: "↓";
45
50
  }
51
+ revogr-header .rgHeaderCell .sort-indicator .sort-order-index {
52
+ font-size: 10px;
53
+ line-height: 1;
54
+ top: 0;
55
+ }
46
56
  revogr-header .rgHeaderCell.active {
47
57
  z-index: 10;
48
58
  }
@@ -2,7 +2,6 @@
2
2
  * Built by Revolist OU ❤️
3
3
  */
4
4
  import { h, } from "@stencil/core";
5
- import keyBy from "lodash/keyBy";
6
5
  import { getItemByIndex } from "../../store/index";
7
6
  import { HEADER_ACTUAL_ROW_CLASS, HEADER_ROW_CLASS } from "../../utils/consts";
8
7
  import HeaderRenderer from "./header-renderer";
@@ -30,13 +29,10 @@ export class RevogrHeaderComponent {
30
29
  }
31
30
  onResizeGroup(changedX, startIndex, endIndex) {
32
31
  const sizes = {};
33
- const cols = keyBy(this.viewportCol.get('items'), 'itemIndex');
34
32
  const change = changedX / (endIndex - startIndex + 1);
35
33
  for (let i = startIndex; i <= endIndex; i++) {
36
- const item = cols[i];
37
- if (item) {
38
- sizes[i] = item.size + change;
39
- }
34
+ const item = getItemByIndex(this.dimensionCol.state, i);
35
+ sizes[i] = item.end - item.start + change;
40
36
  }
41
37
  this.headerresize.emit(sizes);
42
38
  }
@@ -50,12 +46,13 @@ export class RevogrHeaderComponent {
50
46
  const { cells } = this.renderHeaderColumns(cols, range);
51
47
  const groupRow = this.renderGroupingColumns();
52
48
  return [
53
- h("div", { key: 'a8d57270f4758b454fb4900808453e0c4663c91c', class: "group-rgRow" }, groupRow),
54
- h("div", { key: '41a270ff6bde9943a81d9c46482f2a40312afb50', class: `${HEADER_ROW_CLASS} ${HEADER_ACTUAL_ROW_CLASS}` }, cells),
49
+ h("div", { key: '3cc466db6bc4df0cd61c47a22c3a0473318e5dd8', class: "group-rgRow" }, groupRow),
50
+ h("div", { key: '9742a3fa4d4b75073aef5544806f42386ebffdea', class: `${HEADER_ROW_CLASS} ${HEADER_ACTUAL_ROW_CLASS}` }, cells),
55
51
  ];
56
52
  }
57
53
  renderHeaderColumns(cols, range) {
58
- const cells = [];
54
+ const columnsToRender = [];
55
+ const renderOffset = this.viewportCol.get('renderOffset') || 0;
59
56
  for (let rgCol of cols) {
60
57
  const colData = this.colData[rgCol.itemIndex];
61
58
  const props = {
@@ -64,6 +61,7 @@ export class RevogrHeaderComponent {
64
61
  data: Object.assign(Object.assign({}, colData), { index: rgCol.itemIndex, providers: this.providers }),
65
62
  canFilter: !!this.columnFilter,
66
63
  canResize: this.canResize,
64
+ renderOffset,
67
65
  active: this.resizeHandler,
68
66
  additionalData: this.additionalData,
69
67
  onResize: e => this.onResize(e, rgCol.itemIndex),
@@ -72,45 +70,106 @@ export class RevogrHeaderComponent {
72
70
  };
73
71
  const event = this.beforeHeaderRender.emit(props);
74
72
  if (!event.defaultPrevented) {
75
- cells.push(h(HeaderRenderer, Object.assign({}, event.detail)));
73
+ columnsToRender.push(event.detail);
76
74
  }
77
75
  }
76
+ const duplicateProps = this.getDuplicateHeaderProps(columnsToRender);
77
+ const cells = columnsToRender.map(detail => h(HeaderRenderer, Object.assign({ key: this.getHeaderCellKey(detail.data, this.type, duplicateProps) }, detail)));
78
78
  return { cells };
79
79
  }
80
80
  renderGroupingColumns() {
81
+ const visibleGroupRange = this.getVisibleGroupRange();
82
+ return Array.from({ length: this.groupingDepth }, (_, level) => this.renderGroupRow(level, visibleGroupRange)).flat();
83
+ }
84
+ renderGroupRow(level, visibleGroupRange) {
85
+ const groupCells = (this.groups[level] || [])
86
+ .map(group => this.renderGroupColumn(group, level, visibleGroupRange))
87
+ .filter((cell) => !!cell);
88
+ return [
89
+ ...groupCells,
90
+ h('div', {
91
+ key: `group-row-${level}`,
92
+ class: {
93
+ [HEADER_ROW_CLASS]: true,
94
+ group: true,
95
+ },
96
+ }),
97
+ ];
98
+ }
99
+ renderGroupColumn(group, level, visibleGroupRange) {
81
100
  var _a;
82
- const groupRow = [];
83
- for (let i = 0; i < this.groupingDepth; i++) {
84
- if (this.groups[i]) {
85
- for (let group of this.groups[i]) {
86
- const groupStartIndex = (_a = group.indexes[0]) !== null && _a !== void 0 ? _a : -1;
87
- if (groupStartIndex > -1) {
88
- const groupEndIndex = groupStartIndex + group.indexes.length - 1;
89
- const groupStart = getItemByIndex(this.dimensionCol.state, groupStartIndex).start;
90
- const groupEnd = getItemByIndex(this.dimensionCol.state, groupEndIndex).end;
91
- const props = {
92
- providers: this.providers,
93
- start: groupStart,
94
- end: groupEnd,
95
- group,
96
- active: this.resizeHandler,
97
- canResize: this.canResize,
98
- additionalData: this.additionalData,
99
- onResize: e => {
100
- var _a;
101
- return this.onResizeGroup((_a = e.changedX) !== null && _a !== void 0 ? _a : 0, groupStartIndex, groupEndIndex);
102
- },
103
- };
104
- const event = this.beforeGroupHeaderRender.emit(props);
105
- if (!event.defaultPrevented) {
106
- groupRow.push(h(GroupHeaderRenderer, Object.assign({}, event.detail)));
107
- }
108
- }
101
+ const groupStartIndex = (_a = group.indexes[0]) !== null && _a !== void 0 ? _a : -1;
102
+ if (groupStartIndex < 0) {
103
+ return;
104
+ }
105
+ const groupEndIndex = groupStartIndex + group.indexes.length - 1;
106
+ if (!visibleGroupRange ||
107
+ !isGroupInVisibleRange(groupStartIndex, groupEndIndex, visibleGroupRange)) {
108
+ return;
109
+ }
110
+ const groupStart = getItemByIndex(this.dimensionCol.state, groupStartIndex).start;
111
+ const groupEnd = getItemByIndex(this.dimensionCol.state, groupEndIndex).end;
112
+ const props = {
113
+ providers: this.providers,
114
+ start: groupStart,
115
+ end: groupEnd,
116
+ group,
117
+ renderOffset: this.viewportCol.get('renderOffset') || 0,
118
+ active: this.resizeHandler,
119
+ canResize: this.canResize,
120
+ additionalData: this.additionalData,
121
+ onResize: e => {
122
+ var _a;
123
+ return this.onResizeGroup((_a = e.changedX) !== null && _a !== void 0 ? _a : 0, groupStartIndex, groupEndIndex);
124
+ },
125
+ };
126
+ const event = this.beforeGroupHeaderRender.emit(props);
127
+ if (event.defaultPrevented) {
128
+ return;
129
+ }
130
+ return h(GroupHeaderRenderer, Object.assign({ key: this.getGroupHeaderCellKey(event.detail.group, level) }, event.detail));
131
+ }
132
+ getVisibleGroupRange() {
133
+ const visibleColumns = this.viewportCol.get('items');
134
+ if (!visibleColumns.length) {
135
+ return;
136
+ }
137
+ return visibleColumns.reduce((range, column) => ({
138
+ start: Math.min(range.start, column.itemIndex),
139
+ end: Math.max(range.end, column.itemIndex),
140
+ }), {
141
+ start: visibleColumns[0].itemIndex,
142
+ end: visibleColumns[0].itemIndex,
143
+ });
144
+ }
145
+ getHeaderCellKey(column, type, duplicateProps) {
146
+ if ((column === null || column === void 0 ? void 0 : column.prop) === undefined) {
147
+ return `${type}-${String(column === null || column === void 0 ? void 0 : column.index)}`;
148
+ }
149
+ const propKey = String(column.prop);
150
+ if (duplicateProps.has(propKey)) {
151
+ return `${type}-${propKey}-${String(column.index)}`;
152
+ }
153
+ return `${type}-${propKey}`;
154
+ }
155
+ getDuplicateHeaderProps(columns) {
156
+ const seenProps = new Set();
157
+ const duplicateProps = new Set();
158
+ columns.forEach(({ data }) => {
159
+ if ((data === null || data === void 0 ? void 0 : data.prop) !== undefined) {
160
+ const propKey = String(data.prop);
161
+ if (seenProps.has(propKey)) {
162
+ duplicateProps.add(propKey);
163
+ }
164
+ else {
165
+ seenProps.add(propKey);
109
166
  }
110
167
  }
111
- groupRow.push(h("div", { class: `${HEADER_ROW_CLASS} group` }));
112
- }
113
- return groupRow;
168
+ });
169
+ return duplicateProps;
170
+ }
171
+ getGroupHeaderCellKey(group, level) {
172
+ return `group-${level}-${group.name}-${group.indexes.join('-')}`;
114
173
  }
115
174
  get providers() {
116
175
  return {
@@ -523,7 +582,7 @@ export class RevogrHeaderComponent {
523
582
  },
524
583
  "complexType": {
525
584
  "original": "HeaderRenderProps",
526
- "resolved": "{ column: VirtualPositionItem; additionalData: any; data: ColumnTemplateProp<ColumnProp>; range?: RangeArea | null | undefined; canResize?: boolean | undefined; canFilter?: boolean | undefined; onResize?(e: ResizeEvent): void; onClick?(data: InitialHeaderClick): void; onDblClick?(data: InitialHeaderClick): void; } & Partial<Pick<ResizeProps, \"active\">>",
585
+ "resolved": "{ column: VirtualPositionItem; additionalData: any; data: ColumnTemplateProp<ColumnProp>; range?: RangeArea | null | undefined; canResize?: boolean | undefined; canFilter?: boolean | undefined; renderOffset?: number | undefined; onResize?(e: ResizeEvent): void; onClick?(data: InitialHeaderClick): void; onDblClick?(data: InitialHeaderClick): void; } & Partial<Pick<ResizeProps, \"active\">>",
527
586
  "references": {
528
587
  "HeaderRenderProps": {
529
588
  "location": "import",
@@ -545,7 +604,7 @@ export class RevogrHeaderComponent {
545
604
  },
546
605
  "complexType": {
547
606
  "original": "HeaderGroupRendererProps",
548
- "resolved": "{ start: number; end: number; group: Group; providers: ProvidersColumns<DimensionCols | \"rowHeaders\">; additionalData: any; canResize?: boolean | undefined; onResize?(e: ResizeEvent): void; } & Partial<Pick<ResizeProps, \"active\">>",
607
+ "resolved": "{ start: number; end: number; group: Group; providers: ProvidersColumns<DimensionCols | \"rowHeaders\">; additionalData: any; canResize?: boolean | undefined; renderOffset?: number | undefined; onResize?(e: ResizeEvent): void; } & Partial<Pick<ResizeProps, \"active\">>",
549
608
  "references": {
550
609
  "HeaderGroupRendererProps": {
551
610
  "location": "import",
@@ -581,3 +640,7 @@ export class RevogrHeaderComponent {
581
640
  }
582
641
  static get elementRef() { return "element"; }
583
642
  }
643
+ function isGroupInVisibleRange(groupStartIndex, groupEndIndex, visibleRange) {
644
+ return (groupStartIndex <= visibleRange.end &&
645
+ groupEndIndex >= visibleRange.start);
646
+ }
@@ -51,11 +51,12 @@ export default class RowOrderService {
51
51
  getRow(y, { el, rows }) {
52
52
  const { top } = el.getBoundingClientRect();
53
53
  const topRelative = y - top;
54
- const rgRow = getItemByPosition(rows, topRelative);
54
+ const rowOffset = rows.renderOffset || 0;
55
+ const rgRow = getItemByPosition(rows, topRelative + rowOffset);
55
56
  const absolutePosition = {
56
57
  itemIndex: rgRow.itemIndex,
57
- start: rgRow.start + top,
58
- end: rgRow.end + top,
58
+ start: rgRow.start - rowOffset + top,
59
+ end: rgRow.end - rowOffset + top,
59
60
  };
60
61
  return absolutePosition;
61
62
  }
@@ -64,8 +65,8 @@ export default class RowOrderService {
64
65
  const { top, left } = el.getBoundingClientRect();
65
66
  const topRelative = y - top;
66
67
  const leftRelative = x - left;
67
- const rgRow = getItemByPosition(rows, topRelative);
68
- const rgCol = getItemByPosition(cols, leftRelative);
68
+ const rgRow = getItemByPosition(rows, topRelative + (rows.renderOffset || 0));
69
+ const rgCol = getItemByPosition(cols, leftRelative + (cols.renderOffset || 0));
69
70
  return { x: rgCol.itemIndex, y: rgRow.itemIndex };
70
71
  }
71
72
  }
@@ -2,8 +2,9 @@
2
2
  * Built by Revolist OU ❤️
3
3
  */
4
4
  import { getRange } from "../../store/index";
5
- import { codesLetter, isAll, isClear, isCopy, isCut, isEnterKeyValue, isPaste, isTab, timeout, RESIZE_INTERVAL, } from "../../utils";
5
+ import { codesLetter, isAll, isClear, isCopy, isCut, isEnterKeyValue, isPaste, isShortcutModifier, isTab, timeout, RESIZE_INTERVAL, } from "../../utils";
6
6
  import { getCoordinate, isAfterLast, isBeforeFirst, } from "./selection.utils";
7
+ import { isEditInput } from "../editors/edit.utils";
7
8
  const DIRECTION_CODES = [
8
9
  codesLetter.TAB,
9
10
  codesLetter.ARROW_UP,
@@ -15,9 +16,29 @@ export class KeyboardService {
15
16
  constructor(sv) {
16
17
  this.sv = sv;
17
18
  }
19
+ /**
20
+ * Appends printable key input that arrives after edit mode was requested
21
+ * but before the editor input has mounted or received focus.
22
+ */
23
+ appendPendingEditValue(e) {
24
+ if (isShortcutModifier(e) ||
25
+ e.key.length !== 1 ||
26
+ (e.target instanceof HTMLElement && isEditInput(e.target))) {
27
+ return false;
28
+ }
29
+ const editCell = this.sv.selectionStore.get('edit');
30
+ if (typeof (editCell === null || editCell === void 0 ? void 0 : editCell.val) !== 'string') {
31
+ return false;
32
+ }
33
+ this.sv.selectionStore.set('edit', Object.assign(Object.assign({}, editCell), { val: `${editCell.val}${e.key}` }));
34
+ return true;
35
+ }
18
36
  async keyDown(e, canRange, isEditMode, { range, focus }) {
19
37
  // IF EDIT MODE
20
38
  if (isEditMode) {
39
+ if (this.appendPendingEditValue(e)) {
40
+ return;
41
+ }
21
42
  switch (e.code) {
22
43
  case codesLetter.ESCAPE:
23
44
  this.sv.cancel();
@@ -69,7 +90,7 @@ export class KeyboardService {
69
90
  return;
70
91
  }
71
92
  // pressed letter key
72
- if (e.key.length === 1) {
93
+ if (!isShortcutModifier(e) && e.key.length === 1) {
73
94
  this.sv.change(e.key);
74
95
  return;
75
96
  }
@@ -111,7 +132,8 @@ export class KeyboardService {
111
132
  }
112
133
  const eData = this.sv.getData();
113
134
  if (isMulti) {
114
- if (isAfterLast(data.end, eData.lastCell) || isBeforeFirst(data.start)) {
135
+ const isOutOfBounds = [data.start, data.end].some(cell => isAfterLast(cell, eData.lastCell) || isBeforeFirst(cell));
136
+ if (isOutOfBounds) {
115
137
  return false;
116
138
  }
117
139
  const range = getRange(data.start, data.end);