Conversation
WalkthroughAdds a new toast notification system: UI components (Toast, ToastProvider, ToastRoot, Toaster), a toast store with subscription/timer controls, a toast API, a Storybook example, and adds Changes
Sequence Diagram(s)sequenceDiagram
participant UI as User Interface
participant ToastAPI as toastAPI
participant Store as ToastStore
participant Toaster as Toaster
UI->>ToastAPI: toast.success("Message")
ToastAPI->>Store: addToast({ type: "success", message: "Message" })
Store->>Toaster: notify subscribers (new toast list)
Toaster->>UI: render animated toast
UI-->>Store: (user clicks close) removeToast(id)
Store->>Toaster: notify subscribers (toast removed)
Toaster->>UI: remove toast from display
Toaster->>Store: on hover -> pauseAllToasts()
Toaster-->>Store: on leave -> resumeAllToasts()
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested reviewers
Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 7
🔭 Outside diff range comments (1)
package.json (1)
7-45: Missing Toast component export in package.json.The new Toast component is not included in the exports section, but other UI components are exported. This inconsistency means consumers won't be able to import the Toast component.
Add the Toast export to the exports section:
"./ToggleGroup": "./dist/components/ToggleGroup.js", + "./Toast": "./dist/components/Toast.js", "./Tooltip": "./dist/components/Tooltip.js",
🧹 Nitpick comments (6)
src/components/ui/Toast/stories/Toast.stories.tsx (4)
6-6: Remove commented import.The commented import should be removed entirely rather than left as a comment for cleaner code.
-// import { TabProps } from '../fragments/TabContent'; // Removed - not exported
24-26: Remove unused ArrowIcon component.The
ArrowIconcomponent is defined but never used in the story. Consider removing it to keep the code clean.-const ArrowIcon = ({ className }: { className: string }) => { - return <svg className={className} width="16" height="16" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8.14645 3.14645C8.34171 2.95118 8.65829 2.95118 8.85355 3.14645L12.8536 7.14645C13.0488 7.34171 13.0488 7.65829 12.8536 7.85355L8.85355 11.8536C8.65829 12.0488 8.34171 12.0488 8.14645 11.8536C7.95118 11.6583 7.95118 11.3417 8.14645 11.1464L11.2929 8H2.5C2.22386 8 2 7.77614 2 7.5C2 7.22386 2.22386 7 2.5 7H11.2929L8.14645 3.85355C7.95118 3.65829 7.95118 3.34171 8.14645 3.14645Z" fill="currentColor" fillRule="evenodd" clipRule="evenodd"></path></svg>; -};
32-37: Remove unused state and handler.The
activeTabstate andhandleTabChangefunction are unused and appear to be leftover from a Tabs component template. Remove them to clean up the story.- const [activeTab, setActiveTab] = useState('meteora'); - - const handleTabChange = (value: string) => { - // console.log('tab', value); - setActiveTab(value); - };
47-51: Remove commented-out code.The commented-out
Toast.RootandToast.Titlecode should be removed unless it's needed for immediate future development.- {/* <Toast.Root> - <Toast.Title> - <h1>Hello</h1> - </Toast.Title> - </Toast.Root> */}src/components/ui/Toast/fragments/ToastToaster.tsx (1)
30-30: Consider making toast height configurable.The hardcoded
72pxtoast height could become incorrect if toast styling changes. Consider making this configurable or calculating it dynamically.- const expandedHeight = toasts.length * 72; // (72px is approx toast height + margin) + const toastHeight = 72; // Could be made configurable via props + const expandedHeight = toasts.length * toastHeight;And update the component interface:
interface ToasterProps { visibleToasts?: number; position?: 'top-right' | 'top-left' | 'top-center' | 'bottom-right' | 'bottom-left' | 'bottom-center'; + toastHeight?: number; }Also applies to: 37-37
src/components/ui/Toast/contexts/toastStore.tsx (1)
49-50: Improve readability of remaining time calculation.The remaining time calculation is correct but could be more readable. Consider extracting it to a helper function or adding clearer variable names.
- toast.remainingTime = - (toast.remainingTime ?? 3000) - (Date.now() - (toast.startTime ?? Date.now())); + const elapsedTime = Date.now() - (toast.startTime ?? Date.now()); + toast.remainingTime = Math.max(0, (toast.remainingTime ?? 3000) - elapsedTime);Also consider adding a minimum remaining time check to prevent negative values.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (8)
package.json(2 hunks)src/components/ui/Toast/Toast.tsx(1 hunks)src/components/ui/Toast/contexts/toastStore.tsx(1 hunks)src/components/ui/Toast/fragments/ToastProvider.tsx(1 hunks)src/components/ui/Toast/fragments/ToastRoot.tsx(1 hunks)src/components/ui/Toast/fragments/ToastToaster.tsx(1 hunks)src/components/ui/Toast/stories/Toast.stories.tsx(1 hunks)src/components/ui/Toast/toastAPI.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: the `dropdown.trigger` component is customizable and needs to be used with `dropdown.root`....
Learnt from: decipher-cs
PR: rad-ui/ui#417
File: src/components/ui/Dropdown/Dropdown.tsx:0-0
Timestamp: 2024-12-12T08:22:59.375Z
Learning: The `Dropdown.Trigger` component is customizable and needs to be used with `Dropdown.Root`.
Applied to files:
src/components/ui/Toast/fragments/ToastRoot.tsx
📚 Learning: ensure to verify existing aria attributes in components before suggesting additions during code revi...
Learnt from: decipher-cs
PR: rad-ui/ui#417
File: src/components/ui/Dropdown/Dropdown.stories.tsx:43-50
Timestamp: 2024-12-12T08:34:33.079Z
Learning: Ensure to verify existing ARIA attributes in components before suggesting additions during code reviews, especially in the `Dropdown.Trigger` component in `src/components/ui/Dropdown/Dropdown.stories.tsx`.
Applied to files:
src/components/ui/Toast/stories/Toast.stories.tsx
📚 Learning: in the storybook files, variations in the title prefixes like 'components/', 'wip/', 'tools/', and '...
Learnt from: kotAPI
PR: rad-ui/ui#484
File: src/components/ui/Kbd/stories/Kbd.stories.js:6-6
Timestamp: 2024-10-27T07:20:10.457Z
Learning: In the Storybook files, variations in the title prefixes like 'Components/', 'WIP/', 'Tools/', and 'Examples/' are intentional. These naming patterns are acceptable and should not be flagged as inconsistencies in future code reviews.
Applied to files:
src/components/ui/Toast/stories/Toast.stories.tsx
🧬 Code Graph Analysis (3)
src/components/ui/Toast/toastAPI.ts (1)
src/components/ui/Toast/contexts/toastStore.tsx (1)
addToast(20-36)
src/components/ui/Toast/stories/Toast.stories.tsx (2)
src/components/ui/Toast/contexts/toastStore.tsx (1)
Toast(1-9)src/components/ui/Toast/toastAPI.ts (1)
toast(5-12)
src/components/ui/Toast/contexts/toastStore.tsx (2)
src/components/ui/Toast/Toast.tsx (1)
toast(15-15)src/components/ui/Toast/toastAPI.ts (1)
toast(5-12)
⏰ 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). (1)
- GitHub Check: build
🔇 Additional comments (9)
package.json (1)
122-122: LGTM! framer-motion addition supports toast animations.The addition of framer-motion as a devDependency is appropriate for the toast notification system's animation requirements.
src/components/ui/Toast/toastAPI.ts (1)
5-12: LGTM! Clean and consistent toast API design.The API provides both a generic
createmethod and convenient type-specific methods (success,error,info). The implementation correctly delegates to theaddToastfunction from the store, maintaining good separation of concerns.src/components/ui/Toast/Toast.tsx (1)
12-17: LGTM! Good component composition pattern.The static property attachment pattern and separate export of the toast API follows established UI library conventions and provides a clean interface for consumers.
src/components/ui/Toast/stories/Toast.stories.tsx (1)
41-46: LGTM! Good demonstration of toast architecture.The story correctly demonstrates the toast system with proper component placement -
Toast.Toasterrendered globally andToast.Providerwrapping the interaction area. The usage oftoast.successAPI is appropriate.Also applies to: 52-52
src/components/ui/Toast/fragments/ToastToaster.tsx (3)
20-27: LGTM! Comprehensive position support.The position classes cover all common toast placement options with correct Tailwind CSS classes.
49-77: LGTM! Excellent animation and stacking implementation.The animation logic is well-crafted with smooth transitions, proper stacking effects using scale/opacity, and correct z-index layering. The compressed vs expanded offset calculation creates a polished user experience.
79-98: LGTM! Clean toast rendering with proper styling.The toast rendering implementation is well-structured with appropriate color coding by type, clean layout, and functional close button integration.
src/components/ui/Toast/contexts/toastStore.tsx (2)
1-9: LGTM! Comprehensive Toast type definition.The
Toasttype is well-structured with appropriate optional fields and proper typing for all properties.
11-18: LGTM! Clean observer pattern implementation.The subscription mechanism is well-implemented with immediate state delivery and proper cleanup via the returned unsubscribe function.
|
|
||
| export function addToast(toast: Omit<Toast, 'id'>) { | ||
| const newToast: Toast = { | ||
| id: crypto.randomUUID(), |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Verify browser compatibility for crypto.randomUUID().
crypto.randomUUID() requires modern browser support. Consider adding a fallback for older browsers or document the minimum browser requirements.
🏁 Script executed:
#!/bin/bash
# Check if there are any existing polyfills or compatibility considerations in the codebase
rg -i "crypto\.randomUUID|uuid|polyfill" --type js --type ts -A 2 -B 2Length of output: 515
Add a fallback for crypto.randomUUID()
crypto.randomUUID() isn’t available in some older browsers (e.g. Safari < 15.4, IE). To prevent runtime errors, provide a fallback or clearly document your minimum supported browsers.
• File: src/components/ui/Toast/contexts/toastStore.tsx (around line 22)
• Suggested change:
// import or implement a fallback generator:
import { v4 as uuidV4 } from 'uuid'; // or your own helper
function generateId() {
return crypto.randomUUID?.() ?? uuidV4();
}
export function addToast(toast: Omit<Toast, 'id'>) {
const newToast: Toast = {
id: generateId(),
duration: toast.duration ?? 3000,
startTime: Date.now(),
// …
};
// …
}– Or, if you prefer not to bundle a UUID library, write a small fallback using Math.random().
– Alternatively, in your project’s README, call out that you require only modern browsers supporting crypto.randomUUID().
🤖 Prompt for AI Agents
In src/components/ui/Toast/contexts/toastStore.tsx at line 22, the use of
crypto.randomUUID() lacks a fallback for browsers that do not support it,
causing potential runtime errors. Fix this by creating a helper function that
returns crypto.randomUUID() if available, otherwise falls back to a UUID
generator like the 'uuid' library's v4 function or a custom Math.random()-based
fallback. Replace direct calls to crypto.randomUUID() with this helper to ensure
compatibility across browsers.
| export function removeToast(id: string) { | ||
| toasts = toasts.filter((t) => t.id !== id); | ||
| listeners.forEach((l) => l(toasts)); | ||
| } |
There was a problem hiding this comment.
Clear timeout when removing toast to prevent memory leaks.
The removeToast function should clear the timeout of the removed toast to prevent memory leaks and unnecessary timer callbacks.
export function removeToast(id: string) {
+ const toastToRemove = toasts.find(t => t.id === id);
+ if (toastToRemove?.timeoutId) {
+ clearTimeout(toastToRemove.timeoutId);
+ }
toasts = toasts.filter((t) => t.id !== id);
listeners.forEach((l) => l(toasts));
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export function removeToast(id: string) { | |
| toasts = toasts.filter((t) => t.id !== id); | |
| listeners.forEach((l) => l(toasts)); | |
| } | |
| export function removeToast(id: string) { | |
| const toastToRemove = toasts.find(t => t.id === id); | |
| if (toastToRemove?.timeoutId) { | |
| clearTimeout(toastToRemove.timeoutId); | |
| } | |
| toasts = toasts.filter((t) => t.id !== id); | |
| listeners.forEach((l) => l(toasts)); | |
| } |
🤖 Prompt for AI Agents
In src/components/ui/Toast/contexts/toastStore.tsx around lines 38 to 41, the
removeToast function currently filters out the toast by id but does not clear
its associated timeout, which can cause memory leaks. Modify the function to
first find the toast with the given id, clear its timeout using clearTimeout,
and then proceed to filter it out and notify listeners. This ensures that any
active timers for the removed toast are properly cancelled.
| const ToastProvider = ({ children }: { children: React.ReactNode }) => { | ||
| return <div>{children}</div>; | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Misleading component name - ToastProvider doesn't provide context.
The component name suggests it's a React context provider, but it only wraps children in a div without providing any context or state management. This could confuse developers expecting typical provider patterns.
Consider either:
- Implementing actual provider functionality with React context
- Renaming to something more accurate like
ToastWrapperorToastContainer
-const ToastProvider = ({ children }: { children: React.ReactNode }) => {
- return <div>{children}</div>;
-};
+const ToastWrapper = ({ children }: { children: React.ReactNode }) => {
+ return <div>{children}</div>;
+};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const ToastProvider = ({ children }: { children: React.ReactNode }) => { | |
| return <div>{children}</div>; | |
| }; | |
| const ToastWrapper = ({ children }: { children: React.ReactNode }) => { | |
| return <div>{children}</div>; | |
| }; |
🤖 Prompt for AI Agents
In src/components/ui/Toast/fragments/ToastProvider.tsx around lines 4 to 6, the
component named ToastProvider does not provide any React context or state
management, which is misleading. To fix this, either implement the expected
React context provider functionality inside this component or rename the
component to a more accurate name such as ToastWrapper or ToastContainer to
reflect its actual behavior of just wrapping children in a div.
| const ToastRoot = ({ children, className, asChild }: { children: React.ReactNode, className: string, asChild: boolean }) => { | ||
| return <Primitive.div className={className}>{children}</Primitive.div>; | ||
| }; |
There was a problem hiding this comment.
Unused asChild prop and required className.
Two issues with the component props:
- The
asChildprop is accepted but never used in the implementation classNameis required but should likely be optional
Apply this diff to fix the issues:
-const ToastRoot = ({ children, className, asChild }: { children: React.ReactNode, className: string, asChild: boolean }) => {
- return <Primitive.div className={className}>{children}</Primitive.div>;
+const ToastRoot = ({ children, className, asChild }: { children: React.ReactNode, className?: string, asChild?: boolean }) => {
+ return <Primitive.div className={className}>{children}</Primitive.div>;Alternatively, if asChild functionality is intended, implement the pattern or remove the unused prop entirely.
🤖 Prompt for AI Agents
In src/components/ui/Toast/fragments/ToastRoot.tsx around lines 7 to 9, the
asChild prop is accepted but not used, and className is required though it
should be optional. Fix this by either removing the asChild prop if not needed
or implementing its intended functionality, and make className optional by
updating the prop type accordingly.
| import ToastRoot from '../fragments/ToastRoot'; | ||
| import { AnimatePresence, motion } from 'framer-motion'; | ||
|
|
||
| export function Toaster({ visibleToasts = 3, position = 'bottom-right' }) { |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add TypeScript interface for props.
The component lacks proper TypeScript typing for its props, which reduces type safety and developer experience.
+interface ToasterProps {
+ visibleToasts?: number;
+ position?: 'top-right' | 'top-left' | 'top-center' | 'bottom-right' | 'bottom-left' | 'bottom-center';
+}
+
-export function Toaster({ visibleToasts = 3, position = 'bottom-right' }) {
+export function Toaster({ visibleToasts = 3, position = 'bottom-right' }: ToasterProps) {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export function Toaster({ visibleToasts = 3, position = 'bottom-right' }) { | |
| interface ToasterProps { | |
| visibleToasts?: number; | |
| position?: 'top-right' | 'top-left' | 'top-center' | 'bottom-right' | 'bottom-left' | 'bottom-center'; | |
| } | |
| export function Toaster({ visibleToasts = 3, position = 'bottom-right' }: ToasterProps) { |
🤖 Prompt for AI Agents
In src/components/ui/Toast/fragments/ToastToaster.tsx at line 14, the Toaster
component's props are not typed, reducing type safety. Define a TypeScript
interface for the props specifying the types of visibleToasts (number) and
position (string with allowed values if applicable), then update the function
signature to use this interface for its props.
| <button | ||
| className="ml-2 text-sm opacity-70 hover:opacity-100" | ||
| onClick={() => removeToast(toast.id)} | ||
| > | ||
| ✕ | ||
| </button> |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add accessibility features for better user experience.
The toast component lacks important accessibility features. Consider adding ARIA labels, keyboard support, and screen reader announcements.
<button
+ aria-label="Close notification"
className="ml-2 text-sm opacity-70 hover:opacity-100"
onClick={() => removeToast(toast.id)}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter' || e.key === ' ') {
+ e.preventDefault();
+ removeToast(toast.id);
+ }
+ }}
>
✕
</button>Also consider adding role="alert" or role="status" to the toast container and aria-live regions for screen reader announcements.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <button | |
| className="ml-2 text-sm opacity-70 hover:opacity-100" | |
| onClick={() => removeToast(toast.id)} | |
| > | |
| ✕ | |
| </button> | |
| <button | |
| aria-label="Close notification" | |
| className="ml-2 text-sm opacity-70 hover:opacity-100" | |
| onClick={() => removeToast(toast.id)} | |
| onKeyDown={(e) => { | |
| if (e.key === 'Enter' || e.key === ' ') { | |
| e.preventDefault(); | |
| removeToast(toast.id); | |
| } | |
| }} | |
| > | |
| ✕ | |
| </button> |
🤖 Prompt for AI Agents
In src/components/ui/Toast/fragments/ToastToaster.tsx around lines 91 to 96, the
toast component's close button lacks accessibility features. Add an aria-label
attribute to the button describing its action, ensure it is keyboard accessible
by default, and add role="alert" or role="status" with aria-live attributes to
the toast container to enable screen reader announcements for better
accessibility.
| const Toast = () => { | ||
| console.warn('Direct usage of Toast is not supported. Please use Toast.Root etc. instead.'); | ||
| return null; | ||
| }; |
There was a problem hiding this comment.
Inconsistent warning message - Toast.Root not attached.
The warning message mentions using "Toast.Root" but ToastRoot is not attached as a static property on the Toast component. Only Toast.Provider and Toast.Toaster are available.
Either attach ToastRoot as a static property:
+import ToastRoot from './fragments/ToastRoot';
Toast.Provider = ToastProvider;
Toast.Toaster = Toaster;
+Toast.Root = ToastRoot;Or update the warning message to reflect actual available components:
- console.warn('Direct usage of Toast is not supported. Please use Toast.Root etc. instead.');
+ console.warn('Direct usage of Toast is not supported. Please use Toast.Provider and Toast.Toaster instead.');Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/components/ui/Toast/Toast.tsx around lines 7 to 10, the warning message
references "Toast.Root" which is not attached as a static property on the Toast
component, causing inconsistency. To fix this, either attach ToastRoot as a
static property on Toast alongside Toast.Provider and Toast.Toaster, or update
the warning message to mention only the available components like Toast.Provider
and Toast.Toaster to accurately guide users.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (1)
package.json(1 hunks)
⏰ 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). (1)
- GitHub Check: build
| "eslint-plugin-promise": "6.6.0", | ||
| "eslint-plugin-react": "7.34.0", | ||
| "eslint-plugin-react-hooks": "4.6.0", | ||
| "framer-motion": "^12.23.12", |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
framer-motion should not be only a devDependency if used by published components
If Toast components import framer-motion at runtime, consumers of @radui/ui won’t get it installed because devDependencies aren’t installed for dependents. This will cause runtime/module resolution errors for consumers. Prefer declaring it as a peerDependency (and keep as a devDependency for local development), or explicitly bundle it.
Action:
- Recommended: Move
framer-motionto peerDependencies with a compatible range and keep it in devDependencies for development. - Alternative: If intentionally bundled, ensure Rollup does not mark it external and confirm bundle size implications.
To confirm usage and externalization, run:
Apply within this hunk (remove from devDependencies):
- "framer-motion": "^12.23.12",Then add to peerDependencies (outside this hunk; illustrative snippet):
{
"peerDependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"framer-motion": "^12.23.12"
}
}Optionally pin a broader peer range to reduce churn:
"framer-motion": "^12.0.0"🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Verify code imports framer-motion =="
rg -nP -C2 --type=ts --type=tsx '\bfrom\s+[\'"]framer-motion[\'"]' || true
echo
echo "== Check Rollup externals for framer-motion =="
fd -a 'rollup*.cjs' | xargs -I{} sh -c 'echo "--- {} ---"; rg -nP -C2 "external|exclude|globals" "{}" || true'Length of output: 225
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Repo root: $(pwd) =="
echo "== Find all occurrences of 'framer-motion' =="
if command -v rg >/dev/null 2>&1; then
rg -n --hidden -S --glob '!node_modules' 'framer-motion' || true
else
grep -RIn --exclude-dir=node_modules --exclude-dir=dist 'framer-motion' . || true
fi
echo
echo "== package.json dependency sections =="
if [ -f package.json ]; then
if command -v jq >/dev/null 2>&1; then
jq '{name,version,dependencies:.dependencies,devDependencies:.devDependencies,peerDependencies:.peerDependencies}' package.json || true
else
echo "jq not available — showing lines around occurrences in package.json"
rg -n --hidden -C2 'framer-motion' package.json || true
rg -n --hidden '"(dependencies|devDependencies|peerDependencies)"' package.json || true
fi
else
echo "package.json not found"
fi
echo
echo "== Detect bundler/tooling mentions (rollup / vite / tsup / esbuild / webpack) =="
for t in rollup vite tsup esbuild webpack; do
echo "---- $t ----"
if command -v rg >/dev/null 2>&1; then
rg -n --hidden -S --glob '!node_modules' "$t" || true
else
grep -RIn --exclude-dir=node_modules --exclude-dir=dist "$t" . || true
fi
done
echo
echo "== Search for bundler 'external' / 'externals' / 'globals' / 'exclude' in configs =="
if command -v rg >/dev/null 2>&1; then
rg -n --hidden -S --glob '!node_modules' '\bexternal\b|\bexternals\b|\bglobals\b|\bexclude\b' || true
else
grep -RIn --exclude-dir=node_modules --exclude-dir=dist -E '\bexternal\b|\bexternals\b|\bglobals\b|\bexclude\b' . || true
fiLength of output: 68483
framer-motion must be a peerDependency (or be explicitly bundled)
Short reason: framer-motion is imported by a runtime component but is only listed in devDependencies — consumers will break unless it's bundled into the published package.
Files I verified:
- package.json — framer-motion is in devDependencies ("framer-motion": "^12.23.12").
- src/components/ui/Toast/fragments/ToastToaster.tsx — runtime import:
import { AnimatePresence, motion } from 'framer-motion'; - rollup.config.cjs / build-components.cjs — externals list only react/react-dom/react/jsx-runtime (framer-motion is not listed as external, so if you do not bundle it intentionally, it will be missing for consumers).
Action (recommended):
- Move framer-motion to peerDependencies with a compatible range and keep it in devDependencies for local dev/testing.
Suggested changes:
Remove from devDependencies:
- "framer-motion": "^12.23.12",Add to peerDependencies (example):
"peerDependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"framer-motion": "^12.23.12"
}Alternative: if you intentionally bundle framer-motion into the distributed build, ensure your Rollup/esbuild config does not mark it external and verify bundle size and licensing implications.
🤖 Prompt for AI Agents
In package.json around line 93, framer-motion is currently only in
devDependencies while runtime components import it; move "framer-motion" into
peerDependencies with a compatible semver range (e.g. same range as
devDependency) and keep it in devDependencies for local testing, or
alternatively change the build config to bundle framer-motion (remove it from
externals in rollup/build config) if you intend to ship it; update package.json
accordingly and ensure consumers are informed via peerDependencies so installs
won't break.
Summary by CodeRabbit
New Features
Chores