Skip to content

Add Toast components and Refactor Button + Input#115

Merged
kylengn merged 6 commits intomainfrom
feat/toast-and-refactor
Nov 11, 2025
Merged

Add Toast components and Refactor Button + Input#115
kylengn merged 6 commits intomainfrom
feat/toast-and-refactor

Conversation

@kylengn
Copy link
Contributor

@kylengn kylengn commented Nov 10, 2025

Summary by CodeRabbit

  • New Features

    • Toast notification component with customizable variants (default, info, success, warning, error), support for titles, descriptions, action buttons, and close handlers
    • Input and Toast components now available through the public component library API
  • Changes

    • Alert and Inline Tips components: Updated "destructive" terminology to "error" for consistency across the UI component library

@kylengn kylengn self-assigned this Nov 10, 2025
Copilot AI review requested due to automatic review settings November 10, 2025 08:33
@vercel
Copy link

vercel bot commented Nov 10, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
react-ui Ready Ready Preview Comment Nov 11, 2025 6:00am

@coderabbitai
Copy link

coderabbitai bot commented Nov 10, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

This PR performs multi-part updates across the React UI component library: renames the "destructive" variant to "error" in Alert and InlineTips components, introduces new Toast and Toaster components with Sonner integration and custom toast styling, adds barrel exports for Button and Input components, and updates import paths to use centralized component paths.

Changes

Cohort / File(s) Summary
Variant Renaming (destructive → error)
libs/react/ui/src/components/alert/alert.tsx, libs/react/ui/src/components/alert/alert.stories.tsx
Updated variant key from "destructive" to "error" in alertVariants, alertLineVariants, closeIconVariants, and story argTypes/variants list.
Variant Renaming (destructive → error)
libs/react/ui/src/components/inline-tips/inline-tips.tsx, libs/react/ui/src/components/inline-tips/inline-tips.stories.tsx
Renamed variant from "destructive" to "error" in inlineTipsLineVariants and updated InlineTipsProps.type union; updated story options and content mapping.
Toast Component Implementation
libs/react/ui/src/components/toast/toast.tsx, libs/react/ui/src/components/toast/toast-custom.tsx, libs/react/ui/src/components/toast/toast.stories.tsx, libs/react/ui/src/components/toast/index.ts
Added new Toaster component wrapping Sonner with custom theming, ToastCustom component for custom toast UI with variants (default, info, success, warning, error), and comprehensive Storybook stories.
Barrel Exports
libs/react/ui/src/components/button/index.ts, libs/react/ui/src/components/input/index.ts
Added barrel exports to re-export all public members from respective component modules.
Import Path Updates
libs/react/ui/src/components/button/button.tsx, libs/react/ui/src/components/dynamic-item/dynamic-item.stories.tsx, libs/react/ui/src/components/item/item.stories.tsx, libs/react/ui/src/components/label/label.stories.tsx
Updated import paths from local/relative modules to centralized component paths (e.g., components/button instead of ../button).
Public Exports
libs/react/ui/src/components/index.ts
Added exports for input and toast components to module's public surface.

Sequence Diagram

sequenceDiagram
    participant User as User/App
    participant Toaster as Toaster Component
    participant Toast as toast() API
    participant Sonner as Sonner Library
    participant CustomToast as ToastCustom Component
    
    User->>Toast: toast("Message")
    Toast->>Sonner: Delegate to Sonner
    Sonner->>Toaster: Render toast with theme/styles
    Toaster-->>User: Display themed toast
    
    User->>Toast: toast.custom({ content: ... })
    Toast->>CustomToast: Render ToastCustom
    CustomToast->>CustomToast: Apply variant styles<br/>(default, info, success, warning, error)
    CustomToast-->>User: Display custom toast UI<br/>with title, description, actions
    
    User->>User: Click action/close
    CustomToast->>CustomToast: Trigger onClick/onClose handler
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Toast component implementation (toast.tsx, toast-custom.tsx, toast.stories.tsx): Review custom toast rendering logic, Sonner integration, variant styling, and icon mapping. Pay attention to the styling classNames and responsive layout.
  • Variant renaming consistency: Verify that all "destructive" → "error" renames across Alert and InlineTips are complete and consistent across components, stories, and type definitions.
  • Import path updates: Confirm that centralized import paths resolve correctly and that relative imports have been properly replaced.
  • Barrel exports: Ensure new exports in button/index.ts, input/index.ts, and toast/index.ts don't introduce circular dependencies or naming conflicts.

Possibly related PRs

Suggested reviewers

  • EnzalRad
  • dvxam
  • noe-charmet

Poem

🐰 From "destructive" winds we changed to "error" clear,
A Toast of Sonner flavor now appears!
With custom variants styled, Icon sprites dancing,
Barrel exports gleam—refactoring prancing!
The UI grows sweet, one commit at a time. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main changes: Toast components are added (multiple new files for toast), Button is refactored (import path changes and barrel export), and Input gets a barrel export added.

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.

