@drivenets/design-system 0.18.0 → 0.19.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 +26 -0
- package/dist/index.cjs +15850 -10821
- package/dist/index.d.cts +785 -239
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +785 -239
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15835 -10822
- package/dist/index.js.map +1 -1
- package/dist/index.min.css +1 -1
- package/package.json +13 -13
- package/src/components/ds-bot-button/ds-bot-button.figma.ts +38 -0
- package/src/components/ds-bot-button/ds-bot-button.module.scss +41 -0
- package/src/components/ds-bot-button/ds-bot-button.tsx +48 -0
- package/src/components/ds-bot-button/ds-bot-button.types.ts +33 -0
- package/src/components/ds-bot-button/index.ts +2 -0
- package/src/components/ds-bot-button/net-gen-logo.tsx +46 -0
- package/src/components/ds-bulk-actions/components/action-button.tsx +42 -0
- package/src/components/ds-bulk-actions/components/menu-entries.tsx +76 -0
- package/src/components/ds-bulk-actions/components/overflow.tsx +75 -0
- package/src/components/ds-bulk-actions/ds-bulk-actions.figma.ts +28 -0
- package/src/components/ds-bulk-actions/ds-bulk-actions.module.scss +199 -0
- package/src/components/ds-bulk-actions/ds-bulk-actions.tsx +220 -0
- package/src/components/ds-bulk-actions/ds-bulk-actions.types.ts +170 -0
- package/src/components/ds-bulk-actions/ds-bulk-actions.unit.test.ts +195 -0
- package/src/components/ds-bulk-actions/ds-bulk-actions.utils.ts +91 -0
- package/src/components/ds-bulk-actions/ds-bulk-actions.utils.unit.test.ts +134 -0
- package/src/components/ds-bulk-actions/hooks/compute-bulk-actions-overflow.ts +85 -0
- package/src/components/ds-bulk-actions/hooks/use-bulk-actions-overflow.ts +153 -0
- package/src/components/ds-bulk-actions/index.ts +18 -0
- package/src/components/ds-button-v3/ds-button-v3.module.scss +2 -2
- package/src/components/ds-catalog-layout/ds-catalog-layout.figma.ts +1 -1
- package/src/components/ds-dropdown-menu/ds-dropdown-menu.tsx +2 -0
- package/src/components/ds-empty-state/ds-empty-state.module.scss +16 -0
- package/src/components/ds-empty-state/ds-empty-state.tsx +45 -0
- package/src/components/ds-empty-state/ds-empty-state.types.ts +38 -0
- package/src/components/ds-empty-state/index.ts +3 -0
- package/src/components/ds-file-upload/ds-file-upload.tsx +4 -1
- package/src/components/ds-form-control/ds-form-control.tsx +18 -10
- package/src/components/ds-illustration/ds-illustration.figma.ts +34 -0
- package/src/components/ds-illustration/ds-illustration.module.scss +6 -0
- package/src/components/ds-illustration/ds-illustration.tsx +29 -0
- package/src/components/ds-illustration/ds-illustration.types.ts +45 -0
- package/src/components/ds-illustration/illustrations/configuration.tsx +51 -0
- package/src/components/ds-illustration/illustrations/device.tsx +133 -0
- package/src/components/ds-illustration/illustrations/done.tsx +107 -0
- package/src/components/{ds-catalog-layout/catalog-layout-empty-illustration.tsx → ds-illustration/illustrations/empty-inbox.tsx} +10 -14
- package/src/components/ds-illustration/illustrations/error.tsx +86 -0
- package/src/components/ds-illustration/illustrations/go-filter.tsx +51 -0
- package/src/components/ds-illustration/illustrations/illustration-clouds.tsx +10 -0
- package/src/components/ds-illustration/illustrations/index.ts +39 -0
- package/src/components/ds-illustration/illustrations/no-connection.tsx +54 -0
- package/src/components/ds-illustration/illustrations/no-credit-card.tsx +48 -0
- package/src/components/ds-illustration/illustrations/no-device.tsx +61 -0
- package/src/components/ds-illustration/illustrations/no-documents.tsx +52 -0
- package/src/components/ds-illustration/illustrations/no-gps.tsx +57 -0
- package/src/components/ds-illustration/illustrations/no-images.tsx +82 -0
- package/src/components/ds-illustration/illustrations/no-items-cart.tsx +86 -0
- package/src/components/ds-illustration/illustrations/no-messages.tsx +51 -0
- package/src/components/ds-illustration/illustrations/no-search-result.tsx +76 -0
- package/src/components/ds-illustration/illustrations/no-tasks.tsx +61 -0
- package/src/components/ds-illustration/illustrations/site.tsx +80 -0
- package/src/components/ds-illustration/index.ts +3 -0
- package/src/components/ds-main-menu/components/expanded-item/expanded-item.tsx +108 -0
- package/src/components/ds-main-menu/components/expanded-item/expanded-item.types.ts +8 -0
- package/src/components/ds-main-menu/components/expanded-item/index.ts +1 -0
- package/src/components/ds-main-menu/components/menu-graphic/index.ts +1 -0
- package/src/components/ds-main-menu/components/menu-graphic/menu-graphic.tsx +16 -0
- package/src/components/ds-main-menu/components/menu-graphic/menu-graphic.types.ts +7 -0
- package/src/components/ds-main-menu/components/tile-link/index.ts +1 -0
- package/src/components/ds-main-menu/components/tile-link/tile-link.tsx +85 -0
- package/src/components/ds-main-menu/components/tile-link/tile-link.types.ts +8 -0
- package/src/components/ds-main-menu/components/utility-link/index.ts +1 -0
- package/src/components/ds-main-menu/components/utility-link/utility-link.tsx +37 -0
- package/src/components/ds-main-menu/components/utility-link/utility-link.types.ts +7 -0
- package/src/components/ds-main-menu/ds-main-menu.figma.ts +17 -0
- package/src/components/ds-main-menu/ds-main-menu.module.scss +349 -0
- package/src/components/ds-main-menu/ds-main-menu.tsx +102 -0
- package/src/components/ds-main-menu/ds-main-menu.types.ts +86 -0
- package/src/components/ds-main-menu/ds-main-menu.utils.ts +40 -0
- package/src/components/ds-main-menu/index.ts +9 -0
- package/src/components/ds-modal/figma/ds-modal-footer.figma.ts +1 -1
- package/src/components/ds-popover/ds-popover.tsx +2 -1
- package/src/components/ds-popover/ds-popover.types.ts +7 -0
- package/src/components/ds-site-node/ds-site-node.tsx +2 -2
- package/src/components/ds-table/components/ds-table-body-virtualized/ds-table-body-virtualized.module.scss +12 -2
- package/src/components/ds-table/components/ds-table-body-virtualized/ds-table-body-virtualized.tsx +2 -3
- package/src/components/ds-table/components/ds-table-group-header-cell/ds-table-group-header-cell.module.scss +1 -6
- package/src/components/ds-table/components/ds-table-group-header-cell/ds-table-group-header-cell.tsx +6 -3
- package/src/components/ds-table/components/ds-table-header/ds-table-header.module.scss +18 -7
- package/src/components/ds-table/components/ds-table-header/ds-table-header.tsx +27 -21
- package/src/components/ds-table/components/ds-table-header-label.module.scss +12 -0
- package/src/components/ds-table/components/ds-table-header-label.tsx +28 -0
- package/src/components/ds-table/components/ds-table-row/ds-table-row.module.scss +0 -1
- package/src/components/ds-table/context/ds-table-context.tsx +8 -0
- package/src/components/ds-table/ds-table.module.scss +26 -16
- package/src/components/ds-table/ds-table.tsx +46 -14
- package/src/components/ds-table/ds-table.types.ts +33 -3
- package/src/components/ds-table/hooks/use-column-resize.ts +114 -11
- package/src/components/ds-table/hooks/use-scrollbar-spacer.ts +108 -0
- package/src/components/ds-table/hooks/use-scrollbar-spacer.unit.test.ts +26 -0
- package/src/components/ds-table/styles/_variables.scss +0 -2
- package/src/components/ds-table/utils/column-size.ts +274 -1
- package/src/components/ds-table/utils/column-size.unit.test.ts +157 -0
- package/src/components/ds-table/utils/constants.ts +13 -5
- package/src/components/ds-table/utils/table-columns.tsx +27 -13
- package/src/components/ds-table/utils/table-columns.unit.test.ts +44 -0
- package/src/components/ds-tag-filter/ds-tag-filter.module.scss +7 -35
- package/src/components/ds-tag-filter/ds-tag-filter.tsx +34 -57
- package/src/components/ds-tag-filter/ds-tag-filter.types.ts +2 -1
- package/src/components/ds-tag-filter/hooks/use-tag-overflow-calculation.ts +13 -18
- package/src/components/ds-toggle/ds-toggle.module.scss +18 -0
- package/src/components/ds-toggle/ds-toggle.tsx +15 -13
- package/src/components/ds-tooltip/ds-tooltip.tsx +6 -2
- package/src/components/ds-tooltip/ds-tooltip.types.ts +17 -0
- package/src/components/ds-top-bar-navigation/ds-top-bar-navigation.figma.ts +35 -0
- package/src/components/ds-top-bar-navigation/ds-top-bar-navigation.module.scss +150 -0
- package/src/components/ds-top-bar-navigation/ds-top-bar-navigation.tsx +161 -0
- package/src/components/ds-top-bar-navigation/ds-top-bar-navigation.types.ts +117 -0
- package/src/components/ds-top-bar-navigation/index.ts +2 -0
- package/src/index.ts +6 -0
- package/src/utils/use-is-horizontally-overflowing.ts +35 -0
- package/src/components/ds-site-node/hooks/use-is-overflowing.ts +0 -31
- package/src/components/ds-table/components/ds-table-bulk-actions/ds-table-bulk-actions.module.scss +0 -112
- package/src/components/ds-table/components/ds-table-bulk-actions/ds-table-bulk-actions.tsx +0 -67
- package/src/components/ds-table/components/ds-table-bulk-actions/ds-table-bulk-actions.types.ts +0 -41
- package/src/components/ds-table/components/ds-table-bulk-actions/index.ts +0 -2
package/src/components/ds-table/components/ds-table-group-header-cell/ds-table-group-header-cell.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import { useDsTableContext } from '../../context/ds-table-context';
|
|
|
5
5
|
import { getGroupColumnSizeStyle } from '../../grouping';
|
|
6
6
|
import { getResizableHeaderStyle } from '../../utils/column-size';
|
|
7
7
|
import { defaultDsTableLocale } from '../../ds-table.types';
|
|
8
|
+
import { DsTableHeaderLabel } from '../ds-table-header-label';
|
|
8
9
|
import { DsTableResizeHandle } from '../ds-table-resize-handle';
|
|
9
10
|
import type { DsTableGroupHeaderCellProps } from './ds-table-group-header-cell.types';
|
|
10
11
|
import styles from './ds-table-group-header-cell.module.scss';
|
|
@@ -29,6 +30,8 @@ export const DsTableGroupHeaderCell = <TData, TValue>({
|
|
|
29
30
|
const toggleLabel = isCollapsed ? mergedLocale.expandColumnGroup : mergedLocale.collapseColumnGroup;
|
|
30
31
|
|
|
31
32
|
const handleToggle = () => onToggleColumnGroup?.(groupId);
|
|
33
|
+
const headerDef = header.column.columnDef.header;
|
|
34
|
+
const tooltipText = typeof headerDef === 'string' ? headerDef : undefined;
|
|
32
35
|
|
|
33
36
|
return (
|
|
34
37
|
<TableHead
|
|
@@ -38,9 +41,9 @@ export const DsTableGroupHeaderCell = <TData, TValue>({
|
|
|
38
41
|
colSpan={header.colSpan}
|
|
39
42
|
>
|
|
40
43
|
<div className={styles.groupHeaderContent}>
|
|
41
|
-
<
|
|
42
|
-
{flexRender(
|
|
43
|
-
</
|
|
44
|
+
<DsTableHeaderLabel tooltipText={tooltipText}>
|
|
45
|
+
{flexRender(headerDef, header.getContext())}
|
|
46
|
+
</DsTableHeaderLabel>
|
|
44
47
|
{isCollapsible && (
|
|
45
48
|
<DsButtonV3
|
|
46
49
|
variant="secondary"
|
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
border-bottom: 1px solid var(--color-dap-gray-400);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
.scrollbarSpacer:not(.scrollbarSpacerOccupied) {
|
|
19
|
+
border-bottom: none;
|
|
20
|
+
}
|
|
21
|
+
|
|
18
22
|
&.headerRowNoBorder {
|
|
19
23
|
.headerCell {
|
|
20
24
|
border-bottom: none;
|
|
@@ -42,6 +46,7 @@
|
|
|
42
46
|
|
|
43
47
|
.pageButtonIconContainer {
|
|
44
48
|
display: flex;
|
|
49
|
+
flex-shrink: 0;
|
|
45
50
|
align-items: center;
|
|
46
51
|
justify-content: center;
|
|
47
52
|
width: 24px;
|
|
@@ -54,9 +59,18 @@
|
|
|
54
59
|
}
|
|
55
60
|
}
|
|
56
61
|
|
|
62
|
+
.scrollbarSpacer {
|
|
63
|
+
flex-shrink: 0;
|
|
64
|
+
padding: 0;
|
|
65
|
+
overflow: hidden;
|
|
66
|
+
border-left: none;
|
|
67
|
+
pointer-events: none;
|
|
68
|
+
}
|
|
69
|
+
|
|
57
70
|
.selectHeaderCell {
|
|
58
71
|
padding: 0;
|
|
59
72
|
justify-content: center;
|
|
73
|
+
text-align: center;
|
|
60
74
|
}
|
|
61
75
|
|
|
62
76
|
.groupStart:not(:first-child) {
|
|
@@ -68,7 +82,10 @@
|
|
|
68
82
|
align-items: center;
|
|
69
83
|
justify-content: space-between;
|
|
70
84
|
gap: vars.$header-sort-gap;
|
|
85
|
+
width: 100%;
|
|
86
|
+
min-width: 0;
|
|
71
87
|
height: 100%;
|
|
88
|
+
overflow: hidden;
|
|
72
89
|
}
|
|
73
90
|
|
|
74
91
|
.headerLabelStack {
|
|
@@ -76,15 +93,9 @@
|
|
|
76
93
|
overflow: hidden;
|
|
77
94
|
}
|
|
78
95
|
|
|
79
|
-
.headerLabel {
|
|
80
|
-
display: block;
|
|
81
|
-
overflow: hidden;
|
|
82
|
-
text-overflow: ellipsis;
|
|
83
|
-
white-space: nowrap;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
96
|
.filterTriggerContainer {
|
|
87
97
|
display: inline-flex;
|
|
98
|
+
flex-shrink: 0;
|
|
88
99
|
align-items: center;
|
|
89
100
|
margin-left: vars.$header-sort-gap;
|
|
90
101
|
}
|
|
@@ -12,11 +12,13 @@ import { DsStack } from '../../../ds-stack';
|
|
|
12
12
|
import { DsTableColumnFilterPopover } from '../../filters/components/column-filter-popover';
|
|
13
13
|
import type { ResolvedColumnFilter } from '../../filters/types/filter-adapter.types';
|
|
14
14
|
import { DsTableGroupHeaderCell } from '../ds-table-group-header-cell';
|
|
15
|
+
import { DsTableHeaderLabel } from '../ds-table-header-label';
|
|
15
16
|
import { DsTableResizeHandle } from '../ds-table-resize-handle';
|
|
16
17
|
import { isFirstLeafColumnOfGroup } from '../../grouping';
|
|
17
18
|
|
|
18
19
|
const DsTableHeader = <TData,>({ table }: DsTableHeaderProps<TData>) => {
|
|
19
|
-
const { bordered, virtualized, resizableColumns, resizeSizingReady } =
|
|
20
|
+
const { bordered, virtualized, resizableColumns, resizeSizingReady, scrollbarSpacerWidth } =
|
|
21
|
+
useDsTableContext<TData, unknown>();
|
|
20
22
|
|
|
21
23
|
return (
|
|
22
24
|
<TableHeader className={classnames(styles.header, virtualized && styles.virtualizedHeader)}>
|
|
@@ -58,6 +60,7 @@ const DsTableHeader = <TData,>({ table }: DsTableHeaderProps<TData>) => {
|
|
|
58
60
|
!!resizeSizingReady,
|
|
59
61
|
);
|
|
60
62
|
const canSort = header.column.getCanSort();
|
|
63
|
+
const sortDirection = header.column.getIsSorted();
|
|
61
64
|
const canResize = resizableColumns && header.column.getCanResize();
|
|
62
65
|
const isSelectColumn = header.column.id === SELECT_COLUMN_ID;
|
|
63
66
|
const isGroupStart = isFirstLeafColumnOfGroup(header.column);
|
|
@@ -66,6 +69,8 @@ const DsTableHeader = <TData,>({ table }: DsTableHeaderProps<TData>) => {
|
|
|
66
69
|
const resolvedFilter: ResolvedColumnFilter | undefined =
|
|
67
70
|
metaFilter && 'render' in metaFilter ? metaFilter : undefined;
|
|
68
71
|
const hasActiveColumnFilter = resolvedFilter?.hasActiveFilter ?? false;
|
|
72
|
+
const headerDef = header.column.columnDef.header;
|
|
73
|
+
const tooltipText = typeof headerDef === 'string' ? headerDef : undefined;
|
|
69
74
|
|
|
70
75
|
return (
|
|
71
76
|
<TableHead
|
|
@@ -89,28 +94,16 @@ const DsTableHeader = <TData,>({ table }: DsTableHeaderProps<TData>) => {
|
|
|
89
94
|
width="100%"
|
|
90
95
|
className={styles.headerLabelStack}
|
|
91
96
|
>
|
|
92
|
-
<
|
|
93
|
-
{flexRender(
|
|
94
|
-
</
|
|
97
|
+
<DsTableHeaderLabel tooltipText={tooltipText}>
|
|
98
|
+
{flexRender(headerDef, header.getContext())}
|
|
99
|
+
</DsTableHeaderLabel>
|
|
95
100
|
</DsStack>
|
|
96
|
-
{canSort && (
|
|
101
|
+
{canSort && sortDirection && (
|
|
97
102
|
<div className={styles.pageButtonIconContainer}>
|
|
98
|
-
|
|
99
|
-
asc:
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
className={classnames(styles.pageButtonIcon, stylesShared.pageButtonIcon)}
|
|
103
|
-
/>
|
|
104
|
-
),
|
|
105
|
-
desc: (
|
|
106
|
-
<DsIcon
|
|
107
|
-
icon="arrow_drop_down"
|
|
108
|
-
className={classnames(styles.pageButtonIcon, stylesShared.pageButtonIcon)}
|
|
109
|
-
/>
|
|
110
|
-
),
|
|
111
|
-
}[header.column.getIsSorted() as string] ?? (
|
|
112
|
-
<div className={classnames(styles.pageButtonIcon, stylesShared.pageButtonIcon)} />
|
|
113
|
-
)}
|
|
103
|
+
<DsIcon
|
|
104
|
+
icon={sortDirection === 'asc' ? 'arrow_drop_up' : 'arrow_drop_down'}
|
|
105
|
+
className={classnames(styles.pageButtonIcon, stylesShared.pageButtonIcon)}
|
|
106
|
+
/>
|
|
114
107
|
</div>
|
|
115
108
|
)}
|
|
116
109
|
{resolvedFilter && (
|
|
@@ -130,6 +123,19 @@ const DsTableHeader = <TData,>({ table }: DsTableHeaderProps<TData>) => {
|
|
|
130
123
|
</TableHead>
|
|
131
124
|
);
|
|
132
125
|
})}
|
|
126
|
+
<TableHead
|
|
127
|
+
aria-hidden
|
|
128
|
+
className={classnames(
|
|
129
|
+
styles.headerCell,
|
|
130
|
+
styles.scrollbarSpacer,
|
|
131
|
+
scrollbarSpacerWidth > 0 && styles.scrollbarSpacerOccupied,
|
|
132
|
+
)}
|
|
133
|
+
style={{
|
|
134
|
+
width: scrollbarSpacerWidth,
|
|
135
|
+
minWidth: scrollbarSpacerWidth,
|
|
136
|
+
flexShrink: 0,
|
|
137
|
+
}}
|
|
138
|
+
/>
|
|
133
139
|
</TableRow>
|
|
134
140
|
))}
|
|
135
141
|
</TableHeader>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import classnames from 'classnames';
|
|
3
|
+
import { DsTooltip } from '../../ds-tooltip';
|
|
4
|
+
import { useIsHorizontallyOverflowing } from '../../../utils/use-is-horizontally-overflowing';
|
|
5
|
+
import styles from './ds-table-header-label.module.scss';
|
|
6
|
+
|
|
7
|
+
type DsTableHeaderLabelProps = {
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
tooltipText?: string;
|
|
10
|
+
className?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const DsTableHeaderLabel = ({ className, children, tooltipText }: DsTableHeaderLabelProps) => {
|
|
14
|
+
const { ref, isOverflowing } = useIsHorizontallyOverflowing<HTMLSpanElement>(tooltipText);
|
|
15
|
+
const title = isOverflowing ? tooltipText : undefined;
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<span className={classnames(styles.headerLabel, className)}>
|
|
19
|
+
<DsTooltip content={title} placement="top">
|
|
20
|
+
<span ref={ref} className={styles.headerLabelInner}>
|
|
21
|
+
{children}
|
|
22
|
+
</span>
|
|
23
|
+
</DsTooltip>
|
|
24
|
+
</span>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
DsTableHeaderLabel.displayName = 'DsTableHeaderLabel';
|
|
@@ -2,6 +2,7 @@ import { createContext, useContext, useMemo, type ReactNode, type RefObject } fr
|
|
|
2
2
|
import type { DsDataTableProps, DsTableRowSize } from '../ds-table.types';
|
|
3
3
|
import type { DsTablePropsWithDefaults } from '../ds-table-defaults';
|
|
4
4
|
import type { DsTableResizeContextSlice } from '../hooks/use-column-resize';
|
|
5
|
+
import type { ScrollbarSpacerWidth } from '../hooks/use-scrollbar-spacer';
|
|
5
6
|
import { useEditingState, type UseEditingStateResult } from '../hooks/use-editing-state';
|
|
6
7
|
|
|
7
8
|
/** Visual phase of the full-height column-resize divider. */
|
|
@@ -56,6 +57,10 @@ export interface DsTableContextType<TData, TValue>
|
|
|
56
57
|
* boundary header's column (leaf or group). Clamps and fires persist.
|
|
57
58
|
*/
|
|
58
59
|
onResizeKeyboardNudge?: (columnId: string, delta: number) => void;
|
|
60
|
+
/**
|
|
61
|
+
* Overflow-only **Scrollbar spacer** width (0 or rest scrollbar size).
|
|
62
|
+
*/
|
|
63
|
+
scrollbarSpacerWidth: ScrollbarSpacerWidth;
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -124,6 +129,7 @@ export const DsTableContextProvider = <TData, TValue>({
|
|
|
124
129
|
onResizeDragStart,
|
|
125
130
|
onResizeReset,
|
|
126
131
|
onResizeKeyboardNudge,
|
|
132
|
+
scrollbarSpacerWidth,
|
|
127
133
|
} = derived.resize;
|
|
128
134
|
|
|
129
135
|
const { editing, beginEdit, setDraft, commit, cancel } = useEditingState<TData, TValue>(
|
|
@@ -160,6 +166,7 @@ export const DsTableContextProvider = <TData, TValue>({
|
|
|
160
166
|
onResizeDragStart,
|
|
161
167
|
onResizeReset,
|
|
162
168
|
onResizeKeyboardNudge,
|
|
169
|
+
scrollbarSpacerWidth,
|
|
163
170
|
editing,
|
|
164
171
|
beginEdit,
|
|
165
172
|
setDraft,
|
|
@@ -194,6 +201,7 @@ export const DsTableContextProvider = <TData, TValue>({
|
|
|
194
201
|
onResizeDragStart,
|
|
195
202
|
onResizeReset,
|
|
196
203
|
onResizeKeyboardNudge,
|
|
204
|
+
scrollbarSpacerWidth,
|
|
197
205
|
editing,
|
|
198
206
|
beginEdit,
|
|
199
207
|
setDraft,
|
|
@@ -58,10 +58,7 @@ $bulk-actions-reserved-space: 80px;
|
|
|
58
58
|
thead {
|
|
59
59
|
display: block;
|
|
60
60
|
flex-shrink: 0;
|
|
61
|
-
overflow-y:
|
|
62
|
-
scrollbar-gutter: stable;
|
|
63
|
-
|
|
64
|
-
@include scrollbars.scrollbar-on-hover;
|
|
61
|
+
overflow-y: hidden;
|
|
65
62
|
}
|
|
66
63
|
|
|
67
64
|
tbody {
|
|
@@ -70,14 +67,24 @@ $bulk-actions-reserved-space: 80px;
|
|
|
70
67
|
overflow-x: hidden;
|
|
71
68
|
flex: 1;
|
|
72
69
|
min-height: 0;
|
|
73
|
-
scrollbar-gutter:
|
|
70
|
+
scrollbar-gutter: auto;
|
|
74
71
|
|
|
75
72
|
@include scrollbars.scrollbar-on-hover;
|
|
73
|
+
|
|
74
|
+
&:has(.emptyState) {
|
|
75
|
+
display: flex;
|
|
76
|
+
flex-direction: column;
|
|
77
|
+
}
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
thead tr,
|
|
79
81
|
tbody tr {
|
|
80
82
|
display: flex;
|
|
83
|
+
width: 100%;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
tbody tr {
|
|
87
|
+
padding-inline-end: var(--ds-table-body-scrollbar-compensation, 0px);
|
|
81
88
|
}
|
|
82
89
|
|
|
83
90
|
thead th,
|
|
@@ -109,18 +116,19 @@ $bulk-actions-reserved-space: 80px;
|
|
|
109
116
|
}
|
|
110
117
|
}
|
|
111
118
|
|
|
119
|
+
.emptyStateRow {
|
|
120
|
+
flex: 1;
|
|
121
|
+
align-items: center;
|
|
122
|
+
}
|
|
123
|
+
|
|
112
124
|
.emptyState {
|
|
113
125
|
// colSpan in markup isn't honored by flex row layout, so the cell stretches
|
|
114
|
-
// across the row;
|
|
126
|
+
// across the row; center the Empty state in the remaining body
|
|
115
127
|
flex: 1;
|
|
116
128
|
min-width: 0;
|
|
117
|
-
height: vars.$empty-state-height;
|
|
118
129
|
justify-content: center;
|
|
130
|
+
align-items: center;
|
|
119
131
|
text-align: center;
|
|
120
|
-
|
|
121
|
-
> * {
|
|
122
|
-
flex: 1;
|
|
123
|
-
}
|
|
124
132
|
}
|
|
125
133
|
|
|
126
134
|
.virtualizedContainer {
|
|
@@ -145,20 +153,22 @@ $bulk-actions-reserved-space: 80px;
|
|
|
145
153
|
thead {
|
|
146
154
|
display: block;
|
|
147
155
|
flex-shrink: 0;
|
|
148
|
-
overflow-y:
|
|
149
|
-
scrollbar-gutter: stable;
|
|
150
|
-
|
|
151
|
-
@include scrollbars.scrollbar-on-hover;
|
|
156
|
+
overflow-y: hidden;
|
|
152
157
|
}
|
|
153
158
|
|
|
154
159
|
tbody {
|
|
155
160
|
flex: 1;
|
|
156
161
|
min-height: 0;
|
|
157
|
-
scrollbar-gutter:
|
|
162
|
+
scrollbar-gutter: auto;
|
|
158
163
|
}
|
|
159
164
|
|
|
160
165
|
thead tr {
|
|
161
166
|
display: flex;
|
|
167
|
+
width: 100%;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
tbody tr {
|
|
171
|
+
padding-inline-end: var(--ds-table-body-scrollbar-compensation, 0px);
|
|
162
172
|
}
|
|
163
173
|
|
|
164
174
|
thead th {
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
} from '@tanstack/react-table';
|
|
15
15
|
import classnames from 'classnames';
|
|
16
16
|
import { Table, TableBody, TableCell, TableRow } from './components/core-table';
|
|
17
|
-
import {
|
|
17
|
+
import { DsBulkActions } from '../ds-bulk-actions';
|
|
18
18
|
import { DsTableHeader } from './components/ds-table-header';
|
|
19
19
|
import { DsTableResizeOverlay } from './components/ds-table-resize-overlay';
|
|
20
20
|
import styles from './ds-table.module.scss';
|
|
@@ -26,7 +26,8 @@ import { useColumnResize } from './hooks/use-column-resize';
|
|
|
26
26
|
import { DsTableContextProvider } from './context/ds-table-context';
|
|
27
27
|
import { DsTableBodyVirtualized } from './components/ds-table-body-virtualized';
|
|
28
28
|
import { useColumnGroups } from './grouping';
|
|
29
|
-
import {
|
|
29
|
+
import { DsEmptyState } from '../ds-empty-state';
|
|
30
|
+
import { getUtilityColumnSizing } from './utils/column-size';
|
|
30
31
|
import { createSkeletonRows, getAugmentedColumns, toSkeletonColumns } from './utils/table-columns';
|
|
31
32
|
import { createTableApi } from './utils/table-api';
|
|
32
33
|
import { areBodiesFrozen } from './utils/frozen-body';
|
|
@@ -75,6 +76,9 @@ const DsTable = <TData extends { id: string }, TValue>(props: DsDataTableProps<T
|
|
|
75
76
|
resizableColumns,
|
|
76
77
|
columnSizing,
|
|
77
78
|
onColumnSizingChange,
|
|
79
|
+
selectableColumnWidth,
|
|
80
|
+
expandableColumnWidth,
|
|
81
|
+
reorderableColumnWidth,
|
|
78
82
|
} = tableProps;
|
|
79
83
|
const [data, setData] = React.useState(tableData);
|
|
80
84
|
const [sorting, setSorting] = React.useState<SortingState>([]);
|
|
@@ -155,12 +159,32 @@ const DsTable = <TData extends { id: string }, TValue>(props: DsDataTableProps<T
|
|
|
155
159
|
reorderable,
|
|
156
160
|
virtualized,
|
|
157
161
|
showSelectAllCheckbox,
|
|
162
|
+
selectableColumnWidth,
|
|
163
|
+
expandableColumnWidth,
|
|
164
|
+
reorderableColumnWidth,
|
|
158
165
|
}),
|
|
159
|
-
[
|
|
166
|
+
[
|
|
167
|
+
columnsProp,
|
|
168
|
+
hasSelectColumn,
|
|
169
|
+
hasExpanderColumn,
|
|
170
|
+
reorderable,
|
|
171
|
+
virtualized,
|
|
172
|
+
showSelectAllCheckbox,
|
|
173
|
+
selectableColumnWidth,
|
|
174
|
+
expandableColumnWidth,
|
|
175
|
+
reorderableColumnWidth,
|
|
176
|
+
],
|
|
160
177
|
);
|
|
161
178
|
|
|
162
179
|
const skeletonColumns = useMemo(() => toSkeletonColumns(columns), [columns]);
|
|
163
180
|
const skeletonData = useMemo(() => createSkeletonRows<TData>(), []);
|
|
181
|
+
const utilityColumnSizing = useMemo(() => getUtilityColumnSizing(columns), [columns]);
|
|
182
|
+
const sourceDataLength = (reorderable ? data : tableData).length;
|
|
183
|
+
const inferredEmptyState = useMemo(
|
|
184
|
+
() => <DsEmptyState variant={sourceDataLength === 0 ? 'noData' : 'noMatches'} />,
|
|
185
|
+
[sourceDataLength],
|
|
186
|
+
);
|
|
187
|
+
const resolvedEmptyState = emptyState ?? inferredEmptyState;
|
|
164
188
|
|
|
165
189
|
const resize = useColumnResize({
|
|
166
190
|
enabled: resizableColumns,
|
|
@@ -168,6 +192,8 @@ const DsTable = <TData extends { id: string }, TValue>(props: DsDataTableProps<T
|
|
|
168
192
|
onColumnSizingChange,
|
|
169
193
|
columns,
|
|
170
194
|
columnVisibility,
|
|
195
|
+
overflowKey: (reorderable ? data : tableData).length,
|
|
196
|
+
utilityColumnSizing,
|
|
171
197
|
});
|
|
172
198
|
|
|
173
199
|
const table = useReactTable({
|
|
@@ -238,7 +264,7 @@ const DsTable = <TData extends { id: string }, TValue>(props: DsDataTableProps<T
|
|
|
238
264
|
{virtualized ? (
|
|
239
265
|
<MemoizedDsTableBodyVirtualized
|
|
240
266
|
table={table}
|
|
241
|
-
emptyState={
|
|
267
|
+
emptyState={resolvedEmptyState}
|
|
242
268
|
estimateSize={virtualizedOptions?.estimateSize || ROW_SIZE_HEIGHT_MAP[rowSize]}
|
|
243
269
|
overscan={virtualizedOptions?.overscan}
|
|
244
270
|
onScroll={onScroll}
|
|
@@ -249,7 +275,7 @@ const DsTable = <TData extends { id: string }, TValue>(props: DsDataTableProps<T
|
|
|
249
275
|
<MemoizedDsTableRowsBody
|
|
250
276
|
table={table}
|
|
251
277
|
rowSelection={rowSelection}
|
|
252
|
-
emptyState={
|
|
278
|
+
emptyState={resolvedEmptyState}
|
|
253
279
|
SortableWrapper={SortableWrapper}
|
|
254
280
|
/>
|
|
255
281
|
)}
|
|
@@ -260,14 +286,20 @@ const DsTable = <TData extends { id: string }, TValue>(props: DsDataTableProps<T
|
|
|
260
286
|
) : null}
|
|
261
287
|
</div>
|
|
262
288
|
{selectable && actions.length > 0 && (
|
|
263
|
-
<
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
...action,
|
|
267
|
-
onClick: () => action.onClick(selectedRows),
|
|
268
|
-
}))}
|
|
289
|
+
<DsBulkActions
|
|
290
|
+
placement="floating"
|
|
291
|
+
selectedCount={selectedRows.length}
|
|
269
292
|
onClearSelection={table.resetRowSelection}
|
|
270
|
-
|
|
293
|
+
>
|
|
294
|
+
{actions.map((action, index) => (
|
|
295
|
+
<DsBulkActions.Item
|
|
296
|
+
key={`${action.label}-${String(index)}`}
|
|
297
|
+
icon={action.icon}
|
|
298
|
+
label={action.label}
|
|
299
|
+
onClick={() => action.onClick(selectedRows)}
|
|
300
|
+
/>
|
|
301
|
+
))}
|
|
302
|
+
</DsBulkActions>
|
|
271
303
|
)}
|
|
272
304
|
</div>
|
|
273
305
|
</DsTableContextProvider>
|
|
@@ -296,9 +328,9 @@ const DsTableRowsBody = <TData extends { id: string }>({
|
|
|
296
328
|
{rows.length ? (
|
|
297
329
|
rows.map((row) => <DsTableRow key={row.id} row={row} isSelected={!!rowSelection[row.id]} />)
|
|
298
330
|
) : (
|
|
299
|
-
<TableRow>
|
|
331
|
+
<TableRow className={styles.emptyStateRow}>
|
|
300
332
|
<TableCell colSpan={columnCount} className={styles.emptyState}>
|
|
301
|
-
{emptyState
|
|
333
|
+
{emptyState}
|
|
302
334
|
</TableCell>
|
|
303
335
|
</TableRow>
|
|
304
336
|
)}
|
|
@@ -296,7 +296,9 @@ export interface DsDataTableProps<TData, TValue> {
|
|
|
296
296
|
activeRowId?: string | null;
|
|
297
297
|
|
|
298
298
|
/**
|
|
299
|
-
* Empty state
|
|
299
|
+
* Replaces the inferred **Empty state**. When omitted, the table renders
|
|
300
|
+
* `DsEmptyState` as `noData` if `data` is empty, or `noMatches` if `data`
|
|
301
|
+
* has rows but filters hide all of them.
|
|
300
302
|
*/
|
|
301
303
|
emptyState?: React.ReactNode;
|
|
302
304
|
|
|
@@ -340,14 +342,17 @@ export interface DsDataTableProps<TData, TValue> {
|
|
|
340
342
|
* from {@link onColumnSizingChange}. Pass it (typically on the next mount) to
|
|
341
343
|
* restore widths; columns absent from the map are measured and sized
|
|
342
344
|
* automatically. This seeds widths — live resizing still updates them
|
|
343
|
-
* internally — so it is not a fully controlled value.
|
|
345
|
+
* internally — so it is not a fully controlled value. Ids for the select,
|
|
346
|
+
* expander, and reorder utility columns are ignored; use the matching
|
|
347
|
+
* `*ColumnWidth` props instead.
|
|
344
348
|
*/
|
|
345
349
|
columnSizing?: Record<string, number>;
|
|
346
350
|
|
|
347
351
|
/**
|
|
348
352
|
* Called with the next column id → width (px) map when a resize finishes
|
|
349
353
|
* (drag end, double-click restore, or keyboard nudge). Use this to persist
|
|
350
|
-
* widths across sessions.
|
|
354
|
+
* widths across sessions. Select, expander, and reorder utility columns are
|
|
355
|
+
* omitted from the map.
|
|
351
356
|
*/
|
|
352
357
|
onColumnSizingChange?: (columnSizing: Record<string, number>) => void;
|
|
353
358
|
|
|
@@ -363,6 +368,14 @@ export interface DsDataTableProps<TData, TValue> {
|
|
|
363
368
|
*/
|
|
364
369
|
expandable?: boolean | ((row: TData) => boolean);
|
|
365
370
|
|
|
371
|
+
/**
|
|
372
|
+
* Width in px of the expander utility column. Ignored when `expandable` is
|
|
373
|
+
* off. Non-finite or `<= 0` falls back to the default. The column is not
|
|
374
|
+
* user-resizable. Wins over a `columnSizing` entry for this column.
|
|
375
|
+
* @default 36
|
|
376
|
+
*/
|
|
377
|
+
expandableColumnWidth?: number;
|
|
378
|
+
|
|
366
379
|
/**
|
|
367
380
|
* Function to render the expanded row
|
|
368
381
|
*/
|
|
@@ -394,6 +407,14 @@ export interface DsDataTableProps<TData, TValue> {
|
|
|
394
407
|
*/
|
|
395
408
|
selectable?: boolean | ((rowData: TData) => boolean);
|
|
396
409
|
|
|
410
|
+
/**
|
|
411
|
+
* Width in px of the select utility column. Ignored when `selectable` is
|
|
412
|
+
* off. Non-finite or `<= 0` falls back to the default. The column is not
|
|
413
|
+
* user-resizable. Wins over a `columnSizing` entry for this column.
|
|
414
|
+
* @default 36
|
|
415
|
+
*/
|
|
416
|
+
selectableColumnWidth?: number;
|
|
417
|
+
|
|
397
418
|
/**
|
|
398
419
|
* Whether to show the select/deselect all checkbox in the header
|
|
399
420
|
* @default true
|
|
@@ -474,6 +495,15 @@ export interface DsDataTableProps<TData, TValue> {
|
|
|
474
495
|
*/
|
|
475
496
|
reorderable?: boolean;
|
|
476
497
|
|
|
498
|
+
/**
|
|
499
|
+
* Width in px of the reorder utility column. Ignored when `reorderable` is
|
|
500
|
+
* off or the table is virtualized. Non-finite or `<= 0` falls back to the
|
|
501
|
+
* default. The column is not user-resizable. Wins over a `columnSizing`
|
|
502
|
+
* entry for this column.
|
|
503
|
+
* @default 60
|
|
504
|
+
*/
|
|
505
|
+
reorderableColumnWidth?: number;
|
|
506
|
+
|
|
477
507
|
/**
|
|
478
508
|
* Callback when the order of rows changes via drag & drop
|
|
479
509
|
*/
|