about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/Toast/Toast.tsx91
-rw-r--r--src/components/Toast/index.e2e.tsx8
-rw-r--r--src/components/Toast/index.tsx40
-rw-r--r--src/components/Toast/index.web.tsx30
-rw-r--r--src/view/com/composer/Composer.tsx9
-rw-r--r--src/view/screens/Storybook/Toasts.tsx80
6 files changed, 123 insertions, 135 deletions
diff --git a/src/components/Toast/Toast.tsx b/src/components/Toast/Toast.tsx
index 53d5e5115..ac5bc4889 100644
--- a/src/components/Toast/Toast.tsx
+++ b/src/components/Toast/Toast.tsx
@@ -16,19 +16,6 @@ import {dismiss} from '#/components/Toast/sonner'
 import {type ToastType} from '#/components/Toast/types'
 import {Text as BaseText} from '#/components/Typography'
 
-type ToastConfigContextType = {
-  id: string
-}
-
-type ToastThemeContextType = {
-  type: ToastType
-}
-
-export type ToastComponentProps = {
-  type?: ToastType
-  content: string
-}
-
 export const ICONS = {
   default: CircleCheck,
   success: CircleCheck,
@@ -37,81 +24,67 @@ export const ICONS = {
   info: CircleInfo,
 }
 
-const ToastConfigContext = createContext<ToastConfigContextType>({
+const ToastConfigContext = createContext<{
+  id: string
+  type: ToastType
+}>({
   id: '',
+  type: 'default',
 })
 ToastConfigContext.displayName = 'ToastConfigContext'
 
 export function ToastConfigProvider({
   children,
   id,
+  type,
 }: {
   children: React.ReactNode
   id: string
+  type: ToastType
 }) {
   return (
-    <ToastConfigContext.Provider value={useMemo(() => ({id}), [id])}>
+    <ToastConfigContext.Provider
+      value={useMemo(() => ({id, type}), [id, type])}>
       {children}
     </ToastConfigContext.Provider>
   )
 }
 
-const ToastThemeContext = createContext<ToastThemeContextType>({
-  type: 'default',
-})
-ToastThemeContext.displayName = 'ToastThemeContext'
-
-export function Default({type = 'default', content}: ToastComponentProps) {
-  return (
-    <Outer type={type}>
-      <Icon />
-      <Text>{content}</Text>
-    </Outer>
-  )
-}
-
-export function Outer({
-  children,
-  type = 'default',
-}: {
-  children: React.ReactNode
-  type?: ToastType
-}) {
+export function Outer({children}: {children: React.ReactNode}) {
   const t = useTheme()
+  const {type} = useContext(ToastConfigContext)
   const styles = useToastStyles({type})
 
   return (
-    <ToastThemeContext.Provider value={useMemo(() => ({type}), [type])}>
-      <View
-        style={[
-          a.flex_1,
-          a.p_lg,
-          a.rounded_md,
-          a.border,
-          a.flex_row,
-          a.gap_sm,
-          t.atoms.shadow_sm,
-          {
-            paddingVertical: 14, // 16 seems too big
-            backgroundColor: styles.backgroundColor,
-            borderColor: styles.borderColor,
-          },
-        ]}>
-        {children}
-      </View>
-    </ToastThemeContext.Provider>
+    <View
+      style={[
+        a.flex_1,
+        a.p_lg,
+        a.rounded_md,
+        a.border,
+        a.flex_row,
+        a.gap_sm,
+        t.atoms.shadow_sm,
+        {
+          paddingVertical: 14, // 16 seems too big
+          backgroundColor: styles.backgroundColor,
+          borderColor: styles.borderColor,
+        },
+      ]}>
+      {children}
+    </View>
   )
 }
 
 export function Icon({icon}: {icon?: React.ComponentType<SVGIconProps>}) {
-  const {type} = useContext(ToastThemeContext)
+  const {type} = useContext(ToastConfigContext)
   const styles = useToastStyles({type})
   const IconComponent = icon || ICONS[type]
   return <IconComponent size="md" fill={styles.iconColor} />
 }
 
 export function Text({children}: {children: React.ReactNode}) {
-  const {type} = useContext(ToastThemeContext)
+  const {type} = useContext(ToastConfigContext)
   const {textColor} = useToastStyles({type})
   const {fontScaleCompensation} = useToastFontScaleCompensation()
   return (
@@ -142,12 +115,12 @@ export function Text({children}: {children: React.ReactNode}) {
 
 export function Action(
   props: Omit<ButtonProps, UninheritableButtonProps | 'children'> & {
-    children: string
+    children: React.ReactNode
   },
 ) {
   const t = useTheme()
   const {fontScaleCompensation} = useToastFontScaleCompensation()
-  const {type} = useContext(ToastThemeContext)
+  const {type} = useContext(ToastConfigContext)
   const {id} = useContext(ToastConfigContext)
   const styles = useMemo(() => {
     const base = {
diff --git a/src/components/Toast/index.e2e.tsx b/src/components/Toast/index.e2e.tsx
index 357bd8dda..a4056323d 100644
--- a/src/components/Toast/index.e2e.tsx
+++ b/src/components/Toast/index.e2e.tsx
@@ -1,3 +1,11 @@
+export const DURATION = 0
+
+export const Action = () => null
+export const Icon = () => null
+export const Outer = () => null
+export const Text = () => null
+export const ToastConfigProvider = () => null
+
 export function ToastOutlet() {
   return null
 }
diff --git a/src/components/Toast/index.tsx b/src/components/Toast/index.tsx
index 0d1c661d2..d70a8ad16 100644
--- a/src/components/Toast/index.tsx
+++ b/src/components/Toast/index.tsx
@@ -6,15 +6,15 @@ import {toast as sonner, Toaster} from 'sonner-native'
 import {atoms as a} from '#/alf'
 import {DURATION} from '#/components/Toast/const'
 import {
-  Default as DefaultToast,
+  Icon as ToastIcon,
   Outer as BaseOuter,
-  type ToastComponentProps,
+  Text as ToastText,
   ToastConfigProvider,
 } from '#/components/Toast/Toast'
 import {type BaseToastOptions} from '#/components/Toast/types'
 
 export {DURATION} from '#/components/Toast/const'
-export {Action, Icon, Text} from '#/components/Toast/Toast'
+export {Action, Icon, Text, ToastConfigProvider} from '#/components/Toast/Toast'
 export {type ToastType} from '#/components/Toast/types'
 
 /**
@@ -25,27 +25,10 @@ export function ToastOutlet() {
   return <Toaster pauseWhenPageIsHidden gap={a.gap_sm.gap} />
 }
 
-/**
- * The toast UI component
- */
-export function Default({type, content}: ToastComponentProps) {
+export function Outer({children}: {children: React.ReactNode}) {
   return (
     <View style={[a.px_xl, a.w_full]}>
-      <DefaultToast content={content} type={type} />
-    </View>
-  )
-}
-
-export function Outer({
-  children,
-  type = 'default',
-}: {
-  children: React.ReactNode
-  type?: ToastComponentProps['type']
-}) {
-  return (
-    <View style={[a.px_xl, a.w_full]}>
-      <BaseOuter type={type}>{children}</BaseOuter>
+      <BaseOuter>{children}</BaseOuter>
     </View>
   )
 }
@@ -60,14 +43,17 @@ export const api = sonner
  */
 export function show(
   content: React.ReactNode,
-  {type, ...options}: BaseToastOptions = {},
+  {type = 'default', ...options}: BaseToastOptions = {},
 ) {
   const id = nanoid()
 
   if (typeof content === 'string') {
     sonner.custom(
-      <ToastConfigProvider id={id}>
-        <Default content={content} type={type} />
+      <ToastConfigProvider id={id} type={type}>
+        <Outer>
+          <ToastIcon />
+          <ToastText>{content}</ToastText>
+        </Outer>
       </ToastConfigProvider>,
       {
         ...options,
@@ -77,7 +63,9 @@ export function show(
     )
   } else if (React.isValidElement(content)) {
     sonner.custom(
-      <ToastConfigProvider id={id}>{content}</ToastConfigProvider>,
+      <ToastConfigProvider id={id} type={type}>
+        {content}
+      </ToastConfigProvider>,
       {
         ...options,
         id,
diff --git a/src/components/Toast/index.web.tsx b/src/components/Toast/index.web.tsx
index c4db20dca..8b2028db9 100644
--- a/src/components/Toast/index.web.tsx
+++ b/src/components/Toast/index.web.tsx
@@ -5,7 +5,9 @@ import {toast as sonner, Toaster} from 'sonner'
 import {atoms as a} from '#/alf'
 import {DURATION} from '#/components/Toast/const'
 import {
-  Default as DefaultToast,
+  Icon as ToastIcon,
+  Outer as ToastOuter,
+  Text as ToastText,
   ToastConfigProvider,
 } from '#/components/Toast/Toast'
 import {type BaseToastOptions} from '#/components/Toast/types'
@@ -39,14 +41,17 @@ export const api = sonner
  */
 export function show(
   content: React.ReactNode,
-  {type, ...options}: BaseToastOptions = {},
+  {type = 'default', ...options}: BaseToastOptions = {},
 ) {
   const id = nanoid()
 
   if (typeof content === 'string') {
     sonner(
-      <ToastConfigProvider id={id}>
-        <DefaultToast content={content} type={type} />
+      <ToastConfigProvider id={id} type={type}>
+        <ToastOuter>
+          <ToastIcon />
+          <ToastText>{content}</ToastText>
+        </ToastOuter>
       </ToastConfigProvider>,
       {
         ...options,
@@ -56,12 +61,17 @@ export function show(
       },
     )
   } else if (React.isValidElement(content)) {
-    sonner(<ToastConfigProvider id={id}>{content}</ToastConfigProvider>, {
-      ...options,
-      unstyled: true, // required on web
-      id,
-      duration: options?.duration ?? DURATION,
-    })
+    sonner(
+      <ToastConfigProvider id={id} type={type}>
+        {content}
+      </ToastConfigProvider>,
+      {
+        ...options,
+        unstyled: true, // required on web
+        id,
+        duration: options?.duration ?? DURATION,
+      },
+    )
   } else {
     throw new Error(
       `Toast can be a string or a React element, got ${typeof content}`,
diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx
index 7d4eb8ca7..6d22e4b54 100644
--- a/src/view/com/composer/Composer.tsx
+++ b/src/view/com/composer/Composer.tsx
@@ -126,7 +126,6 @@ import {Text} from '#/view/com/util/text/Text'
 import {UserAvatar} from '#/view/com/util/UserAvatar'
 import {atoms as a, native, useTheme, web} from '#/alf'
 import {Button, ButtonIcon, ButtonText} from '#/components/Button'
-import {CircleCheck_Stroke2_Corner0_Rounded as CircleCheckIcon} from '#/components/icons/CircleCheck'
 import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
 import {EmojiArc_Stroke2_Corner0_Rounded as EmojiSmile} from '#/components/icons/Emoji'
 import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
@@ -527,8 +526,8 @@ export const ComposePost = ({
     }
     onClose()
     Toast.show(
-      <Toast.Outer type="success">
-        <Toast.Icon icon={CircleCheckIcon} />
+      <Toast.Outer>
+        <Toast.Icon />
         <Toast.Text>
           {thread.posts.length > 1
             ? _(msg`Your posts were sent`)
@@ -543,7 +542,9 @@ export const ComposePost = ({
               const {host: name, rkey} = new AtUri(postUri)
               navigation.navigate('PostThread', {name, rkey})
             }}>
-            View
+            <Trans context="Action to view the post the user just created">
+              View
+            </Trans>
           </Toast.Action>
         )}
       </Toast.Outer>,
diff --git a/src/view/screens/Storybook/Toasts.tsx b/src/view/screens/Storybook/Toasts.tsx
index 319f88e21..91fe0d970 100644
--- a/src/view/screens/Storybook/Toasts.tsx
+++ b/src/view/screens/Storybook/Toasts.tsx
@@ -4,12 +4,28 @@ import {show as deprecatedShow} from '#/view/com/util/Toast'
 import {atoms as a} from '#/alf'
 import {Globe_Stroke2_Corner0_Rounded as GlobeIcon} from '#/components/icons/Globe'
 import * as Toast from '#/components/Toast'
-import {Default} from '#/components/Toast/Toast'
 import {H1} from '#/components/Typography'
 
-function ToastWithAction({type = 'default'}: {type?: Toast.ToastType}) {
+function DefaultToast({
+  content,
+  type = 'default',
+}: {
+  content: string
+  type?: Toast.ToastType
+}) {
   return (
-    <Toast.Outer type={type}>
+    <Toast.ToastConfigProvider id="default-toast" type={type}>
+      <Toast.Outer>
+        <Toast.Icon icon={GlobeIcon} />
+        <Toast.Text>{content}</Toast.Text>
+      </Toast.Outer>
+    </Toast.ToastConfigProvider>
+  )
+}
+
+function ToastWithAction() {
+  return (
+    <Toast.Outer>
       <Toast.Icon icon={GlobeIcon} />
       <Toast.Text>This toast has an action button</Toast.Text>
       <Toast.Action
@@ -21,9 +37,9 @@ function ToastWithAction({type = 'default'}: {type?: Toast.ToastType}) {
   )
 }
 
-function LongToastWithAction({type = 'default'}: {type?: Toast.ToastType}) {
+function LongToastWithAction() {
   return (
-    <Toast.Outer type={type}>
+    <Toast.Outer>
       <Toast.Icon icon={GlobeIcon} />
       <Toast.Text>
         This is a longer message to test how the toast handles multiple lines of
@@ -44,33 +60,25 @@ export function Toasts() {
       <H1>Toast Examples</H1>
 
       <View style={[a.gap_md]}>
-        <View style={[a.gap_md, {marginHorizontal: a.px_xl.paddingLeft * -1}]}>
-          <Pressable
-            accessibilityRole="button"
-            onPress={() => Toast.show(<ToastWithAction />)}>
-            <ToastWithAction />
-          </Pressable>
-          <Pressable
-            accessibilityRole="button"
-            onPress={() => Toast.show(<LongToastWithAction />)}>
-            <LongToastWithAction />
-          </Pressable>
-          <Pressable
-            accessibilityRole="button"
-            onPress={() => Toast.show(<ToastWithAction type="success" />)}>
-            <ToastWithAction type="success" />
-          </Pressable>
-          <Pressable
-            accessibilityRole="button"
-            onPress={() => Toast.show(<ToastWithAction type="error" />)}>
-            <ToastWithAction type="error" />
-          </Pressable>
-        </View>
-
+        <Pressable
+          accessibilityRole="button"
+          onPress={() => Toast.show(<ToastWithAction />, {type: 'success'})}>
+          <ToastWithAction />
+        </Pressable>
+        <Pressable
+          accessibilityRole="button"
+          onPress={() => Toast.show(<ToastWithAction />, {type: 'error'})}>
+          <ToastWithAction />
+        </Pressable>
+        <Pressable
+          accessibilityRole="button"
+          onPress={() => Toast.show(<LongToastWithAction />)}>
+          <LongToastWithAction />
+        </Pressable>
         <Pressable
           accessibilityRole="button"
           onPress={() => Toast.show(`Hey I'm a toast!`)}>
-          <Default content="Hey I'm a toast!" />
+          <DefaultToast content="Hey I'm a toast!" />
         </Pressable>
         <Pressable
           accessibilityRole="button"
@@ -79,7 +87,7 @@ export function Toasts() {
               duration: 6e3,
             })
           }>
-          <Default content="This toast will disappear after 6 seconds" />
+          <DefaultToast content="This toast will disappear after 6 seconds" />
         </Pressable>
         <Pressable
           accessibilityRole="button"
@@ -88,7 +96,7 @@ export function Toasts() {
               `This is a longer message to test how the toast handles multiple lines of text content.`,
             )
           }>
-          <Default content="This is a longer message to test how the toast handles multiple lines of text content." />
+          <DefaultToast content="This is a longer message to test how the toast handles multiple lines of text content." />
         </Pressable>
         <Pressable
           accessibilityRole="button"
@@ -97,7 +105,7 @@ export function Toasts() {
               type: 'success',
             })
           }>
-          <Default content="Success! Yayyyyyyy :)" type="success" />
+          <DefaultToast content="Success! Yayyyyyyy :)" type="success" />
         </Pressable>
         <Pressable
           accessibilityRole="button"
@@ -106,7 +114,7 @@ export function Toasts() {
               type: 'info',
             })
           }>
-          <Default content="I'm providing info!" type="info" />
+          <DefaultToast content="I'm providing info!" type="info" />
         </Pressable>
         <Pressable
           accessibilityRole="button"
@@ -115,7 +123,7 @@ export function Toasts() {
               type: 'warning',
             })
           }>
-          <Default content="This is a warning toast" type="warning" />
+          <DefaultToast content="This is a warning toast" type="warning" />
         </Pressable>
         <Pressable
           accessibilityRole="button"
@@ -124,7 +132,7 @@ export function Toasts() {
               type: 'error',
             })
           }>
-          <Default content="This is an error toast :(" type="error" />
+          <DefaultToast content="This is an error toast :(" type="error" />
         </Pressable>
 
         <Pressable
@@ -135,7 +143,7 @@ export function Toasts() {
               'exclamation-circle',
             )
           }>
-          <Default
+          <DefaultToast
             content="This is a test of the deprecated API"
             type="warning"
           />