@drivenets/design-system 0.6.1 → 0.7.1

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.
Files changed (138) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/index.cjs +12297 -8255
  3. package/dist/index.d.cts +817 -118
  4. package/dist/index.d.cts.map +1 -1
  5. package/dist/index.d.ts +817 -118
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +12280 -8259
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.min.css +1 -1
  10. package/package.json +25 -23
  11. package/src/components/ds-autocomplete/ds-autocomplete.module.scss +2 -1
  12. package/src/components/ds-autocomplete/ds-autocomplete.tsx +47 -40
  13. package/src/components/ds-autocomplete/ds-autocomplete.types.tsx +37 -14
  14. package/src/components/ds-button/versions/ds-button-new/ds-button-new.module.scss +3 -7
  15. package/src/components/ds-comment-bubble/components/ds-comment-thread/ds-comment-thread.module.scss +62 -0
  16. package/src/components/ds-comment-bubble/components/ds-comment-thread/ds-comment-thread.tsx +83 -0
  17. package/src/components/ds-comment-bubble/components/ds-comment-thread/ds-comment-thread.types.ts +12 -0
  18. package/src/components/ds-comment-bubble/components/ds-comment-thread/index.ts +2 -0
  19. package/src/components/ds-comment-bubble/components/ds-thread-item/ds-thread-item.module.scss +149 -0
  20. package/src/components/ds-comment-bubble/components/ds-thread-item/ds-thread-item.tsx +147 -0
  21. package/src/components/ds-comment-bubble/components/ds-thread-item/ds-thread-item.types.ts +15 -0
  22. package/src/components/ds-comment-bubble/components/ds-thread-item/index.ts +2 -0
  23. package/src/components/ds-comment-bubble/ds-comment-bubble.module.scss +298 -0
  24. package/src/components/ds-comment-bubble/ds-comment-bubble.tsx +241 -0
  25. package/src/components/ds-comment-bubble/ds-comment-bubble.types.ts +27 -0
  26. package/src/components/ds-comment-bubble/hooks/index.ts +3 -0
  27. package/src/components/ds-comment-bubble/hooks/use-auto-resize.ts +17 -0
  28. package/src/components/ds-comment-bubble/hooks/use-click-outside.ts +22 -0
  29. package/src/components/ds-comment-bubble/hooks/use-scroll-overflow.ts +27 -0
  30. package/src/components/ds-comment-bubble/index.ts +6 -0
  31. package/src/components/ds-comment-card/ds-comment-card.module.scss +162 -0
  32. package/src/components/ds-comment-card/ds-comment-card.tsx +171 -0
  33. package/src/components/ds-comment-card/ds-comment-card.types.ts +45 -0
  34. package/src/components/ds-comment-card/index.ts +2 -0
  35. package/src/components/ds-comment-indicator/ds-comment-indicator.module.scss +65 -0
  36. package/src/components/ds-comment-indicator/ds-comment-indicator.tsx +48 -0
  37. package/src/components/ds-comment-indicator/ds-comment-indicator.types.ts +13 -0
  38. package/src/components/ds-comment-indicator/index.ts +2 -0
  39. package/src/components/ds-comments-drawer/comments-filters.test.ts +483 -0
  40. package/src/components/ds-comments-drawer/comments-filters.ts +134 -0
  41. package/src/components/ds-comments-drawer/comments-filters.types.ts +14 -0
  42. package/src/components/ds-comments-drawer/components/comments-filter-modal/comments-filter-modal.module.scss +92 -0
  43. package/src/components/ds-comments-drawer/components/comments-filter-modal/comments-filter-modal.tsx +219 -0
  44. package/src/components/ds-comments-drawer/components/comments-filter-modal/comments-filter-modal.types.ts +12 -0
  45. package/src/components/ds-comments-drawer/components/comments-filter-modal/index.ts +2 -0
  46. package/src/components/ds-comments-drawer/ds-comments-drawer.module.scss +67 -0
  47. package/src/components/ds-comments-drawer/ds-comments-drawer.tsx +215 -0
  48. package/src/components/ds-comments-drawer/ds-comments-drawer.types.ts +23 -0
  49. package/src/components/ds-comments-drawer/index.ts +3 -0
  50. package/src/components/ds-date-input/ds-date-input.tsx +3 -1
  51. package/src/components/ds-date-input/ds-date-input.types.tsx +6 -0
  52. package/src/components/ds-dropdown-menu/ds-dropdown-menu.tsx +2 -0
  53. package/src/components/ds-expandable-text-input/ds-expandable-text-input.tsx +8 -4
  54. package/src/components/ds-file-upload/components/file-upload/file-upload.tsx +2 -1
  55. package/src/components/ds-file-upload/components/file-upload/file-upload.types.tsx +5 -0
  56. package/src/components/ds-file-upload/types/accept-types.ts +0 -1
  57. package/src/components/ds-filter-status-icon/ds-filter-status-icon.module.scss +19 -0
  58. package/src/components/ds-filter-status-icon/ds-filter-status-icon.tsx +35 -0
  59. package/src/components/ds-filter-status-icon/ds-filter-status-icon.types.ts +31 -0
  60. package/src/components/ds-filter-status-icon/index.ts +3 -0
  61. package/src/components/ds-icon/custom-icons/index.ts +10 -0
  62. package/src/components/ds-icon/custom-icons/special-failed.tsx +16 -0
  63. package/src/components/ds-icon/custom-icons/special-paused.tsx +16 -0
  64. package/src/components/ds-icon/custom-icons/special-running.tsx +16 -0
  65. package/src/components/ds-icon/custom-icons/special-warning.tsx +16 -0
  66. package/src/components/ds-panel/ds-panel.module.scss +3 -3
  67. package/src/components/ds-progress-arc/ds-progress-arc.module.scss +57 -0
  68. package/src/components/ds-progress-arc/ds-progress-arc.tsx +111 -0
  69. package/src/components/ds-progress-arc/ds-progress-arc.types.ts +34 -0
  70. package/src/components/ds-progress-arc/index.ts +3 -0
  71. package/src/components/ds-progress-arc/utils.test.ts +79 -0
  72. package/src/components/ds-progress-arc/utils.ts +61 -0
  73. package/src/components/ds-progress-donut/ds-progress-donut.module.scss +67 -0
  74. package/src/components/ds-progress-donut/ds-progress-donut.tsx +83 -0
  75. package/src/components/ds-progress-donut/ds-progress-donut.types.ts +38 -0
  76. package/src/components/ds-progress-donut/index.ts +2 -0
  77. package/src/components/ds-progress-donut/utils.ts +1 -0
  78. package/src/components/ds-progress-linear/ds-progress-linear.module.scss +100 -0
  79. package/src/components/ds-progress-linear/ds-progress-linear.tsx +107 -0
  80. package/src/components/ds-progress-linear/ds-progress-linear.types.ts +72 -0
  81. package/src/components/ds-progress-linear/index.ts +2 -0
  82. package/src/components/ds-progress-linear/utils.test.ts +70 -0
  83. package/src/components/ds-progress-linear/utils.ts +7 -0
  84. package/src/components/ds-radio-group/ds-radio-group.tsx +2 -0
  85. package/src/components/ds-select/ds-select.tsx +2 -1
  86. package/src/components/ds-select/ds-select.types.tsx +7 -0
  87. package/src/components/ds-stepper/components/ds-step.tsx +1 -1
  88. package/src/components/ds-stepper/ds-stepper.module.scss +16 -2
  89. package/src/components/ds-stepper/ds-stepper.tsx +3 -1
  90. package/src/components/ds-table/components/ds-table-body-virtualized/ds-table-body-virtualized.module.scss +9 -0
  91. package/src/components/ds-table/components/ds-table-body-virtualized/ds-table-body-virtualized.tsx +137 -0
  92. package/src/components/ds-table/components/ds-table-body-virtualized/ds-table-body-virtualized.types.ts +22 -0
  93. package/src/components/ds-table/components/ds-table-body-virtualized/index.ts +2 -0
  94. package/src/components/ds-table/components/ds-table-cell/ds-table-cell.module.scss +3 -1
  95. package/src/components/ds-table/components/ds-table-header/ds-table-header.module.scss +7 -10
  96. package/src/components/ds-table/components/ds-table-header/ds-table-header.tsx +3 -4
  97. package/src/components/ds-table/components/ds-table-row/ds-table-row.module.scss +13 -53
  98. package/src/components/ds-table/components/ds-table-row/ds-table-row.tsx +32 -85
  99. package/src/components/ds-table/components/ds-table-row/ds-table-row.types.ts +0 -6
  100. package/src/components/ds-table/components/ds-table-row-expandable-cell/ds-table-row-expandable-cell.module.scss +10 -0
  101. package/src/components/ds-table/components/ds-table-row-expandable-cell/ds-table-row-expandable-cell.tsx +45 -0
  102. package/src/components/ds-table/components/ds-table-row-expandable-cell/ds-table-row-expandable-cell.types.ts +7 -0
  103. package/src/components/ds-table/components/ds-table-row-expandable-cell/index.ts +2 -0
  104. package/src/components/ds-table/components/ds-table-row-selectable-cell/ds-table-row-selectable-cell.module.scss +6 -0
  105. package/src/components/ds-table/components/ds-table-row-selectable-cell/ds-table-row-selectable-cell.tsx +30 -0
  106. package/src/components/ds-table/components/ds-table-row-selectable-cell/ds-table-row-selectable-cell.types.ts +6 -0
  107. package/src/components/ds-table/components/ds-table-row-selectable-cell/index.ts +2 -0
  108. package/src/components/ds-table/components/ds-table-row-virtualized/ds-table-row-virtualized.module.scss +80 -0
  109. package/src/components/ds-table/components/ds-table-row-virtualized/ds-table-row-virtualized.tsx +95 -0
  110. package/src/components/ds-table/components/ds-table-row-virtualized/ds-table-row-virtualized.types.ts +11 -0
  111. package/src/components/ds-table/components/ds-table-row-virtualized/index.ts +2 -0
  112. package/src/components/ds-table/context/ds-table-context.tsx +0 -9
  113. package/src/components/ds-table/ds-table.module.scss +4 -17
  114. package/src/components/ds-table/ds-table.tsx +44 -77
  115. package/src/components/ds-table/ds-table.types.ts +57 -12
  116. package/src/components/ds-table/index.ts +1 -0
  117. package/src/components/ds-table/styles/_mixins.scss +15 -0
  118. package/src/components/ds-table/styles/_variables.scss +2 -2
  119. package/src/components/ds-table/utils/{column-styling.ts → column-size.ts} +4 -14
  120. package/src/components/ds-table/utils/constants.ts +4 -0
  121. package/src/components/ds-tag/index.tsx +1 -0
  122. package/src/components/ds-tag-filter/ds-tag-filter.module.scss +13 -15
  123. package/src/components/ds-tag-filter/ds-tag-filter.tsx +38 -72
  124. package/src/components/ds-tag-filter/ds-tag-filter.types.ts +2 -3
  125. package/src/components/ds-tag-filter/hooks/use-tag-overflow-calculation.ts +12 -62
  126. package/src/components/ds-tag-filter/utils.test.ts +2 -108
  127. package/src/components/ds-tag-filter/utils.ts +2 -12
  128. package/src/components/ds-tree/ds-tree.module.scss +283 -0
  129. package/src/components/ds-tree/ds-tree.tsx +172 -0
  130. package/src/components/ds-tree/ds-tree.types.ts +83 -0
  131. package/src/components/ds-tree/ds-tree.utils.ts +11 -0
  132. package/src/components/ds-tree/index.ts +3 -0
  133. package/src/index.ts +9 -0
  134. package/src/utils/format-relative-time.test.ts +74 -0
  135. package/src/utils/format-relative-time.ts +52 -0
  136. package/src/utils/numbers.test.ts +24 -0
  137. package/src/utils/numbers.ts +1 -0
  138. package/src/components/ds-table/utils/create-columns-grid-template.ts +0 -23
