@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
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
$count-size: 60px;
|
|
2
|
+
$action-item-min-width: 64px;
|
|
3
|
+
$action-label-max-width: 84px;
|
|
4
|
+
$divider-height: 40px;
|
|
5
|
+
$bar-gap: 3px;
|
|
6
|
+
$bar-radius: 8px;
|
|
7
|
+
$bar-shadow: 0 3.5px 14px 0 var(--shadow-moderate);
|
|
8
|
+
|
|
9
|
+
.bulkActionsContainer {
|
|
10
|
+
position: relative;
|
|
11
|
+
width: fit-content;
|
|
12
|
+
background-color: var(--color-dap-gray-050);
|
|
13
|
+
border-radius: $bar-radius;
|
|
14
|
+
box-shadow: $bar-shadow;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.floating {
|
|
18
|
+
position: absolute;
|
|
19
|
+
bottom: var(--md);
|
|
20
|
+
left: 50%;
|
|
21
|
+
transform: translateX(-50%);
|
|
22
|
+
z-index: 1;
|
|
23
|
+
animation-duration: 0.3s;
|
|
24
|
+
animation-timing-function: ease-out;
|
|
25
|
+
animation-fill-mode: forwards;
|
|
26
|
+
|
|
27
|
+
&.entering {
|
|
28
|
+
animation-name: slideUpFadeIn;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
&.exiting {
|
|
32
|
+
animation-name: slideDownFadeOut;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.selectedCountContainer {
|
|
37
|
+
display: flex;
|
|
38
|
+
flex-shrink: 0;
|
|
39
|
+
align-items: center;
|
|
40
|
+
justify-content: center;
|
|
41
|
+
width: $count-size;
|
|
42
|
+
height: $count-size;
|
|
43
|
+
padding: var(--3xs);
|
|
44
|
+
background-color: var(--color-dap-blue-600);
|
|
45
|
+
border-radius: $bar-radius 0 0 $bar-radius;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.selectedCountBadge {
|
|
49
|
+
margin: 0;
|
|
50
|
+
color: var(--color-dap-gray-050);
|
|
51
|
+
text-align: center;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.bulkActionsInfo {
|
|
55
|
+
flex-shrink: 0;
|
|
56
|
+
margin: 0;
|
|
57
|
+
padding: 0 var(--xs);
|
|
58
|
+
color: var(--color-dap-gray-600);
|
|
59
|
+
text-wrap: nowrap;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.bulkActionsActions {
|
|
63
|
+
min-width: 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.measurementContainer {
|
|
67
|
+
pointer-events: none;
|
|
68
|
+
position: absolute;
|
|
69
|
+
display: flex;
|
|
70
|
+
align-items: center;
|
|
71
|
+
height: 0;
|
|
72
|
+
overflow: hidden;
|
|
73
|
+
visibility: hidden;
|
|
74
|
+
|
|
75
|
+
> * {
|
|
76
|
+
flex-shrink: 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
* {
|
|
80
|
+
visibility: hidden;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.menuTriggerAnchor {
|
|
85
|
+
display: inline-flex;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.actionItem {
|
|
89
|
+
display: flex;
|
|
90
|
+
flex-shrink: 0;
|
|
91
|
+
align-items: center;
|
|
92
|
+
gap: var(--3xs);
|
|
93
|
+
min-width: $action-item-min-width;
|
|
94
|
+
padding-right: var(--3xs);
|
|
95
|
+
|
|
96
|
+
&[data-item-width='fit-content'],
|
|
97
|
+
&[data-item-width='custom'] {
|
|
98
|
+
min-width: 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
&::before {
|
|
102
|
+
content: '';
|
|
103
|
+
flex-shrink: 0;
|
|
104
|
+
width: 1px;
|
|
105
|
+
height: $divider-height;
|
|
106
|
+
background-color: var(--color-dap-gray-400);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.actionButton {
|
|
111
|
+
display: flex;
|
|
112
|
+
flex-direction: column;
|
|
113
|
+
align-items: center;
|
|
114
|
+
justify-content: center;
|
|
115
|
+
gap: var(--4xs);
|
|
116
|
+
min-width: $action-item-min-width;
|
|
117
|
+
max-width: $action-label-max-width;
|
|
118
|
+
padding: var(--3xs) var(--4xs);
|
|
119
|
+
border: none;
|
|
120
|
+
border-radius: var(--3xs);
|
|
121
|
+
background-color: var(--background);
|
|
122
|
+
color: var(--font-action-secondary);
|
|
123
|
+
cursor: pointer;
|
|
124
|
+
transition:
|
|
125
|
+
background-color 0.2s,
|
|
126
|
+
color 0.2s;
|
|
127
|
+
|
|
128
|
+
&[data-item-width='fit-content'] {
|
|
129
|
+
min-width: 0;
|
|
130
|
+
max-width: none;
|
|
131
|
+
width: fit-content;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
&[data-item-width='custom'] {
|
|
135
|
+
min-width: 0;
|
|
136
|
+
max-width: none;
|
|
137
|
+
width: var(--ds-bulk-actions-item-width);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
&:hover:not(:disabled) {
|
|
141
|
+
background-color: var(--background-action-tertiary-hover);
|
|
142
|
+
color: var(--brand-600);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
&:active:not(:disabled) {
|
|
146
|
+
background-color: var(--background-action-secondary-hover);
|
|
147
|
+
color: var(--font-action-secondary);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
&:disabled {
|
|
151
|
+
background-color: transparent;
|
|
152
|
+
color: var(--font-disabled);
|
|
153
|
+
cursor: not-allowed;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
&:focus {
|
|
157
|
+
outline: none;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
&:focus-visible {
|
|
161
|
+
outline: 2px solid var(--brand-600);
|
|
162
|
+
outline-offset: -2px;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.actionLabel {
|
|
167
|
+
min-width: 0;
|
|
168
|
+
max-width: 100%;
|
|
169
|
+
overflow: hidden;
|
|
170
|
+
text-align: center;
|
|
171
|
+
text-overflow: ellipsis;
|
|
172
|
+
white-space: nowrap;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.dismissButton {
|
|
176
|
+
flex-shrink: 0;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
@keyframes slideUpFadeIn {
|
|
180
|
+
0% {
|
|
181
|
+
opacity: 0;
|
|
182
|
+
transform: translate(-50%, 100%);
|
|
183
|
+
}
|
|
184
|
+
100% {
|
|
185
|
+
opacity: 1;
|
|
186
|
+
transform: translate(-50%, 0);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
@keyframes slideDownFadeOut {
|
|
191
|
+
0% {
|
|
192
|
+
opacity: 1;
|
|
193
|
+
transform: translate(-50%, 0);
|
|
194
|
+
}
|
|
195
|
+
100% {
|
|
196
|
+
opacity: 0;
|
|
197
|
+
transform: translate(-50%, 100%);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { createContext, useContext, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import classnames from 'classnames';
|
|
3
|
+
import styles from './ds-bulk-actions.module.scss';
|
|
4
|
+
import type {
|
|
5
|
+
BulkActionsMenuPlacement,
|
|
6
|
+
DsBulkActionsItemProps,
|
|
7
|
+
DsBulkActionsProps,
|
|
8
|
+
} from './ds-bulk-actions.types';
|
|
9
|
+
import {
|
|
10
|
+
getBulkActionItems,
|
|
11
|
+
isMenuItemProps,
|
|
12
|
+
itemToOverflowEntry,
|
|
13
|
+
resolveItemWidth,
|
|
14
|
+
} from './ds-bulk-actions.utils';
|
|
15
|
+
import { ActionButton } from './components/action-button';
|
|
16
|
+
import { MenuEntries, TooltipMenuTrigger } from './components/menu-entries';
|
|
17
|
+
import { OverflowMeasure, OverflowMore } from './components/overflow';
|
|
18
|
+
import { useBulkActionsOverflow } from './hooks/use-bulk-actions-overflow';
|
|
19
|
+
import { DsButtonV3 } from '../ds-button-v3';
|
|
20
|
+
import { DsDropdownMenu } from '../ds-dropdown-menu';
|
|
21
|
+
import { DsStack } from '../ds-stack';
|
|
22
|
+
import { DsTooltip } from '../ds-tooltip';
|
|
23
|
+
import { DsTypography } from '../ds-typography';
|
|
24
|
+
import { mergeRefs } from '../../utils/merge-refs';
|
|
25
|
+
|
|
26
|
+
const EXIT_ANIMATION_MS = 300;
|
|
27
|
+
|
|
28
|
+
interface BulkActionsContextValue {
|
|
29
|
+
menuPlacement: BulkActionsMenuPlacement;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const BulkActionsContext = createContext<BulkActionsContextValue>({ menuPlacement: 'bottom' });
|
|
33
|
+
|
|
34
|
+
const Item = (props: DsBulkActionsItemProps) => {
|
|
35
|
+
const { className, style, ref, width, icon, label, disabled } = props;
|
|
36
|
+
const { menuPlacement } = useContext(BulkActionsContext);
|
|
37
|
+
const { mode, buttonStyle } = resolveItemWidth(width);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div ref={ref} className={classnames(styles.actionItem, className)} style={style} data-item-width={mode}>
|
|
41
|
+
{isMenuItemProps(props) ? (
|
|
42
|
+
<DsDropdownMenu.Root positioning={{ placement: menuPlacement }}>
|
|
43
|
+
<TooltipMenuTrigger
|
|
44
|
+
icon={icon}
|
|
45
|
+
label={label}
|
|
46
|
+
disabled={disabled}
|
|
47
|
+
itemWidth={mode}
|
|
48
|
+
buttonStyle={buttonStyle}
|
|
49
|
+
/>
|
|
50
|
+
<DsDropdownMenu.Content>
|
|
51
|
+
<MenuEntries entries={props.menu} />
|
|
52
|
+
</DsDropdownMenu.Content>
|
|
53
|
+
</DsDropdownMenu.Root>
|
|
54
|
+
) : (
|
|
55
|
+
<DsTooltip content={label}>
|
|
56
|
+
<ActionButton
|
|
57
|
+
icon={icon}
|
|
58
|
+
label={label}
|
|
59
|
+
onClick={props.onClick}
|
|
60
|
+
disabled={disabled}
|
|
61
|
+
itemWidth={mode}
|
|
62
|
+
style={buttonStyle}
|
|
63
|
+
/>
|
|
64
|
+
</DsTooltip>
|
|
65
|
+
)}
|
|
66
|
+
</div>
|
|
67
|
+
);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Floating or static toolbar for bulk operations on a selection.
|
|
72
|
+
**/
|
|
73
|
+
const DsBulkActions = ({
|
|
74
|
+
selectedCount,
|
|
75
|
+
children,
|
|
76
|
+
onClearSelection,
|
|
77
|
+
placement = 'static',
|
|
78
|
+
menuPlacement: menuPlacementProp,
|
|
79
|
+
locale,
|
|
80
|
+
className,
|
|
81
|
+
style,
|
|
82
|
+
ref,
|
|
83
|
+
}: DsBulkActionsProps) => {
|
|
84
|
+
const [isRendered, setIsRendered] = useState(false);
|
|
85
|
+
const [animationClass, setAnimationClass] = useState('');
|
|
86
|
+
const isFloating = placement === 'floating';
|
|
87
|
+
const menuPlacement = menuPlacementProp ?? (isFloating ? 'top' : 'bottom');
|
|
88
|
+
|
|
89
|
+
const itemsSelectedLabel = locale?.itemsSelectedLabel ?? 'Items selected';
|
|
90
|
+
const clearSelectionLabel = locale?.clearSelectionLabel ?? 'Clear selection';
|
|
91
|
+
const moreActionsLabel = locale?.moreActionsLabel ?? 'More';
|
|
92
|
+
|
|
93
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
94
|
+
const stackRef = useRef<HTMLDivElement>(null);
|
|
95
|
+
const badgeRef = useRef<HTMLDivElement>(null);
|
|
96
|
+
const dismissRef = useRef<HTMLButtonElement>(null);
|
|
97
|
+
const measureRef = useRef<HTMLDivElement>(null);
|
|
98
|
+
const items = getBulkActionItems(children);
|
|
99
|
+
|
|
100
|
+
const { visibleCount, showMore, summaryLabelHidden } = useBulkActionsOverflow({
|
|
101
|
+
active: isRendered,
|
|
102
|
+
itemCount: items.length,
|
|
103
|
+
style,
|
|
104
|
+
containerRef,
|
|
105
|
+
stackRef,
|
|
106
|
+
badgeRef,
|
|
107
|
+
dismissRef,
|
|
108
|
+
measureRef,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
if (selectedCount > 0) {
|
|
113
|
+
if (!isRendered) {
|
|
114
|
+
setIsRendered(true);
|
|
115
|
+
setAnimationClass(isFloating ? styles.entering : '');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (isRendered) {
|
|
122
|
+
if (isFloating) {
|
|
123
|
+
setAnimationClass(styles.exiting);
|
|
124
|
+
const timer = setTimeout(() => {
|
|
125
|
+
setIsRendered(false);
|
|
126
|
+
setAnimationClass('');
|
|
127
|
+
}, EXIT_ANIMATION_MS);
|
|
128
|
+
return () => clearTimeout(timer);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
setIsRendered(false);
|
|
132
|
+
setAnimationClass('');
|
|
133
|
+
}
|
|
134
|
+
}, [selectedCount, isRendered, isFloating]);
|
|
135
|
+
|
|
136
|
+
if (!isRendered) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const clampedVisibleCount = Math.min(visibleCount, items.length);
|
|
141
|
+
const visibleItems = items.slice(0, clampedVisibleCount);
|
|
142
|
+
const overflowEntries = items
|
|
143
|
+
.slice(clampedVisibleCount)
|
|
144
|
+
.map((item, index) => itemToOverflowEntry(item.props, index));
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<BulkActionsContext.Provider value={{ menuPlacement }}>
|
|
148
|
+
<div
|
|
149
|
+
ref={mergeRefs(ref, containerRef)}
|
|
150
|
+
role="toolbar"
|
|
151
|
+
aria-label={itemsSelectedLabel}
|
|
152
|
+
className={classnames(
|
|
153
|
+
styles.bulkActionsContainer,
|
|
154
|
+
isFloating && styles.floating,
|
|
155
|
+
isFloating && animationClass,
|
|
156
|
+
className,
|
|
157
|
+
)}
|
|
158
|
+
style={style}
|
|
159
|
+
>
|
|
160
|
+
<DsStack ref={stackRef} direction="row" alignItems="center" gap="var(--3xs)">
|
|
161
|
+
<div ref={badgeRef} className={styles.selectedCountContainer} aria-live="polite" aria-atomic="true">
|
|
162
|
+
<DsTypography variant="heading1" className={styles.selectedCountBadge}>
|
|
163
|
+
{selectedCount}
|
|
164
|
+
</DsTypography>
|
|
165
|
+
</div>
|
|
166
|
+
|
|
167
|
+
{summaryLabelHidden ? null : (
|
|
168
|
+
<DsTypography variant="body-md-semi-bold" className={styles.bulkActionsInfo}>
|
|
169
|
+
{itemsSelectedLabel}
|
|
170
|
+
</DsTypography>
|
|
171
|
+
)}
|
|
172
|
+
|
|
173
|
+
<DsStack
|
|
174
|
+
direction="row"
|
|
175
|
+
alignItems="center"
|
|
176
|
+
justifyContent="flex-end"
|
|
177
|
+
flex="1 1 auto"
|
|
178
|
+
flexWrap="nowrap"
|
|
179
|
+
className={styles.bulkActionsActions}
|
|
180
|
+
>
|
|
181
|
+
{visibleItems}
|
|
182
|
+
{showMore && overflowEntries.length > 0 ? (
|
|
183
|
+
<OverflowMore
|
|
184
|
+
label={moreActionsLabel}
|
|
185
|
+
menuPlacement={menuPlacement}
|
|
186
|
+
entries={overflowEntries}
|
|
187
|
+
/>
|
|
188
|
+
) : null}
|
|
189
|
+
</DsStack>
|
|
190
|
+
|
|
191
|
+
<DsButtonV3
|
|
192
|
+
ref={dismissRef}
|
|
193
|
+
variant="tertiary"
|
|
194
|
+
size="medium"
|
|
195
|
+
icon="close"
|
|
196
|
+
aria-label={clearSelectionLabel}
|
|
197
|
+
className={styles.dismissButton}
|
|
198
|
+
onClick={onClearSelection}
|
|
199
|
+
/>
|
|
200
|
+
</DsStack>
|
|
201
|
+
|
|
202
|
+
{items.length > 0 ? (
|
|
203
|
+
<OverflowMeasure
|
|
204
|
+
items={items}
|
|
205
|
+
moreActionsLabel={moreActionsLabel}
|
|
206
|
+
itemsSelectedLabel={itemsSelectedLabel}
|
|
207
|
+
measureRef={measureRef}
|
|
208
|
+
/>
|
|
209
|
+
) : null}
|
|
210
|
+
</div>
|
|
211
|
+
</BulkActionsContext.Provider>
|
|
212
|
+
);
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
DsBulkActions.displayName = 'DsBulkActions';
|
|
216
|
+
Item.displayName = 'DsBulkActions.Item';
|
|
217
|
+
|
|
218
|
+
DsBulkActions.Item = Item;
|
|
219
|
+
|
|
220
|
+
export default DsBulkActions;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import type { CSSProperties, ReactNode, Ref } from 'react';
|
|
2
|
+
import type { IconType } from '../ds-icon';
|
|
3
|
+
|
|
4
|
+
export const bulkActionsPlacements = ['static', 'floating'] as const;
|
|
5
|
+
export type BulkActionsPlacement = (typeof bulkActionsPlacements)[number];
|
|
6
|
+
|
|
7
|
+
export const bulkActionsMenuPlacements = ['top', 'bottom'] as const;
|
|
8
|
+
export type BulkActionsMenuPlacement = (typeof bulkActionsMenuPlacements)[number];
|
|
9
|
+
|
|
10
|
+
export const bulkActionsMenuItemVariants = ['default', 'error'] as const;
|
|
11
|
+
export type BulkActionsMenuItemVariant = (typeof bulkActionsMenuItemVariants)[number];
|
|
12
|
+
|
|
13
|
+
export const bulkActionsItemWidthModes = ['fixed', 'fit-content'] as const;
|
|
14
|
+
export type BulkActionsItemWidthMode = (typeof bulkActionsItemWidthModes)[number];
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* `'fixed'` keeps the 64–84px column. `'fit-content'` hugs the label. A number is an exact pixel width and truncates.
|
|
18
|
+
*/
|
|
19
|
+
export type DsBulkActionsItemWidth = BulkActionsItemWidthMode | number;
|
|
20
|
+
|
|
21
|
+
export interface DsBulkActionsLocale {
|
|
22
|
+
/**
|
|
23
|
+
* Label shown next to the selection count
|
|
24
|
+
* @default 'Items selected'
|
|
25
|
+
*/
|
|
26
|
+
itemsSelectedLabel?: string;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Accessible name for the dismiss control
|
|
30
|
+
* @default 'Clear selection'
|
|
31
|
+
*/
|
|
32
|
+
clearSelectionLabel?: string;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Label for the overflow trigger that holds collapsed actions
|
|
36
|
+
* @default 'More'
|
|
37
|
+
*/
|
|
38
|
+
moreActionsLabel?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface DsBulkActionsMenuEntryBase {
|
|
42
|
+
value: string;
|
|
43
|
+
label: string;
|
|
44
|
+
icon?: IconType;
|
|
45
|
+
disabled?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* @default 'default'
|
|
48
|
+
*/
|
|
49
|
+
variant?: BulkActionsMenuItemVariant;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type DsBulkActionsMenuLeafEntry = DsBulkActionsMenuEntryBase & {
|
|
53
|
+
onSelect?: () => void;
|
|
54
|
+
menu?: never;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
type DsBulkActionsMenuBranchEntry = DsBulkActionsMenuEntryBase & {
|
|
58
|
+
/**
|
|
59
|
+
* Nested submenu entries. Mutually exclusive with `onSelect`.
|
|
60
|
+
*/
|
|
61
|
+
menu: DsBulkActionsMenuEntry[];
|
|
62
|
+
onSelect?: never;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export type DsBulkActionsMenuEntry = DsBulkActionsMenuLeafEntry | DsBulkActionsMenuBranchEntry;
|
|
66
|
+
|
|
67
|
+
interface DsBulkActionsItemSharedProps {
|
|
68
|
+
/**
|
|
69
|
+
* Action column width.
|
|
70
|
+
* @default 'fixed'
|
|
71
|
+
*/
|
|
72
|
+
width?: DsBulkActionsItemWidth;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Whether the action is non-interactive
|
|
76
|
+
* @default false
|
|
77
|
+
*/
|
|
78
|
+
disabled?: boolean;
|
|
79
|
+
|
|
80
|
+
className?: string;
|
|
81
|
+
style?: CSSProperties;
|
|
82
|
+
ref?: Ref<HTMLDivElement>;
|
|
83
|
+
children?: never;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
type DsBulkActionsItemClickProps = DsBulkActionsItemSharedProps & {
|
|
87
|
+
/**
|
|
88
|
+
* Icon displayed above the action label
|
|
89
|
+
*/
|
|
90
|
+
icon: IconType;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Action label under the icon. Truncates when `width` is `'fixed'` or a pixel length; full text in tooltip.
|
|
94
|
+
*/
|
|
95
|
+
label: string;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Called when the action is activated. Mutually exclusive with `menu`.
|
|
99
|
+
*/
|
|
100
|
+
onClick: () => void;
|
|
101
|
+
|
|
102
|
+
menu?: never;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
type DsBulkActionsItemMenuProps = DsBulkActionsItemSharedProps & {
|
|
106
|
+
/**
|
|
107
|
+
* Icon displayed above the action label
|
|
108
|
+
*/
|
|
109
|
+
icon: IconType;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Action label under the icon. Truncates when `width` is `'fixed'` or a pixel length; full text in tooltip.
|
|
113
|
+
*/
|
|
114
|
+
label: string;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Declarative menu shown from this action. Mutually exclusive with `onClick`.
|
|
118
|
+
*/
|
|
119
|
+
menu: DsBulkActionsMenuEntry[];
|
|
120
|
+
|
|
121
|
+
onClick?: never;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Slot in the bulk-actions toolbar. `onClick` and `menu` are mutually exclusive.
|
|
126
|
+
*/
|
|
127
|
+
export type DsBulkActionsItemProps = DsBulkActionsItemClickProps | DsBulkActionsItemMenuProps;
|
|
128
|
+
|
|
129
|
+
export interface DsBulkActionsProps {
|
|
130
|
+
/**
|
|
131
|
+
* Number of selected items. The bar mounts at 1+ and unmounts when cleared to 0.
|
|
132
|
+
*/
|
|
133
|
+
selectedCount: number;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Action slots rendered between the selection summary and the dismiss control
|
|
137
|
+
*/
|
|
138
|
+
children?: ReactNode;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Called when the dismiss control is activated; should clear the selection
|
|
142
|
+
*/
|
|
143
|
+
onClearSelection: () => void;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Placement of the toolbar. `floating` anchors to the bottom center of a positioned
|
|
147
|
+
* ancestor; `static` leaves placement to the consumer via `className` / `style`.
|
|
148
|
+
*
|
|
149
|
+
* Action overflow ("More") only activates when the toolbar width is bounded via
|
|
150
|
+
* `style.width`, `style.maxWidth`, or a CSS `max-width`; a bare `width` set through
|
|
151
|
+
* `className` is not detected (the default `fit-content` width is indistinguishable).
|
|
152
|
+
* @default 'static'
|
|
153
|
+
*/
|
|
154
|
+
placement?: BulkActionsPlacement;
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Flyout direction for `menu` items and the overflow More menu.
|
|
158
|
+
* @default 'top' when `placement="floating"`, otherwise `'bottom'`
|
|
159
|
+
*/
|
|
160
|
+
menuPlacement?: BulkActionsMenuPlacement;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Localized strings for user-facing copy
|
|
164
|
+
*/
|
|
165
|
+
locale?: DsBulkActionsLocale;
|
|
166
|
+
|
|
167
|
+
className?: string;
|
|
168
|
+
style?: CSSProperties;
|
|
169
|
+
ref?: Ref<HTMLDivElement>;
|
|
170
|
+
}
|