@transferwise/components 46.146.0 → 46.148.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 (109) hide show
  1. package/build/main.css +66 -0
  2. package/build/nudge/Nudge.js.map +1 -1
  3. package/build/nudge/Nudge.mjs.map +1 -1
  4. package/build/prompt/CriticalBanner/CriticalBanner.js +78 -68
  5. package/build/prompt/CriticalBanner/CriticalBanner.js.map +1 -1
  6. package/build/prompt/CriticalBanner/CriticalBanner.mjs +79 -69
  7. package/build/prompt/CriticalBanner/CriticalBanner.mjs.map +1 -1
  8. package/build/styles/main.css +66 -0
  9. package/build/styles/nudge/Nudge.css +11 -0
  10. package/build/styles/prompt/CriticalBanner/CriticalBanner.css +48 -0
  11. package/build/types/nudge/Nudge.d.ts +1 -1
  12. package/build/types/nudge/Nudge.d.ts.map +1 -1
  13. package/build/types/prompt/CriticalBanner/CriticalBanner.d.ts.map +1 -1
  14. package/package.json +23 -19
  15. package/src/accordion/Accordion.story.tsx +25 -0
  16. package/src/avatarLayout/AvatarLayout.story.tsx +10 -0
  17. package/src/avatarView/AvatarView.story.tsx +8 -0
  18. package/src/body/Body.story.tsx +12 -0
  19. package/src/button/_stories/Button.story.tsx +7 -1
  20. package/src/calendar/Calendar.story.tsx +19 -7
  21. package/src/carousel/Carousel.story.tsx +35 -0
  22. package/src/checkbox/Checkbox.story.tsx +20 -0
  23. package/src/checkboxButton/CheckboxButton.story.tsx +16 -0
  24. package/src/chevron/Chevron.story.tsx +6 -0
  25. package/src/chips/Chips.story.tsx +23 -0
  26. package/src/circularButton/CircularButton.story.tsx +13 -0
  27. package/src/common/baseCard/BaseCard.story.tsx +12 -0
  28. package/src/common/bottomSheet/BottomSheet.story.tsx +21 -0
  29. package/src/common/circle/Circle.story.tsx +11 -0
  30. package/src/container/Container.story.tsx +12 -0
  31. package/src/dateInput/DateInput.story.tsx +20 -0
  32. package/src/dateLookup/DateLookup.story.tsx +23 -0
  33. package/src/decision/Decision.story.tsx +36 -0
  34. package/src/definitionList/DefinitionList.story.tsx +16 -0
  35. package/src/dimmer/Dimmer.story.tsx +24 -0
  36. package/src/display/Display.story.tsx +11 -0
  37. package/src/divider/Divider.story.tsx +6 -0
  38. package/src/drawer/Drawer.story.tsx +25 -0
  39. package/src/dropFade/DropFade.story.tsx +27 -0
  40. package/src/emphasis/Emphasis.story.tsx +10 -0
  41. package/src/expressiveMoneyInput/ExpressiveMoneyInput.story.tsx +37 -0
  42. package/src/field/Field.story.tsx +16 -0
  43. package/src/flowNavigation/FlowNavigation.story.tsx +25 -0
  44. package/src/header/Header.story.tsx +17 -0
  45. package/src/iconButton/IconButton.story.tsx +14 -0
  46. package/src/image/Image.story.tsx +11 -0
  47. package/src/info/Info.story.tsx +10 -0
  48. package/src/inputWithDisplayFormat/InputWithDisplayFormat.story.tsx +23 -0
  49. package/src/inputs/InputGroup.story.tsx +37 -0
  50. package/src/inputs/SearchInput.story.tsx +22 -0
  51. package/src/inputs/SelectInput/_stories/SelectInput.story.tsx +42 -0
  52. package/src/inputs/TextArea.story.tsx +22 -0
  53. package/src/instructionsList/InstructionsList.story.tsx +19 -0
  54. package/src/label/Label.story.tsx +17 -0
  55. package/src/link/Link.story.tsx +11 -0
  56. package/src/list/List.story.tsx +19 -0
  57. package/src/listItem/_stories/ListItem.story.tsx +20 -0
  58. package/src/loader/Loader.story.tsx +6 -0
  59. package/src/logo/Logo.story.tsx +6 -0
  60. package/src/main.css +66 -0
  61. package/src/markdown/Markdown.story.tsx +17 -0
  62. package/src/modal/Modal.story.tsx +23 -0
  63. package/src/money/Money.story.tsx +7 -0
  64. package/src/moneyInput/MoneyInput.story.tsx +34 -0
  65. package/src/nudge/Nudge.css +11 -0
  66. package/src/nudge/Nudge.less +4 -0
  67. package/src/nudge/Nudge.story.tsx +26 -0
  68. package/src/nudge/Nudge.tsx +2 -1
  69. package/src/overlayHeader/OverlayHeader.story.tsx +10 -0
  70. package/src/phoneNumberInput/PhoneNumberInput.story.tsx +23 -0
  71. package/src/popover/Popover.story.tsx +12 -0
  72. package/src/primitives/PrimitiveAnchor/stories/PrimitiveAnchor.story.tsx +11 -0
  73. package/src/primitives/PrimitiveButton/stories/PrimitiveButton.story.tsx +11 -0
  74. package/src/processIndicator/ProcessIndicator.story.tsx +10 -0
  75. package/src/progress/Progress.story.tsx +6 -0
  76. package/src/progressBar/ProgressBar.story.tsx +12 -0
  77. package/src/promoCard/PromoCard.story.tsx +15 -0
  78. package/src/promoCard/PromoCardGroup.story.tsx +28 -0
  79. package/src/prompt/ActionPrompt/ActionPrompt.story.tsx +31 -0
  80. package/src/prompt/CriticalBanner/CriticalBanner.accessibility.docs.mdx +9 -0
  81. package/src/prompt/CriticalBanner/CriticalBanner.css +48 -0
  82. package/src/prompt/CriticalBanner/CriticalBanner.less +72 -0
  83. package/src/prompt/CriticalBanner/CriticalBanner.story.tsx +180 -169
  84. package/src/prompt/CriticalBanner/CriticalBanner.test.story.tsx +25 -6
  85. package/src/prompt/CriticalBanner/CriticalBanner.test.tsx +37 -0
  86. package/src/prompt/CriticalBanner/CriticalBanner.tsx +92 -83
  87. package/src/prompt/CriticalBanner/CriticalBanner.vars.less +1 -0
  88. package/src/prompt/InfoPrompt/InfoPrompt.story.tsx +30 -0
  89. package/src/prompt/InlinePrompt/InlinePrompt.story.tsx +14 -0
  90. package/src/radio/Radio.story.tsx +34 -0
  91. package/src/radioGroup/RadioGroup.story.tsx +26 -0
  92. package/src/section/Section.story.tsx +15 -0
  93. package/src/segmentedControl/SegmentedControl.story.tsx +27 -0
  94. package/src/sentimentSurface/SentimentSurface.story.tsx +11 -0
  95. package/src/slidingPanel/SlidingPanel.story.tsx +19 -0
  96. package/src/snackbar/Snackbar.story.tsx +24 -0
  97. package/src/statusIcon/StatusIcon.story.tsx +6 -0
  98. package/src/stepper/Stepper.story.tsx +30 -0
  99. package/src/sticky/Sticky.story.tsx +22 -1
  100. package/src/switch/Switch.story.tsx +17 -0
  101. package/src/table/Table.story.tsx +32 -0
  102. package/src/tabs/Tabs.story.tsx +31 -0
  103. package/src/textareaWithDisplayFormat/TextareaWithDisplayFormat.story.tsx +23 -0
  104. package/src/tile/Tile.story.tsx +13 -0
  105. package/src/title/Title.story.tsx +12 -0
  106. package/src/tooltip/Tooltip.story.tsx +8 -0
  107. package/src/typeahead/Typeahead.story.tsx +33 -0
  108. package/src/upload/Upload.story.tsx +24 -0
  109. package/src/uploadInput/UploadInput.story.tsx +31 -0