@@ -0,0 +1,2 @@
1
+ export * from './ds-table-row-selectable-cell';
2
+ export * from './ds-table-row-selectable-cell.types';
@@ -0,0 +1,80 @@
1
+ @use '../../../../styles/typography';
2
+ @use '../../styles/variables' as vars;
3
+ @use '../../styles/mixins' as table-mixins;
4
+
5
+ .row {
6
+ display: flex;
7
+ position: absolute;
8
+ width: 100%;
9
+
10
+ &:hover {
11
+ background-color: var(--color-background-secondary);
12
+ }
13
+
14
+ &[data-state='selected'] {
15
+ background-color: var(--color-background-selected-weak);
16
+ }
17
+
18
+ &[data-state='active'] {
19
+ background-color: var(--color-background-selected-weak);
20
+ }
21
+
22
+ &:not(:last-child):not(.expandedRowContent) {
23
+ > td {
24
+ border-bottom: vars.$border-width solid var(--color-border-secondary);
25
+ }
26
+ }
27
+
28
+ &.clickableRow {
29
+ cursor: pointer;
30
+ }
31
+
32
+ &.rowNoBorder {
33
+ border-bottom: none;
34
+ }
35
+
36
+ &:not(.expandedRowContent) {
37
+ &.expanded {
38
+ @include table-mixins.expanded-row-border('top');
39
+ }
40
+
41
+ &.sizeSmall {
42
+ height: var(--ds-table-row-small);
43
+ }
44
+
45
+ &.sizeMedium {
46
+ height: var(--ds-table-row-medium);
47
+ }
48
+
49
+ &.sizeLarge {
50
+ height: var(--ds-table-row-large);
51
+ }
52
+ }
53
+ }
54
+
55
+ .cell,
56
+ .selectableCell,
57
+ .expandableCell {
58
+ display: flex;
59
+ align-items: center;
60
+ @include typography.body-sm-reg;
61
+ color: var(--color-font-main);
62
+ }
63
+
64
+ .cell {
65
+ padding: 0 var(--spacing-standard);
66
+ }
67
+
68
+ .expandedRowContent {
69
+ background-color: var(--color-background-secondary);
70
+
71
+ & > td {
72
+ display: flex;
73
+ flex-direction: column;
74
+ flex: 1;
75
+ padding: var(--spacing-standard);
76
+ background-color: var(--color-background-secondary);
77
+ }
78
+
79
+ @include table-mixins.expanded-row-border('bottom');
80
+ }
@@ -0,0 +1,95 @@
1
+ import classnames from 'classnames';
2
+ import styles from './ds-table-row-virtualized.module.scss';
3
+ import { useDsTableContext } from '../../context/ds-table-context';
4
+ import { getColumnSizeStyle } from '../../utils/column-size';
5
+ import { TableCell, TableRow } from '../core-table';
6
+ import { DsTableRowSelectableCell } from '../ds-table-row-selectable-cell';
7
+ import { DsTableRowExpandableCell } from '../ds-table-row-expandable-cell';
8
+ import type { DsTableRowVirtualizedProps } from './ds-table-row-virtualized.types';
9
+ import { DsTableCell } from '../ds-table-cell';
10
+
11
+ export const DsTableRowVirtualized = <TData,>({
12
+ row,
13
+ rowsMapRef,
14
+ rowHeightsMapRef,
15
+ rowVirtualizer,
16
+ virtualRow,
17
+ isExpandedRowContent,
18
+ }: DsTableRowVirtualizedProps<TData>) => {
19
+ const {
20
+ selectable,
21
+ expandable,
22
+ bordered,
23
+ rowSize,
24
+ activeRowId,
25
+ primaryRowActions,
26
+ secondaryRowActions,
27
+ renderExpandedRow,
28
+ onRowClick,
29
+ onRowDoubleClick,
30
+ } = useDsTableContext<TData, unknown>();
31
+ const isExpanded = row.getIsExpanded();
32
+ const isActive = activeRowId === row.id;
33
+
34
+ return (
35
+ <TableRow
36
+ data-index={virtualRow.index}
37
+ ref={(row) => {
38
+ const key = String(virtualRow.key);
39
+
40
+ if (row) {
41
+ rowVirtualizer.measureElement(row); // measure dynamic row height
42
+ rowsMapRef.current.set(key, row); // store ref for virtualizer to apply scrolling transforms
43
+
44
+ const height = row.getBoundingClientRect().height;
45
+ rowHeightsMapRef.current.set(key, height); // store height for virtualizer to estimate size
46
+ } else {
47
+ rowsMapRef.current.delete(key);
48
+ }
49
+ }}
50
+ data-state={isActive ? 'active' : row.getIsSelected() ? 'selected' : undefined}
51
+ className={classnames(
52
+ styles.row,
53
+ {
54
+ [styles.sizeSmall]: rowSize === 'small',
55
+ [styles.sizeMedium]: rowSize === 'medium',
56
+ [styles.sizeLarge]: rowSize === 'large',
57
+ },
58
+ isExpandedRowContent && styles.expandedRowContent,
59
+ onRowClick && styles.clickableRow,
60
+ !bordered && styles.rowNoBorder,
61
+ isExpanded && styles.expanded,
62
+ )}
63
+ onClick={isExpandedRowContent ? undefined : () => onRowClick?.(row.original)}
64
+ onDoubleClick={isExpandedRowContent ? undefined : () => onRowDoubleClick?.(row.original)}
65
+ >
66
+ {isExpandedRowContent ? (
67
+ <TableCell>{renderExpandedRow?.(row.original)}</TableCell>
68
+ ) : (
69
+ <>
70
+ {selectable && <DsTableRowSelectableCell row={row} className={styles.selectableCell} />}
71
+ {expandable && <DsTableRowExpandableCell row={row} className={styles.expandableCell} />}
72
+ {row.getVisibleCells().map((cell, idx) => {
73
+ const isLastColumn = idx === row.getVisibleCells().length - 1;
74
+ const cellStyle = getColumnSizeStyle(cell.column.getSize(), true);
75
+
76
+ return (
77
+ <TableCell key={cell.id} style={cellStyle} className={styles.cell}>
78
+ {isLastColumn ? (
79
+ <DsTableCell
80
+ row={row}
81
+ cell={cell}
82
+ primaryRowActions={primaryRowActions}
83
+ secondaryRowActions={secondaryRowActions}
84
+ />
85
+ ) : (
86
+ <DsTableCell row={row} cell={cell} />
87
+ )}
88
+ </TableCell>
89
+ );
90
+ })}
91
+ </>
92
+ )}
93
+ </TableRow>
94
+ );
95
+ };
@@ -0,0 +1,11 @@
1
+ import { type Row } from '@tanstack/react-table';
2
+ import { type VirtualItem, type Virtualizer } from '@tanstack/react-virtual';
3
+
4
+ export interface DsTableRowVirtualizedProps<TData> {
5
+ row: Row<TData>;
6
+ rowsMapRef: React.RefObject<Map<string, HTMLTableRowElement>>;
7
+ rowHeightsMapRef: React.RefObject<Map<string, number>>;
8
+ rowVirtualizer: Virtualizer<HTMLDivElement, HTMLTableRowElement>;
9
+ virtualRow: VirtualItem;
10
+ isExpandedRowContent?: boolean;
11
+ }
@@ -0,0 +1,2 @@
1
+ export * from './ds-table-row-virtualized';
2
+ export * from './ds-table-row-virtualized.types';
@@ -2,15 +2,6 @@ import { createContext, useContext } from 'react';
2
2
  import type { DsDataTableProps, DsTableRowSize } from '../ds-table.types';
