@bethinkpl/design-system 37.1.0 → 38.0.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 (42) hide show
  1. package/dist/design-system.css +1 -1
  2. package/dist/design-system.js +6071 -6027
  3. package/dist/design-system.js.map +1 -1
  4. package/dist/lib/js/components/Buttons/Button/Button.consts.d.ts +1 -0
  5. package/dist/lib/js/components/Buttons/Button/useMagicGradient.d.ts +5 -0
  6. package/dist/lib/js/components/Buttons/IconButton/IconButton.consts.d.ts +1 -0
  7. package/dist/lib/js/components/Buttons/IconButton/IconButton.vue.d.ts +5 -2
  8. package/dist/lib/js/components/Drawer/DrawerHeader/DrawerHeader.vue.d.ts +3 -0
  9. package/dist/lib/js/components/Drawer/DrawerSection/DrawerSection.vue.d.ts +5 -0
  10. package/dist/lib/js/components/Headers/OverlayHeader/OverlayHeader.vue.d.ts +4 -0
  11. package/dist/lib/js/components/Headers/SectionHeader/SectionHeader.vue.d.ts +4 -0
  12. package/dist/lib/js/components/Modals/Modal/Modal.vue.d.ts +5 -0
  13. package/dist/lib/js/components/Modals/ModalDialog/ModalDialog.vue.d.ts +5 -0
  14. package/dist/lib/js/components/Pagination/Pagination.vue.d.ts +4 -0
  15. package/dist/lib/js/components/SurveyQuestions/SurveyQuestionOpenEnded/SurveyQuestionOpenEnded.vue.d.ts +4 -0
  16. package/dist/lib/js/components/SurveyQuestions/SurveyQuestionScale/SurveyQuestionScale.vue.d.ts +4 -0
  17. package/dist/lib/js/components/Toast/Toast.vue.d.ts +1 -0
  18. package/lib/js/components/Buttons/Button/Button.consts.ts +1 -0
  19. package/lib/js/components/Buttons/Button/Button.spec.ts +35 -0
  20. package/lib/js/components/Buttons/Button/Button.vue +19 -0
  21. package/lib/js/components/Buttons/Button/useMagicGradient.spec.ts +47 -0
  22. package/lib/js/components/Buttons/Button/useMagicGradient.ts +50 -0
  23. package/lib/js/components/Buttons/IconButton/IconButton.consts.ts +1 -0
  24. package/lib/js/components/Buttons/IconButton/IconButton.spec.ts +107 -0
  25. package/lib/js/components/Buttons/IconButton/IconButton.stories.ts +5 -1
  26. package/lib/js/components/Buttons/IconButton/IconButton.vue +45 -5
  27. package/lib/js/components/DatePickers/DatePicker/DatePicker.vue +5 -0
  28. package/lib/js/components/DatePickers/DateRangePicker/DateRangePicker.vue +5 -0
  29. package/lib/styles/components/_buttons.scss +96 -1
  30. package/lib/styles/design-system.scss +9 -3
  31. package/lib/styles/mixins/_scrollbars.scss +6 -2
  32. package/lib/styles/settings/_gradients-variables.scss +34 -0
  33. package/lib/styles/settings/_gradients.scss +4 -0
  34. package/lib/styles/settings/colors/_magic-variables.scss +10 -0
  35. package/lib/styles/settings/colors/_magic.scss +9 -0
  36. package/lib/styles/settings/colors/_raw-bodywork-dark.scss +22 -0
  37. package/lib/styles/settings/colors/_raw-mc-dark.scss +22 -0
  38. package/lib/styles/settings/colors/_raw-wnl-dark.scss +22 -0
  39. package/lib/styles/settings/colors/_raw.json +1 -1
  40. package/lib/styles/settings/colors/_raw.scss +26 -0
  41. package/lib/styles/settings/colors/_tokens-variables-dark.scss +513 -0
  42. package/package.json +1 -1
@@ -18,6 +18,7 @@ export declare const BUTTON_COLORS: {
18
18
  readonly DANGER: "danger";
19
19
  readonly SUCCESS: "success";
20
20
  readonly INVERTED: "inverted";
21
+ readonly MAGIC: "magic";
21
22
  };
