@drivenets/design-system 0.8.0 → 0.9.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 (67) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/index.cjs +1567 -1077
  3. package/dist/index.d.cts +857 -135
  4. package/dist/index.d.cts.map +1 -1
  5. package/dist/index.d.ts +857 -135
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +1555 -1079
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.min.css +1 -1
  10. package/package.json +19 -17
  11. package/src/components/ds-autocomplete/ds-autocomplete.module.scss +0 -1
  12. package/src/components/ds-button/versions/ds-button-new/ds-button-new.module.scss +25 -9
  13. package/src/components/ds-button/versions/ds-button-new/ds-button-new.tsx +5 -5
  14. package/src/components/ds-button/versions/ds-button-new/ds-button-new.types.ts +11 -1
  15. package/src/components/ds-button/versions/ds-button-new/index.ts +4 -1
  16. package/src/components/ds-button-v3/ds-button-v3.module.scss +391 -0
  17. package/src/components/ds-button-v3/ds-button-v3.tsx +55 -0
  18. package/src/components/ds-button-v3/ds-button-v3.types.ts +58 -0
  19. package/src/components/ds-button-v3/index.ts +6 -0
  20. package/src/components/ds-comment-card/ds-comment-card.module.scss +2 -2
  21. package/src/components/ds-comments-drawer/components/comments-filter-modal/comments-filter-modal.tsx +1 -1
  22. package/src/components/ds-comments-drawer/ds-comments-drawer.tsx +3 -9
  23. package/src/components/ds-date-picker/ds-date-picker.module.scss +10 -0
  24. package/src/components/ds-date-picker/ds-date-picker.tsx +4 -2
  25. package/src/components/ds-date-range-picker/ds-date-range-picker.tsx +2 -2
  26. package/src/components/ds-drawer/ds-drawer.tsx +6 -9
  27. package/src/components/ds-drawer/ds-drawer.types.ts +4 -2
  28. package/src/components/ds-form-control/ds-form-control.tsx +2 -3
  29. package/src/components/ds-panel/ds-panel.module.scss +4 -1
  30. package/src/components/ds-panel/ds-panel.tsx +8 -3
  31. package/src/components/ds-panel/ds-panel.types.ts +8 -1
  32. package/src/components/ds-panel/index.ts +4 -1
  33. package/src/components/ds-select/ds-select.module.scss +4 -1
  34. package/src/components/ds-split-button/ds-split-button.module.scss +99 -0
  35. package/src/components/ds-split-button/ds-split-button.tsx +49 -0
  36. package/src/components/ds-split-button/ds-split-button.types.ts +25 -0
  37. package/src/components/ds-split-button/index.ts +10 -0
  38. package/src/components/ds-stack/ds-stack.module.scss +4 -0
  39. package/src/components/ds-stack/ds-stack.tsx +35 -0
  40. package/src/components/ds-stack/ds-stack.types.ts +19 -0
  41. package/src/components/ds-stack/index.ts +18 -0
  42. package/src/components/ds-table/components/ds-table-body-virtualized/ds-table-body-virtualized.tsx +2 -2
  43. package/src/components/ds-table/components/ds-table-bulk-actions/ds-table-bulk-actions.module.scss +5 -8
  44. package/src/components/ds-table/components/ds-table-cell/ds-table-cell.tsx +7 -4
  45. package/src/components/ds-table/components/ds-table-cell/ds-table-cell.types.ts +6 -0
  46. package/src/components/ds-table/ds-table.module.scss +6 -0
  47. package/src/components/ds-table/ds-table.tsx +3 -0
  48. package/src/components/ds-time-picker/ds-time-picker.module.scss +11 -0
  49. package/src/components/ds-time-picker/ds-time-picker.tsx +32 -12
  50. package/src/components/ds-time-picker/ds-time-picker.types.ts +6 -0
  51. package/src/components/ds-tree/ds-tree.types.ts +2 -2
  52. package/src/index.ts +4 -0
  53. package/src/styles/_breakpoints.module.scss +5 -0
  54. package/src/styles/_grid.scss +5 -1
  55. package/src/styles/_mixin.scss +2 -2
  56. package/src/styles/_responsive.scss +13 -0
  57. package/src/styles/_root_updated.scss +20 -20
  58. package/src/styles/_scrollbars.scss +6 -1
  59. package/src/styles/_variables.scss +2 -0
  60. package/src/styles/shared/_button.scss +2 -0
  61. package/src/styles/shared/_input.scss +3 -40
  62. package/src/utils/responsive.browser.test.ts +94 -0
  63. package/src/utils/responsive.ts +79 -0
  64. package/src/utils/responsive.unit.test.ts +54 -0
  65. package/src/utils/type-utils.ts +1 -0
  66. package/src/utils/use-controlled.browser.test.ts +6 -6
  67. package/src/utils/use-controlled.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drivenets/design-system",
