@transferwise/components 0.0.0-experimental-28eac06 → 0.0.0-experimental-e9dbb78

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 (75) hide show
  1. package/build/alert/Alert.js +17 -17
  2. package/build/alert/Alert.js.map +1 -1
  3. package/build/alert/Alert.mjs +14 -14
  4. package/build/alert/Alert.mjs.map +1 -1
  5. package/build/common/action/Action.js +15 -26
  6. package/build/common/action/Action.js.map +1 -1
  7. package/build/common/action/Action.mjs +15 -26
  8. package/build/common/action/Action.mjs.map +1 -1
  9. package/build/common/propsValues/sentiment.js +0 -1
  10. package/build/common/propsValues/sentiment.js.map +1 -1
  11. package/build/common/propsValues/sentiment.mjs +0 -1
  12. package/build/common/propsValues/sentiment.mjs.map +1 -1
  13. package/build/criticalBanner/CriticalCommsBanner.js +73 -10
  14. package/build/criticalBanner/CriticalCommsBanner.js.map +1 -1
  15. package/build/criticalBanner/CriticalCommsBanner.mjs +74 -11
  16. package/build/criticalBanner/CriticalCommsBanner.mjs.map +1 -1
  17. package/build/i18n/en.json +0 -1
  18. package/build/i18n/en.json.js +0 -1
  19. package/build/i18n/en.json.js.map +1 -1
  20. package/build/i18n/en.json.mjs +0 -1
  21. package/build/i18n/en.json.mjs.map +1 -1
  22. package/build/main.css +70 -21
  23. package/build/statusIcon/StatusIcon.js +1 -5
  24. package/build/statusIcon/StatusIcon.js.map +1 -1
  25. package/build/statusIcon/StatusIcon.messages.js +0 -3
  26. package/build/statusIcon/StatusIcon.messages.js.map +1 -1
  27. package/build/statusIcon/StatusIcon.messages.mjs +0 -3
  28. package/build/statusIcon/StatusIcon.messages.mjs.map +1 -1
  29. package/build/statusIcon/StatusIcon.mjs +1 -5
  30. package/build/statusIcon/StatusIcon.mjs.map +1 -1
  31. package/build/styles/button/Button.css +0 -3
  32. package/build/styles/criticalBanner/CriticalCommsBanner.css +73 -21
  33. package/build/styles/main.css +70 -21
  34. package/build/types/alert/Alert.d.ts +4 -3
  35. package/build/types/alert/Alert.d.ts.map +1 -1
  36. package/build/types/common/action/Action.d.ts +2 -5
  37. package/build/types/common/action/Action.d.ts.map +1 -1
  38. package/build/types/common/propsValues/sentiment.d.ts +0 -1
  39. package/build/types/common/propsValues/sentiment.d.ts.map +1 -1
  40. package/build/types/criticalBanner/CriticalCommsBanner.d.ts.map +1 -1
  41. package/build/types/index.d.ts +1 -0
  42. package/build/types/index.d.ts.map +1 -1
  43. package/build/types/statusIcon/StatusIcon.d.ts.map +1 -1
  44. package/build/types/statusIcon/StatusIcon.messages.d.ts +0 -5
  45. package/build/types/statusIcon/StatusIcon.messages.d.ts.map +1 -1
  46. package/build/types/test-utils/index.d.ts +0 -2
  47. package/build/types/test-utils/index.d.ts.map +1 -1
  48. package/package.json +5 -5
  49. package/src/alert/Alert.spec.tsx +30 -0
  50. package/src/alert/Alert.story.tsx +1 -34
  51. package/src/alert/Alert.tsx +15 -20
  52. package/src/button/Button.css +0 -3
  53. package/src/button/Button.less +3 -6
  54. package/src/button/Button.vars.less +4 -0
  55. package/src/common/action/Action.tsx +22 -40
  56. package/src/common/propsValues/sentiment.ts +0 -1
  57. package/src/criticalBanner/CriticalCommsBanner.css +73 -21
  58. package/src/criticalBanner/CriticalCommsBanner.less +70 -24
  59. package/src/criticalBanner/CriticalCommsBanner.story.tsx +4 -26
  60. package/src/criticalBanner/CriticalCommsBanner.tsx +50 -8
  61. package/src/i18n/en.json +0 -1
  62. package/src/index.ts +1 -0
  63. package/src/main.css +70 -21
  64. package/src/radio/Radio.spec.tsx +73 -0
  65. package/src/radio/Radio.story.tsx +22 -52
  66. package/src/radioGroup/RadioGroup.spec.tsx +91 -0
  67. package/src/radioGroup/RadioGroup.story.tsx +3 -5
  68. package/src/statusIcon/StatusIcon.less +0 -1
  69. package/src/statusIcon/StatusIcon.messages.ts +0 -6
  70. package/src/statusIcon/StatusIcon.tsx +1 -8
  71. package/src/radio/Radio.rtl.spec.tsx +0 -24
  72. package/src/radio/Radio.spec.js +0 -76
  73. package/src/radio/__snapshots__/Radio.rtl.spec.tsx.snap +0 -49
  74. package/src/radioGroup/RadioGroup.rtl.spec.tsx +0 -30
  75. package/src/radioGroup/RadioGroup.spec.js +0 -90
