@transferwise/components 46.85.0 → 46.86.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 (123) hide show
  1. package/build/avatarLayout/AvatarLayout.js +4 -3
  2. package/build/avatarLayout/AvatarLayout.js.map +1 -1
  3. package/build/avatarLayout/AvatarLayout.mjs +4 -3
  4. package/build/avatarLayout/AvatarLayout.mjs.map +1 -1
  5. package/build/avatarView/AvatarView.js +12 -1
  6. package/build/avatarView/AvatarView.js.map +1 -1
  7. package/build/avatarView/AvatarView.mjs +12 -1
  8. package/build/avatarView/AvatarView.mjs.map +1 -1
  9. package/build/circularButton/CircularButton.js +18 -21
  10. package/build/circularButton/CircularButton.js.map +1 -1
  11. package/build/circularButton/CircularButton.mjs +19 -22
  12. package/build/circularButton/CircularButton.mjs.map +1 -1
  13. package/build/definitionList/DefinitionList.js.map +1 -1
  14. package/build/definitionList/DefinitionList.mjs.map +1 -1
  15. package/build/i18n/de.json +1 -0
  16. package/build/i18n/de.json.js +1 -0
  17. package/build/i18n/de.json.js.map +1 -1
  18. package/build/i18n/de.json.mjs +1 -0
  19. package/build/i18n/de.json.mjs.map +1 -1
  20. package/build/i18n/es.json +1 -0
  21. package/build/i18n/es.json.js +1 -0
  22. package/build/i18n/es.json.js.map +1 -1
  23. package/build/i18n/es.json.mjs +1 -0
  24. package/build/i18n/es.json.mjs.map +1 -1
  25. package/build/i18n/fr.json +6 -5
  26. package/build/i18n/fr.json.js +6 -5
  27. package/build/i18n/fr.json.js.map +1 -1
  28. package/build/i18n/fr.json.mjs +6 -5
  29. package/build/i18n/fr.json.mjs.map +1 -1
  30. package/build/i18n/hu.json +1 -0
  31. package/build/i18n/hu.json.js +1 -0
  32. package/build/i18n/hu.json.js.map +1 -1
  33. package/build/i18n/hu.json.mjs +1 -0
  34. package/build/i18n/hu.json.mjs.map +1 -1
  35. package/build/i18n/id.json +1 -0
  36. package/build/i18n/id.json.js +1 -0
  37. package/build/i18n/id.json.js.map +1 -1
  38. package/build/i18n/id.json.mjs +1 -0
  39. package/build/i18n/id.json.mjs.map +1 -1
  40. package/build/i18n/it.json +1 -0
  41. package/build/i18n/it.json.js +1 -0
  42. package/build/i18n/it.json.js.map +1 -1
  43. package/build/i18n/it.json.mjs +1 -0
  44. package/build/i18n/it.json.mjs.map +1 -1
  45. package/build/i18n/pl.json +1 -0
  46. package/build/i18n/pl.json.js +1 -0
  47. package/build/i18n/pl.json.js.map +1 -1
  48. package/build/i18n/pl.json.mjs +1 -0
  49. package/build/i18n/pl.json.mjs.map +1 -1
  50. package/build/i18n/ro.json +1 -0
  51. package/build/i18n/ro.json.js +1 -0
  52. package/build/i18n/ro.json.js.map +1 -1
  53. package/build/i18n/ro.json.mjs +1 -0
  54. package/build/i18n/ro.json.mjs.map +1 -1
  55. package/build/i18n/th.json +1 -0
  56. package/build/i18n/th.json.js +1 -0
  57. package/build/i18n/th.json.js.map +1 -1
  58. package/build/i18n/th.json.mjs +1 -0
  59. package/build/i18n/th.json.mjs.map +1 -1
  60. package/build/i18n/tr.json +1 -0
  61. package/build/i18n/tr.json.js +1 -0
  62. package/build/i18n/tr.json.js.map +1 -1
  63. package/build/i18n/tr.json.mjs +1 -0
  64. package/build/i18n/tr.json.mjs.map +1 -1
  65. package/build/i18n/zh-CN.json +1 -0
  66. package/build/i18n/zh-CN.json.js +1 -0
  67. package/build/i18n/zh-CN.json.js.map +1 -1
  68. package/build/i18n/zh-CN.json.mjs +1 -0
  69. package/build/i18n/zh-CN.json.mjs.map +1 -1
  70. package/build/main.css +18 -159
  71. package/build/moneyInput/MoneyInput.js.map +1 -1
  72. package/build/moneyInput/MoneyInput.mjs.map +1 -1
  73. package/build/styles/avatarLayout/AvatarLayout.css +1 -1
  74. package/build/styles/circularButton/CircularButton.css +17 -158
  75. package/build/styles/main.css +18 -159
  76. package/build/types/avatarLayout/AvatarLayout.d.ts.map +1 -1
  77. package/build/types/avatarView/AvatarView.d.ts.map +1 -1
  78. package/build/types/circularButton/CircularButton.d.ts +11 -4
  79. package/build/types/circularButton/CircularButton.d.ts.map +1 -1
  80. package/build/types/definitionList/DefinitionList.d.ts +1 -2
  81. package/build/types/definitionList/DefinitionList.d.ts.map +1 -1
  82. package/build/types/moneyInput/MoneyInput.d.ts +1 -1
  83. package/build/types/moneyInput/MoneyInput.d.ts.map +1 -1
  84. package/package.json +3 -3
  85. package/src/avatar/Avatar.story.tsx +4 -1
  86. package/src/avatarLayout/AvatarLayout.css +1 -1
  87. package/src/avatarLayout/AvatarLayout.less +1 -1
  88. package/src/avatarLayout/AvatarLayout.story.tsx +2 -0
  89. package/src/avatarLayout/AvatarLayout.tsx +6 -4
  90. package/src/avatarView/AvatarView.tsx +15 -1
  91. package/src/avatarWrapper/AvatarWrapper.story.tsx +4 -0
  92. package/src/badge/Badge.story.tsx +4 -0
  93. package/src/circularButton/CircularButton.css +17 -158
  94. package/src/circularButton/CircularButton.less +22 -91
  95. package/src/circularButton/CircularButton.story.tsx +45 -24
  96. package/src/circularButton/CircularButton.tsx +38 -25
  97. package/src/dateInput/DateInput.spec.tsx +45 -26
  98. package/src/definitionList/DefinitionList.story.tsx +57 -57
  99. package/src/definitionList/DefinitionList.tsx +1 -1
  100. package/src/i18n/de.json +1 -0
  101. package/src/i18n/es.json +1 -0
  102. package/src/i18n/fr.json +6 -5
  103. package/src/i18n/hu.json +1 -0
  104. package/src/i18n/id.json +1 -0
  105. package/src/i18n/it.json +1 -0
  106. package/src/i18n/pl.json +1 -0
  107. package/src/i18n/ro.json +1 -0
  108. package/src/i18n/th.json +1 -0
  109. package/src/i18n/tr.json +1 -0
  110. package/src/i18n/zh-CN.json +1 -0
  111. package/src/iconButton/IconButton.story.tsx +6 -6
  112. package/src/main.css +18 -159
  113. package/src/moneyInput/MoneyInput.spec.tsx +468 -0
  114. package/src/moneyInput/MoneyInput.tsx +2 -1
  115. package/src/phoneNumberInput/PhoneNumberInput.spec.tsx +283 -0
  116. package/src/slidingPanel/SlidingPanel.spec.tsx +69 -0
  117. package/src/circularButton/_button-label-states.less +0 -34
  118. package/src/definitionList/DefinitionList.spec.js +0 -91
  119. package/src/moneyInput/MoneyInput.rtl.spec.tsx +0 -149
  120. package/src/moneyInput/MoneyInput.spec.js +0 -820
  121. package/src/phoneNumberInput/PhoneNumberInput.rtl.spec.tsx +0 -32
  122. package/src/phoneNumberInput/PhoneNumberInput.spec.js +0 -356
  123. package/src/slidingPanel/SlidingPanel.spec.js +0 -56
