@drivenets/design-system 0.18.1 → 0.20.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.
Files changed (216) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/dist/index.cjs +17038 -10114
  3. package/dist/index.d.cts +1355 -444
  4. package/dist/index.d.cts.map +1 -1
  5. package/dist/index.d.ts +1354 -443
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +17073 -10172
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.min.css +1 -1
  10. package/package.json +41 -41
  11. package/src/components/ds-bot-button/ds-bot-button.figma.ts +38 -0
  12. package/src/components/ds-bot-button/ds-bot-button.module.scss +41 -0
  13. package/src/components/ds-bot-button/ds-bot-button.tsx +48 -0
  14. package/src/components/ds-bot-button/ds-bot-button.types.ts +33 -0
  15. package/src/components/ds-bot-button/index.ts +2 -0
  16. package/src/components/ds-bot-button/net-gen-logo.tsx +46 -0
  17. package/src/components/ds-bulk-actions/components/action-button.tsx +42 -0
  18. package/src/components/ds-bulk-actions/components/menu-entries.tsx +76 -0
  19. package/src/components/ds-bulk-actions/components/overflow.tsx +75 -0
  20. package/src/components/ds-bulk-actions/ds-bulk-actions.figma.ts +28 -0
  21. package/src/components/ds-bulk-actions/ds-bulk-actions.module.scss +199 -0
  22. package/src/components/ds-bulk-actions/ds-bulk-actions.tsx +220 -0
  23. package/src/components/ds-bulk-actions/ds-bulk-actions.types.ts +170 -0
  24. package/src/components/ds-bulk-actions/ds-bulk-actions.unit.test.ts +195 -0
  25. package/src/components/ds-bulk-actions/ds-bulk-actions.utils.ts +91 -0
  26. package/src/components/ds-bulk-actions/ds-bulk-actions.utils.unit.test.ts +134 -0
  27. package/src/components/ds-bulk-actions/hooks/compute-bulk-actions-overflow.ts +85 -0
  28. package/src/components/ds-bulk-actions/hooks/use-bulk-actions-overflow.ts +153 -0
  29. package/src/components/ds-bulk-actions/index.ts +18 -0
  30. package/src/components/ds-button-v3/ds-button-v3.module.scss +2 -2
  31. package/src/components/ds-catalog-layout/ds-catalog-layout.figma.ts +1 -1
  32. package/src/components/ds-checkbox/ds-checkbox.figma.ts +3 -0
  33. package/src/components/ds-checkbox/ds-checkbox.module.scss +102 -20
  34. package/src/components/ds-checkbox/ds-checkbox.tsx +30 -2
  35. package/src/components/ds-checkbox/ds-checkbox.types.ts +10 -0
  36. package/src/components/ds-code-input/collapsed-code-field/collapsed-code-field.module.scss +169 -0
  37. package/src/components/ds-code-input/collapsed-code-field/collapsed-code-field.tsx +92 -0
  38. package/src/components/ds-code-input/collapsed-code-field/index.ts +1 -0
  39. package/src/components/ds-code-input/ds-code-input-panel/ds-code-input-panel.module.scss +110 -0
  40. package/src/components/ds-code-input/ds-code-input-panel/ds-code-input-panel.tsx +61 -0
  41. package/src/components/ds-code-input/ds-code-input-panel/index.ts +1 -0
  42. package/src/components/ds-code-input/ds-code-input.module.scss +25 -0
  43. package/src/components/ds-code-input/ds-code-input.tsx +401 -0
  44. package/src/components/ds-code-input/ds-code-input.types.ts +166 -0
  45. package/src/components/ds-code-input/ds-code-input.utils.ts +94 -0
  46. package/src/components/ds-code-input/ds-code-input.utils.unit.test.ts +166 -0
  47. package/src/components/ds-code-input/index.ts +2 -0
  48. package/src/components/ds-code-input/use-collapsed-viewport.ts +289 -0
  49. package/src/components/ds-code-input/use-editor-host.ts +87 -0
  50. package/src/components/ds-dropdown-menu/ds-dropdown-menu.tsx +2 -0
  51. package/src/components/ds-empty-state/ds-empty-state.module.scss +16 -0
  52. package/src/components/ds-empty-state/ds-empty-state.tsx +45 -0
  53. package/src/components/ds-empty-state/ds-empty-state.types.ts +38 -0
  54. package/src/components/ds-empty-state/index.ts +3 -0
  55. package/src/components/ds-file-upload/ds-file-upload.tsx +4 -1
  56. package/src/components/ds-filters-bar/components/ds-filters-bar-builder/ds-filters-bar-builder.ts +11 -0
  57. package/src/components/ds-filters-bar/components/ds-filters-bar-builder/ds-filters-bar-builder.types.ts +41 -0
  58. package/src/components/ds-filters-bar/components/ds-filters-bar-builder/index.ts +1 -0
  59. package/src/components/ds-filters-bar/components/ds-filters-bar-clear-all.ts +11 -0
  60. package/src/components/ds-filters-bar/components/ds-filters-bar-conditions/ds-filters-bar-conditions.ts +11 -0
  61. package/src/components/ds-filters-bar/components/ds-filters-bar-conditions/ds-filters-bar-conditions.types.ts +30 -0
  62. package/src/components/ds-filters-bar/components/ds-filters-bar-conditions/index.ts +1 -0
  63. package/src/components/ds-filters-bar/components/ds-filters-bar-pinned.ts +31 -0
  64. package/src/components/ds-filters-bar/components/ds-filters-bar-query/ds-filters-bar-query.ts +11 -0
  65. package/src/components/ds-filters-bar/components/ds-filters-bar-query/ds-filters-bar-query.types.ts +22 -0
  66. package/src/components/ds-filters-bar/components/ds-filters-bar-query/index.ts +1 -0
  67. package/src/components/ds-filters-bar/components/ds-filters-bar-saved-filters.ts +19 -0
  68. package/src/components/ds-filters-bar/components/ds-filters-bar-search.ts +11 -0
  69. package/src/components/ds-filters-bar/components/ds-filters-bar-summary.ts +11 -0
  70. package/src/components/ds-filters-bar/components/ds-filters-bar-toolbar.ts +11 -0
  71. package/src/components/ds-filters-bar/components/ds-filters-bar-view-switch.ts +11 -0
  72. package/src/components/ds-filters-bar/components/ds-filters-bar-view.ts +11 -0
  73. package/src/components/ds-filters-bar/components/index.ts +11 -0
  74. package/src/components/ds-filters-bar/ds-filters-bar.context.ts +69 -0
  75. package/src/components/ds-filters-bar/ds-filters-bar.tsx +120 -0
  76. package/src/components/ds-filters-bar/ds-filters-bar.types.ts +440 -0
  77. package/src/components/ds-filters-bar/ds-filters-bar.unit.test.ts +216 -0
  78. package/src/components/ds-filters-bar/ds-filters-bar.utils.ts +141 -0
  79. package/src/components/ds-filters-bar/index.ts +1 -0
  80. package/src/components/ds-form-control/ds-form-control.module.scss +18 -0
  81. package/src/components/ds-form-control/ds-form-control.tsx +61 -19
  82. package/src/components/ds-form-control/ds-form-control.types.ts +2 -1
  83. package/src/components/ds-icon/custom-icons/index.ts +2 -0
  84. package/src/components/ds-icon/custom-icons/special-adv-filters.tsx +28 -0
  85. package/src/components/ds-illustration/ds-illustration.figma.ts +34 -0
  86. package/src/components/ds-illustration/ds-illustration.module.scss +6 -0
  87. package/src/components/ds-illustration/ds-illustration.tsx +29 -0
  88. package/src/components/ds-illustration/ds-illustration.types.ts +45 -0
  89. package/src/components/ds-illustration/illustrations/configuration.tsx +51 -0
  90. package/src/components/ds-illustration/illustrations/device.tsx +133 -0
  91. package/src/components/ds-illustration/illustrations/done.tsx +107 -0
  92. package/src/components/{ds-catalog-layout/catalog-layout-empty-illustration.tsx → ds-illustration/illustrations/empty-inbox.tsx} +10 -14
  93. package/src/components/ds-illustration/illustrations/error.tsx +86 -0
  94. package/src/components/ds-illustration/illustrations/go-filter.tsx +51 -0
  95. package/src/components/ds-illustration/illustrations/illustration-clouds.tsx +10 -0
  96. package/src/components/ds-illustration/illustrations/index.ts +39 -0
  97. package/src/components/ds-illustration/illustrations/no-connection.tsx +54 -0
  98. package/src/components/ds-illustration/illustrations/no-credit-card.tsx +48 -0
  99. package/src/components/ds-illustration/illustrations/no-device.tsx +61 -0
  100. package/src/components/ds-illustration/illustrations/no-documents.tsx +52 -0
  101. package/src/components/ds-illustration/illustrations/no-gps.tsx +57 -0
  102. package/src/components/ds-illustration/illustrations/no-images.tsx +82 -0
  103. package/src/components/ds-illustration/illustrations/no-items-cart.tsx +86 -0
  104. package/src/components/ds-illustration/illustrations/no-messages.tsx +51 -0
  105. package/src/components/ds-illustration/illustrations/no-search-result.tsx +76 -0
  106. package/src/components/ds-illustration/illustrations/no-tasks.tsx +61 -0
  107. package/src/components/ds-illustration/illustrations/site.tsx +80 -0
  108. package/src/components/ds-illustration/index.ts +3 -0
  109. package/src/components/ds-main-menu/components/expanded-item/expanded-item.tsx +108 -0
  110. package/src/components/ds-main-menu/components/expanded-item/expanded-item.types.ts +8 -0
  111. package/src/components/ds-main-menu/components/expanded-item/index.ts +1 -0
  112. package/src/components/ds-main-menu/components/menu-graphic/index.ts +1 -0
  113. package/src/components/ds-main-menu/components/menu-graphic/menu-graphic.tsx +16 -0
  114. package/src/components/ds-main-menu/components/menu-graphic/menu-graphic.types.ts +7 -0
  115. package/src/components/ds-main-menu/components/tile-link/index.ts +1 -0
  116. package/src/components/ds-main-menu/components/tile-link/tile-link.tsx +85 -0
  117. package/src/components/ds-main-menu/components/tile-link/tile-link.types.ts +8 -0
  118. package/src/components/ds-main-menu/components/utility-link/index.ts +1 -0
  119. package/src/components/ds-main-menu/components/utility-link/utility-link.tsx +37 -0
  120. package/src/components/ds-main-menu/components/utility-link/utility-link.types.ts +7 -0
  121. package/src/components/ds-main-menu/ds-main-menu.figma.ts +17 -0
  122. package/src/components/ds-main-menu/ds-main-menu.module.scss +349 -0
  123. package/src/components/ds-main-menu/ds-main-menu.tsx +102 -0
  124. package/src/components/ds-main-menu/ds-main-menu.types.ts +86 -0
  125. package/src/components/ds-main-menu/ds-main-menu.utils.ts +40 -0
  126. package/src/components/ds-main-menu/index.ts +9 -0
  127. package/src/components/ds-modal/figma/ds-modal-footer.figma.ts +1 -1
  128. package/src/components/ds-pin-toggle/ds-pin-toggle.figma.ts +27 -0
  129. package/src/components/ds-pin-toggle/ds-pin-toggle.module.scss +41 -0
  130. package/src/components/ds-pin-toggle/ds-pin-toggle.tsx +43 -0
  131. package/src/components/ds-pin-toggle/ds-pin-toggle.types.ts +29 -0
  132. package/src/components/ds-pin-toggle/index.ts +2 -0
  133. package/src/components/ds-popover/components/popover-trigger/index.ts +1 -0
  134. package/src/components/ds-popover/components/popover-trigger/popover-trigger.tsx +15 -0
  135. package/src/components/ds-popover/ds-popover.context.ts +18 -0
  136. package/src/components/ds-popover/ds-popover.hover-intent.ts +65 -0
  137. package/src/components/ds-popover/ds-popover.tsx +164 -41
  138. package/src/components/ds-popover/ds-popover.types.ts +65 -0
  139. package/src/components/ds-popover/ds-popover.utils.ts +60 -0
  140. package/src/components/ds-popover/ds-popover.utils.unit.test.ts +25 -0
  141. package/src/components/ds-saved-filters/components/ds-saved-filters-delete-confirm.tsx +53 -0
  142. package/src/components/ds-saved-filters/components/ds-saved-filters-name-entry.tsx +64 -0
  143. package/src/components/ds-saved-filters/components/ds-saved-filters-name-modal.tsx +50 -0
  144. package/src/components/ds-saved-filters/components/ds-saved-filters-row/ds-saved-filters-row.module.scss +68 -0
  145. package/src/components/ds-saved-filters/components/ds-saved-filters-row/ds-saved-filters-row.tsx +83 -0
  146. package/src/components/ds-saved-filters/components/ds-saved-filters-row/index.ts +1 -0
  147. package/src/components/ds-saved-filters/components/ds-saved-filters-save.tsx +164 -0
  148. package/src/components/ds-saved-filters/components/ds-saved-filters-trigger/ds-saved-filters-trigger.module.scss +21 -0
  149. package/src/components/ds-saved-filters/components/ds-saved-filters-trigger/ds-saved-filters-trigger.tsx +237 -0
  150. package/src/components/ds-saved-filters/components/ds-saved-filters-trigger/index.ts +1 -0
  151. package/src/components/ds-saved-filters/components/index.ts +2 -0
  152. package/src/components/ds-saved-filters/ds-saved-filters.ts +6 -0
  153. package/src/components/ds-saved-filters/ds-saved-filters.types.ts +106 -0
  154. package/src/components/ds-saved-filters/ds-saved-filters.utils.ts +35 -0
  155. package/src/components/ds-saved-filters/hooks/index.ts +1 -0
  156. package/src/components/ds-saved-filters/hooks/use-picker-outside-dismiss.ts +42 -0
  157. package/src/components/ds-saved-filters/index.ts +2 -0
  158. package/src/components/ds-segment-group/ds-segment-group.module.scss +65 -37
  159. package/src/components/ds-segment-group/ds-segment-group.tsx +17 -5
  160. package/src/components/ds-segment-group/ds-segment-group.types.ts +20 -5
  161. package/src/components/ds-segment-group/figma/ds-segment-group-v2-item.figma.ts +109 -0
  162. package/src/components/ds-segment-group/figma/ds-segment-group-v2.figma.ts +31 -0
  163. package/src/components/ds-site-node/ds-site-node.tsx +2 -2
  164. package/src/components/ds-table/components/ds-table-body-virtualized/ds-table-body-virtualized.module.scss +12 -2
  165. package/src/components/ds-table/components/ds-table-body-virtualized/ds-table-body-virtualized.tsx +2 -3
  166. package/src/components/ds-table/components/ds-table-group-header-cell/ds-table-group-header-cell.module.scss +1 -6
  167. package/src/components/ds-table/components/ds-table-group-header-cell/ds-table-group-header-cell.tsx +6 -3
  168. package/src/components/ds-table/components/ds-table-header/ds-table-header.module.scss +18 -7
  169. package/src/components/ds-table/components/ds-table-header/ds-table-header.tsx +27 -21
  170. package/src/components/ds-table/components/ds-table-header-label.module.scss +12 -0
  171. package/src/components/ds-table/components/ds-table-header-label.tsx +28 -0
  172. package/src/components/ds-table/components/ds-table-row/ds-table-row.module.scss +0 -1
  173. package/src/components/ds-table/context/ds-table-context.tsx +8 -0
  174. package/src/components/ds-table/ds-table.module.scss +26 -16
  175. package/src/components/ds-table/ds-table.tsx +46 -14
  176. package/src/components/ds-table/ds-table.types.ts +33 -3
  177. package/src/components/ds-table/hooks/use-column-resize.ts +114 -11
  178. package/src/components/ds-table/hooks/use-scrollbar-spacer.ts +108 -0
  179. package/src/components/ds-table/hooks/use-scrollbar-spacer.unit.test.ts +26 -0
  180. package/src/components/ds-table/styles/_variables.scss +0 -2
  181. package/src/components/ds-table/utils/column-size.ts +274 -1
  182. package/src/components/ds-table/utils/column-size.unit.test.ts +157 -0
  183. package/src/components/ds-table/utils/constants.ts +13 -5
  184. package/src/components/ds-table/utils/table-columns.tsx +27 -13
  185. package/src/components/ds-table/utils/table-columns.unit.test.ts +44 -0
  186. package/src/components/ds-tag/ds-tag.figma.ts +23 -3
  187. package/src/components/ds-tag/ds-tag.module.scss +71 -7
  188. package/src/components/ds-tag/ds-tag.tsx +115 -14
  189. package/src/components/ds-tag/ds-tag.types.ts +70 -3
  190. package/src/components/ds-tag/ds-tag.unit.test.ts +23 -4
  191. package/src/components/ds-tag/index.ts +2 -2
  192. package/src/components/ds-text-input/ds-input-field-v02.figma.ts +2 -0
  193. package/src/components/ds-toggle/ds-toggle.module.scss +18 -0
  194. package/src/components/ds-toggle/ds-toggle.tsx +15 -9
  195. package/src/components/ds-toggle/ds-toggle.types.ts +6 -0
  196. package/src/components/ds-toggle-filter-data/ds-toggle-filter-data.module.scss +69 -0
  197. package/src/components/ds-toggle-filter-data/ds-toggle-filter-data.tsx +55 -0
  198. package/src/components/ds-toggle-filter-data/ds-toggle-filter-data.types.ts +43 -0
  199. package/src/components/ds-toggle-filter-data/index.ts +1 -0
  200. package/src/components/ds-tooltip/ds-tooltip.module.scss +8 -0
  201. package/src/components/ds-tooltip/ds-tooltip.tsx +7 -3
  202. package/src/components/ds-tooltip/ds-tooltip.types.ts +17 -0
  203. package/src/components/ds-top-bar-navigation/ds-top-bar-navigation.figma.ts +35 -0
  204. package/src/components/ds-top-bar-navigation/ds-top-bar-navigation.module.scss +150 -0
  205. package/src/components/ds-top-bar-navigation/ds-top-bar-navigation.tsx +161 -0
  206. package/src/components/ds-top-bar-navigation/ds-top-bar-navigation.types.ts +117 -0
  207. package/src/components/ds-top-bar-navigation/index.ts +2 -0
  208. package/src/components/ds-tree/ds-tree.tsx +10 -10
  209. package/src/components/ds-tree/ds-tree.types.ts +40 -7
  210. package/src/index.ts +8 -0
  211. package/src/utils/use-is-horizontally-overflowing.ts +35 -0
  212. package/src/components/ds-site-node/hooks/use-is-overflowing.ts +0 -31
  213. package/src/components/ds-table/components/ds-table-bulk-actions/ds-table-bulk-actions.module.scss +0 -112
  214. package/src/components/ds-table/components/ds-table-bulk-actions/ds-table-bulk-actions.tsx +0 -67
  215. package/src/components/ds-table/components/ds-table-bulk-actions/ds-table-bulk-actions.types.ts +0 -41
  216. package/src/components/ds-table/components/ds-table-bulk-actions/index.ts +0 -2
