@transferwise/components 0.0.0-experimental-b2eafa7 → 0.0.0-experimental-b7402e7

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 (48) hide show
  1. package/build/index.esm.js +50 -178
  2. package/build/index.esm.js.map +1 -1
  3. package/build/index.js +50 -179
  4. package/build/index.js.map +1 -1
  5. package/build/main.css +0 -101
  6. package/build/styles/main.css +0 -101
  7. package/build/types/checkboxOption/CheckboxOption.d.ts +2 -2
  8. package/build/types/checkboxOption/CheckboxOption.d.ts.map +1 -1
  9. package/build/types/index.d.ts +2 -2
  10. package/build/types/index.d.ts.map +1 -1
  11. package/build/types/snackbar/Snackbar.d.ts +30 -22
  12. package/build/types/snackbar/Snackbar.d.ts.map +1 -1
  13. package/build/types/snackbar/SnackbarContext.d.ts +7 -2
  14. package/build/types/snackbar/SnackbarContext.d.ts.map +1 -1
  15. package/build/types/snackbar/SnackbarProvider.d.ts +7 -12
  16. package/build/types/snackbar/SnackbarProvider.d.ts.map +1 -1
  17. package/build/types/snackbar/index.d.ts +2 -0
  18. package/build/types/snackbar/index.d.ts.map +1 -0
  19. package/build/types/snackbar/useSnackbar.d.ts +1 -1
  20. package/build/types/snackbar/useSnackbar.d.ts.map +1 -1
  21. package/build/types/withNextPortal/withNextPortal.d.ts +1 -1
  22. package/build/types/withNextPortal/withNextPortal.d.ts.map +1 -1
  23. package/package.json +5 -5
  24. package/src/checkboxOption/CheckboxOption.tsx +2 -2
  25. package/src/index.ts +2 -2
  26. package/src/main.css +0 -101
  27. package/src/main.less +0 -1
  28. package/src/snackbar/{Snackbar.story.js → Snackbar.story.tsx} +2 -1
  29. package/src/snackbar/{Snackbar.js → Snackbar.tsx} +31 -32
  30. package/src/snackbar/SnackbarContext.ts +11 -0
  31. package/src/snackbar/SnackbarProvider.tsx +39 -0
  32. package/src/ssr.spec.js +0 -17
  33. package/src/withNextPortal/withNextPortal.tsx +1 -1
  34. package/build/styles/segmentedControl/SegmentedControl.css +0 -101
  35. package/build/types/segmentedControl/SegmentedControl.d.ts +0 -31
  36. package/build/types/segmentedControl/SegmentedControl.d.ts.map +0 -1
  37. package/build/types/segmentedControl/index.d.ts +0 -3
  38. package/build/types/segmentedControl/index.d.ts.map +0 -1
  39. package/src/segmentedControl/SegmentedControl.css +0 -101
  40. package/src/segmentedControl/SegmentedControl.less +0 -101
  41. package/src/segmentedControl/SegmentedControl.spec.tsx +0 -106
  42. package/src/segmentedControl/SegmentedControl.story.tsx +0 -55
  43. package/src/segmentedControl/SegmentedControl.tsx +0 -175
  44. package/src/segmentedControl/index.ts +0 -2
  45. package/src/snackbar/SnackbarContext.js +0 -4
  46. package/src/snackbar/SnackbarProvider.js +0 -51
  47. /package/src/snackbar/{index.js → index.ts} +0 -0
  48. /package/src/snackbar/{useSnackbar.js → useSnackbar.ts} +0 -0
@@ -1,21 +1,36 @@
1
- import PropTypes from 'prop-types';
2
- import { Component, createRef, RefObject } from 'react';
1
+ import { Component, createRef } from 'react';
3
2
  import { CSSTransition } from 'react-transition-group';
4
3
 
5
4
  import ActionButton from '../actionButton';
6
5
  import Body from '../body';