@@ -77,6 +77,94 @@ export const CriticalBanner = ({
77
77
  .filter(Boolean)
78
78
  .join(' ');
79
79
 
80
+ const bannerSurface = (
81
+ <PrimitivePrompt
82
+ ref={containerRef}
83
+ id={id}
84
+ sentiment={sentiment}
85
+ emphasis={sentiment === 'neutral' ? 'base' : 'elevated'}
86
+ data-testid={testId}
87
+ className={clsx(
88
+ 'wds-critical-banner',
89
+ 'wds-critical-banner-overhang',
90
+ {
91
+ 'wds-critical-banner--collapsed': !resolvedExpanded,
92
+ 'wds-critical-banner--with-two-actions': !!actionSecondary,
93
+ },
94
+ className,
95
+ )}
96
+ media={renderPromptMedia({
97
+ media,
98
+ sentiment,
99
+ mediaId,
100
+ imgClassName: 'wds-critical-banner--media-image',
101
+ })}
102
+ actions={
103
+ hasActions ? (
104
+ <div aria-hidden={!resolvedExpanded ? true : undefined} style={{ display: 'contents' }}>
105
+ {actionSecondary && (
106
+ // @ts-expect-error onClick type mismatch
107
+ <Button
108
+ v2
109
+ size="md"
110
+ priority="secondary"
111
+ href={actionSecondary.href}
112
+ tabIndex={resolvedExpanded ? undefined : -1}
113
+ onClick={actionSecondary?.onClick}
114
+ >
115
+ {actionSecondary.label}
116
+ </Button>
117
+ )}
118
+ {action && (
119
+ // @ts-expect-error onClick type mismatch
120
+ <Button
121
+ v2
122
+ size="md"
123
+ priority="primary"
124
+ href={action.href}
125
+ tabIndex={resolvedExpanded ? undefined : -1}
126
+ onClick={action.onClick}
127
+ >
128
+ {action.label}
129
+ </Button>
130
+ )}
131
+ </div>
132
+ ) : undefined
133
+ }
134
+ role="region"
135
+ aria-labelledby={ariaLabelledByIds || undefined}
136
+ aria-describedby={description ? descId : undefined}
137
+ >
138
+ <div className="wds-critical-banner__text-wrapper">
139
+ {title && (
140
+ <Body
141
+ id={titleId}
142
+ type={Typography.BODY_LARGE_BOLD}
143
+ className="wds-critical-banner__content wds-critical-banner__title"
144
+ >
145
+ {title}
146
+ </Body>
147
+ )}
148
+ {description && (
149
+ <Body
150
+ id={descId}
151
+ className={clsx('wds-critical-banner__content', 'wds-critical-banner__description', {
152
+ 'wds-critical-banner__description--with-title': !!title,
153
+ })}
154
+ >
155
+ {description}
156
+ </Body>
157
+ )}
158
+ </div>
159
+ <ExpanderToggle
160
+ expanded={resolvedExpanded}
161
+ size={24}
162
+ className="wds-critical-banner__toggle"
163
+ onToggle={handleToggle}
164
+ />
165
+ </PrimitivePrompt>
166
+ );
167
+
80
168
  return (
81
169
  <LiveRegion
82
170
  aria-live="assertive"
@@ -88,90 +176,11 @@ export const CriticalBanner = ({
88
176
  actionSecondaryLabel: actionSecondary?.label,
89
177
  })}
90
178
  >
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
- )}
179
+ <div className="wds-critical-banner-overhang-query">
180
+ <div className="wds-critical-banner__entry-mask">
181
+ <div className="wds-critical-banner__entry-track">{bannerSurface}</div>
167
182
  </div>