Copy link

Copilot AI left a comment

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 introduces new toast and input components, renames the "destructive" variant to "error" across alert and inline-tips components, and standardizes import paths in storybook files.

  • Adds toast notification system with regular and custom toast variants
  • Implements input component with variant and size options
  • Renames "destructive" to "error" for better semantic consistency

Reviewed Changes

Copilot reviewed 15 out of 18 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
libs/react/ui/src/components/toast/toast.tsx Implements the Toaster component wrapper around Sonner with theme integration and custom icons
libs/react/ui/src/components/toast/toast-custom.tsx Provides customizable toast component with variants, actions, and content options
libs/react/ui/src/components/toast/toast.stories.tsx Storybook documentation showing regular and custom toast usage patterns
libs/react/ui/src/components/toast/index.ts Exports toast-related components and types
libs/react/ui/src/components/input/input.tsx Implements input component with variant and size customization
libs/react/ui/src/components/input/input.stories.tsx Storybook documentation for input component states and types
libs/react/ui/src/components/input/index.ts Exports input component
libs/react/ui/src/components/alert/alert.tsx Renames "destructive" variant to "error"
libs/react/ui/src/components/alert/alert.stories.tsx Updates storybook to reflect variant rename
libs/react/ui/src/components/inline-tips/inline-tips.tsx Renames "destructive" variant to "error"
libs/react/ui/src/components/inline-tips/inline-tips.stories.tsx Updates storybook to reflect variant rename
libs/react/ui/src/components/index.ts Adds exports for new input and toast components
libs/react/ui/src/components/label/label.stories.tsx Standardizes import path for Input component
libs/react/ui/src/components/item/item.stories.tsx Standardizes import paths for multiple components
libs/react/ui/src/components/dynamic-item/dynamic-item.stories.tsx Standardizes import path for Button component
libs/react/ui/src/components/button/index.ts Adds barrel export for button component
libs/react/ui/src/components/button/button.tsx Updates Icon import path to use components directory
libs/react/ui/src/components/button/button.stories.tsx Adds storybook documentation for button component

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (5)
libs/react/ui/src/components/label/label.stories.tsx (1)

3-3: Consider importing from the barrel export for consistency.

The PR introduces a barrel export at components/input/index.ts, and the top-level index now re-exports from ./input. For consistency with other refactored imports (e.g., button.tsx imports from 'components/icon'), consider importing from the barrel export instead:

-import {Input} from 'components/input/input';
+import {Input} from 'components/input';

This approach would be more consistent with the barrel export pattern and simplifies future refactoring.

libs/react/ui/src/components/dynamic-item/dynamic-item.stories.tsx (1)

2-2: Consider using the barrel export for consistency.

The PR introduces a barrel export at components/button/index.ts. For consistency with the centralized import pattern used in button.tsx (which imports Icon from 'components/icon'), consider using the barrel export:

-import {Button} from 'components/button/button';
+import {Button} from 'components/button';
libs/react/ui/src/components/item/item.stories.tsx (1)

2-5: Consider using barrel exports for consistency.

While these import paths work correctly, they use full file paths rather than barrel exports. For consistency with the centralized import pattern (e.g., button.tsx imports from 'components/icon' rather than 'components/icon/icon'), consider using barrel exports where available:

-import {Button} from 'components/button/button';
-import {Icon} from 'components/icon/icon';
-import {Input} from 'components/input/input';
-import {Label} from 'components/label/label';
+import {Button} from 'components/button';
+import {Icon} from 'components/icon';
+import {Input} from 'components/input';
+import {Label} from 'components/label';

This assumes barrel exports exist for all these components. If they don't, the current approach is acceptable.

libs/react/ui/src/components/toast/toast.stories.tsx (1)

108-355: Consider extracting a helper function to reduce duplication.

The eight custom toast blocks (4 full variants + 4 simple variants) contain significant repetition. Each differs only in the variant prop and button label.

Consider extracting a helper function:

const createCustomToastButton = (
  label: string,
  variant: 'success' | 'info' | 'warning' | 'error',
  isSimple: boolean,
  props: { title?: string; description?: string; content?: string }
) => (
  <Button
    onClick={() => {
      toast.custom(
        (t) => (
          <ToastCustom
            variant={variant}
            {...props}
            actions={[
              {
                label: isSimple ? 'Learn more' : 'Upgrade',
                onClick: () => {
                  toast(`${isSimple ? 'Learn more' : 'Upgrade'} clicked`);
                  toast.dismiss(t);
                },
              },
              ...(!isSimple ? [{
                label: 'Learn more',
                onClick: () => {
                  toast('Learn more clicked');
                  toast.dismiss(t);
                },
              }] : []),
            ]}
            onClose={() => toast.dismiss(t)}
          />
        ),
        { duration: Infinity }
      );
    }}
  >
    {label}
  </Button>
);