7
- import { Theme } from '../common';
6
+ import { Theme, ThemeDark, ThemeLight } from '../common';
8
7
  import { DirectionContext } from '../provider/direction';
9
8
  import withNextPortal from '../withNextPortal/withNextPortal';
10
9
 
11
10
  export const CSS_TRANSITION_DURATION = 400;
12
11
 
13
- export class Snackbar extends Component {
14
- /** @type {RefObject<HTMLSpanElement>} */
15
- bodyRef = createRef();
12
+ export interface SnackbarProps {
13
+ action?: {
14
+ label: string;
15
+ onClick?: React.MouseEventHandler<HTMLButtonElement>;
16
+ };
17
+ text: React.ReactNode;
18
+ theme?: ThemeLight | ThemeDark;
19
+ timeout: number;
20
+ timestamp: number;
21
+ }
22
+
23
+ interface SnackbarState extends Pick<SnackbarProps, 'action' | 'text' | 'theme'> {
24
+ visible: boolean;
25
+ }
26
+
27
+ export class Snackbar extends Component<SnackbarProps, SnackbarState> {
28
+ bodyRef = createRef<HTMLSpanElement>();
29
+ timeout = 0;
30
+ transitionTimeout = 0;
16
31
 
17
- constructor() {
18
- super();
32
+ constructor(props: SnackbarProps) {
33
+ super(props);
19
34
  this.state = {
20
35
  visible: false,
21
36
  text: '',
@@ -23,11 +38,11 @@ export class Snackbar extends Component {
23
38
  }
24
39
 
25
40
  componentWillUnmount() {
26
- clearTimeout(this.timeout);
27
- clearTimeout(this.transitionTimeout);
41
+ window.clearTimeout(this.timeout);
42
+ window.clearTimeout(this.transitionTimeout);
28
43
  }
29
44
 
30
- shouldComponentUpdate(nextProps, nextState) {
45
+ shouldComponentUpdate(nextProps: SnackbarProps, nextState: SnackbarState) {
31
46
  if (!nextProps.text) {
32
47
  return false;
33
48
  }
@@ -45,12 +60,12 @@ export class Snackbar extends Component {
45
60
  setLeaveTimeout = () => {
46
61
  const { timeout } = this.props;
47
62
 
48
- this.timeout = setTimeout(() => {
63
+ this.timeout = window.setTimeout(() => {
49
64
  this.setState({ visible: false });
50
65
  }, timeout);
51
66
  };
52
67
 
53
- componentDidUpdate(previousProps) {
68
+ componentDidUpdate(previousProps: SnackbarProps) {
54
69
  const { action, text, theme, timestamp } = this.props;
55
70
 
56
71
  if (!previousProps.text) {
@@ -58,11 +73,11 @@ export class Snackbar extends Component {
58
73
  this.setLeaveTimeout();
59
74
  });
60
75
  } else if (previousProps.timestamp !== timestamp) {
61
- clearTimeout(this.timeout);
76
+ window.clearTimeout(this.timeout);
62
77
 
63
78
  if (this.state.visible) {
64
79
  this.setState({ visible: false }, () => {
65
- this.transitionTimeout = setTimeout(() => {
80
+ this.transitionTimeout = window.setTimeout(() => {
66
81
  this.setState({ visible: true, action, text, theme });
67
82
  this.setLeaveTimeout();
68
83
  }, CSS_TRANSITION_DURATION);
@@ -75,7 +90,7 @@ export class Snackbar extends Component {
75
90
  }
76
91
 
77
92
  render() {
78
- const { action, text, theme, visible } = this.state;
93
+ const { action, text, theme = Theme.LIGHT, visible } = this.state;
79
94
  const { timeout } = this.props;
80
95
 
81
96
  return (
@@ -112,20 +127,4 @@ export class Snackbar extends Component {
112
127
 
113
128
  Snackbar.contextType = DirectionContext;
114
129
 
115
- Snackbar.propTypes = {
116
- action: PropTypes.shape({
117
- label: PropTypes.string.isRequired,
118
- onClick: PropTypes.func,
119
- }),
120
- text: PropTypes.node.isRequired,
121
- theme: PropTypes.oneOf(['light', 'dark']),
122
- timeout: PropTypes.number.isRequired,
123
- timestamp: PropTypes.number.isRequired,
124
- };
125
-
126
- Snackbar.defaultProps = {
127
- action: null,
128
- theme: Theme.LIGHT,
129
- };
130
-
131
130
  export default withNextPortal(Snackbar);
@@ -0,0 +1,11 @@
1
+ import { createContext } from 'react';
2
+
3
+ import { SnackbarProps } from './Snackbar';
4
+
5
+ export type SnackbarContextType = {
6
+ createSnackbar: (props: Omit<SnackbarProps, 'timeout' | 'timestamp'>) => void;
7
+ };
8
+
9
+ export const SnackbarContext = createContext<SnackbarContextType>({ createSnackbar: () => {} });
10
+
11
+ export const SnackbarConsumer = SnackbarContext.Consumer;
@@ -0,0 +1,39 @@
1
+ import { useMemo, useState } from 'react';
2
+
3
+ import SnackbarPortal, { SnackbarProps } from './Snackbar';
4
+ import { SnackbarContext } from './SnackbarContext';
5
+
6
+ export interface SnackbarProviderProps {
7
+ timeout?: number;
8
+ children?: React.ReactNode;
9
+ }
10
+
11
+ export default function SnackbarProvider({ timeout = 4500, children }: SnackbarProviderProps) {
12
+ const [state, setState] = useState<Omit<SnackbarProps, 'timeout'>>({
13
+ text: '',
14
+ timestamp: 0,
15
+ });
16
+ const { action, text, theme, timestamp } = state;
17
+
18
+ return (
19
+ <SnackbarContext.Provider
20
+ value={useMemo(
21
+ () => ({
22
+ createSnackbar: ({ action, text, theme }) => {
23
+ setState({ action, text, theme, timestamp: Date.now() });
24
+ },
25
+ }),
26
+ [],
27
+ )}
28
+ >
29
+ <SnackbarPortal
30
+ action={action}
31
+ text={text}
32
+ timestamp={timestamp}
33
+ timeout={timeout}
34
+ theme={theme}
35
+ />
36
+ {children}
37
+ </SnackbarContext.Provider>
38
+ );
39
+ }
package/src/ssr.spec.js CHANGED
@@ -154,23 +154,6 @@ describe('Server side rendering', () => {
154
154
  label: 'Two',
155
155
  },
156
156
  ],
157
- segments: [
158
- {
159
- id: '1',
160
- value: 'accounting',
161
- label: 'Accounting',
162
- },
163
- {
164
- id: '2',
165
- value: 'payroll',
166
- label: 'Payroll',
167
- },
168
- {
169
- id: '3',
170
- value: 'reporting',
171
- label: 'Reporting',
172
- },
173
- ],
174
157
  };
175
158
 
176
159
  // Override props in case of name collision.
@@ -2,7 +2,7 @@ import { useState, useEffect } from 'react';
2
2
  import { createPortal } from 'react-dom';
3
3
 
4
4
  export default function withNextPortalWrapper<T extends Record<string, any>>(
5
- Component: React.FunctionComponent<T>,
5
+ Component: React.ComponentType<T>,
6
6
  ) {
7
7
  return function (props: T) {
8
8
  const [mounted, setMounted] = useState(false);
@@ -1,101 +0,0 @@
1
- .segmented-control {
2
- box-sizing: border-box;
3
- --segment-highlight-width: 0;
4
- --segment-highlight-x: var(--size-4);
5
- }
6
- .segmented-control__segments {
7
- display: inline-flex;
8
- position: relative;
9
- padding: 4px;
10
- padding: var(--size-4);
11
- width: 100%;
12
- justify-content: center;
13
- align-items: center;
14
- background: rgba(134,167,189,0.10196);
15
- background: var(--color-background-neutral);
16
- border-radius: 24px;
17
- border-radius: var(--size-24);
18
- transition: outline 300ms;
19
- outline: 2px solid transparent;
20
- }
21
- .segmented-control--input:has(:focus-visible) > .segmented-control__segments::after {
22
- outline: 2px solid var(--color-interactive-primary);
23
- }
24
- .segmented-control__segments::after {
25
- content: "";
26
- position: absolute;
27
- width: var(--segment-highlight-width);
28
- top: 4px;
29
- top: var(--size-4);
30
- bottom: 4px;
31
- bottom: var(--size-4);
32
- left: var(--segment-highlight-x);
33
- z-index: 0;
34
- background: #ffffff;
35
- background: var(--color-background-screen);
36
- border-radius: 24px;
37
- border-radius: var(--size-24);
38
- transition: left 300ms;
39
- }
40
- .segmented-control__segments--no-animate::after {
41
- transition: none !important;
42
- }
43
- .segmented-control__segment {
44
- position: relative;
45
- flex: 1 1 100%;
46
- flex-flow: column;
47
- padding: 8px 16px;
48
- padding: var(--size-8) var(--size-16);
49
- margin: 0 0 0 4px;
50
- margin: 0 0 0 var(--size-4);
51
- min-width: 0;
52
- line-height: inherit;
53
- align-items: center;
54
- text-align: center;
55
- vertical-align: middle;
56
- border-radius: 24px;
57
- border-radius: var(--size-24);
58
- z-index: 1;
59
- cursor: pointer;
60
- transition: background 300ms;
61
- color: var(--color-interactive-primary);
62
- }
63
- .segmented-control__segment:first-child {
64
- margin-left: 0;
65
- }
66
- .segmented-control__segment:hover {
67
- background: rgba(0,0,0,0.10196);
68
- background: var(--color-background-overlay);
69
- }
70
- .segmented-control__radio-input {
71
- position: fixed;
72
- opacity: 0;
73
- pointer-events: none;
74
- }
75
- .segmented-control__button {
76
- width: 100%;
77
- height: 100%;
78
- background: none;
79
- -webkit-appearance: none;
80
- -moz-appearance: none;
81
- appearance: none;
82
- border: none;
83
- outline: none;
84
- font: inherit;
85
- outline: 2px solid transparent;
86
- }
87
- .segmented-control__button:focus {
88
- outline-offset: 0px;
89
- }
90
- .segmented-control__button:focus-visible {
91
- outline-color: var(--color-interactive-primary);
92
- }
93
- .segmented-control__selected-segment:hover {
94
- background: transparent;
95
- }
96
- .segmented-control__text {
97
- word-wrap: break-word;
98
- word-break: break-word;
99
- color: var(--color-interactive-primary);
100
- transition: font-weight 300ms;
101
- }
@@ -1,31 +0,0 @@
1
- /// <reference types="react" />
2
- type SegmentBase = {
3
- id: string;
4
- label: string;
5
- value: string;
6
- };
7
- type Segment = SegmentBase & {
8
- controls?: never;
9
- };
10
- type SegmentWithControls = SegmentBase & {
11
- controls: string;
12
- };
13
- export type Segments = Segment[] | SegmentWithControls[];
14
- type SegmentedControlPropsBase = {
15
- name: string;
16
- defaultValue: string;
17
- mode: 'input' | 'view';
18
- onChange: (value: string) => void;
19
- };
20
- type SegmentedControlViewProps = {
21
- mode: 'view';
22
- segments: SegmentWithControls[];
23
- };
24
- type SegmentedControlInputProps = {
25
- mode: 'input';
26
- segments: Segment[];
27
- };
28
- export type SegmentedControlProps = SegmentedControlPropsBase & (SegmentedControlViewProps | SegmentedControlInputProps);
29
- declare const SegmentedControl: ({ name, defaultValue, mode, segments, onChange, }: SegmentedControlProps) => import("react").JSX.Element;
30
- export default SegmentedControl;
31
- //# sourceMappingURL=SegmentedControl.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SegmentedControl.d.ts","sourceRoot":"","sources":["../../../src/segmentedControl/SegmentedControl.tsx"],"names":[],"mappings":";AAMA,KAAK,WAAW,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhE,KAAK,OAAO,GAAG,WAAW,GAAG;IAAE,QAAQ,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC;AAClD,KAAK,mBAAmB,GAAG,WAAW,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9D,MAAM,MAAM,QAAQ,GAAG,OAAO,EAAE,GAAG,mBAAmB,EAAE,CAAC;AAEzD,KAAK,yBAAyB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;IACvB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC,CAAC;AAEF,KAAK,yBAAyB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,mBAAmB,EAAE,CAAC;CACjC,CAAC;AAEF,KAAK,0BAA0B,GAAG;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,yBAAyB,GAC3D,CAAC,yBAAyB,GAAG,0BAA0B,CAAC,CAAC;AAE3D,QAAA,MAAM,gBAAgB,sDAMnB,qBAAqB,gCAqIvB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
@@ -1,3 +0,0 @@
1
- export * from './SegmentedControl';
2
- export { default } from './SegmentedControl';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/segmentedControl/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC"}
@@ -1,101 +0,0 @@
1
- .segmented-control {
2
- box-sizing: border-box;
3
- --segment-highlight-width: 0;
4
- --segment-highlight-x: var(--size-4);
5
- }
6
- .segmented-control__segments {
7
- display: inline-flex;
8
- position: relative;
9
- padding: 4px;
10
- padding: var(--size-4);
11
- width: 100%;
12
- justify-content: center;
13
- align-items: center;
14
- background: rgba(134,167,189,0.10196);
15
- background: var(--color-background-neutral);
16
- border-radius: 24px;
17
- border-radius: var(--size-24);
18
- transition: outline 300ms;
19
- outline: 2px solid transparent;
20
- }
21
- .segmented-control--input:has(:focus-visible) > .segmented-control__segments::after {
22
- outline: 2px solid var(--color-interactive-primary);
23
- }
24
- .segmented-control__segments::after {
25
- content: "";
26
- position: absolute;
27
- width: var(--segment-highlight-width);
28
- top: 4px;
29
- top: var(--size-4);
30
- bottom: 4px;
31
- bottom: var(--size-4);
32
- left: var(--segment-highlight-x);
33
- z-index: 0;
34
- background: #ffffff;
35
- background: var(--color-background-screen);
36
- border-radius: 24px;
37
- border-radius: var(--size-24);
38
- transition: left 300ms;
39
- }
40
- .segmented-control__segments--no-animate::after {
41
- transition: none !important;
42
- }
43
- .segmented-control__segment {
44
- position: relative;
45
- flex: 1 1 100%;
46
- flex-flow: column;
47
- padding: 8px 16px;
48
- padding: var(--size-8) var(--size-16);
49
- margin: 0 0 0 4px;
50
- margin: 0 0 0 var(--size-4);
51
- min-width: 0;
52
- line-height: inherit;
53
- align-items: center;
54
- text-align: center;
55
- vertical-align: middle;
56
- border-radius: 24px;
57
- border-radius: var(--size-24);
58
- z-index: 1;
59
- cursor: pointer;
60
- transition: background 300ms;
61
- color: var(--color-interactive-primary);
62
- }
63
- .segmented-control__segment:first-child {
64
- margin-left: 0;
65
- }
66
- .segmented-control__segment:hover {
67
- background: rgba(0,0,0,0.10196);
68
- background: var(--color-background-overlay);
69
- }
70
- .segmented-control__radio-input {
71
- position: fixed;
72
- opacity: 0;
73
- pointer-events: none;
74
- }
75
- .segmented-control__button {
76
- width: 100%;
77
- height: 100%;
78
- background: none;
79
- -webkit-appearance: none;
80
- -moz-appearance: none;
81
- appearance: none;
82
- border: none;
83
- outline: none;
84
- font: inherit;
85
- outline: 2px solid transparent;
86
- }
87
- .segmented-control__button:focus {
88
- outline-offset: 0px;
89
- }
90
- .segmented-control__button:focus-visible {
91
- outline-color: var(--color-interactive-primary);
92
- }
93
- .segmented-control__selected-segment:hover {
94
- background: transparent;
95
- }
96
- .segmented-control__text {
97
- word-wrap: break-word;
98
- word-break: break-word;
99
- color: var(--color-interactive-primary);
100
- transition: font-weight 300ms;
101
- }
@@ -1,101 +0,0 @@
1
- .segmented-control {
2
- box-sizing: border-box;
3
- --segment-highlight-width: 0;
4
- --segment-highlight-x: var(--size-4);
5
- }
6
-
7
- .segmented-control__segments {
8
- display: inline-flex;
9
- position: relative;
10
- padding: var(--size-4);
11
- width: 100%;
12
- justify-content: center;
13
- align-items: center;
14
- background: var(--color-background-neutral);
15
- border-radius: var(--size-24);
16
- transition: outline 300ms;
17
- outline: 2px solid transparent;
18
- }
19
-
20
- .segmented-control--input:has(:focus-visible) > .segmented-control__segments::after {
21
- outline: 2px solid var(--color-interactive-primary);
22
- }
23
-
24
- .segmented-control__segments::after {
25
- content: "";
26
- position: absolute;
27
- width: var(--segment-highlight-width);
28
- top: var(--size-4);
29
- bottom: var(--size-4);
30
- left: var(--segment-highlight-x);
31
- z-index: 0;
32
- background: var(--color-background-screen);
33
- border-radius: var(--size-24);
34
- transition: left 300ms;
35
- }
36
-
37
- .segmented-control__segments--no-animate::after {
38
- transition: none !important;
39
- }
40
-
41
- .segmented-control__segment {
42
- position: relative;
43
- flex: 1 1 100%;
44
- flex-flow: column;
45
- padding: var(--size-8) var(--size-16);
46
- margin: 0 0 0 var(--size-4);
47
- min-width: 0;
48
- line-height: inherit;
49
- align-items: center;
50
- text-align: center;
51
- vertical-align: middle;
52
- border-radius: var(--size-24);
53
- z-index: 1;
54
- cursor: pointer;
55
- transition: background 300ms;
56
- color: var(--color-interactive-primary);
57
- }
58
-
59
- .segmented-control__segment:first-child {
60
- margin-left: 0;
61
- }
62
-
63
- .segmented-control__segment:hover {
64
- background: var(--color-background-overlay);
65
- }
66
-
67
- .segmented-control__radio-input {
68
- position: fixed;
69
- opacity: 0;
70
- pointer-events: none;
71
- }
72
-
73
- .segmented-control__button {
74
- width: 100%;
75
- height: 100%;
76
- background: none;
77
- appearance: none;
78
- border: none;
79
- outline: none;
80
- font: inherit;
81
- outline: 2px solid transparent;
82
- }
83
-
84
- .segmented-control__button:focus {
85
- outline-offset: 0px;
86
- }
87
-
88
- .segmented-control__button:focus-visible {
89
- outline-color: var(--color-interactive-primary);
90
- }
91
-
92
- .segmented-control__selected-segment:hover {
93
- background: transparent;
94
- }
95
-
96
- .segmented-control__text {
97
- word-wrap: break-word;
98
- word-break: break-word;
99
- color: var(--color-interactive-primary);
100
- transition: font-weight 300ms;
101
- }
@@ -1,106 +0,0 @@
1
- import '@testing-library/jest-dom';
2
- import { render, screen, userEvent } from '../test-utils';
3
-
4
- import SegmentedControl, { SegmentedControlProps } from './SegmentedControl';
5
-
6
- const defaultSegments = [
7
- {
8
- id: '1',
9
- value: 'accounting',
10
- label: 'Accounting',
11
- },
12
- {
13
- id: '2',
14
- value: 'payroll',
15
- label: 'Payroll',
16
- },
17
- {
18
- id: '3',
19
- value: 'reporting',
20
- label: 'Reporting',
21
- },
22
- ];
23
-
24
- const defaultSegmentsWithControls = defaultSegments.map((segment, index) => ({
25
- ...segment,
26
- controls: `aControlId${index}`,
27
- }));
28
-
29
- const onChange = jest.fn();
30
-
31
- const defaultProps: SegmentedControlProps = {
32
- name: 'segmentedControl',
33
- defaultValue: defaultSegments[0].value,
34
- mode: 'input',
35
- segments: defaultSegments,
36
- onChange,
37
- };
38
-
39
- const renderSegmentedControl = (overrides: Partial<SegmentedControlProps> = {}) => {
40
- return render(<SegmentedControl {...defaultProps} {...(overrides as SegmentedControlProps)} />);
41
- };
42
-
43
- describe('SegmentedControl', () => {
44
- it('dynamically adds inline style props for animated segment overlay', () => {
45
- renderSegmentedControl();
46
-
47
- const segmentedControls = screen.getByTestId('segmented-control');
48
-
49
- expect(segmentedControls).toHaveStyle(
50
- '--segment-highlight-width: 0px; --segment-highlight-x: 0px;',
51
- );
52
- });
53
-
54
- it('default value is selected', () => {
55
- renderSegmentedControl({ mode: 'view', segments: defaultSegmentsWithControls });
56
-
57
- const accountingTab = screen.getByRole('tab', { name: 'Accounting' });
58
- expect(accountingTab).toHaveAttribute('aria-selected', 'true');
59
- });
60
-
61
- it('lets the user pick through the segments when it is set to input', () => {
62
- renderSegmentedControl();
63
-
64
- const payroll = screen.getByRole('radio', { name: 'Payroll' });
65
- userEvent.click(payroll);
66
-
67
- expect(onChange).toHaveBeenCalledWith('payroll');
68
-
69
- const reporting = screen.getByRole('radio', { name: 'Reporting' });
70
- userEvent.click(reporting);
71
-
72
- expect(onChange).toHaveBeenCalledWith('reporting');
73
- });
74
-
75
- it('lets the user pick through the segments when it is set to view', () => {
76
- renderSegmentedControl({ mode: 'view', segments: defaultSegmentsWithControls });
77
-
78
- const payroll = screen.getByRole('tab', { name: 'Payroll' });
79
- userEvent.click(payroll);
80
-
81
- expect(onChange).toHaveBeenCalledWith('payroll');
82
-
83
- const reporting = screen.getByRole('tab', { name: 'Reporting' });
84
- userEvent.click(reporting);
85
-
86
- expect(onChange).toHaveBeenCalledWith('reporting');
87
- });
88
-
89
- it('throws error if user tries to add too many segments', () => {
90
- expect(() => {
91
- renderSegmentedControl({
92
- mode: 'input',
93
- segments: [
94
- ...defaultSegments,
95
- {
96
- id: '4',
97
- value: 'anotherOne',
98
- label: 'Another One',
99
- },
100
- ],
101
- });
102
- }).toThrow(
103
- 'SegmentedControl only supports up to 3 segments. Please refer to: https://wise.design/components/segmented-control',
104
- );
105
- });
106
- });