Conversation
📝 WalkthroughWalkthroughReplaced framer-motion AnimatePresence/motion usage with plain DOM rendering and class-based show/hide (Tailwind) across calendar, note, header, and common components; removed related props from SwipeableContainer; added one MCP permission in .claude/settings.json. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 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 |
#317 Bundle Size — 2.08MiB (-0.07%).b705687(current) vs 43e577c main#315(baseline) Warning Bundle contains 2 duplicate packages – View duplicate packages Bundle metrics
Bundle size by type
Bundle analysis report Branch refactor/replace-framer-with-css... Project dashboard Generated by RelativeCI Documentation Report issue |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components/common/SwipeableContainer.tsx (1)
4-18:⚠️ Potential issue | 🔴 CriticalProps
directionandswipeKeyare declared but never used.The type definition (lines 7-8) still includes
directionandswipeKeyas required props, but the component destructuring (lines 13-17) omits them entirely. This creates:
- Dead code in the type definition
- A misleading API where callers must provide values that are silently ignored
- Orphaned state in call sites (
ImageCarousel.tsxandDayCalendar.tsx) that maintaindirectionstate no longer consumedRemove these props from the type to complete the refactor:
,
Proposed fix
type SwipeableContainerProps = { children: React.ReactNode; className?: string; - direction: number; - swipeKey: string; onSwipeLeft?: () => void; onSwipeRight?: () => void; };After this change, TypeScript will flag call sites that still pass these props, allowing you to clean up the orphaned
direction/swipeKeystate inImageCarousel.tsxandDayCalendar.tsx.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/common/SwipeableContainer.tsx` around lines 4 - 18, Remove the unused required props from the SwipeableContainer type: delete direction and swipeKey from SwipeableContainerProps and from any related prop documentation so the component signature matches the destructuring in SwipeableContainer; then update call sites (e.g., ImageCarousel.tsx and DayCalendar.tsx) that still pass direction or swipeKey to stop providing them and remove the now-orphaned state/vars there. Ensure no runtime logic depended on those props before deleting, and run TypeScript to catch remaining references.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/calendar/WeekCalendar.tsx`:
- Around line 431-438: The Tailwind animation classes used in WeekCalendar.tsx
("animate-in", "fade-in", "duration-500") require the tailwindcss-animate plugin
(or equivalent for Tailwind v4); install the plugin as a dependency, register it
in the Tailwind config plugins array, and add/import its CSS utilities into your
main stylesheet (e.g., src/index.css) so the classes applied in WeekCalendar.tsx
(the div wrapping OccurrenceChip) produce the intended animation; after changes,
rebuild/start the dev server and verify the animations appear on the
OccurrenceChip elements.
---
Outside diff comments:
In `@src/components/common/SwipeableContainer.tsx`:
- Around line 4-18: Remove the unused required props from the SwipeableContainer
type: delete direction and swipeKey from SwipeableContainerProps and from any
related prop documentation so the component signature matches the destructuring
in SwipeableContainer; then update call sites (e.g., ImageCarousel.tsx and
DayCalendar.tsx) that still pass direction or swipeKey to stop providing them
and remove the now-orphaned state/vars there. Ensure no runtime logic depended
on those props before deleting, and run TypeScript to catch remaining
references.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f5c244a4-549f-4960-9d12-f379961b475d
📒 Files selected for processing (8)
.claude/settings.jsonsrc/components/calendar/CalendarFilters.tsxsrc/components/calendar/DayCalendar.tsxsrc/components/calendar/MonthCalendarCell.tsxsrc/components/calendar/MonthCalendarGrid.tsxsrc/components/calendar/WeekCalendar.tsxsrc/components/common/SwipeableContainer.tsxsrc/components/note/NotePeriodPicker.tsx
| <div | ||
| key={habitId} | ||
| exit={{ scale: 0 }} | ||
| initial={{ opacity: 0 }} | ||
| animate={{ opacity: 1 }} | ||
| transition={{ duration: 0.5 }} | ||
| className="animate-in fade-in duration-500" | ||
| > | ||
| <OccurrenceChip | ||
| occurrences={habitOccurrences} | ||
| /> | ||
| </motion.div> | ||
| </div> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if tailwindcss-animate is installed
echo "=== Checking package.json for tailwindcss-animate ==="
cat package.json | jq '.dependencies["tailwindcss-animate"] // .devDependencies["tailwindcss-animate"] // "NOT FOUND"'
# Check if the plugin is configured anywhere
echo -e "\n=== Searching for tailwindcss-animate configuration ==="
rg -l "tailwindcss-animate" --type-add 'config:*.{js,ts,mjs,cjs,json,css}' --type config
# Check CSS files for animate plugin import
echo -e "\n=== Checking CSS files for plugin imports ==="
fd -e css --exec grep -l "animate" {} \; 2>/dev/null || echo "No matches"Repository: domhhv/habitrack
Length of output: 240
🏁 Script executed:
# Verify the animation classes in the specified file and context
echo "=== Checking WeekCalendar.tsx for animation classes ==="
sed -n '430,440p' src/components/calendar/WeekCalendar.tsx
# Search for all uses of animate-in or fade-in classes in the codebase
echo -e "\n=== Searching for animate-in or fade-in class usage ==="
rg "animate-in|fade-in" --type ts --type tsx -n
# Check tailwind config to see what plugins are configured
echo -e "\n=== Checking tailwind.config file ==="
fd "tailwind.config" -t f --exec cat {} \;Repository: domhhv/habitrack
Length of output: 770
🏁 Script executed:
# Search more broadly for tailwind config files
echo "=== Finding tailwind config files ==="
fd -i "tailwind" -t f
# Check if Tailwind v4 has animate-in natively by checking CSS output
echo -e "\n=== Checking for Tailwind config in tsconfig or other locations ==="
cat tsconfig.json 2>/dev/null | grep -A 5 -B 5 "tailwind\|path" || echo "No tailwind in tsconfig"
# Look for any CSS imports that might load animations
echo -e "\n=== Checking all CSS files for animation-related imports ==="
fd -e css -exec grep -H "animation\|animate" {} \;Repository: domhhv/habitrack
Length of output: 736
🏁 Script executed:
# Check Tailwind version in package.json
echo "=== Checking Tailwind version ==="
cat package.json | jq '.dependencies.tailwindcss, .devDependencies.tailwindcss'
# Correctly search CSS files
echo -e "\n=== Checking CSS files for animation configuration ==="
fd -e css -exec cat {} \;
# Check if Tailwind v4 includes animate-in natively
echo -e "\n=== Searching for animate-in in node_modules (if available) ==="
find node_modules/tailwindcss -name "*.js" -o -name "*.ts" 2>/dev/null | head -5 || echo "node_modules not fully available in sandbox"Repository: domhhv/habitrack
Length of output: 383
🌐 Web query:
Tailwind CSS v4 animate-in fade-in animation classes native support
💡 Result:
No, Tailwind CSS v4 does not have native support for "animate-in fade-in" animation classes. These classes come from the popular community plugin tailwindcss-animate (or its v4-compatible replacements like tw-animate-css), which provides utilities such as animate-in, fade-in, slide-in-from-top, etc., for entrance/exit animations commonly used in UI libraries like shadcn/ui. Tailwind CSS v4 core provides built-in animation utilities like animate-spin, animate-ping, animate-pulse, and animate-bounce, plus support for custom animations via @theme { --animate-*: ... @keyframes ... }. For fade-in effects, use transition-opacity with opacity-0 to opacity-100, or the new starting: variant with @starting-style for entry transitions without JS (e.g., starting:opacity-0 opacity-100 transition-opacity). To add animate-in/fade-in support in v4: - Install tw-animate-css: npm i -D tw-animate-css - Import in CSS: @import "tw-animate-css"; - Usage:
Citations:
- 1: https://tailwindcss.com/docs/animation
- 2: https://tailwindcss.com/blog/tailwindcss-v4
- 3: https://github.com/Wombosvideo/tw-animate-css
- 4: https://tailwindcss.com/docs/animation/
- 5: https://tailkits.com/blog/tailwind-animation-utilities
- 6: feat: add compatibility with tailwindcss v4 jamiebuilds/tailwindcss-animate#63
- 7: https://www.npmjs.com/package/tw-animate-css
Install and configure animation plugin for animate-in and fade-in classes.
The code uses animate-in fade-in duration-500 classes, which require the tailwindcss-animate plugin (or tw-animate-css for Tailwind v4). These classes are not native to Tailwind CSS v4 and are not currently configured in the project—the plugin is not installed in package.json and no imports exist in the CSS files.
Without the plugin, these animation classes will be silently ignored, resulting in no animation effect. Install the plugin, import it in src/index.css, and verify the animations render correctly.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/components/calendar/WeekCalendar.tsx` around lines 431 - 438, The
Tailwind animation classes used in WeekCalendar.tsx ("animate-in", "fade-in",
"duration-500") require the tailwindcss-animate plugin (or equivalent for
Tailwind v4); install the plugin as a dependency, register it in the Tailwind
config plugins array, and add/import its CSS utilities into your main stylesheet
(e.g., src/index.css) so the classes applied in WeekCalendar.tsx (the div
wrapping OccurrenceChip) produce the intended animation; after changes,
rebuild/start the dev server and verify the animations appear on the
OccurrenceChip elements.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/components/header/Header.tsx (1)
115-123: Consider extracting the mobile breakpoint check into a local constant.
screenWidth < 768is repeated across both button props and icon sizes. Pulling it into a singleisMobileActionsflag will keep the two buttons in sync and reduce future drift.Refactor sketch
const Header = () => { const { isDesktop, screenWidth } = useScreenWidth(); + const isMobileActions = screenWidth < 768; @@ - fullWidth={screenWidth < 768} + fullWidth={isMobileActions} onPress={dispatchNoteDrawerOpen} - radius={screenWidth < 768 ? 'full' : 'sm'} + radius={isMobileActions ? 'full' : 'sm'} @@ - size={screenWidth < 768 ? 12 : 16} + size={isMobileActions ? 12 : 16} @@ - fullWidth={screenWidth < 768} + fullWidth={isMobileActions} onPress={dispatchOccurrenceDrawerOpen} - radius={screenWidth < 768 ? 'full' : 'sm'} + radius={isMobileActions ? 'full' : 'sm'} @@ - size={screenWidth < 768 ? 12 : 16} + size={isMobileActions ? 12 : 16}Also applies to: 136-144
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/header/Header.tsx` around lines 115 - 123, Extract the repeated breakpoint check into a local boolean (e.g., isMobileActions) at the top of the Header component and replace all occurrences of `screenWidth < 768` with that flag so the button props and icon sizes stay in sync; update usages in the block around the Note button (fullWidth, radius, icon size, className) and the similar block around lines 136-144 to reference isMobileActions instead of repeating the literal expression.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/calendar/CalendarFilters.tsx`:
- Around line 125-132: The wrapper currently toggles visibility via CSS using
the isVisible variable in CalendarFilters, which leaves mounted Select
components (controlled by useDisclosure) running and can orphan HeroUI popovers;
change the component to return null early when !isVisible so the entire tree
(including the Selects and their popovers) unmounts instead of merely hiding via
the 'hidden' class—remove the conditional 'hidden ...' approach and add an early
guard like "if (!isVisible) return null" at the start of the CalendarFilters
render to ensure cleanup of useDisclosure-managed popovers.
In `@src/components/note/NotePeriodPicker.tsx`:
- Around line 139-159: The icon-only period navigation buttons in
NotePeriodPicker are missing accessible names; update the Button components (the
one wrapping CaretLeftIcon and the matching right-arrow button) to include
aria-label props that reflect the current period (use periodKind and periodDate
to build labels like "Previous day", "Next week", or include the formatted date
if desired) so screen readers announce their purpose; locate the buttons used
inside the onPress handlers that call handleChange and setPeriodDate and add
aria-label attributes accordingly, following the React Aria/HeroUI accessibility
pattern.
---
Nitpick comments:
In `@src/components/header/Header.tsx`:
- Around line 115-123: Extract the repeated breakpoint check into a local
boolean (e.g., isMobileActions) at the top of the Header component and replace
all occurrences of `screenWidth < 768` with that flag so the button props and
icon sizes stay in sync; update usages in the block around the Note button
(fullWidth, radius, icon size, className) and the similar block around lines
136-144 to reference isMobileActions instead of repeating the literal
expression.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: c387ac27-f1f9-49d5-86bd-76eec7ec0dca
📒 Files selected for processing (6)
src/components/calendar/CalendarFilters.tsxsrc/components/calendar/DayCalendar.tsxsrc/components/calendar/MonthCalendarCell.tsxsrc/components/calendar/WeekCalendar.tsxsrc/components/header/Header.tsxsrc/components/note/NotePeriodPicker.tsx
✅ Files skipped from review due to trivial changes (1)
- src/components/calendar/DayCalendar.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- src/components/calendar/WeekCalendar.tsx
- src/components/calendar/MonthCalendarCell.tsx
| const isVisible = (isDesktop || filters.isShownOnMobile) && !!user; | ||
|
|
||
| return ( | ||
| <AnimatePresence mode="wait"> | ||
| {(isDesktop || filters.isShownOnMobile) && user && ( | ||
| <motion.div | ||
| initial={{ | ||
| height: 0, | ||
| opacity: 0, | ||
| }} | ||
| className="flex max-w-full flex-col items-stretch justify-end gap-2 min-[450px]:flex-row lg:justify-between" | ||
| exit={{ | ||
| height: 0, | ||
| opacity: 0, | ||
| transition: { | ||
| height: { | ||
| duration: 0.4, | ||
| }, | ||
| opacity: { | ||
| duration: 0.25, | ||
| }, | ||
| }, | ||
| }} | ||
| animate={{ | ||
| height: 'auto', | ||
| opacity: 1, | ||
| transition: { | ||
| height: { | ||
| duration: 0.4, | ||
| }, | ||
| opacity: { | ||
| delay: 0.15, | ||
| duration: 0.25, | ||
| }, | ||
| }, | ||
| }} | ||
| > | ||
| <Select | ||
| size="sm" | ||
| radius="sm" | ||
| color="secondary" | ||
| variant="bordered" | ||
| selectionMode="multiple" | ||
| className="w-full md:w-50" | ||
| placeholder="Filter by habits" | ||
| selectedKeys={filters.habitIds} | ||
| isOpen={isHabitsFilterSelectOpen} | ||
| onChange={handleHabitsFilterChange} | ||
| onOpenChange={onHabitsFilterSelectOpenChange} | ||
| scrollShadowProps={{ | ||
| visibility: 'bottom', | ||
| }} | ||
| renderValue={(selectedHabits: SelectedItems<Habit>) => { | ||
| return ( | ||
| <CrossPlatformHorizontalScroll className="flex space-x-2"> | ||
| {selectedHabits.map(({ key }) => { | ||
| if (typeof key !== 'string' || !habits[key]) { | ||
| return null; | ||
| } | ||
| <div | ||
| className={cn( | ||
| 'hidden max-w-full flex-col items-stretch justify-end gap-2 min-[450px]:flex-row lg:justify-between', | ||
| isVisible && 'flex' | ||
| )} |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's find and read the CalendarFilters.tsx file
find . -name "CalendarFilters.tsx" -type fRepository: domhhv/habitrack
Length of output: 105
🏁 Script executed:
# Get the file size first to see if we can read it fully
wc -l src/components/calendar/CalendarFilters.tsxRepository: domhhv/habitrack
Length of output: 107
🏁 Script executed:
# Read the entire file to understand the implementation
cat -n src/components/calendar/CalendarFilters.tsxRepository: domhhv/habitrack
Length of output: 10440
🏁 Script executed:
# Check if there are any useEffect hooks or other mechanisms that handle visibility changes
grep -n "useEffect\|isVisible\|isOpen" src/components/calendar/CalendarFilters.tsxRepository: domhhv/habitrack
Length of output: 339
🏁 Script executed:
# Check the imports to understand what components are being used
head -n 50 src/components/calendar/CalendarFilters.tsxRepository: domhhv/habitrack
Length of output: 1536
CSS-hiding the filter bar leaves open Select popovers orphaned in the DOM.
Both Select components maintain controlled isOpen state via useDisclosure. Currently, the wrapper becomes display: none when isVisible is false, but the Select components remain mounted. If either Select is open when the wrapper becomes hidden, HeroUI will leave the popover/backdrop mounted in the DOM (since it renders via a portal), creating an orphaned UI element.
Return null when !isVisible instead of using CSS to hide the wrapper, ensuring the entire component tree unmounts and cleans up any open popovers.
🩹 Suggested change
const isVisible = (isDesktop || filters.isShownOnMobile) && !!user;
+ if (!isVisible) {
+ return null;
+ }
+
return (
- <div
- className={cn(
- 'hidden max-w-full flex-col items-stretch justify-end gap-2 min-[450px]:flex-row lg:justify-between',
- isVisible && 'flex'
- )}
- >
+ <div className="flex max-w-full flex-col items-stretch justify-end gap-2 min-[450px]:flex-row lg:justify-between">Also applies to: 143-145, 237-239
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/components/calendar/CalendarFilters.tsx` around lines 125 - 132, The
wrapper currently toggles visibility via CSS using the isVisible variable in
CalendarFilters, which leaves mounted Select components (controlled by
useDisclosure) running and can orphan HeroUI popovers; change the component to
return null early when !isVisible so the entire tree (including the Selects and
their popovers) unmounts instead of merely hiding via the 'hidden' class—remove
the conditional 'hidden ...' approach and add an early guard like "if
(!isVisible) return null" at the start of the CalendarFilters render to ensure
cleanup of useDisclosure-managed popovers.
| <Button | ||
| size="sm" | ||
| isIconOnly | ||
| variant="flat" | ||
| className="h-full w-5! min-w-auto" | ||
| onPress={() => { | ||
| void handleChange(() => { | ||
| switch (periodKind) { | ||
| case 'day': | ||
| return setPeriodDate(periodDate.subtract({ days: 1 })); | ||
|
|
||
| case 'week': | ||
| return setPeriodDate(periodDate.subtract({ weeks: 1 })); | ||
|
|
||
| case 'month': | ||
| return setPeriodDate(periodDate.subtract({ months: 1 })); | ||
| } | ||
|
|
||
| return ''; | ||
| }} | ||
| renderThumb={(props) => { | ||
| return ( | ||
| <div | ||
| {...props} | ||
| className="bg-primary-600 top-1/2 left-1/2 mx-auto flex h-8 w-8 items-center justify-center rounded-full text-white" | ||
| > | ||
| {periodKind === 'day' && <SunIcon size={20} />} | ||
| {periodKind === 'week' && <NumberSevenIcon size={20} />} | ||
| {periodKind === 'month' && <CalendarDotsIcon size={20} />} | ||
| </div> | ||
| ); | ||
| }} | ||
| onChange={(value) => { | ||
| const nextValue = Array.isArray(value) ? value[0] : value; | ||
|
|
||
| void handleChange(() => { | ||
| switch (nextValue) { | ||
| case 1: | ||
| setPeriodDate(periodDate); | ||
| setPeriodKind('day'); | ||
| break; | ||
|
|
||
| case 2: { | ||
| const weekStart = startOfWeek( | ||
| periodDate, | ||
| locale, | ||
| firstDayOfWeek | ||
| ); | ||
| setPeriodDate(weekStart); | ||
| setPeriodKind('week'); | ||
| break; | ||
| } | ||
|
|
||
| case 3: { | ||
| const monthStart = startOfMonth(periodDate); | ||
| setPeriodDate(monthStart); | ||
| setPeriodKind('month'); | ||
| break; | ||
| } | ||
| } | ||
| }); | ||
| }} | ||
| /> | ||
| <div className="flex gap-1"> | ||
| <Button | ||
| size="sm" | ||
| isIconOnly | ||
| variant="flat" | ||
| className="h-full w-5! min-w-auto" | ||
| onPress={() => { | ||
| void handleChange(() => { | ||
| switch (periodKind) { | ||
| case 'day': | ||
| return setPeriodDate(periodDate.subtract({ days: 1 })); | ||
|
|
||
| case 'week': | ||
| return setPeriodDate(periodDate.subtract({ weeks: 1 })); | ||
|
|
||
| case 'month': | ||
| return setPeriodDate(periodDate.subtract({ months: 1 })); | ||
| } | ||
| }); | ||
| }} | ||
| > | ||
| <CaretLeftIcon /> | ||
| </Button> | ||
| <RangeCalendar | ||
| isReadOnly | ||
| focusedValue={periodDate} | ||
| firstDayOfWeek={firstDayOfWeek} | ||
| value={{ | ||
| end: endRange, | ||
| start: periodDate, | ||
| }} | ||
| classNames={{ | ||
| cell: '[&_span]:cursor-default! cursor-default', | ||
| nextButton: 'hidden', | ||
| prevButton: 'hidden', | ||
| }} | ||
| /> | ||
| <Button | ||
| size="sm" | ||
| isIconOnly | ||
| variant="flat" | ||
| className="h-full w-5! min-w-auto" | ||
| onPress={() => { | ||
| void handleChange(() => { | ||
| switch (periodKind) { | ||
| case 'day': | ||
| return setPeriodDate(periodDate.add({ days: 1 })); | ||
|
|
||
| case 'week': | ||
| return setPeriodDate(periodDate.add({ weeks: 1 })); | ||
|
|
||
| case 'month': | ||
| return setPeriodDate(periodDate.add({ months: 1 })); | ||
| } | ||
| }); | ||
| }} | ||
| > | ||
| <CaretRightIcon /> | ||
| </Button> | ||
| </div> | ||
| </motion.div> | ||
| )} | ||
| </AnimatePresence> | ||
| }); | ||
| }} | ||
| > | ||
| <CaretLeftIcon /> |
There was a problem hiding this comment.
Label the icon-only period buttons.
Both isIconOnly buttons are missing an accessible name, so screen readers will only announce a generic “button”. Add aria-labels that reflect the current period.
♿ Proposed fix
<Button
+ aria-label={`Go to previous ${periodKind}`}
size="sm"
isIconOnly
variant="flat"
className="h-full w-5! min-w-auto"
@@
<Button
+ aria-label={`Go to next ${periodKind}`}
size="sm"
isIconOnly
variant="flat"
className="h-full w-5! min-w-auto"Also applies to: 175-195
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/components/note/NotePeriodPicker.tsx` around lines 139 - 159, The
icon-only period navigation buttons in NotePeriodPicker are missing accessible
names; update the Button components (the one wrapping CaretLeftIcon and the
matching right-arrow button) to include aria-label props that reflect the
current period (use periodKind and periodDate to build labels like "Previous
day", "Next week", or include the formatted date if desired) so screen readers
announce their purpose; locate the buttons used inside the onPress handlers that
call handleChange and setPeriodDate and add aria-label attributes accordingly,
following the React Aria/HeroUI accessibility pattern.
Description
Remove framer-motion (motion/AnimatePresence) usage across several UI components and replace animated wrappers with CSS utility classes and simple layout toggles. Updated components: CalendarFilters, DayCalendar, MonthCalendarCell, MonthCalendarGrid, WeekCalendar, NotePeriodPicker and common/SwipeableContainer — imports and motion variants/props (e.g. direction, swipeKey, slideVariants) were removed and replaced with class-based transitions (animate-in, fade-in, transition-all, grid row toggles, overflow-hidden). Also added cn imports where needed for class composition. Additionally updated .claude/settings.json to include the new "mcp__heroui-migration__get_migration_workflow" hook.
Type of Change
Checklist
Summary by CodeRabbit
Refactor
Chores