@reforgium/data-grid 2.2.0-rc.1 → 2.2.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.
package/README.md CHANGED
@@ -109,8 +109,9 @@ Supported default fields:
109
109
  | headerGroups | `GridHeaderGroup<T>[]` | `[]` | Optional top header row groups (`from`..`to`) for 2-level headers | *[NEW in 2.0.0]* |
110
110
  | pinnedRows | `GridPinnedRow<T>[]` | `[]` | Top / bottom pinned rows | |
111
111
  | isRowSticky | `(row: T, index: number) => boolean` | `undefined` | Predicate that marks rows as sticky at the top | |
112
+ | isRowDisabled | `(row: T, index: number) => boolean` | `undefined` | Predicate that marks rows as disabled (no select/click/context/double-click interactions) | |
112
113
  | getRowTemplate | `(row: T, index: number) => TemplateRef \| null` | `undefined` | Optional resolver for custom row template | |
113
- | mode | `'none' \| 'pagination' \| 'infinity'` | `'pagination'` | Grid operation mode | |
114
+ | sortMode | 'single' \| 'multi' | 'single' | Sorting mode for header clicks | |
114
115
  | pageSize | `number` | `20` | Number of items per page (pagination/infinity modes) | |
115
116
  | pageStartFromZero | `boolean` | `true` | If true, page indexing starts from 0, otherwise from 1 | |
116
117
  | hasIndexColumn | `boolean` | `false` | If true, an index column will be shown | |
@@ -129,6 +130,13 @@ Supported default fields:
129
130
 
130
131
  When selection mode is `'single'` or `'multi'`, provide a `key` (data property) and optionally `defaultSelected`.
131
132
 
133
+ Feature lazy-loading behavior (runtime `import()`):
134
+
135
+ - Selection feature is loaded when `selection.mode !== 'none'`.
136
+ - Sticky feature is loaded when `isRowSticky` is provided.
137
+ - Tooltip feature is loaded when at least one column has `tooltip`.
138
+ - Overlay-scroll feature is loaded on first scroll lifecycle usage.
139
+
132
140
  Loading behavior:
133
141
 
134
142
  - `loadingMode="spinner"`: shows centered spinner over grid content.
@@ -173,7 +181,8 @@ Row templates:
173
181
  | rowClick | `GridRowClickEvent<T>` | Emitted when a row is clicked (includes native event) | *[UPD in 2.0.0]* |
174
182
  | rowContext | `GridRowContextEvent<T>` | Emitted on row context menu | *[NEW in 2.0.0]* |
175
183
  | rowDoubleClick | `GridRowDoubleClickEvent<T>` | Emitted when a row is double-clicked | *[NEW in 2.0.0]* |
176
- | sortChange | `GridSortEvent<T>` | Emitted when sort order changes | |
184
+ | sortChange | `GridSortEvent<T>` | Emitted when single-sort order changes | |
185
+ | multiSortChange | `GridMultiSortEvent<T>` | Emitted when multi-sort order changes | *[NEW in 2.2.0]* |
177
186
  | pageChange | `GridPageChangeEvent` | Emitted when requesting data for a new page | |
178
187
  | selectChange | `GridSelectEvent<T>` | Emitted when selected rows change | |
179
188
 
@@ -181,6 +190,16 @@ Notes:
181
190
 
182
191
  - A cell click also triggers the row click event (bubbling), so listen to one or stop propagation if needed.
183
192
 
193
+ ### Public API methods
194
+
195
+ `DataGrid` exposes imperative helpers via component instance (e.g. `@ViewChild(DataGrid)`):
196
+
197
+ - `clearSelection()` - clears current selection and emits `selectChange`
198
+ - `selectAllLoaded()` - selects currently loaded rows (multi mode) and emits `selectChange`
199
+ - `resetSort()` - resets sort state and emits sort events
200
+ - `setSort(event)` - applies single-sort state and emits sort events
201
+ - `setMultiSort(items)` - applies multi-sort state and emits sort events
202
+
184
203
  ### GridColumn<T> reference
185
204
 