22
23
  export type ButtonColor = Value<typeof BUTTON_COLORS>;
23
24
  export declare const BUTTON_RADIUSES: {
@@ -0,0 +1,5 @@
1
+ import { MaybeRefOrGetter } from 'vue';
2
+
3
+ export declare const GRADIENT_MAGIC_ICON_ID = "ds-gradient-magic-icon";
4
+ export declare const GRADIENT_MAGIC_ICON_DISABLED_ID = "ds-gradient-magic-icon-disabled";
5
+ export declare function useMagicGradient(enabled: MaybeRefOrGetter<boolean>): void;
@@ -29,6 +29,7 @@ export declare const ICON_BUTTON_COLORS: {
29
29
  readonly INVERTED: "inverted";
30
30
  readonly WARNING: "warning";
31
31
  readonly INFO: "info";
32
+ readonly MAGIC: "magic";
32
33
  };
33
34
  export type IconButtonColor = Value<typeof ICON_BUTTON_COLORS>;
34
35
  export declare const ICON_BUTTON_STATES: {
@@ -1,5 +1,5 @@
1
- import { ButtonElevation, ButtonRadius } from '../Button';
2
- import { ICON_BUTTON_STATES, IconButtonColor, IconButtonColorScheme, IconButtonSize, IconButtonType } from './IconButton.consts';
1
+ import { ButtonElevation, ButtonRadius, ButtonState } from '../Button';
2
+ import { ICON_BUTTON_STATES, IconButtonColor, IconButtonColorScheme, IconButtonSize, IconButtonState, IconButtonType } from './IconButton.consts';
3
3
  import { Value } from '../../../utils/type.utils';
4
4
 
5
5
  declare const _default: import('vue').DefineComponent<import('vue').ExtractPropTypes<{
@@ -48,6 +48,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
48
48
  validator(value: Value<typeof ICON_BUTTON_STATES>): boolean;
49
49
  };
50
50
  }>, {
51
+ ICON_BUTTON_STATE_MAP: Record<IconButtonState, ButtonState>;
51
52
  isHovered: import('vue').Ref<boolean>;
52
53
  mouseOver: () => void;
53
54
  mouseLeave: () => void;
@@ -371,6 +372,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
371
372
  readonly INVERTED: "inverted";
372
373
  readonly WARNING: "warning";
373
374
  readonly INFO: "info";
375
+ readonly MAGIC: "magic";
374
376
  }>;
375
377
  BUTTON_COLORS: Readonly<{
376
378
  readonly PRIMARY: "primary";
@@ -378,6 +380,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
378
380
  readonly DANGER: "danger";
379
381
  readonly SUCCESS: "success";
380
382
  readonly INVERTED: "inverted";
383
+ readonly MAGIC: "magic";
381
384
  }>;
382
385
  }, {
383
386
  iconSize(): string;
@@ -693,6 +693,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
693
693
  validator(value: import('../../../utils/type.utils').Value<typeof import('../../Buttons/IconButton').ICON_BUTTON_STATES>): boolean;
694
694
  };
695
695
  }>, {
696
+ ICON_BUTTON_STATE_MAP: Record<import('../../Buttons/IconButton').IconButtonState, import('../../Buttons/Button').ButtonState>;
696
697
  isHovered: import('vue').Ref<boolean>;
697
698
  mouseOver: () => void;
698
699
  mouseLeave: () => void;
@@ -1016,6 +1017,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
1016
1017
  readonly INVERTED: "inverted";
1017
1018
  readonly WARNING: "warning";
1018
1019
  readonly INFO: "info";
1020
+ readonly MAGIC: "magic";
1019
1021
  }>;
1020
1022
  BUTTON_COLORS: Readonly<{
1021
1023
  readonly PRIMARY: "primary";
@@ -1023,6 +1025,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
1023
1025
  readonly DANGER: "danger";
1024
1026
  readonly SUCCESS: "success";
1025
1027
  readonly INVERTED: "inverted";
1028
+ readonly MAGIC: "magic";
1026
1029
  }>;
