@transferwise/components 46.31.0 → 46.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/build/index.js +764 -474
  2. package/build/index.js.map +1 -1
  3. package/build/index.mjs +763 -474
  4. package/build/index.mjs.map +1 -1
  5. package/build/main.css +135 -0
  6. package/build/styles/carousel/Carousel.css +135 -0
  7. package/build/styles/main.css +135 -0
  8. package/build/types/carousel/Carousel.d.ts +26 -0
  9. package/build/types/carousel/Carousel.d.ts.map +1 -0
  10. package/build/types/carousel/index.d.ts +3 -0
  11. package/build/types/carousel/index.d.ts.map +1 -0
  12. package/build/types/common/card/Card.d.ts +2 -2
  13. package/build/types/common/card/Card.d.ts.map +1 -1
  14. package/build/types/common/domHelpers/documentIosClick.d.ts +0 -1
  15. package/build/types/common/domHelpers/documentIosClick.d.ts.map +1 -1
  16. package/build/types/common/domHelpers/index.d.ts +1 -1
  17. package/build/types/common/domHelpers/index.d.ts.map +1 -1
  18. package/build/types/dateLookup/DateLookup.d.ts.map +1 -1
  19. package/build/types/index.d.ts +2 -0
  20. package/build/types/index.d.ts.map +1 -1
  21. package/build/types/moneyInput/MoneyInput.d.ts +4 -2
  22. package/build/types/moneyInput/MoneyInput.d.ts.map +1 -1
  23. package/build/types/phoneNumberInput/PhoneNumberInput.d.ts +1 -1
  24. package/build/types/phoneNumberInput/PhoneNumberInput.d.ts.map +1 -1
  25. package/build/types/promoCard/PromoCard.d.ts +16 -5
  26. package/build/types/promoCard/PromoCard.d.ts.map +1 -1
  27. package/build/types/select/Select.d.ts +7 -7
  28. package/build/types/select/Select.d.ts.map +1 -1
  29. package/build/types/typeahead/Typeahead.d.ts +4 -55
  30. package/build/types/typeahead/Typeahead.d.ts.map +1 -1
  31. package/package.json +1 -1
  32. package/src/carousel/Carousel.css +135 -0
  33. package/src/carousel/Carousel.less +133 -0
  34. package/src/carousel/Carousel.spec.tsx +221 -0
  35. package/src/carousel/Carousel.story.tsx +63 -0
  36. package/src/carousel/Carousel.tsx +345 -0
  37. package/src/carousel/index.ts +3 -0
  38. package/src/common/card/Card.tsx +51 -43
  39. package/src/common/domHelpers/documentIosClick.ts +0 -5
  40. package/src/common/domHelpers/index.ts +0 -1
  41. package/src/dateLookup/DateLookup.rtl.spec.tsx +2 -3
  42. package/src/dateLookup/DateLookup.tsx +1 -3
  43. package/src/index.ts +2 -0
  44. package/src/inputs/SelectInput.spec.tsx +1 -1
  45. package/src/main.css +135 -0
  46. package/src/main.less +1 -0
  47. package/src/moneyInput/MoneyInput.rtl.spec.tsx +10 -0
  48. package/src/moneyInput/MoneyInput.spec.js +10 -5
  49. package/src/moneyInput/MoneyInput.tsx +21 -14
  50. package/src/phoneNumberInput/PhoneNumberInput.rtl.spec.tsx +10 -0
  51. package/src/phoneNumberInput/PhoneNumberInput.tsx +11 -2
  52. package/src/promoCard/PromoCard.story.tsx +2 -2
  53. package/src/promoCard/PromoCard.tsx +30 -9
  54. package/src/select/Select.js +18 -15
  55. package/src/select/Select.rtl.spec.tsx +17 -0
  56. package/src/select/Select.spec.js +2 -7
  57. package/src/typeahead/Typeahead.rtl.spec.tsx +16 -0
  58. package/src/typeahead/Typeahead.tsx +21 -7
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
- import { CardProps } from '../common/card';
3
- import { PromoCardIndicatorProps } from './PromoCardIndicator';
4
- export type ReferenceType = React.Ref<HTMLInputElement>;
2
+ import { type CardProps } from '../common/card';
3
+ import { type PromoCardIndicatorProps } from './PromoCardIndicator';
4
+ export type ReferenceType = React.Ref<HTMLInputElement> | React.Ref<HTMLDivElement>;
5
5
  export type RelatedTypes = '' | 'alternate' | 'author' | 'bookmark' | 'external' | 'help' | 'license' | 'next' | 'nofollow' | 'noreferrer' | 'noopener' | 'prev' | 'search' | 'tag';