3
3
 
4
4
  export interface DsTableContextType<TData, TValue> extends Partial<DsDataTableProps<TData, TValue>> {
5
- /**
6
- * The expanded rows
7
- */
8
- expandedRows: Record<string, boolean>;
9
- /**
10
- * Toggle the expanded state of a row
11
- * @param rowId - The id of the row to toggle
12
- */
13
- toggleRowExpanded: (rowId: string) => void;
14
5
  /**
15
6
  * Whether the table is virtualized
16
7
  * @default false
@@ -10,12 +10,6 @@
10
10
  background: var(--color-background);
11
11
  }
12
12
 
13
- .virtualizedContainer {
14
- position: relative;
15
- height: vars.$virtualized-height;
16
- overflow: auto;
17
- }
18
-
19
13
  .dataTableContainer {
20
14
  max-height: 100%;
21
15
  overflow: auto;
@@ -42,19 +36,12 @@
42
36
  text-align: center;
43
37
  }
44
38
 
45
- .emptyStateVirtualized {
46
- position: absolute;
47
- inset: 0;
48
- top: var(--ds-table-header-height);
49
- }
50
-
51
39
  .virtualized {
52
40
  display: grid;
53
- grid-template-columns: var(--ds-table-columns-template);
54
41
  }
55
42
 
56
- .virtualizedBody {
57
- display: grid;
58
- grid-template-columns: subgrid;
59
- grid-column: 1 / -1;
43
+ .virtualizedContainer {
44
+ position: relative;
45
+ height: vars.$virtualized-height;
46
+ overflow: auto;
60
47
  }
@@ -10,7 +10,6 @@ import {
10
10
  useReactTable,
11
11
  type VisibilityState,
12
12
  } from '@tanstack/react-table';
13
- import { useVirtualizer, type VirtualItem } from '@tanstack/react-virtual';
14
13
  import classnames from 'classnames';
15
14
  import { Table, TableBody, TableCell, TableRow } from './components/core-table';
16
15
  import { DsTableBulkActions } from './components/ds-table-bulk-actions';
@@ -20,7 +19,8 @@ import type { DsDataTableProps, DsTableRowSize } from './ds-table.types';
20
19
  import { DsTableRow } from './components/ds-table-row';
21
20
  import { useDragAndDrop } from './hooks/use-drag-and-drop';
22
21
  import { type DsTableContextType, DsTableContext } from './context/ds-table-context';
23
- import { createColumnsGridTemplate } from './utils/create-columns-grid-template';
22
+ import { DsTableBodyVirtualized } from './components/ds-table-body-virtualized';
23
+ import { EMPTY_TABLE_STATE_TEXT } from './utils/constants';
24
24
 
25
25
  // Row size to pixel height mapping (matches CSS variables)
26
26
  const ROW_SIZE_HEIGHT_MAP: Record<DsTableRowSize, number> = {
@@ -69,7 +69,6 @@ const DsTable = <TData extends { id: string }, TValue>({
69
69
  const [internalColumnFilters, setInternalColumnFilters] = React.useState<ColumnFiltersState>([]);
70
70
  const [internalColumnVisibility, setInternalColumnVisibility] = React.useState<VisibilityState>({});
71
71
  const [rowSelection, setRowSelection] = React.useState<RowSelectionState>({});
72
- const [expandedRows, setExpandedRows] = React.useState<Record<string, boolean>>({});
73
72
 
74
73
  const { DragWrapper, SortableWrapper } = useDragAndDrop<TData>({
75
74
  isDragEnabled: reorderable && !virtualized,
@@ -129,9 +128,9 @@ const DsTable = <TData extends { id: string }, TValue>({
129
128
  getCoreRowModel: getCoreRowModel(),
130
129
  onSortingChange: handleSortingChange,
131
130
  getSortedRowModel: getSortedRowModel(),
132
- onColumnFiltersChange: handleColumnFiltersChange,
131
+ onColumnFiltersChange: handleColumnFiltersChange, // TODO: looks like this is not used, since filters are handled from the outside
133
132
  getFilteredRowModel: getFilteredRowModel(),
134
- onColumnVisibilityChange: handleColumnVisibilityChange,
133
+ onColumnVisibilityChange: handleColumnVisibilityChange, // TODO: looks like this is not used, since visibility is handled from the outside
135
134
  onRowSelectionChange: handleRowSelectionChange,
136
135
  getRowId: (row) => row.id,
137
136
  state: {
@@ -166,51 +165,39 @@ const DsTable = <TData extends { id: string }, TValue>({
166
165
  getSelectedRows: () => {
167
166
  return table.getFilteredSelectedRowModel().rows.map((r) => r.original);
168
167
  },
168
+ expandRow: (rowId: string) => {
169
+ table.getRow(rowId).toggleExpanded(true);
170
+ },
171
+ collapseRow: (rowId: string) => {
172
+ table.getRow(rowId).toggleExpanded(false);
173
+ },
174
+ expandAllRows: () => {
175
+ table.toggleAllRowsExpanded(true);
176
+ },
177
+ collapseAllRows: () => {
178
+ table.toggleAllRowsExpanded(false);
179
+ },
180
+ expandRows: (rowIds: string[]) => {
181
+ const expansion: Record<string, boolean> = {};
182
+ rowIds.forEach((id) => (expansion[id] = true));
183
+ table.setExpanded(expansion);
184
+ },
169
185
  }),
170
186
  [table],
171
187
  );
172
188
 
173
189
  const { rows, rowsById } = table.getRowModel();
174
190
 
175
- const rowVirtualizer = useVirtualizer({
176
- count: rows.length,
177
- getScrollElement: () => tableContainerRef.current,
178
- // estimate row height for accurate scrollbar dragging
179
- estimateSize: () => virtualizedOptions?.estimateSize || ROW_SIZE_HEIGHT_MAP[rowSize],
180
- overscan: virtualizedOptions?.overscan || 5,
181
- onChange: (instance, sync) => {
182
- if (sync && onScroll) {
183
- const scrollOffset = instance.scrollOffset || 0;
184
- const totalContentHeight = instance.getTotalSize();
185
- const viewportHeight = instance.scrollElement?.clientHeight;
186
-
187
- if (viewportHeight) {
188
- onScroll({ scrollOffset, totalContentHeight, viewportHeight });
189
- }
190
- }
191
- },
192
- });
193
-
194
- const toggleRowExpanded = (rowId: string) => {
195
- setExpandedRows((prev) => ({
196
- ...prev,
197
- [rowId]: !prev[rowId],
198
- }));
199
- };
200
-
201
- const renderEmptyState = () =>
202
- virtualized ? (
203
- <div className={styles.emptyStateVirtualized}>{emptyState || 'No results.'}</div>
204
- ) : (
205
- <TableRow>
206
- <TableCell
207
- colSpan={columns.length + (expandable ? 1 : 0) + (selectable ? 1 : 0)}
208
- className={styles.emptyState}
209
- >
210
- {emptyState || 'No results.'}
211
- </TableCell>
212
- </TableRow>
213
- );
191
+ const renderEmptyState = () => (
192
+ <TableRow>
193
+ <TableCell
194
+ colSpan={columns.length + (expandable ? 1 : 0) + (selectable ? 1 : 0)}
195
+ className={styles.emptyState}
196
+ >
197
+ {emptyState || EMPTY_TABLE_STATE_TEXT}
198
+ </TableCell>
199
+ </TableRow>
200
+ );
214
201
 
215
202
  const selectedRows = Object.entries(rowSelection)
216
203
  .filter(([, selected]) => selected)
@@ -232,8 +219,6 @@ const DsTable = <TData extends { id: string }, TValue>({
232
219
  secondaryRowActions,
233
220
  renderExpandedRow,
234
221
  virtualized,
235
- expandedRows,
236
- toggleRowExpanded,
237
222
  activeRowId,
238
223
  };
239
224
 
@@ -250,16 +235,6 @@ const DsTable = <TData extends { id: string }, TValue>({
250
235
  >
251
236
  <DragWrapper>
252
237
  <Table
253
- style={
254
- virtualized
255
- ? ({
256
- '--ds-table-columns-template': createColumnsGridTemplate({
257
- columns,
258
- selectable: !!selectable,
259
- }),
260
- } as React.CSSProperties)
261
- : undefined
262
- }
263
238
  className={classnames(
264
239
  fullWidth && styles.fullWidth,
265
240
  !bordered && styles.tableNoBorder,
@@ -267,32 +242,24 @@ const DsTable = <TData extends { id: string }, TValue>({
267
242
  )}
268
243
  >
269
244
  <DsTableHeader table={table} />
270
- <TableBody
271
- style={{ height: virtualized ? `${String(rowVirtualizer.getTotalSize())}px` : undefined }}
272
- className={classnames(virtualized && styles.virtualizedBody)}
273
- >
274
- {virtualized ? (
275
- rowVirtualizer.getVirtualItems().length ? (
276
- rowVirtualizer.getVirtualItems().map((virtualRow: VirtualItem) => {
277
- const row = rows[virtualRow.index];
278
-
279
- if (!row) {
280
- return null;
281
- }
282
-
283
- return <DsTableRow key={row.id} row={row} virtualRow={virtualRow} />;
284
- })
285
- ) : (
286
- renderEmptyState()
287
- )
288
- ) : (
245
+ {virtualized ? (
246
+ <DsTableBodyVirtualized
247
+ table={table}
248
+ tableContainerRef={tableContainerRef}
249
+ emptyState={emptyState}
250
+ estimateSize={virtualizedOptions?.estimateSize || ROW_SIZE_HEIGHT_MAP[rowSize]}
251
+ overscan={virtualizedOptions?.overscan}
252
+ onScroll={onScroll}
253
+ />
254
+ ) : (
255
+ <TableBody>
289
256
  <SortableWrapper>
290
257
  {rows.length
291
258
  ? rows.map((row) => <DsTableRow key={row.id} row={row} />)
292
259
  : renderEmptyState()}
293
260
  </SortableWrapper>
294
- )}
295
- </TableBody>
261
+ </TableBody>
262
+ )}
296
263
  </Table>
297
264
  </DragWrapper>
298
265
  </div>
@@ -8,24 +8,13 @@ import type {
8
8
  } from '@tanstack/react-table';
9
9
  import type { IconType } from '../ds-icon';
10
10
  import type { RowAction, SecondaryRowAction } from './components/ds-table-cell';
11
+ import type { ScrollParams } from './components/ds-table-body-virtualized';
11
12
 
12
13
  /**
13
14
  * Row size variants based on Figma design specifications
14
15
  */
15
16
  export type DsTableRowSize = 'small' | 'medium' | 'large';
16
17
 
17
- /**
18
- * Parameters passed to the onScroll callback in virtualized tables.
19
- */
20
- export interface ScrollParams {
21
- /** The current vertical scroll position from the top of the scrollable content (in pixels) */
22
- scrollOffset: number;
23
- /** The total height of all content in the virtualized table (in pixels) */
24
- totalContentHeight: number;
25
- /** The visible height of the table container (in pixels) */
26
- viewportHeight: number;
27
- }
28
-
29
18
  /**
30
19
  * API for programmatically controlling a DsTable component.
31
20
  * This interface provides methods to interact with the table's selection, sorting, filtering, and pagination features.
@@ -117,6 +106,62 @@ export interface DsTableApi<TData> {
117
106
  * ```
118
107
  */
119
108
  getSelectedRows: () => TData[];
109
+
110
+ /**
111
+ * Expands a single row by its ID.
112
+ *
113
+ * @param rowId - The unique identifier of the row to expand
114
+ *
115
+ * @example
116
+ * ```tsx
117
+ * tableRef.current?.expandRow('user-123');
118
+ * ```
119
+ */
120
+ expandRow: (rowId: string) => void;
121
+
122
+ /**
123
+ * Collapses a single row by its ID.
124
+ *
125
+ * @param rowId - The unique identifier of the row to collapse
126
+ *
127
+ * @example
128
+ * ```tsx
129
+ * tableRef.current?.collapseRow('user-123');
130
+ * ```
131
+ */
132
+ collapseRow: (rowId: string) => void;
133
+
134
+ /**
135
+ * Expands all rows in the table.
136
+ *
137
+ * @example
138
+ * ```tsx
139
+ * tableRef.current?.expandAllRows();
140
+ * ```
141
+ */
142
+ expandAllRows: () => void;
143
+
144
+ /**
145
+ * Collapses all rows in the table.
146
+ *
147
+ * @example
148
+ * ```tsx
149
+ * tableRef.current?.collapseAllRows();
150
+ * ```
151
+ */
152
+ collapseAllRows: () => void;
153
+
154
+ /**
155
+ * Expands multiple rows by their IDs.
156
+ *
157
+ * @param rowIds - Array of unique identifiers for the rows to expand
158
+ *
159
+ * @example
160
+ * ```tsx
161
+ * tableRef.current?.expandRows(['user-1', 'user-2', 'user-3']);
162
+ * ```
163
+ */
164
+ expandRows: (rowIds: string[]) => void;
120
165
  }
