@transferwise/components 0.0.0-experimental-a087360 → 0.0.0-experimental-5ac2a3c

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 (49) hide show
  1. package/build/index.esm.js +64 -46
  2. package/build/index.esm.js.map +1 -1
  3. package/build/index.js +64 -46
  4. package/build/index.js.map +1 -1
  5. package/build/main.css +1 -1
  6. package/build/styles/flowNavigation/FlowNavigation.css +1 -1
  7. package/build/styles/flowNavigation/animatedLabel/AnimatedLabel.css +1 -1
  8. package/build/styles/header/Header.css +1 -1
  9. package/build/styles/main.css +1 -1
  10. package/build/styles/overlayHeader/OverlayHeader.css +1 -1
  11. package/build/types/common/flowHeader/FlowHeader.d.ts.map +1 -1
  12. package/build/types/flowNavigation/FlowNavigation.d.ts.map +1 -1
  13. package/build/types/flowNavigation/animatedLabel/AnimatedLabel.d.ts +2 -1
  14. package/build/types/flowNavigation/animatedLabel/AnimatedLabel.d.ts.map +1 -1
  15. package/build/types/flowNavigation/backButton/BackButton.d.ts +11 -10
  16. package/build/types/flowNavigation/backButton/BackButton.d.ts.map +1 -1
  17. package/build/types/header/Header.d.ts +1 -1
  18. package/build/types/header/Header.d.ts.map +1 -1
  19. package/build/types/overlayHeader/OverlayHeader.d.ts.map +1 -1
  20. package/build/types/title/Title.d.ts +1 -1
  21. package/build/types/title/Title.d.ts.map +1 -1
  22. package/package.json +1 -1
  23. package/src/common/flowHeader/FlowHeader.tsx +22 -4
  24. package/src/common/flowHeader/__snapshots__/FlowHeader.spec.js.snap +22 -6
  25. package/src/flowNavigation/FlowNavigation.css +1 -1
  26. package/src/flowNavigation/FlowNavigation.less +9 -0
  27. package/src/flowNavigation/FlowNavigation.spec.js +3 -3
  28. package/src/flowNavigation/FlowNavigation.story.js +189 -22
  29. package/src/flowNavigation/FlowNavigation.tsx +27 -22
  30. package/src/flowNavigation/__snapshots__/FlowNavigation.spec.js.snap +26 -18
  31. package/src/flowNavigation/animatedLabel/AnimatedLabel.css +1 -1
  32. package/src/flowNavigation/animatedLabel/AnimatedLabel.less +6 -0
  33. package/src/flowNavigation/animatedLabel/AnimatedLabel.spec.js +21 -7
  34. package/src/flowNavigation/animatedLabel/AnimatedLabel.story.js +22 -0
  35. package/src/flowNavigation/animatedLabel/AnimatedLabel.tsx +17 -8
  36. package/src/flowNavigation/animatedLabel/__snapshots__/AnimatedLabel.spec.js.snap +4 -4
  37. package/src/flowNavigation/backButton/BackButton.js +9 -14
  38. package/src/flowNavigation/backButton/BackButton.spec.js +2 -3
  39. package/src/flowNavigation/backButton/__snapshots__/BackButton.spec.js.snap +21 -28
  40. package/src/header/Header.css +1 -1
  41. package/src/header/Header.less +5 -0
  42. package/src/header/Header.tsx +21 -2
  43. package/src/main.css +1 -1
  44. package/src/overlayHeader/OverlayHeader.css +1 -1
  45. package/src/overlayHeader/OverlayHeader.js +4 -6
  46. package/src/overlayHeader/OverlayHeader.less +8 -0
  47. package/src/overlayHeader/OverlayHeader.spec.js +1 -1
  48. package/src/overlayHeader/__snapshots__/OverlayHeader.spec.js.snap +14 -10
  49. package/src/title/Title.tsx +1 -1