168
- <ExpanderToggle
169
- expanded={resolvedExpanded}
170
- size={24}
171
- className="wds-critical-banner__toggle"
172
- onToggle={handleToggle}
173
- />
174
- </PrimitivePrompt>
183
+ </div>
175
184
  </LiveRegion>
176
185
  );
177
186
  };
@@ -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;
@@ -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
@@ -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
  *
@@ -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} />;
@@ -1,5 +1,6 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
  import React from 'react';
3
+ import { createSandboxStory, globalScope } from '../../.storybook/components/sandbox/SandboxEditor';
3
4
  import Sticky from './Sticky';
4
5
  import { allModes } from '../../.storybook/modes';
5
6
 
@@ -45,7 +46,27 @@ export default meta;
45
46
  // Represents a story object for the `Sticky` component.
46
47
  type Story = StoryObj<typeof Sticky>;
47
48
 
48
- export const Default: Story = {}; // Default story with no additional props
49
+ export const Sandbox = createSandboxStory({
50
+ code: `const App = () => {
51
+ const [open, setOpen] = React.useState(false);
52
+
53
+ return (
54
+ <>
55
+ <Button v2 onClick={() => setOpen(!open)}>
56
+ {open ? 'Close' : 'Open'} Sticky
57
+ </Button>
58
+ <Sticky open={open} position="bottom">
59
+ <div className="d-flex justify-content-start align-items-start flex-wrap p-x-4 p-y-4">
60
+ <p className="m-b-0">Sticky content pinned to the bottom.</p>
61
+ </div>
62
+ </Sticky>
63
+ </>
64
+ );
65
+ };`,
66
+ scope: globalScope,
67
+ });
68
+
69
+ export const Default: Story = {};
49
70
 
50
71
  export const PositionTop: Story = {
51
72
  args: {
@@ -2,6 +2,7 @@ import { useState, useEffect } from 'react';
2
2
  import { fn } from 'storybook/test';
3
3
 
4
4
  import { storySourceWithoutNoise } from '../../.storybook/helpers';
5
+ import { createSandboxStory, globalScope } from '../../.storybook/components/sandbox/SandboxEditor';
5
6
  import Switch, { SwitchProps } from './Switch';
6
7
  import { Field } from '../field/Field';
7
8
  import { Meta, StoryObj } from '@storybook/react-webpack5';
@@ -55,6 +56,22 @@ export const Playground: Story = storySourceWithoutNoise({
55
56
  },
56
57
  });
57
58
 
59
+ export const Sandbox = createSandboxStory({
60
+ code: `const App = () => {
61
+ const [checked, setChecked] = React.useState(false);
62
+
63
+ return (
64
+ <Field id="sandbox-field" label="Enable notifications">
65
+ <Switch
66
+ checked={checked}
67
+ onClick={() => setChecked((prev) => !prev)}
68
+ />
69
+ </Field>
70
+ );
71
+ };`,
72
+ scope: { ...globalScope, Switch },
73
+ });
74
+
58
75
  /**
59
76
  * Three labelling patterns: <a href="?path=/docs/forms-label--docs">Label</a>, `aria-labelledby`, and <a href="?path=/docs/forms-field--docs">Field</a>. <br />
60
77
  * Use Label for simple label-input pairs. Use `aria-labelledby` to reference existing text as the accessible name. Use Field for form layouts with labels, descriptions, and validation.