+1
.eslintrc.js
+1
.eslintrc.js
+219
-50
src/components/Toast/Toast.tsx
+219
-50
src/components/Toast/Toast.tsx
···
1
1
import {createContext, useContext, useMemo} from 'react'
2
-
import {View} from 'react-native'
2
+
import {type GestureResponderEvent, View} from 'react-native'
3
3
4
4
import {atoms as a, select, useAlf, useTheme} from '#/alf'
5
+
import {
6
+
Button,
7
+
type ButtonProps,
8
+
type UninheritableButtonProps,
9
+
} from '#/components/Button'
10
+
import {CircleCheck_Stroke2_Corner0_Rounded as CircleCheck} from '#/components/icons/CircleCheck'
5
11
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
6
12
import {CircleInfo_Stroke2_Corner0_Rounded as ErrorIcon} from '#/components/icons/CircleInfo'
13
+
import {type Props as SVGIconProps} from '#/components/icons/common'
7
14
import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning'
15
+
import {dismiss} from '#/components/Toast/sonner'
8
16
import {type ToastType} from '#/components/Toast/types'
9
-
import {Text} from '#/components/Typography'
10
-
import {CircleCheck_Stroke2_Corner0_Rounded as CircleCheck} from '../icons/CircleCheck'
17
+
import {Text as BaseText} from '#/components/Typography'
11
18
12
-
type ContextType = {
19
+
type ToastConfigContextType = {
20
+
id: string
21
+
}
22
+
23
+
type ToastThemeContextType = {
13
24
type: ToastType
14
25
}
15
26
16
27
export type ToastComponentProps = {
17
28
type?: ToastType
18
-
content: React.ReactNode
29
+
content: string
19
30
}
20
31
21
32
export const ICONS = {
···
26
37
info: CircleInfo,
27
38
}
28
39
29
-
const Context = createContext<ContextType>({
40
+
const ToastConfigContext = createContext<ToastConfigContextType>({
41
+
id: '',
42
+
})
43
+
ToastConfigContext.displayName = 'ToastConfigContext'
44
+
45
+
export function ToastConfigProvider({
46
+
children,
47
+
id,
48
+
}: {
49
+
children: React.ReactNode
50
+
id: string
51
+
}) {
52
+
return (
53
+
<ToastConfigContext.Provider value={useMemo(() => ({id}), [id])}>
54
+
{children}
55
+
</ToastConfigContext.Provider>
56
+
)
57
+
}
58
+
59
+
const ToastThemeContext = createContext<ToastThemeContextType>({
30
60
type: 'default',
31
61
})
32
-
Context.displayName = 'ToastContext'
62
+
ToastThemeContext.displayName = 'ToastThemeContext'
33
63
34
-
export function Toast({type = 'default', content}: ToastComponentProps) {
35
-
const {fonts} = useAlf()
64
+
export function Default({type = 'default', content}: ToastComponentProps) {
65
+
return (
66
+
<Outer type={type}>
67
+
<Icon />
68
+
<Text>{content}</Text>
69
+
</Outer>
70
+
)
71
+
}
72
+
73
+
export function Outer({
74
+
children,
75
+
type = 'default',
76
+
}: {
77
+
children: React.ReactNode
78
+
type?: ToastType
79
+
}) {
36
80
const t = useTheme()
37
81
const styles = useToastStyles({type})
38
-
const Icon = ICONS[type]
39
-
/**
40
-
* Vibes-based number, adjusts `top` of `View` that wraps the text to
41
-
* compensate for different type sizes and keep the first line of text
42
-
* aligned with the icon. - esb
43
-
*/
44
-
const fontScaleCompensation = useMemo(
45
-
() => parseInt(fonts.scale) * -1 * 0.65,
46
-
[fonts.scale],
47
-
)
48
82
49
83
return (
50
-
<Context.Provider value={useMemo(() => ({type}), [type])}>
84
+
<ToastThemeContext.Provider value={useMemo(() => ({type}), [type])}>
51
85
<View
52
86
style={[
53
87
a.flex_1,
54
-
a.py_lg,
55
-
a.pl_xl,
56
-
a.pr_2xl,
88
+
a.p_lg,
57
89
a.rounded_md,
58
90
a.border,
59
91
a.flex_row,
60
92
a.gap_sm,
61
93
t.atoms.shadow_sm,
62
94
{
95
+
paddingVertical: 14, // 16 seems too big
63
96
backgroundColor: styles.backgroundColor,
64
97
borderColor: styles.borderColor,
65
98
},
66
99
]}>
67
-
<Icon size="md" fill={styles.iconColor} />
68
-
69
-
<View
70
-
style={[
71
-
a.flex_1,
72
-
{
73
-
top: fontScaleCompensation,
74
-
},
75
-
]}>
76
-
{typeof content === 'string' ? (
77
-
<ToastText>{content}</ToastText>
78
-
) : (
79
-
content
80
-
)}
81
-
</View>
100
+
{children}
82
101
</View>
83
-
</Context.Provider>
102
+
</ToastThemeContext.Provider>
84
103
)
85
104
}
86
105
87
-
export function ToastText({children}: {children: React.ReactNode}) {
88
-
const {type} = useContext(Context)
106
+
export function Icon({icon}: {icon?: React.ComponentType<SVGIconProps>}) {
107
+
const {type} = useContext(ToastThemeContext)
108
+
const styles = useToastStyles({type})
109
+
const IconComponent = icon || ICONS[type]
110
+
return <IconComponent size="md" fill={styles.iconColor} />
111
+
}
112
+
113
+
export function Text({children}: {children: React.ReactNode}) {
114
+
const {type} = useContext(ToastThemeContext)
89
115
const {textColor} = useToastStyles({type})
116
+
const {fontScaleCompensation} = useToastFontScaleCompensation()
90
117
return (
91
-
<Text
92
-
selectable={false}
118
+
<View
93
119
style={[
94
-
a.text_md,
95
-
a.font_medium,
96
-
a.leading_snug,
97
-
a.pointer_events_none,
120
+
a.flex_1,
121
+
a.pr_lg,
98
122
{
99
-
color: textColor,
123
+
top: fontScaleCompensation,
100
124
},
101
125
]}>
102
-
{children}
103
-
</Text>
126
+
<BaseText
127
+
selectable={false}
128
+
style={[
129
+
a.text_md,
130
+
a.font_medium,
131
+
a.leading_snug,
132
+
a.pointer_events_none,
133
+
{
134
+
color: textColor,
135
+
},
136
+
]}>
137
+
{children}
138
+
</BaseText>
139
+
</View>
140
+
)
141
+
}
142
+
143
+
export function Action(
144
+
props: Omit<ButtonProps, UninheritableButtonProps | 'children'> & {
145
+
children: string
146
+
},
147
+
) {
148
+
const t = useTheme()
149
+
const {fontScaleCompensation} = useToastFontScaleCompensation()
150
+
const {type} = useContext(ToastThemeContext)
151
+
const {id} = useContext(ToastConfigContext)
152
+
const styles = useMemo(() => {
153
+
const base = {
154
+
base: {
155
+
textColor: t.palette.contrast_600,
156
+
backgroundColor: t.atoms.bg_contrast_25.backgroundColor,
157
+
},
158
+
interacted: {
159
+
textColor: t.atoms.text.color,
160
+
backgroundColor: t.atoms.bg_contrast_50.backgroundColor,
161
+
},
162
+
}
163
+
return {
164
+
default: base,
165
+
success: {
166
+
base: {
167
+
textColor: select(t.name, {
168
+
light: t.palette.primary_800,
169
+
dim: t.palette.primary_900,
170
+
dark: t.palette.primary_900,
171
+
}),
172
+
backgroundColor: t.palette.primary_25,
173
+
},
174
+
interacted: {
175
+
textColor: select(t.name, {
176
+
light: t.palette.primary_900,
177
+
dim: t.palette.primary_975,
178
+
dark: t.palette.primary_975,
179
+
}),
180
+
backgroundColor: t.palette.primary_50,
181
+
},
182
+
},
183
+
error: {
184
+
base: {
185
+
textColor: select(t.name, {
186
+
light: t.palette.negative_700,
187
+
dim: t.palette.negative_900,
188
+
dark: t.palette.negative_900,
189
+
}),
190
+
backgroundColor: t.palette.negative_25,
191
+
},
192
+
interacted: {
193
+
textColor: select(t.name, {
194
+
light: t.palette.negative_900,
195
+
dim: t.palette.negative_975,
196
+
dark: t.palette.negative_975,
197
+
}),
198
+
backgroundColor: t.palette.negative_50,
199
+
},
200
+
},
201
+
warning: base,
202
+
info: base,
203
+
}[type]
204
+
}, [t, type])
205
+
206
+
const onPress = (e: GestureResponderEvent) => {
207
+
console.log('Toast Action pressed, dismissing toast', id)
208
+
dismiss(id)
209
+
props.onPress?.(e)
210
+
}
211
+
212
+
return (
213
+
<View style={{top: fontScaleCompensation}}>
214
+
<Button {...props} onPress={onPress}>
215
+
{s => {
216
+
const interacted = s.pressed || s.hovered || s.focused
217
+
return (
218
+
<>
219
+
<View
220
+
style={[
221
+
a.absolute,
222
+
a.curve_continuous,
223
+
{
224
+
// tiny button styles
225
+
top: -5,
226
+
bottom: -5,
227
+
left: -9,
228
+
right: -9,
229
+
borderRadius: 6,
230
+
backgroundColor: interacted
231
+
? styles.interacted.backgroundColor
232
+
: styles.base.backgroundColor,
233
+
},
234
+
]}
235
+
/>
236
+
<BaseText
237
+
style={[
238
+
a.text_md,
239
+
a.font_medium,
240
+
a.leading_snug,
241
+
{
242
+
color: interacted
243
+
? styles.interacted.textColor
244
+
: styles.base.textColor,
245
+
},
246
+
]}>
247
+
{props.children}
248
+
</BaseText>
249
+
</>
250
+
)
251
+
}}
252
+
</Button>
253
+
</View>
254
+
)
255
+
}
256
+
257
+
/**
258
+
* Vibes-based number, provides t `top` value to wrap the text to compensate
259
+
* for different type sizes and keep the first line of text aligned with the
260
+
* icon. - esb
261
+
*/
262
+
function useToastFontScaleCompensation() {
263
+
const {fonts} = useAlf()
264
+
const fontScaleCompensation = useMemo(
265
+
() => parseInt(fonts.scale) * -1 * 0.65,
266
+
[fonts.scale],
267
+
)
268
+
return useMemo(
269
+
() => ({
270
+
fontScaleCompensation,
271
+
}),
272
+
[fontScaleCompensation],
104
273
)
105
274
}
106
275
+50
-7
src/components/Toast/index.tsx
+50
-7
src/components/Toast/index.tsx
···
1
+
import React from 'react'
1
2
import {View} from 'react-native'
3
+
import {nanoid} from 'nanoid/non-secure'
2
4
import {toast as sonner, Toaster} from 'sonner-native'
3
5
4
6
import {atoms as a} from '#/alf'
5
7
import {DURATION} from '#/components/Toast/const'
6
8
import {
7
-
Toast as BaseToast,
9
+
Default as DefaultToast,
10
+
Outer as BaseOuter,
8
11
type ToastComponentProps,
12
+
ToastConfigProvider,
9
13
} from '#/components/Toast/Toast'
10
14
import {type BaseToastOptions} from '#/components/Toast/types'
11
15
12
16
export {DURATION} from '#/components/Toast/const'
17
+
export {Action, Icon, Text} from '#/components/Toast/Toast'
18
+
export {type ToastType} from '#/components/Toast/types'
13
19
14
20
/**
15
21
* Toasts are rendered in a global outlet, which is placed at the top of the
···
22
28
/**
23
29
* The toast UI component
24
30
*/
25
-
export function Toast({type, content}: ToastComponentProps) {
31
+
export function Default({type, content}: ToastComponentProps) {
32
+
return (
33
+
<View style={[a.px_xl, a.w_full]}>
34
+
<DefaultToast content={content} type={type} />
35
+
</View>
36
+
)
37
+
}
38
+
39
+
export function Outer({
40
+
children,
41
+
type = 'default',
42
+
}: {
43
+
children: React.ReactNode
44
+
type?: ToastComponentProps['type']
45
+
}) {
26
46
return (
27
47
<View style={[a.px_xl, a.w_full]}>
28
-
<BaseToast content={content} type={type} />
48
+
<BaseOuter type={type}>{children}</BaseOuter>
29
49
</View>
30
50
)
31
51
}
···
42
62
content: React.ReactNode,
43
63
{type, ...options}: BaseToastOptions = {},
44
64
) {
45
-
sonner.custom(<Toast content={content} type={type} />, {
46
-
...options,
47
-
duration: options?.duration ?? DURATION,
48
-
})
65
+
const id = nanoid()
66
+
67
+
if (typeof content === 'string') {
68
+
sonner.custom(
69
+
<ToastConfigProvider id={id}>
70
+
<DefaultToast content={content} type={type} />
71
+
</ToastConfigProvider>,
72
+
{
73
+
...options,
74
+
id,
75
+
duration: options?.duration ?? DURATION,
76
+
},
77
+
)
78
+
} else if (React.isValidElement(content)) {
79
+
sonner.custom(
80
+
<ToastConfigProvider id={id}>{content}</ToastConfigProvider>,
81
+
{
82
+
...options,
83
+
id,
84
+
duration: options?.duration ?? DURATION,
85
+
},
86
+
)
87
+
} else {
88
+
throw new Error(
89
+
`Toast can be a string or a React element, got ${typeof content}`,
90
+
)
91
+
}
49
92
}
+36
-6
src/components/Toast/index.web.tsx
+36
-6
src/components/Toast/index.web.tsx
···
1
+
import React from 'react'
2
+
import {nanoid} from 'nanoid/non-secure'
1
3
import {toast as sonner, Toaster} from 'sonner'
2
4
3
5
import {atoms as a} from '#/alf'
4
6
import {DURATION} from '#/components/Toast/const'
5
-
import {Toast} from '#/components/Toast/Toast'
7
+
import {
8
+
Default as DefaultToast,
9
+
ToastConfigProvider,
10
+
} from '#/components/Toast/Toast'
6
11
import {type BaseToastOptions} from '#/components/Toast/types'
12
+
13
+
export {DURATION} from '#/components/Toast/const'
14
+
export * from '#/components/Toast/Toast'
15
+
export {type ToastType} from '#/components/Toast/types'
7
16
8
17
/**
9
18
* Toasts are rendered in a global outlet, which is placed at the top of the
···
32
41
content: React.ReactNode,
33
42
{type, ...options}: BaseToastOptions = {},
34
43
) {
35
-
sonner(<Toast content={content} type={type} />, {
36
-
unstyled: true, // required on web
37
-
...options,
38
-
duration: options?.duration ?? DURATION,
39
-
})
44
+
const id = nanoid()
45
+
46
+
if (typeof content === 'string') {
47
+
sonner(
48
+
<ToastConfigProvider id={id}>
49
+
<DefaultToast content={content} type={type} />
50
+
</ToastConfigProvider>,
51
+
{
52
+
...options,
53
+
unstyled: true, // required on web
54
+
id,
55
+
duration: options?.duration ?? DURATION,
56
+
},
57
+
)
58
+
} else if (React.isValidElement(content)) {
59
+
sonner(<ToastConfigProvider id={id}>{content}</ToastConfigProvider>, {
60
+
...options,
61
+
unstyled: true, // required on web
62
+
id,
63
+
duration: options?.duration ?? DURATION,
64
+
})
65
+
} else {
66
+
throw new Error(
67
+
`Toast can be a string or a React element, got ${typeof content}`,
68
+
)
69
+
}
40
70
}
+3
src/components/Toast/sonner/index.ts
+3
src/components/Toast/sonner/index.ts
+3
src/components/Toast/sonner/index.web.ts
+3
src/components/Toast/sonner/index.web.ts
+30
-9
src/view/com/composer/Composer.tsx
+30
-9
src/view/com/composer/Composer.tsx
···
46
46
AppBskyFeedDefs,
47
47
type AppBskyFeedGetPostThread,
48
48
AppBskyUnspeccedDefs,
49
+
AtUri,
49
50
type BskyAgent,
50
51
type RichText,
51
52
} from '@atproto/api'
52
53
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
53
54
import {msg, plural, Trans} from '@lingui/macro'
54
55
import {useLingui} from '@lingui/react'
56
+
import {useNavigation} from '@react-navigation/native'
55
57
import {useQueryClient} from '@tanstack/react-query'
56
58
57
59
import * as apilib from '#/lib/api/index'
···
70
72
import {usePalette} from '#/lib/hooks/usePalette'
71
73
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
72
74
import {mimeToExt} from '#/lib/media/video/util'
75
+
import {type NavigationProp} from '#/lib/routes/types'
73
76
import {logEvent} from '#/lib/statsig/statsig'
74
77
import {cleanError} from '#/lib/strings/errors'
75
78
import {colors} from '#/lib/styles'
···
123
126
import {UserAvatar} from '#/view/com/util/UserAvatar'
124
127
import {atoms as a, native, useTheme, web} from '#/alf'
125
128
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
129
+
import {CircleCheck_Stroke2_Corner0_Rounded as CircleCheckIcon} from '#/components/icons/CircleCheck'
126
130
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
127
131
import {EmojiArc_Stroke2_Corner0_Rounded as EmojiSmile} from '#/components/icons/Emoji'
128
132
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
129
133
import {LazyQuoteEmbed} from '#/components/Post/Embed/LazyQuoteEmbed'
130
134
import * as Prompt from '#/components/Prompt'
131
-
import * as toast from '#/components/Toast'
135
+
import * as Toast from '#/components/Toast'
132
136
import {Text as NewText} from '#/components/Typography'
133
137
import {BottomSheetPortalProvider} from '../../../../modules/bottom-sheet'
134
138
import {
···
188
192
const {closeAllDialogs} = useDialogStateControlContext()
189
193
const {closeAllModals} = useModalControls()
190
194
const {data: preferences} = usePreferencesQuery()
195
+
const navigation = useNavigation<NavigationProp>()
191
196
192
197
const [isKeyboardVisible] = useIsKeyboardVisible({iosUseWillEvents: true})
193
198
const [isPublishing, setIsPublishing] = useState(false)
···
521
526
onPostSuccess?.(postSuccessData)
522
527
}
523
528
onClose()
524
-
toast.show(
525
-
thread.posts.length > 1
526
-
? _(msg`Your posts have been published`)
527
-
: replyTo
528
-
? _(msg`Your reply has been published`)
529
-
: _(msg`Your post has been published`),
529
+
Toast.show(
530
+
<Toast.Outer type="success">
531
+
<Toast.Icon icon={CircleCheckIcon} />
532
+
<Toast.Text>
533
+
{thread.posts.length > 1
534
+
? _(msg`Your posts were sent`)
535
+
: replyTo
536
+
? _(msg`Your reply was sent`)
537
+
: _(msg`Your post was sent`)}
538
+
</Toast.Text>
539
+
{postUri && (
540
+
<Toast.Action
541
+
label={_(msg`View post`)}
542
+
onPress={() => {
543
+
const {host: name, rkey} = new AtUri(postUri)
544
+
navigation.navigate('PostThread', {name, rkey})
545
+
}}>
546
+
View
547
+
</Toast.Action>
548
+
)}
549
+
</Toast.Outer>,
530
550
{type: 'success'},
531
551
)
532
552
}, [
···
543
563
replyTo,
544
564
setLangPrefs,
545
565
queryClient,
566
+
navigation,
546
567
])
547
568
548
569
// Preserves the referential identity passed to each post item.
···
826
847
if (isNative) return // web only
827
848
const [mimeType] = uri.slice('data:'.length).split(';')
828
849
if (!SUPPORTED_MIME_TYPES.includes(mimeType as SupportedMimeTypes)) {
829
-
toast.show(_(msg`Unsupported video type: ${mimeType}`), {
850
+
Toast.show(_(msg`Unsupported video type: ${mimeType}`), {
830
851
type: 'error',
831
852
})
832
853
return
···
1362
1383
}
1363
1384
1364
1385
errors.map(error => {
1365
-
toast.show(error, {
1386
+
Toast.show(error, {
1366
1387
type: 'warning',
1367
1388
})
1368
1389
})
+72
-17
src/view/screens/Storybook/Toasts.tsx
+72
-17
src/view/screens/Storybook/Toasts.tsx
···
2
2
3
3
import {show as deprecatedShow} from '#/view/com/util/Toast'
4
4
import {atoms as a} from '#/alf'
5
-
import * as toast from '#/components/Toast'
6
-
import {Toast} from '#/components/Toast/Toast'
5
+
import {Globe_Stroke2_Corner0_Rounded as GlobeIcon} from '#/components/icons/Globe'
6
+
import * as Toast from '#/components/Toast'
7
+
import {Default} from '#/components/Toast/Toast'
7
8
import {H1} from '#/components/Typography'
8
9
10
+
function ToastWithAction({type = 'default'}: {type?: Toast.ToastType}) {
11
+
return (
12
+
<Toast.Outer type={type}>
13
+
<Toast.Icon icon={GlobeIcon} />
14
+
<Toast.Text>This toast has an action button</Toast.Text>
15
+
<Toast.Action
16
+
label="Action"
17
+
onPress={() => console.log('Action clicked!')}>
18
+
Action
19
+
</Toast.Action>
20
+
</Toast.Outer>
21
+
)
22
+
}
23
+
24
+
function LongToastWithAction({type = 'default'}: {type?: Toast.ToastType}) {
25
+
return (
26
+
<Toast.Outer type={type}>
27
+
<Toast.Icon icon={GlobeIcon} />
28
+
<Toast.Text>
29
+
This is a longer message to test how the toast handles multiple lines of
30
+
text content.
31
+
</Toast.Text>
32
+
<Toast.Action
33
+
label="Action"
34
+
onPress={() => console.log('Action clicked!')}>
35
+
Action
36
+
</Toast.Action>
37
+
</Toast.Outer>
38
+
)
39
+
}
40
+
9
41
export function Toasts() {
10
42
return (
11
43
<View style={[a.gap_md]}>
12
44
<H1>Toast Examples</H1>
13
45
14
46
<View style={[a.gap_md]}>
47
+
<View style={[a.gap_md, {marginHorizontal: a.px_xl.paddingLeft * -1}]}>
48
+
<Pressable
49
+
accessibilityRole="button"
50
+
onPress={() => Toast.show(<ToastWithAction />)}>
51
+
<ToastWithAction />
52
+
</Pressable>
53
+
<Pressable
54
+
accessibilityRole="button"
55
+
onPress={() => Toast.show(<LongToastWithAction />)}>
56
+
<LongToastWithAction />
57
+
</Pressable>
58
+
<Pressable
59
+
accessibilityRole="button"
60
+
onPress={() => Toast.show(<ToastWithAction type="success" />)}>
61
+
<ToastWithAction type="success" />
62
+
</Pressable>
63
+
<Pressable
64
+
accessibilityRole="button"
65
+
onPress={() => Toast.show(<ToastWithAction type="error" />)}>
66
+
<ToastWithAction type="error" />
67
+
</Pressable>
68
+
</View>
69
+
15
70
<Pressable
16
71
accessibilityRole="button"
17
-
onPress={() => toast.show(`Hey I'm a toast!`)}>
18
-
<Toast content="Hey I'm a toast!" />
72
+
onPress={() => Toast.show(`Hey I'm a toast!`)}>
73
+
<Default content="Hey I'm a toast!" />
19
74
</Pressable>
20
75
<Pressable
21
76
accessibilityRole="button"
22
77
onPress={() =>
23
-
toast.show(`This toast will disappear after 6 seconds`, {
78
+
Toast.show(`This toast will disappear after 6 seconds`, {
24
79
duration: 6e3,
25
80
})
26
81
}>
27
-
<Toast content="This toast will disappear after 6 seconds" />
82
+
<Default content="This toast will disappear after 6 seconds" />
28
83
</Pressable>
29
84
<Pressable
30
85
accessibilityRole="button"
31
86
onPress={() =>
32
-
toast.show(
87
+
Toast.show(
33
88
`This is a longer message to test how the toast handles multiple lines of text content.`,
34
89
)
35
90
}>
36
-
<Toast content="This is a longer message to test how the toast handles multiple lines of text content." />
91
+
<Default content="This is a longer message to test how the toast handles multiple lines of text content." />
37
92
</Pressable>
38
93
<Pressable
39
94
accessibilityRole="button"
40
95
onPress={() =>
41
-
toast.show(`Success! Yayyyyyyy :)`, {
96
+
Toast.show(`Success! Yayyyyyyy :)`, {
42
97
type: 'success',
43
98
})
44
99
}>
45
-
<Toast content="Success! Yayyyyyyy :)" type="success" />
100
+
<Default content="Success! Yayyyyyyy :)" type="success" />
46
101
</Pressable>
47
102
<Pressable
48
103
accessibilityRole="button"
49
104
onPress={() =>
50
-
toast.show(`I'm providing info!`, {
105
+
Toast.show(`I'm providing info!`, {
51
106
type: 'info',
52
107
})
53
108
}>
54
-
<Toast content="I'm providing info!" type="info" />
109
+
<Default content="I'm providing info!" type="info" />
55
110
</Pressable>
56
111
<Pressable
57
112
accessibilityRole="button"
58
113
onPress={() =>
59
-
toast.show(`This is a warning toast`, {
114
+
Toast.show(`This is a warning toast`, {
60
115
type: 'warning',
61
116
})
62
117
}>
63
-
<Toast content="This is a warning toast" type="warning" />
118
+
<Default content="This is a warning toast" type="warning" />
64
119
</Pressable>
65
120
<Pressable
66
121
accessibilityRole="button"
67
122
onPress={() =>
68
-
toast.show(`This is an error toast :(`, {
123
+
Toast.show(`This is an error toast :(`, {
69
124
type: 'error',
70
125
})
71
126
}>
72
-
<Toast content="This is an error toast :(" type="error" />
127
+
<Default content="This is an error toast :(" type="error" />
73
128
</Pressable>
74
129
75
130
<Pressable
···
80
135
'exclamation-circle',
81
136
)
82
137
}>
83
-
<Toast
138
+
<Default
84
139
content="This is a test of the deprecated API"
85
140
type="warning"
86
141
/>