@transferwise/components 0.0.0-experimental-70919ee → 0.0.0-experimental-58e9ef8

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 (43) hide show
  1. package/build/common/preventScroll/PreventScroll.js +8 -1
  2. package/build/common/preventScroll/PreventScroll.js.map +1 -1
  3. package/build/common/preventScroll/PreventScroll.mjs +8 -1
  4. package/build/common/preventScroll/PreventScroll.mjs.map +1 -1
  5. package/build/index.js +4 -4
  6. package/build/inputs/SelectInput.mjs +1 -1
  7. package/build/inputs/_BottomSheet.js +29 -1
  8. package/build/inputs/_BottomSheet.js.map +1 -1
  9. package/build/inputs/_BottomSheet.mjs +30 -2
  10. package/build/inputs/_BottomSheet.mjs.map +1 -1
  11. package/build/listItem/Prompt/ListItemPrompt.js +3 -0
  12. package/build/listItem/Prompt/ListItemPrompt.js.map +1 -1
  13. package/build/listItem/Prompt/ListItemPrompt.mjs +1 -1
  14. package/build/main.css +13 -9
  15. package/build/popover/Popover.mjs +1 -1
  16. package/build/promoCard/PromoCardContext.mjs +1 -1
  17. package/build/prompt/ActionPrompt/ActionPrompt.js +3 -0
  18. package/build/prompt/ActionPrompt/ActionPrompt.js.map +1 -1
  19. package/build/prompt/ActionPrompt/ActionPrompt.mjs +1 -1
  20. package/build/slidingPanel/SlidingPanel.js +23 -20
  21. package/build/slidingPanel/SlidingPanel.js.map +1 -1
  22. package/build/slidingPanel/SlidingPanel.mjs +24 -21
  23. package/build/slidingPanel/SlidingPanel.mjs.map +1 -1
  24. package/build/styles/dimmer/Dimmer.css +1 -0
  25. package/build/styles/inputs/SelectInput.css +12 -9
  26. package/build/styles/main.css +13 -9
  27. package/build/types/common/preventScroll/PreventScroll.d.ts +1 -1
  28. package/build/types/common/preventScroll/PreventScroll.d.ts.map +1 -1
  29. package/build/types/inputs/_BottomSheet.d.ts.map +1 -1
  30. package/build/types/slidingPanel/SlidingPanel.d.ts.map +1 -1
  31. package/package.json +17 -17
  32. package/src/common/bottomSheet/BottomSheet.test.story.tsx +94 -0
  33. package/src/common/bottomSheet/__snapshots__/BottomSheet.test.tsx.snap +6 -0
  34. package/src/common/preventScroll/PreventScroll.tsx +11 -1
  35. package/src/dimmer/Dimmer.css +1 -0
  36. package/src/dimmer/Dimmer.less +1 -0
  37. package/src/inputs/SelectInput.css +12 -9
  38. package/src/inputs/SelectInput.test.story.tsx +83 -0
  39. package/src/inputs/_BottomSheet.less +12 -6
  40. package/src/inputs/_BottomSheet.tsx +19 -5
  41. package/src/main.css +13 -9
  42. package/src/moneyInput/MoneyInput.test.story.tsx +101 -0
  43. package/src/slidingPanel/SlidingPanel.tsx +29 -24
