Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
"input-otp": "^1.4.2",
"lucide-react": "^0.563.0",
"recharts": "^2.15.4",
"sonner": "^2.0.7",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Sonner 2.0.7 peerDependencies ==="
npm view sonner@2.0.7 peerDependencies --json

echo ""
echo "=== Current library peerDependencies ==="
python - <<'PY'
import json
with open("package.json") as f:
    pkg = json.load(f)
print(json.dumps(pkg.get("peerDependencies", {}), indent=2))
PY

Repository: getdokan/plugin-ui

Length of output: 295


Update peerDependencies to reflect Sonner's React 18+ requirement.

Sonner 2.0.7 requires react@^18.0.0 || ^19.0.0 and react-dom@^18.0.0 || ^19.0.0, but the current peer ranges declare >=17.0.0. This mismatch creates install conflicts for consumers using React 17. Update peer ranges to >=18.0.0:

Proposed fix
  "peerDependencies": {
-    "react": ">=17.0.0",
-    "react-dom": ">=17.0.0"
+    "react": ">=18.0.0",
+    "react-dom": ">=18.0.0"
  },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` at line 78, Update the package.json peerDependencies so they
match Sonner 2.x's React requirement: in package.json's "peerDependencies"
replace the current react and react-dom ranges that allow ">=17.0.0" with ranges
that require React 18+ (e.g., ">=18.0.0" or the equivalent semver like "^18.0.0
|| ^19.0.0") so the declared peers align with the installed "sonner": "^2.0.7"
constraint.

"tailwind-merge": "^2.6.1",
"tw-animate-css": "^1.4.0"
},
Expand Down
244 changes: 244 additions & 0 deletions src/components/ui/Sonner.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
import type { Meta, StoryObj } from "@storybook/react";
import { toast } from "sonner";
import { Toaster } from "./sonner";
import { Button } from "./button";

const meta = {
title: "UI/Sonner",
component: Toaster,
parameters: { layout: "centered" },
tags: ["autodocs"],
} satisfies Meta<typeof Toaster>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
render: () => (
<>
<div className="flex flex-wrap gap-2">
<Button
variant="outline"
onClick={() => toast("Event has been created.")}
>
Default
</Button>
<Button
variant="outline"
onClick={() =>
toast("Event has been created", {
description: "Sunday, December 03, 2023 at 9:00 AM",
})
}
>
With Description
</Button>
<Button
variant="outline"
onClick={() => toast.success("Event has been created.")}
>
Success
</Button>
<Button
variant="outline"
onClick={() =>
toast.info("Be at the area 10 minutes before the event time.")
}
>
Info
</Button>
<Button
variant="outline"
onClick={() =>
toast.warning("Event start time cannot be earlier than 8am.")
}
>
Warning
</Button>
<Button
variant="outline"
onClick={() => toast.error("Event has not been created.")}
>
Error
</Button>
<Button
variant="outline"
onClick={() => toast.loading("Loading data...")}
>
Loading
</Button>
<Button
variant="outline"
onClick={() =>
toast("Event has been created", {
action: {
label: "Undo",
onClick: () => console.log("Undo"),
},
})
}
>
With Action
</Button>
<Button
variant="outline"
onClick={() =>
toast("Event has been created", {
cancel: {
label: "Cancel",
onClick: () => console.log("Cancel"),
},
})
}
>
With Cancel
</Button>
<Button
variant="outline"
onClick={() => {
toast.promise(
() =>
new window.Promise<{ name: string }>((resolve) =>
setTimeout(() => resolve({ name: "Sonner" }), 2000)
),
{
loading: "Loading...",
success: (data) => `${data.name} toast has been added`,
error: "Error",
}
);
}}
>
Promise
</Button>
<Button
variant="outline"
onClick={() =>
toast(
<div className="flex flex-col gap-1">
<span className="font-semibold">Custom Toast</span>
<span className="text-sm text-muted-foreground">
This is a toast with{" "}
<a href="#" className="underline font-medium">
custom JSX
</a>{" "}
content.
</span>
</div>
)
}
>
Custom JSX
</Button>
</div>
<Toaster />
</>
),
};

export const Positions: Story = {
render: () => {
const positions = [
"top-left",
"top-center",
"top-right",
"bottom-left",
"bottom-center",
"bottom-right",
] as const;

return (
<>
<div className="flex flex-wrap gap-2">
{positions.map((position) => (
<Button
key={position}
variant="outline"
onClick={() =>
toast("Event has been created", {
description: `Position: ${position}`,
position,
})
}
>
{position}
</Button>
))}
</div>
<Toaster />
</>
);
},
};

export const RichColors: Story = {
render: () => (
<>
<div className="flex flex-wrap gap-2">
<Button
variant="outline"
onClick={() => toast.success("Event has been created")}
>
Success
</Button>
<Button
variant="outline"
onClick={() => toast.info("Be at the area 10 minutes before")}
>
Info
</Button>
<Button
variant="outline"
onClick={() =>
toast.warning("Event time cannot be earlier than 8am")
}
>
Warning
</Button>
<Button
variant="outline"
onClick={() => toast.error("Event has not been created")}
>
Error
</Button>
</div>
<Toaster richColors />
</>
),
};

export const CloseButton: Story = {
render: () => (
<>
<Button
variant="outline"
onClick={() =>
toast("Event has been created", {
description: "This toast has a close button.",
})
}
>
With Close Button
</Button>
<Toaster closeButton />
</>
),
};

export const Expanded: Story = {
render: () => (
<>
<Button
variant="outline"
onClick={() => {
toast("First notification");
setTimeout(() => toast.success("Second notification"), 300);
setTimeout(() => toast.info("Third notification"), 600);
}}
>
Show Expanded Toasts
</Button>
<Toaster expand />
</>
),
};
3 changes: 3 additions & 0 deletions src/components/ui/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,9 @@ export {
type LayoutContextValue,
} from "../wordpress/layout";

// Sonner (toast notifications)
export { Toaster } from "./sonner";

// Layout menu (searchable, multi-label nested menu for LayoutSidebar)
export {
LayoutMenu,
Expand Down
39 changes: 39 additions & 0 deletions src/components/ui/sonner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {
CircleCheckIcon,
InfoIcon,
Loader2Icon,
OctagonXIcon,
TriangleAlertIcon,
} from "lucide-react";
import { useThemeOptional } from "@/providers";
import { Toaster as Sonner, type ToasterProps } from "sonner";

const Toaster = ({ ...props }: ToasterProps) => {
const theme = useThemeOptional();
const mode = theme?.mode ?? "system";

return (
<Sonner
theme={mode 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" />,
}}
style={
{
"--normal-bg": "var(--popover)",
"--normal-text": "var(--popover-foreground)",
"--normal-border": "var(--border)",
"--border-radius": "var(--radius)",
} as React.CSSProperties
}
{...props}
/>
);
};

export { Toaster };
5 changes: 4 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,8 @@ export {
useComboboxAnchor,
// Rich Text Editor
RichTextEditor,
// Sonner (toast notifications)
Toaster,
// Calendar & DatePicker
Calendar,
DatePicker,
Expand Down Expand Up @@ -334,4 +336,5 @@ export {
// ============================================
export { cn } from "@/lib/utils";
export { twMerge } from "tailwind-merge";
export * as recharts from 'recharts';
export * as recharts from 'recharts';
export { toast } from 'sonner';
Loading