@drivenets/design-system 0.12.1 → 0.14.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/CHANGELOG.md +31 -0
- package/dist/index.cjs +1989 -735
- package/dist/index.d.cts +1378 -998
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +1378 -998
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1978 -735
- package/dist/index.js.map +1 -1
- package/dist/index.min.css +1 -1
- package/package.json +43 -41
- package/src/components/ds-button-v3/ds-button-v3.figma.ts +99 -0
- package/src/components/ds-button-v3/ds-button-v3.module.scss +22 -22
- package/src/components/ds-card/figma/ds-card-content.figma.ts +15 -0
- package/src/components/ds-card/figma/ds-card-footer.figma.ts +15 -0
- package/src/components/ds-card/figma/ds-card-header.figma.ts +15 -0
- package/src/components/ds-card/figma/ds-card.figma.ts +72 -0
- package/src/components/ds-date-input/ds-date-input.utils.ts +2 -2
- package/src/components/ds-date-picker/ds-date-picker.figma.ts +19 -0
- package/src/components/ds-drawer/ds-drawer.tsx +2 -0
- package/src/components/ds-form-control/ds-form-control.figma.ts +76 -0
- package/src/components/ds-form-control/ds-form-control.tsx +14 -11
- package/src/components/ds-form-control/ds-form-control.types.ts +4 -0
- package/src/components/ds-grid/ds-grid.tsx +1 -2
- package/src/components/ds-icon/figma/ds-icon-material.figma.batch.ts +10 -0
- package/src/components/ds-icon/figma/ds-icon-special.figma.batch.ts +18 -0
- package/src/components/ds-icon/figma/ds-icon.figma.batch.json +2873 -0
- package/src/components/ds-modal/ds-modal.tsx +3 -0
- package/src/components/ds-modal/figma/ds-modal-content.figma.ts +18 -0
- package/src/components/ds-modal/figma/ds-modal-footer.figma.ts +19 -0
- package/src/components/ds-modal/figma/ds-modal-header.figma.ts +21 -0
- package/src/components/ds-modal/figma/ds-modal.figma.ts +36 -0
- package/src/components/ds-popover/ds-popover.module.scss +58 -16
- package/src/components/ds-popover/ds-popover.tsx +148 -24
- package/src/components/ds-popover/ds-popover.types.ts +95 -12
- package/src/components/ds-popover/index.ts +1 -1
- package/src/components/ds-select/ds-select.figma.ts +53 -0
- package/src/components/ds-split-button/ds-split-button.figma.ts +95 -0
- package/src/components/ds-status-badge-v2/ds-status-badge-v2.figma.ts +41 -0
- package/src/components/ds-table/components/ds-table-body-virtualized/ds-table-body-virtualized.module.scss +21 -2
- package/src/components/ds-table/components/ds-table-body-virtualized/ds-table-body-virtualized.tsx +22 -14
- package/src/components/ds-table/components/ds-table-body-virtualized/ds-table-body-virtualized.types.ts +1 -6
- package/src/components/ds-table/components/ds-table-bulk-actions/ds-table-bulk-actions.module.scss +2 -2
- package/src/components/ds-table/components/ds-table-cell/ds-table-cell.module.scss +2 -0
- package/src/components/ds-table/components/ds-table-cell/ds-table-cell.tsx +42 -11
- package/src/components/ds-table/components/ds-table-group-header-cell/ds-table-group-header-cell.module.scss +31 -0
- package/src/components/ds-table/components/ds-table-group-header-cell/ds-table-group-header-cell.tsx +48 -0
- package/src/components/ds-table/components/ds-table-group-header-cell/ds-table-group-header-cell.types.ts +12 -0
- package/src/components/ds-table/components/ds-table-group-header-cell/index.ts +2 -0
- package/src/components/ds-table/components/ds-table-header/ds-table-header.module.scss +28 -4
- package/src/components/ds-table/components/ds-table-header/ds-table-header.tsx +65 -28
- package/src/components/ds-table/components/ds-table-row/ds-table-row.module.scss +26 -0
- package/src/components/ds-table/components/ds-table-row/ds-table-row.tsx +3 -0
- package/src/components/ds-table/components/ds-table-row-virtualized/ds-table-row-virtualized.module.scss +23 -0
- package/src/components/ds-table/components/ds-table-row-virtualized/ds-table-row-virtualized.tsx +4 -1
- package/src/components/ds-table/components/ds-table-row-virtualized/ds-table-row-virtualized.types.ts +1 -1
- package/src/components/ds-table/components/edit/cell-editors/cell-editors.module.scss +3 -0
- package/src/components/ds-table/components/edit/cell-editors/ds-table-edit-cell-checkbox.tsx +27 -0
- package/src/components/ds-table/components/edit/cell-editors/ds-table-edit-cell-date.tsx +50 -0
- package/src/components/ds-table/components/edit/cell-editors/ds-table-edit-cell-number.tsx +51 -0
- package/src/components/ds-table/components/edit/cell-editors/ds-table-edit-cell-select.tsx +36 -0
- package/src/components/ds-table/components/edit/cell-editors/ds-table-edit-cell-text.tsx +50 -0
- package/src/components/ds-table/components/edit/cell-editors/index.ts +14 -0
- package/src/components/ds-table/components/edit/cell-editors/table-edit-form-control.tsx +31 -0
- package/src/components/ds-table/components/edit/ds-table-editable-cell/ds-table-editable-cell.module.scss +28 -0
- package/src/components/ds-table/components/edit/ds-table-editable-cell/ds-table-editable-cell.tsx +39 -0
- package/src/components/ds-table/components/edit/ds-table-editable-cell/ds-table-editable-cell.types.ts +7 -0
- package/src/components/ds-table/components/edit/ds-table-editable-cell/index.ts +2 -0
- package/src/components/ds-table/components/edit/ds-table-editing-cell/ds-table-editing-cell.module.scss +48 -0
- package/src/components/ds-table/components/edit/ds-table-editing-cell/ds-table-editing-cell.tsx +76 -0
- package/src/components/ds-table/components/edit/ds-table-editing-cell/ds-table-editing-cell.types.ts +5 -0
- package/src/components/ds-table/components/edit/ds-table-editing-cell/index.ts +2 -0
- package/src/components/ds-table/context/ds-table-context.ts +83 -1
- package/src/components/ds-table/ds-table-column.types.ts +12 -0
- package/src/components/ds-table/ds-table.module.scss +100 -10
- package/src/components/ds-table/ds-table.tsx +38 -21
- package/src/components/ds-table/ds-table.types.ts +107 -0
- package/src/components/ds-table/figma/ds-table-expandable.figma.ts +17 -0
- package/src/components/ds-table/figma/ds-table.figma.ts +16 -0
- package/src/components/ds-table/filters/adapters/create-checkbox-filter-adapter.tsx +24 -40
- package/src/components/ds-table/filters/adapters/create-dual-range-filter-adapter.tsx +10 -31
- package/src/components/ds-table/filters/adapters/create-filter-adapter.ts +6 -98
- package/src/components/ds-table/filters/components/checkbox-filter/checkbox-filter.module.scss +36 -0
- package/src/components/ds-table/filters/components/checkbox-filter/checkbox-filter.tsx +92 -13
- package/src/components/ds-table/filters/components/checkbox-filter/index.ts +1 -1
- package/src/components/ds-table/filters/components/column-filter-popover/column-filter-popover.module.scss +42 -0
- package/src/components/ds-table/filters/components/column-filter-popover/column-filter-popover.tsx +89 -0
- package/src/components/ds-table/filters/components/column-filter-popover/column-filter-popover.types.ts +25 -0
- package/src/components/ds-table/filters/components/column-filter-popover/index.ts +5 -0
- package/src/components/ds-table/filters/hooks/use-table-filters.ts +113 -78
- package/src/components/ds-table/filters/index.ts +2 -44
- package/src/components/ds-table/filters/types/column-meta.augmentation.ts +19 -0
- package/src/components/ds-table/filters/types/filter-adapter.types.ts +48 -81
- package/src/components/ds-table/grouping/hooks/use-column-groups.ts +73 -0
- package/src/components/ds-table/grouping/index.ts +5 -0
- package/src/components/ds-table/grouping/types/column-group-meta.augmentation.ts +26 -0
- package/src/components/ds-table/grouping/types/column-group.types.ts +35 -0
- package/src/components/ds-table/grouping/utils/column-group.ts +119 -0
- package/src/components/ds-table/hooks/use-cell-editor.ts +81 -0
- package/src/components/ds-table/index.ts +32 -0
- package/src/components/ds-table/styles/_variables.scss +1 -0
- package/src/components/ds-table/utils/column-size.ts +9 -8
- package/src/components/ds-tag/ds-tag.module.scss +22 -1
- package/src/components/ds-tag/ds-tag.tsx +18 -5
- package/src/components/ds-tag/ds-tag.types.ts +22 -8
- package/src/components/ds-tag/ds-tag.unit.test.ts +32 -0
- package/src/components/ds-tag-filter/ds-tag-filter.tsx +14 -22
- package/src/components/ds-text-input/ds-text-input.figma.ts +60 -0
- package/src/components/ds-time-picker/ds-time-picker.figma.ts +18 -0
- package/src/components/ds-workspace-layout/ds-workspace-layout.context.ts +19 -0
- package/src/components/ds-workspace-layout/ds-workspace-layout.module.scss +166 -0
- package/src/components/ds-workspace-layout/ds-workspace-layout.tsx +135 -0
- package/src/components/ds-workspace-layout/ds-workspace-layout.types.ts +52 -0
- package/src/components/ds-workspace-layout/index.ts +11 -0
- package/src/index.ts +1 -1
- package/src/styles/_root_new.scss +2 -0
- package/src/styles/_scrollbars.scss +36 -22
- package/src/utils/restore-document-body-modal-styles.ts +44 -0
- package/src/utils/use-ark-dialog-body-lock-cleanup.ts +36 -0
- package/src/components/ds-workspace/ds-workspace.module.scss +0 -55
- package/src/components/ds-workspace/ds-workspace.tsx +0 -37
- package/src/components/ds-workspace/ds-workspace.types.ts +0 -17
- package/src/components/ds-workspace/index.ts +0 -8
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
@use '../../styles/typography';
|
|
2
|
-
@use '../../styles/
|
|
2
|
+
@use '../../styles/scrollbars' as scrollbars;
|
|
3
3
|
@use './styles/variables' as vars;
|
|
4
4
|
|
|
5
5
|
:root {
|
|
@@ -9,9 +9,10 @@
|
|
|
9
9
|
--ds-table-header-height: 45px;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
$bulk-actions-
|
|
12
|
+
$bulk-actions-reserved-space: 80px;
|
|
13
13
|
|
|
14
14
|
.container {
|
|
15
|
+
position: relative;
|
|
15
16
|
border-radius: vars.$border-radius;
|
|
16
17
|
border-width: vars.$border-width;
|
|
17
18
|
border-style: solid;
|
|
@@ -21,7 +22,51 @@ $bulk-actions-height: 60px;
|
|
|
21
22
|
|
|
22
23
|
.dataTableContainer {
|
|
23
24
|
max-height: 100%;
|
|
24
|
-
overflow: auto;
|
|
25
|
+
overflow-x: auto;
|
|
26
|
+
overflow-y: hidden;
|
|
27
|
+
display: flex;
|
|
28
|
+
flex-direction: column;
|
|
29
|
+
|
|
30
|
+
@include scrollbars.scrollbar-on-hover;
|
|
31
|
+
|
|
32
|
+
> table {
|
|
33
|
+
display: flex;
|
|
34
|
+
flex-direction: column;
|
|
35
|
+
flex: 1;
|
|
36
|
+
min-height: 0;
|
|
37
|
+
width: max-content;
|
|
38
|
+
min-width: 100%;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
thead {
|
|
42
|
+
display: block;
|
|
43
|
+
flex-shrink: 0;
|
|
44
|
+
overflow-y: scroll;
|
|
45
|
+
scrollbar-gutter: stable;
|
|
46
|
+
|
|
47
|
+
@include scrollbars.scrollbar-on-hover;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
tbody {
|
|
51
|
+
display: block;
|
|
52
|
+
overflow-y: auto;
|
|
53
|
+
flex: 1;
|
|
54
|
+
min-height: 0;
|
|
55
|
+
scrollbar-gutter: stable;
|
|
56
|
+
|
|
57
|
+
@include scrollbars.scrollbar-on-hover;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
thead tr,
|
|
61
|
+
tbody tr {
|
|
62
|
+
display: flex;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
thead th,
|
|
66
|
+
tbody td {
|
|
67
|
+
display: flex;
|
|
68
|
+
align-items: center;
|
|
69
|
+
}
|
|
25
70
|
}
|
|
26
71
|
|
|
27
72
|
.table {
|
|
@@ -40,21 +85,66 @@ $bulk-actions-height: 60px;
|
|
|
40
85
|
width: 100%;
|
|
41
86
|
}
|
|
42
87
|
|
|
88
|
+
.bulkActionsVisible {
|
|
89
|
+
tbody {
|
|
90
|
+
padding-bottom: $bulk-actions-reserved-space;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
43
94
|
.emptyState {
|
|
95
|
+
// colSpan in markup isn't honored by flex row layout, so the cell stretches
|
|
96
|
+
// across the row; stretch the inner content so it occupies full table width
|
|
97
|
+
flex: 1;
|
|
98
|
+
min-width: 0;
|
|
44
99
|
height: vars.$empty-state-height;
|
|
100
|
+
justify-content: center;
|
|
45
101
|
text-align: center;
|
|
46
|
-
}
|
|
47
102
|
|
|
48
|
-
|
|
49
|
-
|
|
103
|
+
> * {
|
|
104
|
+
flex: 1;
|
|
105
|
+
}
|
|
50
106
|
}
|
|
51
107
|
|
|
52
108
|
.virtualizedContainer {
|
|
53
109
|
position: relative;
|
|
54
110
|
height: vars.$virtualized-height;
|
|
55
|
-
overflow: auto;
|
|
56
|
-
|
|
111
|
+
overflow-x: auto;
|
|
112
|
+
overflow-y: hidden;
|
|
113
|
+
display: flex;
|
|
114
|
+
flex-direction: column;
|
|
57
115
|
|
|
58
|
-
.
|
|
59
|
-
|
|
116
|
+
@include scrollbars.scrollbar-on-hover;
|
|
117
|
+
|
|
118
|
+
> table {
|
|
119
|
+
display: flex;
|
|
120
|
+
flex-direction: column;
|
|
121
|
+
flex: 1;
|
|
122
|
+
min-height: 0;
|
|
123
|
+
width: max-content;
|
|
124
|
+
min-width: 100%;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
thead {
|
|
128
|
+
display: block;
|
|
129
|
+
flex-shrink: 0;
|
|
130
|
+
overflow-y: scroll;
|
|
131
|
+
scrollbar-gutter: stable;
|
|
132
|
+
|
|
133
|
+
@include scrollbars.scrollbar-on-hover;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
tbody {
|
|
137
|
+
flex: 1;
|
|
138
|
+
min-height: 0;
|
|
139
|
+
scrollbar-gutter: stable;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
thead tr {
|
|
143
|
+
display: flex;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
thead th {
|
|
147
|
+
display: flex;
|
|
148
|
+
align-items: center;
|
|
149
|
+
}
|
|
60
150
|
}
|
|
@@ -23,8 +23,9 @@ import { DsTableRowExpandableCell } from './components/ds-table-row-expandable-c
|
|
|
23
23
|
import { DsTableRowSelectableCell } from './components/ds-table-row-selectable-cell';
|
|
24
24
|
import { DsTableHeaderSelectableCell } from './components/ds-table-header-selectable-cell';
|
|
25
25
|
import { useDragAndDrop } from './hooks/use-drag-and-drop';
|
|
26
|
-
import { type DsTableContextType, DsTableContext } from './context/ds-table-context';
|
|
26
|
+
import { type DsTableContextType, DsTableContext, useEditingState } from './context/ds-table-context';
|
|
27
27
|
import { DsTableBodyVirtualized } from './components/ds-table-body-virtualized';
|
|
28
|
+
import { useColumnGroups } from './grouping';
|
|
28
29
|
import {
|
|
29
30
|
EMPTY_TABLE_STATE_TEXT,
|
|
30
31
|
EXPANDER_COLUMN_ID,
|
|
@@ -75,8 +76,13 @@ const DsTable = <TData extends { id: string }, TValue>({
|
|
|
75
76
|
onColumnFiltersChange,
|
|
76
77
|
columnVisibility: externalColumnVisibility,
|
|
77
78
|
onColumnVisibilityChange,
|
|
79
|
+
collapsedColumnGroups: externalCollapsedColumnGroups,
|
|
80
|
+
onCollapsedColumnGroupsChange,
|
|
81
|
+
locale,
|
|
78
82
|
activeRowId,
|
|
79
83
|
infiniteScroll,
|
|
84
|
+
onCellEdit,
|
|
85
|
+
onCellValidate,
|
|
80
86
|
}: DsDataTableProps<TData, TValue>) => {
|
|
81
87
|
const [data, setData] = React.useState(tableData);
|
|
82
88
|
const [sorting, setSorting] = React.useState<SortingState>([]);
|
|
@@ -107,12 +113,12 @@ const DsTable = <TData extends { id: string }, TValue>({
|
|
|
107
113
|
}
|
|
108
114
|
};
|
|
109
115
|
|
|
110
|
-
const
|
|
116
|
+
const baseColumnVisibility = externalColumnVisibility ?? internalColumnVisibility;
|
|
111
117
|
const handleColumnVisibilityChange = (
|
|
112
118
|
updaterOrValue: VisibilityState | ((old: VisibilityState) => VisibilityState),
|
|
113
119
|
) => {
|
|
114
120
|
const newVisibility =
|
|
115
|
-
typeof updaterOrValue === 'function' ? updaterOrValue(
|
|
121
|
+
typeof updaterOrValue === 'function' ? updaterOrValue(baseColumnVisibility) : updaterOrValue;
|
|
116
122
|
|
|
117
123
|
if (onColumnVisibilityChange) {
|
|
118
124
|
onColumnVisibilityChange(newVisibility);
|
|
@@ -121,6 +127,17 @@ const DsTable = <TData extends { id: string }, TValue>({
|
|
|
121
127
|
}
|
|
122
128
|
};
|
|
123
129
|
|
|
130
|
+
const { collapsedColumnGroups, toggleColumnGroup, collapsedVisibility } = useColumnGroups({
|
|
131
|
+
columns: columnsProp,
|
|
132
|
+
collapsedColumnGroups: externalCollapsedColumnGroups,
|
|
133
|
+
onCollapsedColumnGroupsChange,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const columnVisibility = useMemo(
|
|
137
|
+
() => ({ ...baseColumnVisibility, ...collapsedVisibility }),
|
|
138
|
+
[baseColumnVisibility, collapsedVisibility],
|
|
139
|
+
);
|
|
140
|
+
|
|
124
141
|
const handleSortingChange = (updaterOrValue: SortingState | ((old: SortingState) => SortingState)) => {
|
|
125
142
|
const newSorting = typeof updaterOrValue === 'function' ? updaterOrValue(sorting) : updaterOrValue;
|
|
126
143
|
setSorting(newSorting);
|
|
@@ -267,6 +284,8 @@ const DsTable = <TData extends { id: string }, TValue>({
|
|
|
267
284
|
|
|
268
285
|
const isBulkActionsVisible = selectable && actions.length > 0 && selectedRows.length > 0;
|
|
269
286
|
|
|
287
|
+
const editingState = useEditingState<TData, TValue>(onCellEdit, onCellValidate);
|
|
288
|
+
|
|
270
289
|
const contextValue: DsTableContextType<TData, TValue> = {
|
|
271
290
|
stickyHeader,
|
|
272
291
|
bordered,
|
|
@@ -283,6 +302,11 @@ const DsTable = <TData extends { id: string }, TValue>({
|
|
|
283
302
|
renderExpandedRow,
|
|
284
303
|
virtualized,
|
|
285
304
|
activeRowId,
|
|
305
|
+
collapsedColumnGroups,
|
|
306
|
+
onToggleColumnGroup: toggleColumnGroup,
|
|
307
|
+
locale,
|
|
308
|
+
onCellEdit,
|
|
309
|
+
...editingState,
|
|
286
310
|
};
|
|
287
311
|
|
|
288
312
|
return (
|
|
@@ -298,18 +322,11 @@ const DsTable = <TData extends { id: string }, TValue>({
|
|
|
298
322
|
)}
|
|
299
323
|
>
|
|
300
324
|
<DragWrapper>
|
|
301
|
-
<Table
|
|
302
|
-
className={classnames(
|
|
303
|
-
fullWidth && styles.fullWidth,
|
|
304
|
-
!bordered && styles.tableNoBorder,
|
|
305
|
-
virtualized && styles.virtualized,
|
|
306
|
-
)}
|
|
307
|
-
>
|
|
325
|
+
<Table className={classnames(fullWidth && styles.fullWidth, !bordered && styles.tableNoBorder)}>
|
|
308
326
|
<DsTableHeader table={table} />
|
|
309
327
|
{virtualized ? (
|
|
310
328
|
<DsTableBodyVirtualized
|
|
311
329
|
table={table}
|
|
312
|
-
tableContainerRef={tableContainerRef}
|
|
313
330
|
emptyState={emptyState}
|
|
314
331
|
estimateSize={virtualizedOptions?.estimateSize || ROW_SIZE_HEIGHT_MAP[rowSize]}
|
|
315
332
|
overscan={virtualizedOptions?.overscan}
|
|
@@ -330,17 +347,17 @@ const DsTable = <TData extends { id: string }, TValue>({
|
|
|
330
347
|
)}
|
|
331
348
|
</Table>
|
|
332
349
|
</DragWrapper>
|
|
350
|
+
{selectable && actions.length > 0 && (
|
|
351
|
+
<DsTableBulkActions
|
|
352
|
+
numSelectedRows={selectedRows.length}
|
|
353
|
+
actions={actions.map((action) => ({
|
|
354
|
+
...action,
|
|
355
|
+
onClick: () => action.onClick(selectedRows),
|
|
356
|
+
}))}
|
|
357
|
+
onClearSelection={table.resetRowSelection}
|
|
358
|
+
/>
|
|
359
|
+
)}
|
|
333
360
|
</div>
|
|
334
|
-
{selectable && actions.length > 0 && (
|
|
335
|
-
<DsTableBulkActions
|
|
336
|
-
numSelectedRows={selectedRows.length}
|
|
337
|
-
actions={actions.map((action) => ({
|
|
338
|
-
...action,
|
|
339
|
-
onClick: () => action.onClick(selectedRows),
|
|
340
|
-
}))}
|
|
341
|
-
onClearSelection={table.resetRowSelection}
|
|
342
|
-
/>
|
|
343
|
-
)}
|
|
344
361
|
</DsTableContext.Provider>
|
|
345
362
|
);
|
|
346
363
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
|
+
import './ds-table-column.types';
|
|
2
3
|
import type {
|
|
3
4
|
ColumnDef,
|
|
4
5
|
ColumnFiltersState,
|
|
@@ -15,6 +16,31 @@ import type { InfiniteScrollConfig, ScrollParams } from './components/ds-table-b
|
|
|
15
16
|
*/
|
|
16
17
|
export type DsTableRowSize = 'small' | 'medium' | 'large';
|
|
17
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Overridable, user-facing strings used by the table (e.g. accessible labels for
|
|
21
|
+
* the column-group collapse toggle). Pass a partial object via the `locale` prop
|
|
22
|
+
* to localize.
|
|
23
|
+
*/
|
|
24
|
+
export interface DsTableLocale {
|
|
25
|
+
/**
|
|
26
|
+
* Accessible label for the toggle that collapses a column group.
|
|
27
|
+
*/
|
|
28
|
+
collapseColumnGroup: string;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Accessible label for the toggle that expands a column group.
|
|
32
|
+
*/
|
|
33
|
+
expandColumnGroup: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Default English strings for {@link DsTableLocale}.
|
|
38
|
+
*/
|
|
39
|
+
export const defaultDsTableLocale: DsTableLocale = Object.freeze({
|
|
40
|
+
collapseColumnGroup: 'Collapse column group',
|
|
41
|
+
expandColumnGroup: 'Expand column group',
|
|
42
|
+
});
|
|
43
|
+
|
|
18
44
|
/**
|
|
19
45
|
* API for programmatically controlling a DsTable component.
|
|
20
46
|
* This interface provides methods to interact with the table's selection, sorting, filtering, and pagination features.
|
|
@@ -440,4 +466,85 @@ export interface DsDataTableProps<TData, TValue> {
|
|
|
440
466
|
* Callback when column visibility changes
|
|
441
467
|
*/
|
|
442
468
|
onColumnVisibilityChange?: (visibility: VisibilityState) => void;
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Controlled list of collapsed column-group ids. A group is collapsible when its
|
|
472
|
+
* column def sets `meta.group.collapsible`; collapsing hides every leaf column in
|
|
473
|
+
* the group except those marked `meta.keepVisibleWhenCollapsed`. Omit for
|
|
474
|
+
* uncontrolled behavior (seeded from `meta.group.defaultCollapsed`).
|
|
475
|
+
*
|
|
476
|
+
* @example
|
|
477
|
+
* ```tsx
|
|
478
|
+
* const [collapsed, setCollapsed] = useState<string[]>(['equipment']);
|
|
479
|
+
*
|
|
480
|
+
* <DsTable
|
|
481
|
+
* collapsedColumnGroups={collapsed}
|
|
482
|
+
* onCollapsedColumnGroupsChange={setCollapsed}
|
|
483
|
+
* />
|
|
484
|
+
* ```
|
|
485
|
+
*/
|
|
486
|
+
collapsedColumnGroups?: string[];
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Callback fired with the next list of collapsed group ids when a group's
|
|
490
|
+
* collapse toggle is clicked.
|
|
491
|
+
*/
|
|
492
|
+
onCollapsedColumnGroupsChange?: (collapsedGroupIds: string[]) => void;
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Overrides for user-facing strings (e.g. column-group toggle labels). Merged
|
|
496
|
+
* over the built-in English defaults.
|
|
497
|
+
*/
|
|
498
|
+
locale?: Partial<DsTableLocale>;
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Callback fired when an editable cell commits a new value via one of the
|
|
502
|
+
* `DsTableEditCell*` wrappers or the `useCellEditor` hook. The parent is
|
|
503
|
+
* expected to update the row data in response.
|
|
504
|
+
*
|
|
505
|
+
* Commits occur on confirm (check button or Enter). Opening another cell
|
|
506
|
+
* discards the previous draft without calling this callback.
|
|
507
|
+
*
|
|
508
|
+
* @param row - The row data of the cell that was edited
|
|
509
|
+
* @param columnId - The id of the column whose cell was edited
|
|
510
|
+
* @param value - The new committed value
|
|
511
|
+
*
|
|
512
|
+
* @example
|
|
513
|
+
* ```tsx
|
|
514
|
+
* const [people, setPeople] = useState(initialPeople);
|
|
515
|
+
*
|
|
516
|
+
* <DsTable
|
|
517
|
+
* data={people}
|
|
518
|
+
* columns={columns}
|
|
519
|
+
* onCellEdit={(row, columnId, value) => {
|
|
520
|
+
* setPeople((rows) =>
|
|
521
|
+
* rows.map((r) => (r.id === row.id ? { ...r, [columnId]: value } : r)),
|
|
522
|
+
* );
|
|
523
|
+
* }}
|
|
524
|
+
* />
|
|
525
|
+
* ```
|
|
526
|
+
*/
|
|
527
|
+
onCellEdit?: (row: TData, columnId: string, value: TValue) => void;
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Validates a cell value before it is committed. Return `null` to allow the
|
|
531
|
+
* commit (which fires `onCellEdit`), or an error message string to reject it
|
|
532
|
+
* and keep the cell in edit mode. Synchronous only.
|
|
533
|
+
*
|
|
534
|
+
*
|
|
535
|
+
* @param row - The row data of the cell being edited
|
|
536
|
+
* @param columnId - The id of the column whose cell is being edited
|
|
537
|
+
* @param value - The candidate value to validate
|
|
538
|
+
*
|
|
539
|
+
* @example
|
|
540
|
+
* ```tsx
|
|
541
|
+
* <DsTable
|
|
542
|
+
* data={people}
|
|
543
|
+
* columns={columns}
|
|
544
|
+
* onCellValidate={(row, columnId, value) => validateField(columnId)(value, row)}
|
|
545
|
+
* onCellEdit={...}
|
|
546
|
+
* />
|
|
547
|
+
* ```
|
|
548
|
+
*/
|
|
549
|
+
onCellValidate?: (row: TData, columnId: string, value: TValue) => string | null;
|
|
443
550
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=36535-44213
|
|
2
|
+
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-table
|
|
3
|
+
// component=DsTable
|
|
4
|
+
//
|
|
5
|
+
// `DAP_Table Expandable_v03` is the expandable table on the "Table New (Data grid)"
|
|
6
|
+
// page. It maps to the same `DsTable` code component as the simple table, with the
|
|
7
|
+
// `expandable` prop enabled and a `renderExpandedRow` callback for the nested content.
|
|
8
|
+
// The Simple vs Expandable split exists only because of a Figma restriction (a
|
|
9
|
+
// component can't contain an instance of itself); in code it's one `DsTable`.
|
|
10
|
+
import figma from 'figma';
|
|
11
|
+
|
|
12
|
+
export default {
|
|
13
|
+
example: figma.code`<DsTable columns={columns} data={data} expandable renderExpandedRow={(row) => null} />`,
|
|
14
|
+
imports: ["import { DsTable } from '@drivenets/design-system'"],
|
|
15
|
+
id: 'ds-table-expandable',
|
|
16
|
+
metadata: { nestable: false },
|
|
17
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=36354-1965
|
|
2
|
+
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-table
|
|
3
|
+
// component=DsTable
|
|
4
|
+
//
|
|
5
|
+
// `DAP_Table Simple_v03` is the non-expandable table on the "Table New (Data grid)"
|
|
6
|
+
// page. Figma models the table as separate components (header/row/cell),
|
|
7
|
+
// while code exposes a single declarative `DsTable` driven by `columns`/`data`,
|
|
8
|
+
// so the snippet is a representative usage that references those consts.
|
|
9
|
+
import figma from 'figma';
|
|
10
|
+
|
|
11
|
+
export default {
|
|
12
|
+
example: figma.code`<DsTable columns={columns} data={data} />`,
|
|
13
|
+
imports: ["import { DsTable } from '@drivenets/design-system'"],
|
|
14
|
+
id: 'ds-table',
|
|
15
|
+
metadata: { nestable: false },
|
|
16
|
+
};
|
|
@@ -1,54 +1,36 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
import type { Row } from '@tanstack/react-table';
|
|
3
3
|
import type { FilterAdapter } from '../types/filter-adapter.types';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
type CheckboxFilterItem,
|
|
6
|
+
type CheckboxFilterLocale,
|
|
7
|
+
CheckboxFilter,
|
|
8
|
+
} from '../components/checkbox-filter';
|
|
5
9
|
import { createFilterAdapter } from './create-filter-adapter';
|
|
6
10
|
|
|
7
11
|
export interface CheckboxFilterAdapterConfig<TData, TValue> {
|
|
8
|
-
/**
|
|
9
|
-
* Unique identifier (should match column accessorKey)
|
|
10
|
-
*/
|
|
12
|
+
/** Unique id, should match the column `accessorKey`. */
|
|
11
13
|
id: string;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Display label for filter navigation
|
|
15
|
-
*/
|
|
16
14
|
label: string;
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Available items to select from
|
|
20
|
-
*/
|
|
15
|
+
/** Selectable items. */
|
|
21
16
|
items: CheckboxFilterItem<TValue>[];
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Optional custom renderer for each item
|
|
25
|
-
*/
|
|
17
|
+
/** Custom row renderer; defaults to `item.label`. */
|
|
26
18
|
renderer?: (item: CheckboxFilterItem<TValue>) => ReactNode;
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Optional custom chip label generator
|
|
30
|
-
* @default (item) => `${label}: ${item.label}`
|
|
31
|
-
*/
|
|
19
|
+
/** @default (item) => `${label}: ${item.label}` */
|
|
32
20
|
chipLabelTemplate?: (item: CheckboxFilterItem<TValue>) => string;
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Optional custom cell renderer for table column
|
|
36
|
-
*/
|
|
37
21
|
cellRenderer?: (value: TValue) => ReactNode;
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* How to extract the value from a row for comparison
|
|
41
|
-
* @default (row) => row.getValue(id)
|
|
42
|
-
*/
|
|
22
|
+
/** @default (row) => row.getValue(id) */
|
|
43
23
|
getRowValue?: (row: Row<TData>) => TValue;
|
|
24
|
+
/** Show a search input above the list. @default false */
|
|
25
|
+
searchable?: boolean;
|
|
26
|
+
/** Show an "All" toggle that selects / clears every (visible) item. @default false */
|
|
27
|
+
selectAll?: boolean;
|
|
28
|
+
locale?: CheckboxFilterLocale;
|
|
44
29
|
}
|
|
45
30
|
|
|
46
31
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* Handles multi-select checkbox filtering with inclusion model:
|
|
50
|
-
* - Empty selection = show all data (no filter active)
|
|
51
|
-
* - Selected items = show only those items
|
|
32
|
+
* Multi-select inclusion filter: empty selection shows every row, selected
|
|
33
|
+
* items show only those rows.
|
|
52
34
|
*/
|
|
53
35
|
export function createCheckboxFilterAdapter<TData, TValue = string>(
|
|
54
36
|
config: CheckboxFilterAdapterConfig<TData, TValue>,
|
|
@@ -61,20 +43,21 @@ export function createCheckboxFilterAdapter<TData, TValue = string>(
|
|
|
61
43
|
chipLabelTemplate = (item) => `${label}: ${item.label}`,
|
|
62
44
|
cellRenderer,
|
|
63
45
|
getRowValue = (row) => row.getValue(id),
|
|
46
|
+
searchable = false,
|
|
47
|
+
selectAll = false,
|
|
48
|
+
locale,
|
|
64
49
|
} = config;
|
|
65
50
|
|
|
66
51
|
return createFilterAdapter<TData, CheckboxFilterItem<TValue>[], TValue>({
|
|
67
52
|
id,
|
|
68
53
|
label,
|
|
69
|
-
initialValue: [],
|
|
54
|
+
initialValue: [],
|
|
70
55
|
|
|
71
56
|
filterFn: (row, columnId, filterValue) => {
|
|
72
|
-
// Empty selection = no filter = show all
|
|
73
57
|
if (filterValue.length === 0) {
|
|
74
58
|
return true;
|
|
75
59
|
}
|
|
76
60
|
|
|
77
|
-
// Otherwise, show only selected items
|
|
78
61
|
const rowValue = getRowValue(row);
|
|
79
62
|
return filterValue.some((item) => item.value === rowValue);
|
|
80
63
|
},
|
|
@@ -82,7 +65,6 @@ export function createCheckboxFilterAdapter<TData, TValue = string>(
|
|
|
82
65
|
cellRenderer,
|
|
83
66
|
|
|
84
67
|
toChips: (selectedItems) => {
|
|
85
|
-
// Generate chips for all selected items
|
|
86
68
|
return selectedItems.map((item) => ({
|
|
87
69
|
id: `${id}_${String(item.value)}`,
|
|
88
70
|
label: chipLabelTemplate(item),
|
|
@@ -98,7 +80,6 @@ export function createCheckboxFilterAdapter<TData, TValue = string>(
|
|
|
98
80
|
},
|
|
99
81
|
|
|
100
82
|
getActiveFiltersCount: (selectedItems) => {
|
|
101
|
-
// Count = number of selected items (0 means none selected)
|
|
102
83
|
return selectedItems.length;
|
|
103
84
|
},
|
|
104
85
|
|
|
@@ -109,6 +90,9 @@ export function createCheckboxFilterAdapter<TData, TValue = string>(
|
|
|
109
90
|
renderer={renderer}
|
|
110
91
|
selectedItems={value}
|
|
111
92
|
onSelectionChange={onChange}
|
|
93
|
+
searchable={searchable}
|
|
94
|
+
selectAll={selectAll}
|
|
95
|
+
locale={locale}
|
|
112
96
|
/>
|
|
113
97
|
);
|
|
114
98
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Row } from '@tanstack/react-table';
|
|
2
|
-
import type {
|
|
2
|
+
import type { TagFilterItem } from '../../../ds-tag-filter';
|
|
3
3
|
import type { FilterAdapter } from '../types/filter-adapter.types';
|
|
4
4
|
import { RangeFilter } from '../components/range-filter';
|
|
5
5
|
import { createFilterAdapter } from './create-filter-adapter';
|
|
@@ -14,39 +14,18 @@ export interface DualRangeFilterValue {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export interface DualRangeFilterAdapterConfig<TData> {
|
|
17
|
-
/**
|
|
18
|
-
* Unique identifier (should match column accessorKey)
|
|
19
|
-
*/
|
|
17
|
+
/** Unique id, should match the column `accessorKey`. */
|
|
20
18
|
id: string;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Display label for filter navigation
|
|
24
|
-
*/
|
|
25
19
|
label: string;
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Field configurations: { fieldKey: displayLabel }
|
|
29
|
-
* Example: { running: 'Running', completed: 'Completed' }
|
|
30
|
-
*/
|
|
20
|
+
/** Field key → display label, e.g. `{ running: 'Running' }`. */
|
|
31
21
|
fields: Record<string, string>;
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Optional formatter for chip display
|
|
35
|
-
* @default (num) => num.toLocaleString('en-US')
|
|
36
|
-
*/
|
|
22
|
+
/** @default (num) => num.toLocaleString('en-US') */
|
|
37
23
|
formatNumber?: (num: number) => string;
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* How to extract the value object from a row
|
|
41
|
-
* @default (row) => row.getValue(id)
|
|
42
|
-
*/
|
|
24
|
+
/** @default (row) => row.getValue(id) */
|
|
43
25
|
getRowValue?: (row: Row<TData>) => Record<string, number>;
|
|
44
26
|
}
|
|
45
27
|
|
|
46
|
-
/**
|
|
47
|
-
* Factory function to create a dual-range filter adapter
|
|
48
|
-
* Handles filtering on multiple numeric ranges within a single column
|
|
49
|
-
*/
|
|
28
|
+
/** Filter over multiple numeric ranges within one column (AND across fields). */
|
|
50
29
|
export function createDualRangeFilterAdapter<TData>(
|
|
51
30
|
config: DualRangeFilterAdapterConfig<TData>,
|
|
52
31
|
): FilterAdapter<TData, DualRangeFilterValue, Record<string, number>> {
|
|
@@ -71,7 +50,6 @@ export function createDualRangeFilterAdapter<TData>(
|
|
|
71
50
|
filterFn: (row, columnId, filterValue) => {
|
|
72
51
|
const rowValue = getRowValue(row);
|
|
73
52
|
|
|
74
|
-
// Check each field's range
|
|
75
53
|
for (const [fieldKey, range] of Object.entries(filterValue)) {
|
|
76
54
|
const hasFilter = range.from !== undefined || range.to !== undefined;
|
|
77
55
|
const fieldValue = rowValue[fieldKey];
|
|
@@ -80,8 +58,9 @@ export function createDualRangeFilterAdapter<TData>(
|
|
|
80
58
|
const matchesFrom = range.from === undefined || fieldValue >= range.from;
|
|
81
59
|
const matchesTo = range.to === undefined || fieldValue <= range.to;
|
|
82
60
|
|
|
61
|
+
// AND across fields: every range with a bound must match.
|
|
83
62
|
if (!matchesFrom || !matchesTo) {
|
|
84
|
-
return false;
|
|
63
|
+
return false;
|
|
85
64
|
}
|
|
86
65
|
}
|
|
87
66
|
}
|
|
@@ -89,10 +68,10 @@ export function createDualRangeFilterAdapter<TData>(
|
|
|
89
68
|
return true;
|
|
90
69
|
},
|
|
91
70
|
|
|
92
|
-
cellRenderer: undefined,
|
|
71
|
+
cellRenderer: undefined,
|
|
93
72
|
|
|
94
73
|
toChips: (value) => {
|
|
95
|
-
const chips:
|
|
74
|
+
const chips: TagFilterItem[] = [];
|
|
96
75
|
|
|
97
76
|
Object.entries(value).forEach(([fieldKey, range]) => {
|
|
98
77
|
const hasFilter = range.from !== undefined || range.to !== undefined;
|