@drivenets/design-system 0.17.0 → 0.18.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 (94) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/index.cjs +1727 -701
  3. package/dist/index.d.cts +115 -52
  4. package/dist/index.d.cts.map +1 -1
  5. package/dist/index.d.ts +115 -52
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +1729 -705
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.min.css +1 -1
  10. package/package.json +2 -2
  11. package/src/components/ds-alert-banner/ds-alert-banner-global.figma.ts +49 -0
  12. package/src/components/ds-alert-banner/ds-alert-banner.figma.ts +51 -0
  13. package/src/components/ds-autocomplete/ds-autocomplete.module.scss +15 -4
  14. package/src/components/ds-autocomplete/ds-autocomplete.tsx +10 -3
  15. package/src/components/ds-autocomplete/ds-autocomplete.types.ts +8 -0
  16. package/src/components/ds-button-v3/ds-button-v3.figma.ts +5 -3
  17. package/src/components/ds-button-v3/ds-button-v3.module.scss +84 -17
  18. package/src/components/ds-button-v3/ds-button-v3.tsx +2 -0
  19. package/src/components/ds-button-v3/ds-button-v3.types.ts +11 -2
  20. package/src/components/ds-button-v3/ds-button-v4.figma.ts +121 -0
  21. package/src/components/ds-comment-bubble/ds-comment-bubble.figma.ts +52 -0
  22. package/src/components/ds-comment-card/ds-comment-card.figma.ts +36 -0
  23. package/src/components/ds-comment-indicator/ds-comment-indicator.figma.ts +32 -0
  24. package/src/components/ds-comments-drawer/ds-comments-drawer.figma.ts +19 -0
  25. package/src/components/ds-select/ds-select.figma.ts +2 -1
  26. package/src/components/ds-select/ds-select.tsx +6 -1
  27. package/src/components/ds-select/ds-select.types.ts +2 -1
  28. package/src/components/ds-slider/ds-slider.figma.ts +29 -0
  29. package/src/components/ds-slider/ds-slider.module.scss +104 -0
  30. package/src/components/ds-slider/ds-slider.tsx +118 -0
  31. package/src/components/ds-slider/ds-slider.types.ts +102 -0
  32. package/src/components/ds-slider/ds-slider.utils.ts +14 -0
  33. package/src/components/ds-slider/index.ts +11 -0
  34. package/src/components/ds-smart-tabs/figma/ds-smart-tabs-tab.figma.ts +83 -0
  35. package/src/components/ds-smart-tabs/figma/ds-smart-tabs.figma.ts +23 -0
  36. package/src/components/ds-table/components/ds-table-group-header-cell/ds-table-group-header-cell.module.scss +5 -1
  37. package/src/components/ds-table/components/ds-table-group-header-cell/ds-table-group-header-cell.tsx +15 -3
  38. package/src/components/ds-table/components/ds-table-header/ds-table-header.module.scss +15 -1
  39. package/src/components/ds-table/components/ds-table-header/ds-table-header.tsx +29 -6
  40. package/src/components/ds-table/components/ds-table-resize-handle/ds-table-resize-handle.module.scss +23 -0
  41. package/src/components/ds-table/components/ds-table-resize-handle/ds-table-resize-handle.tsx +218 -0
  42. package/src/components/ds-table/components/ds-table-resize-handle/ds-table-resize-handle.types.ts +14 -0
  43. package/src/components/ds-table/components/ds-table-resize-handle/index.ts +1 -0
  44. package/src/components/ds-table/components/ds-table-resize-overlay/ds-table-resize-overlay.module.scss +18 -0
  45. package/src/components/ds-table/components/ds-table-resize-overlay/ds-table-resize-overlay.tsx +16 -0
  46. package/src/components/ds-table/components/ds-table-resize-overlay/ds-table-resize-overlay.types.ts +13 -0
  47. package/src/components/ds-table/components/ds-table-resize-overlay/index.ts +1 -0
  48. package/src/components/ds-table/components/ds-table-row/ds-table-row.module.scss +1 -1
  49. package/src/components/ds-table/components/ds-table-row/ds-table-row.tsx +9 -2
  50. package/src/components/ds-table/components/ds-table-row-virtualized/ds-table-row-virtualized.module.scss +2 -1
  51. package/src/components/ds-table/components/ds-table-row-virtualized/ds-table-row-virtualized.tsx +9 -2
  52. package/src/components/ds-table/components/edit/cell-editors/ds-table-edit-cell-checkbox.tsx +2 -2
  53. package/src/components/ds-table/components/edit/cell-editors/ds-table-edit-cell-date.tsx +2 -1
  54. package/src/components/ds-table/components/edit/cell-editors/ds-table-edit-cell-number.tsx +2 -1
  55. package/src/components/ds-table/components/edit/cell-editors/ds-table-edit-cell-select.tsx +2 -1
  56. package/src/components/ds-table/components/edit/cell-editors/ds-table-edit-cell-text.tsx +2 -1
  57. package/src/components/ds-table/components/edit/ds-table-editing-cell/ds-table-editing-cell.tsx +12 -3
  58. package/src/components/ds-table/context/ds-table-context.tsx +208 -0
  59. package/src/components/ds-table/ds-table-defaults.ts +42 -0
  60. package/src/components/ds-table/ds-table.module.scss +4 -1
  61. package/src/components/ds-table/ds-table.tsx +139 -214
  62. package/src/components/ds-table/ds-table.types.ts +53 -47
  63. package/src/components/ds-table/grouping/utils/column-group.ts +7 -5
  64. package/src/components/ds-table/hooks/use-cell-editor.ts +5 -1
  65. package/src/components/ds-table/hooks/use-column-resize.ts +385 -0
  66. package/src/components/ds-table/hooks/use-editing-state.ts +190 -0
  67. package/src/components/ds-table/index.ts +1 -0
  68. package/src/components/ds-table/styles/_variables.scss +2 -1
  69. package/src/components/ds-table/utils/column-size-meta.augmentation.ts +16 -0
  70. package/src/components/ds-table/utils/column-size.ts +213 -10
  71. package/src/components/ds-table/utils/column-size.unit.test.ts +213 -0
  72. package/src/components/ds-table/utils/constants.ts +28 -0
  73. package/src/components/ds-table/utils/frozen-body.ts +33 -0
  74. package/src/components/ds-table/utils/frozen-body.unit.test.ts +44 -0
  75. package/src/components/ds-table/utils/table-api.ts +42 -0
  76. package/src/components/ds-table/utils/table-api.unit.test.ts +82 -0
  77. package/src/components/ds-table/utils/table-columns.tsx +119 -0
  78. package/src/components/ds-table/utils/table-columns.unit.test.ts +199 -0
  79. package/src/components/ds-tag/ds-tag.figma.ts +51 -0
  80. package/src/components/ds-tag-filter/ds-tag-filter.figma.ts +16 -0
  81. package/src/components/ds-text-input/ds-input-field-v02.figma.ts +29 -4
  82. package/src/components/ds-text-input/ds-text-input.figma.ts +3 -2
  83. package/src/components/ds-text-input/ds-text-input.tsx +1 -0
  84. package/src/components/ds-text-input/ds-text-input.types.ts +1 -1
  85. package/src/components/ds-tree/ds-tree.figma.ts +54 -0
  86. package/src/components/ds-workspace-layout/ds-workspace-layout.figma.ts +99 -0
  87. package/src/components/ds-workspace-layout/ds-workspace-layout.module.scss +1 -8
  88. package/src/index.ts +1 -0
  89. package/src/styles/_gradients.scss +19 -0
  90. package/src/styles/_root.scss +39 -15
  91. package/src/styles/_typography.scss +1 -0
  92. package/src/styles/shared/_input.scss +10 -0
  93. package/src/styles/styles.scss +1 -0
  94. package/src/components/ds-table/context/ds-table-context.ts +0 -112
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drivenets/design-system",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.cts",
@@ -107,7 +107,7 @@
107
107
  "vitest-browser-react": "^2.1.0",