3
- "version": "0.8.0",
3
+ "version": "0.9.1",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.cts",
@@ -36,7 +36,7 @@
36
36
  "directory": "/packages/design-system"
37
37
  },
38
38
  "dependencies": {
39
- "@ark-ui/react": "^5.34.1",
39
+ "@ark-ui/react": "^5.36.1",
40
40
  "@dnd-kit/core": "^6.3.1",
41
41
  "@dnd-kit/modifiers": "^9.0.0",
42
42
  "@dnd-kit/sortable": "^10.0.0",
@@ -51,10 +51,11 @@
51
51
  "@radix-ui/react-tooltip": "^1.2.8",
52
52
  "@radix-ui/react-visually-hidden": "^1.2.4",
53
53
  "@tanstack/react-table": "^8.21.3",
54
- "@tanstack/react-virtual": "^3.13.23",
55
- "@zag-js/react": "^1.37.0",
56
- "@zag-js/steps": "^1.37.0",
57
- "classnames": "^2.5.1"
54
+ "@tanstack/react-virtual": "^3.13.24",
55
+ "@zag-js/react": "^1.40.0",
56
+ "@zag-js/steps": "^1.40.0",
57
+ "classnames": "^2.5.1",
58
+ "csstype": "^3.2.3"
58
59
  },
59
60
  "peerDependencies": {
60
61
  "@internationalized/date": "^3.0.0",
@@ -67,16 +68,18 @@
67
68
  "@eslint/compat": "^2.0.3",
68
69
  "@faker-js/faker": "^10.3.0",
69
70
  "@hookform/resolvers": "^5.2.2",
70
- "@rolldown/plugin-babel": "^0.2.1",
71
+ "@rolldown/plugin-babel": "^0.2.2",
71
72
  "@storybook/addon-a11y": "^10.2.19",
72
73
  "@storybook/addon-docs": "^10.2.19",
73
74
  "@storybook/addon-vitest": "^10.2.19",
74
75
  "@storybook/react-vite": "^10.2.19",
75
76
  "@tanstack/react-query": "^5.90.21",
76
77
  "@tanstack/react-router": "^1.166.2",
78
+ "@tsdown/css": "^0.21.6",
77
79
  "@types/eslint-plugin-jsx-a11y": "^6.10.1",
78
80
  "@types/react": "^19.2.14",
79
81
  "@types/react-dom": "^19.2.3",
82
+ "@typescript/native-preview": "7.0.0-dev.20260331.1",
80
83
  "@vitejs/plugin-react": "^6.0.1",
81
84
  "@vitest/browser-playwright": "^4.1.0",
82
85
  "@vitest/coverage-v8": "^4.1.0",
@@ -88,30 +91,29 @@
88
91
  "eslint-plugin-storybook": "^10.2.19",
89
92
  "mockdate": "^3.0.5",
90
93
  "playwright": "^1.58.2",
91
- "postcss": "^8.5.8",
92
- "postcss-modules": "^6.0.1",
93
94
  "publint": "^0.3.18",
94
95
  "react": "^19.2.4",
95
96
  "react-dom": "^19.2.4",
96
97
  "react-hook-form": "^7.71.2",
97
- "rollup-plugin-sass": "^1.15.3",
98
98
  "sass-embedded": "^1.97.3",
99
99
  "storybook": "^10.2.19",
100
- "tsdown": "^0.21.0",
100
+ "tsdown": "^0.21.6",
101
101
  "typed-scss-modules": "^8.1.1",
102
- "typescript": "^5.9.3",
102
+ "typescript": "^6.0.2",
103
103
  "typescript-plugin-css-modules": "^5.2.0",
104
- "vite": "^8.0.0",
104
+ "vite": "8.0.5",
105
105
  "vitest": "^4.1.0",
106
106
  "vitest-browser-react": "^2.1.0",
107
107
  "zod": "^4.3.6",
108
- "@drivenets/vite-plugin-design-system": "0.0.6",
109
- "@drivenets/eslint-plugin-internal": "0.0.0"
108
+ "@drivenets/eslint-plugin-internal": "0.0.0",
109
+ "@drivenets/vite-plugin-design-system": "0.0.7"
110
110
  },
