@transferwise/components 0.0.0-experimental-63c3fc6 → 0.0.0-experimental-5f03867

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 (147) hide show
  1. package/build/Snackbar/Snackbar.js +178 -102
  2. package/build/Snackbar/Snackbar.js.map +1 -1
  3. package/build/Snackbar/Snackbar.messages.js +14 -0
  4. package/build/Snackbar/Snackbar.messages.js.map +1 -0
  5. package/build/Snackbar/Snackbar.messages.mjs +10 -0
  6. package/build/Snackbar/Snackbar.messages.mjs.map +1 -0
  7. package/build/Snackbar/Snackbar.mjs +180 -101
  8. package/build/Snackbar/Snackbar.mjs.map +1 -1
  9. package/build/Snackbar/SnackbarContext.js.map +1 -1
  10. package/build/Snackbar/SnackbarContext.mjs.map +1 -1
  11. package/build/Snackbar/SnackbarPortal.js +12 -0
  12. package/build/Snackbar/SnackbarPortal.js.map +1 -0
  13. package/build/Snackbar/SnackbarPortal.mjs +8 -0
  14. package/build/Snackbar/SnackbarPortal.mjs.map +1 -0
  15. package/build/Snackbar/SnackbarProvider.js +24 -28
  16. package/build/Snackbar/SnackbarProvider.js.map +1 -1
  17. package/build/Snackbar/SnackbarProvider.mjs +25 -29
  18. package/build/Snackbar/SnackbarProvider.mjs.map +1 -1
  19. package/build/Snackbar/constants.js +17 -0
  20. package/build/Snackbar/constants.js.map +1 -0
  21. package/build/Snackbar/constants.mjs +11 -0
  22. package/build/Snackbar/constants.mjs.map +1 -0
  23. package/build/Snackbar/useSnackbarAutoDismiss.js +66 -0
  24. package/build/Snackbar/useSnackbarAutoDismiss.js.map +1 -0
  25. package/build/Snackbar/useSnackbarAutoDismiss.mjs +62 -0
  26. package/build/Snackbar/useSnackbarAutoDismiss.mjs.map +1 -0
  27. package/build/Snackbar/useSnackbarManager.js +153 -0
  28. package/build/Snackbar/useSnackbarManager.js.map +1 -0
  29. package/build/Snackbar/useSnackbarManager.mjs +149 -0
  30. package/build/Snackbar/useSnackbarManager.mjs.map +1 -0
  31. package/build/Snackbar/useSnackbarSwipeDismiss.js +135 -0
  32. package/build/Snackbar/useSnackbarSwipeDismiss.js.map +1 -0
  33. package/build/Snackbar/useSnackbarSwipeDismiss.mjs +131 -0
  34. package/build/Snackbar/useSnackbarSwipeDismiss.mjs.map +1 -0
  35. package/build/i18n/en.json +1 -0
  36. package/build/i18n/en.json.js +1 -0
  37. package/build/i18n/en.json.js.map +1 -1
  38. package/build/i18n/en.json.mjs +1 -0
  39. package/build/i18n/en.json.mjs.map +1 -1
  40. package/build/index.js +0 -4
  41. package/build/index.js.map +1 -1
  42. package/build/index.mjs +0 -2
  43. package/build/index.mjs.map +1 -1
  44. package/build/main.css +116 -191
  45. package/build/styles/Snackbar/Snackbar.css +117 -54
  46. package/build/styles/main.css +116 -191
  47. package/build/types/Snackbar/Snackbar.d.ts +55 -9
  48. package/build/types/Snackbar/Snackbar.d.ts.map +1 -1
  49. package/build/types/Snackbar/Snackbar.messages.d.ts +9 -0
  50. package/build/types/Snackbar/Snackbar.messages.d.ts.map +1 -0
  51. package/build/types/Snackbar/Snackbar.types.d.ts +12 -0
  52. package/build/types/Snackbar/Snackbar.types.d.ts.map +1 -0
  53. package/build/types/Snackbar/SnackbarContext.d.ts +2 -2
  54. package/build/types/Snackbar/SnackbarContext.d.ts.map +1 -1
  55. package/build/types/Snackbar/SnackbarPortal.d.ts +4 -0
  56. package/build/types/Snackbar/SnackbarPortal.d.ts.map +1 -0
  57. package/build/types/Snackbar/SnackbarProvider.d.ts +7 -0
  58. package/build/types/Snackbar/SnackbarProvider.d.ts.map +1 -1
  59. package/build/types/Snackbar/constants.d.ts +9 -0
  60. package/build/types/Snackbar/constants.d.ts.map +1 -0
  61. package/build/types/Snackbar/index.d.ts +1 -1
  62. package/build/types/Snackbar/index.d.ts.map +1 -1
  63. package/build/types/Snackbar/useSnackbar.d.ts +1 -1
  64. package/build/types/Snackbar/useSnackbar.d.ts.map +1 -1
  65. package/build/types/Snackbar/useSnackbarAutoDismiss.d.ts +13 -0
  66. package/build/types/Snackbar/useSnackbarAutoDismiss.d.ts.map +1 -0
  67. package/build/types/Snackbar/useSnackbarManager.d.ts +20 -0
  68. package/build/types/Snackbar/useSnackbarManager.d.ts.map +1 -0
  69. package/build/types/Snackbar/useSnackbarSwipeDismiss.d.ts +22 -0
  70. package/build/types/Snackbar/useSnackbarSwipeDismiss.d.ts.map +1 -0
  71. package/build/types/index.d.ts +1 -5
  72. package/build/types/index.d.ts.map +1 -1
  73. package/build/types/test-utils/index.d.ts +2 -0
  74. package/build/types/test-utils/index.d.ts.map +1 -1
  75. package/package.json +3 -3
  76. package/src/Snackbar/Snackbar.css +117 -54
  77. package/src/Snackbar/Snackbar.less +139 -60
  78. package/src/Snackbar/Snackbar.messages.ts +9 -0
  79. package/src/Snackbar/Snackbar.test.tsx +989 -119
  80. package/src/Snackbar/Snackbar.tsx +208 -93
  81. package/src/Snackbar/Snackbar.types.ts +17 -0
  82. package/src/Snackbar/SnackbarContext.ts +2 -2
  83. package/src/Snackbar/SnackbarPortal.tsx +8 -0
  84. package/src/Snackbar/SnackbarProvider.test.tsx +783 -0
  85. package/src/Snackbar/SnackbarProvider.tsx +27 -19
  86. package/src/Snackbar/_stories/Snackbar.accessibility.docs.mdx +66 -0
  87. package/src/Snackbar/_stories/Snackbar.migration.docs.mdx +64 -0
  88. package/src/Snackbar/_stories/Snackbar.rtl.test.story.tsx +16 -8
  89. package/src/Snackbar/_stories/Snackbar.story.tsx +389 -61
  90. package/src/Snackbar/_stories/Snackbar.test.story.tsx +171 -47
  91. package/src/Snackbar/constants.ts +10 -0
  92. package/src/Snackbar/index.ts +1 -1
  93. package/src/Snackbar/useSnackbarAutoDismiss.ts +74 -0
  94. package/src/Snackbar/useSnackbarManager.ts +169 -0
  95. package/src/Snackbar/useSnackbarSwipeDismiss.ts +169 -0
  96. package/src/i18n/en.json +1 -0
  97. package/src/index.ts +1 -14
  98. package/src/main.css +116 -191
  99. package/src/main.less +0 -2
  100. package/build/CardContainer/CardContainer.js +0 -33
  101. package/build/CardContainer/CardContainer.js.map +0 -1
  102. package/build/CardContainer/CardContainer.mjs +0 -29
  103. package/build/CardContainer/CardContainer.mjs.map +0 -1
  104. package/build/CardWidget/CardWidget.js +0 -94
  105. package/build/CardWidget/CardWidget.js.map +0 -1
  106. package/build/CardWidget/CardWidget.mjs +0 -90
  107. package/build/CardWidget/CardWidget.mjs.map +0 -1
  108. package/build/CardWidget/CardWidgetAction.js +0 -70
  109. package/build/CardWidget/CardWidgetAction.js.map +0 -1
  110. package/build/CardWidget/CardWidgetAction.mjs +0 -65
  111. package/build/CardWidget/CardWidgetAction.mjs.map +0 -1
  112. package/build/styles/CardContainer/CardContainer.css +0 -74
  113. package/build/styles/CardWidget/CardWidget.css +0 -64
  114. package/build/types/CardContainer/CardContainer.d.ts +0 -8
  115. package/build/types/CardContainer/CardContainer.d.ts.map +0 -1
  116. package/build/types/CardContainer/CardContainer.types.d.ts +0 -44
  117. package/build/types/CardContainer/CardContainer.types.d.ts.map +0 -1
  118. package/build/types/CardContainer/_stories/helpers.d.ts +0 -3
  119. package/build/types/CardContainer/_stories/helpers.d.ts.map +0 -1
  120. package/build/types/CardContainer/index.d.ts +0 -3
  121. package/build/types/CardContainer/index.d.ts.map +0 -1
  122. package/build/types/CardWidget/CardWidget.d.ts +0 -8
  123. package/build/types/CardWidget/CardWidget.d.ts.map +0 -1
  124. package/build/types/CardWidget/CardWidget.types.d.ts +0 -52
  125. package/build/types/CardWidget/CardWidget.types.d.ts.map +0 -1
  126. package/build/types/CardWidget/CardWidgetAction.d.ts +0 -54
  127. package/build/types/CardWidget/CardWidgetAction.d.ts.map +0 -1
  128. package/build/types/CardWidget/index.d.ts +0 -4
  129. package/build/types/CardWidget/index.d.ts.map +0 -1
  130. package/src/CardContainer/CardContainer.css +0 -74
  131. package/src/CardContainer/CardContainer.less +0 -112
  132. package/src/CardContainer/CardContainer.test.tsx +0 -118
  133. package/src/CardContainer/CardContainer.tsx +0 -39
  134. package/src/CardContainer/CardContainer.types.ts +0 -50
  135. package/src/CardContainer/_stories/CardContainer.story.tsx +0 -136
  136. package/src/CardContainer/_stories/CardContainer.test.story.tsx +0 -103
  137. package/src/CardContainer/_stories/helpers.tsx +0 -50
  138. package/src/CardContainer/index.ts +0 -6
  139. package/src/CardWidget/CardWidget.css +0 -64
  140. package/src/CardWidget/CardWidget.less +0 -82
  141. package/src/CardWidget/CardWidget.test.tsx +0 -189
  142. package/src/CardWidget/CardWidget.tsx +0 -74
  143. package/src/CardWidget/CardWidget.types.ts +0 -60
  144. package/src/CardWidget/CardWidgetAction.tsx +0 -126
  145. package/src/CardWidget/_stories/CardWidget.story.tsx +0 -209
  146. package/src/CardWidget/_stories/CardWidget.test.story.tsx +0 -350
  147. package/src/CardWidget/index.ts +0 -3