186
205
  `columns` accepts `GridColumn<T>[]`, where `GridColumn<T>` is a union of three column variants:
@@ -191,15 +210,15 @@ Notes:
191
210
 
192
211
  Common (base) fields:
193
212
 
194
- | Field | Type | Description |
195
- |-------------------------|---------------------------------------------------------------------|---------------------------------------------------------------------------------|
196
- | `sortKey` | `string` | Alternative key used for sorting when display `key` differs from sortable data. |
197
- | `sticky` | `'left' \| 'right' \| true` | Keeps the column fixed while horizontally scrolling. `true` pins to the left. |
198
- | `expandBy` | `DataKey<T>` | Data key that controls expand/collapse behavior for the column. |
199
- | `flex` | `number` | Flex grow factor for width distribution in flexible layouts. |
200
- | `minWidth` / `maxWidth` | `number` | Column width limits in pixels. |
201
- | `cellClass` | `string \| ((row: T) => string)` | Static CSS class or resolver per row. |
202
- | `tooltip` | `string \| ((row: T) => string) \| TemplateRef<GridTooltipContext>` | Popover tooltip content shown on cell hover. |
213
+ | Field | Type | Description | |
214
+ |-------------------------|-----------------------------------------------------------------------------|----------------------------------------------------------------------------------------|------------------|
215
+ | `sortKey` | `string` | Alternative key used for sorting when display `key` differs from sortable data. | |
216
+ | `sticky` | `'left' \| 'right' \| true` | Keeps the column fixed while horizontally scrolling. `true` pins to the left. | |
217
+ | `expandBy` | `DataKey<T>` | Data key that controls expand/collapse behavior for the column. | |
218
+ | `flex` | `number` | Flex grow factor for width distribution in flexible layouts. | |
219
+ | `minWidth` / `maxWidth` | `number` | Column width limits in pixels. | |
220
+ | `cellClass` | `string \| ((row: T) => string)` | Static CSS class or resolver per row. | |
221
+ | `tooltip` | `true \| string \| ((row: T) => string) \| TemplateRef<GridTooltipContext>` | Popover tooltip content shown on cell hover. `true` uses the cell value automatically. | *[NEW in 2.2.0]* |
203
222
 
204
223
  Renderer-specific fields:
205
224
 
@@ -253,6 +272,7 @@ Notes:
253
272
 