121
166
 
122
167
  /**
@@ -1,4 +1,5 @@
1
1
  export type { SecondaryRowAction, RowAction } from './components/ds-table-cell';
2
+ export type { ScrollParams } from './components/ds-table-body-virtualized';
2
3
 
3
4
  export * from './filters';
4
5
 
@@ -0,0 +1,15 @@
1
+ @mixin expanded-row-border($side) {
2
+ $border: 1px solid var(--color-border-action-primary);
3
+
4
+ &:not(.expandedRow + &) > td {
5
+ border-#{$side}: $border;
6
+ }
7
+
8
+ & > td:first-child {
9
+ border-inline-start: $border;
10
+ }
11
+
12
+ & > td:last-child {
13
+ border-inline-end: $border;
14
+ }
15
+ }
@@ -1,8 +1,8 @@
1
1
  $border-radius: 4px;
2
2
  $border-width: 1px;
3
3
  $virtualized-height: 600px;
4
- $expand-column-width: 40px;
5
- $select-column-width: 40px;
4
+ $expand-column-width: 36px;
5
+ $select-column-width: 36px;
6
6
  $reorder-column-width: 60px;
7
7
  $container-margin-vertical: 1rem;
8
8
  $filter-input-gap: 0.5rem;
@@ -6,25 +6,15 @@ import { defaultColumnSizing } from '@tanstack/react-table';
6
6
  *
7
7
  * @param columnSize - The size of the column
8
8
  * @param virtualized - Whether the table is virtualized
9
- * @param isLastColumn - Whether this is the last column in the row
10
9
  * @returns Style object or undefined if no custom styling is needed
11
10
  */
