@drivenets/design-system 0.18.1 → 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 +20 -0
- package/dist/index.cjs +17138 -12075
- package/dist/index.d.cts +783 -238
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +783 -238
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17123 -12076
- package/dist/index.js.map +1 -1
- package/dist/index.min.css +1 -1
- package/package.json +15 -15
- 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-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
|
@@ -13,8 +13,13 @@ import {
|
|
|
13
13
|
getResizableColumnStyle,
|
|
14
14
|
getResizableHeaderStyle,
|
|
15
15
|
getResizeOriginSize,
|
|
16
|
+
getUtilityColumnSizing,
|
|
17
|
+
growFillLeavesToContainer,
|
|
16
18
|
isExplicitColumnWidth,
|
|
17
19
|
omitBuiltinColumnSizing,
|
|
20
|
+
resolveUtilityColumnWidth,
|
|
21
|
+
shiftColumnTrack,
|
|
22
|
+
withUtilityColumnSizing,
|
|
18
23
|
} from './column-size';
|
|
19
24
|
import {
|
|
20
25
|
EXPANDER_COLUMN_ID,
|
|
@@ -179,6 +184,115 @@ describe('collectMissingLeafSizing', () => {
|
|
|
179
184
|
it('returns an empty map when every measured id already has a sizing entry', () => {
|
|
180
185
|
expect(collectMissingLeafSizing({ a: 100 }, { a: 90 })).toEqual({});
|
|
181
186
|
});
|
|
187
|
+
|
|
188
|
+
it('reconciles independent rounding so seeded widths match the measured total', () => {
|
|
189
|
+
const next = collectMissingLeafSizing({ a: 500.6, b: 500.6 }, {});
|
|
190
|
+
|
|
191
|
+
expect(next).toEqual({ a: 501, b: 500 });
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('absorbs rounding drift into missing ids and leaves existing widths unchanged', () => {
|
|
195
|
+
expect(collectMissingLeafSizing({ a: 500.6, b: 500.6 }, { b: 501 }, 1001)).toEqual({ a: 500 });
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('does not snap seeded widths to the container when measured columns overflow it', () => {
|
|
199
|
+
expect(collectMissingLeafSizing({ a: 1000, b: 1000 }, {}, 1116)).toEqual({ a: 1000, b: 1000 });
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('snaps a 1px measured overflow to the container width', () => {
|
|
203
|
+
const next = collectMissingLeafSizing({ a: 558.5, b: 558.5 }, {}, 1116);
|
|
204
|
+
const total = Object.values(next).reduce((sum, width) => sum + width, 0);
|
|
205
|
+
|
|
206
|
+
expect(total).toBe(1116);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('distributes container underflow across fill leaves by their measured share', () => {
|
|
210
|
+
const next = collectMissingLeafSizing({ a: 200, b: 200 }, {}, 1200, ['a', 'b']);
|
|
211
|
+
|
|
212
|
+
expect(next).toEqual({ a: 600, b: 600 });
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('grows only fill leaves when the container is wider than the measured total', () => {
|
|
216
|
+
const next = collectMissingLeafSizing({ a: 200, b: 200, c: 200 }, {}, 1200, ['b', 'c']);
|
|
217
|
+
|
|
218
|
+
expect(next).toEqual({ a: 200, b: 500, c: 500 });
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
describe('growFillLeavesToContainer', () => {
|
|
223
|
+
it('moves leftover space onto uncapped fill leaves after a sibling hits maxSize', () => {
|
|
224
|
+
const next = growFillLeavesToContainer(
|
|
225
|
+
{ a: 280, b: 360, c: 360 },
|
|
226
|
+
{},
|
|
227
|
+
['a', 'b', 'c'],
|
|
228
|
+
1200,
|
|
229
|
+
['a', 'b', 'c'],
|
|
230
|
+
[
|
|
231
|
+
{ id: 'a', columnDef: { maxSize: 280 } },
|
|
232
|
+
{ id: 'b', columnDef: {} },
|
|
233
|
+
{ id: 'c', columnDef: {} },
|
|
234
|
+
],
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
expect(next.a).toBe(280);
|
|
238
|
+
expect(next.b).toBeGreaterThan(360);
|
|
239
|
+
expect(next.c).toBeGreaterThan(360);
|
|
240
|
+
expect((next.a ?? 0) + (next.b ?? 0) + (next.c ?? 0)).toBe(1200);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it('does not grow an explicit leaf when filling leftover space', () => {
|
|
244
|
+
const next = growFillLeavesToContainer(
|
|
245
|
+
{ a: 280, b: 360, c: 360 },
|
|
246
|
+
{},
|
|
247
|
+
['a', 'b', 'c'],
|
|
248
|
+
1200,
|
|
249
|
+
['b', 'c'],
|
|
250
|
+
[
|
|
251
|
+
{ id: 'a', columnDef: { maxSize: 280 } },
|
|
252
|
+
{ id: 'b', columnDef: {} },
|
|
253
|
+
{ id: 'c', columnDef: {} },
|
|
254
|
+
],
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
expect(next).toEqual({ a: 280, b: 460, c: 460 });
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
describe('shiftColumnTrack', () => {
|
|
262
|
+
const bounds = [
|
|
263
|
+
{ id: 'a', columnDef: {} },
|
|
264
|
+
{ id: 'b', columnDef: {} },
|
|
265
|
+
];
|
|
266
|
+
|
|
267
|
+
it('returns the same map when delta is 0', () => {
|
|
268
|
+
const sizing = { a: 200, b: 200 };
|
|
269
|
+
|
|
270
|
+
expect(shiftColumnTrack(sizing, ['a', 'b'], 0, bounds)).toBe(sizing);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('shrinks from the last leaf when the spacer appears', () => {
|
|
274
|
+
const next = shiftColumnTrack({ a: 500, b: 500 }, ['a', 'b'], -10, bounds);
|
|
275
|
+
|
|
276
|
+
expect(next.a).toBe(500);
|
|
277
|
+
expect(next.b).toBe(490);
|
|
278
|
+
expect((next.a ?? 0) + (next.b ?? 0)).toBe(990);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('grows leaves when the spacer disappears', () => {
|
|
282
|
+
const next = shiftColumnTrack({ a: 500, b: 490 }, ['a', 'b'], 10, bounds);
|
|
283
|
+
|
|
284
|
+
expect((next.a ?? 0) + (next.b ?? 0)).toBe(1000);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it('does not shrink a leaf below minSize', () => {
|
|
288
|
+
const next = shiftColumnTrack({ a: 200, b: 52 }, ['a', 'b'], -10, [
|
|
289
|
+
{ id: 'a', columnDef: {} },
|
|
290
|
+
{ id: 'b', columnDef: { minSize: 52 } },
|
|
291
|
+
]);
|
|
292
|
+
|
|
293
|
+
expect(next.b).toBe(52);
|
|
294
|
+
expect(next.a).toBe(190);
|
|
295
|
+
});
|
|
182
296
|
});
|
|
183
297
|
|
|
184
298
|
describe('omitBuiltinColumnSizing', () => {
|
|
@@ -211,3 +325,46 @@ describe('omitBuiltinColumnSizing', () => {
|
|
|
211
325
|
expect(next).not.toBe(sizing);
|
|
212
326
|
});
|
|
213
327
|
});
|
|
328
|
+
|
|
329
|
+
describe('resolveUtilityColumnWidth', () => {
|
|
330
|
+
it('returns the fallback when the width is omitted, non-finite, or not positive', () => {
|
|
331
|
+
expect(resolveUtilityColumnWidth(undefined, 36)).toBe(36);
|
|
332
|
+
expect(resolveUtilityColumnWidth(0, 36)).toBe(36);
|
|
333
|
+
expect(resolveUtilityColumnWidth(-8, 36)).toBe(36);
|
|
334
|
+
expect(resolveUtilityColumnWidth(Number.NaN, 36)).toBe(36);
|
|
335
|
+
expect(resolveUtilityColumnWidth(Number.POSITIVE_INFINITY, 36)).toBe(36);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it('returns a positive finite width as-is', () => {
|
|
339
|
+
expect(resolveUtilityColumnWidth(48, 36)).toBe(48);
|
|
340
|
+
expect(resolveUtilityColumnWidth(1, 36)).toBe(1);
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
describe('withUtilityColumnSizing', () => {
|
|
345
|
+
it('strips inbound utility ids and overlays the authored widths', () => {
|
|
346
|
+
expect(
|
|
347
|
+
withUtilityColumnSizing(
|
|
348
|
+
{ [SELECT_COLUMN_ID]: 80, firstName: 200 },
|
|
349
|
+
{ [SELECT_COLUMN_ID]: 48, [EXPANDER_COLUMN_ID]: 40 },
|
|
350
|
+
),
|
|
351
|
+
).toEqual({ firstName: 200, [SELECT_COLUMN_ID]: 48, [EXPANDER_COLUMN_ID]: 40 });
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
describe('getUtilityColumnSizing', () => {
|
|
356
|
+
it('collects size entries for injected utility leaves only', () => {
|
|
357
|
+
expect(
|
|
358
|
+
getUtilityColumnSizing([
|
|
359
|
+
{ id: REORDER_COLUMN_ID, size: 80 },
|
|
360
|
+
{ id: EXPANDER_COLUMN_ID, size: 40 },
|
|
361
|
+
{ id: SELECT_COLUMN_ID, size: 48 },
|
|
362
|
+
{ id: 'firstName', size: 200 },
|
|
363
|
+
]),
|
|
364
|
+
).toEqual({
|
|
365
|
+
[REORDER_COLUMN_ID]: 80,
|
|
366
|
+
[EXPANDER_COLUMN_ID]: 40,
|
|
367
|
+
[SELECT_COLUMN_ID]: 48,
|
|
368
|
+
});
|
|
369
|
+
});
|
|
370
|
+
});
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Default text for empty table state
|
|
3
|
-
*/
|
|
4
|
-
export const EMPTY_TABLE_STATE_TEXT = 'No results.';
|
|
5
|
-
|
|
6
1
|
/**
|
|
7
2
|
* Column id used for the synthetic expander column injected when `expandable` is set.
|
|
8
3
|
*/
|
|
@@ -55,6 +50,19 @@ export const SKELETON_ROW_COUNT = 5;
|
|
|
55
50
|
*/
|
|
56
51
|
export const RESIZE_MIN_COLUMN_WIDTH = 52;
|
|
57
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Pixel width of the full-height resize overlay divider. Must match
|
|
55
|
+
* `$resize-divider-width` in `styles/_variables.scss`.
|
|
56
|
+
*/
|
|
57
|
+
export const RESIZE_DIVIDER_WIDTH = 2;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Rest width of the header **Scrollbar spacer** when the body overflows
|
|
61
|
+
* vertically. Must match `$scrollbar-default-size` in `styles/_scrollbars.scss`.
|
|
62
|
+
* Hover (12px) is intentionally not tracked.
|
|
63
|
+
*/
|
|
64
|
+
export const SCROLLBAR_SPACER_WIDTH = 10;
|
|
65
|
+
|
|
58
66
|
/**
|
|
59
67
|
* Width change (in px) applied per Arrow key press when a resize handle is
|
|
60
68
|
* focused.
|
|
@@ -3,6 +3,7 @@ import { DsSkeletonText } from '../../ds-skeleton';
|
|
|
3
3
|
import { DsTableHeaderSelectableCell } from '../components/ds-table-header-selectable-cell';
|
|
4
4
|
import { DsTableRowExpandableCell } from '../components/ds-table-row-expandable-cell';
|
|
5
5
|
import { DsTableRowSelectableCell } from '../components/ds-table-row-selectable-cell';
|
|
6
|
+
import { resolveUtilityColumnWidth } from './column-size';
|
|
6
7
|
import {
|
|
7
8
|
EXPANDER_COLUMN_ID,
|
|
8
9
|
EXPANDER_COLUMN_WIDTH,
|
|
@@ -19,6 +20,9 @@ export type GetAugmentedColumnsOptions = {
|
|
|
19
20
|
reorderable: boolean;
|
|
20
21
|
virtualized: boolean;
|
|
21
22
|
showSelectAllCheckbox: boolean;
|
|
23
|
+
selectableColumnWidth?: number;
|
|
24
|
+
expandableColumnWidth?: number;
|
|
25
|
+
reorderableColumnWidth?: number;
|
|
22
26
|
};
|
|
23
27
|
|
|
24
28
|
const EXPLICIT_SIZE_META = { hasExplicitSize: true } as const;
|
|
@@ -41,6 +45,13 @@ const stampExplicitSize = <TData, TValue>(columns: ColumnDef<TData, TValue>[]):
|
|
|
41
45
|
return { ...column, meta: { ...column.meta, ...EXPLICIT_SIZE_META } };
|
|
42
46
|
});
|
|
43
47
|
|
|
48
|
+
/** Pin min/max so the table-wide resize `minSize` cannot stretch this column. */
|
|
49
|
+
const pinUtilityColumnSize = (width: number) => ({
|
|
50
|
+
size: width,
|
|
51
|
+
minSize: width,
|
|
52
|
+
maxSize: width,
|
|
53
|
+
});
|
|
54
|
+
|
|
44
55
|
/**
|
|
45
56
|
* Prepends the builtin select / expander / reorder columns when those features
|
|
46
57
|
* are on. Reorder is omitted for virtualized tables. Unshift order yields
|
|
@@ -48,19 +59,24 @@ const stampExplicitSize = <TData, TValue>(columns: ColumnDef<TData, TValue>[]):
|
|
|
48
59
|
*/
|
|
49
60
|
export const getAugmentedColumns = <TData, TValue>(
|
|
50
61
|
columns: ColumnDef<TData, TValue>[],
|
|
51
|
-
{
|
|
62
|
+
{
|
|
63
|
+
selectable,
|
|
64
|
+
expandable,
|
|
65
|
+
reorderable,
|
|
66
|
+
virtualized,
|
|
67
|
+
showSelectAllCheckbox,
|
|
68
|
+
selectableColumnWidth,
|
|
69
|
+
expandableColumnWidth,
|
|
70
|
+
reorderableColumnWidth,
|
|
71
|
+
}: GetAugmentedColumnsOptions,
|
|
52
72
|
): ColumnDef<TData, TValue>[] => {
|
|
53
73
|
const augmentedColumns: ColumnDef<TData, TValue>[] = stampExplicitSize(columns);
|
|
54
74
|
|
|
55
75
|
if (selectable) {
|
|
76
|
+
const width = resolveUtilityColumnWidth(selectableColumnWidth, SELECT_COLUMN_WIDTH);
|
|
56
77
|
augmentedColumns.unshift({
|
|
57
78
|
id: SELECT_COLUMN_ID,
|
|
58
|
-
|
|
59
|
-
// Pin min/max to the fixed width: `enableResizing: false` blocks the
|
|
60
|
-
// handle but not the table-wide resize `minSize`, which would otherwise
|
|
61
|
-
// stretch this column.
|
|
62
|
-
minSize: SELECT_COLUMN_WIDTH,
|
|
63
|
-
maxSize: SELECT_COLUMN_WIDTH,
|
|
79
|
+
...pinUtilityColumnSize(width),
|
|
64
80
|
enableSorting: false,
|
|
65
81
|
enableResizing: false,
|
|
66
82
|
meta: EXPLICIT_SIZE_META,
|
|
@@ -70,11 +86,10 @@ export const getAugmentedColumns = <TData, TValue>(
|
|
|
70
86
|
}
|
|
71
87
|
|
|
72
88
|
if (expandable) {
|
|
89
|
+
const width = resolveUtilityColumnWidth(expandableColumnWidth, EXPANDER_COLUMN_WIDTH);
|
|
73
90
|
augmentedColumns.unshift({
|
|
74
91
|
id: EXPANDER_COLUMN_ID,
|
|
75
|
-
|
|
76
|
-
minSize: EXPANDER_COLUMN_WIDTH,
|
|
77
|
-
maxSize: EXPANDER_COLUMN_WIDTH,
|
|
92
|
+
...pinUtilityColumnSize(width),
|
|
78
93
|
enableSorting: false,
|
|
79
94
|
enableResizing: false,
|
|
80
95
|
meta: EXPLICIT_SIZE_META,
|
|
@@ -84,13 +99,12 @@ export const getAugmentedColumns = <TData, TValue>(
|
|
|
84
99
|
}
|
|
85
100
|
|
|
86
101
|
if (reorderable && !virtualized) {
|
|
102
|
+
const width = resolveUtilityColumnWidth(reorderableColumnWidth, REORDER_COLUMN_WIDTH);
|
|
87
103
|
// Cell is rendered inline by DsTableRow when it encounters REORDER_COLUMN_ID,
|
|
88
104
|
// since the drag handle needs row-level useSortable state.
|
|
89
105
|
augmentedColumns.unshift({
|
|
90
106
|
id: REORDER_COLUMN_ID,
|
|
91
|
-
|
|
92
|
-
minSize: REORDER_COLUMN_WIDTH,
|
|
93
|
-
maxSize: REORDER_COLUMN_WIDTH,
|
|
107
|
+
...pinUtilityColumnSize(width),
|
|
94
108
|
enableSorting: false,
|
|
95
109
|
enableResizing: false,
|
|
96
110
|
meta: EXPLICIT_SIZE_META,
|
|
@@ -100,6 +100,50 @@ describe('getAugmentedColumns', () => {
|
|
|
100
100
|
}
|
|
101
101
|
});
|
|
102
102
|
|
|
103
|
+
it('pins custom utility column widths and ignores them when the feature is off', () => {
|
|
104
|
+
const columns = getAugmentedColumns([nameColumn], {
|
|
105
|
+
...noFeatures,
|
|
106
|
+
selectable: true,
|
|
107
|
+
expandable: true,
|
|
108
|
+
reorderable: true,
|
|
109
|
+
selectableColumnWidth: 48,
|
|
110
|
+
expandableColumnWidth: 40,
|
|
111
|
+
reorderableColumnWidth: 80,
|
|
112
|
+
});
|
|
113
|
+
const boundsById = new Map(columns.map((column) => [column.id, column]));
|
|
114
|
+
|
|
115
|
+
expect(boundsById.get(SELECT_COLUMN_ID)?.size).toBe(48);
|
|
116
|
+
expect(boundsById.get(SELECT_COLUMN_ID)?.minSize).toBe(48);
|
|
117
|
+
expect(boundsById.get(SELECT_COLUMN_ID)?.maxSize).toBe(48);
|
|
118
|
+
expect(boundsById.get(EXPANDER_COLUMN_ID)?.size).toBe(40);
|
|
119
|
+
expect(boundsById.get(EXPANDER_COLUMN_ID)?.minSize).toBe(40);
|
|
120
|
+
expect(boundsById.get(EXPANDER_COLUMN_ID)?.maxSize).toBe(40);
|
|
121
|
+
expect(boundsById.get(REORDER_COLUMN_ID)?.size).toBe(80);
|
|
122
|
+
expect(boundsById.get(REORDER_COLUMN_ID)?.minSize).toBe(80);
|
|
123
|
+
expect(boundsById.get(REORDER_COLUMN_ID)?.maxSize).toBe(80);
|
|
124
|
+
|
|
125
|
+
expect(
|
|
126
|
+
columnIds(getAugmentedColumns([nameColumn], { ...noFeatures, selectableColumnWidth: 48 })),
|
|
127
|
+
).toEqual(['name']);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('falls back to the default width when the custom width is invalid', () => {
|
|
131
|
+
const columns = getAugmentedColumns([nameColumn], {
|
|
132
|
+
...noFeatures,
|
|
133
|
+
selectable: true,
|
|
134
|
+
expandable: true,
|
|
135
|
+
reorderable: true,
|
|
136
|
+
selectableColumnWidth: 0,
|
|
137
|
+
expandableColumnWidth: Number.NaN,
|
|
138
|
+
reorderableColumnWidth: -10,
|
|
139
|
+
});
|
|
140
|
+
const boundsById = new Map(columns.map((column) => [column.id, column]));
|
|
141
|
+
|
|
142
|
+
expect(boundsById.get(SELECT_COLUMN_ID)?.size).toBe(SELECT_COLUMN_WIDTH);
|
|
143
|
+
expect(boundsById.get(EXPANDER_COLUMN_ID)?.size).toBe(EXPANDER_COLUMN_WIDTH);
|
|
144
|
+
expect(boundsById.get(REORDER_COLUMN_ID)?.size).toBe(REORDER_COLUMN_WIDTH);
|
|
145
|
+
});
|
|
146
|
+
|
|
103
147
|
it('stamps hasExplicitSize on authored leaves and builtins, not on unsized leaves', () => {
|
|
104
148
|
const columns = getAugmentedColumns(
|
|
105
149
|
[
|
|
@@ -144,6 +144,24 @@
|
|
|
144
144
|
pointer-events: none;
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
+
// Overlay the native input over the control so `getByRole('checkbox')` clicks
|
|
148
|
+
// land on a real interactive surface. Ark applies `visuallyHiddenStyle` inline
|
|
149
|
+
// (1x1, clipped, off-screen) which Playwright refuses to click; `!important`
|
|
150
|
+
// is required to beat inline-style specificity.
|
|
151
|
+
.hiddenInput {
|
|
152
|
+
position: absolute !important;
|
|
153
|
+
inset-block-start: 0 !important;
|
|
154
|
+
inset-inline-start: 0 !important;
|
|
155
|
+
width: calc(var(--switch-track-width) + var(--thumb-gap) * 2) !important;
|
|
156
|
+
height: calc(var(--thumb-size) + var(--thumb-gap) * 2) !important;
|
|
157
|
+
margin: 0 !important;
|
|
158
|
+
padding: 0 !important;
|
|
159
|
+
clip: auto !important;
|
|
160
|
+
overflow: visible !important;
|
|
161
|
+
opacity: 0 !important;
|
|
162
|
+
cursor: pointer !important;
|
|
163
|
+
}
|
|
164
|
+
|
|
147
165
|
.iconCheck {
|
|
148
166
|
left: var(--icon-spacing);
|
|
149
167
|
}
|
|
@@ -58,19 +58,21 @@ const DsToggle = ({
|
|
|
58
58
|
<DsIcon icon="close" size={iconSize} className={closeIconClass} />
|
|
59
59
|
</Switch.Control>
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
{labelInfo}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
61
|
+
<Switch.Label>
|
|
62
|
+
{label ? (
|
|
63
|
+
<>
|
|
64
|
+
<DsTypography variant={isSmall ? 'body-xs-md' : 'body-sm-md'}>{label}</DsTypography>
|
|
65
|
+
{!!labelInfo && (
|
|
66
|
+
<DsTypography variant="body-xs-reg" className={styles.labelInfo}>
|
|
67
|
+
{labelInfo}
|
|
68
|
+
</DsTypography>
|
|
69
|
+
)}
|
|
70
|
+
</>
|
|
71
|
+
) : (
|
|
72
|
+
children
|
|
73
|
+
)}
|
|
74
|
+
</Switch.Label>
|
|
75
|
+
<Switch.HiddenInput className={styles.hiddenInput} />
|
|
74
76
|
</Switch.Root>
|
|
75
77
|
);
|
|
76
78
|
};
|
|
@@ -14,6 +14,9 @@ const DsTooltip: FC<DsTooltipProps> = ({
|
|
|
14
14
|
children,
|
|
15
15
|
placement = 'top',
|
|
16
16
|
disabled = false,
|
|
17
|
+
interactive = false,
|
|
18
|
+
openDelay = OPEN_DELAY_MS,
|
|
19
|
+
closeDelay = CLOSE_DELAY_MS,
|
|
17
20
|
getAnchorRect,
|
|
18
21
|
slotProps,
|
|
19
22
|
}) => {
|
|
@@ -23,8 +26,9 @@ const DsTooltip: FC<DsTooltipProps> = ({
|
|
|
23
26
|
|
|
24
27
|
return (
|
|
25
28
|
<Tooltip.Root
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
interactive={interactive}
|
|
30
|
+
openDelay={openDelay}
|
|
31
|
+
closeDelay={closeDelay}
|
|
28
32
|
disabled={disabled}
|
|
29
33
|
positioning={{ placement, gutter: TOOLTIP_GUTTER_PX, getAnchorRect: getAnchorRect ?? undefined }}
|
|
30
34
|
lazyMount
|
|
@@ -44,6 +44,23 @@ export interface DsTooltipProps {
|
|
|
44
44
|
* When true the trigger renders but the tooltip never opens.
|
|
45
45
|
*/
|
|
46
46
|
disabled?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* When true, content is pointer-reachable and the tooltip stays open while the
|
|
49
|
+
* pointer is over it. Pair with a non-zero `closeDelay` (e.g. 150) so the pointer
|
|
50
|
+
* can travel from the trigger onto the content; `0` can lose that handoff.
|
|
51
|
+
* @default false
|
|
52
|
+
*/
|
|
53
|
+
interactive?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Milliseconds after pointer enter or focus before the tooltip opens.
|
|
56
|
+
* @default 200
|
|
57
|
+
*/
|
|
58
|
+
openDelay?: number;
|
|
59
|
+
/**
|
|
60
|
+
* Milliseconds after pointer leave before the tooltip closes.
|
|
61
|
+
* @default 0
|
|
62
|
+
*/
|
|
63
|
+
closeDelay?: number;
|
|
47
64
|
/**
|
|
48
65
|
* Anchors the tooltip to a virtual rect instead of the trigger, re-evaluated on
|
|
49
66
|
* each reposition. Return `null` to fall back to the trigger.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=9543-40942
|
|
2
|
+
// source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-top-bar-navigation
|
|
3
|
+
// component=DsTopBarNavigation
|
|
4
|
+
//
|
|
5
|
+
// `DsTopBarNavigationV1` maps to the `DsTopBarNavigation` compound component. Figma models the
|
|
6
|
+
// bar as a fixed 920px left frame with an absolutely-positioned breadcrumb; in code the zones
|
|
7
|
+
// are flex (`.Logo` fixed-basis, `.Breadcrumb` shrinkable, `.Center` reserved, `.Actions`
|
|
8
|
+
// pinned right), so none of that geometry maps to props.
|
|
9
|
+
//
|
|
10
|
+
// The brand glyph and wordmark are consumer slots — no brand asset ships with the design
|
|
11
|
+
// system — so they are emitted as placeholders. Figma's `DsBotButtonV1` maps to `DsBotButton`,
|
|
12
|
+
// which is connected separately in `ds-bot-button/ds-bot-button.figma.ts`.
|
|
13
|
+
import figma from 'figma';
|
|
14
|
+
|
|
15
|
+
export default {
|
|
16
|
+
example: figma.code`<DsTopBarNavigation>
|
|
17
|
+
<DsTopBarNavigation.Logo logo={<img src="/brand-mark.svg" alt="" />} wordmark="DAP" href="/" onAppsClick={() => {}} />
|
|
18
|
+
<DsTopBarNavigation.Breadcrumb>
|
|
19
|
+
<DsBreadcrumb items={[]} />
|
|
20
|
+
</DsTopBarNavigation.Breadcrumb>
|
|
21
|
+
<DsTopBarNavigation.Center />
|
|
22
|
+
<DsTopBarNavigation.Actions>
|
|
23
|
+
<DsTopBarNavigation.Notifications count={13} onClick={() => {}} />
|
|
24
|
+
<DsBotButton />
|
|
25
|
+
<DsTopBarNavigation.UserMenu name="Full Name">
|
|
26
|
+
<DsDropdownMenu.Item value="profile">Profile</DsDropdownMenu.Item>
|
|
27
|
+
</DsTopBarNavigation.UserMenu>
|
|
28
|
+
</DsTopBarNavigation.Actions>
|
|
29
|
+
</DsTopBarNavigation>`,
|
|
30
|
+
imports: [
|
|
31
|
+
"import { DsTopBarNavigation, DsBotButton, DsBreadcrumb, DsDropdownMenu } from '@drivenets/design-system';",
|
|
32
|
+
],
|
|
33
|
+
id: 'ds-top-bar-navigation',
|
|
34
|
+
metadata: { nestable: false },
|
|
35
|
+
} satisfies figma.Template;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
$focus-outline-width: 2px;
|
|
2
|
+
$disabled-avatar-opacity: 0.55;
|
|
3
|
+
|
|
4
|
+
.root {
|
|
5
|
+
--ds-top-bar-navigation-height: 54px;
|
|
6
|
+
--ds-top-bar-navigation-logo-min-width: 174px;
|
|
7
|
+
--ds-top-bar-navigation-logo-glyph-size: 32px;
|
|
8
|
+
--ds-top-bar-navigation-wordmark-font-size: 24px;
|
|
9
|
+
--ds-top-bar-navigation-breadcrumb-offset: var(--lg);
|
|
10
|
+
--ds-top-bar-navigation-zone-gap: var(--lg);
|
|
11
|
+
--ds-top-bar-navigation-badge-size: 16px;
|
|
12
|
+
--ds-top-bar-navigation-caret-size: 20px;
|
|
13
|
+
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
display: flex;
|
|
16
|
+
align-items: center;
|
|
17
|
+
flex-shrink: 0;
|
|
18
|
+
height: var(--ds-top-bar-navigation-height);
|
|
19
|
+
padding-right: var(--md);
|
|
20
|
+
border-bottom: 1px solid var(--border);
|
|
21
|
+
background: var(--background);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.logo {
|
|
25
|
+
box-sizing: border-box;
|
|
26
|
+
display: flex;
|
|
27
|
+
align-items: center;
|
|
28
|
+
justify-content: center;
|
|
29
|
+
flex-shrink: 0;
|
|
30
|
+
gap: var(--sm);
|
|
31
|
+
align-self: stretch;
|
|
32
|
+
min-width: var(--ds-top-bar-navigation-logo-min-width);
|
|
33
|
+
padding: 0 var(--lg);
|
|
34
|
+
background: var(--background-primary);
|
|
35
|
+
color: var(--font-on-action);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.logoLockup {
|
|
39
|
+
display: flex;
|
|
40
|
+
align-items: center;
|
|
41
|
+
gap: var(--xs);
|
|
42
|
+
color: inherit;
|
|
43
|
+
text-decoration: none;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.logoGlyph {
|
|
47
|
+
display: flex;
|
|
48
|
+
flex-shrink: 0;
|
|
49
|
+
width: var(--ds-top-bar-navigation-logo-glyph-size);
|
|
50
|
+
height: var(--ds-top-bar-navigation-logo-glyph-size);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.logoWordmark {
|
|
54
|
+
font-family: var(--font-family-heading);
|
|
55
|
+
font-size: var(--ds-top-bar-navigation-wordmark-font-size);
|
|
56
|
+
font-weight: var(--font-weight-bold);
|
|
57
|
+
white-space: nowrap;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.breadcrumb {
|
|
61
|
+
display: flex;
|
|
62
|
+
align-items: center;
|
|
63
|
+
min-width: 0;
|
|
64
|
+
margin-left: var(--ds-top-bar-navigation-breadcrumb-offset);
|
|
65
|
+
overflow: hidden;
|
|
66
|
+
white-space: nowrap;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.center {
|
|
70
|
+
display: flex;
|
|
71
|
+
align-items: center;
|
|
72
|
+
flex: 1;
|
|
73
|
+
min-width: 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.actions {
|
|
77
|
+
display: flex;
|
|
78
|
+
align-items: center;
|
|
79
|
+
flex-shrink: 0;
|
|
80
|
+
gap: var(--standard);
|
|
81
|
+
margin-inline-start: auto;
|
|
82
|
+
padding-inline-start: var(--ds-top-bar-navigation-zone-gap);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.notificationsBadge {
|
|
86
|
+
box-sizing: border-box;
|
|
87
|
+
display: flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
justify-content: center;
|
|
90
|
+
min-width: var(--ds-top-bar-navigation-badge-size);
|
|
91
|
+
height: var(--ds-top-bar-navigation-badge-size);
|
|
92
|
+
padding: 0 var(--3xs);
|
|
93
|
+
border-radius: 9999px;
|
|
94
|
+
background: var(--background-error);
|
|
95
|
+
color: var(--font-on-action);
|
|
96
|
+
font-size: var(--body-font-size-xs);
|
|
97
|
+
font-weight: var(--font-weight-medium);
|
|
98
|
+
line-height: var(--body-line-height-xs);
|
|
99
|
+
|
|
100
|
+
&[data-empty] {
|
|
101
|
+
display: none;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.userMenuTrigger {
|
|
106
|
+
display: flex;
|
|
107
|
+
align-items: center;
|
|
108
|
+
gap: var(--3xs);
|
|
109
|
+
padding: 0;
|
|
110
|
+
border: none;
|
|
111
|
+
border-radius: var(--3xs);
|
|
112
|
+
background: transparent;
|
|
113
|
+
color: var(--font-main);
|
|
114
|
+
cursor: pointer;
|
|
115
|
+
|
|
116
|
+
// Nested for the extra class of specificity: `DsAvatar` paints its own `background-color`
|
|
117
|
+
// and `color` from a single-class rule, so a standalone `.userMenuAvatar` ties with it and
|
|
118
|
+
// bundle order picks the winner.
|
|
119
|
+
.userMenuAvatar {
|
|
120
|
+
background-color: var(--light-buttons-tertiary);
|
|
121
|
+
color: var(--font-main);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
&:focus {
|
|
125
|
+
outline: none;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
&:focus-visible {
|
|
129
|
+
outline: $focus-outline-width solid var(--border-action-primary);
|
|
130
|
+
outline-offset: $focus-outline-width;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
&:disabled {
|
|
134
|
+
color: var(--font-disabled);
|
|
135
|
+
cursor: not-allowed;
|
|
136
|
+
|
|
137
|
+
// The caret follows `color`; the avatar sets its own fill and text color above, so
|
|
138
|
+
// neither inherits the disabled tone — dim the whole lockup instead.
|
|
139
|
+
.userMenuAvatar {
|
|
140
|
+
opacity: $disabled-avatar-opacity;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.userMenuCaret {
|
|
146
|
+
display: flex;
|
|
147
|
+
flex-shrink: 0;
|
|
148
|
+
width: var(--ds-top-bar-navigation-caret-size);
|
|
149
|
+
height: var(--ds-top-bar-navigation-caret-size);
|
|
150
|
+
}
|