@@ -6,19 +6,23 @@ exports[`FlowNavigation on mobile renders as expected 1`] = `
6
6
  class="np-flow-navigation d-flex align-items-center justify-content-center p-y-3 np-flow-navigation--border-bottom"
7
7
  >
8
8
  <div
9
- class="np-flow-header d-flex flex-wrap align-items-center justify-content-between flex__item--12 np-flow-navigation__content p-x-3 np-flow-navigation--xs-max"
9
+ class="np-flow-header d-flex flex-wrap align-items-center np-flow-navigation__content p-x-3 np-flow-navigation--xs-max"
10
10
  >
11
- <div>
12
- BackButton
13
- </div>
14
11
  <div
15
- class="m-x-1"
16
- data-testid="activeLabel-1"
12
+ class="np-flow-header__left flex__item--8"
17
13
  >
18
- AnimatedLabel
14
+ <div>
15
+ BackButton
16
+ <div
17
+ class="m-x-1"
18
+ data-testid="activeLabel-0"
19
+ >
20
+ AnimatedLabel
21
+ </div>
22
+ </div>
19
23
  </div>
20
24
  <div
21
- class="d-flex align-items-center"
25
+ class="align-items-center d-flex np-flow-header__right justify-content-end flex__item--4 "
22
26
  >
23
27
  <div
24
28
  class="tw-avatar tw-avatar--48 tw-avatar--initials np-text-title-body"
@@ -30,7 +34,7 @@ exports[`FlowNavigation on mobile renders as expected 1`] = `
30
34
  </div>
31
35
  </div>
32
36
  <span
33
- class="m-x-1"
37
+ class="separator"
34
38
  />
35
39
  <button
36
40
  aria-label="Close"
@@ -118,16 +122,20 @@ exports[`FlowNavigation renders as expected 1`] = `
118
122
  class="np-flow-navigation d-flex align-items-center justify-content-center p-y-3 np-flow-navigation--border-bottom"
119
123
  >
120
124
  <div
121
- class="np-flow-header d-flex flex-wrap align-items-center justify-content-between flex__item--12 np-flow-navigation__content p-x-3 np-flow-navigation--sm np-flow-navigation--lg"
125
+ class="np-flow-header d-flex flex-wrap align-items-center np-flow-navigation__content p-x-3 np-flow-navigation--sm np-flow-navigation--lg"
122
126
  >
123
- <img
124
- alt="logo"
125
- height="24"
126
- src="logo.svg"
127
- width="138"
128
- />
129
127
  <div
130
- class="d-flex align-items-center order-2"
128
+ class="np-flow-header__left"
129
+ >
130
+ <img
131
+ alt="logo"
132
+ height="24"
133
+ src="logo.svg"
134
+ width="138"
135
+ />
136
+ </div>
137
+ <div
138
+ class="align-items-center d-flex np-flow-header__right justify-content-end order-2"
131
139
  >
132
140
  <div
133
141
  class="tw-avatar tw-avatar--48 tw-avatar--initials np-text-title-body"
@@ -139,7 +147,7 @@ exports[`FlowNavigation renders as expected 1`] = `
139
147
  </div>
140
148
  </div>
141
149
  <span
142
- class="m-x-1"
150
+ class="separator"
143
151
  />
144
152
  <button
145
153
  aria-label="Close"
@@ -1 +1 @@
1
- .np-animated-label{height:24px;overflow:hidden;padding-top:1px;position:relative}.np-animated-label>*{height:0;opacity:0;position:absolute;transform:translateX(-8px);transition:all .3s ease-in}.np-animated-label--in{height:auto;opacity:1;position:relative;top:auto;transform:translateX(0);transition:all .3s ease-in .3s}
1
+ .np-animated-label{height:24px;overflow:hidden;padding-top:1px;position:relative}.np-animated-label>*{height:0;opacity:0;position:absolute;transform:translateX(-8px);transition:all .3s ease-in}.np-animated-label--in{height:auto;opacity:1;position:relative;top:auto;transform:translateX(0);transition:all .3s ease-in .3s}.np-animated-label--out{position:relative;top:-24px;transform:translateX(8px)}
@@ -28,4 +28,10 @@
28
28
  transform: translateX(0);
29
29
  transition: all @transition-duration ease-in @transition-duration;
30
30
  }
31
+
32
+ &--out {
33
+ position: relative;
34
+ top: -@label-height;
35
+ transform: translateX(@slide-length);
36
+ }
31
37
  }
@@ -14,6 +14,12 @@ describe('AnimatedLabel', () => {
14
14
  expect(container).toMatchSnapshot();
15
15
  });
16
16
 