1027
1030
  }, {
1028
1031
  iconSize(): string;
@@ -70,6 +70,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
70
70
  readonly INVERTED: "inverted";
71
71
  readonly WARNING: "warning";
72
72
  readonly INFO: "info";
73
+ readonly MAGIC: "magic";
73
74
  };
74
75
  ICON_BUTTON_SIZES: {
75
76
  readonly XX_SMALL: "xx-small";
@@ -806,6 +807,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
806
807
  readonly INVERTED: "inverted";
807
808
  readonly WARNING: "warning";
808
809
  readonly INFO: "info";
810
+ readonly MAGIC: "magic";
809
811
  }>;
810
812
  SECTION_HEADER_MOBILE_LAYOUTS: Readonly<{
811
813
  readonly VERTICAL: "vertical";
@@ -1027,6 +1029,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
1027
1029
  validator(value: import('../../../utils/type.utils').Value<typeof import('../../Buttons/IconButton').ICON_BUTTON_STATES>): boolean;
1028
1030
  };
1029
1031
  }>, {
1032
+ ICON_BUTTON_STATE_MAP: Record<import('../../Buttons/IconButton').IconButtonState, import('../../..').ButtonState>;
1030
1033
  isHovered: import('vue').Ref<boolean>;
1031
1034
  mouseOver: () => void;
1032
1035
  mouseLeave: () => void;
@@ -1350,6 +1353,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
1350
1353
  readonly INVERTED: "inverted";
1351
1354
  readonly WARNING: "warning";
1352
1355
  readonly INFO: "info";
1356
+ readonly MAGIC: "magic";
1353
1357
  }>;
1354
1358
  BUTTON_COLORS: Readonly<{
1355
1359
  readonly PRIMARY: "primary";
@@ -1357,6 +1361,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
1357
1361
  readonly DANGER: "danger";
1358
1362
  readonly SUCCESS: "success";
1359
1363
  readonly INVERTED: "inverted";
1364
+ readonly MAGIC: "magic";
1360
1365
  }>;
1361
1366
  }, {
1362
1367
  iconSize(): string;
@@ -58,6 +58,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
58
58
  readonly INVERTED: "inverted";
59
59
  readonly WARNING: "warning";
60
60
  readonly INFO: "info";
61
+ readonly MAGIC: "magic";
61
62
  }>;
62
63
  ICON_BUTTON_STATES: Readonly<{
63
64
  readonly DEFAULT: "default";
@@ -469,6 +470,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
469
470
  validator(value: Value<typeof ICON_BUTTON_STATES>): boolean;
470
471
  };
471
472
  }>, {
473
+ ICON_BUTTON_STATE_MAP: Record<import('../../Buttons/IconButton').IconButtonState, import('../../..').ButtonState>;
472
474
  isHovered: import('vue').Ref<boolean>;
473
475
  mouseOver: () => void;
474
476
  mouseLeave: () => void;
@@ -792,6 +794,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
792
794
  readonly INVERTED: "inverted";
793
795
  readonly WARNING: "warning";
794
796
  readonly INFO: "info";
797
+ readonly MAGIC: "magic";
795
798
  }>;
796
799
  BUTTON_COLORS: Readonly<{
797
800
  readonly PRIMARY: "primary";
@@ -799,6 +802,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
799
802
  readonly DANGER: "danger";
800
803
  readonly SUCCESS: "success";
801
804
  readonly INVERTED: "inverted";
805
+ readonly MAGIC: "magic";
802
806
  }>;
803
807
  }, {
804
808
  iconSize(): string;
@@ -370,6 +370,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
370
370
  readonly INVERTED: "inverted";
371
371
  readonly WARNING: "warning";
372
372
  readonly INFO: "info";
373
+ readonly MAGIC: "magic";
373
374
  }>;
374
375
  SECTION_HEADER_MOBILE_LAYOUTS: Readonly<{
375
376
  readonly VERTICAL: "vertical";
@@ -591,6 +592,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
591
592
  validator(value: import('../../../utils/type.utils').Value<typeof import('../../Buttons/IconButton').ICON_BUTTON_STATES>): boolean;
592
593
  };