12
- export const getColumnStyle = (
13
- columnSize: number,
14
- virtualized?: boolean,
15
- isLastColumn: boolean = false,
16
- ): CSSProperties | undefined => {
11
+ export const getColumnSizeStyle = (columnSize: number, virtualized?: boolean): CSSProperties | undefined => {
17
12
  const hasCustomSize = columnSize !== defaultColumnSizing.size;
18
- if (!hasCustomSize) {
19
- return undefined;
13
+ if (hasCustomSize) {
14
+ return { width: columnSize };
20
15
  }
21
16
 
22
17
  if (virtualized) {
23
- return {
24
- flexBasis: `${String(columnSize)}px`,
25
- flexGrow: isLastColumn ? 1 : 0,
26
- };
18
+ return { flex: 1 };
27
19
  }
28
-
29
- return { width: columnSize };
30
20
  };
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Default text for empty table state
3
+ */
4
+ export const EMPTY_TABLE_STATE_TEXT = 'No results.';
@@ -1,2 +1,3 @@
1
1
  export { default as DsTag } from './ds-tag';
2
+ export { tagSizes, tagVariants } from './ds-tag.types';
2
3
  export type { TagSize, TagVariant, DsTagProps } from './ds-tag.types';
@@ -6,7 +6,6 @@
6
6
  background: var(--color-background-selected-weak);
7
7
  border: 1px solid var(--color-outline-weak);
8
8
  border-radius: var(--spacing-3xs);
9
- max-height: 88px; // hardcoded value required in the design
10
9
  overflow: hidden;
11
10
 
12
11
  &.expanded {
@@ -14,7 +13,7 @@
14
13
  }
15
14
  }
16
15
 
17
- .row1 {
16
+ .header {
18
17
  display: flex;
19
18
  align-items: center;
20
19
  width: 100%;
@@ -22,7 +21,15 @@
22
21
  flex-shrink: 0;
23
22
  }
24
23
 
25
- .row2 {
24
+ .headerActions {
25
+ display: flex;
26
+ align-items: center;
27
+ gap: var(--spacing-xs);
28
+ flex-shrink: 0;
29
+ margin-left: auto;
30
+ }
31
+
32
+ .tagsArea {
26
33
  display: flex;
27
34
  align-items: center;
28
35
  width: 100%;
@@ -36,35 +43,26 @@
36
43
  flex-shrink: 0;
37
44
  }
38
45
 
39
- .expandTag {
40
- cursor: pointer;
41
- flex-shrink: 0;
42
- }
43
-
44
46
  .itemCheckbox {
45
47
  display: flex;
46
48
  align-items: center;
47
49
  }
48
50
 
49
- .clearContent {
51
+ .ghostButtonContent {
52
+ // TODO: remove once migrated 1.2 button to the ghost with transparent bg
50
53
  background: transparent !important;
51
54
  }
52
55
 
53
- .clearButton {
54
- margin-left: auto;
56
+ .actionButton {
55
57
  padding: 0;
56
58
  flex-shrink: 0;
57
59
  }
58
60
 
59
- // Hidden container for measuring element widths
60
- // Must render all elements to get accurate measurements
61
61
  .measurementContainer {
62
62
  pointer-events: none;
63
63
  display: flex;
64
64
  align-items: center;
65
65
  gap: var(--spacing-xs);
66
-
67
- // Ensure it doesn't affect layout
68
66
  height: 0;
69
67
  overflow: hidden;
70
68
  position: absolute;