-
-
Notifications
You must be signed in to change notification settings - Fork 67
refactor(components): create reusable left and right SVG chevron #319
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…s and use them across the app.
@YarikDrago is attempting to deploy a commit to the 8bitcn Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughIntroduces two new chevron icon asset components and updates multiple UI components to use them instead of inline SVGs or lucide-react icons. Numerous registry JSON files were normalized to CRLF line endings. One registry item removes a Button import while still using Button in login-form-with-image. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 52
🔭 Outside diff range comments (3)
components/ui/8bit/pagination.tsx (2)
132-155
: Accessibility: Provide an accessible name for “Previous” on small screens.On small viewports the “Previous” text is hidden (
hidden sm:block
), leaving only the icon with no accessible name. Addaria-label
to the link and keep the text available to screen readers.- return ( - <PaginationLink + return ( + <PaginationLink + aria-label="Previous" className={cn( "relative group", "flex flex-row w/full text-sm", ... )} {...props} > - <ChevronLeftIcon /> - <span className="hidden sm:block">Previous</span> + <ChevronLeftIcon aria-hidden="true" /> + <span className="sr-only sm:not-sr-only">Previous</span> </PaginationLink> );
157-181
: Accessibility + minor cleanup: add aria-label and remove duplicate classes.
- The label is hidden on small screens; add
aria-label
andsr-only
text.flex flex-row w-full text-sm
appears twice; remove the duplicate.- return ( - <PaginationLink + return ( + <PaginationLink + aria-label="Next" className={cn( "relative group", - "flex flex-row w-full text-sm", + "flex flex-row w-full text-sm", "bg-transparent hover:bg-transparent active:bg-transparent focus:bg-transparent", "rounded-none border-dashed border-y-4 border-transparent", "hover:border-foreground focus:border-foreground active:border-transparent", "dark:hover:border-ring dark:focus:border-ring", "data-[active=true]:border-none aria-[current=page]:border-none", - "flex flex-row text-sm w-full", font !== "normal" && "retro", className )} {...props} > - <span className="hidden sm:block">Next</span> - <ChevronRightIcon /> + <span className="sr-only sm:not-sr-only">Next</span> + <ChevronRightIcon aria-hidden="true" /> </PaginationLink> );components/ui/calendar.tsx (1)
137-146
: Don’t drop DayPicker-provided props; forward className/props and fix a11y on chevronsThe Chevron render function receives className and props from DayPicker. These are currently ignored for left/right chevrons, which can break theming, sizing, and a11y. Also, the asset icons include an aria-label, which can leak into the button’s accessible name.
- Forward className and props to the icon.
- Ensure the icon is decorative: aria-hidden="true" focusable="false".
- This requires the asset components to accept and spread SVG props.
Apply in components/ui/calendar.tsx:
- if (orientation === "left") { - return <ChevronLeftIcon />; - } + if (orientation === "left") { + return ( + <ChevronLeftIcon + className={cn("size-4", className)} + aria-hidden="true" + focusable="false" + {...props} + /> + ); + } ... - if (orientation === "right") { - return <ChevronRightIcon />; - } + if (orientation === "right") { + return ( + <ChevronRightIcon + className={cn("size-4", className)} + aria-hidden="true" + focusable="false" + {...props} + /> + ); + }Update the assets to accept props and default to aria-hidden:
// components/ui/8bit/assets/chevronLeftIcon.tsx import { cn } from "@/lib/utils"; export const ChevronLeftIcon: React.FC<React.SVGProps<SVGSVGElement>> = ({ className, ...props }) => ( <svg viewBox="0 0 256 256" fill="currentColor" stroke="currentColor" strokeWidth="0.25" className={cn(className)} aria-hidden="true" focusable="false" {...props} > {/* rects */} </svg> ); // components/ui/8bit/assets/chevronRightIcon.tsx import { cn } from "@/lib/utils"; export const ChevronRightIcon: React.FC<React.SVGProps<SVGSVGElement>> = ({ className, ...props }) => ( <svg viewBox="0 0 256 256" fill="currentColor" stroke="currentColor" strokeWidth="0.25" className={cn(className)} aria-hidden="true" focusable="false" {...props} > {/* rects */} </svg> );
♻️ Duplicate comments (1)
public/r/8bit-card.json (1)
13-13
: Same note as 8bit-card in login-form: verify doubleclassName
usage.The wrapper and inner
ShadcnCard
both receiveclassName
. Confirm this is intentional for the 8-bit wrapper pattern; otherwise, consider omitting it from one layer as suggested earlier.
🧹 Nitpick comments (55)
public/r/8bit-alert-dialog.json (2)
13-13
: alertDialogVariants is defined but not used; either remove it or apply it to compose classes.Right now cva is only used for typing (VariantProps) while runtime class composition is manual. Prefer one source of truth.
Apply cva for class composition:
- export const alertDialogVariants = cva("", { + export const alertDialogVariants = cva("", { variants: { font: { normal: "", retro: "retro", }, }, defaultVariants: { font: "retro", }, }); interface BitAlertDialogContentProps extends React.ComponentProps<typeof AlertDialogPrimitive.Content>, VariantProps<typeof alertDialogVariants> {} function AlertDialogContent({ className, children, font, ...props }: BitAlertDialogContentProps) { return ( <AlertDialogPortal> <AlertDialogOverlay /> - <> - <ShadcnAlertDialogContent - className={cn( - "rounded-none border-y-6 border-foreground dark:border-ring", - font !== "normal" && "retro", - className - )} - {...props} - > + <ShadcnAlertDialogContent + className={cn( + "rounded-none border-y-6 border-foreground dark:border-ring", + alertDialogVariants({ font }), + className + )} + {...props} + > {children} <div className="absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none" aria-hidden="true" /> - </ShadcnAlertDialogContent> - </> + </ShadcnAlertDialogContent> </AlertDialogPortal> ); }
13-13
: Remove redundant React fragment around ShadcnAlertDialogContent.The empty fragment inside AlertDialogPortal serves no purpose.
- <AlertDialogPortal> - <AlertDialogOverlay /> - <> - <ShadcnAlertDialogContent + <AlertDialogPortal> + <AlertDialogOverlay /> + <ShadcnAlertDialogContent className={cn( "rounded-none border-y-6 border-foreground dark:border-ring", font !== "normal" && "retro", className )} {...props} > {children} <div className="absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none" aria-hidden="true" /> - </ShadcnAlertDialogContent> - </> + </ShadcnAlertDialogContent> </AlertDialogPortal>public/r/8bit-sidebar.json (1)
19-19
: Consider replacing CSS @import Google Fonts with next/font (self-hosted) for performance and CSP resilienceUsing
@import
to pull Google Fonts can be render-blocking and brittle under strict CSP. If this is a Next.js app (common with shadcn setups), prefernext/font/google
to self-host and automatically preload.Example (outside this JSON, in the TSX that consumes the font):
import { Press_Start_2P } from "next/font/google"; const pressStart2P = Press_Start_2P({ weight: "400", subsets: ["latin"], display: "swap" }); // then use: className={cn(pressStart2P.className, "retro ...")}Optional repo hygiene: to avoid churn from CRLF/LF flips in registry content, ensure
.gitattributes
or.editorconfig
normalizes line endings consistently across platforms.public/r/8bit-drawer.json (3)
13-13
: Remove unnecessary Fragment in DrawerTrigger.The empty Fragment adds no value here.
Patch:
function DrawerTrigger({ className, children, ...props }: React.ComponentProps<typeof DrawerPrimitive.Trigger>) { return ( - <> <ShadcnDrawerTrigger className={cn( "border-foreground dark:border-ring hover:bg-transparent active:bg-transparent focus:bg-transparent rounded-none border-4 focus:border-foreground hover:border-foreground dark:focus:border-ring bg-transparent data-[state=open]:bg-transparent data-[state=open]:border-foreground dark:data-[state=open]:border-ring", className, "retro" )} {...props} > {children} </ShadcnDrawerTrigger> - </> ); }
13-13
: Minor className cleanup in Header/Footer.
cn("", className, "retro")
includes a redundant empty string. Not harmful, but noisy.Patch:
- return ( - <ShadcnDrawerHeader className={cn("", className, "retro")} {...props}> + return ( + <ShadcnDrawerHeader className={cn(className, "retro")} {...props}> {children} </ShadcnDrawerHeader> );- return ( - <ShadcnDrawerFooter className={cn("", className, "retro")} {...props}> + return ( + <ShadcnDrawerFooter className={cn(className, "retro")} {...props}> {children} </ShadcnDrawerFooter> );
19-19
: Prefer self-hosted or next/font for Google Fonts; avoid @import in component CSS.Using
@import
inside component-scoped CSS can trigger additional blocking requests and duplicates across components. Consider:
- Load the font once via next/font/google (preferred) or a top-level
<link>
in your Document/head.- Self-host fonts for privacy/compliance and reliability.
Example with next/font:
// app/fonts.ts import { Press_Start_2P } from "next/font/google"; export const pressStart = Press_Start_2P({ weight: "400", subsets: ["latin"], display: "swap" }); // usage // <div className={`${pressStart.className} retro`}>...</div>If keeping the CSS file, move the
@import
to a global stylesheet that is included once, and have.retro
only setfont-family
.public/r/8bit-alert.json (2)
13-13
: Optional: forwardRef for consistency with shadcn/ui patternsAlign with shadcn components by forwarding refs from your wrapper to the root element. This improves composability (e.g., focusing, anchoring portals/popovers).
Apply this diff to components/ui/8bit/alert.tsx:
-import type React from "react"; +import type React from "react"; import { type VariantProps, cva } from "class-variance-authority"; @@ -function Alert({ - children, - className, - font, - variant, - ...rest -}: BitAlertProps) { - return ( - <div className={cn("relative", className)}> +const Alert = React.forwardRef<HTMLDivElement, BitAlertProps>(function Alert( + { children, className, font, variant, ...rest }, + ref +) { + return ( + <div ref={ref} className={cn("relative", className)}> <ShadcnAlert {...rest} variant={variant} className={cn( "relative rounded-none border-none bg-background", alertVariants({ font }) )} > {children} </ShadcnAlert> @@ -} +}); +Alert.displayName = "Alert";
19-19
: Nit: Prefer next/font or self-hosted fonts over CSS @importUsing
@import
for Google Fonts is less performant and can be render-blocking. Since this is a Next.js app, consider next/font (withPress_Start_2P
) or self-hosting. You already usedisplay=swap
, which is good.Example (Next.js):
import { Press_Start_2P } from "next/font/google"; export const pressStart2P = Press_Start_2P({ subsets: ["latin"], weight: "400", display: "swap", variable: "--font-retro", });Then apply
className={pressStart2P.className}
or use the CSS variable for your.retro
class.public/r/8bit-health-bar.json (1)
11-11
: Confirm CRLF normalization policy to avoid cross-platform churn.These content entries switched to CRLF. Ensure your repo’s .gitattributes intentionally enforces CRLF for these files (or globally) to prevent future churn and inconsistent diffs across platforms.
Also applies to: 17-17, 23-23
public/r/8bit-command.json (1)
19-19
: Optional: Avoid CSS @import for Google Fonts; prefer next/font or self-hosting for performanceUsing @import to load fonts can block rendering and is discouraged. Consider migrating to next/font (or self-hosting the font files) to improve performance and avoid FOUC/CLS.
If you want, I can provide a next/font-based version of the retro font setup that preserves the same styling.
public/r/8bit-skeleton.json (1)
19-19
: CSS is fine; note that Google Fonts @import can be suboptimal for performanceThe
.retro
scoping anddisplay=swap
are good. If this component appears frequently, consider moving the Google Font loading to a global<link>
in the app shell or self-hosting to reduce duplicate fetch overhead and improve caching.public/r/8bit-sheet.json (1)
13-13
: Tidy up the close SVG: drop empty attr, avoid conflicting sizing, remove duplicate rect.Small cleanups to the inline SVG improve readability and avoid redundant DOM attrs.
Apply this diff to the embedded TSX (components/ui/8bit/sheet.tsx):
- <svg - width={50} - height={50} + <svg viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" strokeWidth={0.25} - color="" className="w-6 h-6" aria-label="x" > @@ - <rect - width={14} - height={14} - rx={1} - transform="matrix(0 -1 -1 0 136 136)" - /> + {/* (duplicate rect at 136,136 removed) */}public/r/8bit-toast.json (1)
13-13
: Avoid shadowing and simplify classes in toast helper.Rename the parameter to reduce confusion with the exported
toast
and simplify the className literal; also mark the unused callback id with a leading underscore.Apply this diff to components/ui/8bit/toast.tsx:
-export function toast(toast: string) { - return sonnerToast.custom((id) => <Toast id={id} title={toast} />); +export function toast(message: string) { + return sonnerToast.custom((_id) => <Toast id={_id} title={message} />); } @@ - return ( - <div className={`relative ${"retro"}`}> + return ( + <div className="relative retro">public/r/8bit-table.json (1)
13-13
: Trim redundant padding classes.
p-4 py-2.5
is overlapping; preferpx-4 py-2.5
for clarity.Apply this diff to components/ui/8bit/table.tsx:
- default: "p-4 py-2.5 border-y-6 border-foreground dark:border-ring", + default: "px-4 py-2.5 border-y-6 border-foreground dark:border-ring",public/r/8bit-login-form.json (3)
16-16
: Replace placeholder “#” link with a button to avoid accidental navigation.Using
href="#"
can cause undesired scroll/navigation. Use a button for the placeholder action.Apply this diff to components/ui/8bit/blocks/login-form.tsx:
- <a - href="#" - className="inline-block text-xs underline-offset-4 hover:underline" - > - Forgot password? - </a> + <button + type="button" + className="inline-block text-left text-xs underline-offset-4 hover:underline" + aria-label="Forgot password" + > + Forgot password? + </button>
28-28
: Double-application ofclassName
(wrapper and inner). Confirm intent.
className
is applied to both the outer wrapper and the innerShadcnCard
. This can lead to unexpected styling cascades. If this is intentional for the 8-bit wrappers, ignore. Otherwise, omitclassName
from one of them.If you want to restrict
className
to the inner card only, adjust like:-function Card({ ...props }: BitCardProps) { - const { className, font } = props; +function Card({ ...props }: BitCardProps) { + const { className, font, ...rest } = props as any; @@ - <ShadcnCard - {...props} + <ShadcnCard + {...rest} className={cn( "rounded-none border-0 !w-full", font !== "normal" && "retro", className )} />
40-40
: RenameinputVariants
tolabelVariants
for clarity in Label.Minor naming mismatch; improves readability.
Apply this diff to components/ui/8bit/label.tsx:
-export const inputVariants = cva("", { +export const labelVariants = cva("", { @@ -interface BitLabelProps - extends React.ComponentProps<typeof LabelPrimitive.Root>, - VariantProps<typeof inputVariants> { +interface BitLabelProps + extends React.ComponentProps<typeof LabelPrimitive.Root>, + VariantProps<typeof labelVariants> {public/r/8bit-radio-group.json (1)
13-13
: Avoid duplicatingclassName
on both wrapper and ItemThe same
className
is applied to the outer wrapper and the innerItem
, which can lead to conflicting styles and unexpected specificity. Apply userclassName
only to the interactive root (Item
) and keep the wrapper stable.Apply this minimal change (if you don’t adopt the forwardRef diff above, adjust accordingly):
- return ( - <div className={cn("relative", className)}> + return ( + <div className="relative"> <RadioGroupPrimitive.Item ref={ref} className={cn( "...", - className + className )} {...props} >public/r/8bit-select.json (2)
13-13
: Don’t reuse the sameclassName
for both wrapper andSelectTrigger
Passing
className
to both the wrapper div and the Shadcn trigger can cause styling collisions. Keep the wrapper’s styling stable and apply customclassName
to the trigger only.Apply this diff to components/ui/8bit/select.tsx:
-function SelectTrigger({ children, ...props }: BitSelectTriggerProps) { - const { className, font } = props; +function SelectTrigger({ children, ...props }: BitSelectTriggerProps) { + const { className, font } = props; return ( - <div - className={cn( - "relative border-y-6 border-foreground dark:border-ring", - className, - font !== "normal" && "retro" - )} - > + <div className={cn("relative border-y-6 border-foreground dark:border-ring", font !== "normal" && "retro")}> <ShadcnSelectTrigger {...props} className={cn("rounded-none ring-0 w-full border-0", className)} > {children} </ShadcnSelectTrigger> <div className="absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none" aria-hidden="true" /> </div> ); }
13-13
: Type consistency: use the same source for ScrollDown/Up button prop types
SelectScrollDownButton
usesSelectPrimitive.ScrollDownButton
for its prop type, whileSelectScrollUpButton
uses the Shadcn alias. Align them to avoid subtle mismatches.-function SelectScrollDownButton({ - className, - ...props -}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) { +function SelectScrollDownButton({ + className, + ...props +}: React.ComponentProps<typeof ShadcnSelectScrollDownButton>) { return <ShadcnSelectScrollDownButton className={cn(className)} {...props} />; }public/r/8bit-dropdown-menu.json (1)
13-13
: Fix typo in type name:BitDropdownMenuContentProps
The type is spelled
BitDropownMenuContentProps
. Rename toBitDropdownMenuContentProps
and update usages for clarity and consistency.Apply this diff to components/ui/8bit/dropdown-menu.tsx:
-export interface BitDropownMenuContentProps +export interface BitDropdownMenuContentProps extends React.ComponentProps<typeof DropdownMenuPrimitive.Content>, VariantProps<typeof dropDownVariants> {} function DropdownMenuContent({ children, font, className, ...props -}: BitDropownMenuContentProps) { +}: BitDropdownMenuContentProps) { return ( <ShadcnDropdownMenuContent className={cn("mt-1 py-2", font !== "normal" && "retro", className)} {...props} > {children} @@ function DropdownMenuSubContent({ children, className, font, ...props -}: BitDropownMenuContentProps) { +}: BitDropdownMenuContentProps) { return ( <ShadcnDropdownMenuSubContent {...props} className={cn("bg-popover", font !== "normal" && "retro", className)} > {children}public/r/8bit-badge.json (1)
13-13
: Nit: className splitting is brittle
className.split(" ")
can produce empty tokens and fails on multiple spaces/newlines. Consider a more robust tokenization or use a whitelist approach for spacing vs visual classes.Possible minimal hardening:
- const classes = className.split(" "); + const classes = className.trim().split(/\s+/).filter(Boolean);public/r/8bit-slider.json (2)
11-11
: Avoid embedding CRLF sequences in registry “content”; prefer LF to prevent cross‑platform churnThe embedded file content now uses CRLF escape sequences (e.g., "\r\n"). When these registry items are consumed to generate files, this can cause noisy diffs and inconsistent line-endings across OSes/editors. Unless there’s a hard requirement for CRLF in the generated artifacts, keep the embedded content on LF.
- Action: Normalize embedded content newlines to "\n".
- Repo hygiene: Enforce LF via .gitattributes/.editorconfig to prevent future flips.
Example .gitattributes (repo root):
+*.ts text eol=lf +*.tsx text eol=lf +*.css text eol=lf +public/r/*.json text eol=lf
17-17
: Same CRLF issue in retro.css content blockLine endings inside the embedded CSS are CRLF. Recommend normalizing to "\n" for consistency and to avoid noisy diffs when files are materialized from the registry.
public/r/8bit-button.json (2)
13-13
: Normalize embedded TS content to LF line endingsThe “content” payload contains "\r\n". Prefer "\n" to keep generated files consistent across environments.
19-19
: Normalize embedded CSS content to LFSame as above—avoid CRLF in embedded content strings to reduce cross‑platform churn.
public/r/8bit-navigation-menu.json (1)
19-19
: Normalize embedded CSS content to LFThe content string uses CRLF. Prefer LF to keep downstream generated files consistent and avoid noisy diffs.
public/r/8bit-audio-settings.json (1)
15-15
: CRLF line endings embedded across multiple content blocks; recommend LFThe following embedded files use "\r\n" newlines in their content strings:
- Line 15: components/ui/8bit/blocks/audio-settings.tsx
- Line 21: components/ui/8bit/styles/retro.css
- Line 27: components/ui/8bit/switch.tsx
- Line 33: components/ui/8bit/card.tsx
- Line 39: components/ui/8bit/slider.tsx
- Line 45: components/ui/8bit/label.tsx
Unless you intentionally want CRLF in the generated artifacts, standardize on "\n". This reduces churn when the registry emits files on different platforms and editors.
Repo hygiene suggestion (root .gitattributes):
+*.ts text eol=lf +*.tsx text eol=lf +*.css text eol=lf +public/r/*.json text eol=lfAlso applies to: 21-21, 27-27, 33-33, 39-39, 45-45
public/r/8bit-cheat-code.json (2)
14-14
: CRLF embedded in multiple content strings; standardize to LFThe embedded contents for:
- Line 14: components/ui/8bit/blocks/cheat-code.tsx
- Line 21: components/ui/8bit/alert.tsx
- Line 26: components/ui/8bit/card.tsx
- Line 32: components/ui/8bit/styles/retro.css
all use "\r\n". Recommend normalizing to "\n" to avoid noisy diffs when these registry entries are used to generate files.
Also applies to: 21-21, 26-26, 32-32
14-14
: Optional: consider 8‑bit styled arrows for consistency with the chevron refactor scopeCheat code visuals still use lucide-react Arrow icons. This is fine (PR targets chevrons), but if visual consistency across all directional glyphs is desired, consider swapping to 8‑bit styled arrow assets in a follow-up, similar to the chevron standardization.
public/r/8bit-textarea.json (2)
13-13
: Avoid duplicatingclassName
on wrapper and textarea; introducewrapperClassName
Passing the same
className
prop to both the wrapper<div>
and the inner<ShadcnTextarea>
can cause unintended style leakage and specificity conflicts. Prefer a distinct prop for the wrapper.Apply this diff to components/ui/8bit/textarea.tsx:
-import { type VariantProps, cva } from "class-variance-authority"; +import { type VariantProps, cva } from "class-variance-authority"; import { cn } from "@/lib/utils"; import { Textarea as ShadcnTextarea } from "@/components/ui/textarea"; import "./styles/retro.css"; export const inputVariants = cva("", { variants: { font: { normal: "", retro: "retro", }, }, defaultVariants: { font: "retro", }, }); export interface BitTextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement>, VariantProps<typeof inputVariants> { asChild?: boolean; + wrapperClassName?: string; } -function Textarea({ ...props }: BitTextareaProps) { - const { className, font } = props; +function Textarea({ wrapperClassName, ...props }: BitTextareaProps) { + const { className, font } = props; return ( - <div className={cn("relative w-full", className)}> + <div className={cn("relative w-full", wrapperClassName)}> <ShadcnTextarea {...props} className={cn( - "rounded-none transition-transform ring-0 border-0", - font !== "normal" && "retro", - className + "rounded-none transition-transform ring-0 border-0", + font !== "normal" && "retro", + className )} /> <div className="absolute inset-0 border-y-6 -my-1.5 border-foreground dark:border-ring pointer-events-none" aria-hidden="true" /> <div className="absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none" aria-hidden="true" /> </div> ); } export { Textarea };
13-13
: Optional: UseinputVariants
instead of manualfont
checksYou already define
inputVariants
; using it will centralize styling logic and reduce drift.Apply this localized change in components/ui/8bit/textarea.tsx:
- className={cn( - "rounded-none transition-transform ring-0 border-0", - font !== "normal" && "retro", - className - )} + className={cn( + "rounded-none transition-transform ring-0 border-0", + inputVariants({ font }), + className + )}public/r/8bit-resizable.json (1)
11-11
: Addaria-label
to the resize handle for accessibilityThe handle is focusable and visually indicated; adding an
aria-label
improves screen reader discoverability.Apply this diff to components/ui/8bit/resizable.tsx:
<ResizablePrimitive.PanelResizeHandle className={cn( `relative flex w-[1px] items-center justify-center after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-[6px] data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90 focus:dark:outline-ring`, "bg-foreground dark:bg-ring", className )} + aria-label="Resize panel" {...props} >
public/r/8bit-input-otp.json (1)
13-13
: Avoid duplicatingclassName
on wrapper and input; addwrapperClassName
and reuse variants
className
is applied to both wrapper<div>
and<ShadcnInputOTP>
. Separate the concerns to prevent style conflicts. Also, reuseinputVariants
for consistency.Apply this diff to components/ui/8bit/input-otp.tsx:
-import { type VariantProps, cva } from "class-variance-authority"; +import { type VariantProps, cva } from "class-variance-authority"; import { cn } from "@/lib/utils"; import { InputOTP as ShadcnInputOTP, InputOTPGroup as ShadcnInputOTPGroup, InputOTPSeparator as ShadcnInputOTPSeparator, InputOTPSlot as ShadcnInputOTPSlot, } from "@/components/ui/input-otp"; import "./styles/retro.css"; export const inputVariants = cva("", { variants: { font: { normal: "", retro: "retro", }, }, defaultVariants: { font: "retro", }, }); interface SharedProps extends React.ComponentProps<"div">, VariantProps<typeof inputVariants> { className?: string; children?: React.ReactNode; } -interface InputOTPProps { +interface InputOTPProps extends VariantProps<typeof inputVariants> { maxLength: number; value?: string; onChange?: (value: string) => unknown; children?: React.ReactNode; className?: string; - font?: "normal" | "retro"; + wrapperClassName?: string; } -export const InputOTP = ({ - className, - font, - maxLength, - value, - onChange, - children, - ...otherProps -}: InputOTPProps) => { +export const InputOTP = ({ + className, + font, + wrapperClassName, + maxLength, + value, + onChange, + children, + ...otherProps +}: InputOTPProps) => { return ( - <div className={cn("relative w-fit", className)}> + <div className={cn("relative w-fit", wrapperClassName)}> <ShadcnInputOTP maxLength={maxLength} value={value} onChange={onChange} {...otherProps} - className={cn(font !== "normal" && "retro", className)} + className={cn(inputVariants({ font }), className)} > {children} </ShadcnInputOTP> </div> ); };public/r/8bit-toggle-group.json (2)
13-13
: Remove stray whitespace text nodes ({" "}
) around childrenThese produce unnecessary text nodes and can complicate layout. Safe to remove.
Apply this diff to components/ui/8bit/toggle-group.tsx:
function ToggleGroup({ ...props }: BitToggleGroupProps) { const { className, font, children } = props; return ( <ShadcnToggleGroup className={cn("gap-3", className, font !== "normal" && "retro")} {...props} > - {" "} - {children}{" "} + {children} </ShadcnToggleGroup> ); } function ToggleGroupItem({ ...props }: BitToggleGroupItemProps) { const { className, font, children, variant } = props; return ( <ShadcnToggleGroupItem className={cn( "relative transition-transform active:translate-x-1 active:translate-y-1", className, font !== "normal" && "retro" )} {...props} > - {" "} - {children}{" "} + {children} {variant === "outline" && ( <> - {" "} <div className="absolute inset-0 -my-1.5 border-y-6 border-foreground dark:border-ring pointer-events-none" aria-hidden="true" - />{" "} + /> <div className="absolute inset-0 -mx-1.5 border-x-6 border-foreground dark:border-ring pointer-events-none" aria-hidden="true" - />{" "} + /> </> )} </ShadcnToggleGroupItem> ); }
13-13
: Either use the declaredtoggleGroupVariants
or remove it to avoid confusion
toggleGroupVariants
defines size and variant styles but isn’t applied in eitherToggleGroup
orToggleGroupItem
. This is dead/ambiguous config; consider splitting intogroupVariants
anditemVariants
, or wire it properly.Option A (preferable): Split CVAs and apply them where they belong (item: size/variant; group: font).
Option B: If keeping a single CVA, at least use it on
ToggleGroupItem
:- <ShadcnToggleGroupItem - className={cn( - "relative transition-transform active:translate-x-1 active:translate-y-1", - className, - font !== "normal" && "retro" - )} + <ShadcnToggleGroupItem + className={cn( + "relative transition-transform active:translate-x-1 active:translate-y-1", + toggleGroupVariants({ font, variant }), + className + )}Note: If
size
should apply to items too, include it in the call and ensure defaults are correct.public/r/8bit-combo-box.json (1)
15-15
: Deduplicate the repeated pixel-border markup (DRY).The same border/shadow fragments are duplicated in both the
asChild
and non-asChild
branches. Extract a tiny internal component (e.g., BorderChrome) or a function returning that JSX to improve maintainability and reduce diff noise on future changes.public/r/8bit-chart-area-step.json (1)
11-11
: Nit: Consider replacing lucide iconActivity
with an 8‑bit-styled asset for consistency.While out of scope for the chevron refactor, swapping
Activity
for a local 8‑bit icon would better align with the visual direction.public/r/8bit-mana-bar.json (1)
17-17
: Micro-optimization: compute filledSquares once per render, not per iterationIn
Progress
,filledSquares
is recalculated inside themap
callback 20 times. It’s cheap, but easy to move out for clarity and minor perf.Apply this diff inside
components/ui/8bit/progress.tsx
:- {variant === "retro" && ( - <div className="flex w-full"> - {Array.from({ length: 20 }).map((_, i) => { - const filledSquares = Math.round(((value || 0) / 100) * 20); - return ( - <div - key={i} - className={cn( - "size-2 mx-[1px] w-full", - i < filledSquares ? progressBg : "bg-transparent" - )} - /> - ); - })} - </div> - )} + {variant === "retro" && ( + <div className="flex w-full"> + {(() => { + const filledSquares = Math.round(((value || 0) / 100) * 20); + return Array.from({ length: 20 }).map((_, i) => ( + <div + key={i} + className={cn( + "size-2 mx-[1px] w-full", + i < filledSquares ? progressBg : "bg-transparent" + )} + /> + )); + })()} + </div> + )}public/r/8bit-popover.json (1)
13-13
: Consistent naming: preferpopoverVariants
overpopOverVariants
Minor nit: keep naming consistent with other components (
progressVariants
,tabsVariants
). RenamepopOverVariants
topopoverVariants
and update usages.Apply this diff inside
components/ui/8bit/popover.tsx
:-export const popOverVariants = cva("", { +export const popoverVariants = cva("", { variants: { font: { normal: "", retro: "retro", }, }, defaultVariants: { font: "retro", }, }); export interface BitPopoverProps - extends React.ComponentProps<typeof PopoverPrimitive.Content>, - VariantProps<typeof popOverVariants> {} + extends React.ComponentProps<typeof PopoverPrimitive.Content>, + VariantProps<typeof popoverVariants> {} function PopoverContent({ children, - font, + font, className, ...props }: BitPopoverProps) {public/r/8bit-game-progress.json (1)
29-29
: Apply the same filledSquares micro-optimization as in ManaBar registrySee comment in 8bit-mana-bar.json; identical
Progress
body here benefits from computingfilledSquares
once.Apply the same diff in
components/ui/8bit/progress.tsx
within this registry entry.public/r/8bit-carousel.json (4)
13-13
: Remove leftover console.debug logs in handlersThe
console.log("scrolled prev/next")
calls are noisy in production.Apply this diff inside
components/ui/8bit/carousel.tsx
:- const scrollPrev = React.useCallback(() => { - console.log("scrolled prev"); - api?.scrollPrev(); - }, [api]); + const scrollPrev = React.useCallback(() => { + api?.scrollPrev(); + }, [api]); - const scrollNext = React.useCallback(() => { - console.log("scrolled next"); - api?.scrollNext(); - }, [api]); + const scrollNext = React.useCallback(() => { + api?.scrollNext(); + }, [api]);
13-13
: Simplifyorientation
value provided via contextGiven the default parameter
orientation = "horizontal"
, the fallback usingopts?.axis
is effectively unreachable. Provide the prop’s resolved value directly.Apply this diff inside
components/ui/8bit/carousel.tsx
:<CarouselContext.Provider value={{ carouselRef, api: api, opts, - orientation: - orientation || (opts?.axis === "y" ? "vertical" : "horizontal"), + orientation, scrollPrev, scrollNext, canScrollPrev, canScrollNext, }} >
13-13
: Accessibility: hide decorative SVGs and avoid redundant aria-labelsIf you keep SVGs (before switching to assets), set
aria-hidden="true"
on SVG and rely on the<span className="sr-only">…</span>
for accessible labels. Avoidaria-label
on SVGs which can cause duplicate announcements.Apply this diff inside
components/ui/8bit/carousel.tsx
:- <svg + <svg width="50" height="50" viewBox="0 0 256 256" fill="currentColor" - xmlns="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" stroke="currentColor" strokeWidth="0.25" color="currentColor" - aria-label="arrow-left" + aria-hidden="true" > @@ - <svg + <svg width="50" height="50" viewBox="0 0 256 256" fill="currentColor" className="block" - xmlns="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" stroke="currentColor" strokeWidth="0.25" color="currentColor" - aria-label="arrow-right" + aria-hidden="true" >
13-13
: Remove duplicatedaspect-square
class
aspect-square
is declared both in the orientation-specific class and the base class string. Keep it once in the base for consistency.Apply this diff inside
components/ui/8bit/carousel.tsx
:- className={cn( - orientation === "horizontal" - ? "top-1/2 -left-10 md:-left-14 -translate-y-1/2 active:-translate-y-1 w-8 h-9 md:w-9 md:h-10 " - : "-top-12 left-1/2 -translate-x-1/2 rotate-90 w-8 h-10 md:w-9 md:h-11", - "absolute rounded-none aspect-square grid place-items-center", - className - )} + className={cn( + orientation === "horizontal" + ? "top-1/2 -left-10 md:-left-14 -translate-y-1/2 active:-translate-y-1 w-8 h-9 md:w-9 md:h-10" + : "-top-12 left-1/2 -translate-x-1/2 rotate-90 w-8 h-10 md:w-9 md:h-11", + "absolute rounded-none aspect-square grid place-items-center", + className + )} @@ - className={cn( - orientation === "horizontal" - ? "top-1/2 -right-10 md:-right-14 -translate-y-1/2 active:-translate-y-1 aspect-square shrink-0 w-8 h-9 md:w-9 md:h-10 " - : "-bottom-12 left-1/2 -translate-x-1/2 rotate-90 w-8 h-10 md:w-9 md:h-11", - "absolute rounded-none aspect-square grid place-items-center", - className - )} + className={cn( + orientation === "horizontal" + ? "top-1/2 -right-10 md:-right-14 -translate-y-1/2 active:-translate-y-1 shrink-0 w-8 h-9 md:w-9 md:h-10" + : "-bottom-12 left-1/2 -translate-x-1/2 rotate-90 w-8 h-10 md:w-9 md:h-11", + "absolute rounded-none aspect-square grid place-items-center", + className + )}components/ui/8bit/assets/chevronLeftIcon.tsx (1)
12-13
: Ensure consistency with ChevronRightIcon default classesThe right chevron reportedly uses className "raster-icon size-7" while the left uses only "size-7". Standardize both to the same default classes to avoid subtle layout/antialiasing differences.
If you keep "raster-icon" on the right icon, mirror it here (included in the diff above). Otherwise, remove it from the right icon for parity. Do you want me to prepare a follow-up patch for ChevronRightIcon as well?
components/ui/8bit/menubar.tsx (1)
343-343
: Typo in displayName (non-blocking).
MenubarShortcut.displayname
should bedisplayName
to show correctly in DevTools.-MenubarShortcut.displayname = "MenubarShortcut"; +MenubarShortcut.displayName = "MenubarShortcut";components/ui/pagination.tsx (2)
79-81
: Consider sizing/semantics on the left chevron (optional).The asset uses a relatively large default size. For tighter pagination buttons, a smaller icon often reads better, and decorative icons should be hidden from a11y trees.
After making the icon accept props, consider:
- <ChevronLeftIcon /> + <ChevronLeftIcon className="size-4" aria-hidden="true" />
96-98
: Consider sizing/semantics on the right chevron (optional).Same rationale as for the left chevron: use smaller size and mark as decorative.
- <ChevronRightIcon /> + <ChevronRightIcon className="size-4" aria-hidden="true" />components/ui/8bit/breadcrumb.tsx (1)
137-142
: Separator renders the new chevron correctly; consider avoiding double sizing and noisy aria-labels
- The parent adds "[&>svg]:size-7" while the asset’s SVG already has "size-7". This redundancy is harmless but noisy. Prefer one source of truth for sizing to avoid future specificity issues.
- The asset includes aria-label="chevron-right". The ShadcnBreadcrumbSeparator wrapper from components/ui/breadcrumb sets aria-hidden on the container, so it’s fine here, but in other contexts the label could be read unnecessarily.
Two follow-ups:
- Optional nit: remove one of the size declarations (either keep the parent utility or make the asset size-agnostic).
- Consider updating the asset to accept className/props and omit the fixed size. Example:
// components/ui/8bit/assets/chevronRightIcon.tsx (suggested signature) export const ChevronRightIcon = (props: React.SVGProps<SVGSVGElement>) => { const { className, ...rest } = props return ( <svg viewBox="0 0 256 256" fill="currentColor" stroke="currentColor" strokeWidth="0.25" className={cn("raster-icon", className)} aria-hidden="true" {...rest} > {/* rects... */} </svg> ) }public/r/8bit-menubar.json (1)
11-11
: Typo: displayName property is misspelled.
MenubarShortcut.displayname = "MenubarShortcut";
should bedisplayName
(capital N). The current typo prevents DevTools/component names from being set correctly.-MenubarShortcut.displayname = "MenubarShortcut"; +MenubarShortcut.displayName = "MenubarShortcut";public/r/8bit-login-form-with-image.json (1)
16-16
: Nit: unnecessary template literal for a constant class.
className={\
${"retro"} ...`}` can be simplified to a literal string.- <p - className={`${"retro"} text-balance text-center text-xs text-muted-foreground [&_a]:underline [&_a]:underline-offset-4 hover:[&_a]:text-primary`} - > + <p className="retro text-balance text-center text-xs text-muted-foreground [&_a]:underline [&_a]:underline-offset-4 hover:[&_a]:text-primary">public/r/8bit-breadcrumb.json (1)
13-13
: Make icon assets unopinionated and props-friendlyBreadcrumbSeparator enforces size via "[&>svg]:size-7", but the asset also hard-codes "size-7". Prefer unopinionated assets that accept className and spread props so callers can size/style them consistently.
Proposed asset shape (components/ui/8bit/assets/chevronRightIcon.tsx):
import { cn } from "@/lib/utils"; export const ChevronRightIcon: React.FC<React.SVGProps<SVGSVGElement>> = ({ className, ...props }) => { return ( <svg width="50" height="50" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" strokeWidth="0.25" className={cn("raster-icon", className)} aria-hidden="true" focusable="false" {...props} > {/* rects */} </svg> ); };public/r/8bit-pagination.json (2)
13-13
: Remove duplicate classes in PaginationNext"flex flex-row w/full text-sm" is duplicated, adding noise.
- "relative group", - "flex flex-row w-full text-sm", + "relative group", + "flex flex-row w-full text-sm", "bg-transparent hover:bg-transparent active:bg-transparent focus:bg-transparent", "rounded-none border-dashed border-y-4 border-transparent", "hover:border-foreground focus:border-foreground active:border-transparent", "dark:hover:border-ring dark:focus:border-ring", "data-[active=true]:border-none aria-[current=page]:border-none", - "flex flex-row text-sm w-full", font !== "normal" && "retro", className
13-13
: Minor: prefer consistent import style for ButtonElsewhere you use "@/components/ui/button". Consider replacing import { Button } from "../button" with the alias for consistency.
export const ChevronLeftIcon = () => { | ||
return ( | ||
<svg | ||
width="50" | ||
height="50" | ||
viewBox="0 0 256 256" | ||
fill="currentColor" | ||
xmlns="http://www.w3.org/2000/svg" | ||
stroke="currentColor" | ||
strokeWidth="0.25" | ||
color="" | ||
className="size-7" | ||
aria-label="chevron-left" | ||
> | ||
<rect | ||
width="14" | ||
height="14" | ||
rx="1" | ||
transform="matrix(-1 0 0 1 128 136)" | ||
></rect> | ||
<rect | ||
width="14" | ||
height="14" | ||
rx="1" | ||
transform="matrix(-1 0 0 1 144 152)" | ||
></rect> | ||
<rect | ||
width="14" | ||
height="14" | ||
rx="1" | ||
transform="matrix(-1 0 0 1 160 72)" | ||
></rect> | ||
<rect | ||
width="14" | ||
height="14" | ||
rx="1" | ||
transform="matrix(-1 0 0 1 160 168)" | ||
></rect> | ||
<rect | ||
width="14" | ||
height="14" | ||
rx="1" | ||
transform="matrix(-1 0 0 1 112 120)" | ||
></rect> | ||
<rect | ||
width="14" | ||
height="14" | ||
rx="1" | ||
transform="matrix(-1 0 0 1 128 104)" | ||
></rect> | ||
<rect | ||
width="14" | ||
height="14" | ||
rx="1" | ||
transform="matrix(-1 0 0 1 144 88)" | ||
></rect> | ||
</svg> | ||
); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Make the icon truly reusable: accept SVG props, fix a11y defaults, and remove invalid attribute
Forwarding standard SVG props (className, aria-label, etc.) and merging classes makes this asset versatile. Also remove the empty color=""
attribute and default to decorative a11y unless a label is provided.
Apply this diff:
+import type { SVGProps } from "react";
-
-export const ChevronLeftIcon = () => {
+export function ChevronLeftIcon({
+ className,
+ "aria-label": ariaLabel,
+ ...props
+}: SVGProps<SVGSVGElement>) {
return (
<svg
- width="50"
- height="50"
viewBox="0 0 256 256"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
stroke="currentColor"
strokeWidth="0.25"
- color=""
- className="size-7"
- aria-label="chevron-left"
+ shapeRendering="crispEdges"
+ aria-hidden={ariaLabel ? undefined : true}
+ aria-label={ariaLabel}
+ className={["raster-icon size-7", className].filter(Boolean).join(" ")}
+ {...props}
>
<rect
width="14"
height="14"
rx="1"
transform="matrix(-1 0 0 1 128 136)"
></rect>
<rect
width="14"
height="14"
rx="1"
transform="matrix(-1 0 0 1 144 152)"
></rect>
<rect
width="14"
height="14"
rx="1"
transform="matrix(-1 0 0 1 160 72)"
></rect>
<rect
width="14"
height="14"
rx="1"
transform="matrix(-1 0 0 1 160 168)"
></rect>
<rect
width="14"
height="14"
rx="1"
transform="matrix(-1 0 0 1 112 120)"
></rect>
<rect
width="14"
height="14"
rx="1"
transform="matrix(-1 0 0 1 128 104)"
></rect>
<rect
width="14"
height="14"
rx="1"
transform="matrix(-1 0 0 1 144 88)"
></rect>
</svg>
);
-};
+}
Notes:
- Allowing users to pass className means they can override the default Tailwind size; default listed first so user-specified classes win on conflicts.
aria-hidden
defaults to true unless anaria-label
is provided, which is the typical pattern for decorative icons.shapeRendering="crispEdges"
helps preserve the blocky 8‑bit look for the rects.
📝 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 const ChevronLeftIcon = () => { | |
return ( | |
<svg | |
width="50" | |
height="50" | |
viewBox="0 0 256 256" | |
fill="currentColor" | |
xmlns="http://www.w3.org/2000/svg" | |
stroke="currentColor" | |
strokeWidth="0.25" | |
color="" | |
className="size-7" | |
aria-label="chevron-left" | |
> | |
<rect | |
width="14" | |
height="14" | |
rx="1" | |
transform="matrix(-1 0 0 1 128 136)" | |
></rect> | |
<rect | |
width="14" | |
height="14" | |
rx="1" | |
transform="matrix(-1 0 0 1 144 152)" | |
></rect> | |
<rect | |
width="14" | |
height="14" | |
rx="1" | |
transform="matrix(-1 0 0 1 160 72)" | |
></rect> | |
<rect | |
width="14" | |
height="14" | |
rx="1" | |
transform="matrix(-1 0 0 1 160 168)" | |
></rect> | |
<rect | |
width="14" | |
height="14" | |
rx="1" | |
transform="matrix(-1 0 0 1 112 120)" | |
></rect> | |
<rect | |
width="14" | |
height="14" | |
rx="1" | |
transform="matrix(-1 0 0 1 128 104)" | |
></rect> | |
<rect | |
width="14" | |
height="14" | |
rx="1" | |
transform="matrix(-1 0 0 1 144 88)" | |
></rect> | |
</svg> | |
); | |
}; | |
import type { SVGProps } from "react"; | |
export function ChevronLeftIcon({ | |
className, | |
"aria-label": ariaLabel, | |
...props | |
}: SVGProps<SVGSVGElement>) { | |
return ( | |
<svg | |
viewBox="0 0 256 256" | |
fill="currentColor" | |
xmlns="http://www.w3.org/2000/svg" | |
stroke="currentColor" | |
strokeWidth="0.25" | |
shapeRendering="crispEdges" | |
aria-hidden={ariaLabel ? undefined : true} | |
aria-label={ariaLabel} | |
className={["raster-icon size-7", className].filter(Boolean).join(" ")} | |
{...props} | |
> | |
<rect | |
width="14" | |
height="14" | |
rx="1" | |
transform="matrix(-1 0 0 1 128 136)" | |
></rect> | |
<rect | |
width="14" | |
height="14" | |
rx="1" | |
transform="matrix(-1 0 0 1 144 152)" | |
></rect> | |
<rect | |
width="14" | |
height="14" | |
rx="1" | |
transform="matrix(-1 0 0 1 160 72)" | |
></rect> | |
<rect | |
width="14" | |
height="14" | |
rx="1" | |
transform="matrix(-1 0 0 1 160 168)" | |
></rect> | |
<rect | |
width="14" | |
height="14" | |
rx="1" | |
transform="matrix(-1 0 0 1 112 120)" | |
></rect> | |
<rect | |
width="14" | |
height="14" | |
rx="1" | |
transform="matrix(-1 0 0 1 128 104)" | |
></rect> | |
<rect | |
width="14" | |
height="14" | |
rx="1" | |
transform="matrix(-1 0 0 1 144 88)" | |
></rect> | |
</svg> | |
); | |
} |
🤖 Prompt for AI Agents
In components/ui/8bit/assets/chevronLeftIcon.tsx around lines 1 to 59, the
component should accept and forward standard SVG props, remove the invalid empty
color attribute, and default accessibility to decorative unless an aria-label is
provided; update the SVG to accept props (e.g. function signature
ChevronLeftIcon(props: React.SVGProps<SVGSVGElement>)), spread props onto the
<svg> (placing the default className "size-7" first so user className in props
can override), remove color="", set aria-hidden to true when no aria-label is
present (and do not override if aria-label exists), and add
shapeRendering="crispEdges" to the rect elements to preserve the 8‑bit look.
> | ||
{children} | ||
<ChevronRight className="ml-auto size-4" /> | ||
<ChevronRightIcon /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Restore right-align spacing for submenu chevron.
The lucide chevron previously had ml-auto
to push it to the end of the row. The new <ChevronRightIcon />
lacks that, causing alignment regressions.
Minimal fix in-place:
- <ChevronRightIcon />
+ <span className="ml-auto">
+ <ChevronRightIcon />
+ </span>
Optional (after enabling props on the asset icon): also match previous size and a11y semantics.
- <ChevronRightIcon />
+ <ChevronRightIcon className="ml-auto size-4" aria-hidden="true" />
📝 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.
<ChevronRightIcon /> | |
<span className="ml-auto"> | |
<ChevronRightIcon /> | |
</span> |
🤖 Prompt for AI Agents
In components/ui/8bit/context-menu.tsx around line 42, the submenu chevron lost
its right-alignment because the new <ChevronRightIcon /> is missing the previous
ml-auto spacing; restore the right alignment by adding the same right-margin
utility (e.g. ml-auto) to the ChevronRightIcon element, and optionally restore
prior sizing and accessibility semantics by passing the previous size props and
an appropriate aria-hidden or aria-label as needed.
<rect x="128" y="104" width="14" height="14" rx="1"></rect> | ||
<rect x="112" y="88" width="14" height="14" rx="1"></rect> | ||
</svg> | ||
<ChevronRightIcon /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Restore right-align spacing for submenu chevron.
Previous implementation aligned the chevron to the far right (typically via ml-auto
). The new <ChevronRightIcon />
lacks that spacing, so the icon will sit next to the text.
Minimal fix in-place:
- <ChevronRightIcon />
+ <span className="ml-auto">
+ <ChevronRightIcon />
+ </span>
Optional (after making the icon accept props): shrink and right-align the icon for consistency with previous lucide size:
- <ChevronRightIcon />
+ <ChevronRightIcon className="ml-auto size-4" aria-hidden="true" />
📝 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.
<ChevronRightIcon /> | |
<span className="ml-auto"> | |
<ChevronRightIcon /> | |
</span> |
🤖 Prompt for AI Agents
In components/ui/8bit/menubar.tsx around line 115 the submenu chevron
<ChevronRightIcon /> lost its right-align spacing and now sits next to the menu
text; restore the previous right alignment by giving the icon an auto-left
margin (e.g., add className="ml-auto" to the icon or wrap it in a span/div with
className="ml-auto") so it’s pushed to the far right, and optionally update the
icon usage to pass a smaller size prop (matching the previous lucide size) once
the icon accepts props.
{ | ||
"path": "components/ui/8bit/accordion.tsx", | ||
"content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport * as AccordionPrimitive from \"@radix-ui/react-accordion\";\n\nimport { cn } from \"@/lib/utils\";\n\nimport {\n Accordion as ShadcnAccordion,\n AccordionContent as ShadcnAccordionContent,\n AccordionItem as ShadcnAccordionItem,\n AccordionTrigger as ShadcnAccordionTrigger,\n} from \"@/components/ui/accordion\";\n\nimport \"./styles/retro.css\";\n\nexport interface BitAccordionItemProps\n extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item> {\n asChild?: boolean;\n}\n\nfunction AccordionItem({\n className,\n children,\n ...props\n}: BitAccordionItemProps) {\n return (\n <ShadcnAccordionItem\n className={cn(\n \"border-dashed border-b-4 border-foreground dark:border-ring relative\",\n className\n )}\n {...props}\n >\n {children}\n </ShadcnAccordionItem>\n );\n}\n\nexport interface BitAccordionTriggerProps\n extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger> {\n font?: \"normal\" | \"retro\";\n}\n\nfunction AccordionTrigger({\n className,\n children,\n font,\n ...props\n}: BitAccordionTriggerProps) {\n return (\n <ShadcnAccordionTrigger\n className={cn(font !== \"normal\" && \"retro\", className)}\n {...props}\n >\n {children}\n </ShadcnAccordionTrigger>\n );\n}\n\nexport interface BitAccordionContentProps\n extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content> {\n font?: \"normal\" | \"retro\";\n}\n\nfunction AccordionContent({\n className,\n children,\n font,\n ...props\n}: BitAccordionContentProps) {\n return (\n <div className=\"relative\">\n <ShadcnAccordionContent\n className={cn(\n \"overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down\",\n font !== \"normal\" && \"retro\",\n className\n )}\n {...props}\n >\n <div className=\"pb-4 pt-0 relative z-10 p-1\">{children}</div>\n </ShadcnAccordionContent>\n\n <AccordionPrimitive.Content asChild forceMount />\n </div>\n );\n}\n\nconst Accordion = ShadcnAccordion;\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent };\n", | ||
"content": "\"use client\";\r\n\r\nimport * as React from \"react\";\r\n\r\nimport * as AccordionPrimitive from \"@radix-ui/react-accordion\";\r\n\r\nimport { cn } from \"@/lib/utils\";\r\n\r\nimport {\r\n Accordion as ShadcnAccordion,\r\n AccordionContent as ShadcnAccordionContent,\r\n AccordionItem as ShadcnAccordionItem,\r\n AccordionTrigger as ShadcnAccordionTrigger,\r\n} from \"@/components/ui/accordion\";\r\n\r\nimport \"./styles/retro.css\";\r\n\r\nexport interface BitAccordionItemProps\r\n extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item> {\r\n asChild?: boolean;\r\n}\r\n\r\nfunction AccordionItem({\r\n className,\r\n children,\r\n ...props\r\n}: BitAccordionItemProps) {\r\n return (\r\n <ShadcnAccordionItem\r\n className={cn(\r\n \"border-dashed border-b-4 border-foreground dark:border-ring relative\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n {children}\r\n </ShadcnAccordionItem>\r\n );\r\n}\r\n\r\nexport interface BitAccordionTriggerProps\r\n extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger> {\r\n font?: \"normal\" | \"retro\";\r\n}\r\n\r\nfunction AccordionTrigger({\r\n className,\r\n children,\r\n font,\r\n ...props\r\n}: BitAccordionTriggerProps) {\r\n return (\r\n <ShadcnAccordionTrigger\r\n className={cn(font !== \"normal\" && \"retro\", className)}\r\n {...props}\r\n >\r\n {children}\r\n </ShadcnAccordionTrigger>\r\n );\r\n}\r\n\r\nexport interface BitAccordionContentProps\r\n extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content> {\r\n font?: \"normal\" | \"retro\";\r\n}\r\n\r\nfunction AccordionContent({\r\n className,\r\n children,\r\n font,\r\n ...props\r\n}: BitAccordionContentProps) {\r\n return (\r\n <div className=\"relative\">\r\n <ShadcnAccordionContent\r\n className={cn(\r\n \"overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down\",\r\n font !== \"normal\" && \"retro\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n <div className=\"pb-4 pt-0 relative z-10 p-1\">{children}</div>\r\n </ShadcnAccordionContent>\r\n\r\n <AccordionPrimitive.Content asChild forceMount />\r\n </div>\r\n );\r\n}\r\n\r\nconst Accordion = ShadcnAccordion;\r\n\r\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent };\r\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove stray <AccordionPrimitive.Content asChild forceMount />
Rendering AccordionPrimitive.Content
with asChild
and no children is a no-op at best and potentially problematic. It creates an empty content node unrelated to the Shadcn content above and can cause unexpected behavior.
Apply this diff to components/ui/8bit/accordion.tsx:
</ShadcnAccordionContent>
-
- <AccordionPrimitive.Content asChild forceMount />
</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.
"content": "\"use client\";\r\n\r\nimport * as React from \"react\";\r\n\r\nimport * as AccordionPrimitive from \"@radix-ui/react-accordion\";\r\n\r\nimport { cn } from \"@/lib/utils\";\r\n\r\nimport {\r\n Accordion as ShadcnAccordion,\r\n AccordionContent as ShadcnAccordionContent,\r\n AccordionItem as ShadcnAccordionItem,\r\n AccordionTrigger as ShadcnAccordionTrigger,\r\n} from \"@/components/ui/accordion\";\r\n\r\nimport \"./styles/retro.css\";\r\n\r\nexport interface BitAccordionItemProps\r\n extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item> {\r\n asChild?: boolean;\r\n}\r\n\r\nfunction AccordionItem({\r\n className,\r\n children,\r\n ...props\r\n}: BitAccordionItemProps) {\r\n return (\r\n <ShadcnAccordionItem\r\n className={cn(\r\n \"border-dashed border-b-4 border-foreground dark:border-ring relative\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n {children}\r\n </ShadcnAccordionItem>\r\n );\r\n}\r\n\r\nexport interface BitAccordionTriggerProps\r\n extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger> {\r\n font?: \"normal\" | \"retro\";\r\n}\r\n\r\nfunction AccordionTrigger({\r\n className,\r\n children,\r\n font,\r\n ...props\r\n}: BitAccordionTriggerProps) {\r\n return (\r\n <ShadcnAccordionTrigger\r\n className={cn(font !== \"normal\" && \"retro\", className)}\r\n {...props}\r\n >\r\n {children}\r\n </ShadcnAccordionTrigger>\r\n );\r\n}\r\n\r\nexport interface BitAccordionContentProps\r\n extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content> {\r\n font?: \"normal\" | \"retro\";\r\n}\r\n\r\nfunction AccordionContent({\r\n className,\r\n children,\r\n font,\r\n ...props\r\n}: BitAccordionContentProps) {\r\n return (\r\n <div className=\"relative\">\r\n <ShadcnAccordionContent\r\n className={cn(\r\n \"overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down\",\r\n font !== \"normal\" && \"retro\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n <div className=\"pb-4 pt-0 relative z-10 p-1\">{children}</div>\r\n </ShadcnAccordionContent>\r\n\r\n <AccordionPrimitive.Content asChild forceMount />\r\n </div>\r\n );\r\n}\r\n\r\nconst Accordion = ShadcnAccordion;\r\n\r\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent };\r\n", | |
export interface BitAccordionContentProps | |
extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content> { | |
font?: "normal" | "retro"; | |
} | |
function AccordionContent({ | |
className, | |
children, | |
font, | |
...props | |
}: BitAccordionContentProps) { | |
return ( | |
<div className="relative"> | |
<ShadcnAccordionContent | |
className={cn( | |
"overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down", | |
font !== "normal" && "retro", | |
className | |
)} | |
{...props} | |
> | |
<div className="pb-4 pt-0 relative z-10 p-1">{children}</div> | |
</ShadcnAccordionContent> | |
</div> | |
); | |
} |
🤖 Prompt for AI Agents
In public/r/8bit-accordion.json around line 13 (source component located at
components/ui/8bit/accordion.tsx), there is a stray self-closing
<AccordionPrimitive.Content asChild forceMount /> rendered after the
ShadcnAccordionContent; remove that empty AccordionPrimitive.Content node so the
component only renders the ShadcnAccordionContent wrapper (delete the lone line)
and adjust imports if AccordionPrimitive.Content becomes unused.
{ | ||
"path": "components/ui/8bit/alert-dialog.tsx", | ||
"content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport * as AlertDialogPrimitive from \"@radix-ui/react-alert-dialog\";\nimport { type VariantProps, cva } from \"class-variance-authority\";\n\nimport { cn } from \"@/lib/utils\";\n\nimport {\n AlertDialog as ShadcnAlertDialog,\n AlertDialogAction as ShadcnAlertDialogAction,\n AlertDialogCancel as ShadcnAlertDialogCancel,\n AlertDialogContent as ShadcnAlertDialogContent,\n AlertDialogDescription as ShadcnAlertDialogDescription,\n AlertDialogFooter as ShadcnAlertDialogFooter,\n AlertDialogHeader as ShadcnAlertDialogHeader,\n AlertDialogOverlay as ShadcnAlertDialogOverlay,\n AlertDialogPortal as ShadcnAlertDialogPortal,\n AlertDialogTitle as ShadcnAlertDialogTitle,\n AlertDialogTrigger as ShadcnAlertDialogTrigger,\n} from \"@/components/ui/alert-dialog\";\n\nimport \"./styles/retro.css\";\n\nexport const alertDialogVariants = cva(\"\", {\n variants: {\n font: {\n normal: \"\",\n retro: \"retro\",\n },\n },\n defaultVariants: {\n font: \"retro\",\n },\n});\n\nexport interface BitAlertDialogProps\n extends React.ComponentProps<typeof AlertDialogPrimitive.Root>,\n VariantProps<typeof alertDialogVariants> {}\n\nfunction AlertDialog({ ...props }: BitAlertDialogProps) {\n return <ShadcnAlertDialog {...props} />;\n}\n\nfunction AlertDialogTrigger({\n className,\n asChild = true,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {\n return (\n <ShadcnAlertDialogTrigger\n className={cn(className)}\n asChild={asChild}\n {...props}\n />\n );\n}\n\nfunction AlertDialogPortal({\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {\n return <ShadcnAlertDialogPortal {...props} />;\n}\n\nfunction AlertDialogOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {\n return <ShadcnAlertDialogOverlay className={cn(className)} {...props} />;\n}\n\ninterface BitAlertDialogContentProps\n extends React.ComponentProps<typeof AlertDialogPrimitive.Content>,\n VariantProps<typeof alertDialogVariants> {}\n\nfunction AlertDialogContent({\n className,\n children,\n font,\n ...props\n}: BitAlertDialogContentProps) {\n return (\n <AlertDialogPortal>\n <AlertDialogOverlay />\n <>\n <ShadcnAlertDialogContent\n className={cn(\n \"rounded-none border-y-6 border-foreground dark:border-ring\",\n font !== \"normal\" && \"retro\",\n className\n )}\n {...props}\n >\n {children}\n\n <div\n className=\"absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none\"\n aria-hidden=\"true\"\n />\n </ShadcnAlertDialogContent>\n </>\n </AlertDialogPortal>\n );\n}\n\nfunction AlertDialogHeader({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return <ShadcnAlertDialogHeader className={cn(className)} {...props} />;\n}\n\nfunction AlertDialogFooter({\n className,\n ...props\n}: React.ComponentProps<\"div\">) {\n return (\n <ShadcnAlertDialogFooter\n className={cn(\"flex flex-col-reverse sm:flex-row gap-4\", className)}\n {...props}\n />\n );\n}\n\nfunction AlertDialogTitle({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {\n return <ShadcnAlertDialogTitle className={cn(className)} {...props} />;\n}\n\nfunction AlertDialogDescription({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {\n return <ShadcnAlertDialogDescription className={cn(className)} {...props} />;\n}\n\nfunction AlertDialogAction({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Action>) {\n return (\n <ShadcnAlertDialogAction\n className={cn(\n \"rounded-none active:translate-y-1 transition-transform relative bg-primary\",\n \"ring-0 border-none\",\n className\n )}\n {...props}\n >\n {props.children}\n {/* Pixelated border */}\n <div className=\"absolute -top-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute -top-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute -bottom-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute -bottom-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute top-0 left-0 size-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute top-0 right-0 size-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute bottom-0 left-0 size-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute bottom-0 right-0 size-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute top-1.5 -left-1.5 h-2/3 w-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute top-1.5 -right-1.5 h-2/3 w-1.5 bg-foreground dark:bg-ring\" />\n {/* Top shadow */}\n <div className=\"absolute top-0 left-0 w-full h-1.5 bg-foreground/20\" />\n <div className=\"absolute top-1.5 left-0 w-3 h-1.5 bg-foreground/20\" />\n {/* Bottom shadow */}\n <div className=\"absolute bottom-0 left-0 w-full h-1.5 bg-foreground/20\" />\n <div className=\"absolute bottom-1.5 right-0 w-3 h-1.5 bg-foreground/20\" />\n </ShadcnAlertDialogAction>\n );\n}\n\nfunction AlertDialogCancel({\n className,\n ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>) {\n return (\n <ShadcnAlertDialogCancel\n className={cn(\n \"rounded-none active:translate-y-1 transition-transform relative bg-background\",\n \"ring-0 border-none\",\n className\n )}\n {...props}\n >\n {props.children}\n <div className=\"absolute -top-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute -top-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute -bottom-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute -bottom-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute top-0 left-0 size-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute top-0 right-0 size-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute bottom-0 left-0 size-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute bottom-0 right-0 size-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute top-1.5 -left-1.5 h-2/3 w-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute top-1.5 -right-1.5 h-2/3 w-1.5 bg-foreground dark:bg-ring\" />\n </ShadcnAlertDialogCancel>\n );\n}\n\nexport {\n AlertDialog,\n AlertDialogPortal,\n AlertDialogOverlay,\n AlertDialogTrigger,\n AlertDialogContent,\n AlertDialogHeader,\n AlertDialogFooter,\n AlertDialogTitle,\n AlertDialogDescription,\n AlertDialogAction,\n AlertDialogCancel,\n};\n", | ||
"content": "\"use client\";\r\n\r\nimport * as React from \"react\";\r\n\r\nimport * as AlertDialogPrimitive from \"@radix-ui/react-alert-dialog\";\r\nimport { type VariantProps, cva } from \"class-variance-authority\";\r\n\r\nimport { cn } from \"@/lib/utils\";\r\n\r\nimport {\r\n AlertDialog as ShadcnAlertDialog,\r\n AlertDialogAction as ShadcnAlertDialogAction,\r\n AlertDialogCancel as ShadcnAlertDialogCancel,\r\n AlertDialogContent as ShadcnAlertDialogContent,\r\n AlertDialogDescription as ShadcnAlertDialogDescription,\r\n AlertDialogFooter as ShadcnAlertDialogFooter,\r\n AlertDialogHeader as ShadcnAlertDialogHeader,\r\n AlertDialogOverlay as ShadcnAlertDialogOverlay,\r\n AlertDialogPortal as ShadcnAlertDialogPortal,\r\n AlertDialogTitle as ShadcnAlertDialogTitle,\r\n AlertDialogTrigger as ShadcnAlertDialogTrigger,\r\n} from \"@/components/ui/alert-dialog\";\r\n\r\nimport \"./styles/retro.css\";\r\n\r\nexport const alertDialogVariants = cva(\"\", {\r\n variants: {\r\n font: {\r\n normal: \"\",\r\n retro: \"retro\",\r\n },\r\n },\r\n defaultVariants: {\r\n font: \"retro\",\r\n },\r\n});\r\n\r\nexport interface BitAlertDialogProps\r\n extends React.ComponentProps<typeof AlertDialogPrimitive.Root>,\r\n VariantProps<typeof alertDialogVariants> {}\r\n\r\nfunction AlertDialog({ ...props }: BitAlertDialogProps) {\r\n return <ShadcnAlertDialog {...props} />;\r\n}\r\n\r\nfunction AlertDialogTrigger({\r\n className,\r\n asChild = true,\r\n ...props\r\n}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {\r\n return (\r\n <ShadcnAlertDialogTrigger\r\n className={cn(className)}\r\n asChild={asChild}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction AlertDialogPortal({\r\n ...props\r\n}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {\r\n return <ShadcnAlertDialogPortal {...props} />;\r\n}\r\n\r\nfunction AlertDialogOverlay({\r\n className,\r\n ...props\r\n}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {\r\n return <ShadcnAlertDialogOverlay className={cn(className)} {...props} />;\r\n}\r\n\r\ninterface BitAlertDialogContentProps\r\n extends React.ComponentProps<typeof AlertDialogPrimitive.Content>,\r\n VariantProps<typeof alertDialogVariants> {}\r\n\r\nfunction AlertDialogContent({\r\n className,\r\n children,\r\n font,\r\n ...props\r\n}: BitAlertDialogContentProps) {\r\n return (\r\n <AlertDialogPortal>\r\n <AlertDialogOverlay />\r\n <>\r\n <ShadcnAlertDialogContent\r\n className={cn(\r\n \"rounded-none border-y-6 border-foreground dark:border-ring\",\r\n font !== \"normal\" && \"retro\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n {children}\r\n\r\n <div\r\n className=\"absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n </ShadcnAlertDialogContent>\r\n </>\r\n </AlertDialogPortal>\r\n );\r\n}\r\n\r\nfunction AlertDialogHeader({\r\n className,\r\n ...props\r\n}: React.ComponentProps<\"div\">) {\r\n return <ShadcnAlertDialogHeader className={cn(className)} {...props} />;\r\n}\r\n\r\nfunction AlertDialogFooter({\r\n className,\r\n ...props\r\n}: React.ComponentProps<\"div\">) {\r\n return (\r\n <ShadcnAlertDialogFooter\r\n className={cn(\"flex flex-col-reverse sm:flex-row gap-4\", className)}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction AlertDialogTitle({\r\n className,\r\n ...props\r\n}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {\r\n return <ShadcnAlertDialogTitle className={cn(className)} {...props} />;\r\n}\r\n\r\nfunction AlertDialogDescription({\r\n className,\r\n ...props\r\n}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {\r\n return <ShadcnAlertDialogDescription className={cn(className)} {...props} />;\r\n}\r\n\r\nfunction AlertDialogAction({\r\n className,\r\n ...props\r\n}: React.ComponentProps<typeof AlertDialogPrimitive.Action>) {\r\n return (\r\n <ShadcnAlertDialogAction\r\n className={cn(\r\n \"rounded-none active:translate-y-1 transition-transform relative bg-primary\",\r\n \"ring-0 border-none\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n {props.children}\r\n {/* Pixelated border */}\r\n <div className=\"absolute -top-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute -top-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute -bottom-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute -bottom-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute top-0 left-0 size-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute top-0 right-0 size-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute bottom-0 left-0 size-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute bottom-0 right-0 size-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute top-1.5 -left-1.5 h-2/3 w-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute top-1.5 -right-1.5 h-2/3 w-1.5 bg-foreground dark:bg-ring\" />\r\n {/* Top shadow */}\r\n <div className=\"absolute top-0 left-0 w-full h-1.5 bg-foreground/20\" />\r\n <div className=\"absolute top-1.5 left-0 w-3 h-1.5 bg-foreground/20\" />\r\n {/* Bottom shadow */}\r\n <div className=\"absolute bottom-0 left-0 w-full h-1.5 bg-foreground/20\" />\r\n <div className=\"absolute bottom-1.5 right-0 w-3 h-1.5 bg-foreground/20\" />\r\n </ShadcnAlertDialogAction>\r\n );\r\n}\r\n\r\nfunction AlertDialogCancel({\r\n className,\r\n ...props\r\n}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>) {\r\n return (\r\n <ShadcnAlertDialogCancel\r\n className={cn(\r\n \"rounded-none active:translate-y-1 transition-transform relative bg-background\",\r\n \"ring-0 border-none\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n {props.children}\r\n <div className=\"absolute -top-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute -top-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute -bottom-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute -bottom-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute top-0 left-0 size-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute top-0 right-0 size-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute bottom-0 left-0 size-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute bottom-0 right-0 size-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute top-1.5 -left-1.5 h-2/3 w-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute top-1.5 -right-1.5 h-2/3 w-1.5 bg-foreground dark:bg-ring\" />\r\n </ShadcnAlertDialogCancel>\r\n );\r\n}\r\n\r\nexport {\r\n AlertDialog,\r\n AlertDialogPortal,\r\n AlertDialogOverlay,\r\n AlertDialogTrigger,\r\n AlertDialogContent,\r\n AlertDialogHeader,\r\n AlertDialogFooter,\r\n AlertDialogTitle,\r\n AlertDialogDescription,\r\n AlertDialogAction,\r\n AlertDialogCancel,\r\n};\r\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Formatting-only change to CRLF looks fine; ensure EOL is pinned to avoid churn across OS.
No functional differences in the embedded TSX; only newlines normalized to CRLF. To keep future diffs clean on non-Windows dev machines/CI, pin EOL via .gitattributes for registry JSON (and/or generated component targets).
Run this script to verify .gitattributes has an explicit CRLF rule and that it covers public/r and/or the generated component paths:
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate .gitattributes
fd -H -a '^\.gitattributes$' | while read -r attr; do
echo "Found: $attr"
echo "---- Contents ($attr) ----"
nl -ba "$attr"
echo "--------------------------"
echo
done
# Show any CRLF rules
rg -n --fixed-strings 'eol=crlf' || echo "No explicit eol=crlf rules found."
# Check if there are rules targeting registry or generated component files
echo
echo "Rules targeting registry or 8bit component files (heuristic):"
rg -n 'public/r/|components/ui/8bit' .gitattributes || echo "No path-specific rules found for registry or 8bit components."
Length of output: 558
Add .gitattributes to pin CRLF for generated registry files
Verification: no .gitattributes was found and there are no 'eol=crlf' rules — the change in public/r/8bit-alert-dialog.json is CRLF-only, so pinning EOL will avoid future churn.
Please add a .gitattributes at the repo root (or update it) with rules like:
# Pin EOL for generated registry JSON and generated UI outputs
/public/r/* text eol=crlf
/components/ui/** text eol=crlf
Adjust patterns as needed for other generated targets.
🤖 Prompt for AI Agents
In public/r/8bit-alert-dialog.json around line 13 the file change is CRLF-only
and the repository lacks a .gitattributes entry to pin generated registry/UI
outputs to CRLF, causing future churn; add or update a .gitattributes at the
repo root and include rules that target generated registry JSON and generated UI
outputs (e.g., patterns for /public/r/* and /components/ui/**) setting text
eol=crlf so those files are normalized to CRLF on checkout.
{ | ||
"path": "components/ui/8bit/blocks/sidebar.tsx", | ||
"content": "import { Calendar, Home, Inbox, Search, Settings } from \"lucide-react\";\n\nimport {\n Sidebar,\n SidebarContent,\n SidebarGroup,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n} from \"@/components/ui/sidebar\";\n\nimport \"./styles/retro.css\";\n\n// Menu items.\nconst items = [\n {\n title: \"Home\",\n url: \"#\",\n icon: Home,\n },\n {\n title: \"Inbox\",\n url: \"#\",\n icon: Inbox,\n },\n {\n title: \"Calendar\",\n url: \"#\",\n icon: Calendar,\n },\n {\n title: \"Search\",\n url: \"#\",\n icon: Search,\n },\n {\n title: \"Settings\",\n url: \"#\",\n icon: Settings,\n },\n];\n\nexport function AppSidebar() {\n return (\n <Sidebar\n className={`${\"retro\"} border-r-4 border-foreground dark:border-ring`}\n >\n <SidebarContent>\n <SidebarGroup>\n <SidebarGroupLabel>Application</SidebarGroupLabel>\n <SidebarGroupContent>\n <SidebarMenu>\n {items.map((item) => (\n <SidebarMenuItem key={item.title}>\n <SidebarMenuButton asChild>\n <a href={item.url}>\n <item.icon />\n <span>{item.title}</span>\n </a>\n </SidebarMenuButton>\n </SidebarMenuItem>\n ))}\n </SidebarMenu>\n </SidebarGroupContent>\n </SidebarGroup>\n </SidebarContent>\n </Sidebar>\n );\n}\n", | ||
"content": "import { Calendar, Home, Inbox, Search, Settings } from \"lucide-react\";\r\n\r\nimport {\r\n Sidebar,\r\n SidebarContent,\r\n SidebarGroup,\r\n SidebarGroupContent,\r\n SidebarGroupLabel,\r\n SidebarMenu,\r\n SidebarMenuButton,\r\n SidebarMenuItem,\r\n} from \"@/components/ui/sidebar\";\r\n\r\nimport \"./styles/retro.css\";\r\n\r\n// Menu items.\r\nconst items = [\r\n {\r\n title: \"Home\",\r\n url: \"#\",\r\n icon: Home,\r\n },\r\n {\r\n title: \"Inbox\",\r\n url: \"#\",\r\n icon: Inbox,\r\n },\r\n {\r\n title: \"Calendar\",\r\n url: \"#\",\r\n icon: Calendar,\r\n },\r\n {\r\n title: \"Search\",\r\n url: \"#\",\r\n icon: Search,\r\n },\r\n {\r\n title: \"Settings\",\r\n url: \"#\",\r\n icon: Settings,\r\n },\r\n];\r\n\r\nexport function AppSidebar() {\r\n return (\r\n <Sidebar\r\n className={`${\"retro\"} border-r-4 border-foreground dark:border-ring`}\r\n >\r\n <SidebarContent>\r\n <SidebarGroup>\r\n <SidebarGroupLabel>Application</SidebarGroupLabel>\r\n <SidebarGroupContent>\r\n <SidebarMenu>\r\n {items.map((item) => (\r\n <SidebarMenuItem key={item.title}>\r\n <SidebarMenuButton asChild>\r\n <a href={item.url}>\r\n <item.icon />\r\n <span>{item.title}</span>\r\n </a>\r\n </SidebarMenuButton>\r\n </SidebarMenuItem>\r\n ))}\r\n </SidebarMenu>\r\n </SidebarGroupContent>\r\n </SidebarGroup>\r\n </SidebarContent>\r\n </Sidebar>\r\n );\r\n}\r\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix incorrect relative import to retro.css in embedded sidebar.tsx
In the embedded TSX, sidebar.tsx
lives at components/ui/8bit/blocks/sidebar.tsx
, while the stylesheet target is components/ui/8bit/styles/retro.css
. The current import "./styles/retro.css"
points to components/ui/8bit/blocks/styles/retro.css
(non-existent). It should be one directory up.
Also, minor cleanup: the template literal around the static "retro" class is unnecessary.
Apply this diff within the content
string:
-import "./styles/retro.css";
+import "../styles/retro.css";
Optionally simplify the className:
- <Sidebar
- className={`${"retro"} border-r-4 border-foreground dark:border-ring`}
- >
+ <Sidebar className="retro border-r-4 border-foreground dark:border-ring">
📝 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.
"content": "import { Calendar, Home, Inbox, Search, Settings } from \"lucide-react\";\r\n\r\nimport {\r\n Sidebar,\r\n SidebarContent,\r\n SidebarGroup,\r\n SidebarGroupContent,\r\n SidebarGroupLabel,\r\n SidebarMenu,\r\n SidebarMenuButton,\r\n SidebarMenuItem,\r\n} from \"@/components/ui/sidebar\";\r\n\r\nimport \"./styles/retro.css\";\r\n\r\n// Menu items.\r\nconst items = [\r\n {\r\n title: \"Home\",\r\n url: \"#\",\r\n icon: Home,\r\n },\r\n {\r\n title: \"Inbox\",\r\n url: \"#\",\r\n icon: Inbox,\r\n },\r\n {\r\n title: \"Calendar\",\r\n url: \"#\",\r\n icon: Calendar,\r\n },\r\n {\r\n title: \"Search\",\r\n url: \"#\",\r\n icon: Search,\r\n },\r\n {\r\n title: \"Settings\",\r\n url: \"#\",\r\n icon: Settings,\r\n },\r\n];\r\n\r\nexport function AppSidebar() {\r\n return (\r\n <Sidebar\r\n className={`${\"retro\"} border-r-4 border-foreground dark:border-ring`}\r\n >\r\n <SidebarContent>\r\n <SidebarGroup>\r\n <SidebarGroupLabel>Application</SidebarGroupLabel>\r\n <SidebarGroupContent>\r\n <SidebarMenu>\r\n {items.map((item) => (\r\n <SidebarMenuItem key={item.title}>\r\n <SidebarMenuButton asChild>\r\n <a href={item.url}>\r\n <item.icon />\r\n <span>{item.title}</span>\r\n </a>\r\n </SidebarMenuButton>\r\n </SidebarMenuItem>\r\n ))}\r\n </SidebarMenu>\r\n </SidebarGroupContent>\r\n </SidebarGroup>\r\n </SidebarContent>\r\n </Sidebar>\r\n );\r\n}\r\n", | |
import { Calendar, Home, Inbox, Search, Settings } from "lucide-react"; | |
import { | |
Sidebar, | |
SidebarContent, | |
SidebarGroup, | |
SidebarGroupContent, | |
SidebarGroupLabel, | |
SidebarMenu, | |
SidebarMenuButton, | |
SidebarMenuItem, | |
} from "@/components/ui/sidebar"; | |
import "../styles/retro.css"; | |
// Menu items. | |
const items = [ | |
{ | |
title: "Home", | |
url: "#", | |
icon: Home, | |
}, | |
{ | |
title: "Inbox", | |
url: "#", | |
icon: Inbox, | |
}, | |
{ | |
title: "Calendar", | |
url: "#", | |
icon: Calendar, | |
}, | |
{ | |
title: "Search", | |
url: "#", | |
icon: Search, | |
}, | |
{ | |
title: "Settings", | |
url: "#", | |
icon: Settings, | |
}, | |
]; | |
export function AppSidebar() { | |
return ( | |
<Sidebar className="retro border-r-4 border-foreground dark:border-ring"> | |
<SidebarContent> | |
<SidebarGroup> | |
<SidebarGroupLabel>Application</SidebarGroupLabel> | |
<SidebarGroupContent> | |
<SidebarMenu> | |
{items.map((item) => ( | |
<SidebarMenuItem key={item.title}> | |
<SidebarMenuButton asChild> | |
<a href={item.url}> | |
<item.icon /> | |
<span>{item.title}</span> | |
</a> | |
</SidebarMenuButton> | |
</SidebarMenuItem> | |
))} | |
</SidebarMenu> | |
</SidebarGroupContent> | |
</SidebarGroup> | |
</SidebarContent> | |
</Sidebar> | |
); | |
} |
🤖 Prompt for AI Agents
In public/r/8bit-sidebar.json around line 13, the embedded TSX imports the
stylesheet with import "./styles/retro.css" which points to a non-existent
blocks/styles path; change it to import "../styles/retro.css" so it references
components/ui/8bit/styles/retro.css, and simplify the Sidebar className by
removing the unnecessary template literal so it becomes a plain string with
"retro" plus the existing classes (e.g. "retro border-r-4 border-foreground
dark:border-ring").
{ | ||
"path": "components/ui/8bit/skeleton.tsx", | ||
"content": "import { cn } from \"@/lib/utils\";\n\nimport { Skeleton as ShadcnSkeleton } from \"@/components/ui/skeleton\";\n\nimport \"./styles/retro.css\";\n\nexport interface BitSkeletonProp extends React.ComponentProps<\"div\"> {\n asChild?: boolean;\n}\n\nfunction Skeleton({ children, ...props }: BitSkeletonProp) {\n const { className } = props;\n\n return (\n <div className={cn(\"relative animate-pulse\", className)}>\n <ShadcnSkeleton\n {...props}\n className={cn(\"rounded-none border-none bg-accent\", \"retro\", className)}\n >\n {children}\n </ShadcnSkeleton>\n\n <div className=\"opacity-60\">\n <div className=\"absolute -top-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute -top-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\n </div>\n <div className=\"opacity-60\">\n <div className=\"absolute -bottom-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute -bottom-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\n </div>\n <div className=\"absolute top-0 left-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" />\n <div className=\"absolute top-0 right-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" />\n <div className=\"absolute bottom-0 left-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" />\n <div className=\"absolute bottom-0 right-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" />\n <div className=\"opacity-60\">\n <div className=\"absolute top-1 -left-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute bottom-1 -left-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\n </div>\n <div className=\"opacity-60\">\n <div className=\"absolute top-1 -right-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\n <div className=\"absolute bottom-1 -right-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\n </div>\n </div>\n );\n}\n\nexport { Skeleton };\n", | ||
"content": "import { cn } from \"@/lib/utils\";\r\n\r\nimport { Skeleton as ShadcnSkeleton } from \"@/components/ui/skeleton\";\r\n\r\nimport \"./styles/retro.css\";\r\n\r\nexport interface BitSkeletonProp extends React.ComponentProps<\"div\"> {\r\n asChild?: boolean;\r\n}\r\n\r\nfunction Skeleton({ children, ...props }: BitSkeletonProp) {\r\n const { className } = props;\r\n\r\n return (\r\n <div className={cn(\"relative animate-pulse\", className)}>\r\n <ShadcnSkeleton\r\n {...props}\r\n className={cn(\"rounded-none border-none bg-accent\", \"retro\", className)}\r\n >\r\n {children}\r\n </ShadcnSkeleton>\r\n\r\n <div className=\"opacity-60\">\r\n <div className=\"absolute -top-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute -top-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n <div className=\"opacity-60\">\r\n <div className=\"absolute -bottom-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute -bottom-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n <div className=\"absolute top-0 left-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" />\r\n <div className=\"absolute top-0 right-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" />\r\n <div className=\"absolute bottom-0 left-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" />\r\n <div className=\"absolute bottom-0 right-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" />\r\n <div className=\"opacity-60\">\r\n <div className=\"absolute top-1 -left-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute bottom-1 -left-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n <div className=\"opacity-60\">\r\n <div className=\"absolute top-1 -right-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute bottom-1 -right-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nexport { Skeleton };\r\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Remove unused asChild prop and avoid leaking it into ShadcnSkeleton; also prefer React type imports and consistent Props naming
Spreading {...props}
currently forwards asChild
to ShadcnSkeleton
, which likely violates its prop type (HTMLAttributes<HTMLDivElement>
) and can trip TypeScript. Additionally, applying the consumer className
to both the wrapper and the inner Skeleton can cause unintended styling duplication. Recommend:
- Drop
asChild
(not used and not supported by Skeleton). - Import React types and avoid the
React.
namespace. - Use a single place for consumer
className
(root), and keep inner styles scoped.
Apply this diff to the content field to reflect the changes:
- "content": "import { cn } from \"@/lib/utils\";\r\n\r\nimport { Skeleton as ShadcnSkeleton } from \"@/components/ui/skeleton\";\r\n\r\nimport \"./styles/retro.css\";\r\n\r\nexport interface BitSkeletonProp extends React.ComponentProps<\"div\"> {\r\n asChild?: boolean;\r\n}\r\n\r\nfunction Skeleton({ children, ...props }: BitSkeletonProp) {\r\n const { className } = props;\r\n\r\n return (\r\n <div className={cn(\"relative animate-pulse\", className)}>\r\n <ShadcnSkeleton\r\n {...props}\r\n className={cn(\"rounded-none border-none bg-accent\", \"retro\", className)}\r\n >\r\n {children}\r\n </ShadcnSkeleton>\r\n\r\n <div className=\"opacity-60\">\r\n <div className=\"absolute -top-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute -top-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n <div className=\"opacity-60\">\r\n <div className=\"absolute -bottom-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute -bottom-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n <div className=\"absolute top-0 left-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" />\r\n <div className=\"absolute top-0 right-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" />\r\n <div className=\"absolute bottom-0 left-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" />\r\n <div className=\"absolute bottom-0 right-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" />\r\n <div className=\"opacity-60\">\r\n <div className=\"absolute top-1 -left-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute bottom-1 -left-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n <div className=\"opacity-60\">\r\n <div className=\"absolute top-1 -right-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute bottom-1 -right-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nexport { Skeleton };\r\n",
+ "content": "import type { ComponentPropsWithoutRef } from \"react\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { Skeleton as ShadcnSkeleton } from \"@/components/ui/skeleton\";\r\nimport \"./styles/retro.css\";\r\n\r\nexport type BitSkeletonProps = ComponentPropsWithoutRef<\"div\">;\r\n\r\nfunction Skeleton({ children, className, ...props }: BitSkeletonProps) {\r\n return (\r\n <div className={cn(\"relative animate-pulse\", className)}>\r\n <ShadcnSkeleton\r\n {...props}\r\n className={cn(\"rounded-none border-none bg-accent\", \"retro\")}\r\n >\r\n {children}\r\n </ShadcnSkeleton>\r\n\r\n <div className=\"opacity-60\" aria-hidden=\"true\">\r\n <div className=\"absolute -top-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute -top-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n <div className=\"opacity-60\" aria-hidden=\"true\">\r\n <div className=\"absolute -bottom-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute -bottom-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n <div className=\"absolute top-0 left-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" aria-hidden=\"true\" />\r\n <div className=\"absolute top-0 right-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" aria-hidden=\"true\" />\r\n <div className=\"absolute bottom-0 left-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" aria-hidden=\"true\" />\r\n <div className=\"absolute bottom-0 right-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" aria-hidden=\"true\" />\r\n <div className=\"opacity-60\" aria-hidden=\"true\">\r\n <div className=\"absolute top-1 -left-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute bottom-1 -left-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n <div className=\"opacity-60\" aria-hidden=\"true\">\r\n <div className=\"absolute top-1 -right-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute bottom-1 -right-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nexport { Skeleton };\r\n",
If you prefer preserving the ability to add styles to the inner element, introduce a dedicated prop (e.g., skeletonClassName
) instead of reusing the consumer className
.
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Searching for 8bit-skeleton file..."
rg -n "8bit-skeleton" || true
echo
echo "Printing public/r/8bit-skeleton.json (if present)..."
if [ -f "public/r/8bit-skeleton.json" ]; then
sed -n '1,240p' public/r/8bit-skeleton.json || true
else
echo "public/r/8bit-skeleton.json not found"
fi
echo
echo "Searching for ui skeleton component imports/usages..."
rg -n "@/components/ui/skeleton" || true
echo
echo "Searching for Skeleton component definitions/usages across repo..."
rg -n "function Skeleton" || true
rg -n "export .*Skeleton" || true
echo
echo "Searching for 'asChild' occurrences..."
rg -n "asChild" || true
echo
echo "Searching for React ComponentProps usages..."
rg -n "ComponentProps" || true
Length of output: 304360
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- components/ui/8bit/skeleton.tsx ----"
if [ -f "components/ui/8bit/skeleton.tsx" ]; then
sed -n '1,240p' components/ui/8bit/skeleton.tsx || true
else
echo "NOT FOUND: components/ui/8bit/skeleton.tsx"
fi
echo
echo "---- components/ui/skeleton.tsx ----"
if [ -f "components/ui/skeleton.tsx" ]; then
sed -n '1,240p' components/ui/skeleton.tsx || true
else
echo "NOT FOUND: components/ui/skeleton.tsx"
fi
Length of output: 2590
Fix: remove unused asChild
from 8-bit Skeleton and stop forwarding it into the inner ShadcnSkeleton
Short summary: I verified components/ui/8bit/skeleton.tsx forwards consumer props (including the unused asChild
) into the inner ShadcnSkeleton, which then spreads them onto a DOM div (components/ui/skeleton.tsx). That leaks an invalid prop to the DOM and can cause TypeScript/behavioral issues. Remove the asChild
prop, use typed React imports, keep consumer className
on the outer wrapper only, and mark decorative pixels aria-hidden.
Files to change:
- components/ui/8bit/skeleton.tsx
- public/r/8bit-skeleton.json (update the "content" field to match the component change)
Apply this patch to components/ui/8bit/skeleton.tsx:
*** a/components/ui/8bit/skeleton.tsx
--- b/components/ui/8bit/skeleton.tsx
@@
-import { cn } from "@/lib/utils";
-
-import { Skeleton as ShadcnSkeleton } from "@/components/ui/skeleton";
-
-import "./styles/retro.css";
-
-export interface BitSkeletonProp extends React.ComponentProps<"div"> {
- asChild?: boolean;
-}
-
-function Skeleton({ children, ...props }: BitSkeletonProp) {
- const { className } = props;
-
- return (
- <div className={cn("relative animate-pulse", className)}>
- <ShadcnSkeleton
- {...props}
- className={cn("rounded-none border-none bg-accent", "retro", className)}
- >
- {children}
- </ShadcnSkeleton>
-
- <div className="opacity-60">
- <div className="absolute -top-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring" />
- <div className="absolute -top-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring" />
- </div>
- <div className="opacity-60">
- <div className="absolute -bottom-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring" />
- <div className="absolute -bottom-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring" />
- </div>
- <div className="absolute top-0 left-0 size-1.5 bg-foreground/60 dark:bg-ring/60" />
- <div className="absolute top-0 right-0 size-1.5 bg-foreground/60 dark:bg-ring/60" />
- <div className="absolute bottom-0 left-0 size-1.5 bg-foreground/60 dark:bg-ring/60" />
- <div className="absolute bottom-0 right-0 size-1.5 bg-foreground/60 dark:bg-ring/60" />
- <div className="opacity-60">
- <div className="absolute top-1 -left-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring" />
- <div className="absolute bottom-1 -left-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring" />
- </div>
- <div className="opacity-60">
- <div className="absolute top-1 -right-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring" />
- <div className="absolute bottom-1 -right-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring" />
- </div>
- </div>
- );
-}
-
-export { Skeleton };
+import type { ComponentPropsWithoutRef } from "react";
+import { cn } from "@/lib/utils";
+import { Skeleton as ShadcnSkeleton } from "@/components/ui/skeleton";
+import "./styles/retro.css";
+
+export type BitSkeletonProps = ComponentPropsWithoutRef<"div">;
+
+function Skeleton({ children, className, ...props }: BitSkeletonProps) {
+ return (
+ <div className={cn("relative animate-pulse", className)}>
+ <ShadcnSkeleton
+ {...props}
+ className={cn("rounded-none border-none bg-accent", "retro")}
+ >
+ {children}
+ </ShadcnSkeleton>
+
+ <div className="opacity-60" aria-hidden="true">
+ <div className="absolute -top-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring" />
+ <div className="absolute -top-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring" />
+ </div>
+ <div className="opacity-60" aria-hidden="true">
+ <div className="absolute -bottom-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring" />
+ <div className="absolute -bottom-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring" />
+ </div>
+ <div className="absolute top-0 left-0 size-1.5 bg-foreground/60 dark:bg-ring/60" aria-hidden="true" />
+ <div className="absolute top-0 right-0 size-1.5 bg-foreground/60 dark:bg-ring/60" aria-hidden="true" />
+ <div className="absolute bottom-0 left-0 size-1.5 bg-foreground/60 dark:bg-ring/60" aria-hidden="true" />
+ <div className="absolute bottom-0 right-0 size-1.5 bg-foreground/60 dark:bg-ring/60" aria-hidden="true" />
+ <div className="opacity-60" aria-hidden="true">
+ <div className="absolute top-1 -left-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring" />
+ <div className="absolute bottom-1 -left-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring" />
+ </div>
+ <div className="opacity-60" aria-hidden="true">
+ <div className="absolute top-1 -right-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring" />
+ <div className="absolute bottom-1 -right-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring" />
+ </div>
+ </div>
+ );
+}
+
+export { Skeleton };
And update the registry file public/r/8bit-skeleton.json "content" field with the same component source (replace the old string with the new component code). Example content replacement (apply to the "content" value):
- "content": "import { cn } from \"@/lib/utils\";\r\n\r\nimport { Skeleton as ShadcnSkeleton } from \"@/components/ui/skeleton\";\r\n\r\nimport \"./styles/retro.css\";\r\n\r\nexport interface BitSkeletonProp extends React.ComponentProps<\"div\"> {\r\n asChild?: boolean;\r\n}\r\n\r\nfunction Skeleton({ children, ...props }: BitSkeletonProp) {\r\n const { className } = props;\r\n\r\n return (\r\n <div className={cn(\"relative animate-pulse\", className)}>\r\n <ShadcnSkeleton\r\n {...props}\r\n className={cn(\"rounded-none border-none bg-accent\", \"retro\", className)}\r\n >\r\n {children}\r\n </ShadcnSkeleton>\r\n\r\n <div className=\"opacity-60\">\r\n <div className=\"absolute -top-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute -top-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n <div className=\"opacity-60\">\r\n <div className=\"absolute -bottom-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute -bottom-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n <div className=\"absolute top-0 left-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" />\r\n <div className=\"absolute top-0 right-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" />\r\n <div className=\"absolute bottom-0 left-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" />\r\n <div className=\"absolute bottom-0 right-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" />\r\n <div className=\"opacity-60\">\r\n <div className=\"absolute top-1 -left-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute bottom-1 -left-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n <div className=\"opacity-60\">\r\n <div className=\"absolute top-1 -right-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute bottom-1 -right-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nexport { Skeleton };\r\n",
+ "content": "import type { ComponentPropsWithoutRef } from \"react\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { Skeleton as ShadcnSkeleton } from \"@/components/ui/skeleton\";\r\nimport \"./styles/retro.css\";\r\n\r\nexport type BitSkeletonProps = ComponentPropsWithoutRef<\"div\">;\r\n\r\nfunction Skeleton({ children, className, ...props }: BitSkeletonProps) {\r\n return (\r\n <div className={cn(\"relative animate-pulse\", className)}>\r\n <ShadcnSkeleton\r\n {...props}\r\n className={cn(\"rounded-none border-none bg-accent\", \"retro\")}\r\n >\r\n {children}\r\n </ShadcnSkeleton>\r\n\r\n <div className=\"opacity-60\" aria-hidden=\"true\">\r\n <div className=\"absolute -top-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute -top-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n <div className=\"opacity-60\" aria-hidden=\"true\">\r\n <div className=\"absolute -bottom-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute -bottom-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n <div className=\"absolute top-0 left-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" aria-hidden=\"true\" />\r\n <div className=\"absolute top-0 right-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" aria-hidden=\"true\" />\r\n <div className=\"absolute bottom-0 left-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" aria-hidden=\"true\" />\r\n <div className=\"absolute bottom-0 right-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" aria-hidden=\"true\" />\r\n <div className=\"opacity-60\" aria-hidden=\"true\">\r\n <div className=\"absolute top-1 -left-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute bottom-1 -left-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n <div className=\"opacity-60\" aria-hidden=\"true\">\r\n <div className=\"absolute top-1 -right-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute bottom-1 -right-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nexport { Skeleton };\r\n",
Notes / alternatives:
- If you want consumers to be able to style the inner skeleton separately, add a dedicated prop (e.g.,
skeletonClassName
) and pass it to the inner ShadcnSkeleton instead of reusing the consumerclassName
. - I intentionally removed
asChild
from the 8-bit props (it wasn't used here). If you intendedasChild
behavior, implement it explicitly (e.g., conditional Slot usage) rather than letting it leak to the DOM.
📝 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.
"content": "import { cn } from \"@/lib/utils\";\r\n\r\nimport { Skeleton as ShadcnSkeleton } from \"@/components/ui/skeleton\";\r\n\r\nimport \"./styles/retro.css\";\r\n\r\nexport interface BitSkeletonProp extends React.ComponentProps<\"div\"> {\r\n asChild?: boolean;\r\n}\r\n\r\nfunction Skeleton({ children, ...props }: BitSkeletonProp) {\r\n const { className } = props;\r\n\r\n return (\r\n <div className={cn(\"relative animate-pulse\", className)}>\r\n <ShadcnSkeleton\r\n {...props}\r\n className={cn(\"rounded-none border-none bg-accent\", \"retro\", className)}\r\n >\r\n {children}\r\n </ShadcnSkeleton>\r\n\r\n <div className=\"opacity-60\">\r\n <div className=\"absolute -top-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute -top-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n <div className=\"opacity-60\">\r\n <div className=\"absolute -bottom-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute -bottom-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n <div className=\"absolute top-0 left-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" />\r\n <div className=\"absolute top-0 right-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" />\r\n <div className=\"absolute bottom-0 left-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" />\r\n <div className=\"absolute bottom-0 right-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" />\r\n <div className=\"opacity-60\">\r\n <div className=\"absolute top-1 -left-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute bottom-1 -left-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n <div className=\"opacity-60\">\r\n <div className=\"absolute top-1 -right-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute bottom-1 -right-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nexport { Skeleton };\r\n", | |
"content": "import type { ComponentPropsWithoutRef } from \"react\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { Skeleton as ShadcnSkeleton } from \"@/components/ui/skeleton\";\r\nimport \"./styles/retro.css\";\r\n\r\nexport type BitSkeletonProps = ComponentPropsWithoutRef<\"div\">;\r\n\r\nfunction Skeleton({ children, className, ...props }: BitSkeletonProps) {\r\n return (\r\n <div className={cn(\"relative animate-pulse\", className)}>\r\n <ShadcnSkeleton\r\n {...props}\r\n className={cn(\"rounded-none border-none bg-accent\", \"retro\")}\r\n >\r\n {children}\r\n </ShadcnSkeleton>\r\n\r\n <div className=\"opacity-60\" aria-hidden=\"true\">\r\n <div className=\"absolute -top-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute -top-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n <div className=\"opacity-60\" aria-hidden=\"true\">\r\n <div className=\"absolute -bottom-1.5 w-1/2 left-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute -bottom-1.5 w-1/2 right-1.5 h-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n <div className=\"absolute top-0 left-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" aria-hidden=\"true\" />\r\n <div className=\"absolute top-0 right-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" aria-hidden=\"true\" />\r\n <div className=\"absolute bottom-0 left-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" aria-hidden=\"true\" />\r\n <div className=\"absolute bottom-0 right-0 size-1.5 bg-foreground/60 dark:bg-ring/60\" aria-hidden=\"true\" />\r\n <div className=\"opacity-60\" aria-hidden=\"true\">\r\n <div className=\"absolute top-1 -left-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute bottom-1 -left-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n <div className=\"opacity-60\" aria-hidden=\"true\">\r\n <div className=\"absolute top-1 -right-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n <div className=\"absolute bottom-1 -right-1.5 h-1/2 w-1.5 bg-foreground dark:bg-ring\" />\r\n </div>\r\n </div>\r\n );\r\n}\r\n\r\nexport { Skeleton };\r\n", |
🤖 Prompt for AI Agents
In public/r/8bit-skeleton.json around line 13, the exported component string
still declares and forwards an unused asChild prop into the inner ShadcnSkeleton
which leaks an invalid prop to the DOM; update the component source (and the
registry "content" field) to remove asChild from the BitSkeletonProp, stop
spreading consumer props into ShadcnSkeleton (only pass a dedicated
skeletonClassName or specific safe props), ensure the outer wrapper retains the
consumer className, import React types explicitly (e.g.,
React.ComponentProps<"div">), and add aria-hidden on the decorative pixel divs
so they are ignored by assistive tech.
{ | ||
"path": "components/ui/8bit/tabs.tsx", | ||
"content": "import * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport { type VariantProps, cva } from \"class-variance-authority\";\n\nimport { cn } from \"@/lib/utils\";\n\nimport {\n Tabs as ShadcnTabs,\n TabsContent as ShadcnTabsContent,\n TabsList as ShadcnTabsList,\n TabsTrigger as ShadcnTabsTrigger,\n} from \"@/components/ui/tabs\";\n\nimport \"./styles/retro.css\";\n\nexport const tabsVariants = cva(\"\", {\n variants: {\n variant: {\n default: \"bg-primary\",\n retro: \"retro\",\n },\n font: {\n normal: \"\",\n retro: \"retro\",\n },\n },\n defaultVariants: {\n font: \"retro\",\n },\n});\n\nexport interface BitTabsProps\n extends React.ComponentProps<typeof TabsPrimitive.Root>,\n VariantProps<typeof tabsVariants> {\n asChild?: boolean;\n}\n\nfunction Tabs({ className, ...props }: BitTabsProps) {\n const { font } = props;\n\n return (\n <ShadcnTabs\n {...props}\n className={cn(\"relative\", font !== \"normal\" && \"retro\", className)}\n />\n );\n}\n\nfunction TabsList({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof ShadcnTabsList>) {\n return (\n <ShadcnTabsList\n {...props}\n className={cn(\"relative bg-card rounded-none\", className)}\n >\n <div\n className=\"absolute inset-0 border-y-6 -my-1.5 border-foreground dark:border-ring pointer-events-none\"\n aria-hidden=\"true\"\n />\n\n <div\n className=\"absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none\"\n aria-hidden=\"true\"\n />\n {children}\n </ShadcnTabsList>\n );\n}\n\nfunction TabsTrigger({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof ShadcnTabsTrigger>) {\n return (\n <ShadcnTabsTrigger\n className={cn(\n \"border-none data-[state=active]:bg-accent data-[state=active]:text-foreground text-muted-foreground rounded-none\",\n className\n )}\n {...props}\n >\n {children}\n </ShadcnTabsTrigger>\n );\n}\n\nfunction TabsContent({\n className,\n ...props\n}: React.ComponentProps<typeof ShadcnTabsContent>) {\n return <ShadcnTabsContent className={cn(\"\", className)} {...props} />;\n}\n\nexport { Tabs, TabsList, TabsContent, TabsTrigger };\n", | ||
"content": "import * as TabsPrimitive from \"@radix-ui/react-tabs\";\r\nimport { type VariantProps, cva } from \"class-variance-authority\";\r\n\r\nimport { cn } from \"@/lib/utils\";\r\n\r\nimport {\r\n Tabs as ShadcnTabs,\r\n TabsContent as ShadcnTabsContent,\r\n TabsList as ShadcnTabsList,\r\n TabsTrigger as ShadcnTabsTrigger,\r\n} from \"@/components/ui/tabs\";\r\n\r\nimport \"./styles/retro.css\";\r\n\r\nexport const tabsVariants = cva(\"\", {\r\n variants: {\r\n variant: {\r\n default: \"bg-primary\",\r\n retro: \"retro\",\r\n },\r\n font: {\r\n normal: \"\",\r\n retro: \"retro\",\r\n },\r\n },\r\n defaultVariants: {\r\n font: \"retro\",\r\n },\r\n});\r\n\r\nexport interface BitTabsProps\r\n extends React.ComponentProps<typeof TabsPrimitive.Root>,\r\n VariantProps<typeof tabsVariants> {\r\n asChild?: boolean;\r\n}\r\n\r\nfunction Tabs({ className, ...props }: BitTabsProps) {\r\n const { font } = props;\r\n\r\n return (\r\n <ShadcnTabs\r\n {...props}\r\n className={cn(\"relative\", font !== \"normal\" && \"retro\", className)}\r\n />\r\n );\r\n}\r\n\r\nfunction TabsList({\r\n className,\r\n children,\r\n ...props\r\n}: React.ComponentProps<typeof ShadcnTabsList>) {\r\n return (\r\n <ShadcnTabsList\r\n {...props}\r\n className={cn(\"relative bg-card rounded-none\", className)}\r\n >\r\n <div\r\n className=\"absolute inset-0 border-y-6 -my-1.5 border-foreground dark:border-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n\r\n <div\r\n className=\"absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n {children}\r\n </ShadcnTabsList>\r\n );\r\n}\r\n\r\nfunction TabsTrigger({\r\n className,\r\n children,\r\n ...props\r\n}: React.ComponentProps<typeof ShadcnTabsTrigger>) {\r\n return (\r\n <ShadcnTabsTrigger\r\n className={cn(\r\n \"border-none data-[state=active]:bg-accent data-[state=active]:text-foreground text-muted-foreground rounded-none\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n {children}\r\n </ShadcnTabsTrigger>\r\n );\r\n}\r\n\r\nfunction TabsContent({\r\n className,\r\n ...props\r\n}: React.ComponentProps<typeof ShadcnTabsContent>) {\r\n return <ShadcnTabsContent className={cn(\"\", className)} {...props} />;\r\n}\r\n\r\nexport { Tabs, TabsList, TabsContent, TabsTrigger };\r\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prevent leaking the custom font
prop to the DOM in Tabs
font
is read from props
but still forwarded via {...props}
to ShadcnTabs
, which likely forwards to a DOM node. This can cause React unknown-prop warnings and unexpected attributes on the DOM. Destructure font
out before spreading the rest.
Apply this diff inside components/ui/8bit/tabs.tsx
:
-function Tabs({ className, ...props }: BitTabsProps) {
- const { font } = props;
+function Tabs({ className, font, ...props }: BitTabsProps) {
return (
<ShadcnTabs
- {...props}
+ {...props}
className={cn("relative", font !== "normal" && "retro", className)}
/>
);
}
📝 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.
"content": "import * as TabsPrimitive from \"@radix-ui/react-tabs\";\r\nimport { type VariantProps, cva } from \"class-variance-authority\";\r\n\r\nimport { cn } from \"@/lib/utils\";\r\n\r\nimport {\r\n Tabs as ShadcnTabs,\r\n TabsContent as ShadcnTabsContent,\r\n TabsList as ShadcnTabsList,\r\n TabsTrigger as ShadcnTabsTrigger,\r\n} from \"@/components/ui/tabs\";\r\n\r\nimport \"./styles/retro.css\";\r\n\r\nexport const tabsVariants = cva(\"\", {\r\n variants: {\r\n variant: {\r\n default: \"bg-primary\",\r\n retro: \"retro\",\r\n },\r\n font: {\r\n normal: \"\",\r\n retro: \"retro\",\r\n },\r\n },\r\n defaultVariants: {\r\n font: \"retro\",\r\n },\r\n});\r\n\r\nexport interface BitTabsProps\r\n extends React.ComponentProps<typeof TabsPrimitive.Root>,\r\n VariantProps<typeof tabsVariants> {\r\n asChild?: boolean;\r\n}\r\n\r\nfunction Tabs({ className, ...props }: BitTabsProps) {\r\n const { font } = props;\r\n\r\n return (\r\n <ShadcnTabs\r\n {...props}\r\n className={cn(\"relative\", font !== \"normal\" && \"retro\", className)}\r\n />\r\n );\r\n}\r\n\r\nfunction TabsList({\r\n className,\r\n children,\r\n ...props\r\n}: React.ComponentProps<typeof ShadcnTabsList>) {\r\n return (\r\n <ShadcnTabsList\r\n {...props}\r\n className={cn(\"relative bg-card rounded-none\", className)}\r\n >\r\n <div\r\n className=\"absolute inset-0 border-y-6 -my-1.5 border-foreground dark:border-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n\r\n <div\r\n className=\"absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n {children}\r\n </ShadcnTabsList>\r\n );\r\n}\r\n\r\nfunction TabsTrigger({\r\n className,\r\n children,\r\n ...props\r\n}: React.ComponentProps<typeof ShadcnTabsTrigger>) {\r\n return (\r\n <ShadcnTabsTrigger\r\n className={cn(\r\n \"border-none data-[state=active]:bg-accent data-[state=active]:text-foreground text-muted-foreground rounded-none\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n {children}\r\n </ShadcnTabsTrigger>\r\n );\r\n}\r\n\r\nfunction TabsContent({\r\n className,\r\n ...props\r\n}: React.ComponentProps<typeof ShadcnTabsContent>) {\r\n return <ShadcnTabsContent className={cn(\"\", className)} {...props} />;\r\n}\r\n\r\nexport { Tabs, TabsList, TabsContent, TabsTrigger };\r\n", | |
function Tabs({ className, font, ...props }: BitTabsProps) { | |
return ( | |
<ShadcnTabs | |
{...props} | |
className={cn("relative", font !== "normal" && "retro", className)} | |
/> | |
); | |
} |
🤖 Prompt for AI Agents
In public/r/8bit-tabs.json around line 13 (corresponds to
components/ui/8bit/tabs.tsx Tabs component), the custom prop `font` is read from
props but still forwarded via {...props} to ShadcnTabs which may leak it to the
DOM; fix by destructuring `font` out of props (e.g. const { font, ...rest } =
props) and spread `rest` into <ShadcnTabs> instead of `props`, and keep using
`font` for className logic so the prop is not forwarded to the DOM.
{ | ||
"path": "components/ui/8bit/toggle.tsx", | ||
"content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport * as TogglePrimitive from \"@radix-ui/react-toggle\";\nimport { type VariantProps, cva } from \"class-variance-authority\";\n\nimport { cn } from \"@/lib/utils\";\n\nimport { Toggle as ShadcnToggle } from \"@/components/ui/toggle\";\n\nimport \"./styles/retro.css\";\n\nconst toggleVariants = cva(\"\", {\n variants: {\n font: {\n normal: \"\",\n retro: \"retro\",\n },\n variant: {\n default: \"bg-transparent\",\n outline:\n \"bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground\",\n },\n size: {\n default: \"h-9 px-2 min-w-9\",\n sm: \"h-8 px-1.5 min-w-8\",\n lg: \"h-10 px-2.5 min-w-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n font: \"retro\",\n size: \"default\",\n },\n});\n\nexport interface BitToggleProps\n extends React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root>,\n VariantProps<typeof toggleVariants> {}\n\nfunction Toggle({ children, font, ...props }: BitToggleProps) {\n const { variant, className } = props;\n\n return (\n <ShadcnToggle\n {...props}\n className={cn(\n \"rounded-none active:translate-y-1 transition-transform relative border-none active:translate-x-1\",\n \"data-[state=on]:bg-primary data-[state=on]:text-primary-foreground\",\n font !== \"normal\" && \"retro\",\n className\n )}\n >\n {children}\n\n <>\n {variant === \"outline\" && (\n <>\n <div\n className=\"absolute inset-0 border-y-6 -my-1.5 border-foreground dark:border-ring pointer-events-none\"\n aria-hidden=\"true\"\n />\n\n <div\n className=\"absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none\"\n aria-hidden=\"true\"\n />\n </>\n )}\n </>\n </ShadcnToggle>\n );\n}\n\nexport { Toggle, toggleVariants };\n", | ||
"content": "\"use client\";\r\n\r\nimport * as React from \"react\";\r\n\r\nimport * as TogglePrimitive from \"@radix-ui/react-toggle\";\r\nimport { type VariantProps, cva } from \"class-variance-authority\";\r\n\r\nimport { cn } from \"@/lib/utils\";\r\n\r\nimport { Toggle as ShadcnToggle } from \"@/components/ui/toggle\";\r\n\r\nimport \"./styles/retro.css\";\r\n\r\nconst toggleVariants = cva(\"\", {\r\n variants: {\r\n font: {\r\n normal: \"\",\r\n retro: \"retro\",\r\n },\r\n variant: {\r\n default: \"bg-transparent\",\r\n outline:\r\n \"bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground\",\r\n },\r\n size: {\r\n default: \"h-9 px-2 min-w-9\",\r\n sm: \"h-8 px-1.5 min-w-8\",\r\n lg: \"h-10 px-2.5 min-w-10\",\r\n },\r\n },\r\n defaultVariants: {\r\n variant: \"default\",\r\n font: \"retro\",\r\n size: \"default\",\r\n },\r\n});\r\n\r\nexport interface BitToggleProps\r\n extends React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root>,\r\n VariantProps<typeof toggleVariants> {}\r\n\r\nfunction Toggle({ children, font, ...props }: BitToggleProps) {\r\n const { variant, className } = props;\r\n\r\n return (\r\n <ShadcnToggle\r\n {...props}\r\n className={cn(\r\n \"rounded-none active:translate-y-1 transition-transform relative border-none active:translate-x-1\",\r\n \"data-[state=on]:bg-primary data-[state=on]:text-primary-foreground\",\r\n font !== \"normal\" && \"retro\",\r\n className\r\n )}\r\n >\r\n {children}\r\n\r\n <>\r\n {variant === \"outline\" && (\r\n <>\r\n <div\r\n className=\"absolute inset-0 border-y-6 -my-1.5 border-foreground dark:border-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n\r\n <div\r\n className=\"absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n </>\r\n )}\r\n </>\r\n </ShadcnToggle>\r\n );\r\n}\r\n\r\nexport { Toggle, toggleVariants };\r\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Avoid leaking non-DOM props and align with shadcn patterns (forwardRef + use your cva or drop it).
- The current implementation spreads all props into ShadcnToggle, which forwards unknown props like font to the DOM button. This is leaky and can create noisy DOM attributes.
- toggleVariants is defined/exported but not actually used to compute classes. Either use it to apply variant/size/font or remove it to avoid dead code/config drift.
- Minor: redundant fragments around the outline overlay can be removed.
Apply this refactor to filter non-DOM props, adopt forwardRef for parity with shadcn components, actually use toggleVariants, and simplify fragments:
-"use client";
-
-import * as React from "react";
-
-import * as TogglePrimitive from "@radix-ui/react-toggle";
-import { type VariantProps, cva } from "class-variance-authority";
-
-import { cn } from "@/lib/utils";
-
-import { Toggle as ShadcnToggle } from "@/components/ui/toggle";
-
-import "./styles/retro.css";
-
-const toggleVariants = cva("", {
+ "use client";
+
+ import * as React from "react";
+
+ import * as TogglePrimitive from "@radix-ui/react-toggle";
+ import { type VariantProps, cva } from "class-variance-authority";
+
+ import { cn } from "@/lib/utils";
+
+ import { Toggle as ShadcnToggle } from "@/components/ui/toggle";
+
+ import "./styles/retro.css";
+
+ const toggleVariants = cva("", {
variants: {
font: {
normal: "",
retro: "retro",
},
variant: {
default: "bg-transparent",
outline:
"bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
},
size: {
default: "h-9 px-2 min-w-9",
sm: "h-8 px-1.5 min-w-8",
lg: "h-10 px-2.5 min-w-10",
},
},
defaultVariants: {
variant: "default",
font: "retro",
size: "default",
},
-});
-
-export interface BitToggleProps
- extends React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root>,
- VariantProps<typeof toggleVariants> {}
-
-function Toggle({ children, font, ...props }: BitToggleProps) {
- const { variant, className } = props;
-
- return (
- <ShadcnToggle
- {...props}
- className={cn(
- "rounded-none active:translate-y-1 transition-transform relative border-none active:translate-x-1",
- "data-[state=on]:bg-primary data-[state=on]:text-primary-foreground",
- font !== "normal" && "retro",
- className
- )}
- >
- {children}
-
- <>
- {variant === "outline" && (
- <>
- <div
- className="absolute inset-0 border-y-6 -my-1.5 border-foreground dark:border-ring pointer-events-none"
- aria-hidden="true"
- />
-
- <div
- className="absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none"
- aria-hidden="true"
- />
- </>
- )}
- </>
- </ShadcnToggle>
- );
-}
-
-export { Toggle, toggleVariants };
+ });
+
+ export interface BitToggleProps
+ extends React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root>,
+ VariantProps<typeof toggleVariants> {}
+
+ const Toggle = React.forwardRef<
+ React.ElementRef<typeof ShadcnToggle>,
+ BitToggleProps
+ >(({ children, font, variant, size, className, ...rest }, ref) => {
+ return (
+ <ShadcnToggle
+ ref={ref}
+ {...rest}
+ className={cn(
+ // base 8-bit styles
+ "rounded-none active:translate-y-1 transition-transform relative border-none active:translate-x-1",
+ "data-[state=on]:bg-primary data-[state=on]:text-primary-foreground",
+ // compose variant/size/font classes
+ toggleVariants({ font, variant, size }),
+ className
+ )}
+ >
+ {children}
+ {variant === "outline" && (
+ <>
+ <div
+ className="absolute inset-0 border-y-6 -my-1.5 border-foreground dark:border-ring pointer-events-none"
+ aria-hidden="true"
+ />
+ <div
+ className="absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none"
+ aria-hidden="true"
+ />
+ </>
+ )}
+ </ShadcnToggle>
+ );
+ });
+ Toggle.displayName = "Toggle";
+
+ export { Toggle, toggleVariants };
📝 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.
"content": "\"use client\";\r\n\r\nimport * as React from \"react\";\r\n\r\nimport * as TogglePrimitive from \"@radix-ui/react-toggle\";\r\nimport { type VariantProps, cva } from \"class-variance-authority\";\r\n\r\nimport { cn } from \"@/lib/utils\";\r\n\r\nimport { Toggle as ShadcnToggle } from \"@/components/ui/toggle\";\r\n\r\nimport \"./styles/retro.css\";\r\n\r\nconst toggleVariants = cva(\"\", {\r\n variants: {\r\n font: {\r\n normal: \"\",\r\n retro: \"retro\",\r\n },\r\n variant: {\r\n default: \"bg-transparent\",\r\n outline:\r\n \"bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground\",\r\n },\r\n size: {\r\n default: \"h-9 px-2 min-w-9\",\r\n sm: \"h-8 px-1.5 min-w-8\",\r\n lg: \"h-10 px-2.5 min-w-10\",\r\n },\r\n },\r\n defaultVariants: {\r\n variant: \"default\",\r\n font: \"retro\",\r\n size: \"default\",\r\n },\r\n});\r\n\r\nexport interface BitToggleProps\r\n extends React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root>,\r\n VariantProps<typeof toggleVariants> {}\r\n\r\nfunction Toggle({ children, font, ...props }: BitToggleProps) {\r\n const { variant, className } = props;\r\n\r\n return (\r\n <ShadcnToggle\r\n {...props}\r\n className={cn(\r\n \"rounded-none active:translate-y-1 transition-transform relative border-none active:translate-x-1\",\r\n \"data-[state=on]:bg-primary data-[state=on]:text-primary-foreground\",\r\n font !== \"normal\" && \"retro\",\r\n className\r\n )}\r\n >\r\n {children}\r\n\r\n <>\r\n {variant === \"outline\" && (\r\n <>\r\n <div\r\n className=\"absolute inset-0 border-y-6 -my-1.5 border-foreground dark:border-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n\r\n <div\r\n className=\"absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n </>\r\n )}\r\n </>\r\n </ShadcnToggle>\r\n );\r\n}\r\n\r\nexport { Toggle, toggleVariants };\r\n", | |
"use client"; | |
import * as React from "react"; | |
import * as TogglePrimitive from "@radix-ui/react-toggle"; | |
import { type VariantProps, cva } from "class-variance-authority"; | |
import { cn } from "@/lib/utils"; | |
import { Toggle as ShadcnToggle } from "@/components/ui/toggle"; | |
import "./styles/retro.css"; | |
const toggleVariants = cva("", { | |
variants: { | |
font: { | |
normal: "", | |
retro: "retro", | |
}, | |
variant: { | |
default: "bg-transparent", | |
outline: | |
"bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground", | |
}, | |
size: { | |
default: "h-9 px-2 min-w-9", | |
sm: "h-8 px-1.5 min-w-8", | |
lg: "h-10 px-2.5 min-w-10", | |
}, | |
}, | |
defaultVariants: { | |
variant: "default", | |
font: "retro", | |
size: "default", | |
}, | |
}); | |
export interface BitToggleProps | |
extends React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root>, | |
VariantProps<typeof toggleVariants> {} | |
const Toggle = React.forwardRef< | |
React.ElementRef<typeof ShadcnToggle>, | |
BitToggleProps | |
>(({ children, font, variant, size, className, ...rest }, ref) => { | |
return ( | |
<ShadcnToggle | |
ref={ref} | |
{...rest} | |
className={cn( | |
// base 8-bit styles | |
"rounded-none active:translate-y-1 transition-transform relative border-none active:translate-x-1", | |
"data-[state=on]:bg-primary data-[state=on]:text-primary-foreground", | |
// compose variant/size/font classes | |
toggleVariants({ font, variant, size }), | |
className | |
)} | |
> | |
{children} | |
{variant === "outline" && ( | |
<> | |
<div | |
className="absolute inset-0 border-y-6 -my-1.5 border-foreground dark:border-ring pointer-events-none" | |
aria-hidden="true" | |
/> | |
<div | |
className="absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none" | |
aria-hidden="true" | |
/> | |
</> | |
)} | |
</ShadcnToggle> | |
); | |
}); | |
Toggle.displayName = "Toggle"; | |
export { Toggle, toggleVariants }; |
{ | ||
"path": "components/ui/8bit/tooltip.tsx", | ||
"content": "\"use client\";\n\nimport type * as React from \"react\";\n\nimport { type VariantProps, cva } from \"class-variance-authority\";\n\nimport { cn } from \"@/lib/utils\";\n\nimport {\n Tooltip as ShadcnTooltip,\n TooltipContent as ShadcnTooltipContent,\n TooltipProvider as ShadcnTooltipProvider,\n TooltipTrigger as ShadcnTooltipTrigger,\n} from \"@/components/ui/tooltip\";\n\nimport \"./styles/retro.css\";\n\nexport const tooltipVariants = cva(\"\", {\n variants: {\n font: {\n normal: \"\",\n retro: \"retro\",\n },\n },\n defaultVariants: {\n font: \"retro\",\n },\n});\n\nexport interface BitTooltipContentProps\n extends React.ComponentPropsWithoutRef<typeof ShadcnTooltipContent>,\n VariantProps<typeof tooltipVariants> {}\n\nfunction TooltipContent({\n className,\n children,\n font,\n ...props\n}: BitTooltipContentProps) {\n const color = tooltipVariants({ font });\n\n return (\n <div className={cn(\"relative inline-flex\", className)}>\n <ShadcnTooltipContent\n {...props}\n data-slot=\"tooltip-content\"\n className={cn(\"rounded-none\", color, className)}\n >\n {children}\n <div\n className={cn(\n \"absolute top-1.5 bottom-1.5 -left-1.5 h-1/2 w-1.5 bg-primary\",\n color\n )}\n />\n <div\n className={cn(\n \"absolute top-1.5 bottom-1.5 -right-1.5 h-1/2 w-1.5 bg-primary \",\n color\n )}\n />\n </ShadcnTooltipContent>\n </div>\n );\n}\n\nexport interface BitTooltipProps\n extends React.ComponentPropsWithoutRef<typeof ShadcnTooltip>,\n VariantProps<typeof tooltipVariants> {}\n\nfunction Tooltip({ children, ...props }: BitTooltipProps) {\n return (\n <ShadcnTooltip data-slot=\"tooltip\" {...props}>\n {children}\n </ShadcnTooltip>\n );\n}\n\nexport interface BitTooltipProviderProps\n extends React.ComponentPropsWithoutRef<typeof ShadcnTooltipProvider> {\n delayDuration?: number;\n}\n\nfunction TooltipProvider({\n children,\n delayDuration = 0,\n ...props\n}: BitTooltipProviderProps) {\n return (\n <ShadcnTooltipProvider delayDuration={delayDuration} {...props}>\n {children}\n </ShadcnTooltipProvider>\n );\n}\n\nfunction TooltipTrigger({\n children,\n asChild = true,\n ...props\n}: React.ComponentPropsWithoutRef<typeof ShadcnTooltipTrigger>) {\n return (\n <ShadcnTooltipTrigger\n data-slot=\"tooltip-trigger\"\n asChild={asChild}\n {...props}\n >\n {children}\n </ShadcnTooltipTrigger>\n );\n}\n\nexport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };\n", | ||
"content": "\"use client\";\r\n\r\nimport type * as React from \"react\";\r\n\r\nimport { type VariantProps, cva } from \"class-variance-authority\";\r\n\r\nimport { cn } from \"@/lib/utils\";\r\n\r\nimport {\r\n Tooltip as ShadcnTooltip,\r\n TooltipContent as ShadcnTooltipContent,\r\n TooltipProvider as ShadcnTooltipProvider,\r\n TooltipTrigger as ShadcnTooltipTrigger,\r\n} from \"@/components/ui/tooltip\";\r\n\r\nimport \"./styles/retro.css\";\r\n\r\nexport const tooltipVariants = cva(\"\", {\r\n variants: {\r\n font: {\r\n normal: \"\",\r\n retro: \"retro\",\r\n },\r\n },\r\n defaultVariants: {\r\n font: \"retro\",\r\n },\r\n});\r\n\r\nexport interface BitTooltipContentProps\r\n extends React.ComponentPropsWithoutRef<typeof ShadcnTooltipContent>,\r\n VariantProps<typeof tooltipVariants> {}\r\n\r\nfunction TooltipContent({\r\n className,\r\n children,\r\n font,\r\n ...props\r\n}: BitTooltipContentProps) {\r\n const color = tooltipVariants({ font });\r\n\r\n return (\r\n <div className={cn(\"relative inline-flex\", className)}>\r\n <ShadcnTooltipContent\r\n {...props}\r\n data-slot=\"tooltip-content\"\r\n className={cn(\"rounded-none\", color, className)}\r\n >\r\n {children}\r\n <div\r\n className={cn(\r\n \"absolute top-1.5 bottom-1.5 -left-1.5 h-1/2 w-1.5 bg-primary\",\r\n color\r\n )}\r\n />\r\n <div\r\n className={cn(\r\n \"absolute top-1.5 bottom-1.5 -right-1.5 h-1/2 w-1.5 bg-primary \",\r\n color\r\n )}\r\n />\r\n </ShadcnTooltipContent>\r\n </div>\r\n );\r\n}\r\n\r\nexport interface BitTooltipProps\r\n extends React.ComponentPropsWithoutRef<typeof ShadcnTooltip>,\r\n VariantProps<typeof tooltipVariants> {}\r\n\r\nfunction Tooltip({ children, ...props }: BitTooltipProps) {\r\n return (\r\n <ShadcnTooltip data-slot=\"tooltip\" {...props}>\r\n {children}\r\n </ShadcnTooltip>\r\n );\r\n}\r\n\r\nexport interface BitTooltipProviderProps\r\n extends React.ComponentPropsWithoutRef<typeof ShadcnTooltipProvider> {\r\n delayDuration?: number;\r\n}\r\n\r\nfunction TooltipProvider({\r\n children,\r\n delayDuration = 0,\r\n ...props\r\n}: BitTooltipProviderProps) {\r\n return (\r\n <ShadcnTooltipProvider delayDuration={delayDuration} {...props}>\r\n {children}\r\n </ShadcnTooltipProvider>\r\n );\r\n}\r\n\r\nfunction TooltipTrigger({\r\n children,\r\n asChild = true,\r\n ...props\r\n}: React.ComponentPropsWithoutRef<typeof ShadcnTooltipTrigger>) {\r\n return (\r\n <ShadcnTooltipTrigger\r\n data-slot=\"tooltip-trigger\"\r\n asChild={asChild}\r\n {...props}\r\n >\r\n {children}\r\n </ShadcnTooltipTrigger>\r\n );\r\n}\r\n\r\nexport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };\r\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
TooltipContent applies className
to both wrapper and inner content
className
is passed to the wrapper div and also to ShadcnTooltipContent
, causing duplication that can double margins/padding and complicate overrides.
Simple fix: don’t spread className
to the wrapper; keep it only on the inner content.
function TooltipContent({
className,
children,
font,
...props
}: BitTooltipContentProps) {
const color = tooltipVariants({ font });
return (
- <div className={cn("relative inline-flex", className)}>
+ <div className={cn("relative inline-flex")}>
<ShadcnTooltipContent
{...props}
data-slot="tooltip-content"
className={cn("rounded-none", color, className)}
>
{children}
If you need users to style the wrapper separately, introduce a dedicated wrapperClassName
prop.
📝 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.
"content": "\"use client\";\r\n\r\nimport type * as React from \"react\";\r\n\r\nimport { type VariantProps, cva } from \"class-variance-authority\";\r\n\r\nimport { cn } from \"@/lib/utils\";\r\n\r\nimport {\r\n Tooltip as ShadcnTooltip,\r\n TooltipContent as ShadcnTooltipContent,\r\n TooltipProvider as ShadcnTooltipProvider,\r\n TooltipTrigger as ShadcnTooltipTrigger,\r\n} from \"@/components/ui/tooltip\";\r\n\r\nimport \"./styles/retro.css\";\r\n\r\nexport const tooltipVariants = cva(\"\", {\r\n variants: {\r\n font: {\r\n normal: \"\",\r\n retro: \"retro\",\r\n },\r\n },\r\n defaultVariants: {\r\n font: \"retro\",\r\n },\r\n});\r\n\r\nexport interface BitTooltipContentProps\r\n extends React.ComponentPropsWithoutRef<typeof ShadcnTooltipContent>,\r\n VariantProps<typeof tooltipVariants> {}\r\n\r\nfunction TooltipContent({\r\n className,\r\n children,\r\n font,\r\n ...props\r\n}: BitTooltipContentProps) {\r\n const color = tooltipVariants({ font });\r\n\r\n return (\r\n <div className={cn(\"relative inline-flex\", className)}>\r\n <ShadcnTooltipContent\r\n {...props}\r\n data-slot=\"tooltip-content\"\r\n className={cn(\"rounded-none\", color, className)}\r\n >\r\n {children}\r\n <div\r\n className={cn(\r\n \"absolute top-1.5 bottom-1.5 -left-1.5 h-1/2 w-1.5 bg-primary\",\r\n color\r\n )}\r\n />\r\n <div\r\n className={cn(\r\n \"absolute top-1.5 bottom-1.5 -right-1.5 h-1/2 w-1.5 bg-primary \",\r\n color\r\n )}\r\n />\r\n </ShadcnTooltipContent>\r\n </div>\r\n );\r\n}\r\n\r\nexport interface BitTooltipProps\r\n extends React.ComponentPropsWithoutRef<typeof ShadcnTooltip>,\r\n VariantProps<typeof tooltipVariants> {}\r\n\r\nfunction Tooltip({ children, ...props }: BitTooltipProps) {\r\n return (\r\n <ShadcnTooltip data-slot=\"tooltip\" {...props}>\r\n {children}\r\n </ShadcnTooltip>\r\n );\r\n}\r\n\r\nexport interface BitTooltipProviderProps\r\n extends React.ComponentPropsWithoutRef<typeof ShadcnTooltipProvider> {\r\n delayDuration?: number;\r\n}\r\n\r\nfunction TooltipProvider({\r\n children,\r\n delayDuration = 0,\r\n ...props\r\n}: BitTooltipProviderProps) {\r\n return (\r\n <ShadcnTooltipProvider delayDuration={delayDuration} {...props}>\r\n {children}\r\n </ShadcnTooltipProvider>\r\n );\r\n}\r\n\r\nfunction TooltipTrigger({\r\n children,\r\n asChild = true,\r\n ...props\r\n}: React.ComponentPropsWithoutRef<typeof ShadcnTooltipTrigger>) {\r\n return (\r\n <ShadcnTooltipTrigger\r\n data-slot=\"tooltip-trigger\"\r\n asChild={asChild}\r\n {...props}\r\n >\r\n {children}\r\n </ShadcnTooltipTrigger>\r\n );\r\n}\r\n\r\nexport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };\r\n", | |
export interface BitTooltipContentProps | |
extends React.ComponentPropsWithoutRef<typeof ShadcnTooltipContent>, | |
VariantProps<typeof tooltipVariants> {} | |
function TooltipContent({ | |
className, | |
children, | |
font, | |
...props | |
}: BitTooltipContentProps) { | |
const color = tooltipVariants({ font }); | |
return ( | |
<div className={cn("relative inline-flex")}> | |
<ShadcnTooltipContent | |
{...props} | |
data-slot="tooltip-content" | |
className={cn("rounded-none", color, className)} | |
> | |
{children} | |
<div | |
className={cn( | |
"absolute top-1.5 bottom-1.5 -left-1.5 h-1/2 w-1.5 bg-primary", | |
color | |
)} | |
/> | |
<div | |
className={cn( | |
"absolute top-1.5 bottom-1.5 -right-1.5 h-1/2 w-1.5 bg-primary ", | |
color | |
)} | |
/> | |
</ShadcnTooltipContent> | |
</div> | |
); | |
} |
🤖 Prompt for AI Agents
public/r/8bit-tooltip.json around line 13: TooltipContent passes the same
className to both the outer wrapper div and the ShadcnTooltipContent, causing
duplicated styles; remove className from the wrapper (leave className applied
only to ShadcnTooltipContent) so the wrapper uses only fixed classes (e.g.,
"relative inline-flex"), and if separate wrapper styling is required add a new
optional wrapperClassName prop to the BitTooltipContentProps and apply that to
the wrapper instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review continued from previous batch...
export const ChevronRightIcon = () => { | ||
return ( | ||
<svg | ||
width="50" | ||
height="50" | ||
viewBox="0 0 256 256" | ||
fill="currentColor" | ||
xmlns="http://www.w3.org/2000/svg" | ||
stroke="currentColor" | ||
strokeWidth="0.25" | ||
color="" | ||
className="raster-icon size-7" | ||
aria-label="chevron-right" | ||
> | ||
<rect x="128" y="136" width="14" height="14" rx="1"></rect> | ||
<rect x="112" y="152" width="14" height="14" rx="1"></rect> | ||
<rect x="96" y="72" width="14" height="14" rx="1"></rect> | ||
<rect x="96" y="168" width="14" height="14" rx="1"></rect> | ||
<rect x="144" y="120" width="14" height="14" rx="1"></rect> | ||
<rect x="128" y="104" width="14" height="14" rx="1"></rect> | ||
<rect x="112" y="88" width="14" height="14" rx="1"></rect> | ||
</svg> | ||
); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Make the icon configurable (className/props), remove stray color=""
, and set sensible a11y defaults.
The icon is hard-coded (no className
/props), uses a larger default size than prior lucide usage, and includes a redundant color=""
. To maximize reuse and preserve layout control in callers, let it accept standard SVG props and default to being decorative.
Apply:
+import * as React from "react"
+import { cn } from "@/lib/utils"
+
-export const ChevronRightIcon = () => {
- return (
- <svg
- width="50"
- height="50"
- viewBox="0 0 256 256"
- fill="currentColor"
- xmlns="http://www.w3.org/2000/svg"
- stroke="currentColor"
- strokeWidth="0.25"
- color=""
- className="raster-icon size-7"
- aria-label="chevron-right"
- >
+type IconProps = React.SVGProps<SVGSVGElement> & { title?: string }
+
+export const ChevronRightIcon = ({ className, title, ...props }: IconProps) => {
+ return (
+ <svg
+ width="50"
+ height="50"
+ viewBox="0 0 256 256"
+ fill="currentColor"
+ xmlns="http://www.w3.org/2000/svg"
+ stroke="currentColor"
+ strokeWidth="0.25"
+ className={cn("raster-icon size-7", className)}
+ aria-hidden={title ? undefined : true}
+ role={title ? "img" : "presentation"}
+ {...props}
+ >
+ {title ? <title>{title}</title> : null}
<rect x="128" y="136" width="14" height="14" rx="1"></rect>
<rect x="112" y="152" width="14" height="14" rx="1"></rect>
<rect x="96" y="72" width="14" height="14" rx="1"></rect>
<rect x="96" y="168" width="14" height="14" rx="1"></rect>
<rect x="144" y="120" width="14" height="14" rx="1"></rect>
<rect x="128" y="104" width="14" height="14" rx="1"></rect>
<rect x="112" y="88" width="14" height="14" rx="1"></rect>
</svg>
);
};
This keeps the current default size but allows callers to override (e.g., ml-auto size-4
) and ensures the icon is decorative by default.
📝 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 const ChevronRightIcon = () => { | |
return ( | |
<svg | |
width="50" | |
height="50" | |
viewBox="0 0 256 256" | |
fill="currentColor" | |
xmlns="http://www.w3.org/2000/svg" | |
stroke="currentColor" | |
strokeWidth="0.25" | |
color="" | |
className="raster-icon size-7" | |
aria-label="chevron-right" | |
> | |
<rect x="128" y="136" width="14" height="14" rx="1"></rect> | |
<rect x="112" y="152" width="14" height="14" rx="1"></rect> | |
<rect x="96" y="72" width="14" height="14" rx="1"></rect> | |
<rect x="96" y="168" width="14" height="14" rx="1"></rect> | |
<rect x="144" y="120" width="14" height="14" rx="1"></rect> | |
<rect x="128" y="104" width="14" height="14" rx="1"></rect> | |
<rect x="112" y="88" width="14" height="14" rx="1"></rect> | |
</svg> | |
); | |
}; | |
import * as React from "react" | |
import { cn } from "@/lib/utils" | |
type IconProps = React.SVGProps<SVGSVGElement> & { title?: string } | |
export const ChevronRightIcon = ({ className, title, ...props }: IconProps) => { | |
return ( | |
<svg | |
width="50" | |
height="50" | |
viewBox="0 0 256 256" | |
fill="currentColor" | |
xmlns="http://www.w3.org/2000/svg" | |
stroke="currentColor" | |
strokeWidth="0.25" | |
className={cn("raster-icon size-7", className)} | |
aria-hidden={title ? undefined : true} | |
role={title ? "img" : "presentation"} | |
{...props} | |
> | |
{title ? <title>{title}</title> : null} | |
<rect x="128" y="136" width="14" height="14" rx="1"></rect> | |
<rect x="112" y="152" width="14" height="14" rx="1"></rect> | |
<rect x="96" y="72" width="14" height="14" rx="1"></rect> | |
<rect x="96" y="168" width="14" height="14" rx="1"></rect> | |
<rect x="144" y="120" width="14" height="14" rx="1"></rect> | |
<rect x="128" y="104" width="14" height="14" rx="1"></rect> | |
<rect x="112" y="88" width="14" height="14" rx="1"></rect> | |
</svg> | |
); | |
}; |
🤖 Prompt for AI Agents
In components/ui/8bit/assets/chevronRightIcon.tsx around lines 1 to 24, the SVG
is hard-coded and contains a stray color="" attribute and no way for callers to
override className/props or provide accessibility attributes; update the
component to accept standard SVG props (including className) and spread them
onto the <svg>, remove the color="" attribute, preserve the current default
attributes (width="50" height="50" viewBox and className="raster-icon size-7")
but allow them to be overridden by incoming props, and make the icon decorative
by default by setting aria-hidden=true unless an explicit aria-label or role is
provided by the caller.
Chevron: ({ className, ...props }) => { | ||
if (props.orientation === "left") { | ||
return ( | ||
<svg | ||
viewBox="0 0 256 256" | ||
fill="currentColor" | ||
xmlns="http://www.w3.org/2000/svg" | ||
stroke="currentColor" | ||
strokeWidth="0.25" | ||
color="" | ||
className={cn("size-4 shrink-0", className)} | ||
aria-label="chevron-left" | ||
{...props} | ||
> | ||
<rect | ||
width="14" | ||
height="14" | ||
rx="1" | ||
transform="matrix(-1 0 0 1 128 136)" | ||
></rect> | ||
<rect | ||
width="14" | ||
height="14" | ||
rx="1" | ||
transform="matrix(-1 0 0 1 144 152)" | ||
></rect> | ||
<rect | ||
width="14" | ||
height="14" | ||
rx="1" | ||
transform="matrix(-1 0 0 1 160 72)" | ||
></rect> | ||
<rect | ||
width="14" | ||
height="14" | ||
rx="1" | ||
transform="matrix(-1 0 0 1 160 168)" | ||
></rect> | ||
<rect | ||
width="14" | ||
height="14" | ||
rx="1" | ||
transform="matrix(-1 0 0 1 112 120)" | ||
></rect> | ||
<rect | ||
width="14" | ||
height="14" | ||
rx="1" | ||
transform="matrix(-1 0 0 1 128 104)" | ||
></rect> | ||
<rect | ||
width="14" | ||
height="14" | ||
rx="1" | ||
transform="matrix(-1 0 0 1 144 88)" | ||
></rect> | ||
</svg> | ||
); | ||
return <ChevronLeftIcon />; | ||
} | ||
|
||
return ( | ||
<svg | ||
viewBox="0 0 256 256" | ||
fill="currentColor" | ||
xmlns="http://www.w3.org/2000/svg" | ||
stroke="currentColor" | ||
strokeWidth="0.25" | ||
color="" | ||
className={cn("size-4 shrink-0", className)} | ||
aria-label="chevron-right" | ||
{...props} | ||
> | ||
<rect x="128" y="136" width="14" height="14" rx="1"></rect> | ||
<rect x="112" y="152" width="14" height="14" rx="1"></rect> | ||
<rect x="96" y="72" width="14" height="14" rx="1"></rect> | ||
<rect x="96" y="168" width="14" height="14" rx="1"></rect> | ||
<rect x="144" y="120" width="14" height="14" rx="1"></rect> | ||
<rect x="128" y="104" width="14" height="14" rx="1"></rect> | ||
<rect x="112" y="88" width="14" height="14" rx="1"></rect> | ||
</svg> | ||
); | ||
return <ChevronRightIcon />; | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Chevron component no longer forwards className/props; restore sizing and accessibility locally
The previous inline SVG respected incoming className/props. With the asset, className/props are dropped, and the asset enforces size-7, which may not match the nav button’s intent. Wrap and forward the className for predictable sizing and hide the decorative icon from AT:
Chevron: ({ className, ...props }) => {
if (props.orientation === "left") {
- return <ChevronLeftIcon />;
+ return (
+ <span className={cn(className, "[&>svg]:size-4")} aria-hidden="true">
+ <ChevronLeftIcon />
+ </span>
+ );
}
- return <ChevronRightIcon />;
+ return (
+ <span className={cn(className, "[&>svg]:size-4")} aria-hidden="true">
+ <ChevronRightIcon />
+ </span>
+ );
},
- Preserves styling hooks the DayPicker/Shadcn might pass.
- Ensures a compact icon size that fits the button.
- Avoids duplicate announcements by screen readers.
If you prefer removing wrappers, update both Chevron assets to accept and merge className/props and drop hardcoded size.
📝 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.
Chevron: ({ className, ...props }) => { | |
if (props.orientation === "left") { | |
return ( | |
<svg | |
viewBox="0 0 256 256" | |
fill="currentColor" | |
xmlns="http://www.w3.org/2000/svg" | |
stroke="currentColor" | |
strokeWidth="0.25" | |
color="" | |
className={cn("size-4 shrink-0", className)} | |
aria-label="chevron-left" | |
{...props} | |
> | |
<rect | |
width="14" | |
height="14" | |
rx="1" | |
transform="matrix(-1 0 0 1 128 136)" | |
></rect> | |
<rect | |
width="14" | |
height="14" | |
rx="1" | |
transform="matrix(-1 0 0 1 144 152)" | |
></rect> | |
<rect | |
width="14" | |
height="14" | |
rx="1" | |
transform="matrix(-1 0 0 1 160 72)" | |
></rect> | |
<rect | |
width="14" | |
height="14" | |
rx="1" | |
transform="matrix(-1 0 0 1 160 168)" | |
></rect> | |
<rect | |
width="14" | |
height="14" | |
rx="1" | |
transform="matrix(-1 0 0 1 112 120)" | |
></rect> | |
<rect | |
width="14" | |
height="14" | |
rx="1" | |
transform="matrix(-1 0 0 1 128 104)" | |
></rect> | |
<rect | |
width="14" | |
height="14" | |
rx="1" | |
transform="matrix(-1 0 0 1 144 88)" | |
></rect> | |
</svg> | |
); | |
return <ChevronLeftIcon />; | |
} | |
return ( | |
<svg | |
viewBox="0 0 256 256" | |
fill="currentColor" | |
xmlns="http://www.w3.org/2000/svg" | |
stroke="currentColor" | |
strokeWidth="0.25" | |
color="" | |
className={cn("size-4 shrink-0", className)} | |
aria-label="chevron-right" | |
{...props} | |
> | |
<rect x="128" y="136" width="14" height="14" rx="1"></rect> | |
<rect x="112" y="152" width="14" height="14" rx="1"></rect> | |
<rect x="96" y="72" width="14" height="14" rx="1"></rect> | |
<rect x="96" y="168" width="14" height="14" rx="1"></rect> | |
<rect x="144" y="120" width="14" height="14" rx="1"></rect> | |
<rect x="128" y="104" width="14" height="14" rx="1"></rect> | |
<rect x="112" y="88" width="14" height="14" rx="1"></rect> | |
</svg> | |
); | |
return <ChevronRightIcon />; | |
}, | |
Chevron: ({ className, ...props }) => { | |
if (props.orientation === "left") { | |
return ( | |
<span className={cn(className, "[&>svg]:size-4")} aria-hidden="true"> | |
<ChevronLeftIcon /> | |
</span> | |
); | |
} | |
return ( | |
<span className={cn(className, "[&>svg]:size-4")} aria-hidden="true"> | |
<ChevronRightIcon /> | |
</span> | |
); | |
}, |
{children ?? <ChevronRightIcon />} | ||
</li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Force separator size deterministically to avoid Tailwind specificity clashes
The list item sets "[&>svg]:size-3.5", but the asset’s SVG carries "size-7". Depending on generation order, either could win. Make it deterministic at the render site:
- {children ?? <ChevronRightIcon />}
+ {children ?? (
+ <span className="[&>svg]:!size-3.5">
+ <ChevronRightIcon />
+ </span>
+ )}
- Uses !important to ensure the breadcrumb’s 3.5 sizing wins locally.
- Keeps the asset reusable elsewhere at a different size.
Longer-term, consider making the asset size-agnostic (accept className/props) to avoid wrappers.
📝 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.
{children ?? <ChevronRightIcon />} | |
</li> | |
{children ?? ( | |
<span className="[&>svg]:!size-3.5"> | |
<ChevronRightIcon /> | |
</span> | |
)} | |
</li> |
🤖 Prompt for AI Agents
In components/ui/breadcrumb.tsx around lines 81 to 82, the breadcrumb wrapper
sets "[&>svg]:size-3.5" but the passed SVG has "size-7" which can win due to
Tailwind specificity; update the render so the breadcrumb forces the smaller
size locally by applying Tailwind's important variant to the svg-sizing rule
(e.g. use "[&>svg]:!size-3.5" or render the fallback icon with a class that
includes "!size-3.5") so the breadcrumb always enforces 3.5 while keeping the
asset reusable elsewhere.
import { ChevronRightIcon } from "@/components/ui/8bit/assets/chevronRightIcon"; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Move to local 8‑bit chevron asset — LGTM; scan for any remaining lucide chevrons
The import change aligns with the refactor goal.
Run this quick scan to ensure we didn’t miss any lucide chevron imports:
🏁 Script executed:
#!/bin/bash
# Find any remaining lucide chevron usages
rg -n "(import\\s*\\{[^}]*Chevron(Left|Right)[^}]*\\}\\s*from\\s*['\"]lucide-react['\"])|(<Chevron(Left|Right)\\b)" -S
Length of output: 118
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Search: direct lucide-react imports =="
rg -n "from\s+['\"]lucide-react['\"]" -S || true
echo
echo "== Search: import lines mentioning ChevronLeft/ChevronRight =="
rg -n "import.*Chevron(Left|Right)" -S || true
echo
echo "== Search: JSX usage of <ChevronLeft or <ChevronRight =="
rg -n "<Chevron(Left|Right)\\b" -S || true
echo
echo "== Search: any identifier or filename containing 'chevron' (case-insensitive) =="
rg -n -i "chevron" -S || true
echo
echo "== Search: any usage of 'lucide' (case-insensitive) =="
rg -n -i "lucide" -S || true
Length of output: 148845
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== lucide-react imports that mention 'Chevron' =="
rg -n "from\s+['\"]lucide-react['\"].*Chevron" -S || true
echo
echo "== All import lines that mention 'Chevron' (local or external) =="
rg -n "import.*Chevron" -S || true
Length of output: 43339
Move to local 8‑bit chevron asset — LGTM, but repo still contains lucide chevrons
The change in components/ui/dropdown-menu.tsx is correct. I scanned the repo and found these remaining lucide chevron imports that should be reviewed/replaced if the goal is complete migration:
- components/ui/accordion.tsx — import { ChevronDown } from "lucide-react";
- components/ui/calendar.tsx — import { ChevronDownIcon } from "lucide-react";
- components/ui/navigation-menu.tsx — import { ChevronDownIcon } from "lucide-react";
- components/ui/select.tsx — import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
- components/examples/combobox.tsx — import { ChevronsUpDown } from "lucide-react";
- app/docs/components/combo-box/page.tsx — import { ChevronsUpDown } from "lucide-react";
- components/version-switcher.tsx — import { Check, ChevronsUpDown, GalleryVerticalEnd } from "lucide-react";
Also note generated/public files under public/r/** contain lucide references (if those are regenerated from sources, update the source components).
Please replace these imports with the 8‑bit assets (or confirm they should remain) and re-run the scan.
🤖 Prompt for AI Agents
In components/ui/dropdown-menu.tsx around lines 10-11 and in the other listed
files (components/ui/accordion.tsx, components/ui/calendar.tsx,
components/ui/navigation-menu.tsx, components/ui/select.tsx,
components/examples/combobox.tsx, app/docs/components/combo-box/page.tsx,
components/version-switcher.tsx) replace lucide-react icon imports with the
local 8‑bit icon assets (e.g., import from the project 8‑bit assets module under
components/ui/8bit/assets), update any icon names/usages to match the 8‑bit
exports, ensure type/props compatibility, and then regenerate any public assets
under public/r/** from their sources so they no longer reference lucide; finally
re-run the repo scan to confirm all lucide imports have been removed or
intentionally retained.
{children} | ||
<ChevronRightIcon className="ml-auto size-4" /> | ||
<ChevronRightIcon /> | ||
</DropdownMenuPrimitive.SubTrigger> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Sub trigger chevron lost alignment/sizing (ml-auto, size) — reintroduce layout constraints
Previously the chevron sat at the far right (ml-auto) and matched menu icon sizing (size-4). The asset ships with size-7, so the icon is now larger and no longer right-aligned.
Apply a local wrapper to restore layout and avoid changing the asset’s signature:
{children}
- <ChevronRightIcon />
+ <span className="ml-auto [&>svg]:size-4" aria-hidden="true">
+ <ChevronRightIcon />
+ </span>
- Keeps layout consistent without modifying the asset.
- Hides the decorative icon from AT since the trigger itself is descriptive.
Visually verify the right alignment of submenu chevrons in all dropdown variants after this change.
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Locate dropdown-menu.tsx..."
file=$(fd -H -t f -I "dropdown-menu.tsx" || true)
if [ -z "$file" ]; then
echo "Not found by filename. Searching for 'DropdownMenuPrimitive.SubTrigger'..."
file=$(rg --hidden --glob '!*node_modules*' -n "DropdownMenuPrimitive.SubTrigger" -S | sed -n '1p' | cut -d: -f1 || true)
fi
if [ -z "$file" ]; then
echo "Still not found. Searching for 'components/ui/dropdown-menu' path references..."
file=$(rg --hidden --glob '!*node_modules*' -n "components/ui/dropdown-menu" -S | sed -n '1p' | cut -d: -f1 || true)
fi
if [ -z "$file" ]; then
echo "Could not locate dropdown-menu file in the repository."
exit 0
fi
echo "Found file: $file"
echo "---- Showing file with line numbers (first 400 lines) ----"
nl -ba "$file" | sed -n '1,400p'
echo
echo "---- Searching for ChevronRightIcon usages project-wide ----"
rg --hidden --glob '!*node_modules*' -n "ChevronRightIcon" -S || true
Length of output: 937
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Locating dropdown-menu.tsx files..."
mapfile -t files < <(fd -H -t f -I "dropdown-menu.tsx" || true)
if [ ${#files[@]} -eq 0 ]; then
echo "No dropdown-menu.tsx files found."
exit 0
fi
for f in "${files[@]}"; do
echo
echo "---- FILE: $f ----"
if [ -f "$f" ]; then
echo "---- Showing lines 200-240 ----"
awk 'NR>=200 && NR<=240{printf("%4d: %s\n", NR,$0)}' "$f" || true
echo
echo "---- Searching within this file for relevant tokens ----"
rg --hidden --glob '!*node_modules*' -n -S "ChevronRightIcon|DropdownMenuPrimitive.SubTrigger" "$f" || true
else
echo "File not found: $f"
fi
done
echo
echo "---- Global search for ChevronRightIcon (all files) ----"
rg --hidden --glob '!*node_modules*' -n -S "ChevronRightIcon" || true
Length of output: 263
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Searching for dropdown-menu.tsx files..."
find . -type f -name 'dropdown-menu.tsx' -print > /tmp/dropdown_files.txt 2>/dev/null || true
if [ ! -s /tmp/dropdown_files.txt ]; then
echo "No dropdown-menu.tsx files found."
exit 0
fi
while IFS= read -r f; do
echo
echo "---- FILE: $f ----"
if [ -f "$f" ]; then
echo "---- Showing lines 210-230 ----"
awk 'NR>=210 && NR<=230{printf("%4d: %s\n", NR,$0)}' "$f" || true
echo
echo "---- Showing lines 1-40 (file header/imports) ----"
awk 'NR>=1 && NR<=40{printf("%4d: %s\n", NR,$0)}' "$f" || true
echo
echo "---- Searching this file for relevant tokens ----"
rg -n --hidden --glob '!*node_modules*' "ChevronRightIcon|DropdownMenuPrimitive.SubTrigger|SubTrigger|SubContent" "$f" || true
else
echo "File not found: $f"
fi
done < /tmp/dropdown_files.txt
echo
echo "---- Global search for ChevronRightIcon occurrences ----"
rg -n --hidden --glob '!*node_modules*' -S "ChevronRightIcon" || true
Length of output: 49273
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "---- Showing asset: components/ui/8bit/assets/chevronRightIcon.tsx ----"
if [ -f "components/ui/8bit/assets/chevronRightIcon.tsx" ]; then
awk 'NR<=200{printf("%4d: %s\n", NR,$0)}' components/ui/8bit/assets/chevronRightIcon.tsx || true
else
echo "File not found: components/ui/8bit/assets/chevronRightIcon.tsx"
fi
echo
echo "---- Showing dropdown SubTrigger in components/ui/dropdown-menu.tsx (lines ~200-232) ----"
if [ -f "components/ui/dropdown-menu.tsx" ]; then
awk 'NR>=200 && NR<=232{printf("%4d: %s\n", NR,$0)}' components/ui/dropdown-menu.tsx || true
else
echo "File not found: components/ui/dropdown-menu.tsx"
fi
echo
echo "---- Search repo for '[&>svg]' patterns and 'size-' usages near them ----"
rg -n --hidden --glob '!*node_modules*' '\[&>svg\]' -S || true
rg -n --hidden --glob '!*node_modules*' '\bsize-[0-9]+' -S || true
echo
echo "---- All occurrences of ChevronRightIcon (files + line numbers) ----"
rg -n --hidden --glob '!*node_modules*' 'ChevronRightIcon' -S || true
Length of output: 270242
Restore right-aligned, correctly-sized chevron in SubTrigger
Confirmed: ChevronRightIcon (components/ui/8bit/assets/chevronRightIcon.tsx) ships with class "size-7", and DropdownMenuSubTrigger renders it without layout/sizing overrides — causing an oversized, left-positioned chevron. Wrap locally to restore alignment and size.
Files to change
- components/ui/dropdown-menu.tsx — DropdownMenuSubTrigger (around lines ~213–224)
Suggested change (apply locally so the asset signature stays untouched):
{children}
- <ChevronRightIcon />
+ <span className="ml-auto [&>svg]:size-4" aria-hidden="true">
+ <ChevronRightIcon />
+ </span>
</DropdownMenuPrimitive.SubTrigger>
- Keeps the chevron right-aligned (ml-auto) and forces the smaller size (size-4) without modifying the asset.
- Hides the decorative icon from assistive tech (aria-hidden) since the trigger text is the meaningful label.
Please apply and visually verify chevron alignment/sizing across dropdown variants (including 8bit wrappers / menubar/context-menu where applicable).
📝 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.
{children} | |
<ChevronRightIcon className="ml-auto size-4" /> | |
<ChevronRightIcon /> | |
</DropdownMenuPrimitive.SubTrigger> | |
{children} | |
<span className="ml-auto [&>svg]:size-4" aria-hidden="true"> | |
<ChevronRightIcon /> | |
</span> | |
</DropdownMenuPrimitive.SubTrigger> |
{ | ||
"path": "components/ui/8bit/breadcrumb.tsx", | ||
"content": "import { Slot } from \"@radix-ui/react-slot\";\nimport { type VariantProps, cva } from \"class-variance-authority\";\nimport { MoreHorizontal } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\nimport {\n Breadcrumb as ShadcnBreadcrumb,\n BreadcrumbEllipsis as ShadcnBreadcrumbEllipsis,\n BreadcrumbItem as ShadcnBreadcrumbItem,\n BreadcrumbList as ShadcnBreadcrumbList,\n BreadcrumbPage as ShadcnBreadcrumbPage,\n BreadcrumbSeparator as ShadcnBreadcrumbSeparator,\n} from \"@/components/ui/breadcrumb\";\n\nimport \"./styles/retro.css\";\n\nexport const breadcrumbVariants = cva(\"\", {\n variants: {\n font: {\n normal: \"\",\n retro: \"retro\",\n },\n variant: {\n default: \"text-card-foreground\",\n destructive:\n \"text-destructive [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n});\n\ninterface BitBreadcrumbNavigationProps\n extends React.ComponentProps<\"nav\">,\n VariantProps<typeof breadcrumbVariants> {}\n\ninterface BitBreadcrumbOrderedListProps\n extends React.ComponentProps<\"ol\">,\n VariantProps<typeof breadcrumbVariants> {}\n\ninterface BitBreadcrumbSpanProps\n extends React.ComponentProps<\"span\">,\n VariantProps<typeof breadcrumbVariants> {}\n\ninterface BitBreadcrumbListItemProps\n extends React.ComponentProps<\"li\">,\n VariantProps<typeof breadcrumbVariants> {}\n\ninterface BitBreadcrumbLinkProps\n extends React.ComponentProps<\"a\">,\n VariantProps<typeof breadcrumbVariants> {}\n\nconst ChevronRight = () => {\n return (\n <svg\n width=\"50\"\n height=\"50\"\n viewBox=\"0 0 256 256\"\n fill=\"currentColor\"\n xmlns=\"http://www.w3.org/2000/svg\"\n stroke=\"currentColor\"\n strokeWidth=\"0.25\"\n color=\"\"\n className=\"size-7\"\n aria-label=\"chevron-right\"\n >\n <rect x=\"128\" y=\"136\" width=\"14\" height=\"14\" rx=\"1\"></rect>\n <rect x=\"112\" y=\"152\" width=\"14\" height=\"14\" rx=\"1\"></rect>\n <rect x=\"96\" y=\"72\" width=\"14\" height=\"14\" rx=\"1\"></rect>\n <rect x=\"96\" y=\"168\" width=\"14\" height=\"14\" rx=\"1\"></rect>\n <rect x=\"144\" y=\"120\" width=\"14\" height=\"14\" rx=\"1\"></rect>\n <rect x=\"128\" y=\"104\" width=\"14\" height=\"14\" rx=\"1\"></rect>\n <rect x=\"112\" y=\"88\" width=\"14\" height=\"14\" rx=\"1\"></rect>\n </svg>\n );\n};\n\nfunction Breadcrumb({ children, ...props }: BitBreadcrumbNavigationProps) {\n const { variant, className, font } = props;\n\n return (\n <div\n className={cn(\n \"mb-4 flex items-center space-x-1 text-sm leading-none text-muted-foreground\",\n className\n )}\n >\n <ShadcnBreadcrumb\n {...props}\n className={cn(\n \"relative rounded-none border-none bg-background\",\n breadcrumbVariants({ variant }),\n font !== \"normal\" && \"retro\",\n className\n )}\n >\n {children}\n </ShadcnBreadcrumb>\n </div>\n );\n}\n\nfunction BreadcrumbList({ ...props }: BitBreadcrumbOrderedListProps) {\n const { font, className } = props;\n\n return (\n <ShadcnBreadcrumbList\n className={cn(className, font !== \"normal\" && \"retro\")}\n {...props}\n />\n );\n}\n\nfunction BreadcrumbItem({ ...props }: BitBreadcrumbListItemProps) {\n const { font, className } = props;\n\n return (\n <ShadcnBreadcrumbItem\n className={cn(className, font !== \"normal\" && \"retro\")}\n {...props}\n />\n );\n}\n\nfunction BreadcrumbLink({\n asChild,\n ...props\n}: BitBreadcrumbLinkProps & {\n asChild?: boolean;\n}) {\n const { font, className } = props;\n\n const Comp = asChild ? Slot : \"a\";\n\n return (\n <Comp\n data-slot=\"breadcrumb-link\"\n className={cn(className, font !== \"normal\" && \"retro\")}\n {...props}\n />\n );\n}\n\nfunction BreadcrumbPage({ ...props }: BitBreadcrumbSpanProps) {\n const { font, className } = props;\n\n return (\n <ShadcnBreadcrumbPage\n className={cn(className, font !== \"normal\" && \"retro\")}\n {...props}\n />\n );\n}\n\nfunction BreadcrumbSeparator({ ...props }: BitBreadcrumbListItemProps) {\n const { font, children, className } = props;\n\n return (\n <ShadcnBreadcrumbSeparator\n className={cn(className, font !== \"normal\" && \"retro\", \"[&>svg]:size-7\")}\n {...props}\n >\n {children ?? <ChevronRight />}\n </ShadcnBreadcrumbSeparator>\n );\n}\n\nfunction BreadcrumbEllipsis({ ...props }: BitBreadcrumbSpanProps) {\n const { font, className } = props;\n\n return (\n <ShadcnBreadcrumbEllipsis\n className={cn(className, font !== \"normal\" && \"retro\")}\n {...props}\n >\n <MoreHorizontal className={cn(\"size-7\", \"retro\")} />\n <span className=\"sr-only\">More</span>\n </ShadcnBreadcrumbEllipsis>\n );\n}\n\nexport {\n Breadcrumb,\n BreadcrumbList,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbPage,\n BreadcrumbSeparator,\n BreadcrumbEllipsis,\n};\n", | ||
"content": "import { Slot } from \"@radix-ui/react-slot\";\r\nimport { type VariantProps, cva } from \"class-variance-authority\";\r\nimport { MoreHorizontal } from \"lucide-react\";\r\n\r\nimport { ChevronRightIcon } from \"@/components/ui/8bit/assets/chevronRightIcon\";\r\n\r\nimport { cn } from \"@/lib/utils\";\r\n\r\nimport {\r\n Breadcrumb as ShadcnBreadcrumb,\r\n BreadcrumbEllipsis as ShadcnBreadcrumbEllipsis,\r\n BreadcrumbItem as ShadcnBreadcrumbItem,\r\n BreadcrumbList as ShadcnBreadcrumbList,\r\n BreadcrumbPage as ShadcnBreadcrumbPage,\r\n BreadcrumbSeparator as ShadcnBreadcrumbSeparator,\r\n} from \"@/components/ui/breadcrumb\";\r\n\r\nimport \"./styles/retro.css\";\r\n\r\nexport const breadcrumbVariants = cva(\"\", {\r\n variants: {\r\n font: {\r\n normal: \"\",\r\n retro: \"retro\",\r\n },\r\n variant: {\r\n default: \"text-card-foreground\",\r\n destructive:\r\n \"text-destructive [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90\",\r\n },\r\n },\r\n defaultVariants: {\r\n variant: \"default\",\r\n },\r\n});\r\n\r\ninterface BitBreadcrumbNavigationProps\r\n extends React.ComponentProps<\"nav\">,\r\n VariantProps<typeof breadcrumbVariants> {}\r\n\r\ninterface BitBreadcrumbOrderedListProps\r\n extends React.ComponentProps<\"ol\">,\r\n VariantProps<typeof breadcrumbVariants> {}\r\n\r\ninterface BitBreadcrumbSpanProps\r\n extends React.ComponentProps<\"span\">,\r\n VariantProps<typeof breadcrumbVariants> {}\r\n\r\ninterface BitBreadcrumbListItemProps\r\n extends React.ComponentProps<\"li\">,\r\n VariantProps<typeof breadcrumbVariants> {}\r\n\r\ninterface BitBreadcrumbLinkProps\r\n extends React.ComponentProps<\"a\">,\r\n VariantProps<typeof breadcrumbVariants> {}\r\n\r\nfunction Breadcrumb({ children, ...props }: BitBreadcrumbNavigationProps) {\r\n const { variant, className, font } = props;\r\n\r\n return (\r\n <div\r\n className={cn(\r\n \"mb-4 flex items-center space-x-1 text-sm leading-none text-muted-foreground\",\r\n className\r\n )}\r\n >\r\n <ShadcnBreadcrumb\r\n {...props}\r\n className={cn(\r\n \"relative rounded-none border-none bg-background\",\r\n breadcrumbVariants({ variant }),\r\n font !== \"normal\" && \"retro\",\r\n className\r\n )}\r\n >\r\n {children}\r\n </ShadcnBreadcrumb>\r\n </div>\r\n );\r\n}\r\n\r\nfunction BreadcrumbList({ ...props }: BitBreadcrumbOrderedListProps) {\r\n const { font, className } = props;\r\n\r\n return (\r\n <ShadcnBreadcrumbList\r\n className={cn(className, font !== \"normal\" && \"retro\")}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction BreadcrumbItem({ ...props }: BitBreadcrumbListItemProps) {\r\n const { font, className } = props;\r\n\r\n return (\r\n <ShadcnBreadcrumbItem\r\n className={cn(className, font !== \"normal\" && \"retro\")}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction BreadcrumbLink({\r\n asChild,\r\n ...props\r\n}: BitBreadcrumbLinkProps & {\r\n asChild?: boolean;\r\n}) {\r\n const { font, className } = props;\r\n\r\n const Comp = asChild ? Slot : \"a\";\r\n\r\n return (\r\n <Comp\r\n data-slot=\"breadcrumb-link\"\r\n className={cn(className, font !== \"normal\" && \"retro\")}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction BreadcrumbPage({ ...props }: BitBreadcrumbSpanProps) {\r\n const { font, className } = props;\r\n\r\n return (\r\n <ShadcnBreadcrumbPage\r\n className={cn(className, font !== \"normal\" && \"retro\")}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction BreadcrumbSeparator({ ...props }: BitBreadcrumbListItemProps) {\r\n const { font, children, className } = props;\r\n\r\n return (\r\n <ShadcnBreadcrumbSeparator\r\n className={cn(className, font !== \"normal\" && \"retro\", \"[&>svg]:size-7\")}\r\n {...props}\r\n >\r\n {children ?? <ChevronRightIcon/>}\r\n </ShadcnBreadcrumbSeparator>\r\n );\r\n}\r\n\r\nfunction BreadcrumbEllipsis({ ...props }: BitBreadcrumbSpanProps) {\r\n const { font, className } = props;\r\n\r\n return (\r\n <ShadcnBreadcrumbEllipsis\r\n className={cn(className, font !== \"normal\" && \"retro\")}\r\n {...props}\r\n >\r\n <MoreHorizontal className={cn(\"size-7\", \"retro\")} />\r\n <span className=\"sr-only\">More</span>\r\n </ShadcnBreadcrumbEllipsis>\r\n );\r\n}\r\n\r\nexport {\r\n Breadcrumb,\r\n BreadcrumbList,\r\n BreadcrumbItem,\r\n BreadcrumbLink,\r\n BreadcrumbPage,\r\n BreadcrumbSeparator,\r\n BreadcrumbEllipsis,\r\n};\r\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Decorative separator icon should be aria-hidden
The separator chevron is purely decorative. With the current asset having an aria-label, this can pollute the accessible name. Hide it from assistive tech (and consider removing aria-label from the asset).
Apply in components/ui/8bit/breadcrumb.tsx:
- {children ?? <ChevronRightIcon/>}
+ {children ?? <ChevronRightIcon aria-hidden="true" focusable="false" />}
Additionally, consider updating the icon assets to forward props and default to aria-hidden; see asset suggestion in my Calendar comment.
📝 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.
"content": "import { Slot } from \"@radix-ui/react-slot\";\r\nimport { type VariantProps, cva } from \"class-variance-authority\";\r\nimport { MoreHorizontal } from \"lucide-react\";\r\n\r\nimport { ChevronRightIcon } from \"@/components/ui/8bit/assets/chevronRightIcon\";\r\n\r\nimport { cn } from \"@/lib/utils\";\r\n\r\nimport {\r\n Breadcrumb as ShadcnBreadcrumb,\r\n BreadcrumbEllipsis as ShadcnBreadcrumbEllipsis,\r\n BreadcrumbItem as ShadcnBreadcrumbItem,\r\n BreadcrumbList as ShadcnBreadcrumbList,\r\n BreadcrumbPage as ShadcnBreadcrumbPage,\r\n BreadcrumbSeparator as ShadcnBreadcrumbSeparator,\r\n} from \"@/components/ui/breadcrumb\";\r\n\r\nimport \"./styles/retro.css\";\r\n\r\nexport const breadcrumbVariants = cva(\"\", {\r\n variants: {\r\n font: {\r\n normal: \"\",\r\n retro: \"retro\",\r\n },\r\n variant: {\r\n default: \"text-card-foreground\",\r\n destructive:\r\n \"text-destructive [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90\",\r\n },\r\n },\r\n defaultVariants: {\r\n variant: \"default\",\r\n },\r\n});\r\n\r\ninterface BitBreadcrumbNavigationProps\r\n extends React.ComponentProps<\"nav\">,\r\n VariantProps<typeof breadcrumbVariants> {}\r\n\r\ninterface BitBreadcrumbOrderedListProps\r\n extends React.ComponentProps<\"ol\">,\r\n VariantProps<typeof breadcrumbVariants> {}\r\n\r\ninterface BitBreadcrumbSpanProps\r\n extends React.ComponentProps<\"span\">,\r\n VariantProps<typeof breadcrumbVariants> {}\r\n\r\ninterface BitBreadcrumbListItemProps\r\n extends React.ComponentProps<\"li\">,\r\n VariantProps<typeof breadcrumbVariants> {}\r\n\r\ninterface BitBreadcrumbLinkProps\r\n extends React.ComponentProps<\"a\">,\r\n VariantProps<typeof breadcrumbVariants> {}\r\n\r\nfunction Breadcrumb({ children, ...props }: BitBreadcrumbNavigationProps) {\r\n const { variant, className, font } = props;\r\n\r\n return (\r\n <div\r\n className={cn(\r\n \"mb-4 flex items-center space-x-1 text-sm leading-none text-muted-foreground\",\r\n className\r\n )}\r\n >\r\n <ShadcnBreadcrumb\r\n {...props}\r\n className={cn(\r\n \"relative rounded-none border-none bg-background\",\r\n breadcrumbVariants({ variant }),\r\n font !== \"normal\" && \"retro\",\r\n className\r\n )}\r\n >\r\n {children}\r\n </ShadcnBreadcrumb>\r\n </div>\r\n );\r\n}\r\n\r\nfunction BreadcrumbList({ ...props }: BitBreadcrumbOrderedListProps) {\r\n const { font, className } = props;\r\n\r\n return (\r\n <ShadcnBreadcrumbList\r\n className={cn(className, font !== \"normal\" && \"retro\")}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction BreadcrumbItem({ ...props }: BitBreadcrumbListItemProps) {\r\n const { font, className } = props;\r\n\r\n return (\r\n <ShadcnBreadcrumbItem\r\n className={cn(className, font !== \"normal\" && \"retro\")}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction BreadcrumbLink({\r\n asChild,\r\n ...props\r\n}: BitBreadcrumbLinkProps & {\r\n asChild?: boolean;\r\n}) {\r\n const { font, className } = props;\r\n\r\n const Comp = asChild ? Slot : \"a\";\r\n\r\n return (\r\n <Comp\r\n data-slot=\"breadcrumb-link\"\r\n className={cn(className, font !== \"normal\" && \"retro\")}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction BreadcrumbPage({ ...props }: BitBreadcrumbSpanProps) {\r\n const { font, className } = props;\r\n\r\n return (\r\n <ShadcnBreadcrumbPage\r\n className={cn(className, font !== \"normal\" && \"retro\")}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction BreadcrumbSeparator({ ...props }: BitBreadcrumbListItemProps) {\r\n const { font, children, className } = props;\r\n\r\n return (\r\n <ShadcnBreadcrumbSeparator\r\n className={cn(className, font !== \"normal\" && \"retro\", \"[&>svg]:size-7\")}\r\n {...props}\r\n >\r\n {children ?? <ChevronRightIcon/>}\r\n </ShadcnBreadcrumbSeparator>\r\n );\r\n}\r\n\r\nfunction BreadcrumbEllipsis({ ...props }: BitBreadcrumbSpanProps) {\r\n const { font, className } = props;\r\n\r\n return (\r\n <ShadcnBreadcrumbEllipsis\r\n className={cn(className, font !== \"normal\" && \"retro\")}\r\n {...props}\r\n >\r\n <MoreHorizontal className={cn(\"size-7\", \"retro\")} />\r\n <span className=\"sr-only\">More</span>\r\n </ShadcnBreadcrumbEllipsis>\r\n );\r\n}\r\n\r\nexport {\r\n Breadcrumb,\r\n BreadcrumbList,\r\n BreadcrumbItem,\r\n BreadcrumbLink,\r\n BreadcrumbPage,\r\n BreadcrumbSeparator,\r\n BreadcrumbEllipsis,\r\n};\r\n", | |
function BreadcrumbSeparator({ ...props }: BitBreadcrumbListItemProps) { | |
const { font, children, className } = props; | |
return ( | |
<ShadcnBreadcrumbSeparator | |
className={cn(className, font !== "normal" && "retro", "[&>svg]:size-7")} | |
{...props} | |
> | |
{children ?? <ChevronRightIcon aria-hidden="true" focusable="false" />} | |
</ShadcnBreadcrumbSeparator> | |
); | |
} |
🤖 Prompt for AI Agents
In public/r/8bit-breadcrumb.json around line 13, the separator chevron used in
BreadcrumbSeparator is decorative and should be hidden from assistive
technology; update the BreadcrumbSeparator component in
components/ui/8bit/breadcrumb.tsx to render the ChevronRightIcon with
aria-hidden="true" (and remove any aria-label on that usage), and also update
the chevron icon asset to forward props and default to aria-hidden so consumers
don't need to repeat it.
Retro font applies by default when font is undefined
font !== "normal" will evaluate true when font is undefined, unintentionally applying the retro font unless font="normal" is explicitly passed. Set defaultVariants.font to "normal".
export const breadcrumbVariants = cva("", {
variants: {
font: {
normal: "",
retro: "retro",
},
variant: {
default: "text-card-foreground",
destructive:
"text-destructive [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90",
},
},
defaultVariants: {
variant: "default",
+ font: "normal",
},
});
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
public/r/8bit-breadcrumb.json around line 13: the breadcrumbVariants
defaultVariants currently only sets variant and leaves font undefined which
makes font !== "normal" evaluate true and unintentionally apply the retro font;
update breadcrumbVariants.defaultVariants to include font: "normal" so the retro
font only applies when font is explicitly set (i.e., add font: "normal" to the
defaultVariants object).
🛠️ Refactor suggestion
Prevent leaking design-system props (variant, font) to the DOM
variant and font (and className duplicates) are still included in {...props} and end up as invalid attributes on the DOM nodes. Extract them and pass the rest only.
Apply this refactor inside components/ui/8bit/breadcrumb.tsx:
-function Breadcrumb({ children, ...props }: BitBreadcrumbNavigationProps) {
- const { variant, className, font } = props;
+function Breadcrumb({
+ children,
+ variant,
+ className,
+ font,
+ ...rest
+}: BitBreadcrumbNavigationProps) {
return (
<div
className={cn(
"mb-4 flex items-center space-x-1 text-sm leading-none text-muted-foreground",
className
)}
>
- <ShadcnBreadcrumb
- {...props}
+ <ShadcnBreadcrumb
+ {...rest}
className={cn(
"relative rounded-none border-none bg-background",
breadcrumbVariants({ variant }),
font !== "normal" && "retro",
className
)}
>
{children}
</ShadcnBreadcrumb>
</div>
);
}
-function BreadcrumbList({ ...props }: BitBreadcrumbOrderedListProps) {
- const { font, className } = props;
+function BreadcrumbList({ font, className, ...rest }: BitBreadcrumbOrderedListProps) {
return (
<ShadcnBreadcrumbList
className={cn(className, font !== "normal" && "retro")}
- {...props}
+ {...rest}
/>
);
}
-function BreadcrumbItem({ ...props }: BitBreadcrumbListItemProps) {
- const { font, className } = props;
+function BreadcrumbItem({ font, className, ...rest }: BitBreadcrumbListItemProps) {
return (
<ShadcnBreadcrumbItem
className={cn(className, font !== "normal" && "retro")}
- {...props}
+ {...rest}
/>
);
}
function BreadcrumbLink({
asChild,
- ...props
+ ...props
}: BitBreadcrumbLinkProps & {
asChild?: boolean;
}) {
const { font, className } = props;
const Comp = asChild ? Slot : "a";
return (
<Comp
data-slot="breadcrumb-link"
className={cn(className, font !== "normal" && "retro")}
- {...props}
+ {...props}
/>
);
}
-function BreadcrumbPage({ ...props }: BitBreadcrumbSpanProps) {
- const { font, className } = props;
+function BreadcrumbPage({ font, className, ...rest }: BitBreadcrumbSpanProps) {
return (
<ShadcnBreadcrumbPage
className={cn(className, font !== "normal" && "retro")}
- {...props}
+ {...rest}
/>
);
}
-function BreadcrumbSeparator({ ...props }: BitBreadcrumbListItemProps) {
- const { font, children, className } = props;
+function BreadcrumbSeparator({ font, children, className, ...rest }: BitBreadcrumbListItemProps) {
return (
<ShadcnBreadcrumbSeparator
className={cn(className, font !== "normal" && "retro", "[&>svg]:size-7")}
- {...props}
+ {...rest}
>
{children ?? <ChevronRightIcon/>}
</ShadcnBreadcrumbSeparator>
);
}
-function BreadcrumbEllipsis({ ...props }: BitBreadcrumbSpanProps) {
- const { font, className } = props;
+function BreadcrumbEllipsis({ font, className, ...rest }: BitBreadcrumbSpanProps) {
return (
<ShadcnBreadcrumbEllipsis
className={cn(className, font !== "normal\" && \"retro")}
- {...props}
+ {...rest}
>
<MoreHorizontal className={cn("size-7", "retro")} />
<span className="sr-only">More</span>
</ShadcnBreadcrumbEllipsis>
);
}
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
public/r/8bit-breadcrumb.json lines 13-13: The components leak design-system
props (variant, font and duplicate className) into {...props} which become
invalid DOM attributes; fix by destructuring variant, font, and className (and
any other design props) from props in each component, collect the rest as
...rest, and spread only ...rest onto the underlying element (or Shadcn wrapper)
while composing className manually with cn; ensure BreadcrumbLink handles
asChild correctly by passing ...rest to Comp, and
BreadcrumbSeparator/Ellipsis/others do the same so variant/font are never
forwarded to DOM.
{ | ||
"path": "components/ui/8bit/context-menu.tsx", | ||
"content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport * as ContextMenuPrimitive from \"@radix-ui/react-context-menu\";\nimport { ChevronRight, Circle } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\nimport \"./styles/retro.css\";\n\nconst ContextMenu = ContextMenuPrimitive.Root;\n\nconst ContextMenuTrigger = ContextMenuPrimitive.Trigger;\n\nconst ContextMenuGroup = ContextMenuPrimitive.Group;\n\nconst ContextMenuPortal = ContextMenuPrimitive.Portal;\n\nconst ContextMenuSub = ContextMenuPrimitive.Sub;\n\nconst ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;\n\nconst ContextMenuSubTrigger = React.forwardRef<\n React.ComponentRef<typeof ContextMenuPrimitive.SubTrigger>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & {\n inset?: boolean;\n }\n>(({ className, inset, children, ...props }, ref) => (\n <ContextMenuPrimitive.SubTrigger\n ref={ref}\n className={cn(\n \"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:border-y-4 focus:border-foreground h-8 focus:dark:border-ring border-dashed focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground\",\n inset && \"pl-8\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto size-4\" />\n </ContextMenuPrimitive.SubTrigger>\n));\nContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;\n\nconst ContextMenuSubContent = React.forwardRef<\n React.ComponentRef<typeof ContextMenuPrimitive.SubContent>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>\n>(({ className, ...props }, ref) => (\n <ContextMenuPrimitive.SubContent\n ref={ref}\n className={cn(\n \"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-context-menu-content-transform-origin]\",\n className\n )}\n {...props}\n />\n));\nContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;\n\nconst ContextMenuContent = React.forwardRef<\n React.ComponentRef<typeof ContextMenuPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <ContextMenuPrimitive.Portal>\n <div className=\"relative\">\n <ContextMenuPrimitive.Content\n ref={ref}\n className={cn(\n \"z-50 max-h-[--radix-context-menu-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border-x-4 border-y-6 border-foreground dark:border-ring bg-popover p-1 text-popover-foreground animate-in fade-in-80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-context-menu-content-transform-origin]\",\n \"retro\",\n className\n )}\n {...props}\n />\n <div\n className=\"absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none\"\n aria-hidden=\"true\"\n />\n </div>\n </ContextMenuPrimitive.Portal>\n));\nContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;\n\nconst ContextMenuItem = React.forwardRef<\n React.ComponentRef<typeof ContextMenuPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & {\n inset?: boolean;\n }\n>(({ className, inset, ...props }, ref) => (\n <ContextMenuPrimitive.Item\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:border-y-4 focus:border-foreground h-8 focus:dark:border-ring border-dashed focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n inset && \"pl-8\",\n className\n )}\n {...props}\n />\n));\nContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;\n\nconst ContextMenuCheckboxItem = React.forwardRef<\n React.ComponentRef<typeof ContextMenuPrimitive.CheckboxItem>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <ContextMenuPrimitive.CheckboxItem\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:border-y-4 focus:border-foreground h-8 focus:dark:border-ring border-dashed focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className\n )}\n checked={checked}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <ContextMenuPrimitive.ItemIndicator>\n <svg\n width=\"50\"\n height=\"50\"\n viewBox=\"0 0 256 256\"\n fill=\"currentColor\"\n xmlns=\"http://www.w3.org/2000/svg\"\n stroke=\"currentColor\"\n strokeWidth=\"0.25\"\n aria-label=\"check\"\n className=\"size-9\"\n >\n <rect\n x=\"80\"\n y=\"128\"\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"rotate(90 80 128)\"\n ></rect>\n <rect\n x=\"96\"\n y=\"144\"\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"rotate(90 96 144)\"\n ></rect>\n <rect\n x=\"112\"\n y=\"160\"\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"rotate(90 112 160)\"\n ></rect>\n <rect\n x=\"128\"\n y=\"144\"\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"rotate(90 128 144)\"\n ></rect>\n <rect\n x=\"144\"\n y=\"128\"\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"rotate(90 144 128)\"\n ></rect>\n <rect\n x=\"160\"\n y=\"112\"\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"rotate(90 160 112)\"\n ></rect>\n <rect\n x=\"176\"\n y=\"96\"\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"rotate(90 176 96)\"\n ></rect>\n <rect\n x=\"192\"\n y=\"80\"\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"rotate(90 192 80)\"\n ></rect>\n </svg>\n </ContextMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </ContextMenuPrimitive.CheckboxItem>\n));\nContextMenuCheckboxItem.displayName =\n ContextMenuPrimitive.CheckboxItem.displayName;\n\nconst ContextMenuRadioItem = React.forwardRef<\n React.ComponentRef<typeof ContextMenuPrimitive.RadioItem>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n <ContextMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:border-y-4 focus:border-foreground h-8 focus:dark:border-ring border-dashed focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <ContextMenuPrimitive.ItemIndicator>\n <Circle className=\"size-2 fill-current\" />\n </ContextMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </ContextMenuPrimitive.RadioItem>\n));\nContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;\n\nconst ContextMenuLabel = React.forwardRef<\n React.ComponentRef<typeof ContextMenuPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & {\n inset?: boolean;\n }\n>(({ className, inset, ...props }, ref) => (\n <ContextMenuPrimitive.Label\n ref={ref}\n className={cn(\n \"px-2 py-1.5 text-sm font-semibold text-foreground\",\n inset && \"pl-8\",\n className\n )}\n {...props}\n />\n));\nContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;\n\nconst ContextMenuSeparator = React.forwardRef<\n React.ComponentRef<typeof ContextMenuPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <ContextMenuPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-1 my-1 h-px bg-border\", className)}\n {...props}\n />\n));\nContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;\n\nconst ContextMenuShortcut = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLSpanElement>) => {\n return (\n <span\n className={cn(\n \"ml-auto text-xs tracking-widest text-muted-foreground\",\n className\n )}\n {...props}\n />\n );\n};\nContextMenuShortcut.displayName = \"ContextMenuShortcut\";\n\nexport {\n ContextMenu,\n ContextMenuTrigger,\n ContextMenuContent,\n ContextMenuItem,\n ContextMenuCheckboxItem,\n ContextMenuRadioItem,\n ContextMenuLabel,\n ContextMenuSeparator,\n ContextMenuShortcut,\n ContextMenuGroup,\n ContextMenuPortal,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuRadioGroup,\n};\n", | ||
"content": "\"use client\";\r\n\r\nimport * as React from \"react\";\r\n\r\nimport * as ContextMenuPrimitive from \"@radix-ui/react-context-menu\";\r\nimport { Circle } from \"lucide-react\";\r\n\r\nimport { ChevronRightIcon } from \"@/components/ui/8bit/assets/chevronRightIcon\";\r\n\r\nimport { cn } from \"@/lib/utils\";\r\n\r\nimport \"./styles/retro.css\";\r\n\r\nconst ContextMenu = ContextMenuPrimitive.Root;\r\n\r\nconst ContextMenuTrigger = ContextMenuPrimitive.Trigger;\r\n\r\nconst ContextMenuGroup = ContextMenuPrimitive.Group;\r\n\r\nconst ContextMenuPortal = ContextMenuPrimitive.Portal;\r\n\r\nconst ContextMenuSub = ContextMenuPrimitive.Sub;\r\n\r\nconst ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;\r\n\r\nconst ContextMenuSubTrigger = React.forwardRef<\r\n React.ComponentRef<typeof ContextMenuPrimitive.SubTrigger>,\r\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & {\r\n inset?: boolean;\r\n }\r\n>(({ className, inset, children, ...props }, ref) => (\r\n <ContextMenuPrimitive.SubTrigger\r\n ref={ref}\r\n className={cn(\r\n \"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:border-y-4 focus:border-foreground h-8 focus:dark:border-ring border-dashed focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground\",\r\n inset && \"pl-8\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n {children}\r\n <ChevronRightIcon/>\r\n </ContextMenuPrimitive.SubTrigger>\r\n));\r\nContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;\r\n\r\nconst ContextMenuSubContent = React.forwardRef<\r\n React.ComponentRef<typeof ContextMenuPrimitive.SubContent>,\r\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>\r\n>(({ className, ...props }, ref) => (\r\n <ContextMenuPrimitive.SubContent\r\n ref={ref}\r\n className={cn(\r\n \"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-context-menu-content-transform-origin]\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n));\r\nContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;\r\n\r\nconst ContextMenuContent = React.forwardRef<\r\n React.ComponentRef<typeof ContextMenuPrimitive.Content>,\r\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>\r\n>(({ className, ...props }, ref) => (\r\n <ContextMenuPrimitive.Portal>\r\n <div className=\"relative\">\r\n <ContextMenuPrimitive.Content\r\n ref={ref}\r\n className={cn(\r\n \"z-50 max-h-[--radix-context-menu-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border-x-4 border-y-6 border-foreground dark:border-ring bg-popover p-1 text-popover-foreground animate-in fade-in-80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-context-menu-content-transform-origin]\",\r\n \"retro\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n <div\r\n className=\"absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n </div>\r\n </ContextMenuPrimitive.Portal>\r\n));\r\nContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;\r\n\r\nconst ContextMenuItem = React.forwardRef<\r\n React.ComponentRef<typeof ContextMenuPrimitive.Item>,\r\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & {\r\n inset?: boolean;\r\n }\r\n>(({ className, inset, ...props }, ref) => (\r\n <ContextMenuPrimitive.Item\r\n ref={ref}\r\n className={cn(\r\n \"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:border-y-4 focus:border-foreground h-8 focus:dark:border-ring border-dashed focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\r\n inset && \"pl-8\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n));\r\nContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;\r\n\r\nconst ContextMenuCheckboxItem = React.forwardRef<\r\n React.ComponentRef<typeof ContextMenuPrimitive.CheckboxItem>,\r\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>\r\n>(({ className, children, checked, ...props }, ref) => (\r\n <ContextMenuPrimitive.CheckboxItem\r\n ref={ref}\r\n className={cn(\r\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:border-y-4 focus:border-foreground h-8 focus:dark:border-ring border-dashed focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\r\n className\r\n )}\r\n checked={checked}\r\n {...props}\r\n >\r\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\r\n <ContextMenuPrimitive.ItemIndicator>\r\n <svg\r\n width=\"50\"\r\n height=\"50\"\r\n viewBox=\"0 0 256 256\"\r\n fill=\"currentColor\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"0.25\"\r\n aria-label=\"check\"\r\n className=\"size-9\"\r\n >\r\n <rect\r\n x=\"80\"\r\n y=\"128\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 80 128)\"\r\n ></rect>\r\n <rect\r\n x=\"96\"\r\n y=\"144\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 96 144)\"\r\n ></rect>\r\n <rect\r\n x=\"112\"\r\n y=\"160\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 112 160)\"\r\n ></rect>\r\n <rect\r\n x=\"128\"\r\n y=\"144\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 128 144)\"\r\n ></rect>\r\n <rect\r\n x=\"144\"\r\n y=\"128\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 144 128)\"\r\n ></rect>\r\n <rect\r\n x=\"160\"\r\n y=\"112\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 160 112)\"\r\n ></rect>\r\n <rect\r\n x=\"176\"\r\n y=\"96\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 176 96)\"\r\n ></rect>\r\n <rect\r\n x=\"192\"\r\n y=\"80\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 192 80)\"\r\n ></rect>\r\n </svg>\r\n </ContextMenuPrimitive.ItemIndicator>\r\n </span>\r\n {children}\r\n </ContextMenuPrimitive.CheckboxItem>\r\n));\r\nContextMenuCheckboxItem.displayName =\r\n ContextMenuPrimitive.CheckboxItem.displayName;\r\n\r\nconst ContextMenuRadioItem = React.forwardRef<\r\n React.ComponentRef<typeof ContextMenuPrimitive.RadioItem>,\r\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>\r\n>(({ className, children, ...props }, ref) => (\r\n <ContextMenuPrimitive.RadioItem\r\n ref={ref}\r\n className={cn(\r\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:border-y-4 focus:border-foreground h-8 focus:dark:border-ring border-dashed focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\r\n <ContextMenuPrimitive.ItemIndicator>\r\n <Circle className=\"size-2 fill-current\" />\r\n </ContextMenuPrimitive.ItemIndicator>\r\n </span>\r\n {children}\r\n </ContextMenuPrimitive.RadioItem>\r\n));\r\nContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;\r\n\r\nconst ContextMenuLabel = React.forwardRef<\r\n React.ComponentRef<typeof ContextMenuPrimitive.Label>,\r\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & {\r\n inset?: boolean;\r\n }\r\n>(({ className, inset, ...props }, ref) => (\r\n <ContextMenuPrimitive.Label\r\n ref={ref}\r\n className={cn(\r\n \"px-2 py-1.5 text-sm font-semibold text-foreground\",\r\n inset && \"pl-8\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n));\r\nContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;\r\n\r\nconst ContextMenuSeparator = React.forwardRef<\r\n React.ComponentRef<typeof ContextMenuPrimitive.Separator>,\r\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>\r\n>(({ className, ...props }, ref) => (\r\n <ContextMenuPrimitive.Separator\r\n ref={ref}\r\n className={cn(\"-mx-1 my-1 h-px bg-border\", className)}\r\n {...props}\r\n />\r\n));\r\nContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;\r\n\r\nconst ContextMenuShortcut = ({\r\n className,\r\n ...props\r\n}: React.HTMLAttributes<HTMLSpanElement>) => {\r\n return (\r\n <span\r\n className={cn(\r\n \"ml-auto text-xs tracking-widest text-muted-foreground\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n );\r\n};\r\nContextMenuShortcut.displayName = \"ContextMenuShortcut\";\r\n\r\nexport {\r\n ContextMenu,\r\n ContextMenuTrigger,\r\n ContextMenuContent,\r\n ContextMenuItem,\r\n ContextMenuCheckboxItem,\r\n ContextMenuRadioItem,\r\n ContextMenuLabel,\r\n ContextMenuSeparator,\r\n ContextMenuShortcut,\r\n ContextMenuGroup,\r\n ContextMenuPortal,\r\n ContextMenuSub,\r\n ContextMenuSubContent,\r\n ContextMenuSubTrigger,\r\n ContextMenuRadioGroup,\r\n};\r\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Chevron alignment likely regressed; restore right alignment and improve a11y.
ContextMenuSubTrigger
now renders <ChevronRightIcon />
without ml-auto
. Previously, the lucide icon used ml-auto
to push the chevron to the far right. As-is, the icon will sit directly after the label, which is a behavioral/visual change. Also, the icon should be decorative for screen readers.
Suggested fix (doesn’t require changing the icon component API):
- {children}
- <ChevronRightIcon/>
+ {children}
+ <span className="ml-auto">
+ <ChevronRightIcon aria-hidden="true" />
+ </span>
If you prefer passing classes directly to the icon, make the icon accept className
and then use className="ml-auto size-4 shrink-0 opacity-70"
here.
📝 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.
"content": "\"use client\";\r\n\r\nimport * as React from \"react\";\r\n\r\nimport * as ContextMenuPrimitive from \"@radix-ui/react-context-menu\";\r\nimport { Circle } from \"lucide-react\";\r\n\r\nimport { ChevronRightIcon } from \"@/components/ui/8bit/assets/chevronRightIcon\";\r\n\r\nimport { cn } from \"@/lib/utils\";\r\n\r\nimport \"./styles/retro.css\";\r\n\r\nconst ContextMenu = ContextMenuPrimitive.Root;\r\n\r\nconst ContextMenuTrigger = ContextMenuPrimitive.Trigger;\r\n\r\nconst ContextMenuGroup = ContextMenuPrimitive.Group;\r\n\r\nconst ContextMenuPortal = ContextMenuPrimitive.Portal;\r\n\r\nconst ContextMenuSub = ContextMenuPrimitive.Sub;\r\n\r\nconst ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;\r\n\r\nconst ContextMenuSubTrigger = React.forwardRef<\r\n React.ComponentRef<typeof ContextMenuPrimitive.SubTrigger>,\r\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & {\r\n inset?: boolean;\r\n }\r\n>(({ className, inset, children, ...props }, ref) => (\r\n <ContextMenuPrimitive.SubTrigger\r\n ref={ref}\r\n className={cn(\r\n \"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:border-y-4 focus:border-foreground h-8 focus:dark:border-ring border-dashed focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground\",\r\n inset && \"pl-8\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n {children}\r\n <ChevronRightIcon/>\r\n </ContextMenuPrimitive.SubTrigger>\r\n));\r\nContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;\r\n\r\nconst ContextMenuSubContent = React.forwardRef<\r\n React.ComponentRef<typeof ContextMenuPrimitive.SubContent>,\r\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>\r\n>(({ className, ...props }, ref) => (\r\n <ContextMenuPrimitive.SubContent\r\n ref={ref}\r\n className={cn(\r\n \"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-context-menu-content-transform-origin]\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n));\r\nContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;\r\n\r\nconst ContextMenuContent = React.forwardRef<\r\n React.ComponentRef<typeof ContextMenuPrimitive.Content>,\r\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>\r\n>(({ className, ...props }, ref) => (\r\n <ContextMenuPrimitive.Portal>\r\n <div className=\"relative\">\r\n <ContextMenuPrimitive.Content\r\n ref={ref}\r\n className={cn(\r\n \"z-50 max-h-[--radix-context-menu-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border-x-4 border-y-6 border-foreground dark:border-ring bg-popover p-1 text-popover-foreground animate-in fade-in-80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-context-menu-content-transform-origin]\",\r\n \"retro\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n <div\r\n className=\"absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n </div>\r\n </ContextMenuPrimitive.Portal>\r\n));\r\nContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;\r\n\r\nconst ContextMenuItem = React.forwardRef<\r\n React.ComponentRef<typeof ContextMenuPrimitive.Item>,\r\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & {\r\n inset?: boolean;\r\n }\r\n>(({ className, inset, ...props }, ref) => (\r\n <ContextMenuPrimitive.Item\r\n ref={ref}\r\n className={cn(\r\n \"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:border-y-4 focus:border-foreground h-8 focus:dark:border-ring border-dashed focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\r\n inset && \"pl-8\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n));\r\nContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;\r\n\r\nconst ContextMenuCheckboxItem = React.forwardRef<\r\n React.ComponentRef<typeof ContextMenuPrimitive.CheckboxItem>,\r\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>\r\n>(({ className, children, checked, ...props }, ref) => (\r\n <ContextMenuPrimitive.CheckboxItem\r\n ref={ref}\r\n className={cn(\r\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:border-y-4 focus:border-foreground h-8 focus:dark:border-ring border-dashed focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\r\n className\r\n )}\r\n checked={checked}\r\n {...props}\r\n >\r\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\r\n <ContextMenuPrimitive.ItemIndicator>\r\n <svg\r\n width=\"50\"\r\n height=\"50\"\r\n viewBox=\"0 0 256 256\"\r\n fill=\"currentColor\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"0.25\"\r\n aria-label=\"check\"\r\n className=\"size-9\"\r\n >\r\n <rect\r\n x=\"80\"\r\n y=\"128\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 80 128)\"\r\n ></rect>\r\n <rect\r\n x=\"96\"\r\n y=\"144\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 96 144)\"\r\n ></rect>\r\n <rect\r\n x=\"112\"\r\n y=\"160\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 112 160)\"\r\n ></rect>\r\n <rect\r\n x=\"128\"\r\n y=\"144\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 128 144)\"\r\n ></rect>\r\n <rect\r\n x=\"144\"\r\n y=\"128\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 144 128)\"\r\n ></rect>\r\n <rect\r\n x=\"160\"\r\n y=\"112\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 160 112)\"\r\n ></rect>\r\n <rect\r\n x=\"176\"\r\n y=\"96\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 176 96)\"\r\n ></rect>\r\n <rect\r\n x=\"192\"\r\n y=\"80\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 192 80)\"\r\n ></rect>\r\n </svg>\r\n </ContextMenuPrimitive.ItemIndicator>\r\n </span>\r\n {children}\r\n </ContextMenuPrimitive.CheckboxItem>\r\n));\r\nContextMenuCheckboxItem.displayName =\r\n ContextMenuPrimitive.CheckboxItem.displayName;\r\n\r\nconst ContextMenuRadioItem = React.forwardRef<\r\n React.ComponentRef<typeof ContextMenuPrimitive.RadioItem>,\r\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>\r\n>(({ className, children, ...props }, ref) => (\r\n <ContextMenuPrimitive.RadioItem\r\n ref={ref}\r\n className={cn(\r\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:border-y-4 focus:border-foreground h-8 focus:dark:border-ring border-dashed focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\r\n <ContextMenuPrimitive.ItemIndicator>\r\n <Circle className=\"size-2 fill-current\" />\r\n </ContextMenuPrimitive.ItemIndicator>\r\n </span>\r\n {children}\r\n </ContextMenuPrimitive.RadioItem>\r\n));\r\nContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;\r\n\r\nconst ContextMenuLabel = React.forwardRef<\r\n React.ComponentRef<typeof ContextMenuPrimitive.Label>,\r\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & {\r\n inset?: boolean;\r\n }\r\n>(({ className, inset, ...props }, ref) => (\r\n <ContextMenuPrimitive.Label\r\n ref={ref}\r\n className={cn(\r\n \"px-2 py-1.5 text-sm font-semibold text-foreground\",\r\n inset && \"pl-8\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n));\r\nContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;\r\n\r\nconst ContextMenuSeparator = React.forwardRef<\r\n React.ComponentRef<typeof ContextMenuPrimitive.Separator>,\r\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>\r\n>(({ className, ...props }, ref) => (\r\n <ContextMenuPrimitive.Separator\r\n ref={ref}\r\n className={cn(\"-mx-1 my-1 h-px bg-border\", className)}\r\n {...props}\r\n />\r\n));\r\nContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;\r\n\r\nconst ContextMenuShortcut = ({\r\n className,\r\n ...props\r\n}: React.HTMLAttributes<HTMLSpanElement>) => {\r\n return (\r\n <span\r\n className={cn(\r\n \"ml-auto text-xs tracking-widest text-muted-foreground\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n );\r\n};\r\nContextMenuShortcut.displayName = \"ContextMenuShortcut\";\r\n\r\nexport {\r\n ContextMenu,\r\n ContextMenuTrigger,\r\n ContextMenuContent,\r\n ContextMenuItem,\r\n ContextMenuCheckboxItem,\r\n ContextMenuRadioItem,\r\n ContextMenuLabel,\r\n ContextMenuSeparator,\r\n ContextMenuShortcut,\r\n ContextMenuGroup,\r\n ContextMenuPortal,\r\n ContextMenuSub,\r\n ContextMenuSubContent,\r\n ContextMenuSubTrigger,\r\n ContextMenuRadioGroup,\r\n};\r\n", | |
const ContextMenuSubTrigger = React.forwardRef< | |
React.ComponentRef<typeof ContextMenuPrimitive.SubTrigger>, | |
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & { | |
inset?: boolean; | |
} | |
>(({ className, inset, children, ...props }, ref) => ( | |
<ContextMenuPrimitive.SubTrigger | |
ref={ref} | |
className={cn( | |
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:border-y-4 focus:border-foreground h-8 focus:dark:border-ring border-dashed focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground", | |
inset && "pl-8", | |
className | |
)} | |
{...props} | |
> | |
{children} | |
<span className="ml-auto"> | |
<ChevronRightIcon aria-hidden="true" /> | |
</span> | |
</ContextMenuPrimitive.SubTrigger> | |
)); | |
ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName; |
🤖 Prompt for AI Agents
In public/r/8bit-context-menu.json around line 11, ContextMenuSubTrigger
currently renders <ChevronRightIcon/> without alignment classes or accessibility
attributes; restore the previous right alignment and mark the icon as decorative
by passing a className (e.g. "ml-auto size-4 shrink-0 opacity-70") to push it to
the far right and set it as aria-hidden. If ChevronRightIcon doesn't accept
className/props, update that icon component to accept and apply a className prop
and support aria-hidden so you can pass both className and aria-hidden="true"
from ContextMenuSubTrigger.
{ | ||
"path": "components/ui/8bit/menubar.tsx", | ||
"content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport * as MenubarPrimitive from \"@radix-ui/react-menubar\";\nimport { cva } from \"class-variance-authority\";\nimport { Circle } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\nimport \"./styles/retro.css\";\n\nexport const menubarVariants = cva(\"\", {\n variants: {\n font: {\n normal: \"\",\n retro: \"retro\",\n },\n },\n defaultVariants: {\n font: \"retro\",\n },\n});\n\nfunction MenubarMenu({\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Menu>) {\n return <MenubarPrimitive.Menu {...props} />;\n}\n\nfunction MenubarGroup({\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Group>) {\n return <MenubarPrimitive.Group {...props} />;\n}\n\nfunction MenubarPortal({\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Portal>) {\n return <MenubarPrimitive.Portal {...props} />;\n}\n\nfunction MenubarRadioGroup({\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) {\n return <MenubarPrimitive.RadioGroup {...props} />;\n}\n\nfunction MenubarSub({\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Sub>) {\n return <MenubarPrimitive.Sub data-slot=\"menubar-sub\" {...props} />;\n}\n\nconst Menubar = React.forwardRef<\n React.ComponentRef<typeof MenubarPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Root>\n>(({ className, ...props }, ref) => (\n <div\n className={cn(\n \"relative border-y-6 border-foreground dark:border-ring !p-0\",\n menubarVariants({ font: \"retro\" }),\n className\n )}\n >\n <MenubarPrimitive.Root\n ref={ref}\n className={cn(\n \"flex h-10 items-center space-x-1 rounded-md border bg-background p-1\",\n className\n )}\n {...props}\n />\n <div\n className=\"absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none\"\n aria-hidden=\"true\"\n />\n </div>\n));\nMenubar.displayName = MenubarPrimitive.Root.displayName;\n\nconst MenubarTrigger = React.forwardRef<\n React.ComponentRef<typeof MenubarPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Trigger>\n>(({ className, ...props }, ref) => (\n <MenubarPrimitive.Trigger\n ref={ref}\n className={cn(\n \"flex cursor-default select-none items-center rounded-sm px-3 py-1.5 text-sm font-medium outline-none focus:border-y-4 focus:border-foreground focus:dark:border-ring focus:border-dashed focus:text-accent-foreground data-[state=open]:border-b-4 data-[state=open]:border-foreground data-[state=open]:dark:border-ring data-[state=open]:text-accent-foreground data-[state=open]:border-dashed border-b-4 border-transparent pt-2\",\n className\n )}\n {...props}\n />\n));\nMenubarTrigger.displayName = MenubarPrimitive.Trigger.displayName;\n\nconst MenubarSubTrigger = React.forwardRef<\n React.ComponentRef<typeof MenubarPrimitive.SubTrigger>,\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.SubTrigger> & {\n inset?: boolean;\n }\n>(({ className, inset, children, ...props }, ref) => (\n <MenubarPrimitive.SubTrigger\n ref={ref}\n className={cn(\n \"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none h-10 focus:border-y-4 focus:border-foreground focus:dark:border-ring focus:border-dashed focus:text-accent-foreground data-[state=open]:border-y-4 data-[state=open]:border-foreground data-[state=open]:dark:border-ring data-[state=open]:text-accent-foreground data-[state=open]:border-dashed\",\n inset && \"pl-8\",\n className\n )}\n {...props}\n >\n {children}\n <svg\n width=\"50\"\n height=\"50\"\n viewBox=\"0 0 256 256\"\n fill=\"currentColor\"\n xmlns=\"http://www.w3.org/2000/svg\"\n stroke=\"currentColor\"\n strokeWidth=\"0.25\"\n aria-label=\"chevron-right\"\n className=\"size-7 ml-auto\"\n >\n <rect x=\"128\" y=\"136\" width=\"14\" height=\"14\" rx=\"1\"></rect>\n <rect x=\"112\" y=\"152\" width=\"14\" height=\"14\" rx=\"1\"></rect>\n <rect x=\"96\" y=\"72\" width=\"14\" height=\"14\" rx=\"1\"></rect>\n <rect x=\"96\" y=\"168\" width=\"14\" height=\"14\" rx=\"1\"></rect>\n <rect x=\"144\" y=\"120\" width=\"14\" height=\"14\" rx=\"1\"></rect>\n <rect x=\"128\" y=\"104\" width=\"14\" height=\"14\" rx=\"1\"></rect>\n <rect x=\"112\" y=\"88\" width=\"14\" height=\"14\" rx=\"1\"></rect>\n </svg>\n </MenubarPrimitive.SubTrigger>\n));\nMenubarSubTrigger.displayName = MenubarPrimitive.SubTrigger.displayName;\n\nconst MenubarSubContent = React.forwardRef<\n React.ComponentRef<typeof MenubarPrimitive.SubContent>,\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.SubContent>\n>(({ className, ...props }, ref) => (\n <MenubarPrimitive.SubContent\n ref={ref}\n className={cn(\n \"z-50 min-w-[8rem] overflow-hidden rounded-md border-6 border-foreground dark:border-ring bg-popover p-1 text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-menubar-content-transform-origin]\",\n className\n )}\n {...props}\n />\n));\nMenubarSubContent.displayName = MenubarPrimitive.SubContent.displayName;\n\nconst MenubarContent = React.forwardRef<\n React.ComponentRef<typeof MenubarPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Content>\n>(\n (\n { className, align = \"start\", alignOffset = -4, sideOffset = 8, ...props },\n ref\n ) => (\n <MenubarPrimitive.Portal>\n <MenubarPrimitive.Content\n ref={ref}\n align={align}\n alignOffset={alignOffset}\n sideOffset={sideOffset}\n className={cn(\n \"z-50 min-w-[12rem] overflow-hidden rounded-md border-6 mt-1 border-foreground dark:border-ring bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-menubar-content-transform-origin]\",\n menubarVariants({ font: \"retro\" }),\n className\n )}\n {...props}\n />\n </MenubarPrimitive.Portal>\n )\n);\nMenubarContent.displayName = MenubarPrimitive.Content.displayName;\n\nconst MenubarItem = React.forwardRef<\n React.ComponentRef<typeof MenubarPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Item> & {\n inset?: boolean;\n }\n>(({ className, inset, ...props }, ref) => (\n <MenubarPrimitive.Item\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:border-y-4 focus:border-foreground focus:dark:border-ring h-9 focus:border-dashed focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n inset && \"pl-8\",\n className\n )}\n {...props}\n />\n));\nMenubarItem.displayName = MenubarPrimitive.Item.displayName;\n\nconst MenubarCheckboxItem = React.forwardRef<\n React.ComponentRef<typeof MenubarPrimitive.CheckboxItem>,\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <MenubarPrimitive.CheckboxItem\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none h-9 focus:border-y-4 focus:border-foreground focus:dark:border-ring focus:border-dashed focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className\n )}\n checked={checked}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <MenubarPrimitive.ItemIndicator>\n <svg\n width=\"50\"\n height=\"50\"\n viewBox=\"0 0 256 256\"\n fill=\"currentColor\"\n xmlns=\"http://www.w3.org/2000/svg\"\n stroke=\"currentColor\"\n strokeWidth=\"0.25\"\n aria-label=\"check\"\n className=\"size-7\"\n >\n <rect\n x=\"80\"\n y=\"128\"\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"rotate(90 80 128)\"\n ></rect>\n <rect\n x=\"96\"\n y=\"144\"\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"rotate(90 96 144)\"\n ></rect>\n <rect\n x=\"112\"\n y=\"160\"\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"rotate(90 112 160)\"\n ></rect>\n <rect\n x=\"128\"\n y=\"144\"\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"rotate(90 128 144)\"\n ></rect>\n <rect\n x=\"144\"\n y=\"128\"\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"rotate(90 144 128)\"\n ></rect>\n <rect\n x=\"160\"\n y=\"112\"\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"rotate(90 160 112)\"\n ></rect>\n <rect\n x=\"176\"\n y=\"96\"\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"rotate(90 176 96)\"\n ></rect>\n <rect\n x=\"192\"\n y=\"80\"\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"rotate(90 192 80)\"\n ></rect>\n </svg>\n </MenubarPrimitive.ItemIndicator>\n </span>\n {children}\n </MenubarPrimitive.CheckboxItem>\n));\nMenubarCheckboxItem.displayName = MenubarPrimitive.CheckboxItem.displayName;\n\nconst MenubarRadioItem = React.forwardRef<\n React.ComponentRef<typeof MenubarPrimitive.RadioItem>,\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n <MenubarPrimitive.RadioItem\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 h-9 pl-8 pr-2 text-sm outline-none focus:border-y-4 focus:border-foreground focus:dark:border-ring focus:border-dashed focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <MenubarPrimitive.ItemIndicator>\n <Circle className=\"h-2 w-2 fill-current\" />\n </MenubarPrimitive.ItemIndicator>\n </span>\n {children}\n </MenubarPrimitive.RadioItem>\n));\nMenubarRadioItem.displayName = MenubarPrimitive.RadioItem.displayName;\n\nconst MenubarLabel = React.forwardRef<\n React.ComponentRef<typeof MenubarPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Label> & {\n inset?: boolean;\n }\n>(({ className, inset, ...props }, ref) => (\n <MenubarPrimitive.Label\n ref={ref}\n className={cn(\n \"px-2 py-1.5 text-sm font-semibold\",\n inset && \"pl-8\",\n className\n )}\n {...props}\n />\n));\nMenubarLabel.displayName = MenubarPrimitive.Label.displayName;\n\nconst MenubarSeparator = React.forwardRef<\n React.ComponentRef<typeof MenubarPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <MenubarPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-1 my-1 h-px bg-muted\", className)}\n {...props}\n />\n));\nMenubarSeparator.displayName = MenubarPrimitive.Separator.displayName;\n\nconst MenubarShortcut = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLSpanElement>) => {\n return (\n <span\n className={cn(\n \"ml-auto text-xs tracking-widest text-muted-foreground\",\n className\n )}\n {...props}\n />\n );\n};\nMenubarShortcut.displayname = \"MenubarShortcut\";\n\nexport {\n Menubar,\n MenubarMenu,\n MenubarTrigger,\n MenubarContent,\n MenubarItem,\n MenubarSeparator,\n MenubarLabel,\n MenubarCheckboxItem,\n MenubarRadioGroup,\n MenubarRadioItem,\n MenubarPortal,\n MenubarSubContent,\n MenubarSubTrigger,\n MenubarGroup,\n MenubarSub,\n MenubarShortcut,\n};\n", | ||
"content": "\"use client\";\r\n\r\nimport * as React from \"react\";\r\n\r\nimport * as MenubarPrimitive from \"@radix-ui/react-menubar\";\r\nimport { cva } from \"class-variance-authority\";\r\nimport { Circle } from \"lucide-react\";\r\n\r\nimport { ChevronRightIcon } from \"@/components/ui/8bit/assets/chevronRightIcon\";\r\n\r\nimport { cn } from \"@/lib/utils\";\r\nimport \"./styles/retro.css\";\r\n\r\nexport const menubarVariants = cva(\"\", {\r\n variants: {\r\n font: {\r\n normal: \"\",\r\n retro: \"retro\",\r\n },\r\n },\r\n defaultVariants: {\r\n font: \"retro\",\r\n },\r\n});\r\n\r\nfunction MenubarMenu({\r\n ...props\r\n}: React.ComponentProps<typeof MenubarPrimitive.Menu>) {\r\n return <MenubarPrimitive.Menu {...props} />;\r\n}\r\n\r\nfunction MenubarGroup({\r\n ...props\r\n}: React.ComponentProps<typeof MenubarPrimitive.Group>) {\r\n return <MenubarPrimitive.Group {...props} />;\r\n}\r\n\r\nfunction MenubarPortal({\r\n ...props\r\n}: React.ComponentProps<typeof MenubarPrimitive.Portal>) {\r\n return <MenubarPrimitive.Portal {...props} />;\r\n}\r\n\r\nfunction MenubarRadioGroup({\r\n ...props\r\n}: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) {\r\n return <MenubarPrimitive.RadioGroup {...props} />;\r\n}\r\n\r\nfunction MenubarSub({\r\n ...props\r\n}: React.ComponentProps<typeof MenubarPrimitive.Sub>) {\r\n return <MenubarPrimitive.Sub data-slot=\"menubar-sub\" {...props} />;\r\n}\r\n\r\nconst Menubar = React.forwardRef<\r\n React.ComponentRef<typeof MenubarPrimitive.Root>,\r\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Root>\r\n>(({ className, ...props }, ref) => (\r\n <div\r\n className={cn(\r\n \"relative border-y-6 border-foreground dark:border-ring !p-0\",\r\n menubarVariants({ font: \"retro\" }),\r\n className\r\n )}\r\n >\r\n <MenubarPrimitive.Root\r\n ref={ref}\r\n className={cn(\r\n \"flex h-10 items-center space-x-1 rounded-md border bg-background p-1\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n <div\r\n className=\"absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n </div>\r\n));\r\nMenubar.displayName = MenubarPrimitive.Root.displayName;\r\n\r\nconst MenubarTrigger = React.forwardRef<\r\n React.ComponentRef<typeof MenubarPrimitive.Trigger>,\r\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Trigger>\r\n>(({ className, ...props }, ref) => (\r\n <MenubarPrimitive.Trigger\r\n ref={ref}\r\n className={cn(\r\n \"flex cursor-default select-none items-center rounded-sm px-3 py-1.5 text-sm font-medium outline-none focus:border-y-4 focus:border-foreground focus:dark:border-ring focus:border-dashed focus:text-accent-foreground data-[state=open]:border-b-4 data-[state=open]:border-foreground data-[state=open]:dark:border-ring data-[state=open]:text-accent-foreground data-[state=open]:border-dashed border-b-4 border-transparent pt-2\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n));\r\nMenubarTrigger.displayName = MenubarPrimitive.Trigger.displayName;\r\n\r\nconst MenubarSubTrigger = React.forwardRef<\r\n React.ComponentRef<typeof MenubarPrimitive.SubTrigger>,\r\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.SubTrigger> & {\r\n inset?: boolean;\r\n }\r\n>(({ className, inset, children, ...props }, ref) => (\r\n <MenubarPrimitive.SubTrigger\r\n ref={ref}\r\n className={cn(\r\n \"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none h-10 focus:border-y-4 focus:border-foreground focus:dark:border-ring focus:border-dashed focus:text-accent-foreground data-[state=open]:border-y-4 data-[state=open]:border-foreground data-[state=open]:dark:border-ring data-[state=open]:text-accent-foreground data-[state=open]:border-dashed\",\r\n inset && \"pl-8\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n {children}\r\n <ChevronRightIcon/>\r\n </MenubarPrimitive.SubTrigger>\r\n));\r\nMenubarSubTrigger.displayName = MenubarPrimitive.SubTrigger.displayName;\r\n\r\nconst MenubarSubContent = React.forwardRef<\r\n React.ComponentRef<typeof MenubarPrimitive.SubContent>,\r\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.SubContent>\r\n>(({ className, ...props }, ref) => (\r\n <MenubarPrimitive.SubContent\r\n ref={ref}\r\n className={cn(\r\n \"z-50 min-w-[8rem] overflow-hidden rounded-md border-6 border-foreground dark:border-ring bg-popover p-1 text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-menubar-content-transform-origin]\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n));\r\nMenubarSubContent.displayName = MenubarPrimitive.SubContent.displayName;\r\n\r\nconst MenubarContent = React.forwardRef<\r\n React.ComponentRef<typeof MenubarPrimitive.Content>,\r\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Content>\r\n>(\r\n (\r\n { className, align = \"start\", alignOffset = -4, sideOffset = 8, ...props },\r\n ref\r\n ) => (\r\n <MenubarPrimitive.Portal>\r\n <MenubarPrimitive.Content\r\n ref={ref}\r\n align={align}\r\n alignOffset={alignOffset}\r\n sideOffset={sideOffset}\r\n className={cn(\r\n \"z-50 min-w-[12rem] overflow-hidden rounded-md border-6 mt-1 border-foreground dark:border-ring bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-menubar-content-transform-origin]\",\r\n menubarVariants({ font: \"retro\" }),\r\n className\r\n )}\r\n {...props}\r\n />\r\n </MenubarPrimitive.Portal>\r\n )\r\n);\r\nMenubarContent.displayName = MenubarPrimitive.Content.displayName;\r\n\r\nconst MenubarItem = React.forwardRef<\r\n React.ComponentRef<typeof MenubarPrimitive.Item>,\r\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Item> & {\r\n inset?: boolean;\r\n }\r\n>(({ className, inset, ...props }, ref) => (\r\n <MenubarPrimitive.Item\r\n ref={ref}\r\n className={cn(\r\n \"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:border-y-4 focus:border-foreground focus:dark:border-ring h-9 focus:border-dashed focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\r\n inset && \"pl-8\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n));\r\nMenubarItem.displayName = MenubarPrimitive.Item.displayName;\r\n\r\nconst MenubarCheckboxItem = React.forwardRef<\r\n React.ComponentRef<typeof MenubarPrimitive.CheckboxItem>,\r\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.CheckboxItem>\r\n>(({ className, children, checked, ...props }, ref) => (\r\n <MenubarPrimitive.CheckboxItem\r\n ref={ref}\r\n className={cn(\r\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none h-9 focus:border-y-4 focus:border-foreground focus:dark:border-ring focus:border-dashed focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\r\n className\r\n )}\r\n checked={checked}\r\n {...props}\r\n >\r\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\r\n <MenubarPrimitive.ItemIndicator>\r\n <svg\r\n width=\"50\"\r\n height=\"50\"\r\n viewBox=\"0 0 256 256\"\r\n fill=\"currentColor\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"0.25\"\r\n aria-label=\"check\"\r\n className=\"size-7\"\r\n >\r\n <rect\r\n x=\"80\"\r\n y=\"128\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 80 128)\"\r\n ></rect>\r\n <rect\r\n x=\"96\"\r\n y=\"144\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 96 144)\"\r\n ></rect>\r\n <rect\r\n x=\"112\"\r\n y=\"160\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 112 160)\"\r\n ></rect>\r\n <rect\r\n x=\"128\"\r\n y=\"144\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 128 144)\"\r\n ></rect>\r\n <rect\r\n x=\"144\"\r\n y=\"128\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 144 128)\"\r\n ></rect>\r\n <rect\r\n x=\"160\"\r\n y=\"112\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 160 112)\"\r\n ></rect>\r\n <rect\r\n x=\"176\"\r\n y=\"96\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 176 96)\"\r\n ></rect>\r\n <rect\r\n x=\"192\"\r\n y=\"80\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 192 80)\"\r\n ></rect>\r\n </svg>\r\n </MenubarPrimitive.ItemIndicator>\r\n </span>\r\n {children}\r\n </MenubarPrimitive.CheckboxItem>\r\n));\r\nMenubarCheckboxItem.displayName = MenubarPrimitive.CheckboxItem.displayName;\r\n\r\nconst MenubarRadioItem = React.forwardRef<\r\n React.ComponentRef<typeof MenubarPrimitive.RadioItem>,\r\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.RadioItem>\r\n>(({ className, children, ...props }, ref) => (\r\n <MenubarPrimitive.RadioItem\r\n ref={ref}\r\n className={cn(\r\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 h-9 pl-8 pr-2 text-sm outline-none focus:border-y-4 focus:border-foreground focus:dark:border-ring focus:border-dashed focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\r\n <MenubarPrimitive.ItemIndicator>\r\n <Circle className=\"h-2 w-2 fill-current\" />\r\n </MenubarPrimitive.ItemIndicator>\r\n </span>\r\n {children}\r\n </MenubarPrimitive.RadioItem>\r\n));\r\nMenubarRadioItem.displayName = MenubarPrimitive.RadioItem.displayName;\r\n\r\nconst MenubarLabel = React.forwardRef<\r\n React.ComponentRef<typeof MenubarPrimitive.Label>,\r\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Label> & {\r\n inset?: boolean;\r\n }\r\n>(({ className, inset, ...props }, ref) => (\r\n <MenubarPrimitive.Label\r\n ref={ref}\r\n className={cn(\r\n \"px-2 py-1.5 text-sm font-semibold\",\r\n inset && \"pl-8\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n));\r\nMenubarLabel.displayName = MenubarPrimitive.Label.displayName;\r\n\r\nconst MenubarSeparator = React.forwardRef<\r\n React.ComponentRef<typeof MenubarPrimitive.Separator>,\r\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Separator>\r\n>(({ className, ...props }, ref) => (\r\n <MenubarPrimitive.Separator\r\n ref={ref}\r\n className={cn(\"-mx-1 my-1 h-px bg-muted\", className)}\r\n {...props}\r\n />\r\n));\r\nMenubarSeparator.displayName = MenubarPrimitive.Separator.displayName;\r\n\r\nconst MenubarShortcut = ({\r\n className,\r\n ...props\r\n}: React.HTMLAttributes<HTMLSpanElement>) => {\r\n return (\r\n <span\r\n className={cn(\r\n \"ml-auto text-xs tracking-widest text-muted-foreground\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n );\r\n};\r\nMenubarShortcut.displayname = \"MenubarShortcut\";\r\n\r\nexport {\r\n Menubar,\r\n MenubarMenu,\r\n MenubarTrigger,\r\n MenubarContent,\r\n MenubarItem,\r\n MenubarSeparator,\r\n MenubarLabel,\r\n MenubarCheckboxItem,\r\n MenubarRadioGroup,\r\n MenubarRadioItem,\r\n MenubarPortal,\r\n MenubarSubContent,\r\n MenubarSubTrigger,\r\n MenubarGroup,\r\n MenubarSub,\r\n MenubarShortcut,\r\n};\r\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Chevron in MenubarSubTrigger needs right alignment and a11y; fix like ContextMenu.
Same issue as in the context menu: removing ml-auto
will change alignment. Also make the icon decorative.
- {children}
- <ChevronRightIcon/>
+ {children}
+ <span className="ml-auto">
+ <ChevronRightIcon aria-hidden="true" />
+ </span>
If you updated the icon to accept className
, you can instead do:
- <ChevronRightIcon/>
+ <ChevronRightIcon className="ml-auto size-4 shrink-0 opacity-70" aria-hidden="true" />
📝 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.
"content": "\"use client\";\r\n\r\nimport * as React from \"react\";\r\n\r\nimport * as MenubarPrimitive from \"@radix-ui/react-menubar\";\r\nimport { cva } from \"class-variance-authority\";\r\nimport { Circle } from \"lucide-react\";\r\n\r\nimport { ChevronRightIcon } from \"@/components/ui/8bit/assets/chevronRightIcon\";\r\n\r\nimport { cn } from \"@/lib/utils\";\r\nimport \"./styles/retro.css\";\r\n\r\nexport const menubarVariants = cva(\"\", {\r\n variants: {\r\n font: {\r\n normal: \"\",\r\n retro: \"retro\",\r\n },\r\n },\r\n defaultVariants: {\r\n font: \"retro\",\r\n },\r\n});\r\n\r\nfunction MenubarMenu({\r\n ...props\r\n}: React.ComponentProps<typeof MenubarPrimitive.Menu>) {\r\n return <MenubarPrimitive.Menu {...props} />;\r\n}\r\n\r\nfunction MenubarGroup({\r\n ...props\r\n}: React.ComponentProps<typeof MenubarPrimitive.Group>) {\r\n return <MenubarPrimitive.Group {...props} />;\r\n}\r\n\r\nfunction MenubarPortal({\r\n ...props\r\n}: React.ComponentProps<typeof MenubarPrimitive.Portal>) {\r\n return <MenubarPrimitive.Portal {...props} />;\r\n}\r\n\r\nfunction MenubarRadioGroup({\r\n ...props\r\n}: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) {\r\n return <MenubarPrimitive.RadioGroup {...props} />;\r\n}\r\n\r\nfunction MenubarSub({\r\n ...props\r\n}: React.ComponentProps<typeof MenubarPrimitive.Sub>) {\r\n return <MenubarPrimitive.Sub data-slot=\"menubar-sub\" {...props} />;\r\n}\r\n\r\nconst Menubar = React.forwardRef<\r\n React.ComponentRef<typeof MenubarPrimitive.Root>,\r\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Root>\r\n>(({ className, ...props }, ref) => (\r\n <div\r\n className={cn(\r\n \"relative border-y-6 border-foreground dark:border-ring !p-0\",\r\n menubarVariants({ font: \"retro\" }),\r\n className\r\n )}\r\n >\r\n <MenubarPrimitive.Root\r\n ref={ref}\r\n className={cn(\r\n \"flex h-10 items-center space-x-1 rounded-md border bg-background p-1\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n <div\r\n className=\"absolute inset-0 border-x-6 -mx-1.5 border-foreground dark:border-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n </div>\r\n));\r\nMenubar.displayName = MenubarPrimitive.Root.displayName;\r\n\r\nconst MenubarTrigger = React.forwardRef<\r\n React.ComponentRef<typeof MenubarPrimitive.Trigger>,\r\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Trigger>\r\n>(({ className, ...props }, ref) => (\r\n <MenubarPrimitive.Trigger\r\n ref={ref}\r\n className={cn(\r\n \"flex cursor-default select-none items-center rounded-sm px-3 py-1.5 text-sm font-medium outline-none focus:border-y-4 focus:border-foreground focus:dark:border-ring focus:border-dashed focus:text-accent-foreground data-[state=open]:border-b-4 data-[state=open]:border-foreground data-[state=open]:dark:border-ring data-[state=open]:text-accent-foreground data-[state=open]:border-dashed border-b-4 border-transparent pt-2\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n));\r\nMenubarTrigger.displayName = MenubarPrimitive.Trigger.displayName;\r\n\r\nconst MenubarSubTrigger = React.forwardRef<\r\n React.ComponentRef<typeof MenubarPrimitive.SubTrigger>,\r\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.SubTrigger> & {\r\n inset?: boolean;\r\n }\r\n>(({ className, inset, children, ...props }, ref) => (\r\n <MenubarPrimitive.SubTrigger\r\n ref={ref}\r\n className={cn(\r\n \"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none h-10 focus:border-y-4 focus:border-foreground focus:dark:border-ring focus:border-dashed focus:text-accent-foreground data-[state=open]:border-y-4 data-[state=open]:border-foreground data-[state=open]:dark:border-ring data-[state=open]:text-accent-foreground data-[state=open]:border-dashed\",\r\n inset && \"pl-8\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n {children}\r\n <ChevronRightIcon/>\r\n </MenubarPrimitive.SubTrigger>\r\n));\r\nMenubarSubTrigger.displayName = MenubarPrimitive.SubTrigger.displayName;\r\n\r\nconst MenubarSubContent = React.forwardRef<\r\n React.ComponentRef<typeof MenubarPrimitive.SubContent>,\r\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.SubContent>\r\n>(({ className, ...props }, ref) => (\r\n <MenubarPrimitive.SubContent\r\n ref={ref}\r\n className={cn(\r\n \"z-50 min-w-[8rem] overflow-hidden rounded-md border-6 border-foreground dark:border-ring bg-popover p-1 text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-menubar-content-transform-origin]\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n));\r\nMenubarSubContent.displayName = MenubarPrimitive.SubContent.displayName;\r\n\r\nconst MenubarContent = React.forwardRef<\r\n React.ComponentRef<typeof MenubarPrimitive.Content>,\r\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Content>\r\n>(\r\n (\r\n { className, align = \"start\", alignOffset = -4, sideOffset = 8, ...props },\r\n ref\r\n ) => (\r\n <MenubarPrimitive.Portal>\r\n <MenubarPrimitive.Content\r\n ref={ref}\r\n align={align}\r\n alignOffset={alignOffset}\r\n sideOffset={sideOffset}\r\n className={cn(\r\n \"z-50 min-w-[12rem] overflow-hidden rounded-md border-6 mt-1 border-foreground dark:border-ring bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-menubar-content-transform-origin]\",\r\n menubarVariants({ font: \"retro\" }),\r\n className\r\n )}\r\n {...props}\r\n />\r\n </MenubarPrimitive.Portal>\r\n )\r\n);\r\nMenubarContent.displayName = MenubarPrimitive.Content.displayName;\r\n\r\nconst MenubarItem = React.forwardRef<\r\n React.ComponentRef<typeof MenubarPrimitive.Item>,\r\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Item> & {\r\n inset?: boolean;\r\n }\r\n>(({ className, inset, ...props }, ref) => (\r\n <MenubarPrimitive.Item\r\n ref={ref}\r\n className={cn(\r\n \"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:border-y-4 focus:border-foreground focus:dark:border-ring h-9 focus:border-dashed focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\r\n inset && \"pl-8\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n));\r\nMenubarItem.displayName = MenubarPrimitive.Item.displayName;\r\n\r\nconst MenubarCheckboxItem = React.forwardRef<\r\n React.ComponentRef<typeof MenubarPrimitive.CheckboxItem>,\r\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.CheckboxItem>\r\n>(({ className, children, checked, ...props }, ref) => (\r\n <MenubarPrimitive.CheckboxItem\r\n ref={ref}\r\n className={cn(\r\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none h-9 focus:border-y-4 focus:border-foreground focus:dark:border-ring focus:border-dashed focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\r\n className\r\n )}\r\n checked={checked}\r\n {...props}\r\n >\r\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\r\n <MenubarPrimitive.ItemIndicator>\r\n <svg\r\n width=\"50\"\r\n height=\"50\"\r\n viewBox=\"0 0 256 256\"\r\n fill=\"currentColor\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"0.25\"\r\n aria-label=\"check\"\r\n className=\"size-7\"\r\n >\r\n <rect\r\n x=\"80\"\r\n y=\"128\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 80 128)\"\r\n ></rect>\r\n <rect\r\n x=\"96\"\r\n y=\"144\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 96 144)\"\r\n ></rect>\r\n <rect\r\n x=\"112\"\r\n y=\"160\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 112 160)\"\r\n ></rect>\r\n <rect\r\n x=\"128\"\r\n y=\"144\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 128 144)\"\r\n ></rect>\r\n <rect\r\n x=\"144\"\r\n y=\"128\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 144 128)\"\r\n ></rect>\r\n <rect\r\n x=\"160\"\r\n y=\"112\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 160 112)\"\r\n ></rect>\r\n <rect\r\n x=\"176\"\r\n y=\"96\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 176 96)\"\r\n ></rect>\r\n <rect\r\n x=\"192\"\r\n y=\"80\"\r\n width=\"14\"\r\n height=\"14\"\r\n rx=\"1\"\r\n transform=\"rotate(90 192 80)\"\r\n ></rect>\r\n </svg>\r\n </MenubarPrimitive.ItemIndicator>\r\n </span>\r\n {children}\r\n </MenubarPrimitive.CheckboxItem>\r\n));\r\nMenubarCheckboxItem.displayName = MenubarPrimitive.CheckboxItem.displayName;\r\n\r\nconst MenubarRadioItem = React.forwardRef<\r\n React.ComponentRef<typeof MenubarPrimitive.RadioItem>,\r\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.RadioItem>\r\n>(({ className, children, ...props }, ref) => (\r\n <MenubarPrimitive.RadioItem\r\n ref={ref}\r\n className={cn(\r\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 h-9 pl-8 pr-2 text-sm outline-none focus:border-y-4 focus:border-foreground focus:dark:border-ring focus:border-dashed focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\r\n <MenubarPrimitive.ItemIndicator>\r\n <Circle className=\"h-2 w-2 fill-current\" />\r\n </MenubarPrimitive.ItemIndicator>\r\n </span>\r\n {children}\r\n </MenubarPrimitive.RadioItem>\r\n));\r\nMenubarRadioItem.displayName = MenubarPrimitive.RadioItem.displayName;\r\n\r\nconst MenubarLabel = React.forwardRef<\r\n React.ComponentRef<typeof MenubarPrimitive.Label>,\r\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Label> & {\r\n inset?: boolean;\r\n }\r\n>(({ className, inset, ...props }, ref) => (\r\n <MenubarPrimitive.Label\r\n ref={ref}\r\n className={cn(\r\n \"px-2 py-1.5 text-sm font-semibold\",\r\n inset && \"pl-8\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n));\r\nMenubarLabel.displayName = MenubarPrimitive.Label.displayName;\r\n\r\nconst MenubarSeparator = React.forwardRef<\r\n React.ComponentRef<typeof MenubarPrimitive.Separator>,\r\n React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Separator>\r\n>(({ className, ...props }, ref) => (\r\n <MenubarPrimitive.Separator\r\n ref={ref}\r\n className={cn(\"-mx-1 my-1 h-px bg-muted\", className)}\r\n {...props}\r\n />\r\n));\r\nMenubarSeparator.displayName = MenubarPrimitive.Separator.displayName;\r\n\r\nconst MenubarShortcut = ({\r\n className,\r\n ...props\r\n}: React.HTMLAttributes<HTMLSpanElement>) => {\r\n return (\r\n <span\r\n className={cn(\r\n \"ml-auto text-xs tracking-widest text-muted-foreground\",\r\n className\r\n )}\r\n {...props}\r\n />\r\n );\r\n};\r\nMenubarShortcut.displayname = \"MenubarShortcut\";\r\n\r\nexport {\r\n Menubar,\r\n MenubarMenu,\r\n MenubarTrigger,\r\n MenubarContent,\r\n MenubarItem,\r\n MenubarSeparator,\r\n MenubarLabel,\r\n MenubarCheckboxItem,\r\n MenubarRadioGroup,\r\n MenubarRadioItem,\r\n MenubarPortal,\r\n MenubarSubContent,\r\n MenubarSubTrigger,\r\n MenubarGroup,\r\n MenubarSub,\r\n MenubarShortcut,\r\n};\r\n", | |
const MenubarSubTrigger = React.forwardRef< | |
React.ComponentRef<typeof MenubarPrimitive.SubTrigger>, | |
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.SubTrigger> & { | |
inset?: boolean; | |
} | |
>(({ className, inset, children, ...props }, ref) => ( | |
<MenubarPrimitive.SubTrigger | |
ref={ref} | |
className={cn( | |
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none h-10 focus:border-y-4 focus:border-foreground focus:dark:border-ring focus:border-dashed focus:text-accent-foreground data-[state=open]:border-y-4 data-[state=open]:border-foreground data-[state=open]:dark:border-ring data-[state=open]:text-accent-foreground data-[state=open]:border-dashed", | |
inset && "pl-8", | |
className | |
)} | |
{...props} | |
> | |
{children} | |
<span className="ml-auto"> | |
<ChevronRightIcon aria-hidden="true" /> | |
</span> | |
</MenubarPrimitive.SubTrigger> | |
)); | |
MenubarSubTrigger.displayName = MenubarPrimitive.SubTrigger.displayName; |
🤖 Prompt for AI Agents
public/r/8bit-menubar.json around line 11: the ChevronRightIcon in
MenubarSubTrigger isn't aligned to the right nor marked decorative; update the
component usage to pass a className that pushes it to the right (e.g. "ml-auto"
or equivalent spacing utility) and mark it as decorative for accessibility (e.g.
aria-hidden="true" and focusable={false} or role="img" set appropriately), or if
ChevronRightIcon doesn't accept className, wrap it in a span with the ml-auto
class and set aria-hidden on the icon element; ensure the icon accepts a
className prop if you choose the direct-prop route.
{ | ||
"path": "components/ui/8bit/pagination.tsx", | ||
"content": "import { type VariantProps, cva } from \"class-variance-authority\";\nimport { MoreHorizontal } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\nimport {\n Pagination as ShadcnPagination,\n PaginationContent as ShadcnPaginationContent,\n PaginationEllipsis as ShadcnPaginationEllipsis,\n PaginationItem as ShadcnPaginationItem,\n PaginationLink as ShadcnPaginationLink,\n} from \"@/components/ui/pagination\";\n\nimport { Button } from \"../button\";\nimport \"./styles/retro.css\";\n\nexport const paginationVariants = cva(\"\", {\n variants: {\n font: {\n normal: \"\",\n retro: \"retro\",\n },\n variant: {\n default: \"text-card-foreground\",\n destructive:\n \"text-destructive [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n});\n\nexport type BitPaginationProps<T extends React.ElementType> =\n React.ComponentPropsWithoutRef<T> & VariantProps<typeof paginationVariants>;\n\nfunction Pagination({ ...props }: BitPaginationProps<\"nav\">) {\n const { variant, className, font } = props;\n return (\n <ShadcnPagination\n {...props}\n className={cn(\n paginationVariants({ variant }),\n font !== \"normal\" && \"retro\",\n className\n )}\n />\n );\n}\n\nconst ChevronLeftIcon = () => {\n return (\n <svg\n width=\"50\"\n height=\"50\"\n viewBox=\"0 0 256 256\"\n fill=\"currentColor\"\n xmlns=\"http://www.w3.org/2000/svg\"\n stroke=\"currentColor\"\n strokeWidth=\"0.25\"\n color=\"\"\n className=\"size-7\"\n aria-label=\"chevron-left\"\n >\n <rect\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"matrix(-1 0 0 1 128 136)\"\n ></rect>\n <rect\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"matrix(-1 0 0 1 144 152)\"\n ></rect>\n <rect\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"matrix(-1 0 0 1 160 72)\"\n ></rect>\n <rect\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"matrix(-1 0 0 1 160 168)\"\n ></rect>\n <rect\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"matrix(-1 0 0 1 112 120)\"\n ></rect>\n <rect\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"matrix(-1 0 0 1 128 104)\"\n ></rect>\n <rect\n width=\"14\"\n height=\"14\"\n rx=\"1\"\n transform=\"matrix(-1 0 0 1 144 88)\"\n ></rect>\n </svg>\n );\n};\n\nconst ChevronRightIcon = () => {\n return (\n <svg\n width=\"50\"\n height=\"50\"\n viewBox=\"0 0 256 256\"\n fill=\"currentColor\"\n xmlns=\"http://www.w3.org/2000/svg\"\n stroke=\"currentColor\"\n strokeWidth=\"0.25\"\n color=\"\"\n className=\"raster-icon size-7\"\n aria-label=\"chevron-right\"\n >\n <rect x=\"128\" y=\"136\" width=\"14\" height=\"14\" rx=\"1\"></rect>\n <rect x=\"112\" y=\"152\" width=\"14\" height=\"14\" rx=\"1\"></rect>\n <rect x=\"96\" y=\"72\" width=\"14\" height=\"14\" rx=\"1\"></rect>\n <rect x=\"96\" y=\"168\" width=\"14\" height=\"14\" rx=\"1\"></rect>\n <rect x=\"144\" y=\"120\" width=\"14\" height=\"14\" rx=\"1\"></rect>\n <rect x=\"128\" y=\"104\" width=\"14\" height=\"14\" rx=\"1\"></rect>\n <rect x=\"112\" y=\"88\" width=\"14\" height=\"14\" rx=\"1\"></rect>\n </svg>\n );\n};\n\nfunction PaginationContent({ ...props }: BitPaginationProps<\"ul\">) {\n const { className, font } = props;\n return (\n <ShadcnPaginationContent\n className={cn(\"gap-2\", font !== \"normal\" && \"retro\", className)}\n {...props}\n />\n );\n}\n\nfunction PaginationItem({ ...props }: BitPaginationProps<\"li\">) {\n const { className, font } = props;\n return (\n <ShadcnPaginationItem\n className={cn(font !== \"normal\" && \"retro\", className)}\n {...props}\n />\n );\n}\n\ntype PaginationLinkProps = {\n isActive?: boolean;\n} & Pick<React.ComponentProps<typeof Button>, \"size\"> &\n BitPaginationProps<\"a\">;\n\nfunction PaginationLink({ ...props }: PaginationLinkProps) {\n const { font, children, isActive, className } = props;\n return (\n <ShadcnPaginationLink\n className={cn(\n font !== \"normal\" && \"retro\",\n className,\n \"relative group\",\n \"bg-transparent hover:bg-transparent active:bg-transparent focus:bg-transparent\",\n \"rounded-none border-dashed border-y-4 border-transparent\",\n \"dark:hover:border-ring dark:focus:border-ring\",\n \"hover:border-foreground focus:border-foreground\",\n \"active:border-transparent\",\n \"data-[active=true]:border-none aria-[current=page]:border-none\"\n )}\n {...props}\n >\n {children}\n\n {isActive && (\n <div\n className=\"absolute inset-0 w-full h-full pointer-events-none\"\n style={{ zIndex: 10 }}\n >\n <div\n className=\"absolute top-0 left-0 w-full h-1.5 bg-foreground dark:bg-ring pointer-events-none\"\n aria-hidden=\"true\"\n />\n <div\n className=\"absolute left-0 bottom-0 w-full h-1.5 bg-foreground dark:bg-ring pointer-events-none\"\n aria-hidden=\"true\"\n />\n <div\n className=\"absolute top-1 -left-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none\"\n aria-hidden=\"true\"\n />\n <div\n className=\"absolute bottom-1 -left-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none\"\n aria-hidden=\"true\"\n />\n <div\n className=\"absolute top-1 -right-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none\"\n aria-hidden=\"true\"\n />\n <div\n className=\"absolute bottom-1 -right-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none\"\n aria-hidden=\"true\"\n />\n </div>\n )}\n </ShadcnPaginationLink>\n );\n}\n\nfunction PaginationPrevious({\n ...props\n}: React.ComponentProps<typeof PaginationLink>) {\n const { font, className } = props;\n return (\n <PaginationLink\n className={cn(\n \"relative group\",\n \"flex flex-row w-full text-sm\",\n \"bg-transparent hover:bg-transparent active:bg-transparent focus:bg-transparent\",\n \"rounded-none border-dashed border-y-4 border-transparent\",\n \"hover:border-foreground focus:border-foreground active:border-transparent\",\n \"dark:hover:border-ring dark:focus:border-ring\",\n \"data-[active=true]:border-none aria-[current=page]:border-none\",\n font !== \"normal\" && \"retro\",\n className\n )}\n {...props}\n >\n <ChevronLeftIcon />\n <span className=\"hidden sm:block\">Previous</span>\n </PaginationLink>\n );\n}\n\nfunction PaginationNext({\n ...props\n}: React.ComponentProps<typeof PaginationLink>) {\n const { font, className } = props;\n\n return (\n <PaginationLink\n className={cn(\n \"relative group\",\n \"flex flex-row w-full text-sm\",\n \"bg-transparent hover:bg-transparent active:bg-transparent focus:bg-transparent\",\n \"rounded-none border-dashed border-y-4 border-transparent\",\n \"hover:border-foreground focus:border-foreground active:border-transparent\",\n \"dark:hover:border-ring dark:focus:border-ring\",\n \"data-[active=true]:border-none aria-[current=page]:border-none\",\n \"flex flex-row text-sm w-full\",\n font !== \"normal\" && \"retro\",\n className\n )}\n {...props}\n >\n <span className=\"hidden sm:block\">Next</span>\n <ChevronRightIcon />\n </PaginationLink>\n );\n}\n\nfunction PaginationEllipsis({ ...props }: BitPaginationProps<\"span\">) {\n const { font, className } = props;\n\n return (\n <ShadcnPaginationEllipsis\n className={cn(font !== \"normal\" && \"retro\", className)}\n {...props}\n >\n <MoreHorizontal className={cn(\"size-7\", \"retro\")} />\n <span className=\"sr-only\">More pages</span>\n </ShadcnPaginationEllipsis>\n );\n}\n\nexport {\n Pagination,\n PaginationContent,\n PaginationLink,\n PaginationItem,\n PaginationPrevious,\n PaginationNext,\n PaginationEllipsis,\n};\n", | ||
"content": "import { type VariantProps, cva } from \"class-variance-authority\";\r\nimport { MoreHorizontal } from \"lucide-react\";\r\n\r\nimport { cn } from \"@/lib/utils\";\r\n\r\nimport {\r\n Pagination as ShadcnPagination,\r\n PaginationContent as ShadcnPaginationContent,\r\n PaginationEllipsis as ShadcnPaginationEllipsis,\r\n PaginationItem as ShadcnPaginationItem,\r\n PaginationLink as ShadcnPaginationLink,\r\n} from \"@/components/ui/pagination\";\r\n\r\nimport { ChevronLeftIcon } from \"@/components/ui/8bit/assets/chevronLeftIcon\";\r\nimport { ChevronRightIcon } from \"@/components/ui/8bit/assets/chevronRightIcon\";\r\nimport { Button } from \"../button\";\r\nimport \"./styles/retro.css\";\r\n\r\nexport const paginationVariants = cva(\"\", {\r\n variants: {\r\n font: {\r\n normal: \"\",\r\n retro: \"retro\",\r\n },\r\n variant: {\r\n default: \"text-card-foreground\",\r\n destructive:\r\n \"text-destructive [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90\",\r\n },\r\n },\r\n defaultVariants: {\r\n variant: \"default\",\r\n },\r\n});\r\n\r\nexport type BitPaginationProps<T extends React.ElementType> =\r\n React.ComponentPropsWithoutRef<T> & VariantProps<typeof paginationVariants>;\r\n\r\nfunction Pagination({ ...props }: BitPaginationProps<\"nav\">) {\r\n const { variant, className, font } = props;\r\n return (\r\n <ShadcnPagination\r\n {...props}\r\n className={cn(\r\n paginationVariants({ variant }),\r\n font !== \"normal\" && \"retro\",\r\n className\r\n )}\r\n />\r\n );\r\n}\r\n\r\nfunction PaginationContent({ ...props }: BitPaginationProps<\"ul\">) {\r\n const { className, font } = props;\r\n return (\r\n <ShadcnPaginationContent\r\n className={cn(\"gap-2\", font !== \"normal\" && \"retro\", className)}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction PaginationItem({ ...props }: BitPaginationProps<\"li\">) {\r\n const { className, font } = props;\r\n return (\r\n <ShadcnPaginationItem\r\n className={cn(font !== \"normal\" && \"retro\", className)}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\ntype PaginationLinkProps = {\r\n isActive?: boolean;\r\n} & Pick<React.ComponentProps<typeof Button>, \"size\"> &\r\n BitPaginationProps<\"a\">;\r\n\r\nfunction PaginationLink({ ...props }: PaginationLinkProps) {\r\n const { font, children, isActive, className } = props;\r\n return (\r\n <ShadcnPaginationLink\r\n className={cn(\r\n font !== \"normal\" && \"retro\",\r\n className,\r\n \"relative group\",\r\n \"bg-transparent hover:bg-transparent active:bg-transparent focus:bg-transparent\",\r\n \"rounded-none border-dashed border-y-4 border-transparent\",\r\n \"dark:hover:border-ring dark:focus:border-ring\",\r\n \"hover:border-foreground focus:border-foreground\",\r\n \"active:border-transparent\",\r\n \"data-[active=true]:border-none aria-[current=page]:border-none\"\r\n )}\r\n {...props}\r\n >\r\n {children}\r\n\r\n {isActive && (\r\n <div\r\n className=\"absolute inset-0 w-full h-full pointer-events-none\"\r\n style={{ zIndex: 10 }}\r\n >\r\n <div\r\n className=\"absolute top-0 left-0 w-full h-1.5 bg-foreground dark:bg-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n <div\r\n className=\"absolute left-0 bottom-0 w-full h-1.5 bg-foreground dark:bg-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n <div\r\n className=\"absolute top-1 -left-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n <div\r\n className=\"absolute bottom-1 -left-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n <div\r\n className=\"absolute top-1 -right-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n <div\r\n className=\"absolute bottom-1 -right-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n </div>\r\n )}\r\n </ShadcnPaginationLink>\r\n );\r\n}\r\n\r\nfunction PaginationPrevious({\r\n ...props\r\n}: React.ComponentProps<typeof PaginationLink>) {\r\n const { font, className } = props;\r\n return (\r\n <PaginationLink\r\n className={cn(\r\n \"relative group\",\r\n \"flex flex-row w-full text-sm\",\r\n \"bg-transparent hover:bg-transparent active:bg-transparent focus:bg-transparent\",\r\n \"rounded-none border-dashed border-y-4 border-transparent\",\r\n \"hover:border-foreground focus:border-foreground active:border-transparent\",\r\n \"dark:hover:border-ring dark:focus:border-ring\",\r\n \"data-[active=true]:border-none aria-[current=page]:border-none\",\r\n font !== \"normal\" && \"retro\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n <ChevronLeftIcon />\r\n <span className=\"hidden sm:block\">Previous</span>\r\n </PaginationLink>\r\n );\r\n}\r\n\r\nfunction PaginationNext({\r\n ...props\r\n}: React.ComponentProps<typeof PaginationLink>) {\r\n const { font, className } = props;\r\n\r\n return (\r\n <PaginationLink\r\n className={cn(\r\n \"relative group\",\r\n \"flex flex-row w-full text-sm\",\r\n \"bg-transparent hover:bg-transparent active:bg-transparent focus:bg-transparent\",\r\n \"rounded-none border-dashed border-y-4 border-transparent\",\r\n \"hover:border-foreground focus:border-foreground active:border-transparent\",\r\n \"dark:hover:border-ring dark:focus:border-ring\",\r\n \"data-[active=true]:border-none aria-[current=page]:border-none\",\r\n \"flex flex-row text-sm w-full\",\r\n font !== \"normal\" && \"retro\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n <span className=\"hidden sm:block\">Next</span>\r\n <ChevronRightIcon />\r\n </PaginationLink>\r\n );\r\n}\r\n\r\nfunction PaginationEllipsis({ ...props }: BitPaginationProps<\"span\">) {\r\n const { font, className } = props;\r\n\r\n return (\r\n <ShadcnPaginationEllipsis\r\n className={cn(font !== \"normal\" && \"retro\", className)}\r\n {...props}\r\n >\r\n <MoreHorizontal className={cn(\"size-7\", \"retro\")} />\r\n <span className=\"sr-only\">More pages</span>\r\n </ShadcnPaginationEllipsis>\r\n );\r\n}\r\n\r\nexport {\r\n Pagination,\r\n PaginationContent,\r\n PaginationLink,\r\n PaginationItem,\r\n PaginationPrevious,\r\n PaginationNext,\r\n PaginationEllipsis,\r\n};\r\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Decorative chevrons should be aria-hidden in Previous/Next
The icons are decorative; expose aria-hidden and focusable="false" to avoid polluting accessible names. This assumes the asset components accept SVG props (see asset refactor suggested in Calendar).
- <ChevronLeftIcon />
+ <ChevronLeftIcon aria-hidden="true" focusable="false" />
...
- <ChevronRightIcon />
+ <ChevronRightIcon aria-hidden="true" focusable="false" />
📝 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.
"content": "import { type VariantProps, cva } from \"class-variance-authority\";\r\nimport { MoreHorizontal } from \"lucide-react\";\r\n\r\nimport { cn } from \"@/lib/utils\";\r\n\r\nimport {\r\n Pagination as ShadcnPagination,\r\n PaginationContent as ShadcnPaginationContent,\r\n PaginationEllipsis as ShadcnPaginationEllipsis,\r\n PaginationItem as ShadcnPaginationItem,\r\n PaginationLink as ShadcnPaginationLink,\r\n} from \"@/components/ui/pagination\";\r\n\r\nimport { ChevronLeftIcon } from \"@/components/ui/8bit/assets/chevronLeftIcon\";\r\nimport { ChevronRightIcon } from \"@/components/ui/8bit/assets/chevronRightIcon\";\r\nimport { Button } from \"../button\";\r\nimport \"./styles/retro.css\";\r\n\r\nexport const paginationVariants = cva(\"\", {\r\n variants: {\r\n font: {\r\n normal: \"\",\r\n retro: \"retro\",\r\n },\r\n variant: {\r\n default: \"text-card-foreground\",\r\n destructive:\r\n \"text-destructive [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90\",\r\n },\r\n },\r\n defaultVariants: {\r\n variant: \"default\",\r\n },\r\n});\r\n\r\nexport type BitPaginationProps<T extends React.ElementType> =\r\n React.ComponentPropsWithoutRef<T> & VariantProps<typeof paginationVariants>;\r\n\r\nfunction Pagination({ ...props }: BitPaginationProps<\"nav\">) {\r\n const { variant, className, font } = props;\r\n return (\r\n <ShadcnPagination\r\n {...props}\r\n className={cn(\r\n paginationVariants({ variant }),\r\n font !== \"normal\" && \"retro\",\r\n className\r\n )}\r\n />\r\n );\r\n}\r\n\r\nfunction PaginationContent({ ...props }: BitPaginationProps<\"ul\">) {\r\n const { className, font } = props;\r\n return (\r\n <ShadcnPaginationContent\r\n className={cn(\"gap-2\", font !== \"normal\" && \"retro\", className)}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction PaginationItem({ ...props }: BitPaginationProps<\"li\">) {\r\n const { className, font } = props;\r\n return (\r\n <ShadcnPaginationItem\r\n className={cn(font !== \"normal\" && \"retro\", className)}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\ntype PaginationLinkProps = {\r\n isActive?: boolean;\r\n} & Pick<React.ComponentProps<typeof Button>, \"size\"> &\r\n BitPaginationProps<\"a\">;\r\n\r\nfunction PaginationLink({ ...props }: PaginationLinkProps) {\r\n const { font, children, isActive, className } = props;\r\n return (\r\n <ShadcnPaginationLink\r\n className={cn(\r\n font !== \"normal\" && \"retro\",\r\n className,\r\n \"relative group\",\r\n \"bg-transparent hover:bg-transparent active:bg-transparent focus:bg-transparent\",\r\n \"rounded-none border-dashed border-y-4 border-transparent\",\r\n \"dark:hover:border-ring dark:focus:border-ring\",\r\n \"hover:border-foreground focus:border-foreground\",\r\n \"active:border-transparent\",\r\n \"data-[active=true]:border-none aria-[current=page]:border-none\"\r\n )}\r\n {...props}\r\n >\r\n {children}\r\n\r\n {isActive && (\r\n <div\r\n className=\"absolute inset-0 w-full h-full pointer-events-none\"\r\n style={{ zIndex: 10 }}\r\n >\r\n <div\r\n className=\"absolute top-0 left-0 w-full h-1.5 bg-foreground dark:bg-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n <div\r\n className=\"absolute left-0 bottom-0 w-full h-1.5 bg-foreground dark:bg-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n <div\r\n className=\"absolute top-1 -left-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n <div\r\n className=\"absolute bottom-1 -left-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n <div\r\n className=\"absolute top-1 -right-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n <div\r\n className=\"absolute bottom-1 -right-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n </div>\r\n )}\r\n </ShadcnPaginationLink>\r\n );\r\n}\r\n\r\nfunction PaginationPrevious({\r\n ...props\r\n}: React.ComponentProps<typeof PaginationLink>) {\r\n const { font, className } = props;\r\n return (\r\n <PaginationLink\r\n className={cn(\r\n \"relative group\",\r\n \"flex flex-row w-full text-sm\",\r\n \"bg-transparent hover:bg-transparent active:bg-transparent focus:bg-transparent\",\r\n \"rounded-none border-dashed border-y-4 border-transparent\",\r\n \"hover:border-foreground focus:border-foreground active:border-transparent\",\r\n \"dark:hover:border-ring dark:focus:border-ring\",\r\n \"data-[active=true]:border-none aria-[current=page]:border-none\",\r\n font !== \"normal\" && \"retro\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n <ChevronLeftIcon />\r\n <span className=\"hidden sm:block\">Previous</span>\r\n </PaginationLink>\r\n );\r\n}\r\n\r\nfunction PaginationNext({\r\n ...props\r\n}: React.ComponentProps<typeof PaginationLink>) {\r\n const { font, className } = props;\r\n\r\n return (\r\n <PaginationLink\r\n className={cn(\r\n \"relative group\",\r\n \"flex flex-row w-full text-sm\",\r\n \"bg-transparent hover:bg-transparent active:bg-transparent focus:bg-transparent\",\r\n \"rounded-none border-dashed border-y-4 border-transparent\",\r\n \"hover:border-foreground focus:border-foreground active:border-transparent\",\r\n \"dark:hover:border-ring dark:focus:border-ring\",\r\n \"data-[active=true]:border-none aria-[current=page]:border-none\",\r\n \"flex flex-row text-sm w-full\",\r\n font !== \"normal\" && \"retro\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n <span className=\"hidden sm:block\">Next</span>\r\n <ChevronRightIcon />\r\n </PaginationLink>\r\n );\r\n}\r\n\r\nfunction PaginationEllipsis({ ...props }: BitPaginationProps<\"span\">) {\r\n const { font, className } = props;\r\n\r\n return (\r\n <ShadcnPaginationEllipsis\r\n className={cn(font !== \"normal\" && \"retro\", className)}\r\n {...props}\r\n >\r\n <MoreHorizontal className={cn(\"size-7\", \"retro\")} />\r\n <span className=\"sr-only\">More pages</span>\r\n </ShadcnPaginationEllipsis>\r\n );\r\n}\r\n\r\nexport {\r\n Pagination,\r\n PaginationContent,\r\n PaginationLink,\r\n PaginationItem,\r\n PaginationPrevious,\r\n PaginationNext,\r\n PaginationEllipsis,\r\n};\r\n", | |
import { type VariantProps, cva } from "class-variance-authority"; | |
import { MoreHorizontal } from "lucide-react"; | |
import { cn } from "@/lib/utils"; | |
import { | |
Pagination as ShadcnPagination, | |
PaginationContent as ShadcnPaginationContent, | |
PaginationEllipsis as ShadcnPaginationEllipsis, | |
PaginationItem as ShadcnPaginationItem, | |
PaginationLink as ShadcnPaginationLink, | |
} from "@/components/ui/pagination"; | |
import { ChevronLeftIcon } from "@/components/ui/8bit/assets/chevronLeftIcon"; | |
import { ChevronRightIcon } from "@/components/ui/8bit/assets/chevronRightIcon"; | |
import { Button } from "../button"; | |
import "./styles/retro.css"; | |
export const paginationVariants = cva("", { | |
variants: { | |
font: { | |
normal: "", | |
retro: "retro", | |
}, | |
variant: { | |
default: "text-card-foreground", | |
destructive: | |
"text-destructive [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90", | |
}, | |
}, | |
defaultVariants: { | |
variant: "default", | |
}, | |
}); | |
export type BitPaginationProps<T extends React.ElementType> = | |
React.ComponentPropsWithoutRef<T> & VariantProps<typeof paginationVariants>; | |
function Pagination({ ...props }: BitPaginationProps<"nav">) { | |
const { variant, className, font } = props; | |
return ( | |
<ShadcnPagination | |
{...props} | |
className={cn( | |
paginationVariants({ variant }), | |
font !== "normal" && "retro", | |
className | |
)} | |
/> | |
); | |
} | |
function PaginationContent({ ...props }: BitPaginationProps<"ul">) { | |
const { className, font } = props; | |
return ( | |
<ShadcnPaginationContent | |
className={cn("gap-2", font !== "normal" && "retro", className)} | |
{...props} | |
/> | |
); | |
} | |
function PaginationItem({ ...props }: BitPaginationProps<"li">) { | |
const { className, font } = props; | |
return ( | |
<ShadcnPaginationItem | |
className={cn(font !== "normal" && "retro", className)} | |
{...props} | |
/> | |
); | |
} | |
type PaginationLinkProps = { | |
isActive?: boolean; | |
} & Pick<React.ComponentProps<typeof Button>, "size"> & | |
BitPaginationProps<"a">; | |
function PaginationLink({ ...props }: PaginationLinkProps) { | |
const { font, children, isActive, className } = props; | |
return ( | |
<ShadcnPaginationLink | |
className={cn( | |
font !== "normal" && "retro", | |
className, | |
"relative group", | |
"bg-transparent hover:bg-transparent active:bg-transparent focus:bg-transparent", | |
"rounded-none border-dashed border-y-4 border-transparent", | |
"dark:hover:border-ring dark:focus:border-ring", | |
"hover:border-foreground focus:border-foreground", | |
"active:border-transparent", | |
"data-[active=true]:border-none aria-[current=page]:border-none" | |
)} | |
{...props} | |
> | |
{children} | |
{isActive && ( | |
<div | |
className="absolute inset-0 w-full h-full pointer-events-none" | |
style={{ zIndex: 10 }} | |
> | |
<div | |
className="absolute top-0 left-0 w-full h-1.5 bg-foreground dark:bg-ring pointer-events-none" | |
aria-hidden="true" | |
/> | |
<div | |
className="absolute left-0 bottom-0 w-full h-1.5 bg-foreground dark:bg-ring pointer-events-none" | |
aria-hidden="true" | |
/> | |
<div | |
className="absolute top-1 -left-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none" | |
aria-hidden="true" | |
/> | |
<div | |
className="absolute bottom-1 -left-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none" | |
aria-hidden="true" | |
/> | |
<div | |
className="absolute top-1 -right-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none" | |
aria-hidden="true" | |
/> | |
<div | |
className="absolute bottom-1 -right-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none" | |
aria-hidden="true" | |
/> | |
</div> | |
)} | |
</ShadcnPaginationLink> | |
); | |
} | |
function PaginationPrevious({ | |
...props | |
}: React.ComponentProps<typeof PaginationLink>) { | |
const { font, className } = props; | |
return ( | |
<PaginationLink | |
className={cn( | |
"relative group", | |
"flex flex-row w-full text-sm", | |
"bg-transparent hover:bg-transparent active:bg-transparent focus:bg-transparent", | |
"rounded-none border-dashed border-y-4 border-transparent", | |
"hover:border-foreground focus:border-foreground active:border-transparent", | |
"dark:hover:border-ring dark:focus:border-ring", | |
"data-[active=true]:border-none aria-[current=page]:border-none", | |
font !== "normal" && "retro", | |
className | |
)} | |
{...props} | |
> | |
<ChevronLeftIcon aria-hidden="true" focusable="false" /> | |
<span className="hidden sm:block">Previous</span> | |
</PaginationLink> | |
); | |
} | |
function PaginationNext({ | |
...props | |
}: React.ComponentProps<typeof PaginationLink>) { | |
const { font, className } = props; | |
return ( | |
<PaginationLink | |
className={cn( | |
"relative group", | |
"flex flex-row w-full text-sm", | |
"bg-transparent hover:bg-transparent active:bg-transparent focus:bg-transparent", | |
"rounded-none border-dashed border-y-4 border-transparent", | |
"hover:border-foreground focus:border-foreground active:border-transparent", | |
"dark:hover:border-ring dark:focus:border-ring", | |
"data-[active=true]:border-none aria-[current=page]:border-none", | |
"flex flex-row text-sm w-full", | |
font !== "normal" && "retro", | |
className | |
)} | |
{...props} | |
> | |
<span className="hidden sm:block">Next</span> | |
<ChevronRightIcon aria-hidden="true" focusable="false" /> | |
</PaginationLink> | |
); | |
} | |
function PaginationEllipsis({ ...props }: BitPaginationProps<"span">) { | |
const { font, className } = props; | |
return ( | |
<ShadcnPaginationEllipsis | |
className={cn(font !== "normal" && "retro", className)} | |
{...props} | |
> | |
<MoreHorizontal className={cn("size-7", "retro")} /> | |
<span className="sr-only">More pages</span> | |
</ShadcnPaginationEllipsis> | |
); | |
} | |
export { | |
Pagination, | |
PaginationContent, | |
PaginationLink, | |
PaginationItem, | |
PaginationPrevious, | |
PaginationNext, | |
PaginationEllipsis, | |
}; |
🤖 Prompt for AI Agents
In public/r/8bit-pagination.json around lines 13 to 13, the previous/next
chevron icons are decorative but not marked as such; update the ChevronLeftIcon
and ChevronRightIcon usages in PaginationPrevious and PaginationNext to include
accessibility props aria-hidden="true" and focusable="false" (assuming the SVG
asset components accept standard SVG/React props) so they are ignored by
assistive tech and keyboard focus.
🛠️ Refactor suggestion
Prevent leaking design-system props to DOM and set font default
Same pattern as breadcrumb: variant and font flow into {...props}. Also, font defaults to retro when undefined. Extract props and set defaultVariants.font.
export const paginationVariants = cva("", {
variants: {
font: {
normal: "",
retro: "retro",
},
variant: {
default: "text-card-foreground",
destructive:
"text-destructive [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90",
},
},
defaultVariants: {
variant: "default",
+ font: "normal",
},
});
-function Pagination({ ...props }: BitPaginationProps<"nav">) {
- const { variant, className, font } = props;
+function Pagination({ variant, className, font, ...rest }: BitPaginationProps<"nav">) {
return (
<ShadcnPagination
- {...props}
+ {...rest}
className={cn(
paginationVariants({ variant }),
font !== "normal" && "retro",
className
)}
/>
);
}
-function PaginationContent({ ...props }: BitPaginationProps<"ul">) {
- const { className, font } = props;
+function PaginationContent({ className, font, ...rest }: BitPaginationProps<"ul">) {
return (
<ShadcnPaginationContent
className={cn("gap-2", font !== "normal" && "retro", className)}
- {...props}
+ {...rest}
/>
);
}
-function PaginationItem({ ...props }: BitPaginationProps<"li">) {
- const { className, font } = props;
+function PaginationItem({ className, font, ...rest }: BitPaginationProps<"li">) {
return (
<ShadcnPaginationItem
className={cn(font !== "normal" && "retro", className)}
- {...props}
+ {...rest}
/>
);
}
📝 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.
"content": "import { type VariantProps, cva } from \"class-variance-authority\";\r\nimport { MoreHorizontal } from \"lucide-react\";\r\n\r\nimport { cn } from \"@/lib/utils\";\r\n\r\nimport {\r\n Pagination as ShadcnPagination,\r\n PaginationContent as ShadcnPaginationContent,\r\n PaginationEllipsis as ShadcnPaginationEllipsis,\r\n PaginationItem as ShadcnPaginationItem,\r\n PaginationLink as ShadcnPaginationLink,\r\n} from \"@/components/ui/pagination\";\r\n\r\nimport { ChevronLeftIcon } from \"@/components/ui/8bit/assets/chevronLeftIcon\";\r\nimport { ChevronRightIcon } from \"@/components/ui/8bit/assets/chevronRightIcon\";\r\nimport { Button } from \"../button\";\r\nimport \"./styles/retro.css\";\r\n\r\nexport const paginationVariants = cva(\"\", {\r\n variants: {\r\n font: {\r\n normal: \"\",\r\n retro: \"retro\",\r\n },\r\n variant: {\r\n default: \"text-card-foreground\",\r\n destructive:\r\n \"text-destructive [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90\",\r\n },\r\n },\r\n defaultVariants: {\r\n variant: \"default\",\r\n },\r\n});\r\n\r\nexport type BitPaginationProps<T extends React.ElementType> =\r\n React.ComponentPropsWithoutRef<T> & VariantProps<typeof paginationVariants>;\r\n\r\nfunction Pagination({ ...props }: BitPaginationProps<\"nav\">) {\r\n const { variant, className, font } = props;\r\n return (\r\n <ShadcnPagination\r\n {...props}\r\n className={cn(\r\n paginationVariants({ variant }),\r\n font !== \"normal\" && \"retro\",\r\n className\r\n )}\r\n />\r\n );\r\n}\r\n\r\nfunction PaginationContent({ ...props }: BitPaginationProps<\"ul\">) {\r\n const { className, font } = props;\r\n return (\r\n <ShadcnPaginationContent\r\n className={cn(\"gap-2\", font !== \"normal\" && \"retro\", className)}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\nfunction PaginationItem({ ...props }: BitPaginationProps<\"li\">) {\r\n const { className, font } = props;\r\n return (\r\n <ShadcnPaginationItem\r\n className={cn(font !== \"normal\" && \"retro\", className)}\r\n {...props}\r\n />\r\n );\r\n}\r\n\r\ntype PaginationLinkProps = {\r\n isActive?: boolean;\r\n} & Pick<React.ComponentProps<typeof Button>, \"size\"> &\r\n BitPaginationProps<\"a\">;\r\n\r\nfunction PaginationLink({ ...props }: PaginationLinkProps) {\r\n const { font, children, isActive, className } = props;\r\n return (\r\n <ShadcnPaginationLink\r\n className={cn(\r\n font !== \"normal\" && \"retro\",\r\n className,\r\n \"relative group\",\r\n \"bg-transparent hover:bg-transparent active:bg-transparent focus:bg-transparent\",\r\n \"rounded-none border-dashed border-y-4 border-transparent\",\r\n \"dark:hover:border-ring dark:focus:border-ring\",\r\n \"hover:border-foreground focus:border-foreground\",\r\n \"active:border-transparent\",\r\n \"data-[active=true]:border-none aria-[current=page]:border-none\"\r\n )}\r\n {...props}\r\n >\r\n {children}\r\n\r\n {isActive && (\r\n <div\r\n className=\"absolute inset-0 w-full h-full pointer-events-none\"\r\n style={{ zIndex: 10 }}\r\n >\r\n <div\r\n className=\"absolute top-0 left-0 w-full h-1.5 bg-foreground dark:bg-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n <div\r\n className=\"absolute left-0 bottom-0 w-full h-1.5 bg-foreground dark:bg-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n <div\r\n className=\"absolute top-1 -left-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n <div\r\n className=\"absolute bottom-1 -left-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n <div\r\n className=\"absolute top-1 -right-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n <div\r\n className=\"absolute bottom-1 -right-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none\"\r\n aria-hidden=\"true\"\r\n />\r\n </div>\r\n )}\r\n </ShadcnPaginationLink>\r\n );\r\n}\r\n\r\nfunction PaginationPrevious({\r\n ...props\r\n}: React.ComponentProps<typeof PaginationLink>) {\r\n const { font, className } = props;\r\n return (\r\n <PaginationLink\r\n className={cn(\r\n \"relative group\",\r\n \"flex flex-row w-full text-sm\",\r\n \"bg-transparent hover:bg-transparent active:bg-transparent focus:bg-transparent\",\r\n \"rounded-none border-dashed border-y-4 border-transparent\",\r\n \"hover:border-foreground focus:border-foreground active:border-transparent\",\r\n \"dark:hover:border-ring dark:focus:border-ring\",\r\n \"data-[active=true]:border-none aria-[current=page]:border-none\",\r\n font !== \"normal\" && \"retro\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n <ChevronLeftIcon />\r\n <span className=\"hidden sm:block\">Previous</span>\r\n </PaginationLink>\r\n );\r\n}\r\n\r\nfunction PaginationNext({\r\n ...props\r\n}: React.ComponentProps<typeof PaginationLink>) {\r\n const { font, className } = props;\r\n\r\n return (\r\n <PaginationLink\r\n className={cn(\r\n \"relative group\",\r\n \"flex flex-row w-full text-sm\",\r\n \"bg-transparent hover:bg-transparent active:bg-transparent focus:bg-transparent\",\r\n \"rounded-none border-dashed border-y-4 border-transparent\",\r\n \"hover:border-foreground focus:border-foreground active:border-transparent\",\r\n \"dark:hover:border-ring dark:focus:border-ring\",\r\n \"data-[active=true]:border-none aria-[current=page]:border-none\",\r\n \"flex flex-row text-sm w-full\",\r\n font !== \"normal\" && \"retro\",\r\n className\r\n )}\r\n {...props}\r\n >\r\n <span className=\"hidden sm:block\">Next</span>\r\n <ChevronRightIcon />\r\n </PaginationLink>\r\n );\r\n}\r\n\r\nfunction PaginationEllipsis({ ...props }: BitPaginationProps<\"span\">) {\r\n const { font, className } = props;\r\n\r\n return (\r\n <ShadcnPaginationEllipsis\r\n className={cn(font !== \"normal\" && \"retro\", className)}\r\n {...props}\r\n >\r\n <MoreHorizontal className={cn(\"size-7\", \"retro\")} />\r\n <span className=\"sr-only\">More pages</span>\r\n </ShadcnPaginationEllipsis>\r\n );\r\n}\r\n\r\nexport {\r\n Pagination,\r\n PaginationContent,\r\n PaginationLink,\r\n PaginationItem,\r\n PaginationPrevious,\r\n PaginationNext,\r\n PaginationEllipsis,\r\n};\r\n", | |
import { type VariantProps, cva } from "class-variance-authority"; | |
import { MoreHorizontal } from "lucide-react"; | |
import { cn } from "@/lib/utils"; | |
import { | |
Pagination as ShadcnPagination, | |
PaginationContent as ShadcnPaginationContent, | |
PaginationEllipsis as ShadcnPaginationEllipsis, | |
PaginationItem as ShadcnPaginationItem, | |
PaginationLink as ShadcnPaginationLink, | |
} from "@/components/ui/pagination"; | |
import { ChevronLeftIcon } from "@/components/ui/8bit/assets/chevronLeftIcon"; | |
import { ChevronRightIcon } from "@/components/ui/8bit/assets/chevronRightIcon"; | |
import { Button } from "../button"; | |
import "./styles/retro.css"; | |
export const paginationVariants = cva("", { | |
variants: { | |
font: { | |
normal: "", | |
retro: "retro", | |
}, | |
variant: { | |
default: "text-card-foreground", | |
destructive: | |
"text-destructive [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90", | |
}, | |
}, | |
defaultVariants: { | |
variant: "default", | |
font: "normal", | |
}, | |
}); | |
export type BitPaginationProps<T extends React.ElementType> = | |
React.ComponentPropsWithoutRef<T> & VariantProps<typeof paginationVariants>; | |
function Pagination({ variant, className, font, ...rest }: BitPaginationProps<"nav">) { | |
return ( | |
<ShadcnPagination | |
{...rest} | |
className={cn( | |
paginationVariants({ variant }), | |
font !== "normal" && "retro", | |
className | |
)} | |
/> | |
); | |
} | |
function PaginationContent({ className, font, ...rest }: BitPaginationProps<"ul">) { | |
return ( | |
<ShadcnPaginationContent | |
className={cn("gap-2", font !== "normal" && "retro", className)} | |
{...rest} | |
/> | |
); | |
} | |
function PaginationItem({ className, font, ...rest }: BitPaginationProps<"li">) { | |
return ( | |
<ShadcnPaginationItem | |
className={cn(font !== "normal" && "retro", className)} | |
{...rest} | |
/> | |
); | |
} | |
type PaginationLinkProps = { | |
isActive?: boolean; | |
} & Pick<React.ComponentProps<typeof Button>, "size"> & | |
BitPaginationProps<"a">; | |
function PaginationLink({ ...props }: PaginationLinkProps) { | |
const { font, children, isActive, className } = props; | |
return ( | |
<ShadcnPaginationLink | |
className={cn( | |
font !== "normal" && "retro", | |
className, | |
"relative group", | |
"bg-transparent hover:bg-transparent active:bg-transparent focus:bg-transparent", | |
"rounded-none border-dashed border-y-4 border-transparent", | |
"dark:hover:border-ring dark:focus:border-ring", | |
"hover:border-foreground focus:border-foreground", | |
"active:border-transparent", | |
"data-[active=true]:border-none aria-[current=page]:border-none" | |
)} | |
{...props} | |
> | |
{children} | |
{isActive && ( | |
<div | |
className="absolute inset-0 w-full h-full pointer-events-none" | |
style={{ zIndex: 10 }} | |
> | |
<div | |
className="absolute top-0 left-0 w-full h-1.5 bg-foreground dark:bg-ring pointer-events-none" | |
aria-hidden="true" | |
/> | |
<div | |
className="absolute left-0 bottom-0 w-full h-1.5 bg-foreground dark:bg-ring pointer-events-none" | |
aria-hidden="true" | |
/> | |
<div | |
className="absolute top-1 -left-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none" | |
aria-hidden="true" | |
/> | |
<div | |
className="absolute bottom-1 -left-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none" | |
aria-hidden="true" | |
/> | |
<div | |
className="absolute top-1 -right-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none" | |
aria-hidden="true" | |
/> | |
<div | |
className="absolute bottom-1 -right-1 w-1.5 h-1/2 bg-foreground dark:bg-ring pointer-events-none" | |
aria-hidden="true" | |
/> | |
</div> | |
)} | |
</ShadcnPaginationLink> | |
); | |
} | |
function PaginationPrevious({ | |
...props | |
}: React.ComponentProps<typeof PaginationLink>) { | |
const { font, className } = props; | |
return ( | |
<PaginationLink | |
className={cn( | |
"relative group", | |
"flex flex-row w-full text-sm", | |
"bg-transparent hover:bg-transparent active:bg-transparent focus:bg-transparent", | |
"rounded-none border-dashed border-y-4 border-transparent", | |
"hover:border-foreground focus:border-foreground active:border-transparent", | |
"dark:hover:border-ring dark:focus:border-ring", | |
"data-[active=true]:border-none aria-[current=page]:border-none", | |
font !== "normal" && "retro", | |
className | |
)} | |
{...props} | |
> | |
<ChevronLeftIcon /> | |
<span className="hidden sm:block">Previous</span> | |
</PaginationLink> | |
); | |
} | |
function PaginationNext({ | |
...props | |
}: React.ComponentProps<typeof PaginationLink>) { | |
const { font, className } = props; | |
return ( | |
<PaginationLink | |
className={cn( | |
"relative group", | |
"flex flex-row w-full text-sm", | |
"bg-transparent hover:bg-transparent active:bg-transparent focus:bg-transparent", | |
"rounded-none border-dashed border-y-4 border-transparent", | |
"hover:border-foreground focus:border-foreground active:border-transparent", | |
"dark:hover:border-ring dark:focus:border-ring", | |
"data-[active=true]:border-none aria-[current=page]:border-none", | |
"flex flex-row text-sm w-full", | |
font !== "normal" && "retro", | |
className | |
)} | |
{...props} | |
> | |
<span className="hidden sm:block">Next</span> | |
<ChevronRightIcon /> | |
</PaginationLink> | |
); | |
} | |
function PaginationEllipsis({ ...props }: BitPaginationProps<"span">) { | |
const { font, className } = props; | |
return ( | |
<ShadcnPaginationEllipsis | |
className={cn(font !== "normal" && "retro", className)} | |
{...props} | |
> | |
<MoreHorizontal className={cn("size-7", "retro")} /> | |
<span className="sr-only">More pages</span> | |
</ShadcnPaginationEllipsis> | |
); | |
} | |
export { | |
Pagination, | |
PaginationContent, | |
PaginationLink, | |
PaginationItem, | |
PaginationPrevious, | |
PaginationNext, | |
PaginationEllipsis, | |
}; |
🤖 Prompt for AI Agents
In public/r/8bit-pagination.json around line 13, design props "variant" and
"font" are leaking into the DOM because they are included in {...props} and the
paginationVariants has no default font; destructure and remove variant and font
from the rest props before spreading to underlying Shadcn components (e.g.,
function signatures should extract { variant, font, className, ...rest } and
spread {...rest} to avoid passing variant/font to DOM) and update
paginationVariants.defaultVariants to include font: "retro" so font defaults to
retro when undefined.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey there! Thanks a lot for your contribution!
Good catch on those chevron icons, really appreciate the attention to detail. There’s just one thing we need to keep in mind: icons shouldn’t be exported from anywhere else in our project, because users of the 8bit components aren’t inside our codebase. Each icon needs to be included directly within its component, since that’s the only part users will be importing.
Your changes look great overall, we’ll just need to duplicate those SVGs in every component where they’re used.
Hey hey! |
Yeah normally, duplicating code isn’t ideal. The thing is, this isn’t actually about reusing icons inside our project. The main reason we keep the SVG directly inside each component is so that when a user imports just that one component from the library, it works immediately without pulling in other internal files or extra dependencies. If we moved icons into a shared internal file, then importing a single component would break unless the user also had access to our internal icon file (which they don’t). So in short, the duplication here is intentional, just to keep each component fully self contained for the end user. Working on a UI component library is a little bit different, we must not think locally :) |
The app currently uses two chevron styles: one from the lucide-react library and one custom. The custom variant is better suited to the 8-bit arcade style, so I standardize on it and replace existing usages accordingly.
Summary by CodeRabbit
Style
Refactor
Chores