Skip to content

Conversation

@GoldGroove06
Copy link
Contributor

@GoldGroove06 GoldGroove06 commented Dec 9, 2024

This solves the issue #613 by using clsx to handle passing the className. It ensures no blank space or undefined className is passed. The files have been manually checked after the script did the migration. ** The tests would fail because main has some issues **. The tests failing are not related to components changed. Primitives have not been changed

Summary by CodeRabbit

  • New Features
    • Added clsx utility for improved class name management across various components.
  • Bug Fixes
    • Enhanced handling of conditional class names in components without altering existing functionality.
  • Documentation
    • Updated component return statements to utilize clsx for class name concatenation, improving readability and maintainability.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 9, 2024

Warning

Rate limit exceeded

@GoldGroove06 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 11 minutes and 18 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 2690dc9 and 854c4e1.

📒 Files selected for processing (2)
  • src/components/ui/Accordion/fragments/AccordionRoot.tsx (2 hunks)
  • src/components/ui/Button/Button.tsx (2 hunks)

Walkthrough

The pull request introduces a new dependency, clsx, to the package.json file of the @radui/ui package. This utility is then integrated into various components throughout the codebase, replacing previous methods of class name management with clsx for improved flexibility and cleaner handling of conditional class names. The overall structure and functionality of the components remain unchanged, focusing solely on enhancing class name management.

Changes

File Path Change Summary
package.json Added new dependency: "clsx": "^2.1.1" in dependencies section.
src/components/ui/Accordion/fragments/AccordionContent.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/Accordion/fragments/AccordionHeader.tsx Updated className handling to use clsx instead of direct prop usage.
src/components/ui/Accordion/fragments/AccordionItem.tsx Updated className handling to use clsx for class name management.
src/components/ui/Accordion/fragments/AccordionRoot.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/Accordion/fragments/AccordionTrigger.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/AlertDialog/fragments/AlertDialogContent.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/AlertDialog/fragments/AlertDialogOverlay.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/AlertDialog/fragments/AlertDialogRoot.tsx Updated className handling to use clsx instead of direct usage.
src/components/ui/Avatar/Avatar.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/AvatarGroup/AvatarGroup.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/AvatarGroup/fragments/AvatarGroupRoot.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/Badge/Badge.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/Badge/fragments/BadgeRoot.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/BlockQuote/BlockQuote.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/Button/Button.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/Callout/Callout.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/Callout/fragments/CalloutRoot.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/Card/Card.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/Card/fragments/CardRoot.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/Code/Code.tsx Updated className handling to use clsx instead of static string.
src/components/ui/Collapsible/Collapsible.tsx Updated className handling for ExpandIcon and CollapseIcon to use clsx.
src/components/ui/Dropdown/Dropdown.tsx Updated className handling for <ul> and <div> elements to use clsx.
src/components/ui/Em/Em.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/Heading/Heading.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/HoverCard/fragments/HoverCardArrow.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/HoverCard/fragments/HoverCardContent.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/HoverCard/fragments/HoverCardRoot.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/HoverCard/fragments/HoverCardTrigger.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/Kbd/Kbd.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/Link/Link.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/Modal/Modal.tsx Updated className handling for modal elements to use clsx.
src/components/ui/Progress/fragments/ProgressIndicator.tsx Updated className handling to use clsx instead of string interpolation.
src/components/ui/Progress/fragments/ProgressRoot.tsx Updated className handling to use clsx instead of direct usage.
src/components/ui/Quote/Quote.tsx Updated className handling to use clsx instead of string interpolation.

Possibly related PRs

  • Part 2: fixed linter issues #342: The main PR adds a new dependency (clsx) in package.json, which is directly related to the changes in multiple retrieved PRs that implement the clsx utility for class name management in various components, including AccordionContent.tsx, AccordionHeader.tsx, and others.
  • Accessible Accordion Component #358: This PR introduces the clsx utility in the Accordion components, which aligns with the main PR's addition of the clsx dependency.
  • Better Accordion #363: Similar to the previous PRs, this one also implements the clsx utility in the Accordion components, further connecting it to the main PR's changes.
  • AvatarPrimitive Component + Base AvatarGroup component #425: The AvatarGroup component utilizes the clsx utility for class name management, which is relevant to the main PR's addition of the clsx dependency.
  • HoverCard Component #583: The new HoverCard component also incorporates the clsx utility for managing class names, linking it to the main PR's changes.
  • Progress value fixed #591: The modifications in the Progress component story do not directly relate to the main PR, but the overall context of component updates may connect indirectly through shared dependencies.
  • Update jest config, support tests in TS, tests for customClassSwitcher #593: This PR updates the Jest configuration to support TypeScript tests, which is a broader change but does not directly relate to the main PR's focus on the clsx dependency.

Suggested reviewers

  • kotAPI

🐇 In the meadow, changes bloom,
With clsx now, there's more room.
Class names dance, no more fuss,
Clean and neat, just like us!
Let’s hop along, with joy we cheer,
For every change that brings us near! 🌼


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@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: 7

🧹 Outside diff range and nitpick comments (35)
src/components/ui/HoverCard/fragments/HoverCardRoot.tsx (1)