593
594
  }>, {
595
+ ICON_BUTTON_STATE_MAP: Record<import('../../Buttons/IconButton').IconButtonState, import('../../..').ButtonState>;
594
596
  isHovered: import('vue').Ref<boolean>;
595
597
  mouseOver: () => void;
596
598
  mouseLeave: () => void;
@@ -914,6 +916,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
914
916
  readonly INVERTED: "inverted";
915
917
  readonly WARNING: "warning";
916
918
  readonly INFO: "info";
919
+ readonly MAGIC: "magic";
917
920
  }>;
918
921
  BUTTON_COLORS: Readonly<{
919
922
  readonly PRIMARY: "primary";
@@ -921,6 +924,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
921
924
  readonly DANGER: "danger";
922
925
  readonly SUCCESS: "success";
923
926
  readonly INVERTED: "inverted";
927
+ readonly MAGIC: "magic";
924
928
  }>;
925
929
  }, {
926
930
  iconSize(): string;
@@ -104,6 +104,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
104
104
  readonly DANGER: "danger";
105
105
  readonly SUCCESS: "success";
106
106
  readonly INVERTED: "inverted";
107
+ readonly MAGIC: "magic";
107
108
  };
108
109
  BUTTON_ELEVATIONS: {
109
110
  readonly NONE: "none";
@@ -399,6 +400,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
399
400
  readonly INVERTED: "inverted";
400
401
  readonly WARNING: "warning";
401
402
  readonly INFO: "info";
403
+ readonly MAGIC: "magic";
402
404
  };
403
405
  ICON_SIZES: {
404
406
  XXX_SMALL: string;
@@ -721,6 +723,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
721
723
  validator(value: import('../../../utils/type.utils').Value<typeof import('../../Buttons/IconButton').ICON_BUTTON_STATES>): boolean;
722
724
  };
723
725
  }>, {
726
+ ICON_BUTTON_STATE_MAP: Record<import('../../Buttons/IconButton').IconButtonState, ButtonState>;
724
727
  isHovered: import('vue').Ref<boolean>;
725
728
  mouseOver: () => void;
726
729
  mouseLeave: () => void;
@@ -1044,6 +1047,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
1044
1047
  readonly INVERTED: "inverted";
1045
1048
  readonly WARNING: "warning";
1046
1049
  readonly INFO: "info";
1050
+ readonly MAGIC: "magic";
1047
1051
  }>;
1048
1052
  BUTTON_COLORS: Readonly<{
1049
1053
  readonly PRIMARY: "primary";
@@ -1051,6 +1055,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
1051
1055
  readonly DANGER: "danger";
1052
1056
  readonly SUCCESS: "success";
1053
1057
  readonly INVERTED: "inverted";
1058
+ readonly MAGIC: "magic";
1054
1059
  }>;
1055
1060
  }, {
1056
1061
  iconSize(): string;
@@ -239,6 +239,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
239
239
  readonly DANGER: "danger";
240
240
  readonly SUCCESS: "success";
241
241
  readonly INVERTED: "inverted";
242
+ readonly MAGIC: "magic";
242
243
  };
243
244
  BUTTON_ELEVATIONS: {
244
245
  readonly NONE: "none";
@@ -534,6 +535,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
534
535
  readonly INVERTED: "inverted";
535
536
  readonly WARNING: "warning";
536
537
  readonly INFO: "info";
538
+ readonly MAGIC: "magic";
537
539
  };
538
540
  ICON_SIZES: {
539
541
  XXX_SMALL: string;
@@ -856,6 +858,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
856
858
  validator(value: import('../../../utils/type.utils').Value<typeof import('../../..').ICON_BUTTON_STATES>): boolean;
857
859
  };
858
860
  }>, {
861
+ ICON_BUTTON_STATE_MAP: Record<import('../../..').IconButtonState, ButtonState>;
859
862
  isHovered: import('vue').Ref<boolean>;
860
863
  mouseOver: () => void;
861
864
  mouseLeave: () => void;
@@ -1179,6 +1182,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
1179
1182
  readonly INVERTED: "inverted";
1180
1183
  readonly WARNING: "warning";
1181
1184
  readonly INFO: "info";
1185
+ readonly MAGIC: "magic";
1182
1186
  }>;
