Skip to content

refactor: migrate styling from scss to vanilla-extract#68

Draft
shubug1015 wants to merge 6 commits intomainfrom
feat/adopt-vanilla-extract
Draft

refactor: migrate styling from scss to vanilla-extract#68
shubug1015 wants to merge 6 commits intomainfrom
feat/adopt-vanilla-extract

Conversation

@shubug1015
Copy link
Copy Markdown
Owner

@shubug1015 shubug1015 commented Dec 23, 2025

Description

This PR refactors the existing SCSS-based styling system to Vanilla Extract in order to make react-textmotion more suitable as a reusable library.

Key improvements include:

  • Eliminated global CSS class usage to prevent style collisions in consuming applications
  • Introduced fully type-safe styling through Vanilla Extract
  • Improved tree-shaking potential by generating static, build-time CSS
  • Co-located styles with their corresponding components for better maintainability
  • Removed the need for runtime CSS-in-JS dependencies, keeping the library lightweight for consumers

No changes were made to the public API or component behavior.

Related Issue

Closes #67

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

  • Chores
    • Migrated styling infrastructure from SCSS and PostCSS to Vanilla Extract CSS-in-JS system.
    • Updated Jest and Rollup configurations to support the new styling framework.
    • Refactored animation definitions to work with the new styling system.

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

@shubug1015 shubug1015 requested a review from kjyong702 December 23, 2025 11:59
@shubug1015 shubug1015 self-assigned this Dec 23, 2025
@shubug1015 shubug1015 added the refactor Refactor code label Dec 23, 2025
@codecov
Copy link
Copy Markdown

codecov bot commented Dec 23, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@shubug1015
Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 9, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 9, 2026

📝 Walkthrough

Walkthrough

This PR migrates the styling system from SCSS to Vanilla Extract, replacing global class names with type-safe, locally-scoped CSS modules. Build tooling is updated to use Vanilla Extract transformers, dependencies are swapped from SCSS to Vanilla Extract packages, and components are refactored to import and apply style objects instead of string class names.

Changes

Cohort / File(s) Summary
Build & Dependency Configuration
jest.config.ts, package.json, rollup.config.js, tsconfig.json
Updated Jest to use @vanilla-extract/jest-transform for CSS TS files; replaced postcss/sass dependencies with Vanilla Extract packages; removed postcss plugin from Rollup; enabled noEmit and allowImportingTsExtensions in TypeScript config.
New Vanilla Extract Style Modules
src/styles/animations.css.ts, src/styles/motion.css.ts
Created new Vanilla Extract style definitions with keyframes (fadeIn, fadeOut, slideUp/Down/Left/Right, scaleIn/Out, rotateClockwise/Counterclockwise, bounceIn/Out, elasticIn/Out, flipIn/Out) and motion display styles (motion, inanimate).
Removed SCSS Styles
src/styles/animations.scss, src/styles/motion.scss
Deleted legacy SCSS keyframe and class definitions.
Component Style Integration
src/components/AnimatedSpan/AnimatedSpan.tsx, src/components/NodeMotion/NodeMotion.tsx, src/components/TextMotion/TextMotion.tsx
Updated components to import and apply styles from CSS modules (e.g., styles.motion, styles.inanimate) instead of hardcoded string class names.
Type & Animation Utilities
src/types/animations.ts, src/utils/generateAnimation/keyframesMap.ts, src/utils/generateAnimation/generateAnimation.ts, src/utils/generateAnimation/generateAnimation.spec.ts
Added AnimationName type union; created keyframesMap constant mapping animation categories to keyframe objects; updated generateAnimation.ts to use keyframe lookup instead of string concatenation; updated test mocks to reflect new keyframe mapping.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • PR #73: Directly modifies src/utils/generateAnimation/generateAnimation.ts to inject centralized constants and rename internal variables, overlapping with this PR's animation utility refactoring.

Suggested reviewers

  • kjyong702
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the primary change: migrating styling from SCSS to Vanilla Extract.
Description check ✅ Passed The description covers all required template sections with detailed rationale, checked appropriate change type, and notes on completed checklist items.
Linked Issues check ✅ Passed All code changes comprehensively address the five primary objectives from issue #67: local scoping via CSS modules, type-safe styling imports, static build-time CSS, co-located styles, and zero runtime CSS-in-JS dependencies.
Out of Scope Changes check ✅ Passed All changes are directly aligned with the styling migration objective. tsconfig.json updates enable proper TypeScript extension imports for CSS modules, which is necessary infrastructure for the refactor.
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

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

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