@@ -1 +1 @@
1
- {"version":3,"file":"SlidingPanel.mjs","sources":["../../src/slidingPanel/SlidingPanel.tsx"],"sourcesContent":["import { clsx } from 'clsx';\nimport { forwardRef, useImperativeHandle, useRef } from 'react';\nimport { CSSTransition } from 'react-transition-group';\n\nimport { Position } from '../common';\n\nexport const EXIT_ANIMATION = 350;\n\nexport interface SlidingPanelProps\n extends Pick<React.ComponentPropsWithRef<'div'>, 'ref' | 'className' | 'children'> {\n position?: `${Position.TOP | Position.RIGHT | Position.BOTTOM | Position.LEFT}`;\n open: boolean;\n showSlidingPanelBorder?: boolean;\n slidingPanelPositionFixed?: boolean;\n testId?: string;\n}\n\nconst SlidingPanel = forwardRef(\n (\n {\n position = 'left',\n open,\n showSlidingPanelBorder,\n slidingPanelPositionFixed,\n className,\n children,\n testId,\n ...rest\n }: Omit<SlidingPanelProps, 'ref'>,\n reference: React.ForwardedRef<HTMLDivElement | null>,\n ) => {\n const localReference = useRef<HTMLDivElement>(null as never);\n useImperativeHandle(reference, () => localReference.current, []);\n\n return (\n <CSSTransition\n {...rest}\n key={`sliding-panel--open-${position}`}\n nodeRef={localReference}\n in={open}\n // Wait for animation to finish before unmount.\n timeout={{ enter: 0, exit: EXIT_ANIMATION }}\n classNames=\"sliding-panel\"\n appear\n unmountOnExit\n >\n <div\n ref={localReference}\n data-testid={testId}\n className={clsx(\n 'sliding-panel',\n `sliding-panel--open-${position}`,\n showSlidingPanelBorder && `sliding-panel--border-${position}`,\n slidingPanelPositionFixed && 'sliding-panel--fixed',\n className,\n )}\n >\n {children}\n </div>\n </CSSTransition>\n );\n },\n);\n\nexport default SlidingPanel;\n"],"names":["EXIT_ANIMATION","SlidingPanel","forwardRef","position","open","showSlidingPanelBorder","slidingPanelPositionFixed","className","children","testId","rest","reference","localReference","useRef","useImperativeHandle","current","_createElement","CSSTransition","key","nodeRef","in","timeout","enter","exit","classNames","appear","unmountOnExit","_jsx","ref","clsx"],"mappings":";;;;;AAMO,MAAMA,cAAc,GAAG;AAW9B,MAAMC,YAAY,gBAAGC,UAAU,CAC7B,CACE;AACEC,EAAAA,QAAQ,GAAG,MAAM;EACjBC,IAAI;EACJC,sBAAsB;EACtBC,yBAAyB;EACzBC,SAAS;EACTC,QAAQ;EACRC,MAAM;EACN,GAAGC;AAAI,CACwB,EACjCC,SAAoD,KAClD;AACF,EAAA,MAAMC,cAAc,GAAGC,MAAM,CAAiB,IAAa,CAAC;EAC5DC,mBAAmB,CAACH,SAAS,EAAE,MAAMC,cAAc,CAACG,OAAO,EAAE,EAAE,CAAC;EAEhE,oBACEC,aAAA,CAACC,aAAa,EAAA;AAAA,IAAA,GACRP,IAAI;IACRQ,GAAG,EAAE,CAAA,oBAAA,EAAuBf,QAAQ,CAAA,CAAG;AACvCgB,IAAAA,OAAO,EAAEP,cAAe;AACxBQ,IAAAA,EAAE,EAAEhB;AACJ;AAAA;AACAiB,IAAAA,OAAO,EAAE;AAAEC,MAAAA,KAAK,EAAE,CAAC;AAAEC,MAAAA,IAAI,EAAEvB;KAAiB;AAC5CwB,IAAAA,UAAU,EAAC,eAAe;IAC1BC,MAAM,EAAA,IAAA;IACNC,aAAa,EAAA;AAAA,GAAA,eAEbC,GAAA,CAAA,KAAA,EAAA;AACEC,IAAAA,GAAG,EAAEhB,cAAe;AACpB,IAAA,aAAA,EAAaH,MAAO;IACpBF,SAAS,EAAEsB,IAAI,CACb,eAAe,EACf,CAAA,oBAAA,EAAuB1B,QAAQ,EAAE,EACjCE,sBAAsB,IAAI,CAAA,sBAAA,EAAyBF,QAAQ,EAAE,EAC7DG,yBAAyB,IAAI,sBAAsB,EACnDC,SAAS,CACT;AAAAC,IAAAA,QAAA,EAEDA;AAAQ,GACN,CACQ,CAAC;AAEpB,CAAC;;;;"}
1
+ {"version":3,"file":"SlidingPanel.mjs","sources":["../../src/slidingPanel/SlidingPanel.tsx"],"sourcesContent":["import { clsx } from 'clsx';\nimport { forwardRef, useImperativeHandle, useRef } from 'react';\nimport { CSSTransition } from 'react-transition-group';\n\nimport { Position } from '../common';\nimport { PreventScroll } from '../common/preventScroll/PreventScroll';\n\nexport const EXIT_ANIMATION = 350;\n\nexport interface SlidingPanelProps\n extends Pick<React.ComponentPropsWithRef<'div'>, 'ref' | 'className' | 'children'> {\n position?: `${Position.TOP | Position.RIGHT | Position.BOTTOM | Position.LEFT}`;\n open: boolean;\n showSlidingPanelBorder?: boolean;\n slidingPanelPositionFixed?: boolean;\n testId?: string;\n}\n\nconst SlidingPanel = forwardRef(\n (\n {\n position = 'left',\n open,\n showSlidingPanelBorder,\n slidingPanelPositionFixed,\n className,\n children,\n testId,\n ...rest\n }: Omit<SlidingPanelProps, 'ref'>,\n reference: React.ForwardedRef<HTMLDivElement | null>,\n ) => {\n const localReference = useRef<HTMLDivElement>(null as never);\n useImperativeHandle(reference, () => localReference.current, []);\n\n return (\n <>\n {open ? <PreventScroll /> : null}\n\n <CSSTransition\n {...rest}\n key={`sliding-panel--open-${position}`}\n nodeRef={localReference}\n in={open}\n // Wait for animation to finish before unmount.\n timeout={{ enter: 0, exit: EXIT_ANIMATION }}\n classNames=\"sliding-panel\"\n appear\n unmountOnExit\n >\n <div\n ref={localReference}\n data-testid={testId}\n className={clsx(\n 'sliding-panel',\n `sliding-panel--open-${position}`,\n showSlidingPanelBorder && `sliding-panel--border-${position}`,\n slidingPanelPositionFixed && 'sliding-panel--fixed',\n className,\n )}\n >\n {children}\n </div>\n </CSSTransition>\n </>\n );\n },\n);\n\nexport default SlidingPanel;\n"],"names":["EXIT_ANIMATION","SlidingPanel","forwardRef","position","open","showSlidingPanelBorder","slidingPanelPositionFixed","className","children","testId","rest","reference","localReference","useRef","useImperativeHandle","current","_jsxs","_Fragment","_jsx","PreventScroll","_createElement","CSSTransition","key","nodeRef","in","timeout","enter","exit","classNames","appear","unmountOnExit","ref","clsx"],"mappings":";;;;;;AAOO,MAAMA,cAAc,GAAG;AAW9B,MAAMC,YAAY,gBAAGC,UAAU,CAC7B,CACE;AACEC,EAAAA,QAAQ,GAAG,MAAM;EACjBC,IAAI;EACJC,sBAAsB;EACtBC,yBAAyB;EACzBC,SAAS;EACTC,QAAQ;EACRC,MAAM;EACN,GAAGC;AAAI,CACwB,EACjCC,SAAoD,KAClD;AACF,EAAA,MAAMC,cAAc,GAAGC,MAAM,CAAiB,IAAa,CAAC;EAC5DC,mBAAmB,CAACH,SAAS,EAAE,MAAMC,cAAc,CAACG,OAAO,EAAE,EAAE,CAAC;EAEhE,oBACEC,IAAA,CAAAC,QAAA,EAAA;AAAAT,IAAAA,QAAA,EAAA,CACGJ,IAAI,gBAAGc,GAAA,CAACC,aAAa,EAAA,EAAA,CAAG,GAAG,IAAI,eAEhCC,aAAA,CAACC,aAAa,EAAA;AAAA,MAAA,GACRX,IAAI;MACRY,GAAG,EAAE,CAAA,oBAAA,EAAuBnB,QAAQ,CAAA,CAAG;AACvCoB,MAAAA,OAAO,EAAEX,cAAe;AACxBY,MAAAA,EAAE,EAAEpB;AACJ;AAAA;AACAqB,MAAAA,OAAO,EAAE;AAAEC,QAAAA,KAAK,EAAE,CAAC;AAAEC,QAAAA,IAAI,EAAE3B;OAAiB;AAC5C4B,MAAAA,UAAU,EAAC,eAAe;MAC1BC,MAAM,EAAA,IAAA;MACNC,aAAa,EAAA;AAAA,KAAA,eAEbZ,GAAA,CAAA,KAAA,EAAA;AACEa,MAAAA,GAAG,EAAEnB,cAAe;AACpB,MAAA,aAAA,EAAaH,MAAO;MACpBF,SAAS,EAAEyB,IAAI,CACb,eAAe,EACf,CAAA,oBAAA,EAAuB7B,QAAQ,EAAE,EACjCE,sBAAsB,IAAI,CAAA,sBAAA,EAAyBF,QAAQ,EAAE,EAC7DG,yBAAyB,IAAI,sBAAsB,EACnDC,SAAS,CACT;AAAAC,MAAAA,QAAA,EAEDA;AAAQ,KACN,CACQ,CACjB;AAAA,GAAA,CAAG;AAEP,CAAC;;;;"}
@@ -1,5 +1,6 @@
1
1
  .no-scroll {
2
2
  overflow: hidden;
3
+ scroll-behavior: unset;
3
4
  }