1183
1187
  BUTTON_COLORS: Readonly<{
1184
1188
  readonly PRIMARY: "primary";
@@ -1186,6 +1190,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
1186
1190
  readonly DANGER: "danger";
1187
1191
  readonly SUCCESS: "success";
1188
1192
  readonly INVERTED: "inverted";
1193
+ readonly MAGIC: "magic";
1189
1194
  }>;
1190
1195
  }, {
1191
1196
  iconSize(): string;
@@ -52,6 +52,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
52
52
  readonly INVERTED: "inverted";
53
53
  readonly WARNING: "warning";
54
54
  readonly INFO: "info";
55
+ readonly MAGIC: "magic";
55
56
  }>;
56
57
  ICON_BUTTON_STATES: Readonly<{
57
58
  readonly DEFAULT: "default";
@@ -423,6 +424,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
423
424
  validator(value: import('../../utils/type.utils').Value<typeof ICON_BUTTON_STATES>): boolean;
424
425
  };
425
426
  }>, {
427
+ ICON_BUTTON_STATE_MAP: Record<import('../Buttons/IconButton').IconButtonState, import('../..').ButtonState>;
426
428
  isHovered: import('vue').Ref<boolean>;
427
429
  mouseOver: () => void;
428
430
  mouseLeave: () => void;
@@ -746,6 +748,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
746
748
  readonly INVERTED: "inverted";
747
749
  readonly WARNING: "warning";
748
750
  readonly INFO: "info";
751
+ readonly MAGIC: "magic";
749
752
  }>;
750
753
  BUTTON_COLORS: Readonly<{
751
754
  readonly PRIMARY: "primary";
@@ -753,6 +756,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
753
756
  readonly DANGER: "danger";
754
757
  readonly SUCCESS: "success";
755
758
  readonly INVERTED: "inverted";
759
+ readonly MAGIC: "magic";
756
760
  }>;
757
761
  }, {
758
762
  iconSize(): string;
@@ -307,6 +307,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
307
307
  readonly INVERTED: "inverted";
308
308
  readonly WARNING: "warning";
309
309
  readonly INFO: "info";
310
+ readonly MAGIC: "magic";
310
311
  }>;
311
312
  ICON_SIZES: Readonly<{
312
313
  XXX_SMALL: string;
@@ -687,6 +688,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
687
688
  validator(value: import('../../../utils/type.utils').Value<typeof import('../../Buttons/IconButton').ICON_BUTTON_STATES>): boolean;
688
689
  };
689
690
  }>, {
691
+ ICON_BUTTON_STATE_MAP: Record<import('../../Buttons/IconButton').IconButtonState, import('../../Buttons/Button').ButtonState>;
690
692
  isHovered: import('vue').Ref<boolean>;
691
693
  mouseOver: () => void;
692
694
  mouseLeave: () => void;
@@ -1010,6 +1012,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
1010
1012
  readonly INVERTED: "inverted";
1011
1013
  readonly WARNING: "warning";
1012
1014
  readonly INFO: "info";
1015
+ readonly MAGIC: "magic";
1013
1016
  }>;
1014
1017
  BUTTON_COLORS: Readonly<{
1015
1018
  readonly PRIMARY: "primary";
@@ -1017,6 +1020,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
1017
1020
  readonly DANGER: "danger";
1018
1021
  readonly SUCCESS: "success";
1019
1022
  readonly INVERTED: "inverted";
1023
+ readonly MAGIC: "magic";
1020
1024
  }>;
1021
1025
  }, {
1022
1026
  iconSize(): string;
@@ -336,6 +336,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
336
336
  readonly INVERTED: "inverted";
337
337
  readonly WARNING: "warning";
338
338
  readonly INFO: "info";
339
+ readonly MAGIC: "magic";
339
340
  }>;
340
341
  BUTTON_TYPES: Readonly<{
341
342
  readonly FILLED: "filled";
@@ -659,6 +660,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
659
660
  validator(value: import('../../../utils/type.utils').Value<typeof import('../../Buttons/IconButton').ICON_BUTTON_STATES>): boolean;
660
661
  };
