@transferwise/components 46.147.0 → 46.148.1

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 (124) hide show
  1. package/build/container/Container.js.map +1 -1
  2. package/build/container/Container.mjs.map +1 -1
  3. package/build/main.css +63 -6
  4. package/build/prompt/CriticalBanner/CriticalBanner.js +81 -68
  5. package/build/prompt/CriticalBanner/CriticalBanner.js.map +1 -1
  6. package/build/prompt/CriticalBanner/CriticalBanner.mjs +82 -69
  7. package/build/prompt/CriticalBanner/CriticalBanner.mjs.map +1 -1
  8. package/build/prompt/PrimitivePrompt/PrimitivePrompt.js.map +1 -1
  9. package/build/prompt/PrimitivePrompt/PrimitivePrompt.mjs.map +1 -1
  10. package/build/styles/main.css +63 -6
  11. package/build/styles/prompt/ActionPrompt/ActionPrompt.css +2 -1
  12. package/build/styles/prompt/CriticalBanner/CriticalBanner.css +50 -1
  13. package/build/styles/prompt/InfoPrompt/InfoPrompt.css +2 -1
  14. package/build/styles/prompt/InlinePrompt/InlinePrompt.css +2 -1
  15. package/build/styles/prompt/PrimitivePrompt/PrimitivePrompt.css +2 -2
  16. package/build/types/container/Container.d.ts +2 -2
  17. package/build/types/container/Container.d.ts.map +1 -1
  18. package/build/types/iconButton/IconButton.d.ts +1 -1
  19. package/build/types/prompt/CriticalBanner/CriticalBanner.d.ts.map +1 -1
  20. package/build/types/prompt/PrimitivePrompt/PrimitivePrompt.d.ts +1 -1
  21. package/build/types/prompt/PrimitivePrompt/PrimitivePrompt.d.ts.map +1 -1
  22. package/package.json +1 -1
  23. package/src/accordion/Accordion.story.tsx +25 -0
  24. package/src/avatarLayout/AvatarLayout.story.tsx +10 -0
  25. package/src/avatarView/AvatarView.story.tsx +8 -0
  26. package/src/body/Body.story.tsx +12 -0
  27. package/src/button/_stories/Button.story.tsx +7 -1
  28. package/src/calendar/Calendar.story.tsx +19 -7
  29. package/src/carousel/Carousel.story.tsx +35 -0
  30. package/src/checkbox/Checkbox.story.tsx +20 -0
  31. package/src/checkboxButton/CheckboxButton.story.tsx +16 -0
  32. package/src/chevron/Chevron.story.tsx +6 -0
  33. package/src/chips/Chips.story.tsx +23 -0
  34. package/src/circularButton/CircularButton.story.tsx +13 -0
  35. package/src/common/baseCard/BaseCard.story.tsx +12 -0
  36. package/src/common/bottomSheet/BottomSheet.story.tsx +21 -0
  37. package/src/common/circle/Circle.story.tsx +11 -0
  38. package/src/container/Container.story.tsx +12 -0
  39. package/src/container/Container.tsx +2 -2
  40. package/src/dateInput/DateInput.story.tsx +20 -0
  41. package/src/dateLookup/DateLookup.story.tsx +23 -0
  42. package/src/decision/Decision.story.tsx +36 -0
  43. package/src/definitionList/DefinitionList.story.tsx +16 -0
  44. package/src/dimmer/Dimmer.story.tsx +24 -0
  45. package/src/display/Display.story.tsx +11 -0
  46. package/src/divider/Divider.story.tsx +6 -0
  47. package/src/drawer/Drawer.story.tsx +25 -0
  48. package/src/dropFade/DropFade.story.tsx +27 -0
  49. package/src/emphasis/Emphasis.story.tsx +10 -0
  50. package/src/expressiveMoneyInput/ExpressiveMoneyInput.story.tsx +37 -0
  51. package/src/field/Field.story.tsx +16 -0
  52. package/src/flowNavigation/FlowNavigation.story.tsx +25 -0
  53. package/src/header/Header.story.tsx +17 -0
  54. package/src/iconButton/IconButton.story.tsx +14 -0
  55. package/src/image/Image.story.tsx +11 -0
  56. package/src/info/Info.story.tsx +10 -0
  57. package/src/inputWithDisplayFormat/InputWithDisplayFormat.story.tsx +23 -0
  58. package/src/inputs/InputGroup.story.tsx +37 -0
  59. package/src/inputs/SearchInput.story.tsx +22 -0
  60. package/src/inputs/SelectInput/_stories/SelectInput.story.tsx +42 -0
  61. package/src/inputs/TextArea.story.tsx +22 -0
  62. package/src/instructionsList/InstructionsList.story.tsx +19 -0
  63. package/src/label/Label.story.tsx +17 -0
  64. package/src/link/Link.story.tsx +11 -0
  65. package/src/list/List.story.tsx +19 -0
  66. package/src/listItem/_stories/ListItem.story.tsx +20 -0
  67. package/src/loader/Loader.story.tsx +6 -0
  68. package/src/logo/Logo.story.tsx +6 -0
  69. package/src/main.css +63 -6
  70. package/src/markdown/Markdown.story.tsx +17 -0
  71. package/src/modal/Modal.story.tsx +23 -0
  72. package/src/money/Money.story.tsx +7 -0
  73. package/src/moneyInput/MoneyInput.story.tsx +34 -0
  74. package/src/nudge/Nudge.story.tsx +17 -0
  75. package/src/overlayHeader/OverlayHeader.story.tsx +10 -0
  76. package/src/phoneNumberInput/PhoneNumberInput.story.tsx +23 -0
  77. package/src/popover/Popover.story.tsx +12 -0
  78. package/src/primitives/PrimitiveAnchor/stories/PrimitiveAnchor.story.tsx +11 -0
  79. package/src/primitives/PrimitiveButton/stories/PrimitiveButton.story.tsx +11 -0
  80. package/src/processIndicator/ProcessIndicator.story.tsx +10 -0
  81. package/src/progress/Progress.story.tsx +6 -0
  82. package/src/progressBar/ProgressBar.story.tsx +12 -0
  83. package/src/promoCard/PromoCard.story.tsx +15 -0
  84. package/src/promoCard/PromoCardGroup.story.tsx +28 -0
  85. package/src/prompt/ActionPrompt/ActionPrompt.css +2 -1
  86. package/src/prompt/ActionPrompt/ActionPrompt.less +2 -1
  87. package/src/prompt/ActionPrompt/ActionPrompt.story.tsx +31 -0
  88. package/src/prompt/CriticalBanner/CriticalBanner.accessibility.docs.mdx +9 -0
  89. package/src/prompt/CriticalBanner/CriticalBanner.css +50 -1
  90. package/src/prompt/CriticalBanner/CriticalBanner.less +74 -1
  91. package/src/prompt/CriticalBanner/CriticalBanner.story.tsx +181 -170
  92. package/src/prompt/CriticalBanner/CriticalBanner.test.story.tsx +25 -6
  93. package/src/prompt/CriticalBanner/CriticalBanner.test.tsx +37 -0
  94. package/src/prompt/CriticalBanner/CriticalBanner.tsx +96 -84
  95. package/src/prompt/CriticalBanner/CriticalBanner.vars.less +1 -0
  96. package/src/prompt/InfoPrompt/InfoPrompt.css +2 -1
  97. package/src/prompt/InfoPrompt/InfoPrompt.less +2 -1
  98. package/src/prompt/InfoPrompt/InfoPrompt.story.tsx +30 -0
  99. package/src/prompt/InlinePrompt/InlinePrompt.css +2 -1
  100. package/src/prompt/InlinePrompt/InlinePrompt.less +2 -1
  101. package/src/prompt/InlinePrompt/InlinePrompt.story.tsx +14 -0
  102. package/src/prompt/PrimitivePrompt/PrimitivePrompt.css +2 -2
  103. package/src/prompt/PrimitivePrompt/PrimitivePrompt.less +1 -1
  104. package/src/prompt/PrimitivePrompt/PrimitivePrompt.tsx +1 -1
  105. package/src/radio/Radio.story.tsx +34 -0
  106. package/src/radioGroup/RadioGroup.story.tsx +26 -0
  107. package/src/section/Section.story.tsx +15 -0
  108. package/src/segmentedControl/SegmentedControl.story.tsx +27 -0
  109. package/src/sentimentSurface/SentimentSurface.story.tsx +11 -0
  110. package/src/slidingPanel/SlidingPanel.story.tsx +19 -0
  111. package/src/snackbar/Snackbar.story.tsx +24 -0
  112. package/src/statusIcon/StatusIcon.story.tsx +6 -0
  113. package/src/stepper/Stepper.story.tsx +30 -0
  114. package/src/sticky/Sticky.story.tsx +22 -1
  115. package/src/switch/Switch.story.tsx +17 -0
  116. package/src/table/Table.story.tsx +32 -0
  117. package/src/tabs/Tabs.story.tsx +31 -0
  118. package/src/textareaWithDisplayFormat/TextareaWithDisplayFormat.story.tsx +23 -0
  119. package/src/tile/Tile.story.tsx +13 -0
  120. package/src/title/Title.story.tsx +12 -0
  121. package/src/tooltip/Tooltip.story.tsx +8 -0
  122. package/src/typeahead/Typeahead.story.tsx +33 -0
  123. package/src/upload/Upload.story.tsx +24 -0
  124. package/src/uploadInput/UploadInput.story.tsx +31 -0
