Defer AppView wait behind a pending toast on post

Step 5 of sending a post (waiting for the AppView to index the new record)
can take an unbounded amount of time, but the post is already created after
step 4. Close the composer immediately after the record is written and show
a pending toast while the AppView wait runs in the background. When it
settles, swap the pending toast in place for the existing success toast.

Adds a 'pending' ToastType that renders a spinner via the existing Loader,
and a new Toast.promise() helper that drives the in-place swap on both
sonner and sonner-native.
This commit is contained in:
Claude
2026-05-17 09:38:18 +00:00
parent 45597de6e0
commit f03bf2a65f
7 changed files with 243 additions and 103 deletions
+12
View File
@@ -12,6 +12,7 @@ import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/ico
import {CircleInfo_Stroke2_Corner0_Rounded as ErrorIcon} from '#/components/icons/CircleInfo'
import {type Props as SVGIconProps} from '#/components/icons/common'
import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning'
import {Loader} from '#/components/Loader'
import {dismiss} from '#/components/Toast/sonner'
import {type ToastType} from '#/components/Toast/types'
import {Text as BaseText} from '#/components/Typography'
@@ -22,6 +23,7 @@ export const ICONS = {
error: ErrorIcon,
warning: WarningIcon,
info: CircleInfo,
pending: CircleCheck,
}
const ToastConfigContext = createContext<{
@@ -79,6 +81,9 @@ export function Outer({children}: {children: React.ReactNode}) {
export function Icon({icon}: {icon?: React.ComponentType<SVGIconProps>}) {
const {type} = useContext(ToastConfigContext)
const styles = useToastStyles({type})
if (!icon && type === 'pending') {
return <Loader size="md" fill={styles.iconColor} />
}
const IconComponent = icon || ICONS[type]
return <IconComponent size="md" fill={styles.iconColor} />
}
@@ -173,6 +178,7 @@ export function Action(
},
warning: base,
info: base,
pending: base,
}[type]
}, [t, type])
@@ -304,6 +310,12 @@ function useToastStyles({type}: {type: ToastType}) {
iconColor: t.atoms.text.color,
textColor: t.atoms.text.color,
},
pending: {
backgroundColor: t.atoms.bg_contrast_25.backgroundColor,
borderColor: t.atoms.border_contrast_low.borderColor,
iconColor: t.atoms.text.color,
textColor: t.atoms.text.color,
},
}[type]
}, [t, type])
}