6-6: Optimize the clsx import statement

The current import can be simplified.

-import { clsx } from 'clsx';
+import clsx from 'clsx';
src/components/ui/AvatarGroup/AvatarGroup.tsx (1)

Line range hint 11-17: Consider addressing type definition improvements.

While not directly related to the className changes, there are two type-related improvements to consider:

  1. The size prop is defined but not used in the component implementation
  2. Using Record<string, any> for additional props reduces type safety

Consider these improvements:

type AvatarGroupProps = {
    avatars: { fallback: string, src: string, alt: string }[];
    size: 'sm' | 'md' | 'lg';
-   customRootClass?: string;
    className?: string;
-   props?: Record<string, any>;
+   // Use React's HTMLAttributes for additional props
+   } & React.HTMLAttributes<HTMLDivElement>;

Also, either implement the size prop in the component or remove it if it's not needed.

src/components/ui/Collapsible/Collapsible.tsx (4)

17-17: Simplify className implementation

Using clsx for a single static class adds unnecessary complexity. Since there's no conditional logic or class merging needed, consider using the className directly:

-className={clsx('size-6')}
+className="size-6"

This change would maintain the same functionality while being more straightforward.

Also applies to: 23-23


Line range hint 41-52: Consider enhancing the component's implementation

Several improvements could be made to align with best practices:

  1. Replace inline styles with className-based styling for better maintainability and consistency
  2. The transition property is incomplete - 'all' without duration or timing function may not work as expected
  3. Consider implementing RTL support as mentioned in the TODO comments

Here's a suggested approach for the collapsible content:

 <div
     aria-hidden={!open}
-    style={{
-        overflow: 'hidden',
-        display: 'flex',
-        flexDirection: 'column',
-        height: (props.open ?? open) ? 'auto' : '0',
-        transition: 'all'
-    }}>
+    className={clsx(
+        'overflow-hidden flex flex-column',
+        'transition-all duration-300 ease-in-out',
+        (props.open ?? open) ? 'h-auto' : 'h-0'
+    )}>

Line range hint 34-37: Consider improving the header structure

The header section also uses inline styles. Consider converting to className-based styling and improving the semantic structure:

-<span style={{ display: 'flex', alignItems: 'center' }}>
+<header className="flex items-center justify-between">
     {title && <p>{title}</p>}
     {trigger || <ButtonPrimitive className="ml-auto" onClick={toggleCollapse}>{open ? <CollapseIcon/> : <ExpandIcon/>}</ButtonPrimitive>}
-</span>
+</header>

This change would:

  • Improve semantics with header tag
  • Remove inline styles
  • Better convey the layout intent

Inline styles should be converted to className-based styling for consistency

The verification reveals inconsistencies in styling approaches across the UI components:

  • Multiple components are still using inline styles for layout properties that could be managed through className patterns
  • The codebase shows extensive usage of clsx for className management, indicating a clear preference for this approach

Key areas needing attention:

  • The style={{ display: 'flex', alignItems: 'center' }} in Collapsible component should be converted to className
  • The style={{ marginInlineStart: 'auto' }} on ButtonPrimitive should use utility classes
  • Similar inline styles for layout in TreeItem, Dropdown, and other components should be refactored for consistency
🔗 Analysis chain

Line range hint 1-58: Verify consistency of className management across components

Since this PR is part of a broader effort to improve className management, let's verify the approach is consistent with other components.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other components using inline styles that could be converted to className
rg -t tsx "style={{" src/components/ui/

# Check for other uses of clsx in the codebase to ensure consistent patterns
rg -t tsx "className={clsx" src/components/ui/

Length of output: 297


Script:

#!/bin/bash
# Search for other components using inline styles that could be converted to className
rg --type tsx "style=\{\{" src/components/ui/

# Check for other uses of clsx in the codebase to ensure consistent patterns
rg --type tsx "className=\{clsx" src/components/ui/

Length of output: 157


Script:

#!/bin/bash
# Search for other components using inline styles that could be converted to className
rg "style=\{\{" --type-add 'tsx:*.tsx' src/components/ui/

# Check for other uses of clsx in the codebase to ensure consistent patterns
rg "className=\{clsx" --type-add 'tsx:*.tsx' src/components/ui/

Length of output: 7339

src/components/ui/Code/Code.tsx (1)

9-9: Consider simplifying the clsx usage

While the clsx usage is consistent with other components, using it for a single static className without conditionals or combinations could be simplified. However, keeping it for consistency with the codebase-wide pattern is also valid.

- return <code className={clsx('rui-code-root')}>
+ return <code className="rui-code-root">
src/components/ui/HoverCard/fragments/HoverCardArrow.tsx (1)

9-9: Simplify clsx usage by removing template literal

The template literal inside clsx is unnecessary since clsx already handles string concatenation efficiently.

-    return <Floater.Arrow className={clsx(`${rootClass}-arrow`)} {...props} context={floatingContext} ref={arrowRef} />;
+    return <Floater.Arrow className={clsx(rootClass + '-arrow')} {...props} context={floatingContext} ref={arrowRef} />;
src/components/ui/Card/Card.tsx (1)

11-11: Simplify className handling

Using clsx with a single string argument provides no additional benefit over passing the string directly.

-    <CardRoot className={clsx(className)} customRootClass={customRootClass} {...props}>
+    <CardRoot className={className} customRootClass={customRootClass} {...props}>
src/components/ui/Kbd/Kbd.tsx (1)

Line range hint 8-13: Fix incorrect props type definition

The props property in KbdProps is incorrectly typed as an array of records, which is incompatible with the spread operator usage. It should extend from React's HTMLAttributes.

 export type KbdProps = {
     children: React.ReactNode;
     customRootClass?: string;
     className?: string;
-    props: Record<string, any>[];
-}
+} & React.HTMLAttributes<HTMLElement>
src/components/ui/AvatarGroup/fragments/AvatarGroupRoot.tsx (2)

Line range hint 5-9: Improve type definition for customRootClass

The type string | '' is unusual and can be simplified to just string since an empty string is already included in the string type.

 type AvatarGroupRootProps = {
-    customRootClass?: string | '';
+    customRootClass?: string;
     children: React.ReactNode;
     className?: string;
 }

14-14: Simplify clsx usage

The implementation is correct, but since we're not handling conditional classes, the template literal isn't necessary.

-        <div className={clsx(rootClass, className)} {...props}>
+        <div className={clsx(rootClass, className)} {...props}>
src/components/ui/AlertDialog/fragments/AlertDialogOverlay.tsx (1)

11-11: Simplify clsx usage

The current implementation uses a template literal inside clsx unnecessarily. Since we're concatenating a static suffix, we can simplify this.

-                    className={clsx(`${rootClass}-overlay`)} onClick={handleOverlayClick}>
+                    className={clsx(rootClass + '-overlay')} onClick={handleOverlayClick}>
src/components/ui/AlertDialog/fragments/AlertDialogContent.tsx (1)

14-14: Simplify clsx usage

For consistency with other components, simplify the clsx usage here as well.

-                <div className={clsx(`${rootClass}-content`)}>
+                <div className={clsx(rootClass + '-content')}>
src/components/ui/Em/Em.tsx (1)

Line range hint 8-13: Fix Props type definition

The props type is incorrectly defined as an array of Records. For an em element, it should extend React's HTML attributes.

export type EmProps = {
    children: React.ReactNode;
    customRootClass?: string;
    className?: string;
-   props: Record<string, any>[]
-}
+} & React.HTMLAttributes<HTMLElement>
src/components/ui/Quote/Quote.tsx (1)

Line range hint 8-13: Fix Props type definition

The props type should extend React's quote element attributes for proper typing support.

export type QuoteProps = {
    children: React.ReactNode;
    customRootClass?: string;
    className?: string;
-   props?: Record<string, any>[]
-}
+} & React.QuoteHTMLAttributes<HTMLQuoteElement>
src/components/ui/Card/fragments/CardRoot.tsx (2)

Line range hint 6-10: Improve type safety of props

The props type is too loose with any. Consider extending from appropriate React div element attributes.

export type CardRootProps = {
    children: React.ReactNode;
    customRootClass?: string;
    className?: string;
-   props?: any;
-};
+} & React.HTMLAttributes<HTMLDivElement>;

Line range hint 12-12: Remove unnecessary default value

The clsx utility handles undefined/empty values gracefully, making the default empty string unnecessary.

-const CardRoot = ({ children, customRootClass, className = '', ...props }: CardRootProps) => {
+const CardRoot = ({ children, customRootClass, className, ...props }: CardRootProps) => {
src/components/ui/BlockQuote/BlockQuote.tsx (1)

Line range hint 9-13: Consider improving type safety of props

The props type using Record<string, any>[] is too permissive and could lead to runtime errors. Consider:

  1. Using a more specific type for props
  2. Removing the array type as props are typically an object, not an array
 export type BlockQuoteProps = {
     children: React.ReactNode;
     customRootClass?: string;
     className?: string;
-    props: Record<string, any>[]
+    [key: string]: unknown;  // For additional HTML attributes
 }
src/components/ui/Callout/Callout.tsx (2)

18-20: Simplify className handling

The clsx(className) call is redundant when passing a single string. Since className already has a default empty string, you can pass it directly.

-    return (<CalloutRoot customRootClass={customRootClass} className={clsx(className)} color={color ?? undefined} {...props}>
+    return (<CalloutRoot customRootClass={customRootClass} className={className} color={color} {...props}>
         {children}
     </CalloutRoot>);

Line range hint 8-14: Consider improving type safety for color prop

The color prop could benefit from a union type of allowed values to prevent invalid colors.

 export type CalloutProps = {
     children?: React.ReactNode;
     className?: string;
-    color?: string;
+    color?: 'primary' | 'secondary' | 'warning' | 'error' | 'success';  // Add your supported colors
     customRootClass?: string;
     props?: object[]
 }
src/components/ui/Callout/fragments/CalloutRoot.tsx (1)

Line range hint 7-12: Ensure type consistency across components

There are some inconsistencies in the type definitions between Callout and CalloutRoot:

  1. className type differs: string | '' vs just string
  2. props type differs: Record<any, any>[] vs object[]
 type CalloutRootProps = {
     children?: React.ReactNode;
-    className?: string | '' ;
+    className?: string;
     color?: string;
     customRootClass?: string;
-    props?: Record<any, any>[]
+    [key: string]: unknown;  // For additional HTML attributes
 }
src/components/ui/Badge/Badge.tsx (1)

15-15: Simplify the color prop handling

The ?? undefined check is redundant since undefined is the default value when the prop is not provided.

-    return <BadgeRoot customRootClass={customRootClass} className={clsx(className)} color={color ?? undefined} {...props}>
+    return <BadgeRoot customRootClass={customRootClass} className={clsx(className)} color={color} {...props}>
src/components/ui/Badge/fragments/BadgeRoot.tsx (1)

18-18: Simplify the color prop handling

The ?? undefined check is redundant since undefined is the default value when the prop is not provided.

-        <span className={clsx(rootClass, className)} data-accent-color={color ?? undefined} {...props}>
+        <span className={clsx(rootClass, className)} data-accent-color={color} {...props}>
src/components/ui/Dropdown/Dropdown.tsx (2)

Line range hint 5-8: Address TODO and improve type safety

The component uses any type which reduces type safety. Consider defining proper interfaces for the list items and selected value.

 export type DropdownProps = {
-    list: {value: any}[];
-    selected: any;
+    list: Array<{
+        value: string | number | React.ReactNode;
+        id: string | number;
+    }>;
+    selected: string | number;
 }

12-12: Extract hardcoded class names into constants

Consider extracting the hardcoded class names into constants for better maintainability and reusability.

+const DROPDOWN_LIST_CLASSES = 'bg-white px-2 py-2 shadow-lg rounded-md';
+const DROPDOWN_WRAPPER_CLASSES = 'relative';
+
 const Dropdown = ({ list = [], selected }: DropdownProps) => {
     const PopElem = () => {
-        return <ul className={clsx('bg-white px-2 py-2 shadow-lg rounded-md')}>
+        return <ul className={clsx(DROPDOWN_LIST_CLASSES)}>
     // ...
-    return <div className={clsx('relative')}>
+    return <div className={clsx(DROPDOWN_WRAPPER_CLASSES)}>

Also applies to: 18-18

src/components/ui/Link/Link.tsx (2)

18-18: Remove commented out code

Since the alt prop issue has been addressed in the new implementation, this TODO comment and old implementation can be safely removed.


Line range hint 8-14: Remove invalid alt prop from LinkProps type

The alt prop is noted as invalid for anchor elements, but it's still included in the type definition. Consider removing it from the type definition as well.

export type LinkProps = {
    children: React.ReactNode;
    href: string;
-   alt?: string;
    customRootClass: string;
    className: string;
    props: Record<string, any>[];
}
src/components/ui/Accordion/fragments/AccordionContent.tsx (1)

4-4: Simplify clsx usage by removing template literal

While the current implementation works, we can simplify it by passing the class names directly to clsx without using template literals.

-className={clsx(`${rootClass}-content`, className)}
+className={clsx(rootClass + '-content', className)}

Or even better, if you prefer more readability:

-className={clsx(`${rootClass}-content`, className)}
+className={clsx([rootClass + '-content', className])}

Also applies to: 20-20

src/components/ui/Progress/fragments/ProgressIndicator.tsx (1)

4-4: Optimize clsx usage

The current implementation wraps a template literal in clsx, which is unnecessary. You can pass the string directly to clsx.

-            className={clsx(`${rootClass}-indicator`)}
+            className={clsx(rootClass + '-indicator')}

Also applies to: 31-31

src/components/ui/AlertDialog/fragments/AlertDialogRoot.tsx (1)

4-4: Consider simplifying className handling

The clsx usage here is unnecessary since there's only one class being used. Unless you're planning to add conditional classes in the future, this adds complexity without benefit.

-import { clsx } from 'clsx';
...
-            <div className={clsx(rootClass)} >
+            <div className={rootClass}>

Also applies to: 34-34

src/components/ui/Accordion/fragments/AccordionTrigger.tsx (1)

35-35: Optimize clsx usage by removing template literal

The current implementation uses template literal inside clsx which is unnecessary. The clsx utility can handle multiple arguments directly.

-            className={clsx(`${rootClass}-trigger`, className)}
+            className={clsx(rootClass + '-trigger', className)}

Or even better, to avoid string concatenation:

-            className={clsx(`${rootClass}-trigger`, className)}
+            className={clsx(rootClass && rootClass + '-trigger', className)}

This change makes the code more readable and handles the case where rootClass might be undefined.

src/components/ui/Modal/Modal.tsx (1)

18-19: Simplify className management

The current usage of clsx for static class names doesn't leverage its conditional merging capabilities. Consider using template strings for static classes.

-<div className={clsx('modal')}>
-    <div className={clsx('modal__content')}>
+<div className="modal">
+    <div className="modal__content">
src/components/ui/Accordion/fragments/AccordionRoot.tsx (1)

Line range hint 22-22: Remove empty useEffect hook

The useEffect hook is empty and can be removed.

-useEffect(() => {}, []);
src/components/ui/Accordion/fragments/AccordionItem.tsx (1)

Line range hint 70-70: Simplify conditional data attribute

The spread operator for conditional data attribute can be simplified using direct attribute assignment.

-{...shouldAddFocusDataAttribute ? { 'data-rad-ui-focus-element': '' } : {}}
+data-rad-ui-focus-element={shouldAddFocusDataAttribute ? '' : undefined}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 787c234 and 2690dc9.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (35)
  • package.json (1 hunks)
  • src/components/ui/Accordion/fragments/AccordionContent.tsx (2 hunks)
  • src/components/ui/Accordion/fragments/AccordionHeader.tsx (2 hunks)
  • src/components/ui/Accordion/fragments/AccordionItem.tsx (2 hunks)
  • src/components/ui/Accordion/fragments/AccordionRoot.tsx (2 hunks)
  • src/components/ui/Accordion/fragments/AccordionTrigger.tsx (2 hunks)
  • src/components/ui/AlertDialog/fragments/AlertDialogContent.tsx (2 hunks)
  • src/components/ui/AlertDialog/fragments/AlertDialogOverlay.tsx (1 hunks)
  • src/components/ui/AlertDialog/fragments/AlertDialogRoot.tsx (2 hunks)
  • src/components/ui/Avatar/Avatar.tsx (2 hunks)
  • src/components/ui/AvatarGroup/AvatarGroup.tsx (2 hunks)
  • src/components/ui/AvatarGroup/fragments/AvatarGroupRoot.tsx (2 hunks)
  • src/components/ui/Badge/Badge.tsx (2 hunks)
  • src/components/ui/Badge/fragments/BadgeRoot.tsx (2 hunks)
  • src/components/ui/BlockQuote/BlockQuote.tsx (2 hunks)
  • src/components/ui/Button/Button.tsx (2 hunks)
  • src/components/ui/Callout/Callout.tsx (2 hunks)
  • src/components/ui/Callout/fragments/CalloutRoot.tsx (2 hunks)
  • src/components/ui/Card/Card.tsx (1 hunks)
  • src/components/ui/Card/fragments/CardRoot.tsx (2 hunks)
  • src/components/ui/Code/Code.tsx (1 hunks)
  • src/components/ui/Collapsible/Collapsible.tsx (2 hunks)
  • src/components/ui/Dropdown/Dropdown.tsx (2 hunks)
  • src/components/ui/Em/Em.tsx (2 hunks)
  • src/components/ui/Heading/Heading.tsx (2 hunks)
  • src/components/ui/HoverCard/fragments/HoverCardArrow.tsx (1 hunks)
  • src/components/ui/HoverCard/fragments/HoverCardContent.tsx (2 hunks)
  • src/components/ui/HoverCard/fragments/HoverCardRoot.tsx (2 hunks)
  • src/components/ui/HoverCard/fragments/HoverCardTrigger.tsx (2 hunks)
  • src/components/ui/Kbd/Kbd.tsx (2 hunks)
  • src/components/ui/Link/Link.tsx (2 hunks)
  • src/components/ui/Modal/Modal.tsx (2 hunks)
  • src/components/ui/Progress/fragments/ProgressIndicator.tsx (2 hunks)
  • src/components/ui/Progress/fragments/ProgressRoot.tsx (2 hunks)
  • src/components/ui/Quote/Quote.tsx (2 hunks)
🧰 Additional context used
🪛 eslint
src/components/ui/Button/Button.tsx

[error] 24-24: Unexpected template string expression.

(no-template-curly-in-string)

🪛 Biome (1.9.4)
src/components/ui/Accordion/fragments/AccordionRoot.tsx

[error] 58-58: expected , but instead found {

Remove {

(parse)

🔇 Additional comments (32)
src/components/ui/HoverCard/fragments/HoverCardRoot.tsx (2)

Line range hint 1-119: Overall implementation looks solid

The hover card implementation demonstrates good practices:

  • Proper state management for controlled/uncontrolled modes
  • Well-implemented delay handling for open/close actions
  • Clean integration with floating UI
  • Good separation of concerns

117-117: 🛠️ Refactor suggestion

Reconsider the clsx usage pattern

The current implementation of clsx(rootClass) with a single argument doesn't leverage clsx's main benefits of handling conditional classes and preventing undefined/null values. Consider either:

  1. Using rootClass directly if no conditional logic is needed
  2. Adding conditional classes if needed

Let's check how customClassSwitcher handles undefined/null cases:

If conditional classes are needed, consider this pattern:

-<div className={clsx(rootClass)} {...props}>{children}</div>
+<div 
+  className={clsx(
+    rootClass,
+    {
+      'your-conditional-class': someCondition,
+      // Add more conditional classes as needed
+    }
+  )} 
+  {...props}
+>
+  {children}
+</div>
✅ Verification successful

Remove unnecessary clsx wrapper

The customClassSwitcher utility already handles undefined/null cases by returning an empty string, making the clsx wrapper redundant when used with a single argument. The utility:

  • Returns custom class if provided
  • Returns empty string for undefined component name
  • Generates prefixed class name for valid component names

Since there's no conditional class logic in the current implementation, you can safely use rootClass directly:

-<div className={clsx(rootClass)} {...props}>{children}</div>
+<div className={rootClass} {...props}>{children}</div>
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for customClassSwitcher implementation
ast-grep --pattern 'export const customClassSwitcher = $_' -A 10

Length of output: 1068

src/components/ui/AvatarGroup/AvatarGroup.tsx (1)

2-2: LGTM! Clean import of clsx utility.

The import is correctly placed and uses the recommended named import syntax.

src/components/ui/Button/Button.tsx (1)

4-4: LGTM: Clean clsx import

The import statement is correctly placed and aligns with the PR objective of standardizing className management.

src/components/ui/Collapsible/Collapsible.tsx (1)

3-3: LGTM! Import addition aligns with PR objectives

The addition of the clsx import is consistent with the PR's goal of improving className management.

src/components/ui/Code/Code.tsx (1)

3-3: LGTM: Import statement is correctly placed

The clsx import is properly added at the top of the file with other imports.

src/components/ui/Accordion/fragments/AccordionHeader.tsx (2)

2-2: LGTM: Import statement is correctly placed

The clsx import is properly added at the top of the file.


11-11: LGTM: Proper usage of clsx with optional className

The clsx usage here is appropriate as it handles the optional className prop, ensuring proper class name combination and undefined value handling.

src/components/ui/Progress/fragments/ProgressRoot.tsx (2)

2-2: LGTM: Import statement is correctly placed

The clsx import is properly added at the top of the file.


12-12: Verify customClassSwitcher compatibility with clsx

The integration looks correct, but let's verify that customClassSwitcher always returns a value type that clsx can handle properly.

✅ Verification successful

Let me search for the implementation of customClassSwitcher to verify its return type.


customClassSwitcher is compatible with clsx

The implementation shows that customClassSwitcher always returns a string value (either the custom class, an empty string, or a prefixed component name), which is fully compatible with clsx's type requirements. The function's return type is explicitly typed as :string and all code paths return string values.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for customClassSwitcher implementation and usage
ast-grep --pattern 'function customClassSwitcher($_) {
  $$$
}'

# Also check other usages for consistency
rg -A 2 'customClassSwitcher\(' 

Length of output: 9862


Script:

#!/bin/bash
# Search for the implementation file
fd customClassSwitcher.ts

# Once found, let's see its implementation
cat src/core/customClassSwitcher/customClassSwitcher.ts

Length of output: 169


Script:

#!/bin/bash
# Try alternative search patterns to locate the implementation
rg -l 'export.*customClassSwitcher'

# Search for any file containing customClassSwitcher implementation
rg -A 5 'function customClassSwitcher|const customClassSwitcher'

Length of output: 587


Script:

#!/bin/bash
# Let's see the complete implementation of customClassSwitcher
cat src/core/customClassSwitcher/index.ts

# And check how clsx is being used with it in other components
rg -A 2 'clsx\(.*customClassSwitcher'

Length of output: 714

src/components/ui/Card/Card.tsx (1)

11-11: Verify customRootClass handling in CardRoot

Ensure that the customRootClass prop is properly handled in the CardRoot component.

✅ Verification successful

customRootClass is properly handled in CardRoot

The verification shows that the customRootClass prop is correctly implemented in the CardRoot component:

  1. The prop is properly typed in the CardRootProps interface
  2. It's correctly passed through the component parameters
  3. It's properly processed using the customClassSwitcher utility which:
    • Returns the custom class if provided
    • Falls back to 'rad-ui-card' if not provided
  4. The resulting class is correctly applied to the root div element using clsx
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for CardRoot implementation to verify customRootClass handling
ast-grep --pattern 'const CardRoot = ({ customRootClass, $$$}) => {
  $$$
}'

Length of output: 78


Script:

#!/bin/bash
# Let's try different approaches to find CardRoot implementation

# Search for CardRoot styled component declaration
ast-grep --pattern 'const CardRoot = styled.$_'

# Search for CardRoot component declaration with different pattern
ast-grep --pattern 'const CardRoot = $_'

# Search for CardRoot in any form using ripgrep for more context
rg "CardRoot" -A 5

Length of output: 5460


Script:

#!/bin/bash
# Let's verify the customClassSwitcher implementation since it's used for customRootClass handling
rg "customClassSwitcher" -A 3

# Also check for COMPONENT_NAME constant in CardRoot
rg "COMPONENT_NAME.*=.*" src/components/ui/Card/fragments/CardRoot.tsx

Length of output: 22755

src/components/ui/Kbd/Kbd.tsx (1)

16-16: LGTM! Correct usage of clsx

The clsx usage here is appropriate for combining multiple class names.

src/components/ui/AvatarGroup/fragments/AvatarGroupRoot.tsx (1)

2-2: LGTM: Clean import of clsx utility

The import is correctly placed with other dependencies.

src/components/ui/AlertDialog/fragments/AlertDialogOverlay.tsx (1)

4-4: LGTM: Clean import of clsx utility

The import is correctly placed with other dependencies.

src/components/ui/AlertDialog/fragments/AlertDialogContent.tsx (1)

3-3: LGTM: Clean import of clsx utility

The import is correctly placed with other dependencies.

src/components/ui/Em/Em.tsx (1)

4-4: LGTM! Clean clsx implementation

The migration to clsx is implemented correctly. This change improves className handling by:

  • Preventing undefined values
  • Eliminating extra spaces
  • Providing better type safety

Also applies to: 16-16

src/components/ui/Quote/Quote.tsx (1)

4-4: LGTM! Clean clsx implementation

The migration to clsx is implemented correctly, maintaining consistency with other components.

Also applies to: 16-16

src/components/ui/Card/fragments/CardRoot.tsx (1)

3-3: LGTM! Clean clsx implementation

The migration to clsx is implemented correctly, providing better className handling.

Also applies to: 16-16

src/components/ui/BlockQuote/BlockQuote.tsx (1)

3-3: LGTM: clsx import and usage

The migration to clsx for className management is implemented correctly.

src/components/ui/Callout/fragments/CalloutRoot.tsx (1)

16-18: LGTM: Proper clsx implementation

The migration to clsx for className management is implemented correctly. The data attribute handling for color is also appropriate.

src/components/ui/Badge/Badge.tsx (1)

5-5: LGTM!

The clsx import is correctly added.

src/components/ui/Badge/fragments/BadgeRoot.tsx (1)

3-3: LGTM!

The clsx import is correctly added.

src/components/ui/Dropdown/Dropdown.tsx (1)

3-3: LGTM!

The clsx import is correctly added.

src/components/ui/HoverCard/fragments/HoverCardTrigger.tsx (1)

2-2: LGTM! Clean migration to clsx

The changes correctly implement the clsx utility for className management while maintaining the existing functionality.

Also applies to: 17-17

src/components/ui/Link/Link.tsx (1)

3-3: LGTM! Clean migration to clsx

The changes correctly implement the clsx utility for className management.

Also applies to: 22-22

src/components/ui/Accordion/fragments/AccordionContent.tsx (1)

4-4: Verify consistent clsx implementation across components

Let's verify that all components in the codebase follow the same pattern for className handling.

Also applies to: 20-20

✅ Verification successful

clsx implementation is consistent across UI components

The codebase shows a consistent pattern where:

  • All UI components properly import and use clsx for className handling
  • The majority of components use className={clsx(...)} syntax
  • Only two minor exceptions found in non-component files (stories and demo) that use string concatenation, which is acceptable for those cases
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining string interpolation or concatenation of classNames
rg "className=[\`'\"].*\$\{.*\}.*[\`'\"]" --type tsx
rg "className=.*\+" --type tsx

# Search for current clsx usage pattern
rg "className=\{clsx\(" --type tsx

Length of output: 209


Script:

#!/bin/bash
# Search for any remaining string interpolation or concatenation of classNames
rg "className=[\`'\"].*\$\{.*\}.*[\`'\"]"
rg "className=.*\+" 

# Search for current clsx usage pattern
rg "className=\{clsx\("

# Also check for imports
rg "import.*clsx"

Length of output: 8329

src/components/ui/Heading/Heading.tsx (1)

3-3: LGTM! Proper implementation of clsx

The changes correctly implement clsx for className management, maintaining consistency across both conditional rendering paths.

Also applies to: 38-38, 40-40

src/components/ui/Progress/fragments/ProgressIndicator.tsx (1)

1-1: Consider standardizing clsx usage patterns

While the migration to clsx is a good improvement, I notice varying implementation patterns across components. Consider establishing consistent patterns for:

  1. Order of className concatenation
  2. Handling of conditional classes
  3. Integration with customClassSwitcher

This will help maintain consistency as more components are migrated.

Let's check the current usage patterns:

src/components/ui/HoverCard/fragments/HoverCardContent.tsx (1)

2-2: LGTM: Import of clsx utility

The import aligns with the PR objective of standardizing className handling.

src/components/ui/Accordion/fragments/AccordionItem.tsx (1)

64-64: LGTM! Good use of clsx for className merging

The clsx usage here correctly merges the base class with optional className prop.

package.json (2)

132-132: LGTM! Good choice of dependency version.

The addition of clsx@^2.1.1 as a direct dependency is appropriate for runtime className management. The caret version range allows for compatible minor updates while maintaining stability.


132-132: Verify security status of clsx dependency.

Let's ensure the chosen version is free from known vulnerabilities.

✅ Verification successful

The clsx dependency version 2.1.1 is secure and up-to-date

The verification shows that:

  • 2.1.1 is the latest available version of clsx
  • No security vulnerabilities were found in the GitHub Advisory Database for clsx
  • npm audit shows no direct security issues with clsx (the reported vulnerabilities are from other dependencies)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for security advisories and verify latest version of clsx

# Check npm for latest versions and security advisories
npm view clsx versions --json
npm audit info clsx

# Check GitHub Advisory Database
gh api graphql -f query='
{
  securityVulnerabilities(first: 5, ecosystem: NPM, package: "clsx") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
      firstPatchedVersion {
        identifier
      }
    }
  }
}'

Length of output: 1841


const AvatarGroup = ({ avatars = [], size, customRootClass = '', className, ...props }: AvatarGroupProps) => {
return <AvatarGroupRoot customRootClass={customRootClass} className={className} {...props} >
return <AvatarGroupRoot customRootClass={customRootClass} className={clsx(className)} {...props} >
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve className handling for consistency and clarity.

The current implementation has several areas for improvement:

  1. customRootClass is not being processed by clsx, which could lead to inconsistent handling of class names
  2. Having both customRootClass and className props is redundant and could cause confusion
  3. Current clsx usage (clsx(className)) doesn't provide any additional benefit over using className directly

Consider applying these changes:

  1. Remove the redundant customRootClass prop and use only className
  2. Utilize clsx's ability to handle multiple classes and conditions:
- return <AvatarGroupRoot customRootClass={customRootClass} className={clsx(className)} {...props} >
+ return <AvatarGroupRoot className={clsx(className, customRootClass)} {...props} >

Then update the props type:

type AvatarGroupProps = {
    avatars: { fallback: string, src: string, alt: string }[];
    size: 'sm' | 'md' | 'lg';
-   customRootClass?: string;
    className?: string;
    props?: Record<string, any>;
}

Committable suggestion skipped: line range outside the PR's diff.

@@ -1,5 +1,5 @@
import React from 'react';

import { clsx } from 'clsx';
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Simplify unnecessary clsx usage and improve props handling

  1. Using clsx for a single className value is unnecessary. You can directly use className.
  2. Consider handling customRootClass consistently with clsx as well.
  3. The props spreading after className could potentially override it.
 import React from 'react';
-import { clsx } from 'clsx';
+import { clsx } from 'clsx';
 import AvatarPrimitive from '~/core/primitives/Avatar';

 const Avatar = ({ customRootClass = '', fallback, className, src, alt, ...props }: AvatarProps) => {
     return (
-        <AvatarPrimitive.Root src={src} customRootClass={customRootClass}>
+        <AvatarPrimitive.Root src={src} customRootClass={clsx(customRootClass)}>
             <AvatarPrimitive.Image
                 src={src}
                 alt={alt}
-                className={clsx(className)}
-                {...props}
+                {...props}
+                className={className}
             />

Also applies to: 23-23

onPointerEnter={openWithDelay}
onPointerLeave={closeWithDelay}
className={`${rootClass}`} {...props}
className={clsx(rootClass)} {...props}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider props spreading order and className composition

Two suggestions for improvement:

  1. The props spreading should come before the className to prevent overrides
  2. The clsx usage could be simplified since there's only one class
-        className={clsx(rootClass)} {...props}
+        {...props}
+        className={rootClass}

Note: If you plan to add conditional classes in the future, then keeping clsx would make sense. Otherwise, it adds unnecessary complexity for a single class.

📝 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.

Suggested change
className={clsx(rootClass)} {...props}
{...props}
className={rootClass}

Comment on lines +27 to +30
<FloatingOverlay className={clsx('overlay')} lockScroll>
<FloatingFocusManager context={context}>
<div className='fixed bg-black/80 overflow-auto w-screen h-screen grid place-items-center'>
<div className='bg-white p-4 inline-block rounded-md shadow-lg'>
<div className={clsx('fixed bg-black/80 overflow-auto w-screen h-screen grid place-items-center')}>
<div className={clsx('bg-white p-4 inline-block rounded-md shadow-lg')}>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance modal accessibility and className management

The modal overlay and content could benefit from improved accessibility attributes and better className organization.

-<FloatingOverlay className={clsx('overlay')} lockScroll>
+<FloatingOverlay 
+  className={clsx('overlay', {
+    'fixed inset-0': true,
+    'z-50': true
+  })}
+  lockScroll
+  aria-modal="true"
+  role="dialog"
+>
   <FloatingFocusManager context={context}>
-    <div className={clsx('fixed bg-black/80 overflow-auto w-screen h-screen grid place-items-center')}>
-      <div className={clsx('bg-white p-4 inline-block rounded-md shadow-lg')}>
+    <div className={clsx(
+      'fixed w-screen h-screen grid place-items-center',
+      'bg-black/80 overflow-auto'
+    )}>
+      <div className={clsx(
+        'inline-block',
+        'bg-white rounded-md shadow-lg',
+        'p-4'
+      )}>
📝 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.

Suggested change
<FloatingOverlay className={clsx('overlay')} lockScroll>
<FloatingFocusManager context={context}>
<div className='fixed bg-black/80 overflow-auto w-screen h-screen grid place-items-center'>
<div className='bg-white p-4 inline-block rounded-md shadow-lg'>
<div className={clsx('fixed bg-black/80 overflow-auto w-screen h-screen grid place-items-center')}>
<div className={clsx('bg-white p-4 inline-block rounded-md shadow-lg')}>
<FloatingOverlay
className={clsx('overlay', {
'fixed inset-0': true,
'z-50': true
})}
lockScroll
aria-modal="true"
role="dialog"
>
<FloatingFocusManager context={context}>
<div className={clsx(
'fixed w-screen h-screen grid place-items-center',
'bg-black/80 overflow-auto'
)}>
<div className={clsx(
'inline-block',
'bg-white rounded-md shadow-lg',
'p-4'
)}>

GoldGroove06 and others added 2 commits December 9, 2024 16:21
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@GoldGroove06 GoldGroove06 deleted the util-classname-2 branch December 12, 2024 04:23
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.

1 participant