@@ -1,8 +1,9 @@
1
- import { ReactNode, useId, useState } from 'react';
1
+ import { ElementType, ReactNode, useId, useState } from 'react';
2
2
  import { clsx } from 'clsx';
3
3
 
4
4
  import Body from '../../body';
5
5
  import Button from '../../button';
6
+ import Container from '../../container';
6
7
  import { Breakpoint, LiveRegion, Typography } from '../../common';
7
8
  import { ButtonProps } from '../../button/Button.types';
8
9
  import { PrimitivePrompt, PrimitivePromptProps } from '../PrimitivePrompt';
@@ -77,6 +78,96 @@ export const CriticalBanner = ({
77
78
  .filter(Boolean)
78
79
  .join(' ');
79
80
 
81
+ const bannerSurface = (
82
+ <Container
83
+ size="fluid"
84
+ as={PrimitivePrompt as ElementType}
85
+ ref={containerRef}
86
+ id={id}
87
+ sentiment={sentiment}
88
+ emphasis={sentiment === 'neutral' ? 'base' : 'elevated'}
89
+ data-testid={testId}
90
+ className={clsx(
91
+ 'wds-critical-banner',
92
+ 'wds-critical-banner-overhang',
93
+ {
94
+ 'wds-critical-banner--collapsed': !resolvedExpanded,
95
+ 'wds-critical-banner--with-two-actions': !!actionSecondary,
96
+ },
97
+ className,
98
+ )}
99
+ media={renderPromptMedia({
100
+ media,
101
+ sentiment,
102
+ mediaId,
103
+ imgClassName: 'wds-critical-banner--media-image',
104
+ })}
105
+ actions={
106
+ hasActions ? (
107
+ <div aria-hidden={!resolvedExpanded ? true : undefined} style={{ display: 'contents' }}>
108
+ {actionSecondary && (
109
+ // @ts-expect-error onClick type mismatch
110
+ <Button
111
+ v2
112
+ size="md"
113
+ priority="secondary"
114
+ href={actionSecondary.href}
115
+ tabIndex={resolvedExpanded ? undefined : -1}
116
+ onClick={actionSecondary?.onClick}
117
+ >
118
+ {actionSecondary.label}
119
+ </Button>
120
+ )}
121
+ {action && (
122
+ // @ts-expect-error onClick type mismatch
123
+ <Button
124
+ v2
125
+ size="md"
126
+ priority="primary"
127
+ href={action.href}
128
+ tabIndex={resolvedExpanded ? undefined : -1}
129
+ onClick={action.onClick}
130
+ >
131
+ {action.label}
132
+ </Button>
133
+ )}
134
+ </div>
135
+ ) : undefined
136
+ }
137
+ role="region"
138
+ aria-labelledby={ariaLabelledByIds || undefined}
139
+ aria-describedby={description ? descId : undefined}
140
+ >
141
+ <div className="wds-critical-banner__text-wrapper">
142
+ {title && (
143
+ <Body
144
+ id={titleId}
145
+ type={Typography.BODY_LARGE_BOLD}
146
+ className="wds-critical-banner__content wds-critical-banner__title"
147
+ >
148
+ {title}
149
+ </Body>
150
+ )}
151
+ {description && (
152
+ <Body
153
+ id={descId}
154
+ className={clsx('wds-critical-banner__content', 'wds-critical-banner__description', {
155
+ 'wds-critical-banner__description--with-title': !!title,
156
+ })}
157
+ >
158
+ {description}
159
+ </Body>
160
+ )}
161
+ </div>
162
+ <ExpanderToggle
163
+ expanded={resolvedExpanded}
164
+ size={24}
165
+ className="wds-critical-banner__toggle"
166
+ onToggle={handleToggle}
167
+ />
168
+ </Container>
169
+ );
170
+
80
171
  return (
81
172
  <LiveRegion
82
173
  aria-live="assertive"
@@ -88,90 +179,11 @@ export const CriticalBanner = ({
88
179
  actionSecondaryLabel: actionSecondary?.label,
89
180
  })}
90
181
  >
91
- <PrimitivePrompt
92
- ref={containerRef}
93
- id={id}
94
- sentiment={sentiment}
95
- emphasis={sentiment === 'neutral' ? 'base' : 'elevated'}
96
- data-testid={testId}
97
- className={clsx(
98
- 'wds-critical-banner',
99
- {
100
- 'wds-critical-banner--collapsed': !resolvedExpanded,
101
- 'wds-critical-banner--with-two-actions': !!actionSecondary,
102
- },
103
- className,
104
- )}
105
- media={renderPromptMedia({
106
- media,
107
- sentiment,
108
- mediaId,
109
- imgClassName: 'wds-critical-banner--media-image',
110
- })}
111
- actions={
112
- hasActions ? (
113
- <div aria-hidden={!resolvedExpanded ? true : undefined} style={{ display: 'contents' }}>
114
- {actionSecondary && (
115
- // @ts-expect-error onClick type mismatch
116
- <Button
117
- v2
118
- size="md"
119
- priority="secondary"
120
- href={actionSecondary.href}
121
- tabIndex={resolvedExpanded ? undefined : -1}
122
- onClick={actionSecondary?.onClick}
123
- >
124
- {actionSecondary.label}
125
- </Button>
126
- )}
127
- {action && (
128
- // @ts-expect-error onClick type mismatch
129
- <Button
130
- v2
131
- size="md"
132
- priority="primary"
133
- href={action.href}
134
- tabIndex={resolvedExpanded ? undefined : -1}
135
- onClick={action.onClick}
136
- >
137
- {action.label}
138
- </Button>
139
- )}
140
- </div>
141
- ) : undefined
142
- }
143
- role="region"
144
- aria-labelledby={ariaLabelledByIds || undefined}
145
- aria-describedby={description ? descId : undefined}
146
- >
147
- <div className="wds-critical-banner__text-wrapper">
148
- {title && (
149
- <Body
150
- id={titleId}
151
- type={Typography.BODY_LARGE_BOLD}
152
- className="wds-critical-banner__content wds-critical-banner__title"
153
- >
154
- {title}
155
- </Body>
156
- )}
157
- {description && (
158
- <Body
159
- id={descId}
160
- className={clsx('wds-critical-banner__content', 'wds-critical-banner__description', {
161
- 'wds-critical-banner__description--with-title': !!title,
162
- })}
163
- >
164
- {description}
165
- </Body>
166
- )}
182
+ <div className="wds-critical-banner-overhang-query">
183
+ <div className="wds-critical-banner__entry-mask">
184
+ <div className="wds-critical-banner__entry-track">{bannerSurface}</div>
167
185
  </div>
168
- <ExpanderToggle
169
- expanded={resolvedExpanded}
170
- size={24}
171
- className="wds-critical-banner__toggle"
172
- onToggle={handleToggle}
173
- />
174
- </PrimitivePrompt>
186
+ </div>
175
187
  </LiveRegion>
176
188
  );
177
189
  };