111
111
  "scripts": {
112
112
  "install:playwright": "pnpm exec playwright install chromium --with-deps",
113
- "lint": "pnpm generate-scss-dts && eslint --max-warnings=0 .; EXIT_CODE=$?; rm -rf .scss-dts; exit $EXIT_CODE",
114
- "typecheck": "pnpm generate-scss-dts && tsc; EXIT_CODE=$?; rm -rf .scss-dts; exit $EXIT_CODE",
113
+ "lint": "pnpm generate-scss-dts && eslint --max-warnings=0 ${ESLINT_ARGS-} .; EXIT_CODE=$?; rm -rf .scss-dts; exit $EXIT_CODE",
114
+ "//": "ESLINT_ARGS is used to pass arguments to eslint. We're using it so we don't need to duplicate the lint script.",
115
+ "lint:fix": "ESLINT_ARGS=--fix pnpm lint",
116
+ "typecheck": "pnpm generate-scss-dts && tsgo; EXIT_CODE=$?; rm -rf .scss-dts; exit $EXIT_CODE",
115
117
  "generate-scss-dts": "typed-scss-modules ./src -o ./.scss-dts --nameFormat all --exportType default > /dev/null 2>&1",
116
118
  "storybook": "storybook dev -p 6006",
117
119
  "test": "vitest --project=\"!requires-build\"",
@@ -200,7 +200,6 @@ $autocomplete-opacity-visible: 1;
200
200
  .disabled {
201
201
  .control {
202
202
  color: var(--color-background-deselected);
203
- background: var(--color-background-secondary);
204
203
  border-color: var(--color-border-disabled);
205
204
  cursor: not-allowed;
206
205
 
@@ -5,6 +5,27 @@ $button-size-small: 28px;
5
5
  $button-size-default: 32px;
6
6
  $button-size-large: 40px;
7
7
 
8
+ @mixin content-size-tiny {
9
+ @include typography.body-xs-md;
10
+ height: $button-size-tiny;
11
+ border-radius: var(--spacing-4xs);
12
+ --icon-width-tiny: 13px;
13
+ }
14
+
15
+ @mixin content-size-small {
16
+ @include typography.body-xs-md;
17
+ height: $button-size-small;
18
+ }
19
+
20
+ @mixin content-size-medium {
21
+ height: $button-size-default;
22
+ }
23
+
24
+ @mixin content-size-large {
25
+ @include typography.body-md-md;
26
+ height: $button-size-large;
27
+ }
28
+
8
29
  .button {
9
30
  @include typography.body-sm-md;
10
31
  display: flex;
@@ -31,24 +52,19 @@ $button-size-large: 40px;
31
52
  }
32
53
 
33
54
  &.tiny .content {
34
- @include typography.body-xs-md;
35
- height: $button-size-tiny;
36
- border-radius: var(--spacing-4xs);
37
- --icon-width-tiny: 13px;
55
+ @include content-size-tiny;
38
56
  }
39
57
 
40
58
  &.small .content {
41
- @include typography.body-xs-md;
42
- height: $button-size-small;
59
+ @include content-size-small;
43
60
  }
44
61
 
45
62
  &.medium .content {
46
- height: $button-size-default;
63
+ @include content-size-medium;
47
64
  }
48
65
 
49
66
  &.large .content {
50
- @include typography.body-md-md;
51
- height: $button-size-large;
67
+ @include content-size-large;
52
68
  }
53
69
 
54
70
  &.iconButton {
@@ -1,8 +1,9 @@
1
1
  import classNames from 'classnames';
2
2
  import type React from 'react';
3
3
  import { Children, isValidElement } from 'react';
4
+
4
5
  import styles from './ds-button-new.module.scss';
5
- import type { DsButtonProps } from './ds-button-new.types';
6
+ import type { DsButtonBaseProps } from './ds-button-new.types';
6
7
  import { DsIcon } from '../../../ds-icon';
7
8
 
8
9
  const isIconOnly = (children: React.ReactNode) => {
@@ -19,7 +20,7 @@ const isIconOnly = (children: React.ReactNode) => {
19
20
  /**
20
21
  * Design system Button component
21
22
  */
22
- const DsButton: React.FC<DsButtonProps> = ({
23
+ const DsButton: React.FC<DsButtonBaseProps> = ({
23
24
  buttonType,
24
25
  variant = 'filled',
25
26
  size = 'medium',
@@ -36,9 +37,8 @@ const DsButton: React.FC<DsButtonProps> = ({
36
37
  styles[size],
37
38
  className,
38
39
 
39
- // @ts-expect-error: we don't have all variations of classnames defined
40
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
41
- styles[`${type}-${variant}`],
40
+ // Casting because we don't have all variations of classnames defined
41
+ styles[`${type}-${variant}` as keyof typeof styles],
42
42
  );
43
43
 
44
44
  return (
@@ -1,5 +1,7 @@
1
1
  import type React from 'react';
2
2
 
3
+ import type { ResponsiveValue } from '../../../../utils/responsive';
4
+
3
5
  export const buttonTypes = ['primary', 'secondary', 'secondary-light', 'tertiary'] as const;
4
6
  export type ButtonType = (typeof buttonTypes)[number];
5
7
 
@@ -9,7 +11,7 @@ export type ButtonVariant = (typeof buttonVariants)[number];
9
11
  export const buttonSizes = ['large', 'medium', 'small', 'tiny'] as const;
10
12
  export type ButtonSize = (typeof buttonSizes)[number];
11
13
 
12
- export interface DsButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
14
+ export interface DsButtonBaseProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
13
15
  /**
14
16
  * Type of the button
15
17
  * @default 'primary'
@@ -39,3 +41,11 @@ export interface DsButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElem
39
41
  */
40
42
  contentClassName?: string;
41
43
  }
44
+
45
+ export interface DsButtonProps extends Omit<DsButtonBaseProps, 'size'> {
46
+ /**
47
+ * Size of the button. Accepts a static value or a responsive object.
48
+ * @default 'medium'
49
+ */
50
+ size?: ResponsiveValue<ButtonSize>;
51
+ }
@@ -1,2 +1,5 @@
1
- export { default as DsButtonNew } from './ds-button-new';
1
+ import { withResponsiveProps } from '../../../../utils/responsive';
2
+ import DsButtonBase from './ds-button-new';
3
+
4
+ export const DsButtonNew = withResponsiveProps(DsButtonBase, ['size']);
2
5
  export * from './ds-button-new.types';
@@ -0,0 +1,391 @@
1
+ @use '../../styles/root_updated';
2
+ @use '../../styles/shared/button' as button;
3
+
4
+ $height-large: 40px;
5
+ $height-medium: 36px;
6
+ $height-small: 28px;
7
+ $border-radius: 4px;
8
+ $focus-ring-width: 2px;
9
+
10
+ @mixin focus-ring($outer-color) {
11
+ outline: $focus-ring-width solid $outer-color;
12
+ }
13
+
14
+ .root {
15
+ box-sizing: border-box;
16
+ display: inline-flex;
17
+ align-items: center;
18
+ justify-content: center;
19
+ gap: var(--3xs);
20
+ margin: 0;
21
+ border: 1px solid transparent;
22
+ border-radius: $border-radius;
23
+ background: transparent;
24
+ font-family: var(--font-family-base);
25
+ font-weight: var(--font-weight-medium);
26
+ text-align: center;
27
+ cursor: pointer;
28
+ transition:
29
+ background-color button.$transition-duration-default,
30
+ border-color button.$transition-duration-quick,
31
+ color button.$transition-duration-default,
32
+ outline-color button.$transition-duration-quick;
33
+
34
+ &:disabled:not([data-loading]) {
35
+ cursor: not-allowed;
36
+ }
37
+
38
+ &[data-loading] {
39
+ cursor: default;
40
+ pointer-events: none;
41
+ }
42
+
43
+ &:focus {
44
+ outline: none;
45
+ }
46
+
47
+ &:focus-visible {
48
+ outline-style: solid;
49
+ }
50
+
51
+ &[data-size='large'] {
52
+ padding: var(--3xs) var(--sm);
53
+ min-height: $height-large;
54
+ font-size: var(--font-size-md);
55
+ line-height: var(--line-height-md);
56
+ }
57
+
58
+ &[data-size='medium'] {
59
+ padding: var(--3xs) var(--sm);
60
+ min-height: $height-medium;
61
+ font-size: var(--font-size-sm);
62
+ line-height: var(--line-height-sm);
63
+ }
64
+
65
+ &[data-size='small'] {
66
+ padding: var(--3xs) var(--sm);
67
+ min-height: $height-small;
68
+ font-size: var(--font-size-xs);
69
+ line-height: var(--line-height-xs);
70
+ }
71
+
72
+ &[data-size='tiny'] {
73
+ min-height: var(--icon-width-tiny);
74
+ padding: 0 var(--3xs);
75
+ font-size: var(--font-size-xs);
76
+ line-height: var(--line-height-xs);
77
+ }
78
+
79
+ &[data-icon-only][data-size='large'] {
80
+ padding: var(--3xs);
81
+ min-width: $height-large;
82
+ }
83
+
84
+ &[data-icon-only][data-size='medium'] {
85
+ padding: var(--3xs);
86
+ min-width: $height-medium;
87
+ }
88
+
89
+ &[data-icon-only][data-size='small'] {
90
+ padding: var(--3xs);
91
+ min-width: $height-small;
92
+ }
93
+
94
+ &[data-icon-only][data-size='tiny'] {
95
+ padding: 0;
96
+ min-width: var(--icon-width-tiny);
97
+ }
98
+ }
99
+
100
+ .root[data-color='default'][data-variant='primary'] {
101
+ background-color: var(--background-background-primary);
102
+ color: var(--font-font-on-action);
103
+ border-color: transparent;
104
+
105
+ &:hover:not(:disabled):not(:active):not([data-selected='true']) {
106
+ background-color: var(--background-background-primary-hover);
107
+ }
108
+
109
+ &:active:not(:disabled) {
110
+ background-color: var(--background-background-primary-selected);
111
+ }
112
+
113
+ &:focus-visible {
114
+ @include focus-ring(var(--border-border-action-primary));
115
+
116
+ background-color: var(--background-background-primary-hover);
117
+ border-color: var(--border-border-inverse);
118
+ }
119
+
120
+ &[data-selected='true'] {
121
+ background-color: var(--background-background-primary-selected);
122
+ }
123
+
124
+ &:disabled:not([data-loading]) {
125
+ background-color: var(--background-background-disable);
126
+ color: var(--font-font-on-action);
127
+ }
128
+ }
129
+
130
+ .root[data-color='default'][data-variant='secondary'] {
131
+ background-color: var(--background-background-action-secondary);
132
+ color: var(--font-font-main);
133
+ border-color: var(--border-border);
134
+
135
+ &:hover:not(:disabled):not(:active):not([data-selected='true']) {
136
+ background-color: var(--background-background-secondary-hover);
137
+ color: var(--font-font-action-secondary);
138
+ border-color: var(--border-border-secondary-hover);
139
+ }
140
+
141
+ &:active:not(:disabled) {
142
+ background-color: var(--background-background-action-secondary-hover);
143
+ color: var(--font-font-action-secondary);
144
+ border-color: var(--border-border-secondary-hover);
145
+ }
146
+
147
+ &:focus-visible {
148
+ @include focus-ring(var(--border-border-action-primary-hover));
149
+
150
+ background-color: var(--background-background-secondary-hover);
151
+ border-color: var(--border-border-inverse);
152
+ color: var(--font-font-action-secondary);
153
+ }
154
+
155
+ &[data-selected='true'] {
156
+ background-color: var(--background-background-action-secondary-hover);
157
+ color: var(--font-font-action-secondary);
158
+ border-color: var(--border-border-secondary-hover);
159
+ }
160
+
161
+ &:disabled:not([data-loading]) {
162
+ background-color: var(--background-background-action-secondary);
163
+ color: var(--font-font-disabled);
164
+ border-color: var(--border-border-disabled);
165
+ }
166
+ }
167
+
168
+ .root[data-color='default'][data-variant='tertiary'] {
169
+ background-color: transparent;
170
+ color: var(--font-font-main);
171
+ border-color: transparent;
172
+
173
+ &:hover:not(:disabled):not(:active):not([data-selected='true']) {
174
+ background-color: var(--background-background-secondary-hover);
175
+ color: var(--font-font-action-secondary);
176
+ }
177
+
178
+ &:active:not(:disabled) {
179
+ background-color: var(--background-background-action-secondary-hover);
180
+ color: var(--font-font-action-secondary);
181
+ }
182
+
183
+ &:focus-visible {
184
+ @include focus-ring(var(--border-border-action-primary-hover));
185
+
186
+ background-color: var(--background-background-secondary-hover);
187
+ border-color: var(--border-border-inverse);
188
+ color: var(--font-font-action-secondary);
189
+ }
190
+
191
+ &[data-selected='true'] {
192
+ background-color: var(--background-background-action-secondary-hover);
193
+ color: var(--font-font-action-secondary);
194
+ }
195
+
196
+ &:disabled:not([data-loading]) {
197
+ background-color: transparent;
198
+ color: var(--font-font-disabled);
199
+ }
200
+ }
201
+
202
+ .root[data-color='error'][data-variant='primary'] {
203
+ background-color: var(--background-background-error);
204
+ color: var(--font-font-on-action);
205
+ border-color: transparent;
206
+
207
+ &:hover:not(:disabled):not(:active):not([data-selected='true']) {
208
+ background-color: var(--background-background-error-hover);
209
+ }
210
+
211
+ &:active:not(:disabled) {
212
+ background-color: var(--background-background-error-selected);
213
+ }
214
+
215
+ &:focus-visible {
216
+ @include focus-ring(var(--border-border-error));
217
+
218
+ background-color: var(--background-background-error-hover);
219
+ border-color: var(--border-border-inverse);
220
+ }
221
+
222
+ &[data-selected='true'] {
223
+ background-color: var(--background-background-error-selected);
224
+ }
225
+
226
+ &:disabled:not([data-loading]) {
227
+ background-color: var(--background-background-disable);
228
+ color: var(--font-font-on-action);
229
+ }
230
+ }
231
+
232
+ .root[data-color='error'][data-variant='secondary'] {
233
+ background-color: var(--background-background-action-secondary);
234
+ color: var(--font-font-error);
235
+ border-color: var(--border-border-error);
236
+
237
+ &:hover:not(:disabled):not(:active):not([data-selected='true']) {
238
+ background-color: var(--background-background-error-secondary-hover);
239
+ border-color: var(--border-border-error-hover);
240
+ }
241
+
242
+ &:active:not(:disabled) {
243
+ background-color: var(--background-background-error-secondary-selected);
244
+ border-color: var(--border-border-error-hover);
245
+ }
246
+
247
+ &:focus-visible {
248
+ @include focus-ring(var(--border-border-error));
249
+
250
+ background-color: var(--background-background-error-secondary-hover);
251
+ border-color: var(--border-border-inverse);
252
+ }
253
+
254
+ &[data-selected='true'] {
255
+ background-color: var(--background-background-error-secondary-selected);
256
+ border-color: var(--border-border-error-hover);
257
+ }
258
+
259
+ &:disabled:not([data-loading]) {
260
+ background-color: var(--background-background-action-secondary);
261
+ color: var(--font-font-disabled);
262
+ border-color: var(--border-border-disabled);
263
+ }
264
+ }
265
+
266
+ .root[data-color='error'][data-variant='tertiary'] {
267
+ background-color: transparent;
268
+ color: var(--font-font-error);
269
+ border-color: transparent;
270
+
271
+ &:hover:not(:disabled):not(:active):not([data-selected='true']) {
272
+ background-color: var(--background-background-error-secondary-hover);
273
+ }
274
+
275
+ &:active:not(:disabled) {
276
+ background-color: var(--background-background-error-secondary-selected);
277
+ }
278
+
279
+ &:focus-visible {
280
+ @include focus-ring(var(--border-border-error));
281
+
282
+ background-color: var(--background-background-error-secondary-hover);
283
+ border-color: var(--border-border-inverse);
284
+ }
285
+
286
+ &[data-selected='true'] {
287
+ background-color: var(--background-background-error-secondary-selected);
288
+ }
289
+
290
+ &:disabled:not([data-loading]) {
291
+ background-color: transparent;
292
+ color: var(--font-font-disabled);
293
+ }
294
+ }
295
+
296
+ .root[data-color='light'][data-variant='primary'] {
297
+ background-color: var(--background-background-ondark-primary);
298
+ color: var(--font-font-on-action);
299
+ border-color: transparent;
300
+
301
+ &:hover:not(:disabled):not(:active):not([data-selected='true']) {
302
+ background-color: var(--background-background-ondark-primary-hover);
303
+ }
304
+
305
+ &:active:not(:disabled) {
306
+ background-color: var(--background-background-ondark-primary-selected);
307
+ }
308
+
309
+ &:focus-visible {
310
+ @include focus-ring(var(--outline-outline-inverse));
311
+
312
+ background-color: var(--background-background-ondark-primary-hover);
313
+ border-color: var(--border-border-action-secondary);
314
+ }
315
+
316
+ &[data-selected='true'] {
317
+ background-color: var(--background-background-ondark-primary-selected);
318
+ }
319
+
320
+ &:disabled:not([data-loading]) {
321
+ background-color: var(--background-background-ondark-disabled);
322
+ color: var(--font-font-disabled);
323
+ }
324
+ }
325
+
326
+ .root[data-color='light'][data-variant='secondary'] {
327
+ background-color: transparent;
328
+ color: var(--font-font-on-action);
329
+ border-color: var(--border-border-ondark-secondary);
330
+
331
+ &:hover:not(:disabled):not(:active):not([data-selected='true']) {
332
+ background-color: var(--background-background-ondark-secondary-hover);
333
+ color: var(--font-font-on-action);
334
+ }
335
+
336
+ &:active:not(:disabled) {
337
+ background-color: var(--background-background-ondark-secondary-selected);
338
+ color: var(--font-font-on-action);
339
+ }
340
+
341
+ &:focus-visible {
342
+ @include focus-ring(var(--outline-outline-inverse));
343
+
344
+ background-color: var(--background-background-ondark-secondary-hover);
345
+ border-color: var(--border-border-action-secondary);
346
+ color: var(--font-font-on-action);
347
+ }
348
+
349
+ &[data-selected='true'] {
350
+ background-color: var(--background-background-ondark-secondary-selected);
351
+ }
352
+
353
+ &:disabled:not([data-loading]) {
354
+ background-color: transparent;
355
+ color: var(--font-font-ondark-disabled);
356
+ border-color: var(--background-background-ondark-disabled);
357
+ }
358
+ }
359
+
360
+ .root[data-color='light'][data-variant='tertiary'] {
361
+ background-color: transparent;
362
+ color: var(--font-font-on-action);
363
+ border-color: transparent;
364
+
365
+ &:hover:not(:disabled):not(:active):not([data-selected='true']) {
366
+ background-color: var(--background-background-ondark-secondary-hover);
367
+ color: var(--font-font-on-action);
368
+ }
369
+
370
+ &:active:not(:disabled) {
371
+ background-color: var(--background-background-ondark-secondary-selected);
372
+ color: var(--font-font-on-action);
373
+ }
374
+
375
+ &:focus-visible {
376
+ @include focus-ring(var(--outline-outline-inverse));
377
+
378
+ background-color: var(--background-background-ondark-secondary-hover);
379
+ border-color: var(--border-border-action-secondary);
380
+ color: var(--font-font-on-action);
381
+ }
382
+
383
+ &[data-selected='true'] {
384
+ background-color: var(--background-background-ondark-secondary-selected);
385
+ }
386
+
387
+ &:disabled:not([data-loading]) {
388
+ background-color: transparent;
389
+ color: var(--font-font-ondark-disabled);
390
+ }
391
+ }
@@ -0,0 +1,55 @@
1
+ import classNames from 'classnames';
2
+ import { DsIcon, type IconSize } from '../ds-icon';
3
+ import { DsSpinner } from '../ds-spinner';
4
+ import styles from './ds-button-v3.module.scss';
5
+ import type { ButtonV3Size, DsButtonV3BaseProps } from './ds-button-v3.types.ts';
6
+
7
+ const iconSizeMap: Record<ButtonV3Size, IconSize> = Object.freeze({
8
+ large: 'small',
9
+ medium: 'tiny',
10
+ small: 'tiny',
11
+ tiny: 'tiny',
12
+ });
13
+
14
+ const DsButtonV3 = ({
15
+ ref,
16
+ className,
17
+ style,
18
+ children,
19
+ icon,
20
+ disabled,
21
+ loading = false,
22
+ color = 'default',
23
+ variant = 'primary',
24
+ size = 'medium',
25
+ selected = false,
26
+ type = 'button',
27
+ ...rest
28
+ }: DsButtonV3BaseProps) => {
29
+ const isIconOnly = icon !== undefined && !children;
30
+
31
+ return (
32
+ <button
33
+ ref={ref}
34
+ // eslint-disable-next-line react/button-has-type -- Dynamic by nature of this component
35
+ type={type}
36
+ disabled={disabled || loading}
37
+ aria-busy={loading || undefined}
38
+ aria-pressed={selected}
39
+ className={classNames(styles.root, className)}
40
+ style={style}
41
+ data-color={color}
42
+ data-variant={variant}
43
+ data-size={size}
44
+ data-selected={selected ? 'true' : undefined}
45
+ data-icon-only={isIconOnly || undefined}
46
+ data-loading={loading && !disabled ? '' : undefined}
47
+ {...rest}
48
+ >
49
+ {loading ? <DsSpinner /> : icon && <DsIcon icon={icon} size={iconSizeMap[size]} aria-hidden />}
50
+ {children}
51
+ </button>
52
+ );
53
+ };
54
+
55
+ export default DsButtonV3;