@@ -1,32 +1,40 @@
1
- import { useMemo, useState } from 'react';
1
+ import { useMemo } from 'react';
2
2
 
3
- import SnackbarPortal, { SnackbarProps } from './Snackbar';
3
+ import SnackbarPortal from './SnackbarPortal';
4
4
  import { SnackbarContext } from './SnackbarContext';
5
+ import useSnackbarManager from './useSnackbarManager';
5
6
 
6
7
  export interface SnackbarProviderProps {
8
+ /**
9
+ * @deprecated Use per-Snackbar `duration` instead. Explicit millisecond values remain supported
10
+ * and are not automatically remapped when no `duration` is supplied.
11
+ * When neither option is supplied, the default is 4000ms (previously 4500ms), after entry finishes.
12
+ * To migrate, use `default` for 0–5000ms, `extended` for values above 5000ms, and `indefinite`
13
+ * for intentionally persistent notifications.
14
+ */
7
15
  timeout?: number;
8
16
  children?: React.ReactNode;
9
17
  }
10
18
 
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, timestamp } = state;
19
+ export default function SnackbarProvider({ timeout, children }: SnackbarProviderProps) {
20
+ const { active, announcementKey, createSnackbar, dismissSnackbar, handleExited, visible } =
21
+ useSnackbarManager();
22
+ const contextValue = useMemo(() => ({ createSnackbar }), [createSnackbar]);
17
23
 
18
24
  return (
19
- <SnackbarContext.Provider
20
- value={useMemo(
21
- () => ({
22
- createSnackbar: ({ action, text }) => {
23
- setState({ action, text, timestamp: Date.now() });
24
- },
25
- }),
26
- [],
27
- )}
28
- >
29
- <SnackbarPortal action={action} text={text} timestamp={timestamp} timeout={timeout} />
25
+ <SnackbarContext.Provider value={contextValue}>
26
+ {active ? (
27
+ <SnackbarPortal
28
+ // Each instance gets a fresh appear transition and live-region announcement.
29
+ key={active.id}
30
+ {...active.props}
31
+ announcementKey={announcementKey}
32
+ timeout={timeout}
33
+ visible={visible}
34
+ onDismissRequest={dismissSnackbar}
35
+ onExited={handleExited}
36
+ />
37
+ ) : null}
30
38
  {children}
31
39
  </SnackbarContext.Provider>
32
40
  );
@@ -0,0 +1,66 @@
1
+ import { Meta, Source } from '@storybook/addon-docs/blocks';
2
+
3
+ <Meta title="Prompts/Snackbar/Accessibility" />
4
+
5
+ # Accessibility
6
+
7
+ ## Announcements
8
+
9
+ Snackbar uses `role="status"`, `aria-live="polite"` and `aria-atomic="true"` for every sentiment,
10
+ including negative. Showing a message requests a polite announcement without moving focus.
11
+ There is no live region while the Provider is idle.
12
+
13
+ The localised hint “Press Escape to dismiss.” follows the message, including on touch-only devices.
14
+ Touch-specific wording and a small-screen close button are follow-up work in
15
+ [DS-8650](https://transferwise.atlassian.net/browse/DS-8650).
16
+
17
+ ## Keyboard and dismissal
18
+
19
+ - The action follows normal tab order. Buttons support Enter and Space; links support Enter.
20
+ - Escape dismisses unless another overlay has already handled it.
21
+ - Desktop has a close IconButton labelled “Close”. On small screens it is hidden and not focusable.
22
+ - Swipe or drag down at least half the surface height to dismiss. Shorter or cancelled gestures return to place.
23
+
24
+ There is no shortcut to reach the action. Do not make Snackbar the only way to access an essential action;
25
+ focus management is tracked in [DS-8622](https://transferwise.atlassian.net/browse/DS-8622).
26
+
27
+ ## Timing and motion
28
+
29
+ Timed messages start counting after entry and pause during hover, keyboard focus or a swipe.
30
+ Use `extended` for additional reading time or an action, and `indefinite` for persistent feedback.
31
+ Loading always prevents auto-dismiss; describe the progress in the message, not just the spinner.
32
+
33
+ Reduced motion removes entry/exit movement and scale, and swipe transitions. Check zoom/reflow and RTL
34
+ with your content; the visual test stories provide examples.
35
+
36
+ ## Media
37
+
38
+ Include essential meaning in the message: custom media is outside its live region.
39
+ Hide decorative icons from assistive technology:
40
+
41
+ <Source
42
+ dark
43
+ code={`import { Button, SnackbarProvider, useSnackbar } from '@transferwise/components';
44
+ import { Card } from '@transferwise/icons';
45
+
46
+ function CardFeedback() {
47
+ const createSnackbar = useSnackbar();
48
+
49
+ return (
50
+ <Button v2 size="md" onClick={() => createSnackbar({
51
+ text: 'Card added to your wallet',
52
+ media: <Card aria-hidden />,
53
+ })}>
54
+ Show card confirmation
55
+ </Button>
56
+ );
57
+ }
58
+
59
+ export default function App() {
60
+ return (
61
+ <SnackbarProvider>
62
+ <CardFeedback />
63
+ </SnackbarProvider>
64
+ );
65
+ }`}
66
+ />
@@ -0,0 +1,64 @@
1
+ import { Meta, Source } from '@storybook/addon-docs/blocks';
2
+
3
+ <Meta title="Prompts/Snackbar/Migration" />
4
+
5
+ # Migration
6
+
7
+ Existing `createSnackbar({ text, action })` calls continue to work with the updated design.
8
+
9
+ ## Imports
10
+
11
+ - Replace the public `SnackbarProps` type with `SnackbarCreationProps`.
12
+ - Direct `Snackbar` and `SnackbarPortal` exports are removed. Use `SnackbarProvider` and `useSnackbar()` instead.
13
+ - The Provider, hook, Consumer, Context and their existing public types remain supported.
14
+ The hook still returns `createSnackbar` directly, not an object.
15
+
16
+ Wrap your app in one Provider and call the hook from a component inside it:
17
+
18
+ <Source
19
+ dark
20
+ code={`import { Button, SnackbarProvider, useSnackbar } from '@transferwise/components';
21
+ import type { SnackbarCreationProps } from '@transferwise/components';
22
+
23
+ const savedMessage: SnackbarCreationProps = {
24
+ text: 'Changes saved',
25
+ sentiment: 'success',
26
+ };
27
+
28
+ function SaveButton() {
29
+ const createSnackbar = useSnackbar();
30
+
31
+ return (
32
+ <Button v2 size="md" onClick={() => createSnackbar(savedMessage)}>
33
+ Show confirmation
34
+ </Button>
35
+ );
36
+ }
37
+
38
+ export default function App() {
39
+ return (
40
+ <SnackbarProvider>
41
+ <SaveButton />
42
+ </SnackbarProvider>
43
+ );
44
+ }`}
45
+ />
46
+
47
+ ## Duration
48
+
49
+ The default changes from **4500ms to 4000ms**, counted after entry finishes.
50
+ Replace deprecated Provider `timeout` values with a per-message `duration`:
51
+
52
+ - `default`: 4 seconds, generally replacing 0–5000ms.
53
+ - `extended`: 6 seconds, for more reading time or an action, generally replacing values above 5000ms.
54
+ - `indefinite`: no timer, for intentionally persistent messages, including very large timeouts used to avoid expiry.
55
+
56
+ Explicit Provider timeouts still work and are **not automatically remapped**. A message's `duration`
57
+ takes precedence; `loading: true` always prevents auto-dismiss.
58
+
59
+ ## Other changes
60
+
61
+ - `theme` and `timestamp` remain accepted but are deprecated and have no effect with the Provider.
62
+ - An empty string clears the current message and any waiting replacement.
63
+ - Review CSS and tests targeting the old `snackbar` DOM/classes: these now use `wds-Snackbar` and the shared prompt structure.
64
+ - Announcements change from assertive alerts to polite status messages. See [Accessibility](?path=/docs/prompts-snackbar-accessibility--docs).
@@ -1,8 +1,11 @@
1
- import { useEffect, useState } from 'react';
1
+ import { useEffect } from 'react';
2
2
  import type { Meta, StoryObj } from '@storybook/react-webpack5';
3
3
 
4
4
  import { useRtlDiffI18n, withRTLDiff } from '../../../.storybook/decorators/RtlDiffDecorator';
5
5
  import { Snackbar } from '../Snackbar';
6
+ import type { SnackbarCreationProps } from '../Snackbar.types';
7
+ import SnackbarProvider from '../SnackbarProvider';
8
+ import useSnackbar from '../useSnackbar';
6
9
 
7
10
  export default {
8
11
  component: Snackbar,
@@ -12,18 +15,23 @@ export default {
12
15
 
13
16
  type Story = StoryObj<typeof Snackbar>;
14
17
 
15
- const TIMEOUT = 10_000_000;
16
-
17
- function SnackbarStory({ text, action }: { text: string; action?: { label: string } }) {
18
- const [timestamp, setTimestamp] = useState(0);
18
+ function ShowOnMount(props: SnackbarCreationProps) {
19
+ const createSnackbar = useSnackbar();
19
20
 
20
21
  useEffect(() => {
21
- // eslint-disable-next-line react-hooks/set-state-in-effect
22
- setTimestamp(1);
22
+ createSnackbar(props);
23
+ // This visual fixture creates once per mount, not on every render of its props.
24
+ // eslint-disable-next-line react-hooks/exhaustive-deps
23
25
  }, []);
24
26
 
27
+ return null;
28
+ }
29
+
30
+ function SnackbarStory({ text, action }: { text: string; action?: { label: string } }) {
25
31
  return (
26
- <Snackbar text={<span>{text}</span>} timestamp={timestamp} timeout={TIMEOUT} action={action} />
32
+ <SnackbarProvider>
33
+ <ShowOnMount text={<span>{text}</span>} action={action} duration="indefinite" />
34
+ </SnackbarProvider>
27
35
  );
28
36
  }
29
37