@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
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=34428-16204
|
|
2
|
+
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-status-badge-v2
|
|
3
|
+
// component=DsStatusBadgeV2
|
|
4
|
+
import figma from 'figma';
|
|
5
|
+
|
|
6
|
+
const instance = figma.selectedInstance;
|
|
7
|
+
|
|
8
|
+
const phase = instance.getEnum('status', {
|
|
9
|
+
'not-started': 'not-started',
|
|
10
|
+
temporary: 'temporary',
|
|
11
|
+
'in-review': 'in-review',
|
|
12
|
+
pending: 'pending',
|
|
13
|
+
active: 'active',
|
|
14
|
+
execution: 'execution',
|
|
15
|
+
'result-succeeded': 'result-succeeded',
|
|
16
|
+
'result-warning': 'result-warning',
|
|
17
|
+
'result-failed': 'result-failed',
|
|
18
|
+
deprecated: 'deprecated',
|
|
19
|
+
});
|
|
20
|
+
const variant = instance.getEnum('variant', { primary: 'primary', secondary: 'secondary' });
|
|
21
|
+
const size = instance.getEnum('Size', { medium: 'medium', small: 'small' });
|
|
22
|
+
const structure = instance.getEnum('structure', {
|
|
23
|
+
'icon+text': 'icon+text',
|
|
24
|
+
'icon-only': 'icon-only',
|
|
25
|
+
'text-only': 'text-only',
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const labelNode = instance.findText('Active', { traverseInstances: true });
|
|
29
|
+
const label = labelNode.type === 'TEXT' ? labelNode.textContent : 'Active';
|
|
30
|
+
|
|
31
|
+
export default {
|
|
32
|
+
example:
|
|
33
|
+
structure === 'icon-only'
|
|
34
|
+
? figma.code`<DsStatusBadgeV2 phase="${phase}" label="${label}" variant="${variant}" size="${size}" iconOnly />`
|
|
35
|
+
: structure === 'text-only'
|
|
36
|
+
? figma.code`<DsStatusBadgeV2 phase="${phase}" label="${label}" variant="${variant}" size="${size}" icon={null} />`
|
|
37
|
+
: figma.code`<DsStatusBadgeV2 phase="${phase}" label="${label}" variant="${variant}" size="${size}" />`,
|
|
38
|
+
imports: ["import { DsStatusBadgeV2 } from '@drivenets/design-system'"],
|
|
39
|
+
id: 'ds-status-badge-v2',
|
|
40
|
+
metadata: { nestable: true },
|
|
41
|
+
};
|
|
@@ -1,9 +1,28 @@
|
|
|
1
|
+
@use '../../../../styles/scrollbars' as scrollbars;
|
|
2
|
+
|
|
1
3
|
.body {
|
|
2
|
-
display:
|
|
4
|
+
display: block;
|
|
5
|
+
position: relative;
|
|
6
|
+
overflow-y: auto;
|
|
7
|
+
flex: 1;
|
|
8
|
+
min-height: 0;
|
|
9
|
+
scrollbar-gutter: stable;
|
|
10
|
+
|
|
11
|
+
@include scrollbars.scrollbar-on-hover;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// 1px row pinned at `top: <totalSize>` (set inline) so absolutely-positioned
|
|
15
|
+
// rows extend the parent's scrollable overflow area.
|
|
16
|
+
.sentinel {
|
|
17
|
+
position: absolute;
|
|
18
|
+
left: 0;
|
|
19
|
+
width: 1px;
|
|
20
|
+
height: 1px;
|
|
21
|
+
pointer-events: none;
|
|
22
|
+
visibility: hidden;
|
|
3
23
|
}
|
|
4
24
|
|
|
5
25
|
.emptyState {
|
|
6
26
|
position: absolute;
|
|
7
27
|
inset: 0;
|
|
8
|
-
top: var(--ds-table-header-height);
|
|
9
28
|
}
|
package/src/components/ds-table/components/ds-table-body-virtualized/ds-table-body-virtualized.tsx
CHANGED
|
@@ -10,7 +10,6 @@ import { useInfiniteScroll } from './use-infinite-scroll';
|
|
|
10
10
|
|
|
11
11
|
export const DsTableBodyVirtualized = <TData,>({
|
|
12
12
|
table,
|
|
13
|
-
tableContainerRef,
|
|
14
13
|
emptyState,
|
|
15
14
|
estimateSize,
|
|
16
15
|
overscan,
|
|
@@ -20,6 +19,7 @@ export const DsTableBodyVirtualized = <TData,>({
|
|
|
20
19
|
}: DsTableBodyVirtualizedProps<TData>) => {
|
|
21
20
|
const rowsMapRef = useRef(new Map<string, HTMLTableRowElement>());
|
|
22
21
|
const rowHeightsMapRef = useRef(new Map<string, number>());
|
|
22
|
+
const tbodyRef = useRef<HTMLTableSectionElement>(null);
|
|
23
23
|
|
|
24
24
|
const { rows } = table.getRowModel();
|
|
25
25
|
|
|
@@ -32,16 +32,16 @@ export const DsTableBodyVirtualized = <TData,>({
|
|
|
32
32
|
return item ? `${item.row.id}${item.isExpandedRowContent ? '-expanded-content' : ''}` : String(index);
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
-
const { loadDataIfNeeded } = useInfiniteScroll(
|
|
35
|
+
const { loadDataIfNeeded } = useInfiniteScroll(tbodyRef, rows.length, infiniteScroll);
|
|
36
36
|
|
|
37
|
-
const rowVirtualizer = useVirtualizer<
|
|
37
|
+
const rowVirtualizer = useVirtualizer<HTMLTableSectionElement, HTMLTableRowElement>({
|
|
38
38
|
count: rowsAndExpandedRowContent.length,
|
|
39
39
|
estimateSize: (index) => {
|
|
40
40
|
const cachedHeight = rowHeightsMapRef.current.get(getItemKey(index));
|
|
41
41
|
return cachedHeight || estimateSize;
|
|
42
42
|
}, // estimate row height for accurate scrollbar dragging
|
|
43
43
|
getItemKey,
|
|
44
|
-
getScrollElement: () =>
|
|
44
|
+
getScrollElement: () => tbodyRef.current,
|
|
45
45
|
// measure dynamic row height, except in firefox because it measures table border height incorrectly
|
|
46
46
|
measureElement:
|
|
47
47
|
typeof window !== 'undefined' && navigator.userAgent.indexOf('Firefox') === -1
|
|
@@ -86,6 +86,7 @@ export const DsTableBodyVirtualized = <TData,>({
|
|
|
86
86
|
|
|
87
87
|
return (
|
|
88
88
|
<DsTableBody
|
|
89
|
+
ref={tbodyRef}
|
|
89
90
|
rowsMapRef={rowsMapRef}
|
|
90
91
|
rowHeightsMapRef={rowHeightsMapRef}
|
|
91
92
|
rowVirtualizer={rowVirtualizer}
|
|
@@ -97,7 +98,8 @@ export const DsTableBodyVirtualized = <TData,>({
|
|
|
97
98
|
};
|
|
98
99
|
|
|
99
100
|
interface DsTableBodyProps<TData> {
|
|
100
|
-
|
|
101
|
+
ref: RefObject<HTMLTableSectionElement | null>;
|
|
102
|
+
rowVirtualizer: Virtualizer<HTMLTableSectionElement, HTMLTableRowElement>;
|
|
101
103
|
rowsMapRef: RefObject<Map<string, HTMLTableRowElement>>;
|
|
102
104
|
rowHeightsMapRef: RefObject<Map<string, number>>;
|
|
103
105
|
rowsAndExpandedRowContent: {
|
|
@@ -108,7 +110,8 @@ interface DsTableBodyProps<TData> {
|
|
|
108
110
|
rowSelection: RowSelectionState;
|
|
109
111
|
}
|
|
110
112
|
|
|
111
|
-
function DsTableBody<TData>({
|
|
113
|
+
export function DsTableBody<TData>({
|
|
114
|
+
ref,
|
|
112
115
|
rowVirtualizer,
|
|
113
116
|
rowsMapRef,
|
|
114
117
|
rowHeightsMapRef,
|
|
@@ -117,14 +120,15 @@ function DsTableBody<TData>({
|
|
|
117
120
|
rowSelection,
|
|
118
121
|
}: DsTableBodyProps<TData>) {
|
|
119
122
|
const virtualRows = rowVirtualizer.getVirtualItems();
|
|
123
|
+
const totalSize = rowVirtualizer.getTotalSize();
|
|
124
|
+
|
|
125
|
+
// Gate the empty state on real data count, not on rendered virtual rows.
|
|
126
|
+
// getVirtualItems() transiently returns [] while the virtualizer re-measures
|
|
127
|
+
// after a `data` swap; rendering nothing for that frame avoids an empty-state flash.
|
|
128
|
+
const hasNoData = rowsAndExpandedRowContent.length === 0;
|
|
120
129
|
|
|
121
130
|
return (
|
|
122
|
-
<TableBody
|
|
123
|
-
className={styles.body}
|
|
124
|
-
style={{
|
|
125
|
-
height: `${rowVirtualizer.getTotalSize().toString()}px`, // tells scrollbar how big the table is
|
|
126
|
-
}}
|
|
127
|
-
>
|
|
131
|
+
<TableBody ref={ref} className={styles.body}>
|
|
128
132
|
{virtualRows.length > 0 ? (
|
|
129
133
|
virtualRows.map((virtualRow) => {
|
|
130
134
|
const row = rowsAndExpandedRowContent[virtualRow.index];
|
|
@@ -145,11 +149,15 @@ function DsTableBody<TData>({
|
|
|
145
149
|
/>
|
|
146
150
|
);
|
|
147
151
|
})
|
|
148
|
-
) : (
|
|
152
|
+
) : hasNoData ? (
|
|
149
153
|
<TableRow>
|
|
150
154
|
<TableCell className={styles.emptyState}>{emptyState || EMPTY_TABLE_STATE_TEXT}</TableCell>
|
|
151
155
|
</TableRow>
|
|
152
|
-
)}
|
|
156
|
+
) : null}
|
|
157
|
+
|
|
158
|
+
<tr aria-hidden className={styles.sentinel} style={{ top: `${totalSize.toString()}px` }}>
|
|
159
|
+
<td />
|
|
160
|
+
</tr>
|
|
153
161
|
</TableBody>
|
|
154
162
|
);
|
|
155
163
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
2
|
import { type RowSelectionState, type Table } from '@tanstack/react-table';
|
|
3
3
|
|
|
4
4
|
export interface DsTableBodyVirtualizedProps<TData> {
|
|
@@ -7,11 +7,6 @@ export interface DsTableBodyVirtualizedProps<TData> {
|
|
|
7
7
|
* and column state.
|
|
8
8
|
*/
|
|
9
9
|
table: Table<TData>;
|
|
10
|
-
/**
|
|
11
|
-
* Ref to the scrollable container that hosts the virtualized rows. Required by
|
|
12
|
-
* the virtualizer to measure viewport size and listen for scroll events.
|
|
13
|
-
*/
|
|
14
|
-
tableContainerRef: RefObject<HTMLDivElement | null>;
|
|
15
10
|
/**
|
|
16
11
|
* Optional content rendered in place of rows when the table has no data.
|
|
17
12
|
*/
|
package/src/components/ds-table/components/ds-table-bulk-actions/ds-table-bulk-actions.module.scss
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
@use '../../../../styles/typography';
|
|
2
2
|
|
|
3
3
|
.bulkActionsContainer {
|
|
4
|
-
position:
|
|
4
|
+
position: absolute;
|
|
5
5
|
bottom: 20px;
|
|
6
6
|
left: 50%;
|
|
7
7
|
transform: translateX(-50%);
|
|
8
8
|
background-color: var(--color-dap-gray-050);
|
|
9
9
|
border-radius: 8px;
|
|
10
10
|
box-shadow: 0 4px 12px #0445cc66;
|
|
11
|
-
z-index:
|
|
11
|
+
z-index: 1;
|
|
12
12
|
display: flex;
|
|
13
13
|
align-items: center;
|
|
14
14
|
border-radius: 8px;
|
|
@@ -2,31 +2,31 @@ import { type Cell, flexRender } from '@tanstack/react-table';
|
|
|
2
2
|
import classnames from 'classnames';
|
|
3
3
|
import { DsIcon } from '../../../ds-icon';
|
|
4
4
|
import { DsDropdownMenu } from '../../../ds-dropdown-menu';
|
|
5
|
+
import { useDsTableContext } from '../../context/ds-table-context';
|
|
6
|
+
import { DsTableEditableCell } from '../edit/ds-table-editable-cell';
|
|
7
|
+
import { DsTableEditingCell } from '../edit/ds-table-editing-cell';
|
|
5
8
|
import styles from './ds-table-cell.module.scss';
|
|
6
9
|
import type { DsTableCellProps } from './ds-table-cell.types';
|
|
7
10
|
|
|
8
|
-
const DsDefaultTableCell = <TData, TValue>({ cell }: { cell: Cell<TData, TValue> }) => {
|
|
9
|
-
return (
|
|
10
|
-
<div className={styles.tableCellEllipsis}>
|
|
11
|
-
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
|
12
|
-
</div>
|
|
13
|
-
);
|
|
14
|
-
};
|
|
15
|
-
|
|
16
11
|
export const DsTableCell = <TData, TValue>({
|
|
17
12
|
row,
|
|
18
13
|
cell,
|
|
19
14
|
primaryRowActions = [],
|
|
20
15
|
secondaryRowActions = [],
|
|
21
16
|
}: DsTableCellProps<TData, TValue>) => {
|
|
17
|
+
const { editing } = useDsTableContext<TData, TValue>();
|
|
18
|
+
const isCellBeingEdited =
|
|
19
|
+
editing !== null && editing.cell.row.id === row.id && editing.cell.column.id === cell.column.id;
|
|
20
|
+
|
|
22
21
|
const visiblePrimary = primaryRowActions.filter((action) => !action.hidden?.(row.original));
|
|
23
22
|
const visibleSecondary = secondaryRowActions.filter((action) => !action.hidden?.(row.original));
|
|
24
23
|
|
|
25
|
-
if (visiblePrimary.length || visibleSecondary.length) {
|
|
24
|
+
if (!isCellBeingEdited && (visiblePrimary.length || visibleSecondary.length)) {
|
|
26
25
|
const hasSecondaryRowActions = visibleSecondary.length > 0;
|
|
26
|
+
|
|
27
27
|
return (
|
|
28
28
|
<div className={styles.lastCell}>
|
|
29
|
-
<
|
|
29
|
+
<CellContent cell={cell} isCellBeingEdited={isCellBeingEdited} />
|
|
30
30
|
<div className={styles.cellActions}>
|
|
31
31
|
{visiblePrimary.map((action, i) => {
|
|
32
32
|
const isDisabled = action.disabled?.(row.original);
|
|
@@ -95,5 +95,36 @@ export const DsTableCell = <TData, TValue>({
|
|
|
95
95
|
</div>
|
|
96
96
|
);
|
|
97
97
|
}
|
|
98
|
-
|
|
98
|
+
|
|
99
|
+
return <CellContent cell={cell} isCellBeingEdited={isCellBeingEdited} />;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
interface CellContentProps<TData, TValue> {
|
|
103
|
+
cell: Cell<TData, TValue>;
|
|
104
|
+
isCellBeingEdited: boolean;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const CellContent = <TData, TValue>({ cell, isCellBeingEdited }: CellContentProps<TData, TValue>) => {
|
|
108
|
+
const columnDef = cell.column.columnDef;
|
|
109
|
+
const isEditable = typeof columnDef.editCell === 'function';
|
|
110
|
+
|
|
111
|
+
if (isCellBeingEdited) {
|
|
112
|
+
return <DsTableEditingCell cell={cell} />;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (isEditable) {
|
|
116
|
+
return (
|
|
117
|
+
<DsTableEditableCell cell={cell}>
|
|
118
|
+
<div className={styles.tableCellEllipsis}>
|
|
119
|
+
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
|
120
|
+
</div>
|
|
121
|
+
</DsTableEditableCell>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return (
|
|
126
|
+
<div className={styles.tableCellEllipsis}>
|
|
127
|
+
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
|
128
|
+
</div>
|
|
129
|
+
);
|
|
99
130
|
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
@use '../../../../styles/typography';
|
|
2
|
+
@use '../../styles/variables' as vars;
|
|
3
|
+
|
|
4
|
+
.groupHeaderCell {
|
|
5
|
+
@include typography.body-sm-md;
|
|
6
|
+
color: var(--font-main);
|
|
7
|
+
height: var(--ds-table-header-height);
|
|
8
|
+
padding: 0;
|
|
9
|
+
border-bottom: vars.$border-width solid var(--color-dap-gray-400);
|
|
10
|
+
border-left: vars.$group-border-width solid var(--border);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.groupHeaderContent {
|
|
14
|
+
display: flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
justify-content: space-between;
|
|
17
|
+
gap: vars.$header-sort-gap;
|
|
18
|
+
width: 100%;
|
|
19
|
+
height: 100%;
|
|
20
|
+
padding: 0 var(--standard);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.groupLabel {
|
|
24
|
+
overflow: hidden;
|
|
25
|
+
text-overflow: ellipsis;
|
|
26
|
+
white-space: nowrap;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.collapseToggle {
|
|
30
|
+
flex-shrink: 0;
|
|
31
|
+
}
|
package/src/components/ds-table/components/ds-table-group-header-cell/ds-table-group-header-cell.tsx
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { flexRender } from '@tanstack/react-table';
|
|
2
|
+
import { DsButtonV3 } from '../../../ds-button-v3';
|
|
3
|
+
import { TableHead } from '../core-table';
|
|
4
|
+
import { useDsTableContext } from '../../context/ds-table-context';
|
|
5
|
+
import { getGroupColumnSizeStyle } from '../../grouping';
|
|
6
|
+
import { defaultDsTableLocale } from '../../ds-table.types';
|
|
7
|
+
import type { DsTableGroupHeaderCellProps } from './ds-table-group-header-cell.types';
|
|
8
|
+
import styles from './ds-table-group-header-cell.module.scss';
|
|
9
|
+
|
|
10
|
+
export const DsTableGroupHeaderCell = <TData, TValue>({
|
|
11
|
+
header,
|
|
12
|
+
}: DsTableGroupHeaderCellProps<TData, TValue>) => {
|
|
13
|
+
const { collapsedColumnGroups, onToggleColumnGroup, locale } = useDsTableContext<TData, TValue>();
|
|
14
|
+
|
|
15
|
+
const groupId = header.column.id;
|
|
16
|
+
const visibleLeafColumns = header.column.getLeafColumns().filter((leaf) => leaf.getIsVisible());
|
|
17
|
+
const groupStyle = getGroupColumnSizeStyle(visibleLeafColumns);
|
|
18
|
+
|
|
19
|
+
const isCollapsible = header.column.columnDef.meta?.group?.collapsible ?? false;
|
|
20
|
+
const isCollapsed = collapsedColumnGroups?.includes(groupId) ?? false;
|
|
21
|
+
|
|
22
|
+
const mergedLocale = { ...defaultDsTableLocale, ...locale };
|
|
23
|
+
const toggleLabel = isCollapsed ? mergedLocale.expandColumnGroup : mergedLocale.collapseColumnGroup;
|
|
24
|
+
|
|
25
|
+
const handleToggle = () => onToggleColumnGroup?.(groupId);
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<TableHead className={styles.groupHeaderCell} style={groupStyle} colSpan={header.colSpan}>
|
|
29
|
+
<div className={styles.groupHeaderContent}>
|
|
30
|
+
<span className={styles.groupLabel}>
|
|
31
|
+
{flexRender(header.column.columnDef.header, header.getContext())}
|
|
32
|
+
</span>
|
|
33
|
+
{isCollapsible && (
|
|
34
|
+
<DsButtonV3
|
|
35
|
+
variant="secondary"
|
|
36
|
+
size="tiny"
|
|
37
|
+
icon={isCollapsed ? 'chevron_right' : 'chevron_left'}
|
|
38
|
+
className={styles.collapseToggle}
|
|
39
|
+
aria-label={toggleLabel}
|
|
40
|
+
aria-expanded={!isCollapsed}
|
|
41
|
+
title={toggleLabel}
|
|
42
|
+
onClick={handleToggle}
|
|
43
|
+
/>
|
|
44
|
+
)}
|
|
45
|
+
</div>
|
|
46
|
+
</TableHead>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Header } from '@tanstack/react-table';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Props for the grouping column header cell.
|
|
5
|
+
*/
|
|
6
|
+
export interface DsTableGroupHeaderCellProps<TData, TValue> {
|
|
7
|
+
/**
|
|
8
|
+
* The grouping header from `@tanstack/react-table` (a header whose column nests
|
|
9
|
+
* child columns).
|
|
10
|
+
*/
|
|
11
|
+
header: Header<TData, TValue>;
|
|
12
|
+
}
|
|
@@ -2,14 +2,11 @@
|
|
|
2
2
|
@use '../../styles/variables' as vars;
|
|
3
3
|
|
|
4
4
|
.stickyHeader {
|
|
5
|
-
position: sticky;
|
|
6
|
-
top: 0;
|
|
7
|
-
z-index: 10;
|
|
8
5
|
background-color: var(--background);
|
|
9
6
|
}
|
|
10
7
|
|
|
11
8
|
.virtualizedHeader {
|
|
12
|
-
display:
|
|
9
|
+
display: block;
|
|
13
10
|
}
|
|
14
11
|
|
|
15
12
|
.headerRow {
|
|
@@ -57,6 +54,11 @@
|
|
|
57
54
|
|
|
58
55
|
.selectHeaderCell {
|
|
59
56
|
padding: 0;
|
|
57
|
+
justify-content: center;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.groupStart {
|
|
61
|
+
border-left: vars.$group-border-width solid var(--border);
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
.headerSortContainer {
|
|
@@ -66,3 +68,25 @@
|
|
|
66
68
|
gap: vars.$header-sort-gap;
|
|
67
69
|
height: 100%;
|
|
68
70
|
}
|
|
71
|
+
|
|
72
|
+
.filterTriggerContainer {
|
|
73
|
+
display: inline-flex;
|
|
74
|
+
align-items: center;
|
|
75
|
+
margin-left: vars.$header-sort-gap;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.filterableHeader {
|
|
79
|
+
&:hover .filterTriggerContainer > * {
|
|
80
|
+
opacity: 1;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
&:focus-within .filterTriggerContainer > * {
|
|
84
|
+
opacity: 1;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.filterActive {
|
|
89
|
+
.filterTriggerContainer > * {
|
|
90
|
+
opacity: 1;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -9,6 +9,10 @@ import { useDsTableContext } from '../../context/ds-table-context';
|
|
|
9
9
|
import { getColumnSizeStyle } from '../../utils/column-size';
|
|
10
10
|
import { SELECT_COLUMN_ID } from '../../utils/constants';
|
|
11
11
|
import { DsStack } from '../../../ds-stack';
|
|
12
|
+
import { DsTableColumnFilterPopover } from '../../filters/components/column-filter-popover';
|
|
13
|
+
import type { ResolvedColumnFilter } from '../../filters/types/filter-adapter.types';
|
|
14
|
+
import { DsTableGroupHeaderCell } from '../ds-table-group-header-cell';
|
|
15
|
+
import { isFirstLeafColumnOfGroup } from '../../grouping';
|
|
12
16
|
|
|
13
17
|
const DsTableHeader = <TData,>({ table }: DsTableHeaderProps<TData>) => {
|
|
14
18
|
const { stickyHeader, bordered, virtualized } = useDsTableContext<TData, unknown>();
|
|
@@ -27,9 +31,29 @@ const DsTableHeader = <TData,>({ table }: DsTableHeaderProps<TData>) => {
|
|
|
27
31
|
)}
|
|
28
32
|
>
|
|
29
33
|
{headerGroup.headers.map((header) => {
|
|
30
|
-
|
|
34
|
+
if (header.isPlaceholder) {
|
|
35
|
+
return (
|
|
36
|
+
<TableHead
|
|
37
|
+
key={header.id}
|
|
38
|
+
className={styles.headerCell}
|
|
39
|
+
style={getColumnSizeStyle(header.getSize())}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (header.subHeaders.length > 0) {
|
|
45
|
+
return <DsTableGroupHeaderCell key={header.id} header={header} />;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const headerStyle = getColumnSizeStyle(header.column.getSize());
|
|
31
49
|
const canSort = header.column.getCanSort();
|
|
32
50
|
const isSelectColumn = header.column.id === SELECT_COLUMN_ID;
|
|
51
|
+
const isGroupStart = isFirstLeafColumnOfGroup(header.column);
|
|
52
|
+
|
|
53
|
+
const metaFilter = header.column.columnDef.meta?.filter;
|
|
54
|
+
const resolvedFilter: ResolvedColumnFilter | undefined =
|
|
55
|
+
metaFilter && 'render' in metaFilter ? metaFilter : undefined;
|
|
56
|
+
const hasActiveColumnFilter = resolvedFilter?.hasActiveFilter ?? false;
|
|
33
57
|
|
|
34
58
|
return (
|
|
35
59
|
<TableHead
|
|
@@ -38,37 +62,50 @@ const DsTableHeader = <TData,>({ table }: DsTableHeaderProps<TData>) => {
|
|
|
38
62
|
styles.headerCell,
|
|
39
63
|
canSort && styles.sortableHeader,
|
|
40
64
|
isSelectColumn && styles.selectHeaderCell,
|
|
65
|
+
resolvedFilter && styles.filterableHeader,
|
|
66
|
+
hasActiveColumnFilter && styles.filterActive,
|
|
67
|
+
isGroupStart && styles.groupStart,
|
|
41
68
|
)}
|
|
42
69
|
onClick={header.column.getToggleSortingHandler()}
|
|
43
70
|
style={headerStyle}
|
|
44
71
|
>
|
|
45
|
-
{
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
{
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
<div className={styles.headerSortContainer}>
|
|
73
|
+
<DsStack direction="column" justifyContent="center" width="100%">
|
|
74
|
+
{flexRender(header.column.columnDef.header, header.getContext())}
|
|
75
|
+
</DsStack>
|
|
76
|
+
{canSort && (
|
|
77
|
+
<div className={styles.pageButtonIconContainer}>
|
|
78
|
+
{{
|
|
79
|
+
asc: (
|
|
80
|
+
<DsIcon
|
|
81
|
+
icon="arrow_drop_up"
|
|
82
|
+
className={classnames(styles.pageButtonIcon, stylesShared.pageButtonIcon)}
|
|
83
|
+
/>
|
|
84
|
+
),
|
|
85
|
+
desc: (
|
|
86
|
+
<DsIcon
|
|
87
|
+
icon="arrow_drop_down"
|
|
88
|
+
className={classnames(styles.pageButtonIcon, stylesShared.pageButtonIcon)}
|
|
89
|
+
/>
|
|
90
|
+
),
|
|
91
|
+
}[header.column.getIsSorted() as string] ?? (
|
|
92
|
+
<div className={classnames(styles.pageButtonIcon, stylesShared.pageButtonIcon)} />
|
|
93
|
+
)}
|
|
94
|
+
</div>
|
|
95
|
+
)}
|
|
96
|
+
{resolvedFilter && (
|
|
97
|
+
<div className={styles.filterTriggerContainer}>
|
|
98
|
+
<DsTableColumnFilterPopover
|
|
99
|
+
hasActiveFilter={resolvedFilter.hasActiveFilter}
|
|
100
|
+
onApply={resolvedFilter.onApply}
|
|
101
|
+
onClear={resolvedFilter.onClear}
|
|
102
|
+
onCancel={resolvedFilter.onCancel}
|
|
103
|
+
>
|
|
104
|
+
{resolvedFilter.render()}
|
|
105
|
+
</DsTableColumnFilterPopover>
|
|
106
|
+
</div>
|
|
107
|
+
)}
|
|
108
|
+
</div>
|
|
72
109
|
</TableHead>
|
|
73
110
|
);
|
|
74
111
|
})}
|
|
@@ -50,6 +50,8 @@
|
|
|
50
50
|
background-color: var(--background-secondary);
|
|
51
51
|
|
|
52
52
|
& > td {
|
|
53
|
+
flex: 1;
|
|
54
|
+
min-width: 0;
|
|
53
55
|
padding: var(--standard);
|
|
54
56
|
}
|
|
55
57
|
|
|
@@ -80,4 +82,28 @@
|
|
|
80
82
|
.selectableCell {
|
|
81
83
|
padding: 0;
|
|
82
84
|
text-align: center;
|
|
85
|
+
justify-content: center;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.groupStart {
|
|
89
|
+
border-left: vars.$group-border-width solid var(--border);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.tableRow .editableCell {
|
|
93
|
+
padding: 1px;
|
|
94
|
+
|
|
95
|
+
&:hover {
|
|
96
|
+
border: 1px solid var(--border-secondary-hover);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
&:focus-within {
|
|
100
|
+
border: 1px solid var(--border-action-primary);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
&:hover,
|
|
104
|
+
&:focus-within {
|
|
105
|
+
padding: 0;
|
|
106
|
+
border-bottom-width: 2px;
|
|
107
|
+
background: var(--background);
|
|
108
|
+
}
|
|
83
109
|
}
|
|
@@ -10,6 +10,7 @@ import styles from './ds-table-row.module.scss';
|
|
|
10
10
|
import { useDsTableContext } from '../../context/ds-table-context';
|
|
11
11
|
import { mergeRefs } from '../../../../utils/merge-refs';
|
|
12
12
|
import { getColumnSizeStyle } from '../../utils/column-size';
|
|
13
|
+
import { isFirstLeafColumnOfGroup } from '../../grouping';
|
|
13
14
|
import { EXPANDER_COLUMN_ID, REORDER_COLUMN_ID, SELECT_COLUMN_ID } from '../../utils/constants';
|
|
14
15
|
|
|
15
16
|
interface DsRowDragHandleProps {
|
|
@@ -118,6 +119,8 @@ const DsTableRow = <TData,>({ ref, row, isSelected }: DsTableRowProps<TData>) =>
|
|
|
118
119
|
styles.tableCell,
|
|
119
120
|
cell.column.id === EXPANDER_COLUMN_ID && styles.expandableCell,
|
|
120
121
|
cell.column.id === SELECT_COLUMN_ID && styles.selectableCell,
|
|
122
|
+
isFirstLeafColumnOfGroup(cell.column) && styles.groupStart,
|
|
123
|
+
typeof cell.column.columnDef.editCell === 'function' && styles.editableCell,
|
|
121
124
|
)}
|
|
122
125
|
style={cellStyle}
|
|
123
126
|
>
|
|
@@ -66,6 +66,10 @@
|
|
|
66
66
|
justify-content: center;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
.groupStart {
|
|
70
|
+
border-left: vars.$group-border-width solid var(--border);
|
|
71
|
+
}
|
|
72
|
+
|
|
69
73
|
.expandedRowContent {
|
|
70
74
|
background-color: var(--background-secondary);
|
|
71
75
|
|
|
@@ -79,3 +83,22 @@
|
|
|
79
83
|
|
|
80
84
|
@include table-mixins.expanded-row-border('bottom');
|
|
81
85
|
}
|
|
86
|
+
|
|
87
|
+
.row td.editableCell {
|
|
88
|
+
padding: 1px;
|
|
89
|
+
|
|
90
|
+
&:hover {
|
|
91
|
+
border: 1px solid var(--border-secondary-hover);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
&:focus-within {
|
|
95
|
+
border: 1px solid var(--border-action-primary);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
&:hover,
|
|
99
|
+
&:focus-within {
|
|
100
|
+
padding: 0;
|
|
101
|
+
border-bottom-width: 2px;
|
|
102
|
+
background: var(--background);
|
|
103
|
+
}
|
|
104
|
+
}
|