@nova-design-system/nova-react 3.27.0 → 3.29.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.
- package/README.md +1 -1
- package/dist/cjs/generated/components.server.js +24 -0
- package/dist/cjs/index-DgKzi_Pd.js +10208 -0
- package/dist/cjs/index.js +4 -1
- package/dist/cjs/nova-datetime-CyL2J6O4-0Y9g3rfI.js +10531 -0
- package/dist/cjs/{nv-accordion-item.entry-Gn0QFETn.js → nv-accordion-item.entry-D1o0gC5w.js} +3 -3
- package/dist/cjs/{nv-accordion.entry-BooppL5C.js → nv-accordion.entry-DYJtq9Az.js} +1 -1
- package/dist/cjs/{nv-alert.entry-CDmHhq86.js → nv-alert.entry-CMtCdHmk.js} +2 -2
- package/dist/cjs/{nv-avatar.entry-pYMjQvxK.js → nv-avatar.entry-B6e7aG4W.js} +1 -1
- package/dist/cjs/{nv-badge_2.entry-BneUUyR7.js → nv-badge_2.entry-RD3j0bJM.js} +8 -7
- package/dist/cjs/{nv-breadcrumb.entry-B7CGcJ_l.js → nv-breadcrumb.entry-DgpqY2fr.js} +1 -1
- package/dist/cjs/{nv-breadcrumbs.entry-BNKz4ehX.js → nv-breadcrumbs.entry-CZgcDUw5.js} +1 -1
- package/dist/cjs/{nv-button.entry-DDCkNY_S.js → nv-button.entry-DR9NaRxG.js} +1 -1
- package/dist/cjs/{nv-buttongroup.entry-Bio-SWcx.js → nv-buttongroup.entry-qO8r7WqG.js} +1 -1
- package/dist/cjs/{nv-calendar.entry-BoNFEz6W.js → nv-calendar.entry-DRlv3Xph.js} +1 -1
- package/dist/cjs/{nv-col.entry-BHTqFTHl.js → nv-col.entry-B7utJttP.js} +2 -2
- package/dist/cjs/{nv-datagrid.entry-Bw_sqaMu.js → nv-datagrid.entry-digYmlnA.js} +1 -1
- package/dist/cjs/{nv-datagridcolumn.entry-Z-RXn3ak.js → nv-datagridcolumn.entry-UwaDi-Hr.js} +1 -1
- package/dist/cjs/nv-datetest.entry-BJtWaM2T.js +69 -0
- package/dist/cjs/nv-datetimetest.entry-WaNPcHxh.js +57 -0
- package/dist/cjs/{nv-dialog.entry-ByZkK4F9.js → nv-dialog.entry-BI_mFT2G.js} +2 -2
- package/dist/cjs/{nv-dialogfooter_2.entry-Bddcz6HA.js → nv-dialogfooter_2.entry-DU2ClBUR.js} +7 -5
- package/dist/cjs/{nv-drawer.entry-660dihzy.js → nv-drawer.entry-BKF4CyOt.js} +2 -2
- package/dist/cjs/{nv-drawerfooter_2.entry-D6EA-3-u.js → nv-drawerfooter_2.entry-BSyUs7_4.js} +5 -3
- package/dist/cjs/{nv-fieldcheckbox.entry-Bm6qurcS.js → nv-fieldcheckbox.entry-l5FWToQi.js} +5 -5
- package/dist/cjs/{nv-fielddate.entry-DW9RQ_dD.js → nv-fielddate.entry-BfviesNp.js} +8 -8
- package/dist/cjs/{nv-fielddaterange.entry-m3dY0P2v.js → nv-fielddaterange.entry-BvDkPLXG.js} +8 -8
- package/dist/cjs/{nv-fielddropdown.entry-DkARzQix.js → nv-fielddropdown.entry-B-nYjuMt.js} +6 -6
- package/dist/cjs/{nv-fielddropdownitem.entry-DKG1bO2H.js → nv-fielddropdownitem.entry-Dxqyb9DN.js} +2 -2
- package/dist/cjs/{nv-fieldmultiselect.entry-B4As0NxI.js → nv-fieldmultiselect.entry-CgO1RP0W.js} +115 -86
- package/dist/cjs/{nv-fieldnumber.entry-DHBPKUcr.js → nv-fieldnumber.entry-stgdLi7x.js} +6 -6
- package/dist/cjs/{nv-fieldpassword.entry-DxEaIvRh.js → nv-fieldpassword.entry-CHA3JAUd.js} +6 -6
- package/dist/cjs/{nv-fieldradio.entry-MSrPlSzv.js → nv-fieldradio.entry-DHavVjB-.js} +4 -4
- package/dist/cjs/{nv-fieldselect.entry-qMAtqdcr.js → nv-fieldselect.entry-Dq5AsOFt.js} +7 -7
- package/dist/cjs/{nv-fieldslider.entry-CHdMG-lt.js → nv-fieldslider.entry-SlF3BBUW.js} +4 -4
- package/dist/cjs/{nv-fieldtext.entry-tbYFUJP9.js → nv-fieldtext.entry-BYCc8SyD.js} +6 -6
- package/dist/cjs/{nv-fieldtextarea.entry-D7b3-4Ar.js → nv-fieldtextarea.entry-96JCOb9L.js} +5 -5
- package/dist/cjs/{nv-fieldtime.entry-TSPljEeW.js → nv-fieldtime.entry-BdzjxkaK.js} +15 -12
- package/dist/cjs/nv-icon.entry-CSRxi6BH.js +80 -0
- package/dist/cjs/{nv-iconbutton_2.entry-Ch0rfD12.js → nv-iconbutton_2.entry-BtDxwMFD.js} +3 -3
- package/dist/cjs/{nv-menu.entry-BKLyCbyy.js → nv-menu.entry-aX39SPH8.js} +2 -2
- package/dist/cjs/{nv-menuitem.entry-BBK6uQav.js → nv-menuitem.entry-DzSp52G2.js} +2 -2
- package/dist/cjs/{nv-notification-bullet.entry-Dk0oaUTe.js → nv-notification-bullet.entry-D2yOXj46.js} +1 -1
- package/dist/cjs/{nv-notification.entry-DVUXuj9T.js → nv-notification.entry-BRXHbtT8.js} +2 -2
- package/dist/cjs/{nv-notificationcontainer.entry-BQbB0vJ8.js → nv-notificationcontainer.entry-YNIM2_ah.js} +2 -14
- package/dist/cjs/{nv-pagination-nav.entry-BON8ve70.js → nv-pagination-nav.entry-uY1nT9aT.js} +2 -2
- package/dist/cjs/{nv-paginationtable.entry-pT2Qx3xY.js → nv-paginationtable.entry-mr5KYXVC.js} +2 -2
- package/dist/cjs/{nv-popover.entry-91VegZzi.js → nv-popover.entry-_9ARKM70.js} +2 -2
- package/dist/cjs/{nv-row.entry-C_75GYAm.js → nv-row.entry-BMQvcqlU.js} +2 -2
- package/dist/cjs/{nv-sidebar.entry-XIcDybjF.js → nv-sidebar.entry-C4HTjJmz.js} +2 -2
- package/dist/cjs/{nv-sidebarcontent.entry-JSf1Mb0x.js → nv-sidebarcontent.entry-llnRwVuj.js} +2 -2
- package/dist/cjs/{nv-sidebardivider.entry-XZ1hYAgj.js → nv-sidebardivider.entry--rQv8d5T.js} +2 -2
- package/dist/cjs/{nv-sidebarfooter.entry-BHO9gh6y.js → nv-sidebarfooter.entry-C5R0sUI_.js} +2 -2
- package/dist/cjs/{nv-sidebargroup.entry-DAb7dWFF.js → nv-sidebargroup.entry-DdrpLbU7.js} +2 -2
- package/dist/cjs/{nv-sidebarheader.entry-BksZP_km.js → nv-sidebarheader.entry-HuBPIsyf.js} +2 -2
- package/dist/cjs/{nv-sidebarlogo.entry-BntEWmH_.js → nv-sidebarlogo.entry-TZNPoqnA.js} +2 -2
- package/dist/cjs/{nv-sidebarnavitem.entry-DSu34C34.js → nv-sidebarnavitem.entry-BWc3mF5I.js} +3 -3
- package/dist/cjs/{nv-sidebarnavsubitem.entry-Y8Ex0_Lr.js → nv-sidebarnavsubitem.entry-DekANwO8.js} +2 -2
- package/dist/cjs/{nv-split.entry-BDr6FxCd.js → nv-split.entry-BOwOB8FW.js} +2 -2
- package/dist/cjs/{nv-stack.entry-CChjKrA3.js → nv-stack.entry-CaTiSLGN.js} +2 -2
- package/dist/cjs/{nv-table.entry-CfqHpj1L.js → nv-table.entry-LFZaS0Dy.js} +3 -3
- package/dist/cjs/{nv-tableheader.entry-C61xO9Ra.js → nv-tableheader.entry-CK50S8xW.js} +2 -2
- package/dist/cjs/nv-timetest.entry-A9elKwkf.js +75 -0
- package/dist/cjs/{nv-toggle.entry-B0HofO36.js → nv-toggle.entry-BGu-6rEs.js} +3 -3
- package/dist/cjs/{nv-togglebutton.entry-CzyNiZyK.js → nv-togglebutton.entry-BzAcBOgN.js} +2 -2
- package/dist/cjs/{nv-togglebuttongroup.entry-TizvIVlB.js → nv-togglebuttongroup.entry-CIWp7IXc.js} +2 -2
- package/dist/cjs/{nv-tooltip.entry-0kcGcQZo.js → nv-tooltip.entry-CoGkSHpv.js} +9 -4
- package/dist/components/NvDatatable/NvDatatable.js +384 -65
- package/dist/components/NvDatatable/selectionState.js +45 -0
- package/dist/components/NvDatatable/selectionState.test.js +74 -0
- package/dist/generated/components.js +38 -0
- package/dist/generated/components.server.js +21 -0
- package/dist/types/components/NvDatatable/NvDatatable.d.ts +1 -1
- package/dist/types/components/NvDatatable/selectionState.d.ts +21 -0
- package/dist/types/components/NvDatatable/selectionState.test.d.ts +1 -0
- package/dist/types/components/NvDatatable/types.d.ts +22 -0
- package/dist/types/generated/components.d.ts +51 -1
- package/dist/types/generated/components.server.d.ts +51 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/providers/NotificationProvider.d.ts +2 -2
- package/package.json +6 -4
- package/dist/cjs/index-clzdrCkN.js +0 -9713
- package/dist/cjs/nv-icon.entry-BtmsouTL.js +0 -80
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var index = require('./index-
|
|
3
|
+
var index = require('./index-DgKzi_Pd.js');
|
|
4
4
|
require('@stencil/react-output-target/runtime');
|
|
5
5
|
require('react');
|
|
6
6
|
require('react-dom');
|
|
@@ -57,7 +57,7 @@ const NvTogglebutton = class {
|
|
|
57
57
|
/****************************************************************************/
|
|
58
58
|
//#region RENDER
|
|
59
59
|
render() {
|
|
60
|
-
return (index.h(index.Host, { key: '
|
|
60
|
+
return (index.h(index.Host, { key: '8e700d38ba155b977d4efa0d9e01b41e73fc4413', role: "button", tabindex: "0", "aria-pressed": String(this.active), onClick: this.handleClick }, index.h("slot", { key: '92427015839f98b0d9238b8df6af8e08ee511153' })));
|
|
61
61
|
}
|
|
62
62
|
get el() { return index.getElement(this); }
|
|
63
63
|
};
|
package/dist/cjs/{nv-togglebuttongroup.entry-TizvIVlB.js → nv-togglebuttongroup.entry-CIWp7IXc.js}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var index = require('./index-
|
|
3
|
+
var index = require('./index-DgKzi_Pd.js');
|
|
4
4
|
require('@stencil/react-output-target/runtime');
|
|
5
5
|
require('react');
|
|
6
6
|
require('react-dom');
|
|
@@ -156,7 +156,7 @@ const NvTogglebuttongroup = class {
|
|
|
156
156
|
/****************************************************************************/
|
|
157
157
|
//#region RENDER
|
|
158
158
|
render() {
|
|
159
|
-
return (index.h(index.Host, { key: '
|
|
159
|
+
return (index.h(index.Host, { key: '2026cb95db8b57f2a1cd4ea53608f336843b63fe' }, index.h("slot", { key: '5c06ab59d6c99e789c3a1c3a8a4842a0772ca3a2' })));
|
|
160
160
|
}
|
|
161
161
|
get el() { return index.getElement(this); }
|
|
162
162
|
static get watchers() { return {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var index = require('./index-
|
|
3
|
+
var index = require('./index-DgKzi_Pd.js');
|
|
4
4
|
require('@stencil/react-output-target/runtime');
|
|
5
5
|
require('react');
|
|
6
6
|
require('react-dom');
|
|
@@ -39,15 +39,20 @@ const NvTooltip = class {
|
|
|
39
39
|
/****************************************************************************/
|
|
40
40
|
//#region LIFECYCLE
|
|
41
41
|
componentDidRender() {
|
|
42
|
-
if (
|
|
42
|
+
if (!this.popoverElement)
|
|
43
43
|
return;
|
|
44
|
-
|
|
44
|
+
const trigger = this.triggerElement ??
|
|
45
|
+
this.defaultSlot?.nextElementSibling ??
|
|
46
|
+
this.el.querySelector(':scope > :not(nv-popover):not(slot):not([slot])');
|
|
47
|
+
if (trigger && this.popoverElement.triggerElement !== trigger) {
|
|
48
|
+
this.popoverElement.triggerElement = trigger;
|
|
49
|
+
}
|
|
45
50
|
}
|
|
46
51
|
//#endregion LIFECYCLE
|
|
47
52
|
/****************************************************************************/
|
|
48
53
|
//#region RENDER
|
|
49
54
|
render() {
|
|
50
|
-
return (index.h(index.Host, { key: '
|
|
55
|
+
return (index.h(index.Host, { key: '8285fbb412cb45cc7baf2936f0405c0438395c8d' }, index.h("nv-popover", { key: '29d70e9baa826de35d2cdca88f48610d70ec55e4', ref: el => (this.popoverElement = el), triggerMode: "hover", hasArrow: true, placement: this.placement, strategy: this.strategy, groupName: 'tooltip', enterDelay: this.enterDelay, onOpenChanged: e => this.openChanged.emit(e.detail) }, index.h("p", { key: 'a9c907fa96f9c4108a8d84cec53981218c060811', slot: "content" }, this.message), index.h("slot", { key: 'af1b7ac8069071fe2d41e925f1c0090f8b6aaab5', name: "content" })), index.h("slot", { key: 'e5d3c6d16fb7e4a682b66e0016d9e4e30e5647e0', ref: el => (this.defaultSlot = el) })));
|
|
51
56
|
}
|
|
52
57
|
get el() { return index.getElement(this); }
|
|
53
58
|
};
|
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
import React, { useMemo, useState, useEffect, useRef, useCallback, } from 'react';
|
|
2
2
|
import { flexRender, getCoreRowModel, getPaginationRowModel, getSortedRowModel, getFilteredRowModel, useReactTable, } from '@tanstack/react-table';
|
|
3
|
-
import { NvTable, NvTableheader, NvPaginationtable, } from '../../generated/components';
|
|
3
|
+
import { NvTable, NvTableheader, NvPaginationtable, NvFieldcheckbox, } from '../../generated/components';
|
|
4
4
|
import { defineCustomElement as defineNvPaginationtable } from '@nova-design-system/nova-webcomponents/dist/components/nv-paginationtable.js';
|
|
5
5
|
if (typeof window !== 'undefined' &&
|
|
6
6
|
!customElements.get('nv-paginationtable')) {
|
|
7
7
|
defineNvPaginationtable();
|
|
8
8
|
}
|
|
9
|
-
|
|
9
|
+
import { applyRowSelection, applySelectAllSelection, shouldIgnoreSelectAllEvent, } from './selectionState';
|
|
10
|
+
function NvDatatable({ mode = 'client', columns, rows, pagination, sorting, filtering, selection, renderPagination, renderFiltering, onRowClick, stickyHeader, ...htmlProps }) {
|
|
11
|
+
const areSetsEqual = useCallback((a, b) => {
|
|
12
|
+
if (a.size !== b.size) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
for (const value of a) {
|
|
16
|
+
if (!b.has(value)) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return true;
|
|
21
|
+
}, []);
|
|
10
22
|
const isInfiniteScroll = pagination?.infinite && mode === 'server';
|
|
11
23
|
const [paginationState, setPaginationState] = useState({
|
|
12
24
|
pageIndex: 0,
|
|
@@ -14,7 +26,19 @@ function NvDatatable({ mode = 'client', columns, rows, pagination, sorting, filt
|
|
|
14
26
|
});
|
|
15
27
|
const [sortingState, setSortingState] = useState(sorting?.sortState || []);
|
|
16
28
|
const [globalFilterState, setGlobalFilterState] = useState(filtering?.filterState);
|
|
29
|
+
const [selectedRowIdsState, setSelectedRowIdsState] = useState(() => new Set(selection?.selectedRowIds ?? []));
|
|
30
|
+
const selectedRowIdsRef = useRef(new Set(selection?.selectedRowIds ?? []));
|
|
31
|
+
const selectionMode = selection?.mode ?? 'none';
|
|
32
|
+
const selectionEnabled = selectionMode !== 'none';
|
|
33
|
+
const selectAllEnabled = selection?.enableSelectAll ?? true;
|
|
34
|
+
const rowClickEnabled = typeof onRowClick === 'function';
|
|
35
|
+
const getSelectionRowId = useCallback((row) => selection?.getRowId?.(row) ?? '', [selection]);
|
|
17
36
|
const lastRowRef = useRef(null);
|
|
37
|
+
const selectAllIntentRef = useRef(false);
|
|
38
|
+
const rowSelectionIntentRef = useRef(null);
|
|
39
|
+
const selectAllIntentResetTimerRef = useRef(null);
|
|
40
|
+
const rowSelectionIntentResetTimerRef = useRef(null);
|
|
41
|
+
const INTENT_RESET_DELAY_MS = 16;
|
|
18
42
|
const debouncedSetFilter = useRef(null);
|
|
19
43
|
const setGlobalFilterDebounced = useCallback((value) => {
|
|
20
44
|
const debounceMs = filtering?.debounceMs ?? 300;
|
|
@@ -33,6 +57,12 @@ function NvDatatable({ mode = 'client', columns, rows, pagination, sorting, filt
|
|
|
33
57
|
if (debouncedSetFilter.current) {
|
|
34
58
|
clearTimeout(debouncedSetFilter.current);
|
|
35
59
|
}
|
|
60
|
+
if (selectAllIntentResetTimerRef.current) {
|
|
61
|
+
clearTimeout(selectAllIntentResetTimerRef.current);
|
|
62
|
+
}
|
|
63
|
+
if (rowSelectionIntentResetTimerRef.current) {
|
|
64
|
+
clearTimeout(rowSelectionIntentResetTimerRef.current);
|
|
65
|
+
}
|
|
36
66
|
};
|
|
37
67
|
}, []);
|
|
38
68
|
useEffect(() => {
|
|
@@ -40,60 +70,89 @@ function NvDatatable({ mode = 'client', columns, rows, pagination, sorting, filt
|
|
|
40
70
|
setGlobalFilterState(filtering.filterState);
|
|
41
71
|
}
|
|
42
72
|
}, [filtering?.filterState]);
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
value: rawValue,
|
|
54
|
-
row,
|
|
55
|
-
field: col.field,
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
: undefined,
|
|
59
|
-
header: col.renderHeader
|
|
60
|
-
? () => col.renderHeader({
|
|
61
|
-
headerName,
|
|
62
|
-
field: col.field,
|
|
63
|
-
})
|
|
64
|
-
: headerName,
|
|
65
|
-
size: col.width,
|
|
66
|
-
enableResizing: col.resizable ?? true,
|
|
67
|
-
enableSorting: sorting ? col.sortable ?? true : false,
|
|
68
|
-
cell: (context) => {
|
|
69
|
-
const value = context.getValue();
|
|
70
|
-
const row = context.row.original;
|
|
71
|
-
const rowIndex = context.row.index;
|
|
72
|
-
if (col.renderCell) {
|
|
73
|
-
return col.renderCell({
|
|
74
|
-
value,
|
|
75
|
-
row,
|
|
76
|
-
field: col.field,
|
|
77
|
-
rowIndex,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
return value;
|
|
81
|
-
},
|
|
82
|
-
};
|
|
83
|
-
if (col.sortingFn !== undefined) {
|
|
84
|
-
columnDef.sortingFn = col.sortingFn;
|
|
85
|
-
}
|
|
86
|
-
if (col.sortDescFirst !== undefined) {
|
|
87
|
-
columnDef.sortDescFirst = col.sortDescFirst;
|
|
88
|
-
}
|
|
89
|
-
if (col.invertSorting !== undefined) {
|
|
90
|
-
columnDef.invertSorting = col.invertSorting;
|
|
73
|
+
if (selectionEnabled && !selection?.getRowId) {
|
|
74
|
+
throw new Error('NvDatatable selection requires selection.getRowId when selection.mode is not "none".');
|
|
75
|
+
}
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
if (selection?.selectedRowIds) {
|
|
78
|
+
const controlledIds = new Set(selection.selectedRowIds);
|
|
79
|
+
if (!areSetsEqual(selectedRowIdsState, controlledIds)) {
|
|
80
|
+
selectedRowIdsRef.current = controlledIds;
|
|
81
|
+
setSelectedRowIdsState(controlledIds);
|
|
82
|
+
}
|
|
91
83
|
}
|
|
92
|
-
|
|
93
|
-
|
|
84
|
+
}, [selection?.selectedRowIds, selectedRowIdsState, areSetsEqual]);
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
selectedRowIdsRef.current = selectedRowIdsState;
|
|
87
|
+
}, [selectedRowIdsState]);
|
|
88
|
+
const tableColumns = useMemo(() => {
|
|
89
|
+
const dataColumns = columns
|
|
90
|
+
.filter((col) => !col.hidden)
|
|
91
|
+
.map((col) => {
|
|
92
|
+
const headerName = col.headerName || String(col.field);
|
|
93
|
+
const columnDef = {
|
|
94
|
+
accessorKey: col.field,
|
|
95
|
+
accessorFn: col.valueFormatter
|
|
96
|
+
? (row) => {
|
|
97
|
+
const rawValue = row[col.field];
|
|
98
|
+
return col.valueFormatter({
|
|
99
|
+
value: rawValue,
|
|
100
|
+
row,
|
|
101
|
+
field: col.field,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
: undefined,
|
|
105
|
+
header: col.renderHeader
|
|
106
|
+
? () => col.renderHeader({
|
|
107
|
+
headerName,
|
|
108
|
+
field: col.field,
|
|
109
|
+
})
|
|
110
|
+
: headerName,
|
|
111
|
+
size: col.width,
|
|
112
|
+
enableResizing: col.resizable ?? true,
|
|
113
|
+
enableSorting: sorting ? col.sortable ?? true : false,
|
|
114
|
+
cell: (context) => {
|
|
115
|
+
const value = context.getValue();
|
|
116
|
+
const row = context.row.original;
|
|
117
|
+
const rowIndex = context.row.index;
|
|
118
|
+
if (col.renderCell) {
|
|
119
|
+
return col.renderCell({
|
|
120
|
+
value,
|
|
121
|
+
row,
|
|
122
|
+
field: col.field,
|
|
123
|
+
rowIndex,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
return value;
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
if (col.sortingFn !== undefined) {
|
|
130
|
+
columnDef.sortingFn = col.sortingFn;
|
|
131
|
+
}
|
|
132
|
+
if (col.sortDescFirst !== undefined) {
|
|
133
|
+
columnDef.sortDescFirst = col.sortDescFirst;
|
|
134
|
+
}
|
|
135
|
+
if (col.invertSorting !== undefined) {
|
|
136
|
+
columnDef.invertSorting = col.invertSorting;
|
|
137
|
+
}
|
|
138
|
+
if (col.sortUndefined !== undefined) {
|
|
139
|
+
columnDef.sortUndefined = col.sortUndefined;
|
|
140
|
+
}
|
|
141
|
+
return columnDef;
|
|
142
|
+
});
|
|
143
|
+
if (!selectionEnabled) {
|
|
144
|
+
return dataColumns;
|
|
94
145
|
}
|
|
95
|
-
|
|
96
|
-
|
|
146
|
+
const selectionColumn = {
|
|
147
|
+
id: '__selection__',
|
|
148
|
+
header: '',
|
|
149
|
+
size: selection?.checkboxColumnWidth ?? 48,
|
|
150
|
+
enableResizing: false,
|
|
151
|
+
enableSorting: false,
|
|
152
|
+
cell: () => null,
|
|
153
|
+
};
|
|
154
|
+
return [selectionColumn, ...dataColumns];
|
|
155
|
+
}, [columns, sorting, selectionEnabled, selection?.checkboxColumnWidth]);
|
|
97
156
|
const tableConfig = useMemo(() => {
|
|
98
157
|
const baseConfig = {
|
|
99
158
|
data: rows,
|
|
@@ -187,6 +246,158 @@ function NvDatatable({ mode = 'client', columns, rows, pagination, sorting, filt
|
|
|
187
246
|
mode,
|
|
188
247
|
]);
|
|
189
248
|
const table = useReactTable(tableConfig);
|
|
249
|
+
const tableRows = table.getRowModel().rows;
|
|
250
|
+
const getCurrentVisibleRowIds = useCallback(() => {
|
|
251
|
+
return table
|
|
252
|
+
.getRowModel()
|
|
253
|
+
.rows.map((row) => getSelectionRowId(row.original))
|
|
254
|
+
.filter((id) => !!id);
|
|
255
|
+
}, [table, getSelectionRowId]);
|
|
256
|
+
const setSelectionState = useCallback((nextSelectedIds) => {
|
|
257
|
+
const current = new Set(selectedRowIdsRef.current);
|
|
258
|
+
const nextRaw = typeof nextSelectedIds === 'function'
|
|
259
|
+
? nextSelectedIds(new Set(current))
|
|
260
|
+
: nextSelectedIds;
|
|
261
|
+
const next = new Set(nextRaw);
|
|
262
|
+
if (areSetsEqual(current, next)) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
const hasExplicitSelectionIntent = selectAllIntentRef.current || rowSelectionIntentRef.current !== null;
|
|
266
|
+
if (!hasExplicitSelectionIntent && next.size < current.size) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
selectedRowIdsRef.current = next;
|
|
270
|
+
setSelectedRowIdsState(next);
|
|
271
|
+
selection?.onSelectionChange?.(new Set(next));
|
|
272
|
+
}, [selection, areSetsEqual]);
|
|
273
|
+
const isRowSelected = useCallback((row) => {
|
|
274
|
+
if (!selectionEnabled) {
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
const rowId = getSelectionRowId(row);
|
|
278
|
+
return !!rowId && selectedRowIdsState.has(rowId);
|
|
279
|
+
}, [selectionEnabled, getSelectionRowId, selectedRowIdsState]);
|
|
280
|
+
const visibleRowIds = useMemo(() => tableRows
|
|
281
|
+
.map((row) => getSelectionRowId(row.original))
|
|
282
|
+
.filter((id) => !!id), [tableRows, getSelectionRowId]);
|
|
283
|
+
const setRowSelection = useCallback((row, isChecked) => {
|
|
284
|
+
if (!selectionEnabled) {
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
const rowId = getSelectionRowId(row);
|
|
288
|
+
if (!rowId) {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
const currentVisibleRowIdsSet = new Set(getCurrentVisibleRowIds());
|
|
292
|
+
if (!currentVisibleRowIdsSet.has(rowId)) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
setSelectionState((current) => {
|
|
296
|
+
return applyRowSelection({
|
|
297
|
+
currentSelectedIds: current,
|
|
298
|
+
rowId,
|
|
299
|
+
isChecked,
|
|
300
|
+
selectionMode,
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
}, [
|
|
304
|
+
selectionEnabled,
|
|
305
|
+
getSelectionRowId,
|
|
306
|
+
selectionMode,
|
|
307
|
+
setSelectionState,
|
|
308
|
+
getCurrentVisibleRowIds,
|
|
309
|
+
]);
|
|
310
|
+
const selectAllState = useMemo(() => {
|
|
311
|
+
if (!selectionEnabled ||
|
|
312
|
+
selectionMode !== 'multiple' ||
|
|
313
|
+
!selectAllEnabled ||
|
|
314
|
+
!visibleRowIds.length) {
|
|
315
|
+
return 'unchecked';
|
|
316
|
+
}
|
|
317
|
+
const selectedCount = visibleRowIds.filter((id) => selectedRowIdsState.has(id)).length;
|
|
318
|
+
if (selectedCount === 0) {
|
|
319
|
+
return 'unchecked';
|
|
320
|
+
}
|
|
321
|
+
if (selectedCount === visibleRowIds.length) {
|
|
322
|
+
return 'checked';
|
|
323
|
+
}
|
|
324
|
+
return 'indeterminate';
|
|
325
|
+
}, [
|
|
326
|
+
selectionEnabled,
|
|
327
|
+
selectionMode,
|
|
328
|
+
selectAllEnabled,
|
|
329
|
+
visibleRowIds,
|
|
330
|
+
selectedRowIdsState,
|
|
331
|
+
]);
|
|
332
|
+
const selectAllStateRef = useRef(selectAllState);
|
|
333
|
+
selectAllStateRef.current = selectAllState;
|
|
334
|
+
const handleSelectAllChanged = useCallback((isChecked) => {
|
|
335
|
+
if (!selectionEnabled ||
|
|
336
|
+
selectionMode !== 'multiple' ||
|
|
337
|
+
!selectAllEnabled) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const currentVisibleRowIds = getCurrentVisibleRowIds();
|
|
341
|
+
if (!currentVisibleRowIds.length) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
if (shouldIgnoreSelectAllEvent({
|
|
345
|
+
isChecked,
|
|
346
|
+
selectAllState: selectAllStateRef.current,
|
|
347
|
+
})) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
setSelectionState((current) => {
|
|
351
|
+
return applySelectAllSelection({
|
|
352
|
+
currentSelectedIds: current,
|
|
353
|
+
visibleRowIds: currentVisibleRowIds,
|
|
354
|
+
isChecked,
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
}, [
|
|
358
|
+
selectionEnabled,
|
|
359
|
+
selectionMode,
|
|
360
|
+
selectAllEnabled,
|
|
361
|
+
setSelectionState,
|
|
362
|
+
getCurrentVisibleRowIds,
|
|
363
|
+
]);
|
|
364
|
+
useEffect(() => {
|
|
365
|
+
if (!selectionEnabled || selection?.deselectOnFilter === false) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
if (mode !== 'client' || !filtering) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
const filterVisibleRows = table
|
|
372
|
+
.getFilteredRowModel()
|
|
373
|
+
.rows.map((row) => row.original);
|
|
374
|
+
const visibleIds = new Set(filterVisibleRows
|
|
375
|
+
.map((row) => getSelectionRowId(row))
|
|
376
|
+
.filter((id) => !!id));
|
|
377
|
+
const currentSelection = selection?.selectedRowIds ?? selectedRowIdsState;
|
|
378
|
+
const next = new Set();
|
|
379
|
+
currentSelection.forEach((id) => {
|
|
380
|
+
if (visibleIds.has(id)) {
|
|
381
|
+
next.add(id);
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
if (!areSetsEqual(currentSelection, next)) {
|
|
385
|
+
setSelectedRowIdsState(next);
|
|
386
|
+
selection?.onSelectionChange?.(new Set(next));
|
|
387
|
+
}
|
|
388
|
+
}, [
|
|
389
|
+
areSetsEqual,
|
|
390
|
+
selectionEnabled,
|
|
391
|
+
selection?.deselectOnFilter,
|
|
392
|
+
selection?.onSelectionChange,
|
|
393
|
+
selection?.selectedRowIds,
|
|
394
|
+
mode,
|
|
395
|
+
filtering,
|
|
396
|
+
globalFilterState,
|
|
397
|
+
table,
|
|
398
|
+
selectedRowIdsState,
|
|
399
|
+
getSelectionRowId,
|
|
400
|
+
]);
|
|
190
401
|
useEffect(() => {
|
|
191
402
|
if (mode === 'server' &&
|
|
192
403
|
!pagination?.infinite &&
|
|
@@ -253,7 +464,6 @@ function NvDatatable({ mode = 'client', columns, rows, pagination, sorting, filt
|
|
|
253
464
|
mode,
|
|
254
465
|
isInfiniteScroll,
|
|
255
466
|
]);
|
|
256
|
-
const tableRows = table.getRowModel().rows;
|
|
257
467
|
const renderDefaultPagination = (api) => {
|
|
258
468
|
const labelProps = {};
|
|
259
469
|
if (pagination?.labels?.page)
|
|
@@ -263,7 +473,11 @@ function NvDatatable({ mode = 'client', columns, rows, pagination, sorting, filt
|
|
|
263
473
|
if (pagination?.labels?.pageSizeOption)
|
|
264
474
|
labelProps.labelPageSizeOption = pagination.labels.pageSizeOption;
|
|
265
475
|
return (React.createElement("div", { "data-testid": "default-pagination-wrapper", style: { marginTop: '16px' } },
|
|
266
|
-
React.createElement(NvPaginationtable, { pageIndex: api.pageIndex, pageSize: api.pageSize, pageCount: api.pageCount, rowCount: api.rowCount, ...labelProps, onPageIndexChanged: (e) =>
|
|
476
|
+
React.createElement(NvPaginationtable, { pageIndex: api.pageIndex, pageSize: api.pageSize, pageCount: api.pageCount, rowCount: api.rowCount, ...labelProps, onPageIndexChanged: (e) => {
|
|
477
|
+
api.setPageIndex(e.detail);
|
|
478
|
+
}, onPageSizeChanged: (e) => {
|
|
479
|
+
api.setPageSize(e.detail);
|
|
480
|
+
} })));
|
|
267
481
|
};
|
|
268
482
|
const filteringAPI = useMemo(() => {
|
|
269
483
|
if (!filtering) {
|
|
@@ -284,25 +498,130 @@ function NvDatatable({ mode = 'client', columns, rows, pagination, sorting, filt
|
|
|
284
498
|
filteredRows: filteredRowModel.rows.length,
|
|
285
499
|
};
|
|
286
500
|
}, [filtering, globalFilterState, table, setGlobalFilterDebounced]);
|
|
501
|
+
const markSelectAllIntentFromKey = (event) => {
|
|
502
|
+
if (event.key === ' ' || event.key === 'Enter') {
|
|
503
|
+
if (selectAllIntentResetTimerRef.current) {
|
|
504
|
+
clearTimeout(selectAllIntentResetTimerRef.current);
|
|
505
|
+
}
|
|
506
|
+
selectAllIntentRef.current = true;
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
const scheduleSelectAllIntentReset = () => {
|
|
510
|
+
if (selectAllIntentResetTimerRef.current) {
|
|
511
|
+
clearTimeout(selectAllIntentResetTimerRef.current);
|
|
512
|
+
}
|
|
513
|
+
selectAllIntentResetTimerRef.current = setTimeout(() => {
|
|
514
|
+
selectAllIntentRef.current = false;
|
|
515
|
+
selectAllIntentResetTimerRef.current = null;
|
|
516
|
+
}, INTENT_RESET_DELAY_MS);
|
|
517
|
+
};
|
|
518
|
+
const markRowSelectionIntentFromKey = (event, rowId) => {
|
|
519
|
+
if (event.key === ' ' || event.key === 'Enter') {
|
|
520
|
+
if (rowSelectionIntentResetTimerRef.current) {
|
|
521
|
+
clearTimeout(rowSelectionIntentResetTimerRef.current);
|
|
522
|
+
}
|
|
523
|
+
rowSelectionIntentRef.current = rowId;
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
const scheduleRowSelectionIntentReset = (rowId) => {
|
|
527
|
+
if (rowSelectionIntentResetTimerRef.current) {
|
|
528
|
+
clearTimeout(rowSelectionIntentResetTimerRef.current);
|
|
529
|
+
}
|
|
530
|
+
rowSelectionIntentResetTimerRef.current = setTimeout(() => {
|
|
531
|
+
if (rowSelectionIntentRef.current === rowId) {
|
|
532
|
+
rowSelectionIntentRef.current = null;
|
|
533
|
+
}
|
|
534
|
+
rowSelectionIntentResetTimerRef.current = null;
|
|
535
|
+
}, INTENT_RESET_DELAY_MS);
|
|
536
|
+
};
|
|
537
|
+
const renderRowSelectionCheckbox = useCallback((row, rowIndex) => {
|
|
538
|
+
const rowId = getSelectionRowId(row);
|
|
539
|
+
return (React.createElement(NvFieldcheckbox, { "data-testid": `datatable-row-${rowIndex}-checkbox`, checked: isRowSelected(row), label: `Select row ${rowIndex + 1}`, hideLabel: true, onPointerDownCapture: () => {
|
|
540
|
+
if (rowSelectionIntentResetTimerRef.current) {
|
|
541
|
+
clearTimeout(rowSelectionIntentResetTimerRef.current);
|
|
542
|
+
}
|
|
543
|
+
rowSelectionIntentRef.current = rowId;
|
|
544
|
+
}, onKeyDownCapture: (event) => {
|
|
545
|
+
markRowSelectionIntentFromKey(event, rowId);
|
|
546
|
+
}, onBlurCapture: () => {
|
|
547
|
+
scheduleRowSelectionIntentReset(rowId);
|
|
548
|
+
}, onCheckedChanged: (event) => {
|
|
549
|
+
if (!rowId || rowSelectionIntentRef.current !== rowId) {
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
try {
|
|
553
|
+
setRowSelection(row, event.detail);
|
|
554
|
+
}
|
|
555
|
+
finally {
|
|
556
|
+
rowSelectionIntentRef.current = null;
|
|
557
|
+
}
|
|
558
|
+
} }));
|
|
559
|
+
}, [getSelectionRowId, isRowSelected, setRowSelection]);
|
|
287
560
|
return (React.createElement(React.Fragment, null,
|
|
288
561
|
filteringAPI && renderFiltering && renderFiltering(filteringAPI),
|
|
289
562
|
React.createElement(NvTable, { ...htmlProps },
|
|
290
|
-
React.createElement("table",
|
|
563
|
+
React.createElement("table", { "data-row-click-enabled": rowClickEnabled ? 'true' : 'false' },
|
|
291
564
|
React.createElement("thead", { "data-sticky-top": stickyHeader ? 'true' : undefined }, table.getHeaderGroups().map((headerGroup) => (React.createElement("tr", { key: headerGroup.id }, headerGroup.headers.map((header) => {
|
|
565
|
+
const isSelectionHeader = header.id === '__selection__';
|
|
292
566
|
const canSort = header.column.getCanSort();
|
|
293
567
|
const sortDirection = header.column.getIsSorted();
|
|
294
|
-
return (React.createElement("th", { key: header.id, "data-testid":
|
|
568
|
+
return (React.createElement("th", { key: header.id, "data-testid": isSelectionHeader
|
|
569
|
+
? 'datatable-header-selection'
|
|
570
|
+
: `datatable-header-${header.id}`, style: {
|
|
295
571
|
width: header.column.columnDef.size + 'px',
|
|
296
|
-
}, "data-no-resize":
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
572
|
+
}, "data-no-resize": isSelectionHeader
|
|
573
|
+
? true
|
|
574
|
+
: header.column.columnDef.enableResizing
|
|
575
|
+
? null
|
|
576
|
+
: true }, isSelectionHeader ? (selectionMode === 'multiple' && selectAllEnabled ? (React.createElement("div", { className: "flex items-center justify-center" },
|
|
577
|
+
React.createElement(NvFieldcheckbox, { "data-testid": "datatable-select-all-checkbox", checked: selectAllState === 'checked', indeterminate: selectAllState === 'indeterminate', label: "Select all rows", hideLabel: true, onPointerDownCapture: () => {
|
|
578
|
+
if (selectAllIntentResetTimerRef.current) {
|
|
579
|
+
clearTimeout(selectAllIntentResetTimerRef.current);
|
|
580
|
+
}
|
|
581
|
+
selectAllIntentRef.current = true;
|
|
582
|
+
}, onKeyDownCapture: markSelectAllIntentFromKey, onBlurCapture: () => {
|
|
583
|
+
scheduleSelectAllIntentReset();
|
|
584
|
+
}, onCheckedChanged: (event) => {
|
|
585
|
+
if (!selectAllIntentRef.current) {
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
try {
|
|
589
|
+
handleSelectAllChanged(event.detail);
|
|
590
|
+
}
|
|
591
|
+
finally {
|
|
592
|
+
selectAllIntentRef.current = false;
|
|
593
|
+
}
|
|
594
|
+
} }))) : null) : (React.createElement(NvTableheader, { sortable: canSort ? true : undefined, sortDirection: sortDirection || (canSort ? 'none' : undefined), onSortDirectionChanged: canSort
|
|
595
|
+
? header.column.getToggleSortingHandler()
|
|
596
|
+
: undefined }, header.isPlaceholder
|
|
597
|
+
? null
|
|
598
|
+
: flexRender(header.column.columnDef.header, header.getContext())))));
|
|
302
599
|
}))))),
|
|
303
600
|
React.createElement("tbody", null, tableRows.map((row, index) => {
|
|
304
601
|
const isLastRow = isInfiniteScroll && index === tableRows.length - 1;
|
|
305
|
-
|
|
602
|
+
const stableRowKey = getSelectionRowId(row.original) || row.id;
|
|
603
|
+
return (React.createElement("tr", { key: stableRowKey, "data-testid": `datatable-row-${index}`, ref: isLastRow ? lastRowRef : undefined, className: rowClickEnabled ? 'nv-datatable-row-clickable' : undefined, tabIndex: rowClickEnabled ? 0 : undefined, onClick: rowClickEnabled
|
|
604
|
+
? () => onRowClick?.({ row: row.original, rowIndex: index })
|
|
605
|
+
: undefined, onKeyDown: rowClickEnabled
|
|
606
|
+
? (event) => {
|
|
607
|
+
if (event.currentTarget !== event.target) {
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
611
|
+
event.preventDefault();
|
|
612
|
+
onRowClick?.({
|
|
613
|
+
row: row.original,
|
|
614
|
+
rowIndex: index,
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
: undefined }, row.getVisibleCells().map((cell) => (React.createElement("td", { key: cell.id, "data-testid": cell.column.id === '__selection__'
|
|
619
|
+
? 'datatable-cell-selection'
|
|
620
|
+
: `datatable-cell-${cell.column.id}`, onClick: cell.column.id === '__selection__'
|
|
621
|
+
? (event) => event.stopPropagation()
|
|
622
|
+
: undefined }, cell.column.id === '__selection__'
|
|
623
|
+
? renderRowSelectionCheckbox(row.original, index)
|
|
624
|
+
: flexRender(cell.column.columnDef.cell, cell.getContext()))))));
|
|
306
625
|
})))),
|
|
307
626
|
paginationAPI &&
|
|
308
627
|
(renderPagination
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export function applyRowSelection(params) {
|
|
2
|
+
const { currentSelectedIds, rowId, isChecked, selectionMode } = params;
|
|
3
|
+
const next = new Set(currentSelectedIds);
|
|
4
|
+
const currentlySelected = next.has(rowId);
|
|
5
|
+
if (selectionMode === 'single') {
|
|
6
|
+
if (isChecked) {
|
|
7
|
+
if (!(next.size === 1 && currentlySelected)) {
|
|
8
|
+
next.clear();
|
|
9
|
+
next.add(rowId);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
else if (currentlySelected) {
|
|
13
|
+
next.delete(rowId);
|
|
14
|
+
}
|
|
15
|
+
return next;
|
|
16
|
+
}
|
|
17
|
+
if (selectionMode === 'multiple') {
|
|
18
|
+
if (isChecked && !currentlySelected) {
|
|
19
|
+
next.add(rowId);
|
|
20
|
+
}
|
|
21
|
+
else if (!isChecked && currentlySelected) {
|
|
22
|
+
next.delete(rowId);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return next;
|
|
26
|
+
}
|
|
27
|
+
export function shouldIgnoreSelectAllEvent(params) {
|
|
28
|
+
const { isChecked, selectAllState } = params;
|
|
29
|
+
if ((isChecked && selectAllState === 'checked') ||
|
|
30
|
+
(!isChecked && selectAllState === 'unchecked')) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
return !isChecked && selectAllState === 'indeterminate';
|
|
34
|
+
}
|
|
35
|
+
export function applySelectAllSelection(params) {
|
|
36
|
+
const { currentSelectedIds, visibleRowIds, isChecked } = params;
|
|
37
|
+
const next = new Set(currentSelectedIds);
|
|
38
|
+
if (isChecked) {
|
|
39
|
+
visibleRowIds.forEach((id) => next.add(id));
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
visibleRowIds.forEach((id) => next.delete(id));
|
|
43
|
+
}
|
|
44
|
+
return next;
|
|
45
|
+
}
|