6
6
  export interface PromoCardCommonProps {
7
7
  /** Optional prop to specify classNames onto the PromoCard */
@@ -30,12 +30,15 @@ export interface PromoCardCommonProps {
30
30
  isDisabled?: boolean;
31
31
  /** Specify an onClick event handler */
32
32
  onClick?: () => void;
33
+ /** Specify an onKeyDown event handler */
34
+ onKeyDown?: (event: React.KeyboardEvent<HTMLInputElement>) => void;
33
35
  /** Optional prop to specify the ID used for testing */
34
36
  testId?: string;
35
37
  /** Required prop to specify the title text of the PromoCard */
36
38
  title: string;
37
39
  /** Set to false to use body font style for the title */
38
40
  useDisplayFont?: boolean;
41
+ ref?: ReferenceType;
39
42
  }
40
43
  export interface PromoCardLinkProps extends PromoCardCommonProps, Omit<CardProps, 'children'> {
41
44
  /**
@@ -47,6 +50,12 @@ export interface PromoCardLinkProps extends PromoCardCommonProps, Omit<CardProps
47
50
  href?: string;
48
51
  /** Optionally specify the language of the linked URL */
49
52
  hrefLang?: string;
53
+ /** Optional property that can be pass a ref for the anchor. */
54
+ anchorRef?: React.Ref<HTMLAnchorElement>;
55
+ /**
56
+ * Optional prop to specify the ID of the anchor element which can be useful when using a ref.
57
+ */
58
+ anchorId?: string;
50
59
  /**
51
60
  * Relationship between the PromoCard href URL and the current page. See
52
61
  * [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel).
@@ -59,7 +68,7 @@ export interface PromoCardLinkProps extends PromoCardCommonProps, Omit<CardProps
59
68
  isChecked?: never;
60
69
  tabIndex?: never;
61
70
  type?: never;
62
- reference?: never;
71
+ ref?: ReferenceType;
63
72
  value?: never;
64
73
  }
65
74
  export interface PromoCardCheckedProps extends PromoCardCommonProps, Omit<CardProps, 'children'> {
@@ -70,7 +79,7 @@ export interface PromoCardCheckedProps extends PromoCardCommonProps, Omit<CardPr
70
79
  /** Optional prop to specify the tabIndex of the PromoCard */
71
80
  tabIndex?: number;
72
81
  /** Optional property to provide component Ref */
73
- reference?: ReferenceType;
82
+ ref?: ReferenceType;
74
83
  /** Optional prop to specify the input type of the PromoCard */
75
84
  type?: 'checkbox' | 'radio';
76
85
  /** Specify the value attribute of the PromoCard if Checkbox or Radio */
@@ -78,6 +87,8 @@ export interface PromoCardCheckedProps extends PromoCardCommonProps, Omit<CardPr
78
87
  /** Only applies to <a />s */
79
88
  download?: never;
80
89
  href?: never;
90
+ anchorRef?: never;
91
+ anchorId?: never;
81
92
  hrefLang?: never;
82
93
  rel?: never;
83
94
  target?: never;
@@ -1 +1 @@
1
- {"version":3,"file":"PromoCard.d.ts","sourceRoot":"","sources":["../../../src/promoCard/PromoCard.tsx"],"names":[],"mappings":"AAGA,OAAO,KAA6D,MAAM,OAAO,CAAC;AAIlF,OAAa,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAMjD,OAA2B,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAEnF,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;AACxD,MAAM,MAAM,YAAY,GACpB,EAAE,GACF,WAAW,GACX,QAAQ,GACR,UAAU,GACV,UAAU,GACV,MAAM,GACN,SAAS,GACT,MAAM,GACN,UAAU,GACV,YAAY,GACZ,UAAU,GACV,MAAM,GACN,QAAQ,GACR,KAAK,CAAC;AAEV,MAAM,WAAW,oBAAoB;IACnC,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,uDAAuD;IACvD,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ,sEAAsE;IACtE,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAEzC,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,gFAAgF;IAChF,aAAa,CAAC,EAAE,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAEhD,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,oDAAoD;IACpD,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,wDAAwD;IACxD,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;IAEd,0DAA0D;IAC1D,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAmB,SAAQ,oBAAoB,EAAE,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;IAC3F;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,8EAA8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,GAAG,CAAC,EAAE,YAAY,CAAC;IAEnB,iEAAiE;IACjE,MAAM,CAAC,EAAE,KAAK,CAAC,yBAAyB,CAAC;IAEzC,iDAAiD;IACjD,cAAc,CAAC,EAAE,KAAK,CAAC;IACvB,SAAS,CAAC,EAAE,KAAK,CAAC;IAClB,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,SAAS,CAAC,EAAE,KAAK,CAAC;IAClB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB,EAAE,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;IAC9F,6DAA6D;IAC7D,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB,uDAAuD;IACvD,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,iDAAiD;IACjD,SAAS,CAAC,EAAE,aAAa,CAAC;IAE1B,gEAAgE;IAChE,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC;IAE5B,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,GAAG,CAAC,EAAE,KAAK,CAAC;IACZ,MAAM,CAAC,EAAE,KAAK,CAAC;CAChB;AAED,MAAM,MAAM,cAAc,GAAG,kBAAkB,GAAG,qBAAqB,CAAC;AAExE,MAAM,MAAM,oBAAoB,GAAG,CACjC,KAAK,EAAE,kBAAkB,GAAG,qBAAqB,KAC9C,GAAG,CAAC,OAAO,CAAC;;AAuOjB,wBAAqC"}
1
+ {"version":3,"file":"PromoCard.d.ts","sourceRoot":"","sources":["../../../src/promoCard/PromoCard.tsx"],"names":[],"mappings":"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"}
@@ -47,21 +47,21 @@ export interface SelectProps {
47
47
  * if `function` you can define your own search function to implement custom search experience. This search function used while filtering the options array. The custom search function takes two parameters. First is the option the second is the keyword.
48
48
  */
49
49
  search?: SelectSearch;
50
+ options: SelectOptions[];
51
+ searchValue?: string;
52
+ searchPlaceholder?: string;
53
+ classNames?: any;
54
+ dropdownUp?: boolean;
55
+ buttonProps?: Object;
56
+ dropdownProps?: Object;
50
57
  onChange: (...args: any[])=>any;
51
58
  onFocus?: (...args: any[])=>any;
52
59
  onBlur?: (...args: any[])=>any;
53
- options: SelectOptions[];
54
60
  /**
55
61
  * To have full control of your search value and response use `onSearchChange` function combined with `searchValue` and custom filtering on the options array.
56
62
  * DO NOT USE TOGETHER WITH `search` PROPERTY
57
63
  */
58
64
  onSearchChange?: (...args: any[])=>any;
59
- searchValue?: string;
60
- searchPlaceholder?: string;
61
- classNames?: any;
62
- dropdownUp?: boolean;
63
- buttonProps?: Object;
64
- dropdownProps?: Object;
65
65
  }
66
66
 
67
67
  declare const Select: React.FC<SelectProps>;
@@ -1 +1 @@
1
- {"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../../src/select/Select.js"],"names":[],"mappings":"AA6EA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;gCAieC"}
1
+ {"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../../src/select/Select.js"],"names":[],"mappings":"AA+EA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;gCAkeC"}
@@ -1,8 +1,6 @@
1
- import { DebouncedFunc } from 'lodash';
2
- import { Component, ReactNode } from 'react';
3
- import { Size, SizeMedium, SizeLarge } from '../common';
1
+ import { ReactNode } from 'react';
2
+ import { SizeMedium, SizeLarge } from '../common';
4
3
  import { InlineAlertProps } from '../inlineAlert/InlineAlert';
