// Styled Toast = the unstyled @tamagui/toast behavior + the default skin,
// layered here in `tamagui`. Single skin definition; the shadcn registry item is
// generated from this file. Because the behavior renders its default toast
// content internally, the styled default content lives HERE and is wired through
// Toast.List's `renderItem`, so the copy-paste registry item is a complete,
// customizable toast (no hidden styling in the behavior package).
//
// Surfaced at both the `tamagui` root (shadowing the unstyled @tamagui/toast
// composable Toast) and the `tamagui/toast` subpath. There is exactly one Toast
// API in v3 — the old imperative ToastProvider/useToastController was removed.
import {
Toast as ToastBehavior,
toast,
useToastItem,
useToasts,
type ExternalToast,
type ToastItemRenderProps,
type ToastListProps,
type ToastPosition,
type ToastRootProps,
type ToastT,
} from '@tamagui/toast'
import {
createRefComponent,
styled,
type TamaguiElement,
withStaticProperties,
} from '@tamagui/core'
import { SizableText } from '@tamagui/text'
import { XStack, YStack } from '@tamagui/stacks'
/* -------------------------------------------------------------------------------------------------
* Styled parts — the default skin over the unstyled @tamagui/toast primitives.
* -----------------------------------------------------------------------------------------------*/
export const ToastItem = styled(ToastBehavior.Item, {
displayName: 'ToastItem',
backgroundColor: 'background',
borderRadius: '6',
paddingHorizontal: '4',
paddingVertical: '3',
borderWidth: 1,
borderColor: 'border-color',
shadowColor: 'rgba(0, 0, 0, 0.15)',
shadowOffset: { width: 0, height: 4 },
shadowRadius: 12,
outlineWidth: 'focus-visible:2px',
outlineColor: 'focus-visible:color-8',
outlineStyle: 'focus-visible:solid',
})
export const ToastTitle = styled(ToastBehavior.Title, {
displayName: 'ToastTitle',
color: 'color',
fontWeight: '600',
size: '4',
})
export const ToastDescription = styled(ToastBehavior.Description, {
displayName: 'ToastDescription',
color: 'color-11',
size: '2',
})
// flat on purpose: the glyph is the whole affordance, so it only brightens on
// hover instead of carrying a chip of its own
export const ToastClose = styled(ToastBehavior.Close, {
displayName: 'ToastClose',
backgroundColor: 'transparent',
color: 'color-9 hover:color press:color',
})
export const ToastAction = styled(ToastBehavior.Action, {
displayName: 'ToastAction',
borderRadius: '2',
paddingHorizontal: '2',
backgroundColor: 'color-5 hover:color-6 press:color-7',
})
/* -------------------------------------------------------------------------------------------------
* ToastDefaultContent — the default toast body (icon / title / description /
* actions / close), styled. Rendered via Toast.List's renderItem below.
* -----------------------------------------------------------------------------------------------*/
function ToastDefaultContent({ toast: t }: { toast: ToastT }) {
const { closeButton } = useToasts()
const { handleClose } = useToastItem()
const dismissible = t.dismissible !== false
const title = typeof t.title === 'function' ? t.title() : t.title
const description =
typeof t.description === 'function' ? t.description() : t.description
return (
{title ? {title} : null}
{description ? {description} : null}
{t.action || t.cancel ? (
{t.cancel ? (
{
t.cancel?.onClick?.(e)
handleClose()
}}
>
{t.cancel.label}
) : null}
{t.action ? (
{
t.action?.onClick?.(e)
if (!(e as any).defaultPrevented) {
handleClose()
}
}}
>
{t.action.label}
) : null}
) : null}
{closeButton && dismissible ? : null}
)
}
const renderStyledToast = ({ toast: t, index }: ToastItemRenderProps) => (
)
// Capture the behavior parts up front. `withStaticProperties` assigns onto the
// component it is given, so composing directly onto ToastBehavior would rewrite
// @tamagui/toast's own Toast.List/.Item for every consumer of the unstyled
// package — and ToastList below would end up rendering itself.
const BehaviorList = ToastBehavior.List
const BehaviorViewport = ToastBehavior.Viewport
const BehaviorIcon = ToastBehavior.Icon
// Styled list — defaults renderItem to the styled default content so a bare
// `` is styled; a consumer-supplied renderItem still overrides it.
function ToastList(props: ToastListProps) {
return
}
/* -------------------------------------------------------------------------------------------------
* Toast — the styled composable API (styled parts on the behavior root).
* -----------------------------------------------------------------------------------------------*/
// A distinct root, so the styled parts hang off this skin instead of mutating
// the shared behavior component (see BehaviorList above).
const ToastRoot = createRefComponent(
function Toast(props, ref) {
return
}
)
export const Toast = withStaticProperties(ToastRoot, {
Viewport: BehaviorViewport,
List: ToastList,
Item: ToastItem,
Title: ToastTitle,
Description: ToastDescription,
Close: ToastClose,
Action: ToastAction,
Icon: BehaviorIcon,
})
// Re-export the non-visual surface so `tamagui/toast` is a drop-in for the
// styled toast: imperative API, render hooks, and the public types.
export { toast, useToastItem, useToasts }
export type { ExternalToast, ToastPosition, ToastT }