🤖 Fix all issues with AI agents
In @package.json:
- Around line 63-65: Update the three vanilla-extract dependency entries in
package.json to published versions to avoid npm install failures: change
"@vanilla-extract/css" version to "1.17.4", "@vanilla-extract/jest-transform" to
"1.1.17", and "@vanilla-extract/rollup-plugin" to "1.4.2" (replace the current
^1.17.5, ^1.1.19, ^1.5.0 entries respectively); run a fresh npm install and
lockfile update (npm install or yarn install) to regenerate
package-lock.json/yarn.lock and verify the project builds.

In @src/styles/animations.css.ts:
- Around line 79-87: The flip animations flipIn and flipOut hardcode
perspective(40rem); change this to use a pixel-based default and make it
customizable via a CSS variable (e.g., var(--flip-perspective, 600px)) so the
perspective uses a standard px unit and a reasonable default value; update both
flipIn and flipOut to reference that variable instead of 40rem and ensure the
variable name is documented/consistent with other style vars.
🧹 Nitpick comments (3)
src/types/animations.ts (1)

1-1: Consider exporting AnimationName from the public API.

If consumers might benefit from referencing this type (e.g., for type guards or custom utilities), ensure it's re-exported from the main entry point.

#!/bin/bash
# Description: Check if AnimationName is exported from the main entry point

# Find the main entry point and check exports
fd -t f 'index.ts' -x rg -n "export.*AnimationName"
src/utils/generateAnimation/keyframesMap.ts (1)

4-35: Consider adding type safety for animation variant keys.

The keyframesMap uses plain strings for variant keys ('in', 'out', 'up', etc.), which could allow typos to slip through at compile time. Consider creating specific variant types for each animation category to improve type safety.

🔧 Optional enhancement for stronger typing

Define variant types in src/types/animations.ts:

export type FadeVariant = 'in' | 'out';
export type SlideVariant = 'up' | 'down' | 'left' | 'right';
export type ScaleVariant = 'in' | 'out';
export type RotateVariant = 'clockwise' | 'counterclockwise';
export type BounceVariant = 'in' | 'out';
export type ElasticVariant = 'in' | 'out';
export type FlipVariant = 'in' | 'out';

export type AnimationVariants = {
  fade: FadeVariant;
  slide: SlideVariant;
  scale: ScaleVariant;
  rotate: RotateVariant;
  bounce: BounceVariant;
  elastic: ElasticVariant;
  flip: FlipVariant;
};

Then update the map type:

