Add Toast components and Refactor Button + Input#115
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Note Other AI code review bot(s) detectedCodeRabbit 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. WalkthroughThis 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
Sequence DiagramsequenceDiagram
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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
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. Comment |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.tsximports 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 inbutton.tsx(which importsIconfrom'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.tsximports 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.labelas the key assumes labels are unique within a toast. If duplicate labels are possible, consider adding a uniqueidfield toToastAction.Also applies to: 125-135
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 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.tslibs/react/ui/src/components/dynamic-item/dynamic-item.stories.tsxlibs/react/ui/src/components/label/label.stories.tsxlibs/react/ui/src/components/button/index.tslibs/react/ui/src/components/alert/alert.tsxlibs/react/ui/src/components/toast/index.tslibs/react/ui/src/components/toast/toast.stories.tsxlibs/react/ui/src/components/toast/toast-custom.tsxlibs/react/ui/src/components/inline-tips/inline-tips.stories.tsxlibs/react/ui/src/components/toast/toast.tsxlibs/react/ui/src/components/input/index.tslibs/react/ui/src/components/inline-tips/inline-tips.tsxlibs/react/ui/src/components/alert/alert.stories.tsxlibs/react/ui/src/components/item/item.stories.tsxlibs/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), andcloseIconVariants(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
Toasterand Sonner'sToaster.
9-9: LGTM!Omitting
'theme'from the props is the correct approach since the component automatically derives it from theuseThemehook, 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
sonnerToastastoast, providing a clean public API.
11-16: No issues found—theme type compatibility is correct.The local
Themetype ('dark' | 'light' | 'system') matches Sonner'sToasterProps['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
warningcase returns the same "info" icon as theinfoanddefaultvariants (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 bothtitleandcontentprops are provided, thecontentis 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-labeland keyboard focus states.Also applies to: 142-152
…mproved organization
Summary by CodeRabbit
New Features
Changes