الانتقال إلى المحتوى

Sonner

إشعارات متراكبة على شكل شرائح خبز محمص لتأكيدات الحفظ وعمليات التحميل ونوافذ التراجع — مع أسلوب «النيوبروتاليست» في تصميم الحدود والظلال.

"use client"

import { toast } from "sonner"

يعرض Sonner إشعارات متراكبة تُغلق تلقائيًا على الشاشة من خلال استدعاء واحد لـ toast() — قم بتركيب <Toaster /> واحد وأطلق الإشعارات من أي مكان، دون الحاجة إلى ربط السياق. هذه ليست عنصرًا أساسيًّا في واجهة المستخدم Radix أو Base: فكل من متغيرات الخلفية هذه تغلف نفس مكتبة Sonner بواسطة emilkowalski، المصممة وفقًا لوصفة النمط «النيوبروتاليةي»: حدود سميكة، وظلال حادة، وخط عريض.

استخدمه عندما:

  • ردود فعل على الإجراءات — «تم الحفظ»، «تم النسخ إلى الحافظة»، «تم تحديث الإعدادات» بعد اكتمال التغيير.
  • العمليات غير المتزامنة — يتتبع toast.promise() عملية التحميل أو النشر بدءًا من التحميل وحتى النجاح أو الخطأ في إشعار واحد.
  • نوافذ التراجع — الحذف والأرشفة باستخدام زر إجراء، بحيث تحصل العمليات المدمرة على فترة سماح.

نبذة

Sonner مبني ومُصان بواسطة emilkowalski.

التثبيت

شغّل الأمر التالي:

pnpm dlx shadcn@latest add https://neobrutalism.com/r/base/sonner.json
npx shadcn@latest add https://neobrutalism.com/r/base/sonner.json
yarn dlx shadcn@latest add https://neobrutalism.com/r/base/sonner.json
bunx --bun shadcn@latest add https://neobrutalism.com/r/base/sonner.json

أضف المكوّن Toaster.

app/layout.tsx
import { Toaster } from "@/components/ui/sonner"
 
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head />
      <body>
        <main>{children}</main>
        <Toaster />
      </body>
    </html>
  )
}

ثبّت التبعيات التالية:

pnpm add sonner next-themes
npm install sonner next-themes
yarn add sonner next-themes
bun add sonner next-themes

انسخ الكود التالي والصقه في مشروعك.

components/ui/sonner.tsx
"use client"

import {
  CircleCheckIcon,
  InfoIcon,
  Loader2Icon,
  OctagonXIcon,
  TriangleAlertIcon,
} from "lucide-react"
import { useTheme } from "next-themes"
import { Toaster as Sonner, type ToasterProps } from "sonner"

const Toaster = ({ ...props }: ToasterProps) => {
  const { theme = "system" } = useTheme()

  return (
    <Sonner
      theme={theme as ToasterProps["theme"]}
      className="toaster group"
      icons={{
        success: <CircleCheckIcon className="size-4" />,
        info: <InfoIcon className="size-4" />,
        warning: <TriangleAlertIcon className="size-4" />,
        error: <OctagonXIcon className="size-4" />,
        loading: <Loader2Icon className="size-4 animate-spin" />,
      }}
      toastOptions={{
        // Fully unstyled so the neobrutalist recipe below owns every surface:
        // hard offset shadow, 2px border, square corners, press-down buttons.
        unstyled: true,
        classNames: {
          toast:
            "group/toast relative flex w-(--width) items-center gap-3 rounded border-2 border-border bg-popover p-4 font-sans text-popover-foreground shadow-md",
          content: "flex min-w-0 flex-col gap-0.5",
          title: "font-head text-sm font-medium",
          description: "text-sm text-muted-foreground",
          icon: "shrink-0",
          actionButton:
            "ms-auto h-fit min-w-fit shrink-0 rounded border-2 border-border bg-primary px-2 py-1 text-xs font-medium text-primary-foreground shadow-sm transition-all duration-200 hover:translate-x-0.5 hover:translate-y-0.5 hover:shadow-none",
          cancelButton:
            "ms-auto h-fit min-w-fit shrink-0 rounded border-2 border-border bg-muted px-2 py-1 text-xs font-medium text-foreground shadow-sm transition-all duration-200 hover:translate-x-0.5 hover:translate-y-0.5 hover:shadow-none",
          closeButton:
            "absolute -top-2 -start-2 rounded-full border-2 border-border bg-background p-0.5 transition-colors hover:bg-muted",
          success: "[&_[data-icon]]:text-chart-2",
          warning: "[&_[data-icon]]:text-chart-1",
          error: "[&_[data-icon]]:text-destructive",
        },
      }}
      {...props}
    />
  )
}

export { Toaster }

أضف المكوّن Toaster.

app/layout.tsx
import { Toaster } from "@/components/ui/sonner"
 
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <head />
      <body>
        <Toaster />
        <main>{children}</main>
      </body>
    </html>
  )
}

الاستخدام

import { toast } from "sonner"
toast("Event has been created.")

أمثلة

الأنواع

"use client"

import { toast } from "sonner"

الوصف

"use client"

import { toast } from "sonner"

الموضع

استخدم الخاصية position لتغيير موضع الإشعار المنبثق.

"use client"

import { toast } from "sonner"

إمكانية الوصول

لا يوجد نمط مخصص من أنماط WAI-ARIA APG لإشعارات toasts؛ وأقرب توجيه هو Alert pattern. يقوم Sonner بعرض إشعارات toasts في منطقة ARIA الحية polite، بحيث تقوم برامج قراءة الشاشة بإعلانها دون سرقة التركيز. تقع هذه المنطقة خارج ترتيب التبويب العادي — ولا يمكن الوصول إليها إلا عبر مفتاح الاختصار — وتتوقف مؤقتات الإغلاق مؤقتًا عند تمرير المؤشر فوق المكدس أو التركيز عليه أو إخفاء علامة التبويب.

تفاعلات لوحة المفاتيح:

المفتاحالإجراء
Alt + Tالتركيز على مكدس الإشعارات المنبثقة وتوسيعه (قابل للتكوين عبر الخاصية hotkey في Toaster)
Tab / Shift + Tabالتنقل بين الإشعارات المنبثقة وأزرار الإجراءات/الإغلاق الخاصة بها
Enter / Spaceتنشيط الإجراء الذي تم التركيز عليه أو زر الإغلاق
Escapeطي مكدس الإشعارات أثناء وجود التركيز بداخله

مرجع API

لمزيد من المعلومات، راجع وثائق Sonner.