@@ -2,173 +2,32 @@
2
2
  display: inline-flex;
3
3
  flex-direction: column;
4
4
  align-items: center;
5
- text-align: center;
6
5
  cursor: pointer;
7
- position: relative;
8
6
  }
9
- .np-circular-btn .tw-icon {
10
- position: absolute;
11
- top: 16px;
12
- top: var(--size-16);
13
- pointer-events: none;
14
- color: white;
15
- transition: color 0.15s ease-in-out;
16
- width: 100%;
17
- left: 0;
18
- }
19
- [dir="rtl"] .np-circular-btn .tw-icon {
20
- right: 0;
21
- left: auto;
22
- left: initial;
23
- }
24
- @media (max-width: 320px) {
25
- .np-circular-btn .tw-icon {
26
- top: 12px;
27
- top: var(--size-12);
28
- }
29
- }
30
- .np-circular-btn .tw-icon > svg {
31
- margin: 0 auto;
32
- }
33
- .np-theme-personal .np-circular-btn {
34
- /* stylelint-disable-next-line no-duplicate-selectors */
35
- }
36
- .np-theme-personal .np-circular-btn .tw-icon,
37
- .np-theme-personal .np-circular-btn .tw-icon:hover,
38
- .np-theme-personal .np-circular-btn .tw-icon:active {
39
- color: var(--color-interactive-control);
40
- }
41
- .np-theme-personal .np-circular-btn.negative .tw-icon,
42
- .np-theme-personal .np-circular-btn.negative.secondary:not(.disabled):not(:disabled):hover .tw-icon,
43
- .np-theme-personal .np-circular-btn.negative.secondary:not(.disabled):not(:disabled):active .tw-icon {
44
- color: var(--color-contrast) !important;
45
- }
46
- .np-theme-personal .np-circular-btn.negative.secondary:not(.disabled):not(:disabled) .tw-icon {
47
- color: var(--color-sentiment-negative) !important;
48
- }
49
- .np-circular-btn.accent .np-circular-btn__label {
50
- color: #00a2dd;
51
- color: var(--color-interactive-accent);
52
- }
53
- .np-circular-btn.accent:not(.disabled):not(:disabled):hover .np-circular-btn__label {
54
- color: #008fc9;
55
- color: var(--color-interactive-accent-hover);
56
- }
57
- .np-circular-btn.accent:active .np-circular-btn__label,
58
- .np-circular-btn.accent input[type="button"]:active ~ .np-circular-btn__label {
59
- color: #0081ba;
60
- color: var(--color-interactive-accent-active);
61
- }
62
- .np-circular-btn.accent.secondary .tw-icon {
63
- color: #00a2dd;
64
- color: var(--color-interactive-accent);
65
- }
66
- .np-circular-btn.accent.secondary:not(.disabled):not(:disabled):hover .tw-icon,
67
- .np-circular-btn.accent.secondary input[type="button"]:active + .tw-icon {
68
- color: white;
69
- }
70
- .np-circular-btn.positive .np-circular-btn__label {
71
- color: #2ead4b;
72
- color: var(--color-interactive-positive);
73
- }
74
- .np-circular-btn.positive:not(.disabled):not(:disabled):hover .np-circular-btn__label {
75
- color: #069939;
76
- color: var(--color-interactive-positive-hover);
77
- }
78
- .np-circular-btn.positive:active .np-circular-btn__label,
79
- .np-circular-btn.positive input[type="button"]:active ~ .np-circular-btn__label {
80
- color: #008b2b;
81
- color: var(--color-interactive-positive-active);
82
- }
83
- .np-circular-btn.positive.secondary .tw-icon {
84
- color: #2ead4b;
85
- color: var(--color-interactive-positive);
86
- }
87
- .np-circular-btn.positive.secondary:not(.disabled):not(:disabled):hover .tw-icon,
88
- .np-circular-btn.positive.secondary input[type="button"]:active + .tw-icon {
89
- color: white;
90
- }
91
- .np-circular-btn.negative .np-circular-btn__label {
92
- color: #e74848;
93
- color: var(--color-interactive-negative);
94
- }
95
- .np-circular-btn.negative:not(.disabled):not(:disabled):hover .np-circular-btn__label {
96
- color: #d03238;
97
- color: var(--color-interactive-negative-hover);
98
- }
99
- .np-circular-btn.negative:active .np-circular-btn__label,
100
- .np-circular-btn.negative input[type="button"]:active ~ .np-circular-btn__label {
101
- color: #bf1e2c;
102
- color: var(--color-interactive-negative-active);
103
- }
104
- .np-circular-btn.negative.secondary .tw-icon {
105
- color: #e74848;
106
- color: var(--color-interactive-negative);
107
- }
108
- .np-circular-btn.negative.secondary:not(.disabled):not(:disabled):hover .tw-icon,
109
- .np-circular-btn.negative.secondary input[type="button"]:active + .tw-icon {
110
- color: white;
111
- }
112
- .np-theme-personal .np-circular-btn.accent .np-circular-btn__label {
7
+ .np-circular-btn-primary-default .np-circular-btn-label,
8
+ .np-circular-btn-secondary-default .np-circular-btn-label {
113
9
  color: var(--color-interactive-primary);
114
10
  }
115
- .np-theme-personal .np-circular-btn.accent:not(.disabled):not(:disabled):hover .np-circular-btn__label {
11
+ .np-circular-btn-primary-default .np-circular-btn-label:not(.disabled):not(:disabled):hover,
12
+ .np-circular-btn-secondary-default .np-circular-btn-label:not(.disabled):not(:disabled):hover {
116
13
  color: var(--color-interactive-primary-hover);
117
14
  }
118
- .np-theme-personal .np-circular-btn.accent:active .np-circular-btn__label,
119
- .np-theme-personal .np-circular-btn.accent input[type="button"]:active ~ .np-circular-btn__label {
15
+ .np-circular-btn-primary-default .np-circular-btn-label:not(.disabled):not(:disabled):active,
16
+ .np-circular-btn-secondary-default .np-circular-btn-label:not(.disabled):not(:disabled):active {
120
17
  color: var(--color-interactive-primary-active);
121
18
  }
122
- .np-theme-personal .np-circular-btn.accent.secondary .tw-icon {
123
- color: var(--color-interactive-primary);
124
- }
125
- .np-theme-personal .np-circular-btn.accent.secondary:not(.disabled):not(:disabled):hover .tw-icon,
126
- .np-theme-personal .np-circular-btn.accent.secondary input[type="button"]:active + .tw-icon {
127
- color: white;
128
- color: var(--color-interactive-control);
129
- }
130
- .np-theme-personal .np-circular-btn.accent.secondary:active input[type="button"] + .tw-icon {
131
- color: var(--color-interactive-control);
132
- }
133
- .np-theme-personal .np-circular-btn.positive .np-circular-btn__label {
134
- color: var(--color-interactive-primary);
135
- }
136
- .np-theme-personal .np-circular-btn.positive:not(.disabled):not(:disabled):hover .np-circular-btn__label {
137
- color: var(--color-interactive-primary-hover);
138
- }
139
- .np-theme-personal .np-circular-btn.positive:active .np-circular-btn__label,
140
- .np-theme-personal .np-circular-btn.positive input[type="button"]:active ~ .np-circular-btn__label {
141
- color: var(--color-interactive-primary-active);
142
- }
143
- .np-theme-personal .np-circular-btn.positive.secondary .tw-icon {
144
- color: var(--color-interactive-primary);
145
- }
146
- .np-theme-personal .np-circular-btn.positive.secondary:not(.disabled):not(:disabled):hover .tw-icon,
147
- .np-theme-personal .np-circular-btn.positive.secondary input[type="button"]:active + .tw-icon {
148
- color: white;
149
- color: var(--color-interactive-control);
150
- }
151
- .np-theme-personal .np-circular-btn.positive.secondary:active input[type="button"] + .tw-icon {
152
- color: var(--color-interactive-control);
153
- }
154
- .np-theme-personal .np-circular-btn.negative .np-circular-btn__label {
155
- color: var(--color-sentiment-negative);
156
- }
157
- .np-theme-personal .np-circular-btn.negative:not(.disabled):not(:disabled):hover .np-circular-btn__label {
158
- color: var(--color-sentiment-negative-hover);
159
- }
160
- .np-theme-personal .np-circular-btn.negative:active .np-circular-btn__label,
161
- .np-theme-personal .np-circular-btn.negative input[type="button"]:active ~ .np-circular-btn__label {
162
- color: var(--color-sentiment-negative-active);
19
+ .np-circular-btn-primary-negative .np-circular-btn-label,
20
+ .np-circular-btn-secondary-negative .np-circular-btn-label {
21
+ color: var(--color-sentiment-negative-primary);
163
22
  }
164
- .np-theme-personal .np-circular-btn.negative.secondary .tw-icon {
165
- color: var(--color-sentiment-negative);
23
+ .np-circular-btn-primary-negative .np-circular-btn-label:not(.disabled):not(:disabled):hover,
24
+ .np-circular-btn-secondary-negative .np-circular-btn-label:not(.disabled):not(:disabled):hover {
25
+ color: var(--color-sentiment-negative-primary-hover);
166
26
  }
167
- .np-theme-personal .np-circular-btn.negative.secondary:not(.disabled):not(:disabled):hover .tw-icon,
168
- .np-theme-personal .np-circular-btn.negative.secondary input[type="button"]:active + .tw-icon {
169
- color: white;
170
- color: var(--color-interactive-control);
27
+ .np-circular-btn-primary-negative .np-circular-btn-label:not(.disabled):not(:disabled):active,
28
+ .np-circular-btn-secondary-negative .np-circular-btn-label:not(.disabled):not(:disabled):active {
29
+ color: var(--color-sentiment-negative-primary-active);
171
30
  }
172
- .np-theme-personal .np-circular-btn.negative.secondary:active input[type="button"] + .tw-icon {
173
- color: var(--color-interactive-control);
31
+ .np-circular-btn-disabled {
32
+ cursor: not-allowed;
174
33
  }
@@ -1,105 +1,36 @@
1
- @import (reference) "../../node_modules/@transferwise/neptune-css/src/less/mixins/_logical-properties.less";
2
- @import "./_button-label-states.less";
3
-
4
1
  .np-circular-btn {
5
2
  display: inline-flex;
6
3
  flex-direction: column;
7
4
  align-items: center;
8
- text-align: center;
9
5
  cursor: pointer;
10
- position: relative;
11
-
12
- .tw-icon {
13
- position: absolute;
14
- top: var(--size-16);
15
- pointer-events: none;
16
- color: white;
17
- transition: color 0.15s ease-in-out;
18
- width: 100%;
19
- .left(0);
20
6
 
21
- @media (--screen-400-zoom) {
22
- top: var(--size-12);
23
- }
24
-
25
- > svg {
26
- margin: 0 auto;
7
+ &-primary-default,
8
+ &-secondary-default {
9
+ .np-circular-btn-label {
10
+ color: var(--color-interactive-primary);
11
+ &:not(.disabled, :disabled):hover {
12
+ color: var(--color-interactive-primary-hover);
13
+ }
14
+ &:not(.disabled, :disabled):active {
15
+ color: var(--color-interactive-primary-active);
16
+ }
27
17
  }
28
18
  }
29
19
 
30
- .np-theme-personal & {
31
- /* stylelint-disable-next-line no-duplicate-selectors */
32
- .tw-icon {
33
- &,
34
- &:hover,
35
- &:active {
36
- color: var(--color-interactive-control);
20
+ &-primary-negative,
21
+ &-secondary-negative {
22
+ .np-circular-btn-label {
23
+ color: var(--color-sentiment-negative-primary);
24
+ &:not(.disabled, :disabled):hover {
25
+ color: var(--color-sentiment-negative-primary-hover);
26
+ }
27
+ &:not(.disabled, :disabled):active {
28
+ color: var(--color-sentiment-negative-primary-active);
37
29
  }
38
- }
39
-
40
- &.negative .tw-icon,
41
- &.negative.secondary:not(.disabled, :disabled):hover .tw-icon,
42
- &.negative.secondary:not(.disabled, :disabled):active .tw-icon {
43
- // TODO, this will need to be removed when we update our CSS architecture
44
- color: var(--color-contrast) !important;
45
- }
46
-
47
- &.negative.secondary:not(.disabled, :disabled) .tw-icon {
48
- // TODO, this will need to be removed when we update our CSS architecture
49
- color: var(--color-sentiment-negative) !important;
50
30
  }
51
31
  }
52
- }
53
-
54
- .button-label-states(
55
- np-circular-btn,
56
- accent,
57
- var(--color-interactive-accent),
58
- var(--color-interactive-accent-hover),
59
- var(--color-interactive-accent-active)
60
- );
61
-
62
- .button-label-states(
63
- np-circular-btn,
64
- positive,
65
- var(--color-interactive-positive),
66
- var(--color-interactive-positive-hover),
67
- var(--color-interactive-positive-active)
68
- );
69
32
 
70
- .button-label-states(
71
- np-circular-btn,
72
- negative,
73
- var(--color-interactive-negative),
74
- var(--color-interactive-negative-hover),
75
- var(--color-interactive-negative-active)
76
- );
77
-
78
- .np-theme-personal {
79
- .button-label-states(
80
- np-circular-btn,
81
- accent,
82
- var(--color-interactive-primary),
83
- var(--color-interactive-primary-hover),
84
- var(--color-interactive-primary-active),
85
- true
86
- );
87
-
88
- .button-label-states(
89
- np-circular-btn,
90
- positive,
91
- var(--color-interactive-primary),
92
- var(--color-interactive-primary-hover),
93
- var(--color-interactive-primary-active),
94
- true
95
- );
96
-
97
- .button-label-states(
98
- np-circular-btn,
99
- negative,
100
- var(--color-sentiment-negative),
101
- var(--color-sentiment-negative-hover),
102
- var(--color-sentiment-negative-active),
103
- true
104
- );
33
+ &-disabled {
34
+ cursor: not-allowed;
35
+ }
105
36
  }
@@ -5,14 +5,16 @@ import { ControlType, Priority } from '../common';
5
5
  import { Meta, StoryObj } from '@storybook/react';
6
6
  import CircularButton from './CircularButton';
7
7
  import { storyConfig } from '../test-utils';
8
+ import Title from '../title';
9
+ import Body from '../body';
8
10
 
9
11
  export default {
10
12
  component: CircularButton,
11
13
  title: 'Actions/CircularButton',
14
+ tags: ['autodocs'],
12
15
  args: {
13
16
  children: 'Button text',
14
- // Needs to be cast because we're mapping icon names to components
15
- icon: 'Freeze' as unknown as React.ReactElement,
17
+ icon: <Icons.Freeze />,
16
18
  },
17
19
  argTypes: {
18
20
  icon: {
@@ -28,8 +30,8 @@ type Story = StoryObj<typeof CircularButton>;
28
30
 
29
31
  export const Basic: Story = {
30
32
  args: {
31
- priority: Priority.PRIMARY,
32
- type: ControlType.ACCENT,
33
+ priority: 'primary',
34
+ type: 'default',
33
35
  disabled: false,
34
36
  },
35
37
  };
@@ -41,26 +43,45 @@ export const All: Story = {
41
43
  render: (props) => {
42
44
  return (
43
45
  <>
44
- <div className="m-b-2">
45
- <div className="title-4 m-b-1">Accent</div>
46
- <CircularButton {...props} priority={Priority.PRIMARY} type={ControlType.ACCENT} />
47
- <CircularButton {...props} priority={Priority.SECONDARY} type={ControlType.ACCENT} />
48
- </div>
49
- <div className="m-b-2">
50
- <div className="title-4 m-b-1">Positive</div>
51
- <CircularButton {...props} priority={Priority.PRIMARY} type={ControlType.POSITIVE} />
52
- <CircularButton {...props} priority={Priority.SECONDARY} type={ControlType.POSITIVE} />
53
- </div>
54
- <div className="m-b-2">
55
- <div className="title-4 m-b-1">Negative</div>
56
- <CircularButton {...props} priority={Priority.PRIMARY} type={ControlType.NEGATIVE} />
57
- <CircularButton {...props} priority={Priority.SECONDARY} type={ControlType.NEGATIVE} />
58
- </div>
59
- <div className="m-b-2">
60
- <div className="title-4 m-b-1">Disabled</div>
61
- <CircularButton {...props} disabled />
62
- <CircularButton {...props} priority={Priority.SECONDARY} disabled />
63
- </div>
46
+ <Title type="title-subsection" className="m-y-2">
47
+ Default (Primary and secondary)
48
+ </Title>
49
+ <Body>
50
+ <CircularButton {...props} priority="primary" type="default" />
51
+ <CircularButton {...props} priority="secondary" type="default" />
52
+ <CircularButton {...props} priority="primary" type="default" disabled />
53
+ <CircularButton {...props} priority="secondary" type="default" disabled />
54
+ </Body>
55
+
56
+ <Title type="title-subsection" className="m-y-2">
57
+ Negative (Primary and secondary)
58
+ </Title>
59
+ <Body>
60
+ <CircularButton {...props} priority="primary" type="negative" />
61
+ <CircularButton {...props} priority="secondary" type="negative" />
62
+ <CircularButton {...props} priority="primary" type="negative" disabled />
63
+ <CircularButton {...props} priority="secondary" type="negative" disabled />
64
+ </Body>
65
+
66
+ <Title type="title-body" className="m-y-2">
67
+ Accent (Deprecated)
68
+ </Title>
69
+ <Body>
70
+ <CircularButton {...props} priority="primary" type="accent" />
71
+ <CircularButton {...props} priority="secondary" type="accent" />
72
+ <CircularButton {...props} priority="primary" type="accent" disabled />
73
+ <CircularButton {...props} priority="secondary" type="accent" disabled />
74
+ </Body>
75
+
76
+ <Title type="title-body" className="m-y-2">
77
+ Positive (Deprecated)
78
+ </Title>
79
+ <Body>
80
+ <CircularButton {...props} priority="primary" type="positive" />
81
+ <CircularButton {...props} priority="secondary" type="positive" />
82
+ <CircularButton {...props} priority="primary" type="positive" disabled />
83
+ <CircularButton {...props} priority="secondary" type="positive" disabled />
84
+ </Body>
64
85
  </>
65
86
  );
66
87
  },
@@ -1,20 +1,28 @@
1
1
  import { clsx } from 'clsx';
2
- import { cloneElement } from 'react';
3
2
 
4
3
  import Body from '../body/Body';
5
- import { typeClassMap, priorityClassMap } from '../button/classMap';
6
4
  import { Breakpoint, ControlType, Priority, Typography } from '../common';
7
- import Circle from '../common/circle';
5
+ import IconButton, { IconButtonProps } from '../iconButton';
8
6
  import { useMedia } from '../common/hooks/useMedia';
9
7
 
8
+ /**
9
+ * @deprecated use `'default'` instead
10
+ */
11
+ type DeprecatedTypes = `${ControlType.ACCENT | ControlType.POSITIVE}`;
12
+
10
13
  export interface CircularButtonProps {
11
14
  className?: string;
12
15
  children: string;
13
16
  disabled?: boolean;
14
- icon: React.ReactElement<{ size?: unknown }>;
15
- onClick?: React.MouseEventHandler<HTMLInputElement>;
17
+ icon: React.ReactElement<{ size?: unknown }> | React.ReactNode;
18
+ onClick?: React.MouseEventHandler<HTMLInputElement> &
19
+ React.MouseEventHandler<HTMLButtonElement> &
20
+ React.MouseEventHandler<HTMLAnchorElement>;
16
21
  priority?: `${Priority.PRIMARY | Priority.SECONDARY}`;
17
- type?: `${ControlType.ACCENT | ControlType.POSITIVE | ControlType.NEGATIVE}`;
22
+ /**
23
+ * `"accent"` and `"positive"` values are **deprecated**, please use `"default"` instead
24
+ */
25
+ type?: DeprecatedTypes | 'default' | `${ControlType.NEGATIVE}`;
18
26
  }
19
27
 
20
28
  const CircularButton = ({
@@ -22,30 +30,35 @@ const CircularButton = ({
22
30
  children,
23
31
  disabled,
24
32
  icon,
33
+ onClick,
25
34
  priority = Priority.PRIMARY,
26
- type = ControlType.ACCENT,
27
- ...rest
35
+ type = 'default',
28
36
  }: CircularButtonProps) => {
29
- const classes = clsx('btn np-btn', 'm-b-1', typeClassMap[type], priorityClassMap[priority]);
30
-
31
- const iconElement = Number(icon.props.size) !== 24 ? cloneElement(icon, { size: 24 }) : icon;
32
-
33
37
  const isTinyViewport = useMedia(`(max-width: ${Breakpoint.ZOOM_400}px)`);
34
-
35
38
  return (
36
- <label className={clsx('np-circular-btn', priority, type, disabled && 'disabled', className)}>
37
- <Circle
38
- as="input"
39
- // @ts-expect-error it's input[type=button] element
40
- type="button"
41
- size={isTinyViewport ? 72 : 56}
42
- aria-label={children}
43
- className={classes}
39
+ <label
40
+ className={clsx(
41
+ 'np-circular-btn',
42
+ `np-circular-btn-${priority}-${type}`,
43
+ { 'np-circular-btn-disabled': disabled },
44
+ className,
45
+ )}
46
+ >
47
+ <IconButton
48
+ size={isTinyViewport ? 32 : 56}
49
+ priority={priority}
50
+ type={['accent', 'positive'].includes(type) ? 'default' : (type as IconButtonProps['type'])}
51
+ className={clsx('m-b-1')}
44
52
  disabled={disabled}
45
- {...rest}
46
- />
47
- {iconElement}
48
- <Body as="span" className="np-circular-btn__label" type={Typography.BODY_DEFAULT_BOLD}>
53
+ onClick={onClick}
54
+ >
55
+ {icon}
56
+ </IconButton>
57
+ <Body
58
+ as="span"
59
+ className={clsx('np-circular-btn-label', { disabled })}
60
+ type={Typography.BODY_DEFAULT_BOLD}
61
+ >
49
62
  {children}
50
63
  </Body>
51
64
  </label>
@@ -1,19 +1,17 @@
1
- import { screen, fireEvent } from '@testing-library/react';
2
- import userEvent from '@testing-library/user-event';
3
1
  import { DateInput, DateInputProps, Field } from '..';
4
- import { mockMatchMedia, mockResizeObserver, render } from '../test-utils';
2
+ import { mockMatchMedia, mockResizeObserver, render, userEvent, screen } from '../test-utils';
5
3
 
6
- describe('Date Input Component', () => {
7
- const props: DateInputProps = { onChange: jest.fn() };
4
+ mockMatchMedia();
5
+ mockResizeObserver();
8
6
 
9
- beforeEach(() => {
10
- mockMatchMedia();
11
- mockResizeObserver();
12
- });
7
+ describe('Date Input Component', () => {
8
+ const props: DateInputProps = {
9
+ onChange: jest.fn(),
10
+ onFocus: jest.fn(),
11
+ onBlur: jest.fn(),
12
+ };
13
13
 
14
- afterEach(() => {
15
- jest.resetAllMocks();
16
- });
14
+ afterEach(jest.clearAllMocks);
17
15
 
18
16
  describe('when initialised without a model', () => {
19
17
  it('sets day field to empty', () => {
@@ -104,7 +102,7 @@ describe('Date Input Component', () => {
104
102
  await userEvent.click(monthSelect);
105
103
  await userEvent.click(screen.getByRole('option', { name: /January/ }));
106
104
  expect(props.onChange).toHaveBeenCalledWith(null);
107
- });
105
+ }, 10_000);
108
106
 
109
107
  it('calls the onChange callback with null when changing the year but nothing else is filled out', async () => {
110
108
  render(<DateInput {...props} />);
@@ -126,7 +124,7 @@ describe('Date Input Component', () => {
126
124
  await userEvent.click(monthSelect);
127
125
  await userEvent.click(screen.getByRole('option', { name: /January/ }));
128
126
  expect(props.onChange).toHaveBeenCalledWith('2022-01-01');
129
- });
127
+ }, 10_000);
130
128
 
131
129
  it('calls the onChange callback with the correct value when changing the year', async () => {
132
130
  render(<DateInput {...props} value="0122-12-1" />);
@@ -178,19 +176,40 @@ describe('Date Input Component', () => {
178
176
  });
179
177
  });
180
178
 
181
- describe('when switching from day input to year input', () => {
182
- it('does not call onBlur nor onFocus', () => {
183
- const onFocus = jest.fn();
184
- const onBlur = jest.fn();
179
+ describe('propagating focus and blur callbacks', () => {
180
+ it('should propagate if focusing from or blurring to external component', async () => {
181
+ render(
182
+ <>
183
+ <button type="button">starting point</button>
184
+ <DateInput {...props} />
185
+ </>,
186
+ );
187
+ await userEvent.tab();
188
+ await userEvent.tab();
189
+ await userEvent.tab({ shift: true });
190
+ expect(props.onFocus).toHaveBeenCalledTimes(1);
191
+ expect(props.onBlur).toHaveBeenCalledTimes(1);
192
+ });
185
193
 
186
- render(<DateInput {...props} />);
187
- const dayInput = screen.getByRole('textbox', { name: /day/i });
188
- const yearInput = screen.getByRole('textbox', { name: /year/i });
189
- fireEvent.focus(dayInput);
190
- fireEvent.blur(dayInput);
191
- fireEvent.focus(yearInput);
192
- expect(onFocus).not.toHaveBeenCalled();
193
- expect(onBlur).not.toHaveBeenCalled();
194
+ it('should not propagate if switching between internals', async () => {
195
+ render(
196
+ <>
197
+ <button type="button">external button</button>
198
+ <DateInput {...props} />
199
+ </>,
200
+ );
201
+ const externalButton = screen.getByRole('button', { name: 'external button' });
202
+
203
+ await userEvent.click(externalButton);
204
+ await userEvent.click(screen.getByRole('textbox', { name: /day/i }));
205
+ await userEvent.click(screen.getByRole('textbox', { name: /year/i }));
206
+ await userEvent.click(externalButton);
207
+
208
+ // 1 call is caused by the initial switch to the component,
209
+ // as reflected in `should propagate if focusing from or
210
+ // blurring to external component` test
211
+ expect(props.onFocus).toHaveBeenCalledTimes(1);
212
+ expect(props.onBlur).toHaveBeenCalledTimes(1);
194
213
  });
195
214
  });
196
215