-export const keyframesMap: Record<AnimationName, Record<string, string>> = {
+export const keyframesMap: {
+  [K in AnimationName]: Record<AnimationVariants[K], string>
+} = {
   fade: {
     in: animations.fadeIn,
     out: animations.fadeOut,
   },
   // ... rest of the map
 };
src/styles/animations.css.ts (1)

43-51: Inconsistent CSS variable pattern in rotate animations.

The rotate animations wrap the entire rotate() function inside the CSS variable (e.g., var(--rotate-from, rotate(0deg))), while other animations (slide, scale) only put the numeric value in the variable. This inconsistency makes the rotate animations harder to customize—users must provide the full transform function rather than just an angle value.

🔧 Align rotate animations with the pattern used in other animations
 export const rotateClockwise = keyframes({
-  from: { transform: 'var(--rotate-from, rotate(0deg))' },
-  to: { transform: 'var(--rotate-to, rotate(360deg))' },
+  from: { transform: 'rotate(var(--rotate-from, 0deg))' },
+  to: { transform: 'rotate(var(--rotate-to, 360deg))' },
 });

 export const rotateCounterclockwise = keyframes({
-  from: { transform: 'var(--rotate-from, rotate(360deg))' },
-  to: { transform: 'var(--rotate-to, rotate(0deg))' },
+  from: { transform: 'rotate(var(--rotate-from, 360deg))' },
+  to: { transform: 'rotate(var(--rotate-to, 0deg))' },
 });
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 56684b1 and a9fdf8f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (15)
  • jest.config.ts
  • package.json
  • rollup.config.js
  • src/components/AnimatedSpan/AnimatedSpan.tsx
  • src/components/NodeMotion/NodeMotion.tsx
  • src/components/TextMotion/TextMotion.tsx
  • src/styles/animations.css.ts
  • src/styles/animations.scss
  • src/styles/motion.css.ts
  • src/styles/motion.scss
  • src/types/animations.ts
  • src/utils/generateAnimation/generateAnimation.spec.ts
  • src/utils/generateAnimation/generateAnimation.ts
  • src/utils/generateAnimation/keyframesMap.ts
  • tsconfig.json
💤 Files with no reviewable changes (2)
  • src/styles/motion.scss
  • src/styles/animations.scss
🧰 Additional context used
🧬 Code graph analysis (2)
src/utils/generateAnimation/generateAnimation.ts (2)
src/utils/generateAnimation/keyframesMap.ts (1)
  • keyframesMap (4-35)
src/types/animations.ts (1)
  • AnimationName (1-1)
src/utils/generateAnimation/keyframesMap.ts (1)
src/types/animations.ts (1)
  • AnimationName (1-1)
🔇 Additional comments (23)
rollup.config.js (1)

8-8: LGTM! Vanilla Extract plugin correctly integrated.

The vanillaExtractPlugin is properly imported and added to the Rollup pipeline, enabling .css.ts file processing as part of the migration from SCSS.

Also applies to: 54-54

tsconfig.json (1)

16-16: Appropriate setting for Vanilla Extract imports.

The allowImportingTsExtensions option enables importing .css.ts files, which is necessary for the Vanilla Extract migration. However, note that the conventional approach is to import these files without the .ts extension (e.g., from './styles.css'), letting the bundler resolve the .css.ts file.

jest.config.ts (2)

7-10: LGTM! Transform configuration correctly handles Vanilla Extract files.

The transform configuration properly routes .css.ts files through the Vanilla Extract Jest transformer while maintaining ts-jest for TypeScript files. This is the correct setup for testing components that import Vanilla Extract styles.


14-14: Appropriate exclusion of CSS files from coverage.

Excluding src/styles/**/*.css.ts from coverage collection is correct, as Vanilla Extract style files contain styling declarations rather than testable logic.

src/components/AnimatedSpan/AnimatedSpan.tsx (2)

36-36: LGTM! CSS module class correctly applied.

The className={styles.motion} correctly applies the Vanilla Extract style to the animated span, properly replacing the previous SCSS-based styling approach.


3-3: The import pattern in this codebase is already correct and follows Vanilla Extract best practices. The .css.ts extension is the official Vanilla Extract convention for authoring style files, and the codebase consistently uses this import pattern across all files (4 instances, 100% uniform). While some toolchains optionally allow importing from .css without the .ts suffix, this project's bundler clearly requires the full .css.ts path, as evidenced by the absence of any .css-only imports in the codebase. Changing to the suggested .css import path could break the build if the resolver doesn't support stripping the .ts extension.

Likely an incorrect or invalid review comment.

src/components/NodeMotion/NodeMotion.tsx (3)

7-7: LGTM! Vanilla Extract import added correctly.

The import of Vanilla Extract styles replaces the previous SCSS imports, providing type-safe style references.


118-118: LGTM! Type-safe className application.

The styles.inanimate reference provides compile-time type safety and eliminates the risk of typos in class names.


111-111: The review concern is invalid—this is a new component, not a modification.

The git history shows NodeMotion.tsx is a new file being added, not an existing component being modified. The animated Tag element was never assigned a className in the initial implementation, so there is no className being removed. The codebase contains no references to "node-motion" as a CSS class name.

Likely an incorrect or invalid review comment.

src/utils/generateAnimation/generateAnimation.spec.ts (2)

163-163: LGTM! Correct test expectation for prototype filtering.

The empty string expectation confirms that generateAnimation correctly ignores enumerable properties from the prototype chain using hasOwnProperty filtering.


5-22: Mock is complete and covers all animation exports from animations.css.ts.

The jest.mock includes all 16 animation keyframes exported from the animations file (fadeIn, fadeOut, slideUp, slideDown, slideLeft, slideRight, scaleIn, scaleOut, rotateClockwise, rotateCounterclockwise, bounceIn, bounceOut, elasticIn, elasticOut, flipIn, flipOut). Non-animation exports (DELAY, DURATION, utility functions) are correctly excluded from the mock.

Likely an incorrect or invalid review comment.

src/components/TextMotion/TextMotion.tsx (2)

7-7: LGTM! Consistent Vanilla Extract migration.

The import change matches the pattern used in NodeMotion.tsx, ensuring consistency across components.


108-108: Clarify if className was actually removed from the animated element. The current code shows both TextMotion and NodeMotion follow an identical pattern: no className on the animated element (line 108), and styles.inanimate on the non-animated element (line 115). If a className was previously applied to the animated element, confirm which class and whether external consumers depend on it.

src/styles/motion.css.ts (2)

3-6: LGTM! Motion style supports text animation correctly.

The inline-block display enables CSS transforms, and whiteSpace: 'pre' preserves spacing for text animation—both essential for the library's animation behavior.


8-10: No action needed. The visibility: 'hidden' implementation is correct for SSR and hydration scenarios.

According to React 19 and SSR best practices, visibility: hidden preserves layout space while hiding content, preventing layout shifts during hydration. This is the recommended approach over display: none, which removes layout space and can cause CLS (Cumulative Layout Shift) when content is revealed. The code correctly applies this pattern.

Likely an incorrect or invalid review comment.

src/types/animations.ts (1)

1-1: LGTM! Type safety improvement for animation names.

The AnimationName union type provides compile-time validation for animation lookups, preventing typos and improving developer experience.

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

3-5: LGTM!

The new imports correctly support the transition to runtime keyframe lookup via the centralized keyframesMap.

src/styles/animations.css.ts (5)

3-11: LGTM!

The fade animations are correctly defined with sensible CSS variable fallbacks for customization.


13-31: LGTM!

The slide animations correctly use CSS variables within transform functions, with sensible directional defaults. The syntax is valid and well-supported.


33-41: LGTM!

The scale animations are properly defined with sensible fallback values for subtle scaling effects.


53-63: LGTM!

The bounce animations are well-structured with appropriate keyframe percentages and CSS variable fallbacks that create a pleasing bounce effect.


65-77: LGTM!

The elastic animations correctly use horizontal scaling (scaleX) with multi-step keyframes to create an elastic stretch effect. The CSS variable structure supports full customization.

src/utils/generateAnimation/keyframesMap.ts (1)

1-1: No action required. The import correctly follows Vanilla Extract conventions by including the full .css.ts extension in the import path. This is necessary for Vanilla Extract's build-time processing and is the standard pattern documented in Vanilla Extract's official API.

Comment on lines +63 to +65
"@vanilla-extract/css": "^1.17.5",
"@vanilla-extract/jest-transform": "^1.1.19",
"@vanilla-extract/rollup-plugin": "^1.5.0",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

@vanilla-extract/css latest stable version 2025 2026 npm

💡 Result:

Latest stable @vanilla-extract/css on npm: 1.17.4. Install: npm i @vanilla-extract/css. [1]

Sources
[1] npm package page for @vanilla-extract/css.


🌐 Web query:

@vanilla-extract/jest-transform latest stable version 2025 2026 npm

💡 Result:

Latest stable on the npm registry: @vanilla-extract/jest-transform v1.1.17 (published June 12, 2025). [1][2]

Sources:

  • npm package page (version shown: 1.1.17). [1]
  • Snyk version listing (1.1.17 — published 12 Jun 2025). [2]

🌐 Web query:

@vanilla-extract/rollup-plugin latest stable version 2025 2026 npm

💡 Result:

As of Jan 9, 2026: the upstream releases page shows @vanilla-extract/rollup-plugin v1.4.2 (released Nov 14, 2025), while the npm registry page currently lists v1.4.1 as the published package. [1][2]

Sources:

  • GitHub releases (vanilla-extract): @vanilla-extract/rollup-plugin@1.4.2 (Nov 14, 2025). [1]
  • npm package page: @vanilla-extract/rollup-plugin — version 1.4.1 (published ~a month ago). [2]

🌐 Web query:

vanilla-extract security vulnerabilities CVE 2025 2026

💡 Result:

Short answer: There are no CVEs specifically assigned to the vanilla-extract project (packages like @vanilla-extract/css, /vite-plugin, /webpack-plugin, /esbuild-plugin) in 2025–2026 that I can find. However, there was a related npm supply‑chain incident: the unrelated package docusaurus-plugin-vanilla-extract was reported as malicious following an npm account takeover (advisory dated November 24, 2025). Security scanners (Snyk / ReversingLabs) report no known security issues for the official vanilla-extract packages. [1][2][3]

Sources:

  • GitLab advisory — docusaurus-plugin-vanilla-extract (supply‑chain malware, Nov 24, 2025). [1]
  • Snyk package pages for vanilla-extract plugins (no direct vulnerabilities reported). [2]
  • ReversingLabs / package scans for @vanilla-extract/css (no vulnerabilities detected). [3]

If you want, I can (a) search NVD/CVE databases for any newly published CVEs right now, or (b) list recommended mitigation steps (dependency scanning, lockfile pinning, rotate credentials) for supply‑chain incidents.


Update Vanilla Extract package versions—specified versions do not exist in npm registry.

The package.json references versions that have not been released:

  • @vanilla-extract/css: ^1.17.5 (latest is 1.17.4)
  • @vanilla-extract/jest-transform: ^1.1.19 (latest is 1.1.17)
  • @vanilla-extract/rollup-plugin: ^1.5.0 (latest is 1.4.2)

These will cause npm install to fail. Update to available versions: 1.17.4, 1.1.17, and 1.4.2 respectively. No security vulnerabilities were found in the official vanilla-extract packages.

🤖 Prompt for AI Agents
In @package.json around lines 63 - 65, Update the three vanilla-extract
dependency entries in package.json to published versions to avoid npm install
failures: change "@vanilla-extract/css" version to "1.17.4",
"@vanilla-extract/jest-transform" to "1.1.17", and
"@vanilla-extract/rollup-plugin" to "1.4.2" (replace the current ^1.17.5,
^1.1.19, ^1.5.0 entries respectively); run a fresh npm install and lockfile
update (npm install or yarn install) to regenerate package-lock.json/yarn.lock
and verify the project builds.

Comment on lines +79 to +87
export const flipIn = keyframes({
from: { transform: 'perspective(40rem) rotateY(var(--flip-from, 90deg))' },
to: { transform: 'perspective(40rem) rotateY(var(--flip-to, 0deg))' },
});

export const flipOut = keyframes({
from: { transform: 'perspective(40rem) rotateY(var(--flip-from, 0deg))' },
to: { transform: 'perspective(40rem) rotateY(var(--flip-to, 90deg))' },
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Perspective value uses unusual unit and may be too large.

The flip animations use perspective(40rem) which has two concerns:

  1. Unusual unit: Perspective is typically specified in px units, not rem. Using rem makes the perspective scale with the root font size, which could lead to inconsistent 3D effects across different devices or user font preferences.

  2. Large value: 40rem is extremely large (640px at default 16px font size). Standard perspective values for UI animations are typically 400-600px. A larger perspective creates a more subtle 3D effect, which may be intentional but should be documented or made customizable.

  3. Not customizable: Unlike other animation parameters, the perspective value is hardcoded and cannot be adjusted via CSS variables.

🎨 Proposed fix to use standard units and add customization
 export const flipIn = keyframes({
-  from: { transform: 'perspective(40rem) rotateY(var(--flip-from, 90deg))' },
-  to: { transform: 'perspective(40rem) rotateY(var(--flip-to, 0deg))' },
+  from: { transform: 'perspective(var(--flip-perspective, 400px)) rotateY(var(--flip-from, 90deg))' },
+  to: { transform: 'perspective(var(--flip-perspective, 400px)) rotateY(var(--flip-to, 0deg))' },
 });

 export const flipOut = keyframes({
-  from: { transform: 'perspective(40rem) rotateY(var(--flip-from, 0deg))' },
-  to: { transform: 'perspective(40rem) rotateY(var(--flip-to, 90deg))' },
+  from: { transform: 'perspective(var(--flip-perspective, 400px)) rotateY(var(--flip-from, 0deg))' },
+  to: { transform: 'perspective(var(--flip-perspective, 400px)) rotateY(var(--flip-to, 90deg))' },
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const flipIn = keyframes({
from: { transform: 'perspective(40rem) rotateY(var(--flip-from, 90deg))' },
to: { transform: 'perspective(40rem) rotateY(var(--flip-to, 0deg))' },
});
export const flipOut = keyframes({
from: { transform: 'perspective(40rem) rotateY(var(--flip-from, 0deg))' },
to: { transform: 'perspective(40rem) rotateY(var(--flip-to, 90deg))' },
});
export const flipIn = keyframes({
from: { transform: 'perspective(var(--flip-perspective, 400px)) rotateY(var(--flip-from, 90deg))' },
to: { transform: 'perspective(var(--flip-perspective, 400px)) rotateY(var(--flip-to, 0deg))' },
});
export const flipOut = keyframes({
from: { transform: 'perspective(var(--flip-perspective, 400px)) rotateY(var(--flip-from, 0deg))' },
to: { transform: 'perspective(var(--flip-perspective, 400px)) rotateY(var(--flip-to, 90deg))' },
});
🤖 Prompt for AI Agents
In @src/styles/animations.css.ts around lines 79 - 87, The flip animations
flipIn and flipOut hardcode perspective(40rem); change this to use a pixel-based
default and make it customizable via a CSS variable (e.g.,
var(--flip-perspective, 600px)) so the perspective uses a standard px unit and a
reasonable default value; update both flipIn and flipOut to reference that
variable instead of 40rem and ensure the variable name is documented/consistent
with other style vars.

Comment on lines +41 to +46
const keyframe = keyframesMap[name as AnimationName]?.[variant];

if (keyframe) {
const animationString = `${keyframe} ${duration}s ${easing} ${calculatedDelay}s both`;
acc.animationStrings.push(animationString);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Unsafe type assertion could break with future animation types.

The type assertion name as AnimationName on line 41 assumes that any non-'custom' key with a 'variant' property is a valid AnimationName. While this holds true for the current codebase, adding new animation types without updating the type definition could cause runtime lookup failures that are silently ignored by the conditional on line 43.

Additionally, when a keyframe is not found (line 43), the code silently skips it without any warning. This makes it difficult for consumers to debug misconfigurations or typos in animation names/variants.

🛡️ Proposed fix to add type guard and development warning
+      const isValidAnimationName = (key: string): key is AnimationName => {
+        return ['fade', 'slide', 'scale', 'rotate', 'bounce', 'elastic', 'flip'].includes(key);
+      };
+
       if (name === 'custom') {
         const { name: animationName, duration, delay, easing = 'ease-out' } = config as CustomAnimation;
         const calculatedDelay = sequenceIndex * delay + initialDelay;

         const animationString = `${animationName} ${duration}s ${easing} ${calculatedDelay}s both`;
         acc.animationStrings.push(animationString);
       } else if ('variant' in config) {
         const { variant, duration, delay, easing = 'ease-out', ...rest } = config;
         const calculatedDelay = sequenceIndex * delay + initialDelay;

-        const keyframe = keyframesMap[name as AnimationName]?.[variant];
+        const keyframe = isValidAnimationName(name) ? keyframesMap[name]?.[variant] : undefined;

         if (keyframe) {
           const animationString = `${keyframe} ${duration}s ${easing} ${calculatedDelay}s both`;
           acc.animationStrings.push(animationString);
+        } else if (process.env.NODE_ENV !== 'production') {
+          console.warn(`Animation keyframe not found for: ${name}.${variant}`);
         }

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

"resolveJsonModule": true,
"esModuleInterop": true,
"skipLibCheck": true,
"noEmit": true,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's look at the tsconfig.json file to understand the full context
cat -n tsconfig.json

Repository: shubug1015/react-textmotion

Length of output: 786


🏁 Script executed:

# Check for any Rollup configuration files
fd -e "rollup" -e "rollup.config" -e "js" -e "ts" | grep -i rollup | head -20

Repository: shubug1015/react-textmotion

Length of output: 87


🏁 Script executed:

# Look for build configuration files
ls -la | grep -E "(rollup|webpack|vite|build)"

Repository: shubug1015/react-textmotion

Length of output: 138


🏁 Script executed:

cat -n rollup.config.js

Repository: shubug1015/react-textmotion

Length of output: 1830


🏁 Script executed:

# Also check package.json to understand the build script
cat -n package.json

Repository: shubug1015/react-textmotion

Length of output: 4082


Confusing TypeScript configuration: noEmit: true conflicts with declaration: true in tsconfig.json.

The tsconfig.json has noEmit: true (Line 15) alongside declaration: true (Line 8) and outDir (Line 7), which are logically contradictory. While this works in practice because the Rollup TypeScript plugin explicitly overrides these settings with declaration: true and declarationDir: 'dist' (rollup.config.js, lines 40-41), the configuration is unnecessarily confusing and could cause issues in other contexts (IDE type checking, manual tsc runs, or future tooling changes).

The noEmit: true appears intentional for the test:type script (package.json, line 39), but this purpose should be clearer in the configuration.

Consider restructuring to reduce confusion:

  1. Move noEmit to a separate tsconfig for type-checking purposes, or
  2. Add a comment explaining that Rollup's plugin overrides these settings for the build.

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.

[FEATURE] Refactor SCSS Styling to Vanilla Extract

1 participant