However, explicit examples in Storybook stories can aid clarity, so this refactor is optional.

libs/react/ui/src/components/toast/toast-custom.tsx (1)

99-109: Consider extracting the action button to reduce duplication.

The action button styling and structure is duplicated across both rendering paths (simple and non-simple modes).

Extract to a reusable component or helper:

const ActionButton = ({ action }: { action: ToastAction }) => (
  <button
    key={action.label}
    data-slot="toast-custom-action"
    type="button"
    onClick={action.onClick}
    className="bg-transparent border-none p-0 cursor-pointer text-xs font-medium leading-20 text-foreground-neutral-base hover:text-foreground-neutral-subtle transition-colors duration-150 outline-none focus-visible:ring-2 focus-visible:ring-background-accent-blue-base focus-visible:ring-offset-2"
  >
    {action.label}
  </button>
);

Then use:

{actions?.map((action) => <ActionButton key={action.label} action={action} />)}

Note: Using action.label as the key assumes labels are unique within a toast. If duplicate labels are possible, consider adding a unique id field to ToastAction.

Also applies to: 125-135

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1294ccb and 5a46145.

📒 Files selected for processing (15)
  • libs/react/ui/src/components/alert/alert.stories.tsx (2 hunks)
  • libs/react/ui/src/components/alert/alert.tsx (3 hunks)
  • libs/react/ui/src/components/button/button.tsx (1 hunks)
  • libs/react/ui/src/components/button/index.ts (1 hunks)
  • libs/react/ui/src/components/dynamic-item/dynamic-item.stories.tsx (1 hunks)
  • libs/react/ui/src/components/index.ts (1 hunks)
  • libs/react/ui/src/components/inline-tips/inline-tips.stories.tsx (3 hunks)
  • libs/react/ui/src/components/inline-tips/inline-tips.tsx (2 hunks)
  • libs/react/ui/src/components/input/index.ts (1 hunks)
  • libs/react/ui/src/components/item/item.stories.tsx (2 hunks)
  • libs/react/ui/src/components/label/label.stories.tsx (1 hunks)
  • libs/react/ui/src/components/toast/index.ts (1 hunks)
  • libs/react/ui/src/components/toast/toast-custom.tsx (1 hunks)
  • libs/react/ui/src/components/toast/toast.stories.tsx (1 hunks)
  • libs/react/ui/src/components/toast/toast.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*

⚙️ CodeRabbit configuration file

We handle errors at the edge of our applications in most cases. Do not recommend to add error handling around every single function. We prefer them to bubble up and be handled at upper layers.

Files:

  • libs/react/ui/src/components/index.ts
  • libs/react/ui/src/components/dynamic-item/dynamic-item.stories.tsx
  • libs/react/ui/src/components/label/label.stories.tsx
  • libs/react/ui/src/components/button/index.ts
  • libs/react/ui/src/components/alert/alert.tsx
  • libs/react/ui/src/components/toast/index.ts
  • libs/react/ui/src/components/toast/toast.stories.tsx
  • libs/react/ui/src/components/toast/toast-custom.tsx
  • libs/react/ui/src/components/inline-tips/inline-tips.stories.tsx
  • libs/react/ui/src/components/toast/toast.tsx
  • libs/react/ui/src/components/input/index.ts
  • libs/react/ui/src/components/inline-tips/inline-tips.tsx
  • libs/react/ui/src/components/alert/alert.stories.tsx
  • libs/react/ui/src/components/item/item.stories.tsx
  • libs/react/ui/src/components/button/button.tsx
🧬 Code graph analysis (2)
libs/react/ui/src/components/toast/toast.stories.tsx (2)
libs/react/ui/src/components/button/button.tsx (1)
  • Button (39-63)
libs/react/ui/src/components/toast/toast-custom.tsx (1)
  • ToastCustom (51-155)
libs/react/ui/src/components/toast/toast-custom.tsx (2)
libs/react/ui/src/components/toast/index.ts (2)
  • ToastCustomProps (2-2)
  • ToastCustom (2-2)
libs/react/ui/src/components/icon/icon.tsx (1)
  • Icon (63-66)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Continuous integration (arm64)
  • GitHub Check: Continuous integration (amd64)
🔇 Additional comments (22)
libs/react/ui/src/components/inline-tips/inline-tips.stories.tsx (1)

19-19: LGTM! Consistent variant renaming in story configuration.

The renaming from "destructive" to "error" is applied consistently across the Storybook argTypes options, types array, and content mapping. This aligns with the component implementation changes.

Also applies to: 36-36, 83-83

libs/react/ui/src/components/alert/alert.stories.tsx (1)