661
662
  }>, {
663
+ ICON_BUTTON_STATE_MAP: Record<import('../../Buttons/IconButton').IconButtonState, import('../../Buttons/Button').ButtonState>;
662
664
  isHovered: import('vue').Ref<boolean>;
663
665
  mouseOver: () => void;
664
666
  mouseLeave: () => void;
@@ -982,6 +984,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
982
984
  readonly INVERTED: "inverted";
983
985
  readonly WARNING: "warning";
984
986
  readonly INFO: "info";
987
+ readonly MAGIC: "magic";
985
988
  }>;
986
989
  BUTTON_COLORS: Readonly<{
987
990
  readonly PRIMARY: "primary";
@@ -989,6 +992,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
989
992
  readonly DANGER: "danger";
990
993
  readonly SUCCESS: "success";
991
994
  readonly INVERTED: "inverted";
995
+ readonly MAGIC: "magic";
992
996
  }>;
993
997
  }, {
994
998
  iconSize(): string;
@@ -55,6 +55,7 @@ declare const _default: import('vue').DefineComponent<import('vue').ExtractPropT
55
55
  readonly DANGER: "danger";
56
56
  readonly SUCCESS: "success";
57
57
  readonly INVERTED: "inverted";
58
+ readonly MAGIC: "magic";
58
59
  }>;
