Skip to content

refactor: extract reusable utilities and simplify logic#75

Merged
shubug1015 merged 4 commits into
mainfrom
refactor/utility-separation-and-enhancement
Jan 12, 2026
Merged

refactor: extract reusable utilities and simplify logic#75
shubug1015 merged 4 commits into
mainfrom
refactor/utility-separation-and-enhancement

Conversation

@shubug1015
Copy link
Copy Markdown
Owner

@shubug1015 shubug1015 commented Jan 12, 2026

Description

This PR completes refactoring, focusing on improving reusability and reducing function complexity across core animation logic.

  1. Utility extraction & reuse

    • Extracted countNodes into a standalone, reusable utility.
    • Simplified useResolvedMotion by extracting mergePresets into a dedicated helper function.
    • Reduced coupling between hooks and internal logic, improving testability and clarity.
  2. Function complexity reduction

    • Refactored generateAnimation by splitting its logic into:
      • processStandardAnimation
      • processCustomAnimation
    • Removed conditional complexity from the main function, making each animation path explicit and easier to reason about.
    • Replaced remaining magic strings with centralized constants.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactor

Checklist

  • My code follows the project style guidelines
  • I performed a self-review of my own code
  • I added tests that prove my fix is effective
  • I added necessary documentation

Summary by CodeRabbit

  • New Features

    • Added a combined standard animation type.
    • Added a utility to count React nodes.
  • Tests

    • Comprehensive tests for the node-counting utility.
    • Added test ensuring multiple animation presets merge correctly.
  • Refactor

    • Internal reorganization of animation processing and hook logic for clearer structure.

✏️ Tip: You can customize this high-level summary in your review settings.

@shubug1015 shubug1015 requested a review from kjyong702 January 12, 2026 08:31
@shubug1015 shubug1015 self-assigned this Jan 12, 2026
@shubug1015 shubug1015 added the refactor Refactor code label Jan 12, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 12, 2026

📝 Walkthrough

Walkthrough

Extracts and centralizes internal utilities and refactors animation logic: adds a reusable countNodes utility, introduces StandardAnimation type, modularizes generateAnimation, and moves preset merging into mergePresets — behavior preserved.

Changes

Cohort / File(s) Summary
New countNodes utility
src/utils/countNodes/countNodes.ts, src/utils/countNodes/countNodes.spec.tsx, src/utils/countNodes/index.ts
Adds countNodes pure utility with comprehensive tests and re-export for reuse.
Animation generation refactoring
src/utils/generateAnimation/generateAnimation.ts
Replaces reduce-based aggregation with processStandardAnimation and processCustomAnimation processors; imports StandardAnimation; no external API change.
Motion resolution refactoring
src/hooks/useResolvedMotion/useResolvedMotion.ts, src/hooks/useResolvedMotion/useResolvedMotion.spec.ts
Extracts preset merging into mergePresets; adds test validating merging multiple presets.
Type definitions
src/types/animations.ts
Adds export type StandardAnimation = ... union of standard animation types.
Hook integration
src/hooks/useAnimatedChildren/useAnimatedChildren.tsx
Replaces local node-counting helper with import from src/utils/countNodes.

Sequence Diagram(s)

(omitted — changes are refactors and a utility addition; no multi-component control flow requiring diagram)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • kjyong702
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main refactoring objectives: extracting reusable utilities (countNodes, mergePresets) and simplifying function complexity (generateAnimation), which are the core changes throughout the changeset.
Description check ✅ Passed The description comprehensively covers the refactoring scope, clearly documents extracted utilities and simplified functions, marks the appropriate type of change (Refactor), and checks relevant checklist items, aligning well with the description template requirements.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2f9f418 and c8bee02.

📒 Files selected for processing (1)
  • src/utils/countNodes/countNodes.spec.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/utils/countNodes/countNodes.spec.tsx

Comment @coderabbitai help to get the list of available commands and usage tips.

@shubug1015 shubug1015 marked this pull request as ready for review January 12, 2026 08:32
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @src/hooks/useResolvedMotion/useResolvedMotion.ts:
- Line 28: The call to mergePresets inside useResolvedMotion occurs before the
const arrow mergePresets is declared, causing a Temporal Dead Zone error; fix it
by moving the mergePresets declaration above the useResolvedMotion hook (or
convert mergePresets to a hoisted function declaration) so mergePresets is
defined before being called, ensuring the useResolvedMotion function can call
mergePresets without runtime ReferenceError.

In @src/utils/countNodes/countNodes.spec.tsx:
- Around line 87-90: The test under getNodes/countNodes is misnamed or has the
wrong expectation: the spec "should return 0 for an empty array" calls
getNodes(<></>) and expects countNodes(nodes) toBe(1); change the expectation to
0 (or update the test name if 1 was intentional). Locate the test case
referencing getNodes and countNodes in src/utils/countNodes/countNodes.spec.tsx
and set expect(countNodes(nodes)).toBe(0) to match an empty fragment producing
an empty array.
🧹 Nitpick comments (1)
src/hooks/useResolvedMotion/useResolvedMotion.spec.ts (1)