20-20: LGTM! Story configuration updated consistently.

The variant renaming is properly reflected in both the argTypes options and the variants array used in the DesignMock story.

Also applies to: 32-32

libs/react/ui/src/components/alert/alert.tsx (1)

15-15: LGTM! Comprehensive variant renaming across all Alert CVA definitions.

The "destructive" → "error" renaming is consistently applied across alertVariants (line 15), alertLineVariants (line 31), and closeIconVariants (line 46), ensuring visual consistency throughout the Alert component. Codebase verification confirms no remaining references to the old "destructive" variant exist.

libs/react/ui/src/components/inline-tips/inline-tips.tsx (1)

24-24: Verification complete: Breaking change properly implemented.

The "destructive" → "error" renaming has been fully applied:

  • Line 24: error: 'bg-tag-error-icon', in variant definition
  • Line 34: Type union includes 'error' (no remaining 'destructive' references)
  • Codebase search confirms no remaining references to old variant
libs/react/ui/src/components/toast/toast.tsx (6)

1-7: LGTM!

The imports are well-organized with appropriate aliasing to avoid naming conflicts between the local Toaster and Sonner's Toaster.


9-9: LGTM!

Omitting 'theme' from the props is the correct approach since the component automatically derives it from the useTheme hook, preventing prop conflicts.


18-28: LGTM!

The toast customization extensively uses design system tokens and follows consistent patterns. The grouped class names ensure proper scoping for toast elements.


29-35: LGTM!

The custom icons appropriately represent each toast state with consistent sizing and design system color tokens. The loading state correctly uses an animated spinner.


41-41: LGTM!

The export pattern properly encapsulates the Sonner dependency by aliasing sonnerToast as toast, providing a clean public API.


11-16: No issues found—theme type compatibility is correct.

The local Theme type ('dark' | 'light' | 'system') matches Sonner's ToasterProps['theme'] type exactly. The cast is unnecessary since the types are already compatible, but it does not hide type errors or cause runtime issues. The code is safe as-is.

libs/react/ui/src/components/button/button.tsx (1)

3-3: LGTM!

The Icon import correctly uses the barrel export path ('components/icon'), which is the preferred pattern for centralized imports.

libs/react/ui/src/components/button/index.ts (1)

1-1: LGTM!

Clean barrel export implementation that centralizes Button component exports.

libs/react/ui/src/components/input/index.ts (1)

1-1: LGTM!

Clean barrel export implementation that centralizes Input component exports.

libs/react/ui/src/components/item/item.stories.tsx (1)

16-16: LGTM!

The change to export from './item' makes the export source more explicit and improves code clarity.

libs/react/ui/src/components/index.ts (2)

8-8: LGTM!

The input barrel export is now properly exposed through the main components index, enabling centralized imports.


13-13: LGTM!

The toast module is now properly exposed through the main components index, making the new Toast/Toaster components available for consumption.

libs/react/ui/src/components/toast/index.ts (1)

1-2: LGTM!

Clean barrel exports with proper type exports. The naming is clear and follows established patterns.

libs/react/ui/src/components/toast/toast.stories.tsx (2)

1-13: LGTM!

Standard Storybook configuration with appropriate imports and meta setup.


367-369: LGTM!

Clean story definition with appropriate Toaster configuration.

libs/react/ui/src/components/toast/toast-custom.tsx (3)

36-49: Verify that warning variant should use the same icon as info.

The warning case returns the same "info" icon as the info and default variants (lines 39, 43, 47). Warnings typically have distinct iconography (e.g., exclamation triangle) to differentiate them visually from informational messages.

If this is intentional, consider adding a comment to document the decision. Otherwise, update to use a distinct warning icon:

     case 'warning':
-      return <Icon name="info" size={20} />;
+      return <Icon name="exclamationTriangle" size={20} />; // or appropriate warning icon

115-122: Verify content rendering logic when both title and content are provided.

In the non-simple rendering path, content is only rendered if hasContent && !hasTitle (line 115). This means when both title and content props are provided, the content is silently ignored.

Is this the intended behavior? If so, consider documenting this in a comment or the prop types. If not, the condition should be adjusted:

-            {hasContent && !hasTitle && (
+            {hasContent && (
               <div
                 data-slot="toast-custom-content"
                 className="text-sm leading-20 text-foreground-neutral-base mb-8"
               >
                 {content}
               </div>
             )}

68-70: LGTM!

The icon container and close button have appropriate styling and accessibility features. The close button includes proper aria-label and keyboard focus states.

Also applies to: 142-152

noe-charmet
noe-charmet previously approved these changes Nov 11, 2025
@kylengn kylengn merged commit a808a32 into main Nov 11, 2025
5 checks passed
@kylengn kylengn deleted the feat/toast-and-refactor branch November 11, 2025 06:02
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.

2 participants