17
+ it('renders aria-label if provided', () => {
18
+ render(<AnimatedLabel {...props} aria-label="hello" />);
19
+ const checkbox = screen.getByLabelText('hello');
20
+ expect(checkbox).toBeInTheDocument();
21
+ });
22
+
17
23
  it('renders only one label with class in', () => {
18
24
  const { container } = render(<AnimatedLabel {...props} />);
19
25
  expect(screen.getByText(props.labels[0])).toHaveClass('np-animated-label--in');
@@ -22,33 +28,41 @@ describe('AnimatedLabel', () => {
22
28
 
23
29
  it('renders only one label with class out', () => {
24
30
  const { container } = render(<AnimatedLabel {...props} />);
25
- expect(screen.getByText(props.labels[1])).not.toHaveClass('np-animated-label--in');
26
- expect(container.querySelectorAll('.np-animated-label--in')).toHaveLength(1);
31
+ expect(screen.getByText(props.labels[1])).toHaveClass('np-animated-label--out');
32
+ expect(container.querySelectorAll('.np-animated-label--out')).toHaveLength(1);
27
33
  });
28
34
 
29
35
  it('when activeLabel increase it switches class accordingly', () => {
30
36
  const { rerender } = render(<AnimatedLabel {...props} />);
31
37
  expect(screen.getByText(props.labels[0])).toHaveClass('np-animated-label--in');
32
- expect(screen.getByText(props.labels[1])).not.toHaveClass('np-animated-label--in');
38
+ expect(screen.getByText(props.labels[1])).toHaveClass('np-animated-label--out');
39
+
40
+ expect(screen.getByText(props.labels[2])).not.toHaveClass('np-animated-label--out');
33
41
  expect(screen.getByText(props.labels[2])).not.toHaveClass('np-animated-label--in');
34
42
 
35
43
  rerender(<AnimatedLabel {...props} activeLabel={1} />);
36
44
 
45
+ expect(screen.getByText(props.labels[0])).not.toHaveClass('np-animated-label--out');
37
46
  expect(screen.getByText(props.labels[0])).not.toHaveClass('np-animated-label--in');
47
+
38
48
  expect(screen.getByText(props.labels[1])).toHaveClass('np-animated-label--in');
39
- expect(screen.getByText(props.labels[2])).not.toHaveClass('np-animated-label--in');
49
+ expect(screen.getByText(props.labels[2])).toHaveClass('np-animated-label--out');
40
50
  });
41
51
 
42
52
  it('when activeLabel decrease it switches class accordingly', () => {
43
53
  const { rerender } = render(<AnimatedLabel {...props} activeLabel={1} />);
44
- expect(screen.getByText(props.labels[0])).not.toHaveClass('np-animated-label--in');
45
54
  expect(screen.getByText(props.labels[1])).toHaveClass('np-animated-label--in');
46
- expect(screen.getByText(props.labels[2])).not.toHaveClass('np-animated-label--in');
55
+ expect(screen.getByText(props.labels[2])).toHaveClass('np-animated-label--out');
56
+
57
+ expect(screen.getByText(props.labels[0])).not.toHaveClass('np-animated-label--out');
58
+ expect(screen.getByText(props.labels[0])).not.toHaveClass('np-animated-label--in');
47
59
 
48
60
  rerender(<AnimatedLabel {...props} activeLabel={0} />);
49
61
 
50
62
  expect(screen.getByText(props.labels[0])).toHaveClass('np-animated-label--in');
51
- expect(screen.getByText(props.labels[1])).not.toHaveClass('np-animated-label--in');
63
+ expect(screen.getByText(props.labels[1])).toHaveClass('np-animated-label--out');
64
+
65
+ expect(screen.getByText(props.labels[2])).not.toHaveClass('np-animated-label--out');
52
66
  expect(screen.getByText(props.labels[2])).not.toHaveClass('np-animated-label--in');
53
67
  });
54
68
  });
@@ -0,0 +1,22 @@
1
+ import { select } from '@storybook/addon-knobs';
2
+
3
+ import AnimatedLabel from './AnimatedLabel';
4
+
5
+ export default {
6
+ component: AnimatedLabel,
7
+ title: 'Internal/AnimatedLabel',
8
+ };
9
+
10
+ export const Basic = () => {
11
+ const labels = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
12
+ const activeLabel = select('active label', labels, 10);
13
+
14
+ return (
15
+ <div style={{ width: '120px' }} className="p-a-1">
16
+ <AnimatedLabel
17
+ labels={labels.map((element) => `label-${element}`)}
18
+ activeLabel={activeLabel}
19
+ />
20
+ </div>
21
+ );
22
+ };
@@ -1,32 +1,41 @@
1
1
  import classNames from 'classnames';
2
2
  import React from 'react';
3
3
 
4
- import Body from '../../body';
5
- import { Typography } from '../../common';
6
-
7
4
  export interface AnimatedLabelProps {
8
5
  activeLabel: number;
9
6
  className?: string;
10
7
  labels: React.ReactNode[];
8
+ 'aria-label': string;
11
9
  }
12
10
 
13
- const AnimatedLabel = ({ activeLabel, className, labels }: AnimatedLabelProps) => {
11
+ const AnimatedLabel = ({
12
+ activeLabel,
13
+ className,
14
+ labels,
15
+ 'aria-label': ariaLabel,
16
+ }: AnimatedLabelProps) => {
17
+ const numberLabels = labels.length - 1;
18
+
14
19
  return (
15
- <Body type={Typography.BODY_LARGE_BOLD} className={classNames('np-animated-label', className)}>
20
+ <div
21
+ aria-label={ariaLabel}
22
+ className={classNames('np-animated-label', 'np-text-body-large-bold', className)}
23
+ >
16
24
  {labels.map((label, index) => {
17
25
  const nextLabel = index - 1;
18
26
  return (
19
27
  <div
20
28
  key={nextLabel}
21
- className={classNames('text-xs-center', {
22
- 'np-animated-label--in text-ellipsis': index === activeLabel,
29
+ className={classNames('text-xs-left', {
30
+ 'np-animated-label--in': index === activeLabel,
31
+ 'np-animated-label--out': nextLabel === activeLabel && nextLabel !== numberLabels,
23
32
  })}
24
33
  >
25
34
  {label}
26
35
  </div>
27
36
  );
28
37
  })}
29
- </Body>
38
+ </div>
30
39
  );
31
40
  };
32
41
 
@@ -3,20 +3,20 @@
3
3
  exports[`AnimatedLabel renders all labels 1`] = `
4
4
  <div>
5
5
  <div
6
- class="np-text-body-large-bold np-animated-label"
6
+ class="np-animated-label np-text-body-large-bold"
7
7
  >
8
8
  <div
9
- class="text-xs-center np-animated-label--in text-ellipsis"
9
+ class="text-xs-left np-animated-label--in"
10
10
  >
11
11
  label1
12
12
  </div>
13
13
  <div
14
- class="text-xs-center"
14
+ class="text-xs-left np-animated-label--out"
15
15
  >
16
16
  label2
17
17
  </div>
18
18
  <div
19
- class="text-xs-center"
19
+ class="text-xs-left"
20
20
  >
21
21
  label3
22
22
  </div>
@@ -2,23 +2,18 @@ import { ArrowLeft as ArrowLeftIcon } from '@transferwise/icons';
2
2
  import classNames from 'classnames';
3
3
  import PropTypes from 'prop-types';
4
4
 
5
- import Avatar, { AvatarType } from '../../avatar';
6
-
7
- const BackButton = ({ className, onClick, 'aria-label': ariaLabel }) => (
8
- <Avatar type={AvatarType.ICON} size={40}>
9
- <button
10
- type="button"
11
- aria-label={ariaLabel}
12
- className={classNames('np-back-button', 'btn-unstyled', className)}
13
- onClick={onClick}
14
- >
15
- <ArrowLeftIcon size={24} />
16
- </button>
17
- </Avatar>
5
+ const BackButton = ({ label, className, onClick }) => (
6
+ <button
7
+ type="button"
8
+ className={classNames('np-back-button', 'align-items-center', 'btn-unstyled', className)}
9
+ onClick={onClick}
10
+ >
11
+ <ArrowLeftIcon size={24} />
12
+ {label}
13
+ </button>
18
14
  );
19
15
 
20
16
  BackButton.propTypes = {
21
- 'aria-label': PropTypes.string.isRequired,
22
17
  className: PropTypes.string,
23
18
  label: PropTypes.element,
24
19
  onClick: PropTypes.func,
@@ -1,5 +1,5 @@
1
- import { render } from '../../test-utils';
2
- import messages from '../FlowNavigation.messages';
1
+ import '@testing-library/jest-dom';
2
+ import { render } from '@testing-library/react';
3
3
 
4
4
  import BackButton from '.';
5
5
 
@@ -7,7 +7,6 @@ const props = {
7
7
  label: <>label</>,
8
8
  className: 'className',
9
9
  onClick: jest.fn(),
10
- 'aria-label': messages.back.defaultMessage,
11
10
  };
12
11
  describe('BackButton', () => {
13
12
  it(`renders as expected`, () => {
@@ -2,36 +2,29 @@
2
2
 
3
3
  exports[`BackButton renders as expected 1`] = `
4
4
  <div>
5
- <div
6
- class="tw-avatar tw-avatar--40 tw-avatar--icon"
5
+ <button
6
+ class="np-back-button align-items-center btn-unstyled className"
7
+ type="button"
7
8
  >
8
- <div
9
- class="tw-avatar__content"
9
+ <span
10
+ aria-hidden="true"
11
+ class="tw-icon tw-icon-arrow-left "
12
+ data-testid="arrow-left-icon"
13
+ role="presentation"
10
14
  >
11
- <button
12
- class="np-back-button btn-unstyled className"
13
- type="button"
15
+ <svg
16
+ fill="currentColor"
17
+ focusable="false"
18
+ height="24"
19
+ viewBox="0 0 24 24"
20
+ width="24"
14
21
  >
15
- <span
16
- aria-hidden="true"
17
- class="tw-icon tw-icon-arrow-left "
18
- data-testid="arrow-left-icon"
19
- role="presentation"
20
- >
21
- <svg
22
- fill="currentColor"
23
- focusable="false"
24
- height="24"
25
- viewBox="0 0 24 24"
26
- width="24"
27
- >
28
- <path
29
- d="M22.286 11.316H4.629l7.114-7.114-1.2-1.2-8.572 8.571a.829.829 0 0 0 0 1.2l8.572 8.572 1.2-1.2-7.114-7.114h17.657v-1.715Z"
30
- />
31
- </svg>
32
- </span>
33
- </button>
34
- </div>
35
- </div>
22
+ <path
23
+ d="M22.286 11.316H4.629l7.114-7.114-1.2-1.2-8.572 8.571a.829.829 0 0 0 0 1.2l8.572 8.572 1.2-1.2-7.114-7.114h17.657v-1.715Z"
24
+ />
25
+ </svg>
26
+ </span>
27
+ label
28
+ </button>
36
29
  </div>
37
30
  `;
@@ -1 +1 @@
1
- .np-header{align-items:flex-end;border-bottom:1px solid #0000001a;border-bottom:1px solid var(--color-border-neutral);display:flex;justify-content:space-between;margin-bottom:8px;margin-bottom:var(--size-8);max-width:100%;padding:8px 0;padding:var(--size-8) 0}.np-header__title{color:#5d7079;color:var(--color-content-secondary)}.np-theme-personal .np-header{-moz-column-gap:24px;column-gap:24px;-moz-column-gap:var(--size-24);column-gap:var(--size-24)}.np-theme-personal .np-header__button{margin-inline:-16px;margin-inline:calc(var(--size-16)*-1);margin-bottom:-4px;margin-bottom:calc(var(--size-4)*-1)}
1
+ .np-header{align-items:flex-end;border-bottom:1px solid #0000001a;border-bottom:1px solid var(--color-border-neutral);display:flex;justify-content:space-between;margin-bottom:8px;margin-bottom:var(--size-8);max-width:100%;padding:8px 0;padding:var(--size-8) 0}.np-header__title{color:#5d7079;color:var(--color-content-secondary)}.np-theme-personal .np-header{-moz-column-gap:24px;column-gap:24px;-moz-column-gap:var(--size-24);column-gap:var(--size-24)}.np-theme-personal .np-header__button{margin-inline:-16px;margin-inline:calc(var(--size-16)*-1);margin-bottom:-4px;margin-bottom:calc(var(--size-4)*-1)}.np-header legend{border-bottom:none;padding:0}
@@ -19,4 +19,9 @@
19
19
  margin-bottom: calc(var(--size-4) * -1);
20
20
  }
21
21
  }
22
+
23
+ legend {
24
+ padding: 0;
25
+ border-bottom: none;
26
+ }
22
27
  }
@@ -25,7 +25,7 @@ export type HeaderProps = CommonProps & {
25
25
  *
26
26
  * @default "h5"
27
27
  */
28
- as?: Heading;
28
+ as?: Heading | 'legend';
29
29
  title: string;
30
30
  };
31
31
 
@@ -66,12 +66,31 @@ const HeaderAction = ({ action }: { action: ButtonActionProps | LinkActionProps
66
66
  *
67
67
  */
68
68
  export const Header = ({ action, as = 'h5', title, className }: HeaderProps) => {
69
+ if (!action) {
70
+ return (
71
+ <Title
72
+ as={as}
73
+ type={Typography.TITLE_GROUP}
74
+ className={classNames('np-header', 'np-header__title', className)}
75
+ >
76
+ {title}
77
+ </Title>
78
+ );
79
+ }
80
+
81
+ if (as === 'legend') {
82
+ // eslint-disable-next-line no-console
83
+ console.warn(
84
+ 'Legends should be the first child in a fieldset, and this is not possible when including an action',
85
+ );
86
+ }
87
+
69
88
  return (
70
89
  <div className={classNames('np-header', className)}>
71
90
  <Title as={as} type={Typography.TITLE_GROUP} className="np-header__title">
72
91
  {title}
73
92
  </Title>
74
- {action && <HeaderAction action={action} />}
93
+ <HeaderAction action={action} />
75
94
  </div>
76
95
  );
77
96
  };