5
- import TypeaheadOption from './typeaheadOption/TypeaheadOption';
6
4
  export type TypeaheadOption<T = string> = {
7
5
  label: string;
8
6
  note?: string;
@@ -43,55 +41,6 @@ export interface TypeaheadProps<T> {
43
41
  onSearch?: (query: string) => void;
44
42
  validateChip?: (chip: TypeaheadOption<T>) => boolean;
45
43
  }
46
- type TypeaheadState<T> = {
47
- selected: readonly TypeaheadOption<T>[];
48
- keyboardFocusedOptionIndex: number | null;
49
- errorState: boolean;
50
- query: string;
51
- optionsShown: boolean;
52
- isFocused: boolean;
53
- };
54
- export default class Typeahead<T> extends Component<TypeaheadProps<T>, TypeaheadState<T>> {
55
- props: TypeaheadProps<T> & Required<Pick<TypeaheadProps<T>, keyof typeof Typeahead.defaultProps>>;
56
- static defaultProps: {
57
- allowNew: false;
58
- autoFillOnBlur: true;
59
- autoFocus: false;
60
- chipSeparators: never[];
61
- clearable: true;
62
- initialValue: never[];
63
- inputAutoComplete: string;
64
- minQueryLength: number;
65
- multiple: false;
66
- searchDelay: number;
67
- showSuggestions: true;
68
- showNewEntry: true;
69
- size: Size.MEDIUM;
70
- validateChip: () => true;
71
- };
72
- constructor(props: TypeaheadProps<T>);
73
- handleSearchDebounced: DebouncedFunc<Typeahead<T>['handleSearch']>;
74
- UNSAFE_componentWillReceiveProps(nextProps: TypeaheadProps<T>): void;
75
- componentWillUnmount(): void;
76
- handleOnFocus: () => void;
77
- onOptionSelected: (event: React.MouseEvent, item: TypeaheadOption<T>) => void;
78
- handleOnChange: React.ChangeEventHandler<HTMLInputElement>;
79
- handleOnPaste: React.ClipboardEventHandler<HTMLInputElement>;
80
- handleOnKeyDown: React.KeyboardEventHandler<HTMLInputElement>;
81
- moveFocusedOption(offset: number): void;
82
- selectItem: (item: TypeaheadOption<T>) => void;
83
- handleSearch: (query: string) => void;
84
- handleDocumentClick: () => void;
85
- showMenu: () => void;
86
- hideMenu: () => void;
87
- updateSelectedValue: (selected: readonly TypeaheadOption<T>[]) => void;
88
- clear: (event: React.MouseEvent<HTMLButtonElement>) => void;
89
- removeChip: (option: TypeaheadOption<T>) => void;
90
- renderChip: (option: TypeaheadOption<T>, idx: number) => ReactNode;
91
- renderMenu: ({ footer, options, id, keyboardFocusedOptionIndex, query, allowNew, showNewEntry, dropdownOpen, }: Pick<TypeaheadProps<T>, "footer" | "id" | "options" | "allowNew" | "showNewEntry"> & Pick<TypeaheadState<T>, "query" | "keyboardFocusedOptionIndex"> & {
92
- dropdownOpen: boolean;
93
- }) => import("react").JSX.Element;
94
- render(): import("react").JSX.Element;
95
- }
96
- export {};
44
+ declare const _default: <T>(props: TypeaheadProps<T>) => React.ReactElement;
45
+ export default _default;
97
46
  //# sourceMappingURL=Typeahead.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Typeahead.d.ts","sourceRoot":"","sources":["../../../src/typeahead/Typeahead.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Typeahead.d.ts","sourceRoot":"","sources":["../../../src/typeahead/Typeahead.tsx"],"names":[],"mappings":"AASA,OAAO,EAAa,SAAS,EAAE,MAAM,OAAO,CAAC;AAG7C,OAAO,EAAmB,UAAU,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAOnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAS9D,MAAM,MAAM,eAAe,CAAC,CAAC,GAAG,MAAM,IAAI;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,CAAC,CAAC;IACV,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,KAAK,CAAC,EAAE;QACN,OAAO,EAAE,gBAAgB,CAAC,UAAU,CAAC,CAAC;QACtC,IAAI,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;KACjC,CAAC;IACF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,YAAY,CAAC,EAAE,SAAS,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,SAAS,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,IAAI,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAE9B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;IAClD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC;CACtD;yDA6cI,MAAM,YAAY;AAFvB,wBAEwB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@transferwise/components",
3
- "version": "46.31.0",
3
+ "version": "46.33.0",
4
4
  "description": "Neptune React components",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -0,0 +1,135 @@
1
+ .carousel-wrapper {
2
+ overflow: hidden;
3
+ }
4
+ .carousel {
5
+ display: flex;
6
+ align-items: center;
7
+ overflow-x: scroll;
8
+ overflow-y: hidden;
9
+ scroll-snap-type: x mandatory;
10
+ scroll-behavior: smooth;
11
+ gap: 16px;
12
+ gap: var(--size-16);
13
+ padding: 8px;
14
+ padding: var(--size-8);
15
+ margin: 8px;
16
+ margin: var(--size-8);
17
+ }
18
+ @media (max-width: 767px) {
19
+ .carousel {
20
+ gap: 8px;
21
+ gap: var(--size-8);
22
+ }
23
+ }
24
+ .carousel__header {
25
+ display: flex;
26
+ align-items: center;
27
+ overflow: hidden;
28
+ min-height: 32px;
29
+ min-height: var(--size-32);
30
+ padding-bottom: 16px;
31
+ padding-bottom: var(--size-16);
32
+ }
33
+ .carousel__card,
34
+ .carousel__card:hover,
35
+ .carousel__card:focus,
36
+ .carousel__card:focus-within {
37
+ -webkit-text-decoration: none;
38
+ text-decoration: none;
39
+ transition: none !important;
40
+ box-shadow: none !important;
41
+ }
42
+ .carousel__card {
43
+ display: block;
44
+ position: relative;
45
+ text-align: left;
46
+ border: none;
47
+ overflow: hidden;
48
+ background: rgba(134,167,189,0.10196);
49
+ background: var(--color-background-neutral);
50
+ border-radius: 32px;
51
+ border-radius: var(--size-32);
52
+ scroll-snap-align: center;
53
+ -webkit-scroll-snap-align: center;
54
+ transition: all 0.4s !important;
55
+ }
56
+ @media (min-width: 1200px) {
57
+ .carousel__card {
58
+ min-width: 280px;
59
+ width: 280px;
60
+ height: 280px;
61
+ }
62
+ }
63
+ @media (max-width: 1199px) {
64
+ .carousel__card {
65
+ min-width: 242px;
66
+ width: 242px;
67
+ height: 242px;
68
+ }
69
+ }
70
+ @media (max-width: 767px) {
71
+ .carousel__card {
72
+ min-width: 336px;
73
+ width: 336px;
74
+ height: 336px;
75
+ scroll-snap-stop: always;
76
+ }
77
+ }
78
+ .carousel__card:focus,
79
+ .carousel__card:has(:focus-visible) {
80
+ outline: var(--ring-outline-color) solid var(--ring-outline-width) !important;
81
+ outline-offset: var(--ring-outline-offset) !important;
82
+ }
83
+ .carousel__card:hover {
84
+ background-color: var(--color-background-neutral-hover);
85
+ }
86
+ .carousel__card:focus {
87
+ background-color: var(--color-background-neutral-hover);
88
+ }
89
+ .carousel__card-content {
90
+ height: 100%;
91
+ font-weight: normal;
92
+ padding: 24px;
93
+ padding: var(--size-24);
94
+ }
95
+ .carousel__scroll-button {
96
+ width: 32px;
97
+ width: var(--size-32);
98
+ height: 32px;
99
+ height: var(--size-32);
100
+ align-items: center;
101
+ justify-content: center;
102
+ }
103
+ .carousel__indicators {
104
+ display: flex;
105
+ justify-content: center;
106
+ padding-top: 8px;
107
+ padding-top: var(--size-8);
108
+ gap: 8px;
109
+ gap: var(--size-8);
110
+ }
111
+ .carousel__indicator {
112
+ width: 12px;
113
+ width: var(--size-12);
114
+ height: 12px;
115
+ height: var(--size-12);
116
+ border-radius: 8px;
117
+ border-radius: var(--size-8);
118
+ background: #c9cbce;
119
+ background: var(--color-interactive-secondary);
120
+ border: none;
121
+ -webkit-appearance: none;
122
+ -moz-appearance: none;
123
+ appearance: none;
124
+ transition: all 0.1s;
125
+ }
126
+ .carousel__indicator:hover {
127
+ width: 16px;
128
+ width: var(--size-16);
129
+ }
130
+ .carousel__indicator--selected,
131
+ .carousel__indicator--selected:hover {
132
+ background: var(--color-interactive-primary);
133
+ width: 24px;
134
+ width: var(--size-24);
135
+ }
@@ -0,0 +1,133 @@
1
+ .carousel-wrapper {
2
+ overflow: hidden;
3
+ }
4
+
5
+ .carousel {
6
+ display: flex;
7
+ align-items: center;
8
+ overflow-x: scroll;
9
+ overflow-y: hidden;
10
+ scroll-snap-type: x mandatory;
11
+ scroll-behavior: smooth;
12
+ gap: var(--size-16);
13
+ padding: var(--size-8);
14
+ margin: var(--size-8);
15
+ }
16
+
17
+ @media (--screen-sm-max) {
18
+ .carousel {
19
+ gap: var(--size-8);
20
+ }
21
+ }
22
+
23
+
24
+ .carousel__header {
25
+ display: flex;
26
+ align-items: center;
27
+ overflow: hidden;
28
+ min-height: var(--size-32);
29
+ padding-bottom: var(--size-16)
30
+ }
31
+
32
+ // The specificity inside PromoCard is too high for transition / box-shaodw, so we need to use !important below
33
+ .carousel__card,
34
+ .carousel__card:hover,
35
+ .carousel__card:focus,
36
+ .carousel__card:focus-within {
37
+ text-decoration: none;
38
+ transition: none !important;
39
+ box-shadow: none !important;
40
+ }
41
+
42
+ .carousel__card {
43
+ display: block;
44
+ position: relative;
45
+ text-align: left;
46
+ border: none;
47
+ overflow: hidden;
48
+ background: var(--color-background-neutral);
49
+ border-radius: var(--size-32);
50
+ scroll-snap-align: center;
51
+ -webkit-scroll-snap-align: center;
52
+ transition: all 0.4s !important;
53
+ }
54
+
55
+ @media (--screen-xl) {
56
+ .carousel__card {
57
+ min-width: 280px;
58
+ width: 280px;
59
+ height: 280px;
60
+ }
61
+ }
62
+
63
+
64
+ @media (--screen-lg-max) {
65
+ .carousel__card {
66
+ min-width: 242px;
67
+ width: 242px;
68
+ height: 242px;
69
+ }
70
+ }
71
+
72
+
73
+ @media (--screen-sm-max) {
74
+ .carousel__card {
75
+ min-width: 336px;
76
+ width: 336px;
77
+ height: 336px;
78
+ scroll-snap-stop: always;
79
+ }
80
+ }
81
+
82
+ .carousel__card:focus, .carousel__card:has(:focus-visible) {
83
+ outline: var(--ring-outline-color) solid var(--ring-outline-width) !important;
84
+ outline-offset: var(--ring-outline-offset) !important;
85
+ }
86
+
87
+ .carousel__card:hover {
88
+ background-color: var(--color-background-neutral-hover);
89
+ }
90
+
91
+ .carousel__card:focus {
92
+ background-color: var(--color-background-neutral-hover);
93
+ }
94
+
95
+ .carousel__card-content {
96
+ height: 100%;
97
+ font-weight: normal;
98
+ padding: var(--size-24);
99
+ }
100
+
101
+ .carousel__scroll-button {
102
+ width: var(--size-32);
103
+ height: var(--size-32);
104
+ align-items: center;
105
+ justify-content: center;
106
+ }
107
+
108
+ .carousel__indicators {
109
+ display: flex;
110
+ justify-content: center;
111
+ padding-top: var(--size-8);
112
+ gap: var(--size-8);
113
+ }
114
+
115
+ .carousel__indicator {
116
+ width: var(--size-12);
117
+ height: var(--size-12);
118
+ border-radius: var(--size-8);
119
+ background: var(--color-interactive-secondary);
120
+ border: none;
121
+ appearance: none;
122
+ transition: all 0.1s;
123
+ }
124
+
125
+ .carousel__indicator:hover {
126
+ width: var(--size-16)
127
+ }
128
+
129
+ .carousel__indicator--selected,
130
+ .carousel__indicator--selected:hover {
131
+ background: var(--color-interactive-primary);
132
+ width: var(--size-24);
133
+ }
@@ -0,0 +1,221 @@
1
+ import { fireEvent, render, screen } from '@testing-library/react';
2
+ import { userEvent } from '../test-utils';
3
+
4
+ import Display from '../display';
5
+ import Title from '../title';
6
+
7
+ import Carousel, { type CarouselCard } from './Carousel';
8
+
9
+ jest.mock('@wise/components-theming', () => ({
10
+ ...jest.requireActual<Record<string, unknown>>('@wise/components-theming'),
11
+ useTheme: jest.fn().mockReturnValue({ theme: 'personal' }),
12
+ }));
13
+
14
+ const yourInvoiceOnClick = jest.fn();
15
+
16
+ const carouselCards: CarouselCard[] = [
17
+ {
18
+ id: 'YOUR_INVOICE',
19
+ type: 'anchor',
20
+ href: 'https://wise.com',
21
+ onClick: yourInvoiceOnClick,
22
+ content: <div>Add a link in accounting software like Xero or QuickBooks.</div>,
23
+ },
24
+ {
25
+ id: 'YOUR_WEBSITE',
26
+ type: 'button',
27
+ onClick: () => {},
28
+ content: <Title type="title-screen">Wise.</Title>,
29
+ },
30
+ {
31
+ id: 'SHOP_OR_STALL',
32
+ type: 'anchor',
33
+ href: 'https://wise.com',
34
+ onClick: () => {},
35
+ content: <Display type="display-small">Get Quick Pay</Display>,
36
+ },
37
+ ];
38
+
39
+ const onClick = jest.fn();
40
+
41
+ const renderCarousel = () => {
42
+ render(<Carousel header="Cool stuff" cards={carouselCards} onClick={onClick} />);
43
+ };
44
+
45
+ describe('Carousel', () => {
46
+ const focusSpy = jest.fn();
47
+ const scrollBy = jest.fn();
48
+
49
+ beforeEach(() => {
50
+ // eslint-disable-next-line functional/immutable-data
51
+ window.HTMLElement.prototype.scrollIntoView = focusSpy;
52
+ // eslint-disable-next-line functional/immutable-data
53
+ window.HTMLElement.prototype.scrollBy = scrollBy;
54
+ });
55
+
56
+ afterEach(() => {
57
+ focusSpy.mockClear();
58
+ });
59
+
60
+ it('shows expected content on page', async () => {
61
+ renderCarousel();
62
+
63
+ expect(
64
+ screen.getByText('Add a link in accounting software like Xero or QuickBooks.'),
65
+ ).toBeInTheDocument();
66
+
67
+ expect(screen.getByText('Wise.')).toBeInTheDocument();
68
+
69
+ expect(screen.getByText('Get Quick Pay')).toBeInTheDocument();
70
+ });
71
+
72
+ it('allows user to scroll carousel to the right when at start', () => {
73
+ mockPositions(948, 903);
74
+
75
+ renderCarousel();
76
+
77
+ const scrollLeftButton = screen.getByTestId('scroll-carousel-left');
78
+ const scrollRightButton = screen.getByTestId('scroll-carousel-right');
79
+
80
+ expect(scrollLeftButton).toBeDisabled();
81
+ expect(scrollRightButton).toBeEnabled();
82
+
83
+ userEvent.click(scrollRightButton);
84
+
85
+ expect(scrollBy).toHaveBeenCalledWith({ left: 300, behavior: 'smooth' });
86
+ });
87
+
88
+ it('allows user to scroll carousel to the left or right when in middle', () => {
89
+ mockPositions(948, 903);
90
+
91
+ renderCarousel();
92
+
93
+ const carousel = screen.getByRole('list');
94
+ fireEvent.scroll(carousel, { target: { scrollLeft: 10 } });
95
+
96
+ const scrollLeftButton = screen.getByTestId('scroll-carousel-left');
97
+ const scrollRightButton = screen.getByTestId('scroll-carousel-right');
98
+
99
+ expect(scrollLeftButton).toBeEnabled();
100
+ expect(scrollRightButton).toBeEnabled();
101
+
102
+ userEvent.click(scrollLeftButton);
103
+
104
+ expect(scrollBy).toHaveBeenCalledWith({ left: -300, behavior: 'smooth' });
105
+
106
+ userEvent.click(scrollRightButton);
107
+
108
+ expect(scrollBy).toHaveBeenCalledWith({ left: 300, behavior: 'smooth' });
109
+ });
110
+
111
+ it('allows user to scroll carousel to the left when at end', () => {
112
+ mockPositions(948, 903);
113
+
114
+ renderCarousel();
115
+
116
+ const carousel = screen.getByRole('list');
117
+ fireEvent.scroll(carousel, { target: { scrollLeft: 50 } });
118
+
119
+ const scrollLeftButton = screen.getByTestId('scroll-carousel-left');
120
+ const scrollRightButton = screen.getByTestId('scroll-carousel-right');
121
+
122
+ expect(scrollLeftButton).toBeEnabled();
123
+ expect(scrollRightButton).toBeDisabled();
124
+
125
+ userEvent.click(scrollLeftButton);
126
+
127
+ expect(scrollBy).toHaveBeenCalledWith({ left: -300, behavior: 'smooth' });
128
+ });
129
+
130
+ it('allows user to go through carousel by indicator', async () => {
131
+ mockPositions(948, 903);
132
+
133
+ renderCarousel();
134
+
135
+ const yourInvoiceIndicator = screen.getByTestId('YOUR_INVOICE-indicator');
136
+ const yourWebsiteIndicator = screen.getByTestId('YOUR_WEBSITE-indicator');
137
+ const shopOrStallIndicator = screen.getByTestId('SHOP_OR_STALL-indicator');
138
+ const firstCard = getFirstCard();
139
+ const secondCard = getSecondCard();
140
+ const thirdCard = getThirdCard();
141
+
142
+ expect(focusSpy).toHaveBeenCalledTimes(0);
143
+ expect(firstCard).toHaveClass('carousel__card--focused');
144
+
145
+ userEvent.click(yourWebsiteIndicator);
146
+
147
+ expect(focusSpy).toHaveBeenCalledTimes(1);
148
+ expect(secondCard).toHaveClass('carousel__card--focused');
149
+
150
+ userEvent.click(shopOrStallIndicator);
151
+
152
+ expect(focusSpy).toHaveBeenCalledTimes(2);
153
+ expect(thirdCard).toHaveClass('carousel__card--focused');
154
+
155
+ userEvent.click(yourInvoiceIndicator);
156
+
157
+ expect(focusSpy).toHaveBeenCalledTimes(3);
158
+ expect(firstCard).toHaveClass('carousel__card--focused');
159
+ });
160
+
161
+ it('is focused on the first element and lets user navigate through them', () => {
162
+ renderCarousel();
163
+
164
+ const firstCard = getFirstCard();
165
+ const secondCard = getSecondCard();
166
+ const thirdCard = getThirdCard();
167
+
168
+ expect(firstCard).toBeInTheDocument();
169
+
170
+ firstCard.focus();
171
+ expect(firstCard).toHaveFocus();
172
+
173
+ userEvent.keyboard('{arrowright}');
174
+
175
+ expect(secondCard).toHaveFocus();
176
+
177
+ userEvent.keyboard('{arrowright}');
178
+
179
+ expect(thirdCard).toHaveFocus();
180
+
181
+ userEvent.keyboard('{arrowleft}');
182
+
183
+ expect(secondCard).toHaveFocus();
184
+
185
+ userEvent.keyboard('{arrowleft}');
186
+
187
+ expect(firstCard).toHaveFocus();
188
+ });
189
+
190
+ it('calls onClick when a card is clicked', () => {
191
+ renderCarousel();
192
+
193
+ userEvent.click(getFirstCard());
194
+
195
+ expect(onClick).toHaveBeenCalledTimes(1);
196
+ expect(yourInvoiceOnClick).toHaveBeenCalledTimes(1);
197
+ });
198
+ });
199
+
200
+ const mockPositions = (scrollWidth: number, offsetWidth: number) => {
201
+ // eslint-disable-next-line functional/immutable-data
202
+ Object.defineProperty(HTMLElement.prototype, 'scrollWidth', {
203
+ configurable: true,
204
+ value: scrollWidth,
205
+ });
206
+
207
+ // eslint-disable-next-line functional/immutable-data
208
+ Object.defineProperty(HTMLElement.prototype, 'offsetWidth', {
209
+ configurable: true,
210
+ value: offsetWidth,
211
+ });
212
+ };
213
+
214
+ const getFirstCard = () =>
215
+ screen.getByRole('link', {
216
+ name: /Add a link in accounting software like Xero or QuickBooks\./,
217
+ });
218
+
219
+ const getSecondCard = () => screen.getByRole('button', { name: /Wise\./ });
220
+
221
+ const getThirdCard = () => screen.getByRole('link', { name: /Get Quick Pay/ });