108
108
  "zod": "^4.4.3",
109
109
  "@drivenets/eslint-plugin-internal": "0.0.0",
110
- "@drivenets/vite-plugin-design-system": "0.0.10"
110
+ "@drivenets/vite-plugin-design-system": "0.0.11"
111
111
  },
112
112
  "scripts": {
113
113
  "start": "storybook dev -p 6006",
@@ -0,0 +1,49 @@
1
+ // url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=15271-7357
2
+ // source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-alert-banner
3
+ // component=DsAlertBanner
4
+ //
5
+ // `DsAlertBannerGlobalV1` is the full-width bar pinned to the top of the viewport. It
6
+ // maps to the same `DsAlertBanner` as the inline card but without `inline` (the
7
+ // default `global` layout) and with no title. See `ds-alert-banner.figma.ts` for the
8
+ // inline variant.
9
+ import figma from 'figma';
10
+
11
+ const instance = figma.selectedInstance;
12
+
13
+ const variant = instance.getEnum('Type', {
14
+ 'info neutral': 'info-neutral',
15
+ 'info blue': 'info-blue',
16
+ warning: 'warning',
17
+ error: 'error',
18
+ success: 'success',
19
+ });
20
+
21
+ // The status icon is set automatically by `Type` in Figma; mirror that mapping so the
22
+ // snippet passes the matching `DsIcon` name.
23
+ const icon = instance.getEnum('Type', {
24
+ 'info neutral': 'info',
25
+ 'info blue': 'info',
26
+ warning: 'warning',
27
+ error: 'error',
28
+ success: 'check_circle',
29
+ });
30
+
31
+ const closable = instance.getBoolean('Show Dismiss Button');
32
+ const showActions = instance.getBoolean('Show Actions');
33
+
34
+ const closableAttr = closable ? ' closable' : '';
35
+ const actionsBlock = showActions
36
+ ? `\n\t<DsAlertBanner.Actions>\n\t\t<DsButtonV3 variant="secondary" size="small">Action</DsButtonV3>\n\t</DsAlertBanner.Actions>`
37
+ : '';
38
+
39
+ export default {
40
+ example: figma.code`<DsAlertBanner open onOpenChange={() => {}} variant="${variant}" icon="${icon}"${closableAttr}>
41
+ <DsAlertBanner.Body>Description</DsAlertBanner.Body>${actionsBlock}
42
+ </DsAlertBanner>`,
43
+ imports: [
44
+ "import { DsAlertBanner } from '@drivenets/design-system';",
45
+ "import { DsButtonV3 } from '@drivenets/design-system';",
46
+ ],
47
+ id: 'ds-alert-banner-global',
48
+ metadata: { nestable: false },
49
+ } satisfies figma.Template;
@@ -0,0 +1,51 @@
1
+ // url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=14850-7088
2
+ // source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-alert-banner
3
+ // component=DsAlertBanner
4
+ //
5
+ // `DsAlertBannerInlineV1` is the inline (bordered card) banner that sits in normal
6
+ // document flow. It maps to the controlled `DsAlertBanner` with `inline`. The
7
+ // full-width, top-of-viewport `DsAlertBannerGlobalV1` maps to the same component
8
+ // without `inline` — see `ds-alert-banner-global.figma.ts`.
9
+ import figma from 'figma';
10
+
11
+ const instance = figma.selectedInstance;
12
+
13
+ const variant = instance.getEnum('Type', {
14
+ 'Info Neutral': 'info-neutral',
15
+ 'Info Blue': 'info-blue',
16
+ Warning: 'warning',
17
+ Error: 'error',
18
+ Success: 'success',
19
+ });
20
+
21
+ // The status icon is set automatically by `Type` in Figma; mirror that mapping so the
22
+ // snippet passes the matching `DsIcon` name.
23
+ const icon = instance.getEnum('Type', {
24
+ 'Info Neutral': 'info',
25
+ 'Info Blue': 'info',
26
+ Warning: 'warning',
27
+ Error: 'error',
28
+ Success: 'check_circle',
29
+ });
30
+
31
+ const closable = instance.getBoolean('Show Dismiss Button');
32
+ const showTitle = instance.getBoolean('Show Titles');
33
+ const showActions = instance.getBoolean('Show Actions');
34
+
35
+ const closableAttr = closable ? ' closable' : '';
36
+ const titleLine = showTitle ? `\n\t<DsAlertBanner.Title>Title</DsAlertBanner.Title>` : '';
37
+ const actionsBlock = showActions
38
+ ? `\n\t<DsAlertBanner.Actions>\n\t\t<DsButtonV3 variant="secondary" size="small">Action</DsButtonV3>\n\t</DsAlertBanner.Actions>`
39
+ : '';
40
+
41
+ export default {
42
+ example: figma.code`<DsAlertBanner open onOpenChange={() => {}} inline variant="${variant}" icon="${icon}"${closableAttr}>${titleLine}
43
+ <DsAlertBanner.Body>Description</DsAlertBanner.Body>${actionsBlock}
44
+ </DsAlertBanner>`,
45
+ imports: [
46
+ "import { DsAlertBanner } from '@drivenets/design-system';",
47
+ "import { DsButtonV3 } from '@drivenets/design-system';",
48
+ ],
49
+ id: 'ds-alert-banner',
50
+ metadata: { nestable: false },
51
+ } satisfies figma.Template;
@@ -1,7 +1,6 @@
1
1
  @use '../../styles/shared/dropdown';
2
2
  @use '../../styles/shared/input';
3
3
 
4
- $autocomplete-input-height: 36px;
5
4
  $autocomplete-max-visible-items: 4;
6
5
  $autocomplete-item-height: 38px;
7
6
  $autocomplete-dropdown-max-height: calc($autocomplete-max-visible-items * $autocomplete-item-height);
@@ -29,9 +28,21 @@ $autocomplete-opacity-visible: 1;
29
28
  display: flex;
30
29
  align-items: center;
31
30
  gap: var(--3xs);
32
- height: $autocomplete-input-height;
33
- min-height: $autocomplete-input-height;
34
- max-height: $autocomplete-input-height;
31
+ height: input.$input-text-height-default;
32
+ min-height: input.$input-text-height-default;
33
+ max-height: input.$input-text-height-default;
34
+
35
+ &.small {
36
+ height: input.$input-text-height-small;
37
+ min-height: input.$input-text-height-small;
38
+ max-height: input.$input-text-height-small;
39
+ }
40
+
41
+ &.large {
42
+ height: input.$input-text-height-large;
43
+ min-height: input.$input-text-height-large;
44
+ max-height: input.$input-text-height-large;
45
+ }
35
46
 
36
47
  &[data-focus] {
37
48
  border-color: var(--form-control-border-color, var(--border-action-primary)) !important;
@@ -12,6 +12,7 @@ export const DsAutocomplete = ({
12
12
  id,
13
13
  options = [],
14
14
  loading = false,
15
+ size = 'default',
15
16
  style,
16
17
  className,
17
18
  placeholder = 'Start typing to search...',
@@ -74,7 +75,13 @@ export const DsAutocomplete = ({
74
75
  onOpenChange={handleOpenChange}
75
76
  closeOnSelect
76
77
  >
77
- <Combobox.Control className={styles.control}>
78
+ <Combobox.Control
79
+ className={classNames(
80
+ styles.control,
81
+ size === 'small' && styles.small,
82
+ size === 'large' && styles.large,
83
+ )}
84
+ >
78
85
  {startAdornment && <span className={styles.startAdornment}>{startAdornment}</span>}
79
86
 
80
87
  <Combobox.Input className={styles.input} placeholder={placeholder} />
@@ -92,13 +99,13 @@ export const DsAutocomplete = ({
92
99
  combobox.setInputValue('');
93
100
  }}
94
101
  >
95
- <DsIcon icon="close" size="medium" />
102
+ <DsIcon icon="close" size={size === 'small' ? 'small' : 'medium'} />
96
103
  </button>
97
104
  )}
98
105
 
99
106
  {showTrigger && (
100
107
  <Combobox.Trigger className={styles.trigger} aria-label="Toggle dropdown">
101
- <DsIcon icon="keyboard_arrow_down" size="medium" />
108
+ <DsIcon icon="keyboard_arrow_down" size={size === 'small' ? 'small' : 'medium'} />
102
109
  </Combobox.Trigger>
103
110
  )}
104
111
  </div>
@@ -1,6 +1,9 @@
1
1
  import type React from 'react';
2
2
  import type { IconName } from '../ds-icon';
3
3
 
4
+ export const autocompleteSizes = ['small', 'default', 'large'] as const;
5
+ export type AutocompleteSize = (typeof autocompleteSizes)[number];
6
+
4
7
  export interface DsAutocompleteOption {
5
8
  /**
6
9
  * Label to display in the autocomplete dropdown
@@ -31,6 +34,11 @@ export interface DsAutocompleteProps {
31
34
  * When true, a loading message is shown in the dropdown.
32
35
  */
33
36
  loading?: boolean;
37
+ /**
38
+ * The size of the autocomplete control
39
+ * @default 'default'
40
+ */
41
+ size?: AutocompleteSize;
34
42
 
35
43
  /**
36
44
  * Additional styles to apply to the component
@@ -7,6 +7,7 @@ const instance = figma.selectedInstance;
7
7
 
8
8
  const variant = instance.getEnum('buttonType', {
9
9
  primary: 'primary',
10
+ 'primary-subtle': 'primary-subtle',
10
11
  secondary: 'secondary',
11
12
  tertiary: 'tertiary',
12
13
  });
@@ -86,13 +87,14 @@ const labelNode = instance.findText('Button', { traverseInstances: true });
86
87
  const label = labelNode.type === 'TEXT' ? labelNode.textContent : 'Button';
87
88
 
88
89
  const iconProp = icon ? figma.code` icon="${icon}"` : '';
90
+ const disabledProp = disabled ? ' disabled' : '';
89
91
 
90
92
  export default {
91
93
  example: iconOnly
92
- ? figma.code`<DsButtonV3 variant="${variant}" color="${color}" size="${size}" ${disabled ? 'disabled' : ''}${iconProp} aria-label="${label}" />`
94
+ ? figma.code`<DsButtonV3 variant="${variant}" color="${color}" size="${size}"${disabledProp}${iconProp} aria-label="${label}" />`
93
95
  : showIcon && icon
94
- ? figma.code`<DsButtonV3 variant="${variant}" color="${color}" size="${size}" ${disabled ? 'disabled' : ''} icon="${icon}">${label}</DsButtonV3>`
95
- : figma.code`<DsButtonV3 variant="${variant}" color="${color}" size="${size}" ${disabled ? 'disabled' : ''}>${label}</DsButtonV3>`,
96
+ ? figma.code`<DsButtonV3 variant="${variant}" color="${color}" size="${size}"${disabledProp} icon="${icon}">${label}</DsButtonV3>`
97
+ : figma.code`<DsButtonV3 variant="${variant}" color="${color}" size="${size}"${disabledProp}>${label}</DsButtonV3>`,
96
98
  imports: ["import { DsButtonV3 } from '@drivenets/design-system';"],
97
99
  id: 'ds-button-v3',
98
100
  metadata: { nestable: true },
@@ -3,7 +3,8 @@
3
3
  $height-large: 40px;
4
4
  $height-medium: 36px;
5
5
  $height-small: 28px;
6
- $border-radius: 4px;
6
+ $border-radius: var(--3xs);
7
+ $border-radius-high-emphasis: var(--sm);
7
8
  $focus-ring-width: 2px;
8
9
 
9
10
  @mixin focus-ring($outer-color) {
@@ -34,6 +35,10 @@ $focus-ring-width: 2px;
34
35
  cursor: not-allowed;
35
36
  }
36
37
 
38
+ &[data-high-emphasis] {
39
+ border-radius: $border-radius-high-emphasis;
40
+ }
41
+
37
42
  &[data-loading] {
38
43
  cursor: default;
39
44
  pointer-events: none;
@@ -126,6 +131,37 @@ $focus-ring-width: 2px;
126
131
  }
127
132
  }
128
133
 
134
+ .root[data-color='default'][data-variant='primary-subtle'] {
135
+ background-color: var(--background-primary-subtle);
136
+ color: var(--font-action);
137
+ border-color: var(--border-action-primary);
138
+
139
+ &:hover:not(:disabled):not(:active):not([data-selected='true']) {
140
+ background-color: var(--background-primary-subtle-hover);
141
+ }
142
+
143
+ &:active:not(:disabled) {
144
+ background-color: var(--background-primary-subtle-active);
145
+ }
146
+
147
+ &:focus-visible {
148
+ @include focus-ring(var(--border-action-primary));
149
+
150
+ background-color: var(--background-primary-subtle-hover);
151
+ border-color: var(--border-inverse);
152
+ }
153
+
154
+ &[data-selected='true'] {
155
+ background-color: var(--background-primary-subtle-active);
156
+ }
157
+
158
+ &:disabled:not([data-loading]) {
159
+ background-color: var(--background-primary-subtle-disabled);
160
+ color: var(--font-disabled);
161
+ border-color: var(--border-disabled);
162
+ }
163
+ }
164
+
129
165
  .root[data-color='default'][data-variant='secondary'] {
130
166
  background-color: var(--background-action-secondary);
131
167
  color: var(--font-main);
@@ -228,19 +264,50 @@ $focus-ring-width: 2px;
228
264
  }
229
265
  }
230
266
 
267
+ .root[data-color='error'][data-variant='primary-subtle'] {
268
+ background-color: var(--background-error-subtle);
269
+ color: var(--font-error);
270
+ border-color: var(--border-error);
271
+
272
+ &:hover:not(:disabled):not(:active):not([data-selected='true']) {
273
+ background-color: var(--background-error-subtle-hover);
274
+ }
275
+
276
+ &:active:not(:disabled) {
277
+ background-color: var(--background-error-subtle-active);
278
+ }
279
+
280
+ &:focus-visible {
281
+ @include focus-ring(var(--border-error));
282
+
283
+ background-color: var(--background-error-subtle-hover);
284
+ border-color: var(--border-inverse);
285
+ }
286
+
287
+ &[data-selected='true'] {
288
+ background-color: var(--background-error-subtle-active);
289
+ }
290
+
291
+ &:disabled:not([data-loading]) {
292
+ background-color: var(--background-error-subtle-disabled);
293
+ color: var(--font-disabled);
294
+ border-color: var(--border-disabled);
295
+ }
296
+ }
297
+
231
298
  .root[data-color='error'][data-variant='secondary'] {
232
299
  background-color: var(--background-action-secondary);
233
300
  color: var(--font-error);
234
- border-color: var(--border-error);
301
+ border-color: var(--border-error-weak);
235
302
 
236
303
  &:hover:not(:disabled):not(:active):not([data-selected='true']) {
237
304
  background-color: var(--background-error-secondary-hover);
238
- border-color: var(--border-error-hover);
305
+ border-color: var(--border-error-medium);
239
306
  }
240
307
 
241
308
  &:active:not(:disabled) {
242
- background-color: var(--background-error-secondary-selected);
243
- border-color: var(--border-error-hover);
309
+ background-color: var(--background-error-secondary-active);
310
+ border-color: var(--border-error-medium);
244
311
  }
245
312
 
246
313
  &:focus-visible {
@@ -251,8 +318,8 @@ $focus-ring-width: 2px;
251
318
  }
252
319
 
253
320
  &[data-selected='true'] {
254
- background-color: var(--background-error-secondary-selected);
255
- border-color: var(--border-error-hover);
321
+ background-color: var(--background-error-secondary-active);
322
+ border-color: var(--border-error-medium);
256
323
  }
257
324
 
258
325
  &:disabled:not([data-loading]) {
@@ -293,32 +360,32 @@ $focus-ring-width: 2px;
293
360
  }
294
361
 
295
362
  .root[data-color='light'][data-variant='primary'] {
296
- background-color: var(--background-light-primary);
363
+ background-color: var(--background-light-subtle);
297
364
  color: var(--font-on-action);
298
- border-color: transparent;
365
+ border-color: var(--border-inverse);
299
366
 
300
367
  &:hover:not(:disabled):not(:active):not([data-selected='true']) {
301
- background-color: var(--background-light-primary-hover);
368
+ background-color: var(--background-light-hover);
302
369
  }
303
370
 
304
371
  &:active:not(:disabled) {
305
- background-color: var(--background-light-primary-selected);
372
+ background-color: var(--background-light-active);
306
373
  }
307
374
 
308
375
  &:focus-visible {
309
- @include focus-ring(var(--outline-inverse));
376
+ @include focus-ring(var(--border-action-primary));
310
377
 
311
- background-color: var(--background-light-primary-hover);
312
- border-color: var(--border-action-secondary);
378
+ background-color: var(--background-light-hover);
313
379
  }
314
380
 
315
381
  &[data-selected='true'] {
316
- background-color: var(--background-light-primary-selected);
382
+ background-color: var(--background-light-active);
317
383
  }
318
384
 
319
385
  &:disabled:not([data-loading]) {
320
- background-color: var(--background-light-disabled);
321
- color: var(--font-light-disabled);
386
+ background-color: transparent;
387
+ color: var(--font-disabled);
388
+ border-color: var(--border-disabled);
322
389
  }
323
390
  }
324
391
 
@@ -29,6 +29,7 @@ const DsButtonV3 = ({
29
29
  variant = 'primary',
30
30
  size = 'medium',
31
31
  selected = false,
32
+ highEmphasis = false,
32
33
  type = 'button',
33
34
  ...rest
34
35
  }: DsButtonV3BaseProps) => {
@@ -48,6 +49,7 @@ const DsButtonV3 = ({
48
49
  data-variant={variant}
49
50
  data-size={size}
50
51
  data-selected={selected ? 'true' : undefined}
52
+ data-high-emphasis={highEmphasis ? 'true' : undefined}
51
53
  data-icon-only={isIconOnly || undefined}
52
54
  data-loading={loading && !disabled ? '' : undefined}
53
55
  {...rest}
@@ -2,7 +2,7 @@ import type { ButtonHTMLAttributes, Ref } from 'react';
2
2
  import type { IconType } from '../ds-icon';
3
3
  import type { ResponsiveValue } from '../../utils/responsive';
4
4
 
5
- export const buttonV3Variants = ['primary', 'secondary', 'tertiary'] as const;
5
+ export const buttonV3Variants = ['primary', 'primary-subtle', 'secondary', 'tertiary'] as const;
6
6
  export type ButtonV3Variant = (typeof buttonV3Variants)[number];
7
7
 
8
8
  export const buttonV3Colors = ['default', 'error', 'light'] as const;
@@ -24,7 +24,8 @@ export interface DsButtonV3BaseProps extends ButtonHTMLAttributes<HTMLButtonElem
24
24
 
25
25
  /**
26
26
  * Visual variant of the button:
27
- * - `primary` — filled, highest-emphasis action
27
+ * - `primary` — highest-emphasis action; filled for `default`/`error`, subtle outline for `color="light"`
28
+ * - `primary-subtle` — subtle-filled, colored border and text (emphasis outline); `default`/`error` only
28
29
  * - `secondary` — outlined, medium-emphasis action
29
30
  * - `tertiary` — borderless, low-emphasis action (text-like)
30
31
  * @default 'primary'
@@ -44,6 +45,14 @@ export interface DsButtonV3BaseProps extends ButtonHTMLAttributes<HTMLButtonElem
44
45
  */
45
46
  selected?: boolean;
46
47
 
48
+ /**
49
+ * Raises the corner radius for high-emphasis surfaces such as
50
+ * Sign in, Landing, and NetGen. Purely a rounding change — does not affect
51
+ * color or priority.
52
+ * @default false
53
+ */
54
+ highEmphasis?: boolean;
55
+
47
56
  /**
48
57
  * Leading icon. When set without children, renders as icon-only (square) layout.
49
58
  */
@@ -0,0 +1,121 @@
1
+ // url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=39666-40247
2
+ // source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-button-v3
3
+ // component=DsButtonV3
4
+ import figma from 'figma';
5
+
6
+ // Figma ships several button generations; the `DsButtonV4` component set maps onto the
7
+ // same code component as `DsButtonV3` (see ds-button-v3.figma.ts for the older set).
8
+ const instance = figma.selectedInstance;
9
+
10
+ const variant = instance.getEnum('variant', {
11
+ primary: 'primary',
12
+ 'primary-subtle': 'primary-subtle',
13
+ secondary: 'secondary',
14
+ tertiary: 'tertiary',
15
+ });
16
+ const color = instance.getEnum('color', {
17
+ default: 'default',
18
+ error: 'error',
19
+ light: 'light',
20
+ });
21
+ const state = instance.getEnum('state', {
22
+ default: 'default',
23
+ hover: 'hover',
24
+ focus: 'focus',
25
+ active: 'active',
26
+ disabled: 'disabled',
27
+ isLoading: 'isLoading',
28
+ });
29
+
30
+ const disabled = state === 'disabled';
31
+ const loading = state === 'isLoading';
32
+
33
+ const structure = instance.findInstance('Part_ButtonStructureV2', { traverseInstances: true });
34
+
35
+ const size =
36
+ structure.type === 'INSTANCE'
37
+ ? (structure.getEnum('size', {
38
+ large: 'large',
39
+ medium: 'medium',
40
+ small: 'small',
41
+ tiny: 'tiny',
42
+ }) ?? 'medium')
43
+ : 'medium';
44
+
45
+ const iconOnly =
46
+ structure.type === 'INSTANCE' ? structure.getEnum('icon-only', { True: true, False: false }) : false;
47
+
48
+ const highEmphasis =
49
+ structure.type === 'INSTANCE' ? structure.getEnum('high-emphasis', { true: true, false: false }) : false;
50
+
51
+ const showIcon = structure.type === 'INSTANCE' ? structure.getBoolean('isIconBefore') : false;
52
+
53
+ // `DsButtonV3.icon` is an icon-name string. Swapped icons keep the placeholder layer
54
+ // name (e.g. `DAP_GM_O_check_circle`), so resolve via Code Connect ID or metadata.
55
+ const toIconName = (name: string): string =>
56
+ name
57
+ .replace(/^DAP_DAP_/, 'DAP_')
58
+ .replace(/^DAP_GM_[OS]_/, '')
59
+ .replace(/^DAP_outline_icon\//, '')
60
+ .replace(/^DAP_/, '')
61
+ .replace(/^\/+/, '')
62
+ .replace(/[\s/]+/g, '_')
63
+ .toLowerCase();
64
+
65
+ const iconNameFromCodeConnectId = (id: string | null): string | undefined => {
66
+ if (!id) {
67
+ return undefined;
68
+ }
69
+ if (id.startsWith('ds-icon-o-')) {
70
+ return id.slice('ds-icon-o-'.length);
71
+ }
72
+ if (id.startsWith('ds-icon-s-')) {
73
+ return id.slice('ds-icon-s-'.length);
74
+ }
75
+ return undefined;
76
+ };
77
+
78
+ const resolveIcon = (iconInstance: figma.InstanceHandle): string | undefined => {
79
+ const fromCcId = iconNameFromCodeConnectId(iconInstance.codeConnectId());
80
+ if (fromCcId) {
81
+ return fromCcId;
82
+ }
83
+
84
+ const iconFromMetadata = iconInstance.executeTemplate().metadata?.props?.icon;
85
+ if (typeof iconFromMetadata === 'string') {
86
+ return iconFromMetadata;
87
+ }
88
+
89
+ return toIconName(iconInstance.name);
90
+ };
91
+
92
+ const leadingIcon = structure.type === 'INSTANCE' ? structure.getInstanceSwap('iconBefore') : undefined;
93
+ const iconFromSwap = leadingIcon?.type === 'INSTANCE' ? resolveIcon(leadingIcon) : undefined;
94
+ const iconFromChild =
95
+ structure.type === 'INSTANCE'
96
+ ? structure
97
+ .findConnectedInstances((node) => node.codeConnectId()?.startsWith('ds-icon-') ?? false, {
98
+ traverseInstances: true,
99
+ })
100
+ .find((node): node is figma.InstanceHandle => node.type === 'INSTANCE')
101
+ : undefined;
102
+ const icon = iconFromSwap ?? (iconFromChild ? resolveIcon(iconFromChild) : undefined);
103
+
104
+ const labelNode = instance.findText('Button', { traverseInstances: true });
105
+ const label = labelNode.type === 'TEXT' ? labelNode.textContent : 'Button';
106
+
107
+ const iconProp = icon ? figma.code` icon="${icon}"` : '';
108
+ const disabledProp = disabled ? ' disabled' : '';
109
+ const loadingProp = loading ? ' loading' : '';
110
+ const highEmphasisProp = highEmphasis ? ' highEmphasis' : '';
111
+
112
+ export default {
113
+ example: iconOnly
114
+ ? figma.code`<DsButtonV3 variant="${variant}" color="${color}" size="${size}"${disabledProp}${loadingProp}${highEmphasisProp}${iconProp} aria-label="${label}" />`
115
+ : showIcon && icon
116
+ ? figma.code`<DsButtonV3 variant="${variant}" color="${color}" size="${size}"${disabledProp}${loadingProp}${highEmphasisProp} icon="${icon}">${label}</DsButtonV3>`
117
+ : figma.code`<DsButtonV3 variant="${variant}" color="${color}" size="${size}"${disabledProp}${loadingProp}${highEmphasisProp}>${label}</DsButtonV3>`,
118
+ imports: ["import { DsButtonV3 } from '@drivenets/design-system';"],
119
+ id: 'ds-button-v4',
120
+ metadata: { nestable: true },
121
+ } satisfies figma.Template;
@@ -0,0 +1,52 @@
1
+ // url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=18638-7430
2
+ // source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-comment-bubble
3
+ // component=DsCommentBubble
4
+ //
5
+ // `DsCommentBubbleV1` is the floating comment bubble. Its Figma `type` axis
6
+ // (`initial` / `start typing` vs `open`) selects between the empty compose state and
7
+ // a thread; in code this is driven by whether the `comment` prop is present, so the
8
+ // snippet emits `comment` / `currentUser` identifier placeholders for the developer to
9
+ // wire to state. The `action required` axis maps to `hideActionRequired` (the
10
+ // `no checkbox` variant hides the control); `State` is visual only and has no prop.
11
+ import figma from 'figma';
12
+
13
+ const instance = figma.selectedInstance;
14
+
15
+ const bubbleType =
16
+ instance.getEnum('type', {
17
+ initial: 'compose',
18
+ 'start typing': 'compose',
19
+ open: 'thread',
20
+ }) ?? 'compose';
21
+
22
+ const hideActionRequired =
23
+ instance.getEnum('action required', {
24
+ 'no checkbox': true,
25
+ false: false,
26
+ true: false,
27
+ }) ?? false;
28
+
29
+ const hideActionRequiredAttr = hideActionRequired ? '\n\thideActionRequired' : '';
30
+
31
+ export default {
32
+ example:
33
+ bubbleType === 'thread'
34
+ ? figma.code`<DsCommentBubble
35
+ comment={comment}
36
+ currentUser={currentUser}
37
+ value={value}
38
+ onValueChange={setValue}
39
+ onSend={handleSend}
40
+ onClose={handleClose}${hideActionRequiredAttr}
41
+ />`
42
+ : figma.code`<DsCommentBubble
43
+ currentUser={currentUser}
44
+ value={value}
45
+ onValueChange={setValue}
46
+ onSend={handleSend}
47
+ onClose={handleClose}${hideActionRequiredAttr}
48
+ />`,
49
+ imports: ["import { DsCommentBubble } from '@drivenets/design-system';"],
50
+ id: 'ds-comment-bubble',
51
+ metadata: { nestable: true },
52
+ } satisfies figma.Template;
@@ -0,0 +1,36 @@
1
+ // url=https://www.figma.com/design/nha3m67y7S57cHCSuQO2gp/DAP-Design-System-1.2?node-id=18166-58292
2
+ // source=https://github.com/drivenets/design-system/tree/main/packages/design-system/src/components/ds-comment-card
3
+ // component=DsCommentCard
4
+ //
5
+ // `DsCommentCardV1` composes the inner `Structure_CommentCardV1`. Its `overflow` axis
6
+ // maps directly to the `overflow` prop. The `type` axis is interaction state
7
+ // (default/hover are visual and CSS-driven — only `disabled` maps to a prop),
8
+ // mirroring `ds-card.figma.ts`. The `action required` axis is encoded in the `comment`
9
+ // data (`isActionRequired`), not a prop. `comment` is a data object that is not
10
+ // derivable from Figma, so it is emitted as an identifier placeholder for the
11
+ // developer to wire (see `ds-smart-tabs.figma.ts`).
12
+ import figma from 'figma';
13
+
14
+ const instance = figma.selectedInstance;
15
+
16
+ const state =
17
+ instance.getEnum('type', {
18
+ default: 'default',
19
+ hover: 'default',
20
+ disabled: 'disabled',
21
+ }) ?? 'default';
22
+
23
+ const overflow =
24
+ instance.getEnum('overflow', {
25
+ hidden: 'hidden',
26
+ displayed: 'displayed',
27
+ }) ?? 'hidden';
28
+
29
+ const disabledAttr = state === 'disabled' ? ' disabled' : '';
30
+
31
+ export default {
32
+ example: figma.code`<DsCommentCard comment={comment} overflow="${overflow}"${disabledAttr} />`,
33
+ imports: ["import { DsCommentCard } from '@drivenets/design-system';"],
34
+ id: 'ds-comment-card',
35
+ metadata: { nestable: true },
36
+ } satisfies figma.Template;