@@ -3,4 +3,5 @@
3
3
  // * collapse toggle is visible below collapsible-max token
4
4
  // At some point in the not too distant future hopefully these two value will be the same but because of launchpad quirks, for now they'll be different
5
5
  @wds-critical-banner-action-wrapper-max: 600px;
6
+ @wds-critical-banner-mobile-overhang-max: 600px;
6
7
  @wds-critical-banner-collapsible-max: 768px;
@@ -1,7 +1,8 @@
1
1
  .wds-info-prompt {
2
2
  --Prompt-border-radius: var(--radius-medium);
3
3
  --Prompt-gap: var(--size-8);
4
- --Prompt-padding: var(--size-12);
4
+ --Prompt-padding-x: var(--size-12);
5
+ --Prompt-padding-y: var(--size-12);
5
6
  }
6
7
  .wds-info-prompt__content {
7
8
  display: flex;
@@ -1,7 +1,8 @@
1
1
  .wds-info-prompt {
2
2
  --Prompt-border-radius: var(--radius-medium);
3
3
  --Prompt-gap: var(--size-8);
4
- --Prompt-padding: var(--size-12);
4
+ --Prompt-padding-x: var(--size-12);
5
+ --Prompt-padding-y: var(--size-12);
5
6
 
6
7
  &__content {
7
8
  display: flex;
@@ -3,6 +3,10 @@ import { useState } from 'react';
3
3
  import type { Meta, StoryObj } from '@storybook/react-webpack5';
4
4
  import { action } from 'storybook/actions';
5
5
  import { Confetti, GiftBox, Star, Suitcase, Briefcase, Plane } from '@transferwise/icons';
6
+ import {
7
+ createSandboxStory,
8
+ globalScope,
9
+ } from '../../../.storybook/components/sandbox/SandboxEditor';
6
10
  import { lorem10, lorem20 } from '../../test-utils';
7
11
  import Button from '../../button';
8
12
  import Title from '../../title';
@@ -154,6 +158,32 @@ export const Playground: StoryObj<PreviewStoryArgs> = {
154
158
  },
155
159
  };
156
160
 
161
+ export const Sandbox = createSandboxStory({
162
+ code: `const App = () => {
163
+ const [dismissed, setDismissed] = React.useState(false);
164
+
165
+ if (dismissed) {
166
+ return (
167
+ <Button v2 size="md" onClick={() => setDismissed(false)}>
168
+ Show prompt again
169
+ </Button>
170
+ );
171
+ }
172
+
173
+ return (
174
+ <InfoPrompt
175
+ sentiment="success"
176
+ title="Payment successful"
177
+ description="Your payment is being processed."
178
+ media={{ asset: <Star /> }}
179
+ action={{ label: 'View details', onClick: () => console.log('view') }}
180
+ onDismiss={() => setDismissed(true)}
181
+ />
182
+ );
183
+ };`,
184
+ scope: globalScope,
185
+ });
186
+
157
187
  /**
158
188
  * InfoPrompt supports multiple sentiments to communicate different types of messages:
159
189
  * - `neutral` (default): General information
@@ -1,6 +1,7 @@
1
1
  .wds-inline-prompt {
2
2
  --Prompt-gap: calc(var(--size-12) / 2);
3
- --Prompt-padding: calc(var(--padding-x-small) / 2) var(--padding-x-small);
3
+ --Prompt-padding-x: var(--padding-x-small);
4
+ --Prompt-padding-y: calc(var(--padding-x-small) / 2);
4
5
  display: inline-flex;
5
6
  border-radius: 10px;
6
7
  border-radius: var(--radius-small);
@@ -1,6 +1,7 @@
1
1
  .wds-inline-prompt {
2
2
  --Prompt-gap: calc(var(--size-12) / 2);
3
- --Prompt-padding: calc(var(--padding-x-small) / 2) var(--padding-x-small);
3
+ --Prompt-padding-x: var(--padding-x-small);
4
+ --Prompt-padding-y: calc(var(--padding-x-small) / 2);
4
5
 
5
6
  display: inline-flex;
6
7
  border-radius: var(--radius-small);
@@ -2,6 +2,10 @@ import type { ReactElement } from 'react';
2
2
  import type { Meta, StoryObj } from '@storybook/react-webpack5';
3
3
  import { action } from 'storybook/actions';
4
4
  import { Clock, Taxi, Suitcase } from '@transferwise/icons';
5
+ import {
6
+ createSandboxStory,
7
+ globalScope,
8
+ } from '../../../.storybook/components/sandbox/SandboxEditor';
5
9
  import { lorem5 } from '../../test-utils';
6
10
  import Link from '../../link';
7
11
  import { InlinePrompt, InlinePromptProps } from './InlinePrompt';
@@ -106,6 +110,16 @@ export const Playground: StoryObj<PreviewStoryArgs> = {
106
110
  },
107
111
  };
108
112
 
113
+ export const Sandbox = createSandboxStory({
114
+ code: `<InlinePrompt sentiment="positive" media={<Suitcase />}>
115
+ Your travel account is set up and ready to use.{' '}
116
+ <Link href="https://wise.com" target="_blank" rel="noreferrer">
117
+ View details
118
+ </Link>
119
+ </InlinePrompt>`,
120
+ scope: { ...globalScope, Link },
121
+ });
122
+
109
123
  /**
110
124
  * Aside from the known `neutral`, `negative`, `warning` and `positive` sentiments, `InlinePrompt` is the first of the prompts to introduce a new `proposition` sentiment, which can be used to encourage the user to take an action that might benefit them.
111
125
  *
@@ -5,8 +5,8 @@
5
5
  gap: 16px;
6
6
  gap: var(--Prompt-gap, var(--size-16));
7
7
  word-wrap: break-word;
8
- padding: 8px;
9
- padding: var(--Prompt-padding, var(--padding-x-small));
8
+ padding: 8px 8px;
9
+ padding: var(--Prompt-padding-y, var(--padding-x-small)) var(--Prompt-padding-x, var(--padding-x-small));
10
10
  text-align: left;
11
11
  word-break: break-word;
12
12
  width: 100%;
@@ -3,7 +3,7 @@
3
3
  display: flex;
4
4
  gap: var(--Prompt-gap, var(--size-16));
5
5
  overflow-wrap: break-word;
6
- padding: var(--Prompt-padding, var(--padding-x-small));
6
+ padding: var(--Prompt-padding-y, var(--padding-x-small)) var(--Prompt-padding-x, var(--padding-x-small));
7
7
  text-align: left;
8
8
  word-break: break-word;
9
9
  width: 100%;
@@ -37,7 +37,7 @@ export type PrimitivePromptProps = HTMLAttributes<HTMLDivElement> & {
37
37
 
38
38
  /**
39
39
  * PrimitivePrompt is a low-level component that provides the structure, sentiment support and styling for various prompts.
40
- * Uses several css variables to handle styling from within the consuming component, e.g. --Prompt-padding. */
40
+ * Uses several css variables to handle styling from within the consuming component, e.g. --Prompt-padding-x. */
41
41
  export const PrimitivePrompt = forwardRef<HTMLDivElement, PrimitivePromptProps>(
42
42
  (
43
43
  {
@@ -1,5 +1,9 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
  import { useState } from 'react';
3
+ import {
4
+ createSandboxStory,
5
+ globalScope,
6
+ } from '../../.storybook/components/sandbox/SandboxEditor';
3
7
  import Radio, { type RadioProps } from './Radio';
4
8
  import AvatarView from '../avatarView';
5
9
  import { Flag } from '@wise/art';
@@ -14,6 +18,36 @@ const meta: Meta<RadioProps> = {
14
18
  };
15
19
  export default meta;
16
20
 
21
+ export const Sandbox = createSandboxStory({
22
+ code: `const App = () => {
23
+ const [selected, setSelected] = React.useState('option1');
24
+
25
+ return (
26
+ <>
27
+ <Radio
28
+ label="Standard delivery"
29
+ secondary="3-5 business days"
30
+ name="delivery"
31
+ id="radio-standard"
32
+ value="option1"
33
+ checked={selected === 'option1'}
34
+ onChange={() => setSelected('option1')}
35
+ />
36
+ <Radio
37
+ label="Express delivery"
38
+ secondary="1-2 business days"
39
+ name="delivery"
40
+ id="radio-express"
41
+ value="option2"
42
+ checked={selected === 'option2'}
43
+ onChange={() => setSelected('option2')}
44
+ />
45
+ </>
46
+ );
47
+ };`,
48
+ scope: globalScope,
49
+ });
50
+
17
51
  export const Basic: StoryObj<RadioProps> = {
18
52
  render: (args) => {
19
53
  return <Radio {...args} value="option1" onChange={fn()} />;
@@ -1,4 +1,8 @@
1
1
  import { Flag } from '@wise/art';
2
+ import {
3
+ createSandboxStory,
4
+ globalScope,
5
+ } from '../../.storybook/components/sandbox/SandboxEditor';
2
6
  import RadioGroup, { RadioGroupProps, RadioGroupRadio } from './RadioGroup';
3
7
  import { Field } from '../field/Field';
4
8
  import { Meta, StoryObj } from '@storybook/react-webpack5';
@@ -14,6 +18,28 @@ const meta = {
14
18
  export default meta;
15
19
  type Story<T extends string | number = string> = StoryObj<RadioGroupProps<T>>;
16
20
 
21
+ export const Sandbox = createSandboxStory({
22
+ code: `const App = () => {
23
+ const [selectedValue, setSelectedValue] = React.useState('radio-1');
24
+
25
+ return (
26
+ <Field label="Choose an option">
27
+ <RadioGroup
28
+ name="radio-group"
29
+ selectedValue={selectedValue}
30
+ onChange={(value) => setSelectedValue(value)}
31
+ radios={[
32
+ { value: 'radio-1', label: 'Option 1', secondary: 'Description for option 1' },
33
+ { value: 'radio-2', label: 'Option 2', secondary: 'Description for option 2' },
34
+ { value: 'radio-3', label: 'Option 3', secondary: 'Description for option 3' },
35
+ ]}
36
+ />
37
+ </Field>
38
+ );
39
+ };`,
40
+ scope: globalScope,
41
+ });
42
+
17
43
  export const Basic: Story = {
18
44
  args: {
19
45
  selectedValue: 'radio-2',
@@ -1,6 +1,7 @@
1
1
  import { FastFlag as FastFlagIcon } from '@transferwise/icons';
2
2
  import { useState } from 'react';
3
3
  import { action } from 'storybook/actions';
4
+ import { createSandboxStory, globalScope } from '../../.storybook/components/sandbox/SandboxEditor';
4
5
  import Accordion from '../accordion';
5
6
  import Card from '../card';
6
7
  import Header from '../header';
@@ -12,6 +13,20 @@ export default {
12
13
  title: 'Content/Section',
13
14
  };
14
15
 
16
+ export const Sandbox = createSandboxStory({
17
+ code: `<>
18
+ <Section>
19
+ <Header title="Section with header" />
20
+ Section content goes here.
21
+ </Section>
22
+ <Section>
23
+ <Header title="Another section" />
24
+ More content goes here.
25
+ </Section>
26
+ </>`,
27
+ scope: globalScope,
28
+ });
29
+
15
30
  export const Basic = () => {
16
31
  return (
17
32
  <>
@@ -1,6 +1,10 @@
1
1
  import { StoryFn, StoryObj } from '@storybook/react-webpack5';
2
2
  import React from 'react';
3
3
 
4
+ import {
5
+ createSandboxStory,
6
+ globalScope,
7
+ } from '../../.storybook/components/sandbox/SandboxEditor';
4
8
  import Button from '../button';
5
9
 
6
10
  import SegmentedControl from './SegmentedControl';
@@ -12,6 +16,29 @@ export default {
12
16
 
13
17
  type Story = StoryObj<typeof SegmentedControl>;
14
18
 
19
+ export const Sandbox = createSandboxStory({
20
+ code: `const App = () => {
21
+ const [value, setValue] = React.useState('cupcakes');
22
+
23
+ const segments = [
24
+ { id: 'CUPCAKE', label: 'Cupcakes', value: 'cupcakes' },
25
+ { id: 'SPONGECAKE', label: 'Sponge cake', value: 'spongecake' },
26
+ { id: 'CARROT_CAKE', label: 'Carrot cake', value: 'carrotcake' },
27
+ ];
28
+
29
+ return (
30
+ <SegmentedControl
31
+ name="cake-selector"
32
+ mode="input"
33
+ segments={segments}
34
+ value={value}
35
+ onChange={(newValue) => setValue(newValue)}
36
+ />
37
+ );
38
+ };`,
39
+ scope: globalScope,
40
+ });
41
+
15
42
  const Template: Story = {
16
43
  render: (args) => {
17
44
  const [segments, setSegments] = React.useState([
@@ -1,5 +1,6 @@
1
1
  import { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
  import { Bank, Defrost } from '@transferwise/icons';
3
+ import { createSandboxStory, globalScope } from '../../.storybook/components/sandbox/SandboxEditor';
3
4
  import Body from '../body';
4
5
  import Button from '../button';
5
6
  import Header from '../header';
@@ -127,6 +128,16 @@ export const Playground: Story = {
127
128
  },
128
129
  };
129
130
 
131
+ export const Sandbox = createSandboxStory({
132
+ code: `<SentimentSurface sentiment="negative" className="p-a-2">
133
+ <p>
134
+ This text and its <Link href="#">inline links</Link> use sentiment-matched colour.
135
+ </p>
136
+ <Button v2 size="sm">Primary</Button>
137
+ </SentimentSurface>`,
138
+ scope: { ...globalScope, Link },
139
+ });
140
+
130
141
  const sentiments: Sentiment[] = ['negative', 'warning', 'neutral', 'success', 'proposition'];
131
142
  const emphasisLevels: Emphasis[] = ['base', 'elevated'];
132
143
  const tokenCategories = [
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import Button from '../button';
3
+ import { createSandboxStory, globalScope } from '../../.storybook/components/sandbox/SandboxEditor';
3
4
  import SlidingPanel, { type SlidingPanelProps } from './SlidingPanel';
4
5
 
5
6
  export default {
@@ -25,6 +26,24 @@ export default {
25
26
  ],
26
27
  };
27
28
 
29
+ export const Sandbox = createSandboxStory({
30
+ code: `const App = () => {
31
+ const [open, setOpen] = React.useState(false);
32
+
33
+ return (
34
+ <div>
35
+ <Button v2 onClick={() => setOpen(!open)}>Toggle Sliding Panel</Button>
36
+ <SlidingPanel open={open} position="top">
37
+ <div className="p-y-4 p-x-4">
38
+ Panel content slides in from the chosen position.
39
+ </div>
40
+ </SlidingPanel>
41
+ </div>
42
+ );
43
+ };`,
44
+ scope: globalScope,
45
+ });
46
+
28
47
  export const Basic = function Render(args: SlidingPanelProps) {
29
48
  const [open, setOpen] = React.useState(false);
30
49
 
@@ -1,6 +1,7 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
  import { fn, userEvent, within } from 'storybook/test';
3
3
  import { wait } from '../test-utils/wait';
4
+ import { createSandboxStory, globalScope } from '../../.storybook/components/sandbox/SandboxEditor';
4
5
  import Button from '../button';
5
6
  import { Snackbar } from './Snackbar';
6
7
  import { SnackbarConsumer } from './SnackbarContext';
@@ -12,6 +13,29 @@ const meta: Meta = {
12
13
  };
13
14
  export default meta;
14
15
 
16
+ export const Sandbox = createSandboxStory({
17
+ code: `<SnackbarProvider>
18
+ <SnackbarConsumer>
19
+ {({ createSnackbar }) => (
20
+ <Button v2 size="md"
21
+ onClick={() =>
22
+ createSnackbar({
23
+ text: <span>Transfer completed successfully</span>,
24
+ action: {
25
+ label: 'View',
26
+ onClick: () => console.log('View clicked'),
27
+ },
28
+ })
29
+ }
30
+ >
31
+ Show Snackbar
32
+ </Button>
33
+ )}
34
+ </SnackbarConsumer>
35
+ </SnackbarProvider>`,
36
+ scope: globalScope,
37
+ });
38
+
15
39
  export const Basic: StoryObj = {
16
40
  parameters: {
17
41
  docs: {
@@ -1,4 +1,5 @@
1
1
  import { Meta, StoryObj } from '@storybook/react-webpack5';
2
+ import { createSandboxStory } from '../../.storybook/components/sandbox/SandboxEditor';
2
3
 
3
4
  import { Sentiment } from '../common';
4
5
  import SentimentSurface from '../sentimentSurface';
@@ -36,6 +37,11 @@ export const Playground: Story = {
36
37
  },
37
38
  };
38
39
 
40
+ export const Sandbox = createSandboxStory({
41
+ code: `<StatusIcon sentiment="positive" size={48} />`,
42
+ scope: { StatusIcon },
43
+ });
44
+
39
45
  /**
40
46
  * All available sentiments at the selected size.
41
47
  */
@@ -1,5 +1,6 @@
1
1
  import { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
  import { fn } from 'storybook/test';
3
+ import { createSandboxStory, globalScope } from '../../.storybook/components/sandbox/SandboxEditor';
3
4
  import Stepper from './Stepper';
4
5
 
5
6
  const STEPS = [
@@ -37,6 +38,35 @@ export default {
37
38
 
38
39
  type Story = StoryObj<typeof Stepper>;
39
40
 
41
+ export const Sandbox = createSandboxStory({
42
+ code: `const App = () => {
43
+ const [activeStep, setActiveStep] = React.useState(1);
44
+
45
+ return (
46
+ <Stepper
47
+ activeStep={activeStep}
48
+ steps={[
49
+ { label: 'Amount', onClick: () => setActiveStep(0) },
50
+ {
51
+ label: 'You',
52
+ hoverLabel: (
53
+ <>
54
+ <div><strong>Diana Jaramillo</strong></div>
55
+ dianajarm123@gmail.com
56
+ </>
57
+ ),
58
+ onClick: () => setActiveStep(1),
59
+ },
60
+ { label: 'Recipient', onClick: () => setActiveStep(2) },
61
+ { label: 'Review', onClick: () => setActiveStep(3) },
62
+ { label: 'Pay', onClick: () => setActiveStep(4) },
63
+ ]}
64
+ />
65
+ );
66
+ };`,
67
+ scope: globalScope,
68
+ });
69
+
40
70
  export const Basic: Story = {
41
71
  render: ({ activeStep, steps }) => {
42
72
  return <Stepper activeStep={activeStep} steps={steps} />;