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