59
60
  BUTTON_RADIUSES: Readonly<{
60
61
  readonly CAPSULE: "capsule";
@@ -22,6 +22,7 @@ export const BUTTON_COLORS = {
22
22
  DANGER: 'danger',
23
23
  SUCCESS: 'success',
24
24
  INVERTED: 'inverted',
25
+ MAGIC: 'magic',
25
26
  } as const;
26
27
 
27
28
  export type ButtonColor = Value<typeof BUTTON_COLORS>;
@@ -9,6 +9,7 @@ import {
9
9
  BUTTON_STATES,
10
10
  BUTTON_TYPES,
11
11
  } from './Button.consts';
12
+ import { GRADIENT_MAGIC_ICON_DISABLED_ID, GRADIENT_MAGIC_ICON_ID } from './useMagicGradient';
12
13
  import Icon, { ICONS } from '../../Icons/Icon';
13
14
 
14
15
  describe('Button', () => {
@@ -35,6 +36,12 @@ describe('Button', () => {
35
36
  [{ props: { color: BUTTON_COLORS.PRIMARY }, expectedClass: '-ds-color-primary' }],
36
37
  [{ props: { color: BUTTON_COLORS.DANGER }, expectedClass: '-ds-color-danger' }],
37
38
  [{ props: { color: BUTTON_COLORS.SUCCESS }, expectedClass: '-ds-color-success' }],
39
+ [
40
+ {
41
+ props: { color: BUTTON_COLORS.MAGIC, type: BUTTON_TYPES.OUTLINED },
42
+ expectedClass: '-ds-color-magic',
43
+ },
44
+ ],
38
45
  [{ props: { radius: BUTTON_RADIUSES.ROUNDED }, expectedClass: '-ds-rounded' }],
39
46
  [{ props: { state: BUTTON_STATES.HOVERED }, expectedClass: '-ds-hovered' }],
40
47
  [{ props: { state: BUTTON_STATES.FOCUSED }, expectedClass: '-ds-focused' }],
@@ -45,6 +52,34 @@ describe('Button', () => {
45
52
  expect(outlinedButton.classes()).toContain(expectedClass);
46
53
  });
47
54
 
55
+ it('magic button fills with the magic gradient', () => {
56
+ const component = createComponent({ color: BUTTON_COLORS.MAGIC });
57
+
58
+ expect(component.element.style.getPropertyValue('--ds-magic-fill')).toBe(
59
+ `url(#${GRADIENT_MAGIC_ICON_ID})`,
60
+ );
61
+ });
62
+
63
+ it('disabled magic button fills with the disabled magic gradient', () => {
64
+ const component = createComponent({
65
+ color: BUTTON_COLORS.MAGIC,
66
+ state: BUTTON_STATES.DISABLED,
67
+ });
68
+
69
+ expect(component.element.style.getPropertyValue('--ds-magic-fill')).toBe(
70
+ `url(#${GRADIENT_MAGIC_ICON_DISABLED_ID})`,
71
+ );
72
+ });
73
+
74
+ it('non-magic button has no magic fill style', () => {
75
+ const component = createComponent({
76
+ color: BUTTON_COLORS.PRIMARY,
77
+ state: BUTTON_STATES.DISABLED,
78
+ });
79
+
80
+ expect(component.element.style.getPropertyValue('--ds-magic-fill')).toBe('');
81
+ });
82
+
48
83
  it('loading should have correct text container and loading icon', () => {
49
84
  const component = createComponent({ state: BUTTON_STATES.LOADING });
50
85
 
@@ -21,6 +21,17 @@
21
21
  '-ds-elevation-x-small': elevation === BUTTON_ELEVATIONS.X_SMALL,
22
22
  '-ds-elevation-small': elevation === BUTTON_ELEVATIONS.SMALL,
23
23
  }"
24
+ :style="
25
+ color === BUTTON_COLORS.MAGIC
26
+ ? {
27
+ '--ds-magic-fill': `url(#${
28
+ state === BUTTON_STATES.DISABLED
29
+ ? GRADIENT_MAGIC_ICON_DISABLED_ID
30
+ : GRADIENT_MAGIC_ICON_ID
31
+ })`,
32
+ }
33
+ : undefined
34
+ "
24
35
  >
25
36
  <span class="ds-button__content">
26
37
  <wnl-icon
@@ -65,6 +76,11 @@ import {
65
76
  ButtonElevation,
66
77
  } from './Button.consts';
67
78
  import { computed } from 'vue';
79
+ import {
80
+ GRADIENT_MAGIC_ICON_DISABLED_ID,
81
+ GRADIENT_MAGIC_ICON_ID,
82
+ useMagicGradient,
83
+ } from './useMagicGradient';
68
84
 
69
85
  const {
70
86
  size = BUTTON_SIZES.MEDIUM,
@@ -100,6 +116,9 @@ const colorClassName = computed((): string => {
100
116
  return `-ds-color-${color}`;
101
117
  });
102
118
 
119
+ // The loading spinner's icon fills via `url(#MAGIC_GRADIENT_ID)`; ensure that def exists.
120
+ useMagicGradient(() => color === BUTTON_COLORS.MAGIC);
121
+
103
122
  const loadingIconSize = computed((): IconSize => {
104
123
  if (size === BUTTON_SIZES.LARGE) {
105
124
  return ICON_SIZES.MEDIUM;
@@ -0,0 +1,47 @@
1
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
2
+ import { ref } from 'vue';
3
+
4
+ import { GRADIENT_MAGIC_ICON_ID, useMagicGradient } from './useMagicGradient';
5
+
6
+ describe('useMagicGradient', () => {
7
+ beforeEach(() => {
8
+ document.getElementById(GRADIENT_MAGIC_ICON_ID)?.remove();
9
+ });
10
+ afterEach(() => {
11
+ document.getElementById(GRADIENT_MAGIC_ICON_ID)?.remove();
12
+ });
13
+
14
+ it('injects a single linearGradient with the hardcoded id when enabled', () => {
15
+ useMagicGradient(true);
16
+
17
+ const gradient = document.getElementById(GRADIENT_MAGIC_ICON_ID);
18
+ expect(gradient).not.toBeNull();
19
+ expect(gradient?.tagName.toLowerCase()).toBe('lineargradient');
20
+ });
21
+
22
+ it('does not inject the def when disabled', () => {
23
+ useMagicGradient(false);
24
+
25
+ expect(document.getElementById(GRADIENT_MAGIC_ICON_ID)).toBeNull();
26
+ });
27
+
28
+ it('injects the def when the reactive source becomes enabled', async () => {
29
+ const enabled = ref(false);
30
+ useMagicGradient(enabled);
31
+
32
+ expect(document.getElementById(GRADIENT_MAGIC_ICON_ID)).toBeNull();
33
+
34
+ enabled.value = true;
35
+ await Promise.resolve();
36
+
37
+ expect(document.getElementById(GRADIENT_MAGIC_ICON_ID)).not.toBeNull();
38
+ });
39
+
40
+ it('is idempotent — multiple enabled consumers leave exactly one def', () => {
41
+ useMagicGradient(true);
42
+ useMagicGradient(() => true);
43
+ useMagicGradient(ref(true));
44
+
45
+ expect(document.querySelectorAll(`#${GRADIENT_MAGIC_ICON_ID}`)).toHaveLength(1);
46
+ });
47
+ });
@@ -0,0 +1,50 @@
1
+ import { toValue, watch, type MaybeRefOrGetter } from 'vue';
2
+
3
+ export const GRADIENT_MAGIC_ICON_ID = 'ds-gradient-magic-icon';
4
+ export const GRADIENT_MAGIC_ICON_DISABLED_ID = 'ds-gradient-magic-icon-disabled';
5
+
6
+ // SVG icons (the loading spinner) fill with the magic gradient via `fill: url(#...)`, which
7
+ // CSS gradients can't do. The gradient is identical for every magic button, so a single
8
+ // shared def is injected into <body> once and left for the page lifetime (invisible, 0×0).
9
+ function ensureMagicGradientDef(): void {
10
+ if (typeof document === 'undefined') {
11
+ return; // SSR guard
12
+ }
13
+ if (document.getElementById(GRADIENT_MAGIC_ICON_ID)) {
14
+ return; // already injected
15
+ }
16
+ // `var()` works in the `style` property but not in the `stop-color` presentation
17
+ // attribute, so stop colors are set inline.
18
+ document.body.insertAdjacentHTML(
19
+ 'beforeend',
20
+ `<svg aria-hidden="true" width="0" height="0" style="position:absolute">
21
+ <defs>
22
+ <linearGradient id="${GRADIENT_MAGIC_ICON_ID}" x1="0" y1="0" x2="1" y2="0.17">
23
+ <stop offset="7%" style="stop-color:var(--gradient-magic-color-1)"/>
24
+ <stop offset="36%" style="stop-color:var(--gradient-magic-color-2)"/>
25
+ <stop offset="65%" style="stop-color:var(--gradient-magic-color-3)"/>
26
+ <stop offset="95%" style="stop-color:var(--gradient-magic-color-4)"/>
27
+ </linearGradient>
28
+ <linearGradient id="${GRADIENT_MAGIC_ICON_DISABLED_ID}" x1="0" y1="0" x2="1" y2="0.17">
29
+ <stop offset="7.16%" style="stop-color:rgba(var(--gradient-magic-color-1-rgb), 0.3)"/>
30
+ <stop offset="36.18%" style="stop-color:rgba(var(--gradient-magic-color-2-rgb), 0.3)"/>
31
+ <stop offset="65.19%" style="stop-color:rgba(var(--gradient-magic-color-3-rgb), 0.3)"/>
32
+ <stop offset="95.08%" style="stop-color:rgba(var(--gradient-magic-color-4-rgb), 0.3)"/>
33
+ </linearGradient>
34
+ </defs>
35
+ </svg>`,
36
+ );
37
+ }
38
+
39
+ // Injects the shared magic-gradient def once `enabled` becomes truthy (immediate + reactive).
40
+ export function useMagicGradient(enabled: MaybeRefOrGetter<boolean>): void {
41
+ watch(
42
+ () => toValue(enabled),
43
+ (isEnabled) => {
44
+ if (isEnabled) {
45
+ ensureMagicGradientDef();
46
+ }
47
+ },
48
+ { immediate: true },
49
+ );
50
+ }
@@ -36,6 +36,7 @@ export const ICON_BUTTON_COLORS = {
36
36
  INVERTED: 'inverted',
37
37
  WARNING: 'warning',
38
38
  INFO: 'info',
39
+ MAGIC: 'magic',
39
40
  } as const;
40
41
 
41
42
  export type IconButtonColor = Value<typeof ICON_BUTTON_COLORS>;