4
5
  .dimmer {
5
6
  position: fixed;
@@ -11,35 +11,38 @@
11
11
  transition-property: opacity;
12
12
  transition-timing-function: ease-out;
13
13
  transition-duration: 300ms;
14
+ height: 100vh;
15
+ min-height: -webkit-fill-available;
14
16
  }
15
17
  .np-bottom-sheet-v2-backdrop--closed {
16
18
  opacity: 0;
17
19
  }
18
20
  .np-bottom-sheet-v2 {
19
21
  position: fixed;
20
- inset: 0px;
22
+ inset: 0;
21
23
  bottom: env(keyboard-inset-height, 0px);
22
- margin-left: 8px;
23
- margin-left: var(--size-8);
24
- margin-right: 8px;
25
- margin-right: var(--size-8);
26
- margin-top: 64px;
27
- margin-top: var(--size-64);
24
+ padding-top: 64px;
25
+ padding-top: var(--size-64);
26
+ padding-bottom: min(env(safe-area-inset-bottom, 16px));
27
+ padding-bottom: min(env(safe-area-inset-bottom, var(--size-16)));
28
28
  display: flex;
29
29
  flex-direction: column;
30
30
  justify-content: flex-end;
31
+ height: 100%;
32
+ min-height: -webkit-fill-available;
31
33
  }
32
34
  .np-bottom-sheet-v2-content {
33
35
  display: flex;
34
36
  flex-direction: column;
35
37
  overflow: auto;
36
38
  border-top-left-radius: 32px;
37
- /* TODO: Tokenize */
39
+ border-top-left-radius: var(--size-32);
38
40
  border-top-right-radius: 32px;
39
- /* TODO: Tokenize */
41
+ border-top-right-radius: var(--size-32);
40
42
  background-color: #ffffff;
41
43
  background-color: var(--color-background-elevated);
42
44
  box-shadow: 0 0 40px rgba(69, 71, 69, 0.2);
45
+ will-change: transform;
43
46
  }