41-49: Good test coverage for the new merging behavior.

The test validates that multiple presets are correctly merged into a single motion configuration. This aligns well with the mergePresets helper introduction.

Consider adding an edge case test for overlapping presets (e.g., ['fade-in', 'fade-out']) to document the expected overwrite behavior.

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5d77740 and 2f9f418.

📒 Files selected for processing (8)
  • src/hooks/useAnimatedChildren/useAnimatedChildren.tsx
  • src/hooks/useResolvedMotion/useResolvedMotion.spec.ts
  • src/hooks/useResolvedMotion/useResolvedMotion.ts
  • src/types/animations.ts
  • src/utils/countNodes/countNodes.spec.tsx
  • src/utils/countNodes/countNodes.ts
  • src/utils/countNodes/index.ts
  • src/utils/generateAnimation/generateAnimation.ts
🧰 Additional context used
🧬 Code graph analysis (4)
src/utils/countNodes/countNodes.ts (1)
src/utils/typeGuards/typeGuards.ts (2)
  • isNullishNode (21-23)
  • isElementWithChildren (32-39)
src/utils/countNodes/countNodes.spec.tsx (1)
src/utils/countNodes/countNodes.ts (1)
  • countNodes (13-29)
src/utils/generateAnimation/generateAnimation.ts (2)
src/constants/animationDefaults.ts (1)
  • ANIMATION_DEFAULTS (19-22)
src/types/animations.ts (2)
  • CustomAnimation (141-143)
  • StandardAnimation (123-130)
src/hooks/useResolvedMotion/useResolvedMotion.ts (3)
src/types/common.ts (2)
  • Preset (67-83)
  • Motion (51-60)
src/hooks/useResolvedMotion/motionMap.ts (1)
  • motionMap (6-23)
src/hooks/useResolvedMotion/index.ts (1)
  • motionMap (1-1)
🔇 Additional comments (9)
src/types/animations.ts (1)

119-131: LGTM!

The StandardAnimation union type is a clean abstraction that consolidates all standard animation types. This improves type safety in generateAnimation.ts and makes the animation type hierarchy more explicit.

src/hooks/useResolvedMotion/useResolvedMotion.ts (1)

41-45: Helper logic is correct.

The mergePresets implementation cleanly combines preset configurations. Note that if multiple presets define the same animation type (e.g., two presets both defining fade), the later preset will overwrite the earlier one—this appears to be the intended behavior based on the reduce pattern.

src/utils/generateAnimation/generateAnimation.ts (3)

26-45: Clean refactor to processor-based architecture.

The decomposition into processStandardAnimation and processCustomAnimation makes the animation type handling explicit and easier to extend. The forEach loop with early return for null/undefined is cleaner than the previous reduce-based approach.


50-69: Well-structured standard animation processor.

The logic correctly extracts animation parameters, calculates timing, and generates both the animation string and CSS custom properties. The separation of concerns makes unit testing and future modifications straightforward.


71-81: Consistent interface with standard processor.

Returning an empty customProps object maintains a uniform return shape across both processors, which simplifies the calling code and supports future extensibility if custom animations need CSS properties.

src/utils/countNodes/index.ts (1)

1-1: LGTM!

Clean barrel export for the new countNodes utility. This establishes a clear public API for the extracted utility.

src/hooks/useAnimatedChildren/useAnimatedChildren.tsx (1)

5-5: LGTM! Clean extraction of node counting logic.

The import change correctly sources countNodes from the new centralized utility, aligning with the PR's goal of improving reusability. The function signature and usage remain consistent.

src/utils/countNodes/countNodes.ts (1)

13-29: Clean, well-documented utility function.

The implementation correctly:

  • Iterates using Children.forEach for proper ReactNode handling
  • Skips nullish nodes appropriately
  • Counts both parent elements and recursively traverses their children
  • Returns the total count as a pure function

The logic properly counts each non-nullish node once, including both container elements and their nested children, which matches the animation sequencing requirements in useAnimatedChildren.

src/utils/countNodes/countNodes.spec.tsx (1)

5-132: Comprehensive test coverage for the utility.

The test suite covers a good range of scenarios:

  • Simple text and element nodes
  • Nested and deeply nested structures
  • Mixed content
  • Arrays and null/undefined handling
  • Functional component children
  • Complex real-world structures

This provides solid confidence in the countNodes utility's correctness.

Comment thread src/hooks/useResolvedMotion/useResolvedMotion.ts
Comment thread src/utils/countNodes/countNodes.spec.tsx Outdated
@codecov
Copy link
Copy Markdown

codecov Bot commented Jan 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@shubug1015 shubug1015 merged commit 673e9c6 into main Jan 12, 2026
10 checks passed
@shubug1015 shubug1015 deleted the refactor/utility-separation-and-enhancement branch January 17, 2026 10:45
@coderabbitai coderabbitai Bot mentioned this pull request Jan 18, 2026
9 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactor Refactor code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant