Skip to content

feat: Sonner toast integration - #415

Merged
bdjulbic merged 10 commits into
mainfrom
cursor/sonner-toast-integration-8256
Mar 19, 2026
Merged

bdjulbic merged 10 commits into
mainfrom
cursor/sonner-toast-integration-8256

Conversation

@ilyabo

@ilyabo ilyabo commented Mar 3, 2026 •

Copy link
Copy Markdown
Collaborator

Deprecate useToast and migrate all usages to the new Sonner-based toast, while extracting legacy toaster code and aligning Sonner styles.


Open in Web Open in Cursor 

Summary by CodeRabbit

  • Refactor

    • Replaced the legacy in-app toast system with a unified Sonner-based toaster; components updated to use the new toast API.
  • New Features

    • Added a theme-aware Toaster component and expanded the public UI surface with many additional layout and control components.
  • Style

    • Improved toast theming, icons, and light/dark presentation for consistent notifications.

@cursor

cursor Bot commented Mar 3, 2026

Copy link
Copy Markdown

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

@coderabbitai

coderabbitai Bot commented Mar 3, 2026 •

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Replaces the legacy in-memory Radix toast system (useToast, Toast components, LegacyToaster) with a Sonner-backed Toaster; removes legacy toast modules and dependency, adds a Sonner Toaster component, updates package exports, and migrates components to import and call the new toast API (e.g., toast.success / toast.error).

Changes

Cohort / File(s) Summary
Toast system removed
packages/ui/src/hooks/use-toast.ts, packages/ui/src/components/toast.tsx, packages/ui/src/components/toaster.tsx
Deleted legacy in-memory toast manager, useToast hook, Radix-based Toast components, and legacy Toaster implementation and exports.
Sonner Toaster added
packages/ui/src/components/sonner.tsx, packages/ui/tailwind-preset.css
Added Sonner-backed Toaster component with theme/icon mapping; trivial Tailwind whitespace edit.
Component toast API migrations
apps/sqlrooms-cli-ui/src/components/DataSourcesPanel.tsx, examples/notebook/src/DataSourcesPanel.tsx, packages/ai-settings/src/components/AiModelParameters.tsx, packages/ai-settings/src/components/AiModelsSettings.tsx, packages/ai-settings/src/components/AiProvidersSettings.tsx, packages/canvas/src/nodes/AddNodePopover.tsx
Replaced useToast + const { toast } = useToast() with import { toast } from '@sqlrooms/ui'; converted toast({ variant, title, description }) calls to toast.success(...) / toast.error(...).
UI package surface & deps
packages/ui/src/index.ts, packages/ui/package.json
Removed Radix toast exports and @radix-ui/react-toast dependency; expanded/reorganized public exports and re-exported Toaster from ./components/sonner.

Sequence Diagram(s)

sequenceDiagram
  participant Component
  participant ToastAPI as "toast (export)"
  participant Toaster as "Sonner Toaster"
  participant Browser as "UI Display"

  Component->>ToastAPI: import { toast }\ntoast.success("Message", { description })
  ToastAPI->>Toaster: enqueue success toast (payload)
  Toaster->>Browser: render toast (icon, text, theme styles)
  Browser-->>Toaster: user dismiss / timeout
  Toaster->>ToastAPI: optional callback (dismissed)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • mihajlo-stojkovic

Poem

🐰
I hopped through code with whiskers bright,
Old hooks retired, Sonner brings light,
Successes sing, errors cry “oh no,”
New toasts bloom in a neat row,
A rabbit dances — code in flight! 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: Sonner toast integration' accurately captures the main objective of this changeset, which is to migrate from useToast to a Sonner-based toast system across multiple files and the UI package.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/sonner-toast-integration-8256
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ilyabo ilyabo changed the title Sonner toast integration feat: Sonner toast integration Mar 3, 2026
@ilyabo
ilyabo marked this pull request as ready for review March 3, 2026 15:18
ilyabo added 3 commits March 4, 2026 16:48
Signed-off-by: Ilya Boyandin <[email protected]>
Signed-off-by: Ilya Boyandin <[email protected]>
Signed-off-by: Ilya Boyandin <[email protected]>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/ai-settings/src/components/AiModelParameters.tsx (1)

66-83: ⚠️ Potential issue | 🟡 Minor

Reset file input on validation failures as well.

Line 70 and Line 79 return before the input is reset, which can block re-selecting the same invalid file.

🛠️ Proposed fix
   const handleFileUpload = async (
     event: React.ChangeEvent<HTMLInputElement>,
   ) => {
     const file = event.target.files?.[0];
     if (!file) return;
+    const resetFileInput = () => {
+      if (fileInputRef.current) {
+        fileInputRef.current.value = '';
+      }
+    };

@@
     if (
       !allowedTypes.includes(file.type) &&
       !allowedExtensions.includes(fileExtension)
     ) {
       toast.error('Invalid file type', {
         description: 'Please select a text file (.txt, .md, .json)',
       });
+      resetFileInput();
       return;
     }

@@
     if (file.size > maxSize) {
       toast.error('File too large', {
         description: 'File size must be less than 1MB',
       });
+      resetFileInput();
       return;
     }

@@
-    if (fileInputRef.current) {
-      fileInputRef.current.value = '';
-    }
+    resetFileInput();
   };

Also applies to: 99-102

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ai-settings/src/components/AiModelParameters.tsx` around lines 66 -
83, Validation early-returns in the AiModelParameters component leave the file
input value unchanged, preventing re-selecting the same invalid file; update the
validation branches in the file selection handler (the block that checks
allowedTypes/allowedExtensions and the maxSize check, and the later validation
around lines ~99-102) to reset the file input before returning by clearing the
input element (e.g., via the same input ref used elsewhere in this component) so
the input’s value is set to empty string prior to each toast.error return.
🧹 Nitpick comments (1)
packages/ui/src/components/sonner.tsx (1)

28-35: Consolidate Sonner style variables in one place.

--normal-* vars are defined inline here while Sonner vars are also defined in packages/ui/tailwind-preset.css. Keeping one source of truth will reduce styling drift.

♻️ Suggested refactor
-      style={
-        {
-          '--normal-bg': 'var(--popover)',
-          '--normal-text': 'var(--popover-foreground)',
-          '--normal-border': 'var(--border)',
-          '--border-radius': 'var(--radius)',
-        } as React.CSSProperties
-      }
+      // Keep Sonner color variables in tailwind-preset.css to avoid split styling sources.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ui/src/components/sonner.tsx` around lines 28 - 35, The inline CSS
custom properties (--normal-bg, --normal-text, --normal-border, --border-radius)
set in the style prop of the Sonner component in
packages/ui/src/components/sonner.tsx should be removed and consolidated to use
the existing Sonner/Tailwind variables defined in
packages/ui/tailwind-preset.css; update the Sonner component (where the style
prop is applied) to rely on the preset CSS variables (or add any missing
variables to tailwind-preset.css) instead of inline styles so there is a single
source of truth for these tokens and no duplicated definitions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/ai-settings/src/components/AiModelParameters.tsx`:
- Around line 66-83: Validation early-returns in the AiModelParameters component
leave the file input value unchanged, preventing re-selecting the same invalid
file; update the validation branches in the file selection handler (the block
that checks allowedTypes/allowedExtensions and the maxSize check, and the later
validation around lines ~99-102) to reset the file input before returning by
clearing the input element (e.g., via the same input ref used elsewhere in this
component) so the input’s value is set to empty string prior to each toast.error
return.

---

Nitpick comments:
In `@packages/ui/src/components/sonner.tsx`:
- Around line 28-35: The inline CSS custom properties (--normal-bg,
--normal-text, --normal-border, --border-radius) set in the style prop of the
Sonner component in packages/ui/src/components/sonner.tsx should be removed and
consolidated to use the existing Sonner/Tailwind variables defined in
packages/ui/tailwind-preset.css; update the Sonner component (where the style
prop is applied) to rely on the preset CSS variables (or add any missing
variables to tailwind-preset.css) instead of inline styles so there is a single
source of truth for these tokens and no duplicated definitions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 35d36b76-aa54-4de5-a986-c9201a123e40

📥 Commits

Reviewing files that changed from the base of the PR and between 00fe136 and 4a5c59f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (13)
  • apps/sqlrooms-cli-ui/src/components/DataSourcesPanel.tsx
  • examples/notebook/src/DataSourcesPanel.tsx
  • packages/ai-settings/src/components/AiModelParameters.tsx
  • packages/ai-settings/src/components/AiModelsSettings.tsx
  • packages/ai-settings/src/components/AiProvidersSettings.tsx
  • packages/canvas/src/nodes/AddNodePopover.tsx
  • packages/ui/package.json
  • packages/ui/src/components/sonner.tsx
  • packages/ui/src/components/toast.tsx
  • packages/ui/src/components/toaster.tsx
  • packages/ui/src/hooks/use-toast.ts
  • packages/ui/src/index.ts
  • packages/ui/tailwind-preset.css
💤 Files with no reviewable changes (3)
  • packages/ui/src/components/toast.tsx
  • packages/ui/src/hooks/use-toast.ts
  • packages/ui/src/components/toaster.tsx

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR migrates the codebase from the legacy Radix-based toast + useToast hook to a Sonner-based toast API, updates consumers to use toast.*, and removes the Radix toast dependency from the UI package.

Changes:

  • Remove legacy toast implementation (useToast, Radix toast components, legacy toaster wrapper).
  • Add a new Sonner-backed Toaster component integrated with the theme provider and update UI exports.
  • Update call sites across apps/packages/examples to use toast.success/error(...) instead of useToast().

Reviewed changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pnpm-lock.yaml Removes @radix-ui/react-toast from lockfile.
packages/ui/package.json Drops @radix-ui/react-toast dependency.
packages/ui/tailwind-preset.css Minor formatting change.
packages/ui/src/index.ts Removes legacy toast exports, re-exports Sonner toast, and exports new Toaster.
packages/ui/src/hooks/use-toast.ts Deletes legacy hook-based toast state/reducer.
packages/ui/src/components/toaster.tsx Deletes legacy wrapper toaster (Radix + Sonner).
packages/ui/src/components/toast.tsx Deletes Radix toast component implementation.
packages/ui/src/components/sonner.tsx Adds new themed Sonner Toaster component with icons and CSS variable styling.
packages/canvas/src/nodes/AddNodePopover.tsx Migrates from useToast() to toast.error(...).
packages/ai-settings/src/components/AiProvidersSettings.tsx Migrates to toast.success/error(...).
packages/ai-settings/src/components/AiModelsSettings.tsx Migrates to toast.success/error(...).
packages/ai-settings/src/components/AiModelParameters.tsx Migrates to toast.success/error(...).
examples/notebook/src/DataSourcesPanel.tsx Migrates to toast.success/error(...).
apps/sqlrooms-cli-ui/src/components/DataSourcesPanel.tsx Migrates to toast.success/error(...).
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread packages/ui/src/components/sonner.tsx
Comment thread packages/ui/src/index.ts
Comment on lines 306 to 308
// Hooks
export {useToast, toast as legacyToast, reducer} from './hooks/use-toast';
export {toast, type ExternalToast} from 'sonner';

Co-authored-by: Copilot Autofix powered by AI <[email protected]>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/ui/src/components/sonner.tsx`:
- Line 14: The Toaster component currently spreads {...props} and allows
caller-provided icons or toastOptions to completely replace defaults; fix this
by merging defaults with incoming props before spreading — inside the Toaster
component compute mergedProps that does icons: {...defaultIcons,
...(props.icons||{})} and toastOptions: {...defaultToastOptions,
...(props.toastOptions||{}), classNames: {...defaultToastOptions.classNames,
...(props.toastOptions?.classNames||{})}} (so classNames.toast and variant icons
are preserved) and then pass mergedProps to the underlying Toaster renderer;
reference the Toaster component, props, icons, toastOptions, classNames.toast
and variant icon keys when applying the merge.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ff6e77e1-b6b4-4275-a293-5bbf269cbdeb

📥 Commits

Reviewing files that changed from the base of the PR and between d6b16ea and 38aff33.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (2)
  • packages/ui/package.json
  • packages/ui/src/components/sonner.tsx
💤 Files with no reviewable changes (1)
  • packages/ui/package.json

import {useTheme} from '../theme/theme-provider';
import type {CSSProperties} from 'react';

const Toaster = ({...props}: ToasterProps) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Merge default icons/toastOptions with incoming props to avoid losing wrapper defaults.

Because ...props is applied at Line 42, any caller-provided icons or toastOptions fully replaces the defaults. That can silently drop classNames.toast = 'cn-toast' and variant icons.

🔧 Proposed fix
-const Toaster = ({...props}: ToasterProps) => {
+const Toaster = ({toastOptions, icons, ...props}: ToasterProps) => {
   const {theme = 'system'} = useTheme();

   return (
     <Sonner
       richColors
       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" />,
+        ...icons,
       }}
       style={
         {
           '--normal-bg': 'var(--popover)',
           '--normal-text': 'var(--popover-foreground)',
           '--normal-border': 'var(--border)',
           '--border-radius': 'var(--radius)',
         } as CSSProperties
       }
       toastOptions={{
+        ...toastOptions,
         classNames: {
           toast: 'cn-toast',
+          ...toastOptions?.classNames,
         },
       }}
       {...props}
     />
   );
 };

Also applies to: 22-28, 37-43

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ui/src/components/sonner.tsx` at line 14, The Toaster component
currently spreads {...props} and allows caller-provided icons or toastOptions to
completely replace defaults; fix this by merging defaults with incoming props
before spreading — inside the Toaster component compute mergedProps that does
icons: {...defaultIcons, ...(props.icons||{})} and toastOptions:
{...defaultToastOptions, ...(props.toastOptions||{}), classNames:
{...defaultToastOptions.classNames, ...(props.toastOptions?.classNames||{})}}
(so classNames.toast and variant icons are preserved) and then pass mergedProps
to the underlying Toaster renderer; reference the Toaster component, props,
icons, toastOptions, classNames.toast and variant icon keys when applying the
merge.

@bdjulbic
bdjulbic merged commit b4a792e into main Mar 19, 2026
4 checks passed
@bdjulbic
bdjulbic deleted the cursor/sonner-toast-integration-8256 branch March 19, 2026 14:59
dmitriy-kostianetskiy pushed a commit that referenced this pull request Mar 20, 2026
Signed-off-by: Ilya Boyandin <[email protected]>
Signed-off-by: bdjulbic <[email protected]>
Co-authored-by: Cursor Agent <[email protected]>
Co-authored-by: bdjulbic <[email protected]>
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
Co-authored-by: bdjulbic <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants