-
-
Notifications
You must be signed in to change notification settings - Fork 43
New calendar component! #101
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
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughAdds a new Calendar React component (react-day-picker) with CalendarDayButton, exports Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant User
participant Calendar (wrapper)
participant DayPicker
participant CalendarDayButton
participant Button
User->>Calendar: mount(props: selected, defaultMonth, ...)
Calendar->>DayPicker: render with classNames, formatters, components map
DayPicker->>Calendar: needs day cell render
Calendar->>CalendarDayButton: render day(day, modifiers)
CalendarDayButton->>Button: render button (variant="ghost")
Button-->>CalendarDayButton: returns styled button element
CalendarDayButton-->>DayPicker: returns rendered cell
DayPicker-->>Calendar: calendar UI assembled
Calendar-->>User: interactive calendar displayed
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (5)
components/retroui/Button.tsx (1)
6-19: ExportingbuttonVariantsand addingghostvariant works wellMaking
buttonVariantspublic and adding aghostvariant fits the Calendar usage and keeps typing intact viaVariantProps<typeof buttonVariants>. If you notice low contrast or weak focus indication forghostin dark backgrounds, consider adding afocus-visible/outline treatment later, but it’s not blocking.content/docs/components/calendar.mdx (1)
1-9: Docs hook correctly into the showcase; copy is a bit narrowThe page correctly references the
"calendar-style-default"showcase and should integrate fine with the docs system. If you want this to read more generally, you might broaden the description beyond the “cancel subscription” use case and align thelastUpdateddate format with other docs, but that’s optional polish.preview/components/calendar-style-default.tsx (1)
1-18: Consider avoidingnew Date()at module scope for deterministic previewsThis example will work, but
const start = new Date()at module scope can diverge between build-time HTML and client runtime if the page is statically rendered, leading to small hydration warnings around month/day boundaries. For a docs preview, you might instead:
- Use a fixed date (e.g.
new Date(2025, 0, 1)) so the example is fully deterministic, or- Compute “today” inside the component or via
useState/useEffectif you explicitly want client-time behavior.Not blocking, but worth considering.
components/retroui/Calendar.tsx (2)
14-170: Calendar wrapper overDayPickeris solid; only minor API polish to considerThe
Calendarwrapper is well-structured: defaults (showOutsideDays,captionLayout,formatters) are sensible, user overrides forclassNames,formatters, andcomponentscorrectly win via spread order, andbuttonVariantis safely typed againstButton’svariant. A couple of small, non-blocking ideas:
- You might export a
type CalendarProps = React.ComponentProps<typeof DayPicker> & { buttonVariant?: React.ComponentProps<typeof Button>["variant"] }to make reuse and documentation of the prop surface easier.- If you eventually want consumers to control the day-cell styling as well as nav buttons via
buttonVariant, you could threadbuttonVariantdown intoCalendarDayButtoninstead of hardcoding"ghost"there, while still allowing a fullcomponents.DayButtonoverride.These are nice-to-have refinements; behavior as written looks correct.
172-208:CalendarDayButtonimplementation is correct; could share defaults and expose hooksThe custom
CalendarDayButtoncorrectly usesDayButtonprops, auto-focuses the focused day, and maps range/selection modifiers intodata-*attributes for styling. A few optional cleanups you could consider:
getDefaultClassNames()is called here and inCalendar; if you care about micro-optimizations, hoisting a sharedconst defaultClassNames = getDefaultClassNames()outside the components would avoid re-instantiation.- If you adopt the earlier suggestion to let
buttonVariantcontrol more than nav buttons, you could accept avariantprop here (defaulting to"ghost") and wire it up fromCalendar’scomponents.DayButtonoverride to make theming more flexible.No functional issues from this diff; the current behavior is fine.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (7)
components/retroui/Button.tsx(2 hunks)components/retroui/Calendar.tsx(1 hunks)config/components.ts(1 hunks)config/navigation.ts(2 hunks)content/docs/components/calendar.mdx(1 hunks)package.json(1 hunks)preview/components/calendar-style-default.tsx(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
preview/components/calendar-style-default.tsx (1)
components/retroui/Calendar.tsx (1)
Calendar(210-210)
components/retroui/Calendar.tsx (2)
components/retroui/Button.tsx (2)
Button(40-63)buttonVariants(6-32)lib/utils.ts (1)
cn(4-6)
🔇 Additional comments (3)
package.json (1)
44-44: react-day-picker dependency addition looks consistentThe new
react-day-pickerdependency aligns with the newCalendarimplementation and existing React/Next versions; no issues from this diff.config/components.ts (1)
289-293: Calendar example wiring is consistentThe
"calendar-style-default"example is correctly keyed, named, and wired topreview/components/calendar-style-default.tsxvialazy(...), matching the surrounding config pattern.config/navigation.ts (1)
52-55: Navigation updates for Calendar and charts look correctThe new Calendar entry (
${componentsRoute}/calendar) matches the MDX route, and dropping “New” tags from chart links while tagging Calendar as"New"is consistent with how other items are annotated. No issues spotted.Also applies to: 97-100
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: 2
🧹 Nitpick comments (1)
public/r/calendar.json (1)
150-172: Refactor CalendarDayButton className for improved maintainability.The className string spans multiple lines with complex nested selectors, making it difficult to read and maintain. Consider extracting the className logic into smaller, named constants or using a CSS-in-JS approach.
As a refactoring suggestion, you could extract the className logic:
const dayButtonClasses = { base: "font-sans flex justify-center items-center aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal flex-col gap-1 leading-none font-normal", states: { selectedSingle: "data-[selected-single=true]:shadow-md data-[selected-single=true]:outline-2 outline-border data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground", rangeMiddle: "data-[range-middle=true]:bg-secondary data-[range-middle=true]:hover:text-secondary-foreground data-[range-middle=true]:text-secondary-foreground", rangeStart: "data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground", rangeEnd: "data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground", focused: "group-data-[focused=true]/day:border-ring-1 group-data-[focused=true]/day:ring-ring/50 group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[2px]", } };This would make the component easier to update and test individual states.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
content/docs/components/calendar.mdx(1 hunks)public/r/button.json(1 hunks)public/r/calendar.json(1 hunks)public/r/sonner.json(1 hunks)public/r/table-with-sticky-header.json(1 hunks)public/r/table.json(1 hunks)registry.json(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- content/docs/components/calendar.mdx
🔇 Additional comments (5)
public/r/table-with-sticky-header.json (1)
12-12: Verify that removingoverflow-autodoesn't break the sticky header scroll behavior.Line 12 removes
overflow-autofrom the container, which means content exceeding the fixedh-96height won't scroll. This may be intentional, but please confirm the scrolling behavior is still correct. Similarly, removingw-fullcould affect layout in flex/grid contexts.Also applies to: 76-76
public/r/sonner.json (1)
12-16: Sonner toast button enhancements look good.The addition of hover effects (
hover:shadow-xs,hover:translate-[2px],transition-all) improves the toast button interactivity and aligns with the retro UI aesthetic.public/r/button.json (1)
6-6: Button API expansion is appropriate and well-designed.Exporting
buttonVariantsas public API and adding theghostvariant (bg-transparent hover:bg-accent) provides the necessary primitives for the Calendar component while maintaining backward compatibility. The ghost variant is semantically appropriate for calendar interactions.Also applies to: 18-18
public/r/calendar.json (2)
30-32: Verify RTL support implementation with complex Tailwind selectors.Lines 30-32 use
String.rawtemplate literals with complex RTL selectors (rtl:**:[.rdp-button_next>svg]:rotate-180). Please verify that these selectors are correctly parsed by Tailwind and that RTL mode properly reverses the chevron icons as intended.
38-42: Approve Calendar component overall structure.The Calendar component properly wraps
DayPickerwith comprehensive customization, including month dropdown formatting, responsive layout (flex-col md:flex-row), and proper class name merging with defaults. The integration with the Button component for navigation and the CalendarDayButton for day rendering is well-structured.
| { | ||
| "path": "components/retroui/Table.tsx", | ||
| "content": "import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst Table = React.forwardRef<\n HTMLTableElement,\n React.HTMLAttributes<HTMLTableElement>\n>(({ className, ...props }, ref) => (\n <div className=\"relative w-full overflow-auto\">\n <table\n ref={ref}\n className={cn(\"w-full caption-bottom text-sm border-2 shadow-lg\", className)}\n {...props}\n />\n </div>\n))\nTable.displayName = \"Table\"\n\nconst TableHeader = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <thead ref={ref} className={cn(\"[&_tr]:border-b bg-primary text-primary-foreground font-head\", className)} {...props} />\n))\nTableHeader.displayName = \"TableHeader\"\n\nconst TableBody = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <tbody\n ref={ref}\n className={cn(\"[&_tr:last-child]:border-0\", className)}\n {...props}\n />\n))\nTableBody.displayName = \"TableBody\"\n\nconst TableFooter = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <tfoot\n ref={ref}\n className={cn(\n \"border-t bg-accent font-medium [&>tr]:last:border-b-0\",\n className\n )}\n {...props}\n />\n))\nTableFooter.displayName = \"TableFooter\"\n\nconst TableRow = React.forwardRef<\n HTMLTableRowElement,\n React.HTMLAttributes<HTMLTableRowElement>\n>(({ className, ...props }, ref) => (\n <tr\n ref={ref}\n className={cn(\n \"border-b transition-colors hover:bg-primary/50 hover:text-primary-foreground data-[state=selected]:bg-muted\",\n className\n )}\n {...props}\n />\n))\nTableRow.displayName = \"TableRow\"\n\nconst TableHead = React.forwardRef<\n HTMLTableCellElement,\n React.ThHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <th\n ref={ref}\n className={cn(\n \"h-10 md:h-12 px-4 text-left align-middle font-medium text-primary-foreground [&:has([role=checkbox])]:pr-0\",\n className\n )}\n {...props}\n />\n))\nTableHead.displayName = \"TableHead\"\n\nconst TableCell = React.forwardRef<\n HTMLTableCellElement,\n React.TdHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <td\n ref={ref}\n className={cn(\"p-2 md:p-3 align-middle [&:has([role=checkbox])]:pr-0\", className)}\n {...props}\n />\n))\nTableCell.displayName = \"TableCell\"\n\nconst TableCaption = React.forwardRef<\n HTMLTableCaptionElement,\n React.HTMLAttributes<HTMLTableCaptionElement>\n>(({ className, ...props }, ref) => (\n <caption\n ref={ref}\n className={cn(\"my-2 text-sm text-muted-foreground\", className)}\n {...props}\n />\n))\nTableCaption.displayName = \"TableCaption\"\n\nconst TableObj = Object.assign(Table, {\n Header: TableHeader,\n Body: TableBody,\n Footer: TableFooter,\n Row: TableRow,\n Head: TableHead,\n Cell: TableCell,\n Caption: TableCaption,\n})\n\nexport {\n TableObj as Table,\n}", | ||
| "content": "import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst Table = React.forwardRef<\n HTMLTableElement,\n React.HTMLAttributes<HTMLTableElement>\n>(({ className, ...props }, ref) => (\n <div className=\"relative h-full w-full overflow-auto\">\n <table\n ref={ref}\n className={cn(\"w-full caption-bottom text-sm border-2 shadow-lg\", className)}\n {...props}\n />\n </div>\n))\nTable.displayName = \"Table\"\n\nconst TableHeader = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <thead ref={ref} className={cn(\"[&_tr]:border-b bg-primary text-primary-foreground font-head\", className)} {...props} />\n))\nTableHeader.displayName = \"TableHeader\"\n\nconst TableBody = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <tbody\n ref={ref}\n className={cn(\"[&_tr:last-child]:border-0\", className)}\n {...props}\n />\n))\nTableBody.displayName = \"TableBody\"\n\nconst TableFooter = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <tfoot\n ref={ref}\n className={cn(\n \"border-t bg-accent font-medium [&>tr]:last:border-b-0\",\n className\n )}\n {...props}\n />\n))\nTableFooter.displayName = \"TableFooter\"\n\nconst TableRow = React.forwardRef<\n HTMLTableRowElement,\n React.HTMLAttributes<HTMLTableRowElement>\n>(({ className, ...props }, ref) => (\n <tr\n ref={ref}\n className={cn(\n \"border-b transition-colors hover:bg-primary/50 hover:text-primary-foreground data-[state=selected]:bg-muted\",\n className\n )}\n {...props}\n />\n))\nTableRow.displayName = \"TableRow\"\n\nconst TableHead = React.forwardRef<\n HTMLTableCellElement,\n React.ThHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <th\n ref={ref}\n className={cn(\n \"h-10 md:h-12 px-4 text-left align-middle font-medium text-primary-foreground [&:has([role=checkbox])]:pr-0\",\n className\n )}\n {...props}\n />\n))\nTableHead.displayName = \"TableHead\"\n\nconst TableCell = React.forwardRef<\n HTMLTableCellElement,\n React.TdHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <td\n ref={ref}\n className={cn(\"p-2 md:p-3 align-middle [&:has([role=checkbox])]:pr-0\", className)}\n {...props}\n />\n))\nTableCell.displayName = \"TableCell\"\n\nconst TableCaption = React.forwardRef<\n HTMLTableCaptionElement,\n React.HTMLAttributes<HTMLTableCaptionElement>\n>(({ className, ...props }, ref) => (\n <caption\n ref={ref}\n className={cn(\"my-2 text-sm text-muted-foreground\", className)}\n {...props}\n />\n))\nTableCaption.displayName = \"TableCaption\"\n\nconst TableObj = Object.assign(Table, {\n Header: TableHeader,\n Body: TableBody,\n Footer: TableFooter,\n Row: TableRow,\n Head: TableHead,\n Cell: TableCell,\n Caption: TableCaption,\n})\n\nexport {\n TableObj as Table,\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.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for Table component imports and usage patterns
rg -nP --type=tsx --type=ts '(import.*Table|from.*Table|<Table|Table\.)' -C 2 | head -100Repository: Logging-Studio/RetroUI
Length of output: 93
🏁 Script executed:
#!/bin/bash
# First, let's see what file types exist in the codebase
echo "=== File types in repo ==="
fd -e ts -e js -e tsx -e jsx | head -20
echo ""
echo "=== Searching for Table usage ==="
# Search for Table component imports and usage
rg -n 'Table' --type=ts --type=js -C 2 | head -150Repository: Logging-Studio/RetroUI
Length of output: 12781
🏁 Script executed:
#!/bin/bash
# Find the Table component source
echo "=== Looking for Table component source ==="
fd -n 'table' -t f | grep -i 'table' | head -20
echo ""
echo "=== Search for more Table usages ==="
rg -n 'from.*Table|import.*Table' -C 1 | head -80
echo ""
echo "=== Check if public/r/table.json exists and its structure ==="
if [ -f "public/r/table.json" ]; then
head -20 public/r/table.json
fiRepository: Logging-Studio/RetroUI
Length of output: 20747
🏁 Script executed:
#!/bin/bash
# Check git diff for public/r/table.json to see what actually changed
echo "=== Git status ==="
git status public/r/table.json 2>&1 || echo "File may not be in git index"
echo ""
echo "=== Git diff for public/r/table.json ==="
git diff public/r/table.json 2>&1 | head -150
echo ""
echo "=== Git diff --cached (staged changes) ==="
git diff --cached public/r/table.json 2>&1 | head -150Repository: Logging-Studio/RetroUI
Length of output: 236
🏁 Script executed:
#!/bin/bash
# Check git log and branch info
echo "=== Git branch info ==="
git branch -v 2>&1 || echo "Cannot get branches"
echo ""
echo "=== Git log (last 10 commits) ==="
git log --oneline -10 2>&1
echo ""
echo "=== Current HEAD ==="
git rev-parse HEAD 2>&1
echo ""
echo "=== Check if there are other branches available ==="
git branch -a 2>&1 | head -20Repository: Logging-Studio/RetroUI
Length of output: 601
🏁 Script executed:
#!/bin/bash
# Search for Table usage in actual app pages (not preview)
echo "=== Table usage in app pages ==="
rg -n 'Table' app/ --type=ts --type=js 2>&1 | grep -v node_modules | head -80
echo ""
echo "=== Check MDX.tsx usage of Table ==="
cat components/MDX.tsx | head -50Repository: Logging-Studio/RetroUI
Length of output: 2810
🏁 Script executed:
#!/bin/bash
# Check how table-with-checkbox and table-style-default are rendered in the demo page
echo "=== Check demo page structure ==="
cat app/\(sink\)/demo/components/page.tsx | grep -A 10 "TableWithCheckbox\|TableStyleDefault" | head -40
echo ""
echo "=== Look for any container classes ==="
cat app/\(sink\)/demo/components/page.tsx | grep -B 5 "TableWithCheckbox\|TableStyleDefault" | head -30Repository: Logging-Studio/RetroUI
Length of output: 1465
Based on my verification, I can now provide the rewritten review comment.
The h-full wrapper will cause tables to collapse in unconstrained parent containers.
The Table wrapper div now includes h-full, which attempts to fill 100% of the parent's height. However, in the demo page (app/(sink)/demo/components/page.tsx), tables render directly in a container with no explicit height constraint (className="container max-w-6xl mx-auto space-y-6"). This will cause h-full to collapse the wrapper, breaking table rendering for TableStyleDefault and TableWithCheckbox. Only TableWithStickyHeader (wrapped in h-96) will render correctly.
Remove h-full from the wrapper className, or wrap all table implementations in explicit height-constrained containers before merging.
🤖 Prompt for AI Agents
public/r/table.json around line 10: the wrapper div includes "h-full" which
makes the table collapse when its parent has no explicit height; remove "h-full"
from the wrapper's className (i.e., change "relative h-full w-full
overflow-auto" to "relative w-full overflow-auto") so the table sizes naturally,
or alternatively ensure every consumer wraps the table in an explicit
height-constrained container; after the change, verify demo pages
(TableStyleDefault, TableWithCheckbox, TableWithStickyHeader) still render
correctly.
| { | ||
| "name": "calendar", | ||
| "type": "registry:component", | ||
| "title": "Calendar", | ||
| "description": "A customizable calendar component for showing dates. 📝", | ||
| "dependencies": ["react-day-picker", "lucide-react"], | ||
| "files": [ | ||
| { | ||
| "path": "components/retroui/Calendar.tsx", | ||
| "target": "components/retroui/Calendar.tsx", | ||
| "type": "registry:component" | ||
| }, | ||
| { | ||
| "path": "components/retroui/Button.tsx", | ||
| "target": "components/retroui/Button.tsx", | ||
| "type": "registry:component" | ||
| } | ||
| ] | ||
| }, |
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 duplicate Button.tsx from calendar registry entry.
Line 167-170 includes components/retroui/Button.tsx as a file in the calendar registry item, but Button is already registered as a separate component (lines 123-135). This creates duplication and API surface confusion. The Calendar component should import Button (which is already available), not include it in the calendar registry.
Remove the Button.tsx file entry from the calendar registry:
{
"name": "calendar",
"type": "registry:component",
"title": "Calendar",
"description": "A customizable calendar component for showing dates. 📝",
"dependencies": ["react-day-picker", "lucide-react"],
"files": [
{
"path": "components/retroui/Calendar.tsx",
"target": "components/retroui/Calendar.tsx",
"type": "registry:component"
}
- ,
- {
- "path": "components/retroui/Button.tsx",
- "target": "components/retroui/Button.tsx",
- "type": "registry:component"
- }
]
}📝 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.
| { | |
| "name": "calendar", | |
| "type": "registry:component", | |
| "title": "Calendar", | |
| "description": "A customizable calendar component for showing dates. 📝", | |
| "dependencies": ["react-day-picker", "lucide-react"], | |
| "files": [ | |
| { | |
| "path": "components/retroui/Calendar.tsx", | |
| "target": "components/retroui/Calendar.tsx", | |
| "type": "registry:component" | |
| }, | |
| { | |
| "path": "components/retroui/Button.tsx", | |
| "target": "components/retroui/Button.tsx", | |
| "type": "registry:component" | |
| } | |
| ] | |
| }, | |
| { | |
| "name": "calendar", | |
| "type": "registry:component", | |
| "title": "Calendar", | |
| "description": "A customizable calendar component for showing dates. 📝", | |
| "dependencies": ["react-day-picker", "lucide-react"], | |
| "files": [ | |
| { | |
| "path": "components/retroui/Calendar.tsx", | |
| "target": "components/retroui/Calendar.tsx", | |
| "type": "registry:component" | |
| } | |
| ] | |
| }, |
🤖 Prompt for AI Agents
In registry.json around lines 154 to 172, the calendar registry entry
incorrectly includes components/retroui/Button.tsx as a file dependency (lines
167-170); remove that Button.tsx file object from the calendar entry so the
calendar only lists its own component file(s) (keep
components/retroui/Calendar.tsx) and rely on the separately-registered Button
component instead, ensuring the JSON remains valid (no trailing commas) after
removal.
Summary by CodeRabbit
New Features
Documentation
Chores
Style
✏️ Tip: You can customize this high-level summary in your review settings.