@@ -1,24 +1,76 @@
1
- .critical-comms .alert-critical {
2
- color: var(--color-contrast-overlay) !important;
3
- background-color: var(--color-sentiment-negative) !important;
4
- }
5
- .critical-comms .alert-critical .np-text-title-body {
6
- color: var(--color-contrast-overlay);
7
- }
8
- .critical-comms .status-circle.critical {
9
- background-color: #ffffff;
10
- background-color: var(--color-background-screen);
11
- }
12
- @media (min-width: 768px) {
13
- .critical-comms .alert-critical .alert__message {
14
- flex-direction: row !important;
15
- justify-content: space-between;
16
- align-items: center;
17
- width: 100%;
1
+ div.critical-comms {
2
+ --critical-comms-background-color: var(--color-background-negative);
3
+ --critical-comms-title-color: var(--color-content-negative);
4
+ --critical-comms-subtitle-color: var(--color-content-secondary);
5
+ --critical-comms-subtitle-color-padding-left: var(--size-16);
6
+ --critical-comms-vertical-spacing: var(--size-8);
7
+ background-color: rgba(255,135,135,0.10196);
8
+ background-color: var(--critical-comms-background-color);
9
+ display: flex;
10
+ justify-content: center;
11
+ align-items: center;
12
+ }
13
+ .np-theme-personal div.critical-comms,
14
+ .np-theme-personal--dark div.critical-comms {
15
+ --critical-comms-background-color: var(--color-sentiment-negative);
16
+ --critical-comms-title-color: var(--color-contrast);
17
+ --critical-comms-subtitle-color: var(--color-contrast);
18
+ --critical-comms-subtitle-color-padding-left: 0;
19
+ --critical-comms-vertical-spacing: var(--size-16);
20
+ padding: 24px;
21
+ padding: var(--padding-medium);
22
+ }
23
+ .np-theme-personal div.critical-comms .tw-icon-alert-circle-fill,
24
+ .np-theme-personal--dark div.critical-comms .tw-icon-alert-circle-fill {
25
+ color: var(--color-contrast);
26
+ }
27
+ .np-theme-personal div.critical-comms .tw-icon-alert-circle-fill svg,
28
+ .np-theme-personal--dark div.critical-comms .tw-icon-alert-circle-fill svg {
29
+ width: 48px;
30
+ height: 48px;
31
+ }
32
+ .np-theme-personal div.critical-comms .cta-btn,
33
+ .np-theme-personal--dark div.critical-comms .cta-btn {
34
+ background-color: var(--color-contrast);
35
+ }
36
+ .np-theme-personal div.critical-comms .cta-btn:not(.disabled):not(:disabled):focus,
37
+ .np-theme-personal--dark div.critical-comms .cta-btn:not(.disabled):not(:disabled):focus {
38
+ outline-color: var(--color-contrast);
39
+ }
40
+ @media (max-width: 767px) {
41
+ div.critical-comms {
42
+ display: inline;
43
+ display: initial;
18
44
  }
19
- .critical-comms .alert-critical .alert__message .alert__action {
20
- margin-top: 0;
21
- padding-left: 16px;
22
- padding-left: var(--padding-small);
45
+ }
46
+ div.critical-comms .critical-comms--title {
47
+ color: var(--critical-comms-title-color);
48
+ }
49
+ div.critical-comms .critical-comms--subtitle {
50
+ color: var(--critical-comms-subtitle-color);
51
+ }
52
+ div.critical-comms .critical-comms--cta {
53
+ padding-left: 0;
54
+ }
55
+ @media (max-width: 767px) {
56
+ div.critical-comms .critical-comms--cta {
57
+ padding-left: var(--critical-comms-subtitle-color-padding-left);
58
+ padding-top: var(--critical-comms-vertical-spacing);
59
+ min-width: 100%;
60
+ }
61
+ }
62
+ div.critical-comms .critical-comms-body {
63
+ display: flex;
64
+ width: 100%;
65
+ }
66
+ @media (max-width: 767px) {
67
+ div.critical-comms .critical-comms-body {
68
+ flex-direction: column;
69
+ }
70
+ }
71
+ @media (max-width: 767px) {
72
+ div.critical-comms .critical-comms-content {
73
+ padding-top: var(--critical-comms-vertical-spacing);
74
+ flex-wrap: wrap;
23
75
  }
24
76
  }
@@ -1,32 +1,78 @@
1
- .critical-comms {
2
- .alert-critical {
3
- color: var(--color-contrast-overlay) !important;
4
- background-color: var(--color-sentiment-negative) !important;
1
+ div.critical-comms {
2
+ --critical-comms-background-color: var(--color-background-negative);
3
+ --critical-comms-title-color: var(--color-content-negative);
4
+ --critical-comms-subtitle-color: var(--color-content-secondary);
5
+ --critical-comms-subtitle-color-padding-left: var(--size-16);
6
+ --critical-comms-vertical-spacing: var(--size-8);
5
7
 
6
- .np-text-title-body {
7
- color: var(--color-contrast-overlay);
8
+ .np-theme-personal &,
9
+ .np-theme-personal--dark & {
10
+ --critical-comms-background-color: var(--color-sentiment-negative);
11
+ --critical-comms-title-color: var(--color-contrast);
12
+ --critical-comms-subtitle-color: var(--color-contrast);
13
+ --critical-comms-subtitle-color-padding-left: 0;
14
+ --critical-comms-vertical-spacing: var(--size-16);
15
+
16
+ padding: var(--padding-medium);
17
+
18
+ .tw-icon-alert-circle-fill {
19
+ color: var(--color-contrast);
20
+
21
+ svg {
22
+ width: 48px;
23
+ height: 48px;
24
+ }
25
+ }
26
+
27
+ .cta-btn {
28
+ background-color: var(--color-contrast);
29
+
30
+ &:not(.disabled,:disabled):focus {
31
+ outline-color: var(--color-contrast);
32
+ }
8
33
  }
9
34
  }
10
35
 
11
- .status-circle.critical {
12
- background-color: var(--color-background-screen);
36
+ background-color: var(--critical-comms-background-color);
37
+ display: flex;
38
+ justify-content: center;
39
+ align-items: center;
40
+
41
+ @media (--screen-sm-max) {
42
+ display: initial;
13
43
  }
14
- }
15
44
 
16
- @media (--screen-md) {
17
- .critical-comms {
18
- .alert-critical {
19
- .alert__message {
20
- flex-direction: row !important;
21
- justify-content: space-between;
22
- align-items: center;
23
- width: 100%;
24
-
25
- .alert__action {
26
- margin-top: 0;
27
- padding-left: var(--padding-small);
28
- }
29
- }
45
+ .critical-comms--title {
46
+ color: var(--critical-comms-title-color);
47
+ }
48
+
49
+ .critical-comms--subtitle {
50
+ color: var(--critical-comms-subtitle-color);
51
+ }
52
+
53
+ .critical-comms--cta {
54
+ padding-left: 0;
55
+
56
+ @media (--screen-sm-max) {
57
+ padding-left: var(--critical-comms-subtitle-color-padding-left);
58
+ padding-top: var(--critical-comms-vertical-spacing);
59
+ min-width: 100%;
60
+ }
61
+ }
62
+
63
+ .critical-comms-body {
64
+ display: flex;
65
+ width: 100%;
66
+
67
+ @media (--screen-sm-max) {
68
+ flex-direction: column;
69
+ }
70
+ }
71
+
72
+ .critical-comms-content {
73
+ @media (--screen-sm-max) {
74
+ padding-top: var(--critical-comms-vertical-spacing);
75
+ flex-wrap: wrap;
30
76
  }
31
77
  }
32
- }
78
+ }
@@ -1,7 +1,6 @@
1
- import { Meta } from '@storybook/react';
1
+ import { Meta, StoryObj } from '@storybook/react';
2
2
 
3
3
  import CriticalCommsBanner from '.';
4
- import { storyConfig } from '../test-utils';
5
4
 
6
5
  export default {
7
6
  component: CriticalCommsBanner,
@@ -9,33 +8,12 @@ export default {
9
8
  tags: ['autodocs'],
10
9
  } satisfies Meta<typeof CriticalCommsBanner>;
11
10
 
12
- export const Basic = {
11
+ type Story = StoryObj<typeof CriticalCommsBanner>;
12
+
13
+ export const Basic: Story = {
13
14
  args: {
14
15
  title: 'Your account is overdrawn',
15
16
  subtitle: 'Add money within the next 30 days',
16
17
  action: { label: 'Take action', href: 'https://wise.com' },
17
18
  },
18
19
  };
19
-
20
- export const Variants = storyConfig(
21
- {
22
- args: {
23
- title: 'Your account is overdrawn',
24
- subtitle: 'Add money within the next 30 days',
25
- action: { label: 'Take action', href: 'https://wise.com' },
26
- },
27
- },
28
- { variants: ['default', 'dark', 'rtl'] },
29
- );
30
-
31
- export const Mobile = storyConfig(
32
- {
33
- tags: ['!autodocs'],
34
- args: {
35
- title: 'Your account is overdrawn',
36
- subtitle: 'Add money within the next 30 days',
37
- action: { label: 'Take action', href: 'https://wise.com' },
38
- },
39
- },
40
- { variants: ['default', 'dark', 'rtl', 'mobile'] },
41
- );
@@ -1,6 +1,13 @@
1
- import Alert from '../alert';
1
+ import { Alert as DangerIcon, AlertCircleFill } from '@transferwise/icons';
2
+ import { useTheme } from '@wise/components-theming';
2
3
  import { clsx } from 'clsx';
3
4
 
5
+ import Avatar, { AvatarType } from '../avatar';
6
+ import Body from '../body';
7
+ import Button from '../button';
8
+ import { ControlType, Priority, Size, Typography } from '../common';
9
+ import Title from '../title';
10
+
4
11
  export type CriticalCommsBannerProps = {
5
12
  title: string;
6
13
  subtitle?: string;
@@ -12,15 +19,50 @@ export type CriticalCommsBannerProps = {
12
19
  };
13
20
 
14
21
  function CriticalCommsBanner({ title, subtitle, action, className }: CriticalCommsBannerProps) {
22
+ const { isModern } = useTheme();
15
23
  return (
16
24
  <div className={clsx('critical-comms', className)}>
17
- <Alert
18
- title={title}
19
- message={subtitle}
20
- action={{ target: action?.href, text: action?.label }}
21
- className={className}
22
- type="critical"
23
- />
25
+ <div className="critical-comms-body">
26
+ <Avatar
27
+ size={Size.MEDIUM}
28
+ type={AvatarType.ICON}
29
+ className={clsx(isModern ? 'm-r-2' : 'm-r-1')}
30
+ backgroundColor={
31
+ isModern ? 'var(--color-sentiment-negative)' : 'var(--color-background-negative)'
32
+ }
33
+ >
34
+ {isModern ? <AlertCircleFill /> : <DangerIcon size={24} />}
35
+ </Avatar>
36
+ <div className="critical-comms-content d-flex align-items-center flex-grow-1">
37
+ <div className={clsx('flex-grow-1', { 'p-x-2': !isModern })}>
38
+ <Title
39
+ type={isModern ? Typography.TITLE_BODY : Typography.TITLE_GROUP}
40
+ className="critical-comms--title"
41
+ >
42
+ {title}
43
+ </Title>
44
+ <Body className="critical-comms--subtitle">{subtitle}</Body>
45
+ </div>
46
+ {action ? (
47
+ <div className="critical-comms--cta">
48
+ <Button
49
+ block={isModern}
50
+ size={Size.SMALL}
51
+ type={ControlType.NEGATIVE}
52
+ priority={isModern ? Priority.SECONDARY : Priority.PRIMARY}
53
+ className="cta-btn"
54
+ onClick={() => {
55
+ if (action) {
56
+ window.location.href = action.href;
57
+ }
58
+ }}
59
+ >
60
+ {action.label}
61
+ </Button>
62
+ </div>
63
+ ) : null}
64
+ </div>
65
+ </div>
24
66
  </div>
25
67
  );
26
68
  }
package/src/i18n/en.json CHANGED
@@ -27,7 +27,6 @@
27
27
  "neptune.SelectInput.noResultsFound": "No results found",
28
28
  "neptune.SelectOption.action.label": "Choose",
29
29
  "neptune.SelectOption.selected.action.label": "Change chosen option",
30
- "neptune.StatusIcon.iconLabel.critical": "Critical:",
31
30
  "neptune.StatusIcon.iconLabel.error": "Error:",
32
31
  "neptune.StatusIcon.iconLabel.information": "Information:",
33
32
  "neptune.StatusIcon.iconLabel.pending": "Pending:",
package/src/index.ts CHANGED
@@ -11,6 +11,7 @@ export type { AvatarProps } from './avatar';
11
11
  export type { AvatarViewProps } from './avatarView';
12
12
  export type { AvatarLayoutProps } from './avatarLayout';
13
13
  export type { BadgeProps } from './badge';
14
+ export type { ButtonProps } from './button';
14
15
  export type { CardProps } from './card';
15
16
  export type { CarouselProps } from './carousel';
16
17
  export type { CheckboxProps } from './checkbox';
package/src/main.css CHANGED
@@ -1,25 +1,77 @@
1
- .critical-comms .alert-critical {
2
- color: var(--color-contrast-overlay) !important;
3
- background-color: var(--color-sentiment-negative) !important;
1
+ div.critical-comms {
2
+ --critical-comms-background-color: var(--color-background-negative);
3
+ --critical-comms-title-color: var(--color-content-negative);
4
+ --critical-comms-subtitle-color: var(--color-content-secondary);
5
+ --critical-comms-subtitle-color-padding-left: var(--size-16);
6
+ --critical-comms-vertical-spacing: var(--size-8);
7
+ background-color: rgba(255,135,135,0.10196);
8
+ background-color: var(--critical-comms-background-color);
9
+ display: flex;
10
+ justify-content: center;
11
+ align-items: center;
4
12
  }
5
- .critical-comms .alert-critical .np-text-title-body {
6
- color: var(--color-contrast-overlay);
13
+ .np-theme-personal div.critical-comms,
14
+ .np-theme-personal--dark div.critical-comms {
15
+ --critical-comms-background-color: var(--color-sentiment-negative);
16
+ --critical-comms-title-color: var(--color-contrast);
17
+ --critical-comms-subtitle-color: var(--color-contrast);
18
+ --critical-comms-subtitle-color-padding-left: 0;
19
+ --critical-comms-vertical-spacing: var(--size-16);
20
+ padding: 24px;
21
+ padding: var(--padding-medium);
7
22
  }
8
- .critical-comms .status-circle.critical {
9
- background-color: #ffffff;
10
- background-color: var(--color-background-screen);
23
+ .np-theme-personal div.critical-comms .tw-icon-alert-circle-fill,
24
+ .np-theme-personal--dark div.critical-comms .tw-icon-alert-circle-fill {
25
+ color: var(--color-contrast);
11
26
  }
12
- @media (min-width: 768px) {
13
- .critical-comms .alert-critical .alert__message {
14
- flex-direction: row !important;
15
- justify-content: space-between;
16
- align-items: center;
17
- width: 100%;
27
+ .np-theme-personal div.critical-comms .tw-icon-alert-circle-fill svg,
28
+ .np-theme-personal--dark div.critical-comms .tw-icon-alert-circle-fill svg {
29
+ width: 48px;
30
+ height: 48px;
31
+ }
32
+ .np-theme-personal div.critical-comms .cta-btn,
33
+ .np-theme-personal--dark div.critical-comms .cta-btn {
34
+ background-color: var(--color-contrast);
35
+ }
36
+ .np-theme-personal div.critical-comms .cta-btn:not(.disabled):not(:disabled):focus,
37
+ .np-theme-personal--dark div.critical-comms .cta-btn:not(.disabled):not(:disabled):focus {
38
+ outline-color: var(--color-contrast);
39
+ }
40
+ @media (max-width: 767px) {
41
+ div.critical-comms {
42
+ display: inline;
43
+ display: initial;
44
+ }
45
+ }
46
+ div.critical-comms .critical-comms--title {
47
+ color: var(--critical-comms-title-color);
48
+ }
49
+ div.critical-comms .critical-comms--subtitle {
50
+ color: var(--critical-comms-subtitle-color);
51
+ }
52
+ div.critical-comms .critical-comms--cta {
53
+ padding-left: 0;
54
+ }
55
+ @media (max-width: 767px) {
56
+ div.critical-comms .critical-comms--cta {
57
+ padding-left: var(--critical-comms-subtitle-color-padding-left);
58
+ padding-top: var(--critical-comms-vertical-spacing);
59
+ min-width: 100%;
60
+ }
61
+ }
62
+ div.critical-comms .critical-comms-body {
63
+ display: flex;
64
+ width: 100%;
65
+ }
66
+ @media (max-width: 767px) {
67
+ div.critical-comms .critical-comms-body {
68
+ flex-direction: column;
18
69
  }
19
- .critical-comms .alert-critical .alert__message .alert__action {
20
- margin-top: 0;
21
- padding-left: 16px;
22
- padding-left: var(--padding-small);
70
+ }
71
+ @media (max-width: 767px) {
72
+ div.critical-comms .critical-comms-content {
73
+ padding-top: var(--critical-comms-vertical-spacing);
74
+ flex-wrap: wrap;
23
75
  }
24
76
  }
25
77
  .tw-date-lookup-calendar > tbody > tr > td.weekend button {
@@ -897,9 +949,6 @@
897
949
  .np-theme-personal--bright-green .wds-Button--minimal .wds-Button-avatars .np-circle {
898
950
  --circle-border-color: color-mix(in srgb, var(--Button-color) 12%, transparent);
899
951
  }
900
- .critical-comms .wds-Button {
901
- --Button-background: var(--color-contrast-overlay);
902
- }
903
952
  [dir="rtl"] .wds-Button .tw-icon-chevron-right,[dir="rtl"] .wds-Button .tw-icon-arrow-right,[dir="rtl"] .wds-Button .tw-icon-chevron-left,[dir="rtl"] .wds-Button .tw-icon-arrow-left,[dir="rtl"] .wds-Button .tw-icon-arrow-diagonal-down,[dir="rtl"] .wds-Button .tw-icon-arrow-diagonal-up,[dir="rtl"] .wds-Button .tw-icon-list,[dir="rtl"] .wds-Button .tw-icon-activity {
904
953
  scale: -1 1;
905
954
  }
@@ -0,0 +1,73 @@
1
+ import AvatarView from '../avatarView';
2
+ import { render, screen, mockMatchMedia } from '../test-utils';
3
+ import { userEvent } from '@testing-library/user-event';
4
+
5
+ import Radio from '.';
6
+
7
+ jest.mock('../common/hooks');
8
+ mockMatchMedia();
9
+
10
+ describe('Radio', () => {
11
+ const props = {
12
+ label: 'This is a label',
13
+ name: 'name',
14
+ onChange: jest.fn(),
15
+ checked: false,
16
+ disabled: false,
17
+ secondary: '',
18
+ };
19
+
20
+ it('shows the avatar when supplied', () => {
21
+ render(<Radio {...props} avatar={<AvatarView profileName="High Def" />} />);
22
+ expect(screen.getByText('HD')).toBeInTheDocument();
23
+ });
24
+
25
+ it('displays the given label', () => {
26
+ render(<Radio {...props} />);
27
+ expect(screen.getByText(props.label)).toBeInTheDocument();
28
+ });
29
+
30
+ it('passes radio button id', () => {
31
+ render(<Radio {...props} id="some-id" />);
32
+ expect(screen.getByRole('radio')).toHaveAttribute('id', 'some-id');
33
+ });
34
+
35
+ it('passes radio button name', () => {
36
+ render(<Radio {...props} name="a-name" />);
37
+ expect(screen.getByRole('radio')).toHaveAttribute('name', 'a-name');
38
+ });
39
+
40
+ it('handles checked state correctly', () => {
41
+ render(<Radio {...props} checked />);
42
+ expect(screen.getByRole('radio')).toBeChecked();
43
+ });
44
+
45
+ it('handles unchecked state correctly', () => {
46
+ render(<Radio {...props} checked={false} />);
47
+ expect(screen.getByRole('radio')).not.toBeChecked();
48
+ });
49
+
50
+ it('handles disabled state correctly', () => {
51
+ render(<Radio {...props} disabled />);
52
+ expect(screen.getByRole('radio')).toBeDisabled();
53
+ });
54
+
55
+ it('displays secondary text when supplied', () => {
56
+ render(<Radio {...props} secondary="additional info" />);
57
+ expect(screen.getByText('additional info')).toBeInTheDocument();
58
+ });
59
+
60
+ it('calls onChange when clicked', async () => {
61
+ const onChange = jest.fn();
62
+ render(<Radio {...props} onChange={onChange} />);
63
+ await userEvent.click(screen.getByRole('radio'));
64
+ expect(onChange).toHaveBeenCalled();
65
+ });
66
+
67
+ it('does not call onChange when disabled', async () => {
68
+ const onChange = jest.fn();
69
+ render(<Radio {...props} disabled onChange={onChange} />);
70
+ await userEvent.click(screen.getByRole('radio'));
71
+ expect(onChange).not.toHaveBeenCalled();
72
+ });
73
+ });
@@ -1,11 +1,8 @@
1
- import { boolean, text } from '@storybook/addon-knobs';
2
- import { Flag } from '@wise/art';
1
+ import { boolean } from '@storybook/addon-knobs';
3
2
  import { useState } from 'react';
4
-
5
- import Avatar, { AvatarType } from '../avatar';
6
- import Checkbox from '../checkbox';
7
-
8
3
  import Radio from './Radio';
4
+ import AvatarView from '../avatarView';
5
+ import { Flag } from '@wise/art';
9
6
 
10
7
  export default {
11
8
  component: Radio,
@@ -13,69 +10,42 @@ export default {
13
10
  };
14
11
 
15
12
  export const Basic = () => {
16
- const [checked, setChecked] = useState(true);
13
+ const [selectedValue, setSelectedValue] = useState('option1');
17
14
 
18
15
  const disabled = boolean('disabled', false);
19
- const label = text('label', 'This is the label');
20
- const secondary = text('secondary', '');
21
- const showAvatar = boolean('avatar', false);
22
- const hasError = boolean('hasError', false);
23
16
 
24
17
  return (
25
18
  <>
26
- <div className={`form-group ${hasError ? 'has-error' : ''}`}>
19
+ <div className={`form-group ${selectedValue === 'option1' ? 'has-error' : ''}`}>
27
20
  <Radio
28
- label={label}
21
+ label="Without Avatar"
29
22
  name="name"
30
- id="id"
31
- checked={checked}
23
+ secondary="This is secondary text"
24
+ id="radioGroup1"
32
25
  disabled={disabled}
33
- avatar={
34
- showAvatar ? (
35
- <Avatar type={AvatarType.THUMBNAIL}>
36
- <Flag code="IMP" />
37
- </Avatar>
38
- ) : null
39
- }
40
- onChange={() => setChecked(!checked)}
26
+ value="option1"
27
+ checked={selectedValue === 'option1'}
28
+ onChange={() => setSelectedValue('option1')}
41
29
  />
42
30
  </div>
43
- <div className={`form-group ${hasError ? 'has-error' : ''}`}>
31
+ <div className="form-group">
44
32
  <Radio
45
- label={label}
33
+ label="With Avatar"
46
34
  name="name"
47
- id="id1"
48
- checked={checked}
35
+ id="radioGroup2"
49
36
  disabled={disabled}
50
- secondary={secondary}
51
37
  avatar={
52
- showAvatar ? (
53
- <Avatar type={AvatarType.THUMBNAIL}>
54
- <Flag code="KES" />
55
- </Avatar>
56
- ) : null
38
+ <AvatarView>
39
+ <Flag code="IMP" />
40
+ </AvatarView>
57
41
  }
58
- onChange={() => setChecked(!checked)}
42
+ value="option1"
43
+ checked={selectedValue === 'option2'}
44
+ onChange={() => setSelectedValue('option2')}
59
45
  />
60
46
  </div>
61
- <div className={`form-group ${hasError ? 'has-error' : ''}`}>
62
- <Checkbox
63
- label={label}
64
- id="id2"
65
- checked={checked}
66
- disabled={disabled}
67
- secondary={secondary}
68
- onChange={() => setChecked(!checked)}
69
- />
70
- </div>
71
- <div className={`form-group ${hasError ? 'has-error' : ''}`}>
72
- <Checkbox
73
- label={label}
74
- id="id3"
75
- checked={checked}
76
- disabled={disabled}
77
- onChange={() => setChecked(!checked)}
78
- />
47
+ <div className="form-group">
48
+ <Radio label="Disabled" name="name" id="radioGroup3" disabled value="option3" />
79
49
  </div>
80
50
  </>
81
51
  );