44
47
  .np-bottom-sheet-v2-content:focus {
45
48
  outline: none;
@@ -2574,6 +2574,7 @@ button.np-option {
2574
2574
  }
2575
2575
  .no-scroll {
2576
2576
  overflow: hidden;
2577
+ scroll-behavior: unset;
2577
2578
  }
2578
2579
  .dimmer {
2579
2580
  position: fixed;
@@ -3839,35 +3840,38 @@ html:not([dir="rtl"]) .np-flow-navigation--sm .np-flow-navigation__stepper {
3839
3840
  transition-property: opacity;
3840
3841
  transition-timing-function: ease-out;
3841
3842
  transition-duration: 300ms;
3843
+ height: 100vh;
3844
+ min-height: -webkit-fill-available;
3842
3845
  }
3843
3846
  .np-bottom-sheet-v2-backdrop--closed {
3844
3847
  opacity: 0;
3845
3848
  }
3846
3849
  .np-bottom-sheet-v2 {
3847
3850
  position: fixed;
3848
- inset: 0px;
3851
+ inset: 0;
3849
3852
  bottom: env(keyboard-inset-height, 0px);
3850
- margin-left: 8px;
3851
- margin-left: var(--size-8);
3852
- margin-right: 8px;
3853
- margin-right: var(--size-8);
3854
- margin-top: 64px;
3855
- margin-top: var(--size-64);
3853
+ padding-top: 64px;
3854
+ padding-top: var(--size-64);
3855
+ padding-bottom: min(env(safe-area-inset-bottom, 16px));
3856
+ padding-bottom: min(env(safe-area-inset-bottom, var(--size-16)));
3856
3857
  display: flex;
3857
3858
  flex-direction: column;
3858
3859
  justify-content: flex-end;
3860
+ height: 100%;
3861
+ min-height: -webkit-fill-available;
3859
3862
  }
3860
3863
  .np-bottom-sheet-v2-content {
3861
3864
  display: flex;
3862
3865
  flex-direction: column;
3863
3866
  overflow: auto;
3864
3867
  border-top-left-radius: 32px;
3865
- /* TODO: Tokenize */
3868
+ border-top-left-radius: var(--size-32);
3866
3869
  border-top-right-radius: 32px;
3867
- /* TODO: Tokenize */
3870
+ border-top-right-radius: var(--size-32);
3868
3871
  background-color: #ffffff;
3869
3872
  background-color: var(--color-background-elevated);
3870
3873
  box-shadow: 0 0 40px rgba(69, 71, 69, 0.2);
3874
+ will-change: transform;
3871
3875
  }
3872
3876
  .np-bottom-sheet-v2-content:focus {
3873
3877
  outline: none;
@@ -1,2 +1,2 @@
1
- export declare function PreventScroll(): null;
1
+ export declare function PreventScroll(): import("react").JSX.Element;
2
2
  //# sourceMappingURL=PreventScroll.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PreventScroll.d.ts","sourceRoot":"","sources":["../../../../src/common/preventScroll/PreventScroll.tsx"],"names":[],"mappings":"AAEA,wBAAgB,aAAa,SAG5B"}
1
+ {"version":3,"file":"PreventScroll.d.ts","sourceRoot":"","sources":["../../../../src/common/preventScroll/PreventScroll.tsx"],"names":[],"mappings":"AAEA,wBAAgB,aAAa,gCAa5B"}
@@ -1 +1 @@
1
- {"version":3,"file":"_BottomSheet.d.ts","sourceRoot":"","sources":["../../../src/inputs/_BottomSheet.tsx"],"names":[],"mappings":"AAmBA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE;QACrB,GAAG,EAAE,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAChC,mBAAmB,EAAE,CAAC,mBAAmB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK;YACvE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;SACxB,CAAC;KACH,KAAK,KAAK,CAAC,SAAS,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,KAAK,CAAC,gBAAgB,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC7D,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,aAAa,EACb,KAAK,EACL,eAAe,EACf,OAAc,EACd,QAAQ,EACR,OAAO,EACP,UAAU,GACX,EAAE,gBAAgB,+BA4FlB"}
1
+ {"version":3,"file":"_BottomSheet.d.ts","sourceRoot":"","sources":["../../../src/inputs/_BottomSheet.tsx"],"names":[],"mappings":"AAkBA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE;QACrB,GAAG,EAAE,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAChC,mBAAmB,EAAE,CAAC,mBAAmB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK;YACvE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;SACxB,CAAC;KACH,KAAK,KAAK,CAAC,SAAS,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,KAAK,CAAC,gBAAgB,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC7D,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAeD,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,aAAa,EACb,KAAK,EACL,eAAe,EACf,OAAc,EACd,QAAQ,EACR,OAAO,EACP,UAAU,GACX,EAAE,gBAAgB,+BA8FlB"}
@@ -1 +1 @@
1
- {"version":3,"file":"SlidingPanel.d.ts","sourceRoot":"","sources":["../../../src/slidingPanel/SlidingPanel.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,eAAO,MAAM,cAAc,MAAM,CAAC;AAElC,MAAM,WAAW,iBACf,SAAQ,IAAI,CAAC,KAAK,CAAC,qBAAqB,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,WAAW,GAAG,UAAU,CAAC;IAClF,QAAQ,CAAC,EAAE,GAAG,QAAQ,CAAC,GAAG,GAAG,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IAChF,IAAI,EAAE,OAAO,CAAC;IACd,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,QAAA,MAAM,YAAY,kIA6CjB,CAAC;AAEF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"SlidingPanel.d.ts","sourceRoot":"","sources":["../../../src/slidingPanel/SlidingPanel.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAGrC,eAAO,MAAM,cAAc,MAAM,CAAC;AAElC,MAAM,WAAW,iBACf,SAAQ,IAAI,CAAC,KAAK,CAAC,qBAAqB,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,WAAW,GAAG,UAAU,CAAC;IAClF,QAAQ,CAAC,EAAE,GAAG,QAAQ,CAAC,GAAG,GAAG,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IAChF,IAAI,EAAE,OAAO,CAAC;IACd,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,QAAA,MAAM,YAAY,kIAiDjB,CAAC;AAEF,eAAe,YAAY,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@transferwise/components",
3
- "version": "0.0.0-experimental-70919ee",
3
+ "version": "0.0.0-experimental-58e9ef8",
4
4
  "description": "Neptune React components",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -38,12 +38,12 @@
38
38
  "!**/*.tsbuildinfo"
39
39
  ],
40
40
  "devDependencies": {
41
- "@babel/core": "^7.29.0",
42
- "@babel/plugin-transform-runtime": "^7.29.0",
43
- "@babel/preset-env": "^7.29.0",
41
+ "@babel/core": "^7.28.5",
42
+ "@babel/plugin-transform-runtime": "^7.28.5",
43
+ "@babel/preset-env": "^7.28.5",
44
44
  "@babel/preset-react": "^7.28.5",
45
45
  "@babel/preset-typescript": "^7.28.5",
46
- "@formatjs/cli": "^6.12.2",
46
+ "@formatjs/cli": "^6.8.4",
47
47
  "@rollup/plugin-babel": "^6.1.0",
48
48
  "@rollup/plugin-json": "^6.1.0",
49
49
  "@rollup/plugin-node-resolve": "^16.0.3",
@@ -63,15 +63,15 @@
63
63
  "@types/babel__core": "^7.20.5",
64
64
  "@types/commonmark": "^0.27.10",
65
65
  "@types/jest": "^30.0.0",
66
- "@types/lodash": "4.17.23",
66
+ "@types/lodash": "4.17.21",
67
67
  "@types/lodash.clamp": "^4.0.9",
68
68
  "@types/lodash.debounce": "^4.0.9",
69
- "@types/react": "^18.3.28",
69
+ "@types/react": "^18.3.23",
70
70
  "@types/react-dom": "^18.3.7",
71
71
  "@types/react-transition-group": "4.4.12",
72
72
  "@wise/art": "^2.26.0",
73
73
  "@wise/eslint-config": "^13.3.0",
74
- "babel-plugin-formatjs": "^10.5.41",
74
+ "babel-plugin-formatjs": "^10.5.39",
75
75
  "eslint": "^9.39.2",
76
76
  "eslint-plugin-storybook": "^10.3.0-alpha.0",
77
77
  "gulp": "^5.0.1",
@@ -80,16 +80,16 @@
80
80
  "jest-fetch-mock": "^3.0.3",
81
81
  "jsdom-testing-mocks": "^1.16.0",
82
82
  "lodash.times": "^4.3.2",
83
- "react-intl": "^7.1.14",
84
- "rollup": "^4.57.1",
83
+ "react-intl": "^7.1.11",
84
+ "rollup": "^4.54.0",
85
85
  "rollup-preserve-directives": "^1.1.3",
86
86
  "storybook": "^10.3.0-alpha.0",
87
- "storybook-addon-tag-badges": "^3.0.6",
87
+ "storybook-addon-tag-badges": "^3.0.4",
88
88
  "storybook-addon-test-codegen": "^3.0.1",
89
89
  "@transferwise/less-config": "3.1.2",
90
90
  "@transferwise/neptune-css": "14.26.1",
91
- "@wise/wds-configs": "0.0.0",
92
- "@wise/components-theming": "1.10.1"
91
+ "@wise/components-theming": "1.10.1",
92
+ "@wise/wds-configs": "0.0.0"
93
93
  },
94
94
  "peerDependencies": {
95
95
  "@transferwise/icons": "^3 || ^4",
@@ -102,18 +102,18 @@
102
102
  "react-intl": "^5.10.0 || ^6 || ^7"
103
103
  },
104
104
  "dependencies": {
105
- "@babel/runtime": "^7.28.6",
105
+ "@babel/runtime": "^7.28.4",
106
106
  "@floating-ui/react": "^0.27.16",
107
107
  "@headlessui/react": "^2.2.9",
108
108
  "@popperjs/core": "^2.11.8",
109
109
  "@react-aria/focus": "^3.21.4",
110
110
  "@react-aria/overlays": "^3.31.1",
111
- "@transferwise/formatting": "^2.13.5",
111
+ "@transferwise/formatting": "^2.13.4",
112
112
  "@transferwise/neptune-validation": "^3.3.1",
113
113
  "clsx": "^2.1.1",
114
114
  "commonmark": "^0.31.2",
115
- "core-js": "^3.48.0",
116
- "framer-motion": "^12.33.0",
115
+ "core-js": "^3.47.0",
116
+ "framer-motion": "^12.23.26",
117
117
  "lodash.clamp": "^4.0.3",
118
118
  "lodash.debounce": "^4.0.8",
119
119
  "merge-props": "^6.0.0",
@@ -0,0 +1,94 @@
1
+ import { useState } from 'react';
2
+ import { Meta, StoryObj } from '@storybook/react-webpack5';
3
+ import { userEvent, within } from 'storybook/test';
4
+ import { lorem100, lorem500 } from '../../test-utils';
5
+ import { Typography } from '../propsValues/typography';
6
+ import Alert from '../../alert';
7
+ import Body from '../../body';
8
+ import Button from '../../button';
9
+ import Title from '../../title';
10
+ import BottomSheet from './BottomSheet';
11
+
12
+ const wait = async (duration = 500) =>
13
+ new Promise<void>((resolve) => {
14
+ setTimeout(resolve, duration);
15
+ });
16
+
17
+ export default {
18
+ component: BottomSheet,
19
+ title: 'Dialogs/BottomSheet/tests',
20
+ tags: ['!autodocs'],
21
+ args: {
22
+ open: false,
23
+ },
24
+ } satisfies Meta<typeof BottomSheet>;
25
+
26
+ type Story = StoryObj<typeof BottomSheet>;
27
+
28
+ /**
29
+ * This test ensures that when the SelectInput is used within a scrollable page,
30
+ * opening the dropdown does not cause any unwanted scrolling or layout shifts.
31
+ * Expected preview should start with green bar at the top, with yellow section
32
+ * not in the viewport.
33
+ *
34
+ * NB: This test is disabled in Chromatic as there's no obvious way to control <html/> element of a snapshot.
35
+ */
36
+ export const SmoothScrollReset: Story = {
37
+ args: {
38
+ children: (
39
+ <>
40
+ <Title type={Typography.TITLE_SECTION}>Observe the document</Title>
41
+ <Alert className="m-t-2" type="warning">
42
+ Once the <code>BottomSheet</code> opens, the document underneath should be static and
43
+ should not scroll.
44
+ </Alert>
45
+ <Body as="p">{lorem100}</Body>
46
+ <Body as="p">{lorem100}</Body>
47
+ </>
48
+ ),
49
+ },
50
+ decorators: [
51
+ (Story) => (
52
+ <>
53
+ <style>{'html { scroll-behavior: smooth; }'}</style>
54
+ <div style={{ maxWidth: 500 }}>
55
+ <Body>
56
+ <p>{lorem100}</p>
57
+ <p>{lorem100}</p>
58
+ </Body>
59
+ <Story />
60
+ <Body as="p" className="m-t-5 disabled">
61
+ {lorem500}
62
+ </Body>
63
+ </div>
64
+ </>
65
+ ),
66
+ ],
67
+ parameters: {
68
+ chromatic: {
69
+ disableSnapshot: true,
70
+ },
71
+ },
72
+ play: async ({ canvasElement }) => {
73
+ document.documentElement.scrollTop = 400;
74
+ await wait(500);
75
+ const canvas = within(canvasElement);
76
+ await userEvent.click(canvas.getByRole('button'));
77
+ },
78
+ render: ({ open, ...args }) => {
79
+ const [isOpen, setIsOpen] = useState(false);
80
+
81
+ return (
82
+ <div>
83
+ <Button onClick={() => setIsOpen(true)}>Open BottomSheet</Button>
84
+ <BottomSheet
85
+ {...args}
86
+ open={isOpen}
87
+ onClose={() => {
88
+ setIsOpen(false);
89
+ }}
90
+ />
91
+ </div>
92
+ );
93
+ },
94
+ };
@@ -20,6 +20,12 @@ exports[`BottomSheet renders content when open 1`] = `
20
20
  <div
21
21
  class="dimmer-content-positioner"
22
22
  >
23
+ <style>
24
+ html, body {
25
+ height: 100dvh;
26
+ overflow: hidden;
27
+ }
28
+ </style>
23
29
  <div
24
30
  class="sliding-panel sliding-panel--open-bottom np-bottom-sheet sliding-panel-appear sliding-panel-appear-active"
25
31
  >
@@ -2,5 +2,15 @@ import { usePreventScroll } from '@react-aria/overlays';
2
2
 
3
3
  export function PreventScroll() {
4
4
  usePreventScroll();
5
- return null;
5
+
6
+ // ios18
7
+ return (
8
+ <style>{`html, body {
9
+ height: 100dvh;
10
+ overflow: hidden;
11
+ }`}</style>
12
+ );
13
+
14
+ // ios26
15
+ return <style>{`html, body { height: 100dvh; overflow: hidden; }`}</style>;
6
16
  }
@@ -1,5 +1,6 @@
1
1
  .no-scroll {
2
2
  overflow: hidden;
3
+ scroll-behavior: unset;
3
4
  }
4
5
  .dimmer {
5
6
  position: fixed;
@@ -6,6 +6,7 @@
6
6
  // (see https://bugs.webkit.org/show_bug.cgi?id=153852 & https://bugs.webkit.org/show_bug.cgi?id=220908)
7
7
  .no-scroll {
8
8
  overflow: hidden;
9
+ scroll-behavior: unset;
9
10
  }
10
11
 
11
12
  .dimmer {
@@ -11,35 +11,38 @@
11
11
  transition-property: opacity;
12
12
  transition-timing-function: ease-out;
13
13
  transition-duration: 300ms;
14
+ height: 100vh;
15
+ min-height: -webkit-fill-available;
14
16
  }
15
17
  .np-bottom-sheet-v2-backdrop--closed {
16
18
  opacity: 0;
17
19
  }
18
20
  .np-bottom-sheet-v2 {
19
21
  position: fixed;
20
- inset: 0px;
22
+ inset: 0;
21
23
  bottom: env(keyboard-inset-height, 0px);
22
- margin-left: 8px;
23
- margin-left: var(--size-8);
24
- margin-right: 8px;
25
- margin-right: var(--size-8);
26
- margin-top: 64px;
27
- margin-top: var(--size-64);
24
+ padding-top: 64px;
25
+ padding-top: var(--size-64);
26
+ padding-bottom: min(env(safe-area-inset-bottom, 16px));
27
+ padding-bottom: min(env(safe-area-inset-bottom, var(--size-16)));
28
28
  display: flex;
29
29
  flex-direction: column;
30
30
  justify-content: flex-end;
31
+ height: 100%;
32
+ min-height: -webkit-fill-available;
31
33
  }
32
34
  .np-bottom-sheet-v2-content {
33
35
  display: flex;
34
36
  flex-direction: column;
35
37
  overflow: auto;
36
38
  border-top-left-radius: 32px;
37
- /* TODO: Tokenize */
39
+ border-top-left-radius: var(--size-32);
38
40
  border-top-right-radius: 32px;
39
- /* TODO: Tokenize */
41
+ border-top-right-radius: var(--size-32);
40
42
  background-color: #ffffff;
41
43
  background-color: var(--color-background-elevated);
42
44
  box-shadow: 0 0 40px rgba(69, 71, 69, 0.2);
45
+ will-change: transform;
43
46
  }
44
47
  .np-bottom-sheet-v2-content:focus {
45
48
  outline: none;
@@ -0,0 +1,83 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
+ import { fn, type Mock, userEvent, within } from 'storybook/test';
3
+ import { allModes } from '../../.storybook/modes';
4
+ import { lorem5, lorem500 } from '../test-utils';
5
+ import { Field } from '../field/Field';
6
+ import Body from '../body';
7
+ import { SelectInput, type SelectInputProps } from './SelectInput';
8
+
9
+ const meta = {
10
+ title: 'Forms/SelectInput/tests',
11
+ component: SelectInput,
12
+ args: {
13
+ onFilterChange: fn() satisfies Mock,
14
+ onChange: fn() satisfies Mock,
15
+ onClose: fn() satisfies Mock,
16
+ onOpen: fn() satisfies Mock,
17
+ },
18
+ tags: ['!autodocs'],
19
+ } satisfies Meta<typeof SelectInput>;
20
+ export default meta;
21
+
22
+ type Story<T, M extends boolean = false> = StoryObj<SelectInputProps<T, M>>;
23
+
24
+ const wait = async (duration = 500) =>
25
+ new Promise<void>((resolve) => {
26
+ setTimeout(resolve, duration);
27
+ });
28
+
29
+ /**
30
+ * This test ensures that when the SelectInput is used within a scrollable page,
31
+ * opening the dropdown does not cause any unwanted scrolling or layout shifts.
32
+ * Expected preview should start with green bar at the top, with yellow section
33
+ * not in the viewport.
34
+ *
35
+ * NB: This test is disabled in Chromatic as there's no obvious way to control <html/> element of a snapshot.
36
+ */
37
+ export const SmoothScrollReset: Story<string> = {
38
+ args: {
39
+ items: Array.from({ length: 15 }).map((_, id) => ({
40
+ type: 'option',
41
+ value: `option ${id + 1}`,
42
+ })),
43
+ placeholder: 'Select option',
44
+ },
45
+ decorators: [
46
+ (Story) => (
47
+ <>
48
+ <style>{`html { scroll-behavior: smooth; }`}</style>
49
+ <div>
50
+ <div
51
+ className="d-flex align-items-center justify-content-center"
52
+ style={{
53
+ backgroundColor: 'var(--color-bright-yellow)',
54
+ height: 400,
55
+ }}
56
+ >
57
+ This block should not be in the viewport.
58
+ </div>
59
+ <div style={{ height: 10, backgroundColor: 'var(--color-bright-green)' }} />
60
+ <Field id="el1" label={lorem5}>
61
+ <Story />
62
+ </Field>
63
+ <Body as="p">{lorem500}</Body>
64
+ </div>
65
+ </>
66
+ ),
67
+ ],
68
+ play: async ({ canvasElement }) => {
69
+ document.documentElement.scrollTop = 400;
70
+ await wait();
71
+ const canvas = within(canvasElement);
72
+ const triggerButton = canvas.getByRole('combobox');
73
+ await userEvent.click(triggerButton);
74
+ },
75
+ globals: {
76
+ viewport: { value: allModes.largeMobile.viewport, isRotated: false },
77
+ },
78
+ parameters: {
79
+ chromatic: {
80
+ disableSnapshot: true,
81
+ },
82
+ },
83
+ };
@@ -11,6 +11,8 @@
11
11
  transition-property: opacity;
12
12
  transition-timing-function: ease-out;
13
13
  transition-duration: 300ms;
14
+ height: 100vh;
15
+ min-height: -webkit-fill-available;
14
16
 
15
17
  &--closed {
16
18
  opacity: 0;
@@ -19,24 +21,28 @@
19
21
 
20
22
  .np-bottom-sheet-v2 {
21
23
  position: fixed;
22
- inset: 0px;
24
+ inset: 0;
23
25
  bottom: env(keyboard-inset-height, 0px);
24
- margin-left: var(--size-8);
25
- margin-right: var(--size-8);
26
- margin-top: var(--size-64);
26
+ // margin-left: var(--size-8);
27
+ // margin-right: var(--size-8);
28
+ padding-top: var(--size-64);
29
+ padding-bottom: min(env(safe-area-inset-bottom, var(--size-16)));
27
30
  display: flex;
28
31
  flex-direction: column;
29
32
  justify-content: flex-end;
33
+ height: 100%;
34
+ min-height: -webkit-fill-available;
30
35
  }
31
36
 
32
37
  .np-bottom-sheet-v2-content {
33
38
  display: flex;
34
39
  flex-direction: column;
35
40
  overflow: auto;
36
- border-top-left-radius: 32px; /* TODO: Tokenize */
37
- border-top-right-radius: 32px; /* TODO: Tokenize */
41
+ border-top-left-radius: var(--size-32);
42
+ border-top-right-radius: var(--size-32);
38
43
  background-color: var(--color-background-elevated);
39
44
  box-shadow: 0 0 40px rgb(69 71 69 / 0.2);
45
+ will-change: transform;
40
46
 
41
47
  &:focus {
42
48
  outline: none;
@@ -10,12 +10,11 @@ import { Transition, TransitionChild } from '@headlessui/react';
10
10
  import { FocusScope } from '@react-aria/focus';
11
11
  import { ThemeProvider, useTheme } from '@wise/components-theming';
12
12
  import { clsx } from 'clsx';
13
- import { Fragment, useState } from 'react';
13
+ import { Fragment, useState, useEffect } from 'react';
14
14
 
15
- import { CloseButton } from '../common/closeButton';
15
+ import { CloseButton, Size } from '../common';
16
16
  import { useVirtualKeyboard } from '../common/hooks/useVirtualKeyboard';
17
17
  import { PreventScroll } from '../common/preventScroll/PreventScroll';
18
- import { Size } from '../common/propsValues/size';
19
18
 
20
19
  export interface BottomSheetProps {
21
20
  open: boolean;
@@ -33,6 +32,19 @@ export interface BottomSheetProps {
33
32
  onCloseEnd?: () => void;
34
33
  }
35
34
 
35
+ /**
36
+ * App pages set scroll-behavior to 'smooth' which causes mobile Safari to
37
+ * slow-scroll and glitch. This function temporarily disables that behaviour
38
+ * while the BottomSheet is open.
39
+ */
40
+ const freezeScroll = (shouldFreeze = true) => {
41
+ if (shouldFreeze) {
42
+ document.documentElement.style.scrollBehavior = 'unset';
43
+ } else {
44
+ document.documentElement.style.removeProperty('scroll-behavior');
45
+ }
46
+ };
47
+
36
48
  export function BottomSheet({
37
49
  open,
38
50
  renderTrigger,
@@ -54,12 +66,14 @@ export function BottomSheet({
54
66
  },
55
67
  });
56
68
 
69
+ useEffect(() => {
70
+ freezeScroll(open);
71
+ }, [open]);
72
+
57
73
  const dismiss = useDismiss(context);
58
74
  const role = useRole(context);
59
75
  const { getReferenceProps, getFloatingProps } = useInteractions([dismiss, role]);
60
-
61
76
  const [floatingKey, setFloatingKey] = useState(0);
62
-
63
77
  const { theme, screenMode } = useTheme();
64
78
 
65
79
  return (