@@ -0,0 +1,109 @@
1
+ // url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=42657-2125
2
+ // source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-segment-group
3
+ // component=DsSegmentGroup.Item
4
+ //
5
+ // Figma `Part_SegmentItemV2` maps onto `DsSegmentGroup.Item` (see
6
+ // ds-segment-group-item.figma.ts for the V1 part). Hover / pressed / focus are
7
+ // visual-only and have no matching props.
8
+ import figma from 'figma';
9
+
10
+ const instance = figma.selectedInstance;
11
+
12
+ const state = instance.getEnum('state', {
13
+ default: 'default',
14
+ hover: 'hover',
15
+ pressed: 'pressed',
16
+ focus: 'focus',
17
+ disabled: 'disabled',
18
+ });
19
+
20
+ const structure = instance.findInstance('Structure_SegmentItemV2', { traverseInstances: true });
21
+
22
+ const iconOnly =
23
+ structure.type === 'INSTANCE' ? structure.getEnum('icon-only', { true: true, false: false }) : false;
24
+ const withIcon = structure.type === 'INSTANCE' ? structure.getBoolean('withIcon') : false;
25
+
26
+ const mediumLabel = structure.type === 'INSTANCE' ? structure.findText('SegBtn') : undefined;
27
+ const smallLabel = structure.type === 'INSTANCE' ? structure.findText('Button') : undefined;
28
+ const label =
29
+ mediumLabel?.type === 'TEXT'
30
+ ? mediumLabel.textContent
31
+ : smallLabel?.type === 'TEXT'
32
+ ? smallLabel.textContent
33
+ : 'Option';
34
+
35
+ const toIconName = (name: string): string =>
36
+ name
37
+ .replace(/^DAP_DAP_/, 'DAP_')
38
+ .replace(/^DAP_GM_[OS]_/, '')
39
+ .replace(/^DAP_outline_icon\//, '')
40
+ .replace(/^DAP_/, '')
41
+ .replace(/^\/+/, '')
42
+ .replace(/[\s/]+/g, '_')
43
+ .toLowerCase();
44
+
45
+ const iconNameFromCodeConnectId = (id: string | null): string | undefined => {
46
+ if (!id) {
47
+ return undefined;
48
+ }
49
+ if (id.startsWith('ds-icon-o-')) {
50
+ return id.slice('ds-icon-o-'.length);
51
+ }
52
+ if (id.startsWith('ds-icon-s-')) {
53
+ return id.slice('ds-icon-s-'.length);
54
+ }
55
+ return undefined;
56
+ };
57
+
58
+ const resolveIcon = (iconInstance: figma.InstanceHandle): string | undefined => {
59
+ const fromCcId = iconNameFromCodeConnectId(iconInstance.codeConnectId());
60
+ if (fromCcId) {
61
+ return fromCcId;
62
+ }
63
+
64
+ const iconFromMetadata = iconInstance.executeTemplate().metadata?.props?.icon;
65
+ if (typeof iconFromMetadata === 'string') {
66
+ return iconFromMetadata;
67
+ }
68
+
69
+ return toIconName(iconInstance.name);
70
+ };
71
+
72
+ const iconNode =
73
+ structure.type === 'INSTANCE'
74
+ ? structure
75
+ .findConnectedInstances((node) => node.codeConnectId()?.startsWith('ds-icon-') ?? false, {
76
+ traverseInstances: true,
77
+ })
78
+ .find((node): node is figma.InstanceHandle => node.type === 'INSTANCE')
79
+ : undefined;
80
+ const icon = iconNode ? resolveIcon(iconNode) : undefined;
81
+
82
+ const slug = label
83
+ .toLowerCase()
84
+ .replace(/[^a-z0-9]+/g, '-')
85
+ .replace(/^-+|-+$/g, '');
86
+ const value = slug || 'option';
87
+
88
+ const disabledAttr = state === 'disabled' ? ' disabled' : '';
89
+ const showIcon = Boolean(icon && (iconOnly || withIcon));
90
+
91
+ export default {
92
+ example:
93
+ iconOnly && icon
94
+ ? figma.code`<DsSegmentGroup.Item value="${value}" aria-label="${label}"${disabledAttr}>
95
+ <DsIcon icon="${icon}" size="tiny" color="main" />
96
+ </DsSegmentGroup.Item>`
97
+ : showIcon && icon
98
+ ? figma.code`<DsSegmentGroup.Item value="${value}"${disabledAttr}>
99
+ <DsIcon icon="${icon}" size="tiny" color="main" />
100
+ <DsSegmentGroup.ItemText>${label}</DsSegmentGroup.ItemText>
101
+ </DsSegmentGroup.Item>`
102
+ : figma.code`<DsSegmentGroup.Item value="${value}" label="${label}"${disabledAttr} />`,
103
+ imports:
104
+ showIcon || iconOnly
105
+ ? ["import { DsIcon, DsSegmentGroup } from '@drivenets/design-system';"]
106
+ : ["import { DsSegmentGroup } from '@drivenets/design-system';"],
107
+ id: 'ds-segment-group-v2-item',
108
+ metadata: { nestable: true },
109
+ } satisfies figma.Template;
@@ -0,0 +1,31 @@
1
+ // url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=42663-2224
2
+ // source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-segment-group
3
+ // component=DsSegmentGroup.Root
4
+ //
5
+ // Figma ships `DsSegmentGroupV2` alongside `DsSegmentGroupV1`. Both map onto the
6
+ // same code component (see ds-segment-group.figma.ts for the older set).
7
+ import figma from 'figma';
8
+
9
+ const instance = figma.selectedInstance;
10
+
11
+ const size = instance.getEnum('Size', {
12
+ medium: 'medium',
13
+ small: 'small',
14
+ });
15
+
16
+ const sizeAttr = size === 'small' ? ' size="small"' : '';
17
+
18
+ // `Slot` is homogeneous `Part_SegmentItemV2` instances. Interpolating the slot
19
+ // object itself renders a clickable "Slot" label; execute each child's template
20
+ // so the parent snippet inline `DsSegmentGroup.Item`.
21
+ const slot = instance.getSlot('Slot');
22
+ const items = (slot?.connectedInstances ?? []).map((item) => item.executeTemplate().example);
23
+
24
+ export default {
25
+ example: figma.code`<DsSegmentGroup.Root${sizeAttr}>
26
+ ${items}
27
+ </DsSegmentGroup.Root>`,
28
+ imports: ["import { DsSegmentGroup } from '@drivenets/design-system';"],
29
+ id: 'ds-segment-group-v2',
30
+ metadata: { nestable: false },
31
+ } satisfies figma.Template;
@@ -1,6 +1,6 @@
1
1
  import classNames from 'classnames';
2
2
  import type { DsSiteNodeProps } from './ds-site-node.types';
3
- import { useIsOverflowing } from './hooks/use-is-overflowing';
3
+ import { useIsHorizontallyOverflowing } from '../../utils/use-is-horizontally-overflowing';
4
4
  import { DsStack } from '../ds-stack';
5
5
  import { DsTooltip } from '../ds-tooltip';
6
6
  import { DsTypography } from '../ds-typography';
@@ -21,7 +21,7 @@ const DsSiteNode = ({
21
21
  const isSelected = state === 'selected';
22
22
  const isMuted = state === 'muted';
23
23
 
24
- const { ref: siteCodeRef, isOverflowing } = useIsOverflowing<HTMLSpanElement>(siteCode);
24
+ const { ref: siteCodeRef, isOverflowing } = useIsHorizontallyOverflowing<HTMLSpanElement>(siteCode);
25
25
 
26
26
  return (
27
27
  <button
@@ -4,9 +4,10 @@
4
4
  display: block;
5
5
  position: relative;
6
6
  overflow-y: auto;
7
+ overflow-x: hidden;
7
8
  flex: 1;
8
9
  min-height: 0;
9
- scrollbar-gutter: stable;
10
+ scrollbar-gutter: auto;
10
11
 
11
12
  @include scrollbars.scrollbar-on-hover;
12
13
  }
@@ -22,7 +23,16 @@
22
23
  visibility: hidden;
23
24
  }
24
25
 
25
- .emptyState {
26
+ .emptyStateRow {
26
27
  position: absolute;
27
28
  inset: 0;
28
29
  }
30
+
31
+ .emptyState {
32
+ display: flex;
33
+ align-items: center;
34
+ justify-content: center;
35
+ width: 100%;
36
+ height: 100%;
37
+ text-align: center;
38
+ }
@@ -5,7 +5,6 @@ import styles from './ds-table-body-virtualized.module.scss';
5
5
  import { DsTableRowVirtualized } from '../ds-table-row-virtualized';
6
6
  import type { DsTableBodyVirtualizedProps } from './ds-table-body-virtualized.types';
7
7
  import { TableBody, TableRow, TableCell } from '../core-table';
8
- import { EMPTY_TABLE_STATE_TEXT } from '../../utils/constants';
9
8
  import { useInfiniteScroll } from './use-infinite-scroll';
10
9
 
11
10
  export const DsTableBodyVirtualized = <TData,>({
@@ -150,8 +149,8 @@ export function DsTableBody<TData>({
150
149
  );
151
150
  })
152
151
  ) : hasNoData ? (
153
- <TableRow>
154
- <TableCell className={styles.emptyState}>{emptyState || EMPTY_TABLE_STATE_TEXT}</TableCell>
152
+ <TableRow className={styles.emptyStateRow}>
153
+ <TableCell className={styles.emptyState}>{emptyState}</TableCell>
155
154
  </TableRow>
156
155
  ) : null}
157
156
 
@@ -20,16 +20,11 @@
20
20
  justify-content: space-between;
21
21
  gap: vars.$header-sort-gap;
22
22
  width: 100%;
23
+ min-width: 0;
23
24
  height: 100%;
24
25
  padding: 0 var(--standard);
25
26
  }
26
27
 
27
- .groupLabel {
28
- overflow: hidden;
29
- text-overflow: ellipsis;
30
- white-space: nowrap;
31
- }
32
-
33
28
  .collapseToggle {
34
29
  flex-shrink: 0;
35
30
  }
@@ -5,6 +5,7 @@ import { useDsTableContext } from '../../context/ds-table-context';
5
5
  import { getGroupColumnSizeStyle } from '../../grouping';
6
6
  import { getResizableHeaderStyle } from '../../utils/column-size';
7
7
  import { defaultDsTableLocale } from '../../ds-table.types';
8
+ import { DsTableHeaderLabel } from '../ds-table-header-label';
8
9
  import { DsTableResizeHandle } from '../ds-table-resize-handle';
9
10
  import type { DsTableGroupHeaderCellProps } from './ds-table-group-header-cell.types';
10
11
  import styles from './ds-table-group-header-cell.module.scss';
@@ -29,6 +30,8 @@ export const DsTableGroupHeaderCell = <TData, TValue>({
29
30
  const toggleLabel = isCollapsed ? mergedLocale.expandColumnGroup : mergedLocale.collapseColumnGroup;
30
31
 
31
32
  const handleToggle = () => onToggleColumnGroup?.(groupId);
33
+ const headerDef = header.column.columnDef.header;
34
+ const tooltipText = typeof headerDef === 'string' ? headerDef : undefined;
32
35
 
33
36
  return (
34
37
  <TableHead
@@ -38,9 +41,9 @@ export const DsTableGroupHeaderCell = <TData, TValue>({
38
41
  colSpan={header.colSpan}
39
42
  >
40
43
  <div className={styles.groupHeaderContent}>
41
- <span className={styles.groupLabel}>
42
- {flexRender(header.column.columnDef.header, header.getContext())}
43
- </span>
44
+ <DsTableHeaderLabel tooltipText={tooltipText}>
45
+ {flexRender(headerDef, header.getContext())}
46
+ </DsTableHeaderLabel>
44
47
  {isCollapsible && (
45
48
  <DsButtonV3
46
49
  variant="secondary"
@@ -15,6 +15,10 @@
15
15
  border-bottom: 1px solid var(--color-dap-gray-400);
16
16
  }
17
17
 
18
+ .scrollbarSpacer:not(.scrollbarSpacerOccupied) {
19
+ border-bottom: none;
20
+ }
21
+
18
22
  &.headerRowNoBorder {
19
23
  .headerCell {
20
24
  border-bottom: none;
@@ -42,6 +46,7 @@
42
46
 
43
47
  .pageButtonIconContainer {
44
48
  display: flex;
49
+ flex-shrink: 0;
45
50
  align-items: center;
46
51
  justify-content: center;
47
52
  width: 24px;
@@ -54,9 +59,18 @@
54
59
  }
55
60
  }
56
61
 
62
+ .scrollbarSpacer {
63
+ flex-shrink: 0;
64
+ padding: 0;
65
+ overflow: hidden;
66
+ border-left: none;
67
+ pointer-events: none;
68
+ }
69
+
57
70
  .selectHeaderCell {
58
71
  padding: 0;
59
72
  justify-content: center;
73
+ text-align: center;
60
74
  }
61
75
 
62
76
  .groupStart:not(:first-child) {
@@ -68,7 +82,10 @@
68
82
  align-items: center;
69
83
  justify-content: space-between;
70
84
  gap: vars.$header-sort-gap;
85
+ width: 100%;
86
+ min-width: 0;
71
87
  height: 100%;
88
+ overflow: hidden;
72
89
  }
73
90
 
74
91
  .headerLabelStack {
@@ -76,15 +93,9 @@
76
93
  overflow: hidden;
77
94
  }
78
95
 
79
- .headerLabel {
80
- display: block;
81
- overflow: hidden;
82
- text-overflow: ellipsis;
83
- white-space: nowrap;
84
- }
85
-
86
96
  .filterTriggerContainer {
87
97
  display: inline-flex;
98
+ flex-shrink: 0;
88
99
  align-items: center;
89
100
  margin-left: vars.$header-sort-gap;
90
101
  }
@@ -12,11 +12,13 @@ import { DsStack } from '../../../ds-stack';
12
12
  import { DsTableColumnFilterPopover } from '../../filters/components/column-filter-popover';
13
13
  import type { ResolvedColumnFilter } from '../../filters/types/filter-adapter.types';
14
14
  import { DsTableGroupHeaderCell } from '../ds-table-group-header-cell';
15
+ import { DsTableHeaderLabel } from '../ds-table-header-label';
15
16
  import { DsTableResizeHandle } from '../ds-table-resize-handle';
16
17
  import { isFirstLeafColumnOfGroup } from '../../grouping';
17
18
 
18
19
  const DsTableHeader = <TData,>({ table }: DsTableHeaderProps<TData>) => {
19
- const { bordered, virtualized, resizableColumns, resizeSizingReady } = useDsTableContext<TData, unknown>();
20
+ const { bordered, virtualized, resizableColumns, resizeSizingReady, scrollbarSpacerWidth } =
21
+ useDsTableContext<TData, unknown>();
20
22
 
21
23
  return (
22
24
  <TableHeader className={classnames(styles.header, virtualized && styles.virtualizedHeader)}>
@@ -58,6 +60,7 @@ const DsTableHeader = <TData,>({ table }: DsTableHeaderProps<TData>) => {
58
60
  !!resizeSizingReady,
59
61
  );
60
62
  const canSort = header.column.getCanSort();
63
+ const sortDirection = header.column.getIsSorted();
61
64
  const canResize = resizableColumns && header.column.getCanResize();
62
65
  const isSelectColumn = header.column.id === SELECT_COLUMN_ID;
63
66
  const isGroupStart = isFirstLeafColumnOfGroup(header.column);
@@ -66,6 +69,8 @@ const DsTableHeader = <TData,>({ table }: DsTableHeaderProps<TData>) => {
66
69
  const resolvedFilter: ResolvedColumnFilter | undefined =
67
70
  metaFilter && 'render' in metaFilter ? metaFilter : undefined;
68
71
  const hasActiveColumnFilter = resolvedFilter?.hasActiveFilter ?? false;
72
+ const headerDef = header.column.columnDef.header;
73
+ const tooltipText = typeof headerDef === 'string' ? headerDef : undefined;
69
74
 
70
75
  return (
71
76
  <TableHead
@@ -89,28 +94,16 @@ const DsTableHeader = <TData,>({ table }: DsTableHeaderProps<TData>) => {
89
94
  width="100%"
90
95
  className={styles.headerLabelStack}
91
96
  >
92
- <span className={styles.headerLabel}>
93
- {flexRender(header.column.columnDef.header, header.getContext())}
94
- </span>
97
+ <DsTableHeaderLabel tooltipText={tooltipText}>
98
+ {flexRender(headerDef, header.getContext())}
99
+ </DsTableHeaderLabel>
95
100
  </DsStack>
96
- {canSort && (
101
+ {canSort && sortDirection && (
97
102
  <div className={styles.pageButtonIconContainer}>
98
- {{
99
- asc: (
100
- <DsIcon
101
- icon="arrow_drop_up"
102
- className={classnames(styles.pageButtonIcon, stylesShared.pageButtonIcon)}
103
- />
104
- ),
105
- desc: (
106
- <DsIcon
107
- icon="arrow_drop_down"
108
- className={classnames(styles.pageButtonIcon, stylesShared.pageButtonIcon)}
109
- />
110
- ),
111
- }[header.column.getIsSorted() as string] ?? (
112
- <div className={classnames(styles.pageButtonIcon, stylesShared.pageButtonIcon)} />
113
- )}
103
+ <DsIcon
104
+ icon={sortDirection === 'asc' ? 'arrow_drop_up' : 'arrow_drop_down'}
105
+ className={classnames(styles.pageButtonIcon, stylesShared.pageButtonIcon)}
106
+ />
114
107
  </div>
115
108
  )}
116
109
  {resolvedFilter && (
@@ -130,6 +123,19 @@ const DsTableHeader = <TData,>({ table }: DsTableHeaderProps<TData>) => {
130
123
  </TableHead>
131
124
  );
132
125
  })}
126
+ <TableHead
127
+ aria-hidden
128
+ className={classnames(
129
+ styles.headerCell,
130
+ styles.scrollbarSpacer,
131
+ scrollbarSpacerWidth > 0 && styles.scrollbarSpacerOccupied,
132
+ )}
133
+ style={{
134
+ width: scrollbarSpacerWidth,
135
+ minWidth: scrollbarSpacerWidth,
136
+ flexShrink: 0,
137
+ }}
138
+ />
133
139
  </TableRow>
134
140
  ))}
135
141
  </TableHeader>
@@ -0,0 +1,12 @@
1
+ @use '../../../styles/typography';
2
+
3
+ .headerLabel {
4
+ display: block;
5
+ min-width: 0;
6
+ }
7
+
8
+ .headerLabelInner {
9
+ display: block;
10
+ min-width: 0;
11
+ @include typography.ellipsis;
12
+ }
@@ -0,0 +1,28 @@
1
+ import type { ReactNode } from 'react';
2
+ import classnames from 'classnames';
3
+ import { DsTooltip } from '../../ds-tooltip';
4
+ import { useIsHorizontallyOverflowing } from '../../../utils/use-is-horizontally-overflowing';
5
+ import styles from './ds-table-header-label.module.scss';
6
+
7
+ type DsTableHeaderLabelProps = {
8
+ children: ReactNode;
9
+ tooltipText?: string;
10
+ className?: string;
11
+ };
12
+
13
+ export const DsTableHeaderLabel = ({ className, children, tooltipText }: DsTableHeaderLabelProps) => {
14
+ const { ref, isOverflowing } = useIsHorizontallyOverflowing<HTMLSpanElement>(tooltipText);
15
+ const title = isOverflowing ? tooltipText : undefined;
16
+
17
+ return (
18
+ <span className={classnames(styles.headerLabel, className)}>
19
+ <DsTooltip content={title} placement="top">
20
+ <span ref={ref} className={styles.headerLabelInner}>
21
+ {children}
22
+ </span>
23
+ </DsTooltip>
24
+ </span>
25
+ );
26
+ };
27
+
28
+ DsTableHeaderLabel.displayName = 'DsTableHeaderLabel';
@@ -59,7 +59,6 @@
59
59
  }
60
60
 
61
61
  .cellReorder {
62
- width: vars.$reorder-column-width;
63
62
  text-align: center;
64
63
 
65
64
  &.isDragging {
@@ -2,6 +2,7 @@ import { createContext, useContext, useMemo, type ReactNode, type RefObject } fr
2
2
  import type { DsDataTableProps, DsTableRowSize } from '../ds-table.types';
3
3
  import type { DsTablePropsWithDefaults } from '../ds-table-defaults';
4
4
  import type { DsTableResizeContextSlice } from '../hooks/use-column-resize';
5
+ import type { ScrollbarSpacerWidth } from '../hooks/use-scrollbar-spacer';
5
6
  import { useEditingState, type UseEditingStateResult } from '../hooks/use-editing-state';
6
7
 
7
8
  /** Visual phase of the full-height column-resize divider. */
@@ -56,6 +57,10 @@ export interface DsTableContextType<TData, TValue>
56
57
  * boundary header's column (leaf or group). Clamps and fires persist.
57
58
  */
58
59
  onResizeKeyboardNudge?: (columnId: string, delta: number) => void;
60
+ /**
61
+ * Overflow-only **Scrollbar spacer** width (0 or rest scrollbar size).
62
+ */
63
+ scrollbarSpacerWidth: ScrollbarSpacerWidth;
59
64
  }
60
65
 
61
66
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -124,6 +129,7 @@ export const DsTableContextProvider = <TData, TValue>({
124
129
  onResizeDragStart,
125
130
  onResizeReset,
126
131
  onResizeKeyboardNudge,
132
+ scrollbarSpacerWidth,
127
133
  } = derived.resize;
128
134
 
129
135
  const { editing, beginEdit, setDraft, commit, cancel } = useEditingState<TData, TValue>(
@@ -160,6 +166,7 @@ export const DsTableContextProvider = <TData, TValue>({
160
166
  onResizeDragStart,
161
167
  onResizeReset,
162
168
  onResizeKeyboardNudge,
169
+ scrollbarSpacerWidth,
163
170
  editing,
164
171
  beginEdit,
165
172
  setDraft,
@@ -194,6 +201,7 @@ export const DsTableContextProvider = <TData, TValue>({
194
201
  onResizeDragStart,
195
202
  onResizeReset,
196
203
  onResizeKeyboardNudge,
204
+ scrollbarSpacerWidth,
197
205
  editing,
198
206
  beginEdit,
199
207
  setDraft,
@@ -58,10 +58,7 @@ $bulk-actions-reserved-space: 80px;
58
58
  thead {
59
59
  display: block;
60
60
  flex-shrink: 0;
61
- overflow-y: scroll;
62
- scrollbar-gutter: stable;
63
-
64
- @include scrollbars.scrollbar-on-hover;
61
+ overflow-y: hidden;
65
62
  }
66
63
 
67
64
  tbody {
@@ -70,14 +67,24 @@ $bulk-actions-reserved-space: 80px;
70
67
  overflow-x: hidden;
71
68
  flex: 1;
72
69
  min-height: 0;
73
- scrollbar-gutter: stable;
70
+ scrollbar-gutter: auto;
74
71
 
75
72
  @include scrollbars.scrollbar-on-hover;
73
+
74
+ &:has(.emptyState) {
75
+ display: flex;
76
+ flex-direction: column;
77
+ }
76
78
  }
77
79
 
78
80
  thead tr,
79
81
  tbody tr {
80
82
  display: flex;
83
+ width: 100%;
84
+ }
85
+
86
+ tbody tr {
87
+ padding-inline-end: var(--ds-table-body-scrollbar-compensation, 0px);
81
88
  }
82
89
 
83
90
  thead th,
@@ -109,18 +116,19 @@ $bulk-actions-reserved-space: 80px;
109
116
  }
110
117
  }
111
118
 
119
+ .emptyStateRow {
120
+ flex: 1;
121
+ align-items: center;
122
+ }
123
+
112
124
  .emptyState {
113
125
  // colSpan in markup isn't honored by flex row layout, so the cell stretches
114
- // across the row; stretch the inner content so it occupies full table width
126
+ // across the row; center the Empty state in the remaining body
115
127
  flex: 1;
116
128
  min-width: 0;
117
- height: vars.$empty-state-height;
118
129
  justify-content: center;
130
+ align-items: center;
119
131
  text-align: center;
120
-
121
- > * {
122
- flex: 1;
123
- }
124
132
  }
125
133
 
126
134
  .virtualizedContainer {
@@ -145,20 +153,22 @@ $bulk-actions-reserved-space: 80px;
145
153
  thead {
146
154
  display: block;
147
155
  flex-shrink: 0;
148
- overflow-y: scroll;
149
- scrollbar-gutter: stable;
150
-
151
- @include scrollbars.scrollbar-on-hover;
156
+ overflow-y: hidden;
152
157
  }
153
158
 
154
159
  tbody {
155
160
  flex: 1;
156
161
  min-height: 0;
157
- scrollbar-gutter: stable;
162
+ scrollbar-gutter: auto;
158
163
  }
159
164
 
160
165
  thead tr {
161
166
  display: flex;
167
+ width: 100%;
168
+ }
169
+
170
+ tbody tr {
171
+ padding-inline-end: var(--ds-table-body-scrollbar-compensation, 0px);
162
172
  }
163
173
 
164
174
  thead th {