about summary refs log tree commit diff
path: root/src/components/Toast/index.tsx
diff options
context:
space:
mode:
authorEric Bailey <git@esb.lol>2025-08-26 11:20:04 -0500
committerGitHub <noreply@github.com>2025-08-26 11:20:04 -0500
commit8ec20026c042e1f26224ef2967dad6f0386e1eca (patch)
tree751add9e13a9c631724cc1c7ec120bdbc4f3a318 /src/components/Toast/index.tsx
parentacd7211b357f2bfc74bf0828994e12f0c41d39d5 (diff)
downloadvoidsky-8ec20026c042e1f26224ef2967dad6f0386e1eca.tar.zst
Yeah toast (#8878)
* Split out into macro component

* Add Action component

* Add fallback

* add button to view post after sending

* Dismiss toast when clicking action button

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
Diffstat (limited to 'src/components/Toast/index.tsx')
-rw-r--r--src/components/Toast/index.tsx57
1 files changed, 50 insertions, 7 deletions
diff --git a/src/components/Toast/index.tsx b/src/components/Toast/index.tsx
index 286d414a1..16d62afcd 100644
--- a/src/components/Toast/index.tsx
+++ b/src/components/Toast/index.tsx
@@ -1,15 +1,21 @@
+import React from 'react'
 import {View} from 'react-native'
+import {nanoid} from 'nanoid/non-secure'
 import {toast as sonner, Toaster} from 'sonner-native'
 
 import {atoms as a} from '#/alf'
 import {DURATION} from '#/components/Toast/const'
 import {
-  Toast as BaseToast,
+  Default as DefaultToast,
+  Outer as BaseOuter,
   type ToastComponentProps,
+  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 {type ToastType} from '#/components/Toast/types'
 
 /**
  * Toasts are rendered in a global outlet, which is placed at the top of the
@@ -22,10 +28,24 @@ export function ToastOutlet() {
 /**
  * The toast UI component
  */
-export function Toast({type, content}: ToastComponentProps) {
+export function Default({type, content}: ToastComponentProps) {
   return (
     <View style={[a.px_xl, a.w_full]}>
-      <BaseToast content={content} type={type} />
+      <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>
     </View>
   )
 }
@@ -42,8 +62,31 @@ export function show(
   content: React.ReactNode,
   {type, ...options}: BaseToastOptions = {},
 ) {
-  sonner.custom(<Toast content={content} type={type} />, {
-    ...options,
-    duration: options?.duration ?? DURATION,
-  })
+  const id = nanoid()
+
+  if (typeof content === 'string') {
+    sonner.custom(
+      <ToastConfigProvider id={id}>
+        <DefaultToast content={content} type={type} />
+      </ToastConfigProvider>,
+      {
+        ...options,
+        id,
+        duration: options?.duration ?? DURATION,
+      },
+    )
+  } else if (React.isValidElement(content)) {
+    sonner.custom(
+      <ToastConfigProvider id={id}>{content}</ToastConfigProvider>,
+      {
+        ...options,
+        id,
+        duration: options?.duration ?? DURATION,
+      },
+    )
+  } else {
+    throw new Error(
+      `Toast can be a string or a React element, got ${typeof content}`,
+    )
+  }
 }