Update API

This commit is contained in:
Eric Bailey
2025-07-30 11:59:33 -05:00
parent bda14b3f3c
commit 6e96d3a5f9
5 changed files with 107 additions and 45 deletions
+25 -19
View File
@@ -21,7 +21,7 @@ import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
import {atoms as a} from '#/alf'
import {Toast} from '#/components/Toast/Toast'
import {type ToastType} from '#/components/Toast/types'
import {type ToastApi, type ToastType} from '#/components/Toast/types'
const TIMEOUT = 2e3
const TOAST_ANIMATION_DURATION = 300
@@ -30,30 +30,36 @@ export function ToastContainer() {
return null
}
export function show(message: string, type: ToastType = 'default'): void {
if (process.env.NODE_ENV === 'test') {
return
}
export const toast: ToastApi = {
show(props) {
if (process.env.NODE_ENV === 'test') {
return
}
AccessibilityInfo.announceForAccessibility(message)
const item = new RootSiblings(
(
<AnimatedToast
message={message}
type={type}
destroy={() => item.destroy()}
/>
),
)
AccessibilityInfo.announceForAccessibility(props.a11yLabel)
const item = new RootSiblings(
(
<AnimatedToast
type={props.type}
content={props.content}
a11yLabel={props.a11yLabel}
destroy={() => item.destroy()}
/>
),
)
},
}
function AnimatedToast({
message,
type,
content,
a11yLabel,
destroy,
}: {
message: string
type: ToastType
content: React.ReactNode
a11yLabel: string
destroy: () => void
}) {
const {top} = useSafeAreaInsets()
@@ -169,12 +175,12 @@ function AnimatedToast({
onLayout={evt => setCardHeight(evt.nativeEvent.layout.height)}
accessibilityRole="alert"
accessible={true}
accessibilityLabel={message}
accessibilityLabel={a11yLabel}
accessibilityHint=""
onAccessibilityEscape={hideAndDestroyImmediately}
style={[a.flex_1, animatedStyle]}>
<GestureDetector gesture={panGesture}>
<Toast content={message} type={type} />
<Toast content={content} type={type} />
</GestureDetector>
</Animated.View>
)}
+23 -12
View File
@@ -3,13 +3,13 @@
*/
import {useEffect, useState} from 'react'
import {Pressable, View} from 'react-native'
import {AccessibilityInfo, Pressable, View} from 'react-native'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {atoms as a, web} from '#/alf'
import {Toast} from '#/components/Toast/Toast'
import {type ToastType} from '#/components/Toast/types'
import {type ToastApi, type ToastType} from '#/components/Toast/types'
const DURATION = 3500
const TOAST_ANIMATION_STYLES = {
@@ -22,8 +22,9 @@ const TOAST_ANIMATION_STYLES = {
}
interface ActiveToast {
text: string
type: ToastType
content: React.ReactNode
a11yLabel: string
}
type GlobalSetActiveToast = (_activeToast: ActiveToast | undefined) => void
let globalSetActiveToast: GlobalSetActiveToast | undefined
@@ -44,6 +45,9 @@ export const ToastContainer: React.FC<ToastContainerProps> = ({}) => {
setIsExiting(false)
}, 200)
} else {
if (t) {
AccessibilityInfo.announceForAccessibility(t.a11yLabel)
}
setActiveToast(t)
setIsExiting(false)
}
@@ -66,7 +70,7 @@ export const ToastContainer: React.FC<ToastContainerProps> = ({}) => {
: TOAST_ANIMATION_STYLES.entering),
},
]}>
<Toast content={activeToast.text} type={activeToast.type} />
<Toast content={activeToast.content} type={activeToast.type} />
<Pressable
style={[a.absolute, a.inset_0]}
accessibilityLabel={_(msg`Dismiss toast`)}
@@ -79,13 +83,20 @@ export const ToastContainer: React.FC<ToastContainerProps> = ({}) => {
)
}
export function show(text: string, type: ToastType = 'default') {
if (toastTimeout) {
clearTimeout(toastTimeout)
}
export const toast: ToastApi = {
show(props) {
if (toastTimeout) {
clearTimeout(toastTimeout)
}
globalSetActiveToast?.({text, type})
toastTimeout = setTimeout(() => {
globalSetActiveToast?.(undefined)
}, DURATION)
globalSetActiveToast?.({
type: props.type,
content: props.content,
a11yLabel: props.a11yLabel,
})
toastTimeout = setTimeout(() => {
globalSetActiveToast?.(undefined)
}, DURATION)
},
}
+8
View File
@@ -1 +1,9 @@
export type ToastType = 'default' | 'success' | 'error' | 'warning' | 'info'
export type ToastApi = {
show: (props: {
type: ToastType
content: React.ReactNode
a11yLabel: string
}) => void
}
+8 -4
View File
@@ -1,8 +1,8 @@
import {show as baseShow} from '#/components/Toast'
import {toast} from '#/components/Toast'
import {type ToastType} from '#/components/Toast/types'
/**
* @deprecated use {@link ToastType} and {@link baseShow} instead
* @deprecated use {@link ToastType} and {@link toast} instead
*/
export type LegacyToastType =
| 'xmark'
@@ -39,12 +39,16 @@ export const convertLegacyToastType = (
}
/**
* @deprecated use {@link baseShow} instead
* @deprecated use {@link toast} instead
*/
export function show(
message: string,
type: ToastType | LegacyToastType = 'default',
): void {
const convertedType = convertLegacyToastType(type)
baseShow(message, convertedType)
toast.show({
type: convertedType,
content: message,
a11yLabel: message,
})
}
+43 -10
View File
@@ -3,7 +3,7 @@ import {Pressable, View} from 'react-native'
import {show as deprecatedShow} from '#/view/com/util/Toast'
import {atoms as a} from '#/alf'
import {Button, ButtonText} from '#/components/Button'
import {show} from '#/components/Toast'
import {toast} from '#/components/Toast'
import {Toast} from '#/components/Toast/Toast'
import {H1} from '#/components/Typography'
@@ -15,16 +15,25 @@ export function Toasts() {
<View style={[a.gap_md]}>
<Pressable
accessibilityRole="button"
onPress={() => show('Default toast', 'default')}>
onPress={() =>
toast.show({
type: 'default',
content: 'Default toast',
a11yLabel: 'Default toast',
})
}>
<Toast content="Default toast" type="default" />
</Pressable>
<Pressable
accessibilityRole="button"
onPress={() =>
show(
'This is a longer message to test how the toast handles multiple lines of text content.',
'default',
)
toast.show({
type: 'default',
content:
'This is a longer message to test how the toast handles multiple lines of text content.',
a11yLabel:
'This is a longer message to test how the toast handles multiple lines of text content.',
})
}>
<Toast
content="This is a longer message to test how the toast handles multiple lines of text content."
@@ -33,22 +42,46 @@ export function Toasts() {
</Pressable>
<Pressable
accessibilityRole="button"
onPress={() => show('Success toast', 'success')}>
onPress={() =>
toast.show({
type: 'success',
content: 'Success toast',
a11yLabel: 'Success toast',
})
}>
<Toast content="Success toast" type="success" />
</Pressable>
<Pressable
accessibilityRole="button"
onPress={() => show('Info toast', 'info')}>
onPress={() =>
toast.show({
type: 'info',
content: 'Info toast',
a11yLabel: 'Info toast',
})
}>
<Toast content="Info" type="info" />
</Pressable>
<Pressable
accessibilityRole="button"
onPress={() => show('Warning toast', 'warning')}>
onPress={() =>
toast.show({
type: 'warning',
content: 'Warning toast',
a11yLabel: 'Warning toast',
})
}>
<Toast content="Warning" type="warning" />
</Pressable>
<Pressable
accessibilityRole="button"
onPress={() => show('Error toast', 'error')}>
onPress={() =>
toast.show({
type: 'error',
content: 'Error toast',
a11yLabel: 'Error toast',
})
}>
<Toast content="Error" type="error" />
</Pressable>