254
273
  ```ts
255
274
  columns = [
275
+ { key: 'name', header: 'Name', tooltip: true }, // auto tooltip from cell value
256
276
  { key: 'email', header: 'Email', tooltip: (row) => row.email },
257
277
  { key: 'status', header: 'Status', tooltip: 'User status' },
258
278
  ];
@@ -424,6 +444,12 @@ Checkbox:
424
444
  - `--re-data-grid-checkbox-surface` - checkbox background (`var(--surface-neutral, #fff)`)
425
445
  - `--re-data-grid-checkbox-active-color` - checkbox active color (`var(--primary-color, #2563eb)`)
426
446
 
447
+ Focus Ring:
448
+
449
+ - `--re-data-grid-focus-ring-color` - keyboard focus outline color (`color-mix(in srgb, var(--primary-color, #2a90f4) 55%, transparent)`)
450
+ - `--re-data-grid-focus-ring-width` - keyboard focus outline width (`2px`)
451
+ - `--re-data-grid-focus-ring-offset` - keyboard focus outline offset (`-2px`)
452
+
427
453
  Sticky Cells:
428
454
 
429
455
  - `--re-data-grid-sticky-header-cell-surface` - sticky header cell background (`#fff`)
@@ -0,0 +1,79 @@
1
+ import { c as computeScrollbarState, a as clampThumbTop, m as mapThumbTopToScrollTop } from './reforgium-data-grid-reforgium-data-grid-uZ3onkWO.mjs';
2
+
3
+ function createGridOverlayScrollFeature(ctx) {
4
+ const showScrollbar = () => {
5
+ ctx.setScrollbarVisible(true);
6
+ clearTimeout(ctx.getHideTimeout());
7
+ };
8
+ const hideScrollbarSoon = (delay = 1200) => {
9
+ if (ctx.isDragging()) {
10
+ return;
11
+ }
12
+ clearTimeout(ctx.getHideTimeout());
13
+ ctx.setHideTimeout(setTimeout(() => ctx.setScrollbarVisible(false), delay));
14
+ };
15
+ const onThumbDown = (event) => {
16
+ event.preventDefault();
17
+ event.stopPropagation();
18
+ const scrollEl = ctx.getScrollElement();
19
+ if (!scrollEl) {
20
+ return;
21
+ }
22
+ ctx.setDragging(true);
23
+ showScrollbar();
24
+ const startY = event.clientY;
25
+ const startTop = ctx.getThumbTop();
26
+ const state = computeScrollbarState(scrollEl.scrollHeight || 1, scrollEl.clientHeight || 1, scrollEl.scrollTop || 0);
27
+ const maxThumbTop = state.maxThumbTop || 1;
28
+ const maxScrollTop = state.maxScrollTop || 1;
29
+ const onMove = (moveEvent) => {
30
+ const delta = moveEvent.clientY - startY;
31
+ const newTop = clampThumbTop(startTop + delta, maxThumbTop);
32
+ ctx.setThumbTop(newTop);
33
+ scrollEl.scrollTop = mapThumbTopToScrollTop(newTop, maxThumbTop, maxScrollTop);
34
+ ctx.calcScrollbar();
35
+ showScrollbar();
36
+ };
37
+ const onUp = () => {
38
+ window.removeEventListener('mousemove', onMove);
39
+ window.removeEventListener('mouseup', onUp);
40
+ ctx.setDragging(false);
41
+ hideScrollbarSoon();
42
+ };
43
+ window.addEventListener('mousemove', onMove);
44
+ window.addEventListener('mouseup', onUp);
45
+ };
46
+ const scheduleScrollbarUpdate = () => {
47
+ if (ctx.getScrollbarRafId() !== null) {
48
+ return;
49
+ }
50
+ ctx.setScrollbarRafId(requestAnimationFrame(() => {
51
+ ctx.setScrollbarRafId(null);
52
+ ctx.calcScrollbar();
53
+ }));
54
+ };
55
+ const clearScrollbarRaf = () => {
56
+ const rafId = ctx.getScrollbarRafId();
57
+ if (rafId === null) {
58
+ return;
59
+ }
60
+ cancelAnimationFrame(rafId);
61
+ ctx.setScrollbarRafId(null);
62
+ };
63
+ const finalizeScroll = () => {
64
+ scheduleScrollbarUpdate();
65
+ showScrollbar();
66
+ hideScrollbarSoon();
67
+ };
68
+ return {
69
+ onThumbDown,
70
+ showScrollbar,
71
+ hideScrollbarSoon,
72
+ scheduleScrollbarUpdate,
73
+ clearScrollbarRaf,
74
+ finalizeScroll,
75
+ };
76
+ }
77
+
78
+ export { createGridOverlayScrollFeature };
79
+ //# sourceMappingURL=reforgium-data-grid-grid-overlay-scroll.feature-B3hwiKYh.mjs.map
@@ -0,0 +1,54 @@
1
+ // noinspection ES6PreferShortImport
2
+ function createGridSelectionFeature(ctx) {
3
+ const clearSelection = () => {
4
+ ctx.clearSelectedKeys();
5
+ ctx.emitSelectChange([]);
6
+ };
7
+ const selectAllLoaded = () => {
8
+ if (ctx.getSelectionMode() !== 'multi') {
9
+ return;
10
+ }
11
+ ctx.emitSelectChange(ctx.selectAll());
12
+ };
13
+ const onSelectAll = (event) => {
14
+ event?.preventDefault();
15
+ event?.stopPropagation();
16
+ selectAllLoaded();
17
+ };
18
+ const onCheckboxToggle = (row, index, event) => {
19
+ event?.preventDefault();
20
+ event?.stopPropagation();
21
+ if (ctx.isRowDisabled(row, index)) {
22
+ return;
23
+ }
24
+ if (ctx.getSelectionMode() === 'none') {
25
+ return;
26
+ }
27
+ ctx.emitSelectChange(ctx.selectRow(row));
28
+ };
29
+ const onSelectAllKeydown = (event) => {
30
+ const key = event.key;
31
+ if (key !== 'Enter' && key !== ' ') {
32
+ return;
33
+ }
34
+ onSelectAll(event);
35
+ };
36
+ const onCheckboxKeydown = (row, index, event) => {
37
+ const key = event.key;
38
+ if (key !== 'Enter' && key !== ' ') {
39
+ return;
40
+ }
41
+ onCheckboxToggle(row, index, event);
42
+ };
43
+ return {
44
+ clearSelection,
45
+ selectAllLoaded,
46
+ onSelectAll,
47
+ onCheckboxToggle,
48
+ onSelectAllKeydown,
49
+ onCheckboxKeydown,
50
+ };
51
+ }
52
+
53
+ export { createGridSelectionFeature };
54
+ //# sourceMappingURL=reforgium-data-grid-grid-selection.feature-CGRNpMeD.mjs.map
@@ -0,0 +1,86 @@
1
+ function createGridStickyFeature(ctx) {
2
+ const isStickyRowIndex = (index) => {
3
+ return ctx.getStickyRowIndex() === index;
4
+ };
5
+ const findStickyIndexBefore = (indexes, index) => {
6
+ let low = 0;
7
+ let high = indexes.length - 1;
8
+ let result = -1;
9
+ while (low <= high) {
10
+ const mid = (low + high) >>> 1;
11
+ const value = indexes[mid];
12
+ if (value <= index) {
13
+ result = value;
14
+ low = mid + 1;
15
+ }
16
+ else {
17
+ high = mid - 1;
18
+ }
19
+ }
20
+ return result === -1 ? null : result;
21
+ };
22
+ const updateStickyRow = (scrollTop, rowHeight, pinnedTopH) => {
23
+ const indexes = ctx.getStickyIndexes();
24
+ if (!indexes.length) {
25
+ ctx.setStickyRowIndex(null);
26
+ return;
27
+ }
28
+ const scrollRowIndex = Math.max(0, Math.floor(scrollTop / rowHeight));
29
+ const currentIndex = findStickyIndexBefore(indexes, scrollRowIndex);
30
+ if (currentIndex === null) {
31
+ ctx.setStickyRowIndex(null);
32
+ return;
33
+ }
34
+ let activeIndex = currentIndex;
35
+ const prevIndex = ctx.getStickyRowIndex();
36
+ const hysteresisPx = Math.max(1, rowHeight * 0.5);
37
+ if (prevIndex !== null && prevIndex !== currentIndex) {
38
+ const boundaryPx = currentIndex * rowHeight;
39
+ const delta = Math.abs(scrollTop - boundaryPx);
40
+ if (delta < hysteresisPx) {
41
+ activeIndex = prevIndex;
42
+ }
43
+ }
44
+ const stickyTop = ctx.getHeaderHeight() + pinnedTopH;
45
+ const topPx = scrollTop + stickyTop;
46
+ ctx.setStickyRowIndex(activeIndex);
47
+ ctx.setStickyRowTopPx(topPx);
48
+ };
49
+ const updateStickyFromScroll = () => {
50
+ const el = ctx.getScrollElement();
51
+ if (!el) {
52
+ return;
53
+ }
54
+ const scrollTop = el.scrollTop ?? 0;
55
+ const rowHeight = Math.max(1, ctx.getRowHeight());
56
+ const pinnedTopH = ctx.getPinnedTopCount() * rowHeight;
57
+ updateStickyRow(scrollTop, rowHeight, pinnedTopH);
58
+ };
59
+ const scheduleStickyUpdate = () => {
60
+ if (ctx.getStickyRafId() !== null) {
61
+ return;
62
+ }
63
+ ctx.setStickyRafId(requestAnimationFrame(() => {
64
+ ctx.setStickyRafId(null);
65
+ ctx.runInAngular(() => updateStickyFromScroll());
66
+ }));
67
+ };
68
+ const clearStickyRaf = () => {
69
+ const rafId = ctx.getStickyRafId();
70
+ if (rafId === null) {
71
+ return;
72
+ }
73
+ cancelAnimationFrame(rafId);
74
+ ctx.setStickyRafId(null);
75
+ };
76
+ return {
77
+ isStickyRowIndex,
78
+ updateStickyRow,
79
+ updateStickyFromScroll,
80
+ scheduleStickyUpdate,
81
+ clearStickyRaf,
82
+ };
83
+ }
84
+
85
+ export { createGridStickyFeature };
86
+ //# sourceMappingURL=reforgium-data-grid-grid-sticky.feature-DBpn_6R8.mjs.map
@@ -0,0 +1,89 @@
1
+ function createGridTooltipFeature(ctx) {
2
+ const resolveCellValue = (row, col) => {
3
+ return 'value' in col ? col.value(row) : row[col.key];
4
+ };
5
+ const resolveTooltip = (row, col) => {
6
+ const tooltip = col.tooltip;
7
+ if (!tooltip) {
8
+ return null;
9
+ }
10
+ if (tooltip === true) {
11
+ const baseValue = resolveCellValue(row, col);
12
+ if (baseValue === null || baseValue === undefined || baseValue === '') {
13
+ return null;
14
+ }
15
+ return String(baseValue);
16
+ }
17
+ if (typeof tooltip === 'function') {
18
+ const value = tooltip(row);
19
+ if (value === null || value === undefined || value === '') {
20
+ return null;
21
+ }
22
+ return String(value);
23
+ }
24
+ if (typeof tooltip === 'string') {
25
+ return tooltip === '' ? null : tooltip;
26
+ }
27
+ return tooltip;
28
+ };
29
+ const showTooltip = (event, row, col, index) => {
30
+ const resolved = resolveTooltip(row, col);
31
+ if (!resolved) {
32
+ return;
33
+ }
34
+ const baseValue = resolveCellValue(row, col);
35
+ const context = {
36
+ $implicit: row,
37
+ row,
38
+ col: col,
39
+ index,
40
+ value: baseValue,
41
+ };
42
+ const offset = 12;
43
+ const x = event.clientX + offset;
44
+ const y = event.clientY + offset;
45
+ if (typeof resolved === 'string') {
46
+ ctx.setTooltipState({ text: resolved, x, y, visible: true });
47
+ }
48
+ else {
49
+ ctx.setTooltipState({ tpl: resolved, ctx: context, x, y, visible: true });
50
+ }
51
+ ctx.requestPositioning();
52
+ };
53
+ const hideTooltip = () => {
54
+ if (!ctx.getTooltipState().visible) {
55
+ return;
56
+ }
57
+ ctx.patchTooltipState({ visible: false });
58
+ };
59
+ const positionTooltip = (tooltipEl) => {
60
+ const state = ctx.getTooltipState();
61
+ if (!tooltipEl || !state.visible) {
62
+ return;
63
+ }
64
+ const rect = tooltipEl.getBoundingClientRect();
65
+ const padding = 8;
66
+ const vw = window.innerWidth;
67
+ const vh = window.innerHeight;
68
+ let x = state.x;
69
+ let y = state.y;
70
+ if (x + rect.width + padding > vw) {
71
+ x = Math.max(padding, vw - rect.width - padding);
72
+ }
73
+ if (y + rect.height + padding > vh) {
74
+ y = Math.max(padding, vh - rect.height - padding);
75
+ }
76
+ if (x !== state.x || y !== state.y) {
77
+ ctx.patchTooltipState({ x, y });
78
+ }
79
+ };
80
+ return {
81
+ resolveTooltip,
82
+ showTooltip,
83
+ hideTooltip,
84
+ positionTooltip,
85
+ };
86
+ }
87
+
88
+ export { createGridTooltipFeature };
89
+ //# sourceMappingURL=reforgium-data-grid-grid-tooltip.feature-CMo88m8o.mjs.map