-
Notifications
You must be signed in to change notification settings - Fork 13
Refactor #25
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: master
Are you sure you want to change the base?
Refactor #25
Conversation
WalkthroughThis update represents a major refactor and modernization of the card stack component project. The legacy Vue 2 codebase, documentation, and build tooling are removed. In their place, a new monorepo structure is introduced, featuring a Vue 3, TypeScript, and Vite-based implementation with improved linting, formatting, and type safety. New workspace, demo, and tooling configurations are added. Changes
Changes Table
Sequence Diagram(s)sequenceDiagram
participant App as Vue Demo App
participant VueCardStack as VueCardStack Component
participant useCardStack as useCardStack Composable
participant useDragHandling as useDragHandling Composable
participant useStackCalculations as useStackCalculations Composable
App->>VueCardStack: Render with cards/config/slots
VueCardStack->>useCardStack: Initialize stack state & events
useCardStack->>useStackCalculations: Compute layout & positions
useCardStack->>useDragHandling: Setup drag/touch event handlers
VueCardStack-->>App: Emit move events
App->>VueCardStack: Handle navigation (onNext/onPrevious)
VueCardStack->>useCardStack: Update stack & layout
useCardStack->>useStackCalculations: Recompute positions
VueCardStack-->>App: Update slot props (card/nav)
Poem
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
demos/vue/src/main.tsOops! Something went wrong! :( ESLint: 9.29.0 ESLint couldn't find an eslint.config.(js|mjs|cjs) file. From ESLint v9.0.0, the default configuration file is now eslint.config.js. https://eslint.org/docs/latest/use/configure/migration-guide If you still have problems after following the migration guide, please stop by packages/vue/src/composables/useCardStack.tsOops! Something went wrong! :( ESLint: 9.29.0 ESLint couldn't find an eslint.config.(js|mjs|cjs) file. From ESLint v9.0.0, the default configuration file is now eslint.config.js. https://eslint.org/docs/latest/use/configure/migration-guide If you still have problems after following the migration guide, please stop by demos/vue/src/App.vueOops! Something went wrong! :( ESLint: 9.29.0 ESLint couldn't find an eslint.config.(js|mjs|cjs) file. From ESLint v9.0.0, the default configuration file is now eslint.config.js. https://eslint.org/docs/latest/use/configure/migration-guide If you still have problems after following the migration guide, please stop by
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
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: 3
🧹 Nitpick comments (8)
.gitignore (1)
3-3: Preferdist/to avoid false-positivesAdding the trailing slash limits the ignore rule to the directory itself and avoids accidentally ignoring a file literally named
dist.-dist +dist/packages/vue/tsconfig.node.json (1)
1-10: Add explicit Node typings for better IntelliSenseVite configs frequently access Node globals (
process,__dirname, etc.). Declaring the Node type definitions avoids implicit-any warnings in strict projects."allowSyntheticDefaultImports": true, + "types": ["node"]Optional: if the root
tsconfig.jsonalready contains common settings, consider extending it to avoid duplication:{ "extends": "../tsconfig.json", ... }examples/vue/tsconfig.node.json (1)
1-10: Mirror the Node typings improvementSame rationale as in
packages/vue/tsconfig.node.json."allowSyntheticDefaultImports": true + ,"types": ["node"]packages/vue/src/env.d.ts (1)
1-5: Replace banned{}with a safer object shapeBiome flags
{}as “any non-nullable value”. Swap inRecord<string, unknown>(or simply omit the generics) to satisfy the linter without changing behaviour.- const component: DefineComponent<{}, {}, any>; + const component: DefineComponent<Record<string, unknown>, Record<string, unknown>, any>;examples/vue/src/env.d.ts (1)
3-7: Mirror the fix for banned{}here as wellSame linter warning; apply the identical change.
- const component: DefineComponent<{}, {}, any>; + const component: DefineComponent<Record<string, unknown>, Record<string, unknown>, any>;packages/vue/README.md (1)
91-105: Fix grammatical issues in the slots documentation.The static analysis correctly identified grammatical issues that should be addressed for better documentation clarity.
Apply this diff to fix the grammatical issues:
-#### Props +#### Slot Props - `card`: The card data object with additional internal properties - `$index`: Current index in the stack ### Navigation Slot (`#nav`) Slot for customizing navigation controls. -#### Props +#### Slot Props - `activeCardIndex`: Current active card index -- `onNext`: Function to move to next card -- `onPrevious`: Function to move to previous card +- `onNext`: Function to move to the next card +- `onPrevious`: Function to move to the previous cardpackages/vue/src/composables/useStackCalculations.ts (1)
38-40: Simplify the scaleMultiplier calculation.The current formula can be simplified for better readability.
Apply this diff to simplify the calculation:
-return ((config.value.scaleMultiplier - 1) * -1) / 10; +return (1 - config.value.scaleMultiplier) / 10;packages/vue/src/composables/useCardStack.ts (1)
1-264: Excellent implementation of the card stack composable!The composable is well-architected with:
- Proper use of
shallowReffor performance optimization with large arrays- Clean separation of concerns using helper composables
- Comprehensive lifecycle management with proper cleanup
- Well-documented functions
Consider adding error handling for edge cases like empty card arrays or invalid configurations to make the component more robust.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (15)
dist/vue-card-stack.esm.jsis excluded by!**/dist/**dist/vue-card-stack.min.jsis excluded by!**/dist/**,!**/*.min.jsdist/vue-card-stack.ssr.jsis excluded by!**/dist/**docs/assets/img/search.83621669.svgis excluded by!**/*.svgpackage-lock.jsonis excluded by!**/package-lock.jsonpackages/vue/dist/components/VueCardStack.vue.d.tsis excluded by!**/dist/**packages/vue/dist/composables/useCardStack.d.tsis excluded by!**/dist/**packages/vue/dist/composables/useDragHandling.d.tsis excluded by!**/dist/**packages/vue/dist/composables/useStackCalculations.d.tsis excluded by!**/dist/**packages/vue/dist/index.cjsis excluded by!**/dist/**packages/vue/dist/index.d.tsis excluded by!**/dist/**packages/vue/dist/index.jsis excluded by!**/dist/**packages/vue/dist/types/index.d.tsis excluded by!**/dist/**packages/vue/dist/utils/debounce.d.tsis excluded by!**/dist/**pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (56)
.browserslistrc(0 hunks).gitignore(1 hunks)babel.config.js(0 hunks)build/rollup.config.js(0 hunks)docs-src/.vuepress/components/BasicDemo.vue(0 hunks)docs-src/.vuepress/components/InteractiveDemo.vue(0 hunks)docs-src/.vuepress/components/Logo.vue(0 hunks)docs-src/.vuepress/components/WithNavigation.vue(0 hunks)docs-src/.vuepress/config.js(0 hunks)docs-src/.vuepress/theme/components/Navbar.vue(0 hunks)docs-src/.vuepress/theme/index.js(0 hunks)docs-src/README.md(0 hunks)docs/404.html(0 hunks)docs/assets/css/0.styles.b1edaa7e.css(0 hunks)docs/assets/js/10.e7543215.js(0 hunks)docs/assets/js/11.f75c36d0.js(0 hunks)docs/assets/js/12.84e3d62c.js(0 hunks)docs/assets/js/2.c33d44d0.js(0 hunks)docs/assets/js/3.8a696035.js(0 hunks)docs/assets/js/4.f2c8cd7b.js(0 hunks)docs/assets/js/5.e2f78417.js(0 hunks)docs/assets/js/6.7305ea95.js(0 hunks)docs/assets/js/7.b6985e8a.js(0 hunks)docs/assets/js/8.cedb5513.js(0 hunks)docs/assets/js/9.3de4e58b.js(0 hunks)docs/index.html(0 hunks)examples/vue/App.vue(1 hunks)examples/vue/index.html(1 hunks)examples/vue/package.json(1 hunks)examples/vue/src/App.vue(1 hunks)examples/vue/src/env.d.ts(1 hunks)examples/vue/src/main.ts(1 hunks)examples/vue/src/types.ts(1 hunks)examples/vue/tsconfig.json(1 hunks)examples/vue/tsconfig.node.json(1 hunks)examples/vue/vite.config.ts(1 hunks)package.json(1 hunks)packages/vue/README.md(1 hunks)packages/vue/package.json(1 hunks)packages/vue/src/components/VueCardStack.vue(1 hunks)packages/vue/src/composables/useCardStack.ts(1 hunks)packages/vue/src/composables/useDragHandling.ts(1 hunks)packages/vue/src/composables/useStackCalculations.ts(1 hunks)packages/vue/src/env.d.ts(1 hunks)packages/vue/src/index.ts(1 hunks)packages/vue/src/types/index.ts(1 hunks)packages/vue/src/utils/debounce.ts(1 hunks)packages/vue/tsconfig.json(1 hunks)packages/vue/tsconfig.node.json(1 hunks)packages/vue/vite.config.ts(1 hunks)pnpm-workspace.yaml(1 hunks)src/entry.js(0 hunks)src/serve-dev.js(0 hunks)src/serve-dev.vue(0 hunks)src/utils/debounce.js(0 hunks)src/vue-card-stack.vue(0 hunks)
💤 Files with no reviewable changes (30)
- .browserslistrc
- docs-src/.vuepress/theme/index.js
- babel.config.js
- src/serve-dev.js
- docs-src/.vuepress/config.js
- docs/assets/js/11.f75c36d0.js
- docs-src/.vuepress/components/Logo.vue
- docs-src/.vuepress/components/BasicDemo.vue
- docs/assets/js/9.3de4e58b.js
- docs/404.html
- src/entry.js
- docs-src/README.md
- build/rollup.config.js
- docs-src/.vuepress/components/WithNavigation.vue
- docs/assets/css/0.styles.b1edaa7e.css
- docs/assets/js/10.e7543215.js
- docs/assets/js/8.cedb5513.js
- docs/assets/js/12.84e3d62c.js
- docs-src/.vuepress/components/InteractiveDemo.vue
- docs/index.html
- src/serve-dev.vue
- src/utils/debounce.js
- docs-src/.vuepress/theme/components/Navbar.vue
- docs/assets/js/3.8a696035.js
- docs/assets/js/7.b6985e8a.js
- docs/assets/js/6.7305ea95.js
- src/vue-card-stack.vue
- docs/assets/js/5.e2f78417.js
- docs/assets/js/2.c33d44d0.js
- docs/assets/js/4.f2c8cd7b.js
🧰 Additional context used
🧬 Code Graph Analysis (5)
examples/vue/src/types.ts (1)
packages/vue/src/types/index.ts (1)
BaseCardData(4-7)
packages/vue/src/composables/useDragHandling.ts (1)
packages/vue/src/types/index.ts (2)
CardStackConfig(12-31)DragEvent(64-64)
packages/vue/src/composables/useStackCalculations.ts (1)
packages/vue/src/types/index.ts (2)
BaseCardData(4-7)CardStackConfig(12-31)
packages/vue/src/composables/useCardStack.ts (4)
packages/vue/src/types/index.ts (4)
BaseCardData(4-7)CardStackConfig(12-31)InternalCard(36-59)DragEvent(64-64)packages/vue/src/composables/useStackCalculations.ts (1)
useStackCalculations(7-131)packages/vue/src/composables/useDragHandling.ts (1)
useDragHandling(7-123)packages/vue/src/utils/debounce.ts (1)
debounce(9-24)
packages/vue/src/types/index.ts (1)
packages/vue/dist/types/index.d.ts (8)
BaseCardData(4-7)CardStackConfig(11-30)InternalCard(34-57)DragEvent(61-61)CardStackProps(65-86)CardStackEmits(90-93)NavSlotProps(97-104)CardSlotProps(108-113)
🪛 Biome (1.9.4)
packages/vue/src/env.d.ts
[error] 3-3: Don't use '{}' as a type.
Prefer explicitly define the object shape. '{}' means "any non-nullable value".
(lint/complexity/noBannedTypes)
[error] 3-3: Don't use '{}' as a type.
Prefer explicitly define the object shape. '{}' means "any non-nullable value".
(lint/complexity/noBannedTypes)
examples/vue/src/env.d.ts
[error] 5-5: Don't use '{}' as a type.
Prefer explicitly define the object shape. '{}' means "any non-nullable value".
(lint/complexity/noBannedTypes)
[error] 5-5: Don't use '{}' as a type.
Prefer explicitly define the object shape. '{}' means "any non-nullable value".
(lint/complexity/noBannedTypes)
🪛 LanguageTool
packages/vue/README.md
[uncategorized] ~93-~93: Loose punctuation mark.
Context: ...dual card content. #### Props - card: The card data object with additional in...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~102-~102: Loose punctuation mark.
Context: ...ntrols. #### Props - activeCardIndex: Current active card index - onNext: F...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~103-~103: You might be missing the article “the” here.
Context: ...d index - onNext: Function to move to next card - onPrevious: Function to move t...
(AI_EN_LECTOR_MISSING_DETERMINER_THE)
[uncategorized] ~104-~104: You might be missing the article “the” here.
Context: ...ard - onPrevious: Function to move to previous card ## TypeScript Support The compon...
(AI_EN_LECTOR_MISSING_DETERMINER_THE)
🔇 Additional comments (27)
pnpm-workspace.yaml (1)
1-3: Workspace glob definitions look goodThe YAML syntax and workspace globs are correct and will pick up every package under
packages/*andexamples/*. No issues spotted.examples/vue/src/main.ts (1)
1-4: Implementation is concise and idiomaticThe bootstrap code follows the standard Vue 3 pattern and compiles fine under strict TypeScript settings. ✅
examples/vue/vite.config.ts (1)
1-6: Minimal, correct Vite config – looks goodNothing to add. Default export with the Vue plugin is the canonical setup for a sample app.
examples/vue/index.html (1)
1-11: HTML scaffold is fineThe document is minimal yet sufficient for a Vite-served demo. No issues spotted.
examples/vue/src/types.ts (1)
1-11: Type alias is clear and extensibleGood use of intersection to extend the shared
BaseCardData. No concerns.examples/vue/tsconfig.json (1)
1-21: LGTM! Well-configured TypeScript setup for Vue 3.The TypeScript configuration follows modern best practices with appropriate compiler options for a Vue 3 + Vite project. The strict type checking and safety options will help maintain code quality.
packages/vue/vite.config.ts (1)
1-31: Excellent Vite library configuration for Vue component package.The configuration properly sets up library mode with TypeScript declarations, appropriate externals, and dual module format support. The CSS asset naming and code splitting settings are well-configured for a component library.
packages/vue/tsconfig.json (1)
1-22: Consistent TypeScript configuration for the Vue package.The configuration matches the example project with the appropriate addition of Node.js types. This consistency will help maintain uniform development experience across the workspace.
examples/vue/package.json (1)
1-21: Well-structured example package configuration.The package.json correctly uses workspace protocol for the local dependency, appropriate Vue 3 version, and standard Vite tooling setup. Good use of private flag for the example project.
packages/vue/package.json (1)
1-36: Excellent library package configuration with comprehensive exports.The package.json follows modern packaging best practices with proper export mappings for TypeScript, ES modules, CommonJS, and CSS. The peer dependency approach for Vue and absence of runtime dependencies are appropriate design choices for a component library.
packages/vue/src/index.ts (1)
1-22: Well-structured Vue 3 library entry point.The implementation correctly provides both modern Vue 3 plugin installation via
VueCardStackPluginand legacy global Vue support. The TypeScript declarations and component exports follow Vue 3 best practices.packages/vue/src/composables/useDragHandling.ts (1)
1-28: Excellent composable structure with comprehensive device detection.The composable provides good separation of concerns with reactive state management and cross-platform event handling. The device detection and event type mapping is well-implemented.
examples/vue/App.vue (1)
1-26: Good example demonstrating component usage with scoped slots.The component usage properly demonstrates the VueCardStack with both card content customization and navigation controls using scoped slots. Event handling is correctly implemented.
packages/vue/src/utils/debounce.ts (1)
1-47: Well-implemented utility functions with excellent TypeScript support.Both
debounceandthrottlefunctions are correctly implemented with proper generic type preservation and clear documentation. The implementations follow standard patterns and handle edge cases appropriately.package.json (1)
2-22: Good transformation to framework-agnostic workspace structure.The package.json changes appropriately reflect the architectural shift from a Vue-specific library to a framework-agnostic workspace. The private flag, pnpm workspace commands, and updated keywords align well with the refactor objectives.
examples/vue/src/App.vue (1)
1-27: Code implementation looks good!The example properly demonstrates the usage of the VueCardStack component with TypeScript and Vue 3 Composition API.
Note: The AI summary mentions listening to
changeevents, but the code only implements the@moveevent handler.Likely an incorrect or invalid review comment.
packages/vue/src/composables/useStackCalculations.ts (1)
29-33: Potential edge case in maxVisibleCards calculation.When
cards.value.lengthequalsconfig.value.maxVisibleCards, the function returnscards.value.length - 1, which might not be the intended behavior. Consider whether all cards should be visible in this case.Could you clarify the intended behavior when the number of cards equals the configured maximum visible cards?
packages/vue/src/components/VueCardStack.vue (1)
1-102: Well-structured Vue 3 component!The component follows Vue 3 best practices with proper TypeScript integration, reactive state management, and clean slot-based architecture. The use of
toReffor creating the reactive config and the integration with composables is excellent.packages/vue/src/types/index.ts (9)
4-7: Well-designed base interface.The
BaseCardDatainterface provides a clean foundation for card data with optional internal properties. The underscore prefix convention clearly indicates these are system-managed properties.
12-31: Comprehensive and well-documented configuration interface.The
CardStackConfiginterface covers all necessary configuration options with clear documentation. The flexiblestackWidthtyping supports both pixel values and CSS strings, which is excellent for component flexibility.
36-59: Excellent internal state interface design.The
InternalCardinterface properly captures all necessary internal state properties for card positioning, styling, and interaction. The distinction between optional properties inBaseCardDataand required properties here demonstrates good architectural thinking.
64-64: Appropriate type union for cross-platform compatibility.The
DragEventtype correctly handles both mouse and touch interactions, ensuring the component works across different input methods.
69-90: Well-structured component props interface.The generic
CardStackPropsinterface correctly maps configuration options to optional component props while keeping the essentialcardsarray required. This design supports default values while maintaining type safety.
95-98: Correct Vue 3 emit interface implementation.The
CardStackEmitsinterface properly uses tuple syntax for Vue 3 emit definitions. The singlemoveevent with a numeric parameter is appropriate for card stack interactions.
103-110: Clean navigation slot props interface.The
NavSlotPropsinterface provides the necessary data and actions for navigation slots with clear, focused properties.
115-120: Excellent slot props design with intersection types.The
CardSlotPropsinterface effectively combines external card data with internal properties using intersection types (T & InternalCard). This provides slots with complete access to both user data and internal state while maintaining type safety.
1-120: Outstanding TypeScript architecture for Vue 3 component.This type definition file demonstrates excellent TypeScript practices and Vue 3 component design. The interfaces show thoughtful separation of concerns, proper generic usage, and comprehensive documentation. The type system provides strong guarantees while maintaining flexibility for various use cases.
Key strengths:
- Clear distinction between external data (
BaseCardData) and internal state (InternalCard)- Flexible configuration with appropriate optional/required property distinctions
- Proper Vue 3 emit and slot typing patterns
- Comprehensive documentation throughout
This forms a solid foundation for the refactored card stack component.
| const shouldChangeCard = (distanceTravelled: number): boolean => { | ||
| const minDistanceToTravel = | ||
| (config.value.cardWidth + config.value.paddingHorizontal) / | ||
| (1 / config.value.sensitivity); | ||
|
|
||
| return Math.abs(distanceTravelled) > minDistanceToTravel; | ||
| }; |
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.
Critical: Sensitivity calculation is inverted.
The sensitivity calculation produces counterintuitive behavior. When sensitivity is higher (closer to 1), the threshold becomes larger, requiring MORE drag distance to trigger a card change. This is opposite to expected behavior where higher sensitivity should require LESS distance.
The current formula:
const minDistanceToTravel = (config.value.cardWidth + config.value.paddingHorizontal) / (1 / config.value.sensitivity);Should be:
- const minDistanceToTravel =
- (config.value.cardWidth + config.value.paddingHorizontal) /
- (1 / config.value.sensitivity);
+ const minDistanceToTravel =
+ (config.value.cardWidth + config.value.paddingHorizontal) /
+ config.value.sensitivity;This ensures higher sensitivity values (closer to 1) result in lower thresholds for easier card changes.
🤖 Prompt for AI Agents
In packages/vue/src/composables/useDragHandling.ts around lines 83 to 89, the
sensitivity calculation is inverted, causing higher sensitivity values to
increase the drag distance threshold instead of decreasing it. To fix this,
change the formula so that minDistanceToTravel is multiplied by the inverse of
sensitivity rather than divided by it, ensuring that higher sensitivity values
reduce the required drag distance for a card change.
examples/vue/App.vue
Outdated
| </template> | ||
|
|
||
| <script> | ||
| import { VueCardStack } from '@vue-card-stack/vue'; |
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 correct
Incorrect import path - package name mismatch.
The import uses @vue-card-stack/vue but based on the package restructuring, this should likely be @card-stack/vue to match the new package naming convention.
- import { VueCardStack } from '@vue-card-stack/vue';
+ import { VueCardStack } from '@card-stack/vue';Verify the correct package name by checking the Vue package's package.json:
🏁 Script executed:
#!/bin/bash
# Check the actual package name in the Vue package
cat packages/vue/package.json | jq '.name'Length of output: 60
Incorrect import path - package name mismatch.
The import uses @vue-card-stack/vue but based on the package restructuring, this should likely be @card-stack/vue to match the new package naming convention.
- import { VueCardStack } from '@vue-card-stack/vue';
+ import { VueCardStack } from '@card-stack/vue';Verify the correct package name by checking the Vue package's package.json:
#!/bin/bash
# Check the actual package name in the Vue package
cat packages/vue/package.json | jq '.name'🤖 Prompt for AI Agents
In examples/vue/App.vue at line 29, the import path '@vue-card-stack/vue' is
incorrect due to package renaming. Change the import statement to use
'@card-stack/vue' instead to match the updated package naming convention. Verify
the correct package name by checking the package.json of the Vue package if
needed.
Docstrings generation was requested by @rodleviton. * #25 (comment) The following files were modified: * `packages/vue/src/composables/useCardStack.ts` * `packages/vue/src/composables/useDragHandling.ts` * `packages/vue/src/composables/useStackCalculations.ts` * `packages/vue/src/utils/debounce.ts`
|
Note Generated docstrings for this pull request at #26 |
Refactored VueCardStack to support generic card types for full TypeScript inference. Added createVueCardStack factory for type-safe usage, updated slot and prop typings, and improved documentation for custom card data. Updated example and README to demonstrate new strongly-typed API.
Card slot props now provide a `data` property containing only user-defined card fields, separating them from internal properties like _id and _index. This improves type safety and clarity for slot consumers. Example and typings updated accordingly in both source and dist files.
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: 1
🧹 Nitpick comments (1)
packages/vue/src/components/VueCardStackDefineComponent.ts (1)
38-38: Consider the data property type design.The
data: Omit<T, keyof BaseCardData>approach removes base properties from the generic type, but this might be confusing since the card object also contains_idand_indexat the same level (lines 26-27).Consider flattening the structure or making the separation clearer:
- data: Omit<T, keyof BaseCardData>; + ...T; // Spread all T properties at the top levelOr provide clearer documentation about why
datais separated from the base card properties.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (5)
packages/vue/dist/components/VueCardStack.vue.d.tsis excluded by!**/dist/**packages/vue/dist/index.cjsis excluded by!**/dist/**packages/vue/dist/index.d.tsis excluded by!**/dist/**packages/vue/dist/index.jsis excluded by!**/dist/**packages/vue/dist/types/index.d.tsis excluded by!**/dist/**
📒 Files selected for processing (6)
examples/vue/src/App.vue(1 hunks)packages/vue/README.md(1 hunks)packages/vue/src/components/VueCardStack.vue(1 hunks)packages/vue/src/components/VueCardStackDefineComponent.ts(1 hunks)packages/vue/src/index.ts(1 hunks)packages/vue/src/types/index.ts(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- packages/vue/README.md
🚧 Files skipped from review as they are similar to previous changes (4)
- packages/vue/src/index.ts
- examples/vue/src/App.vue
- packages/vue/src/components/VueCardStack.vue
- packages/vue/src/types/index.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/vue/src/components/VueCardStackDefineComponent.ts (3)
packages/vue/dist/index.d.ts (2)
createVueCardStack(4-4)VueCardStack(5-5)packages/vue/src/index.ts (2)
createVueCardStack(3-3)VueCardStack(6-6)packages/vue/src/types/index.ts (1)
BaseCardData(4-7)
🔇 Additional comments (2)
packages/vue/src/components/VueCardStackDefineComponent.ts (2)
1-2: LGTM! Clean imports and exports.The imports are well-structured and the re-export of the raw component provides flexibility for users who don't need the generic typing.
Also applies to: 52-52
24-39: Verify slot prop definitions match the actual component implementation.The
cardslot has extensive prop definitions including positioning, styling, and data properties. Ensure these match exactly with what the actualVueCardStack.vuecomponent provides to avoid runtime errors.Run this script to verify the slot prop definitions:
#!/bin/bash # Description: Check VueCardStack.vue implementation for slot prop consistency # Search for slot definitions and prop passing in the Vue component rg -A 10 -B 5 "slot.*card" packages/vue/src/components/VueCardStack.vue rg -A 10 -B 5 "v-slot" packages/vue/src/components/VueCardStack.vue rg -A 10 -B 5 "\$slots" packages/vue/src/components/VueCardStack.vue
| export function createVueCardStack<T extends BaseCardData = BaseCardData>() { | ||
| return VueCardStack as typeof VueCardStack & { | ||
| new (): { | ||
| $props: { | ||
| cards: T[]; | ||
| cardWidth?: number; | ||
| cardHeight?: number; | ||
| stackWidth?: number | string | null; | ||
| sensitivity?: number; | ||
| maxVisibleCards?: number; | ||
| scaleMultiplier?: number; | ||
| speed?: number; | ||
| paddingHorizontal?: number; | ||
| paddingVertical?: number; | ||
| }; | ||
| $slots: { | ||
| card: (props: { | ||
| card: { | ||
| _id: number; | ||
| _index: number; | ||
| xPos: number; | ||
| yPos: number; | ||
| scale: number; | ||
| opacity: number; | ||
| display: string; | ||
| zIndex: number; | ||
| width: number; | ||
| height: number; | ||
| isDragging: boolean; | ||
| $index: number; | ||
| data: Omit<T, keyof BaseCardData>; | ||
| }; | ||
| }) => any; | ||
| nav: (props: { | ||
| activeCardIndex: number; | ||
| onNext: () => void; | ||
| onPrevious: () => void; | ||
| }) => any; | ||
| }; | ||
| }; | ||
| }; | ||
| } |
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
Consider using defineComponent or a more type-safe approach instead of type assertion.
The current implementation uses type assertion (as typeof VueCardStack & ...) to add generic typing, which bypasses TypeScript's type checking and could lead to runtime inconsistencies. Additionally, manually defining props and slots creates a maintenance burden and risk of divergence from the actual component implementation.
Consider these alternatives:
Option 1: Use Vue's defineComponent with generic support
-export function createVueCardStack<T extends BaseCardData = BaseCardData>() {
- return VueCardStack as typeof VueCardStack & {
- new (): {
- $props: {
- cards: T[];
- // ... other props
- };
- $slots: {
- // ... slots
- };
- };
- };
-}
+export function createVueCardStack<T extends BaseCardData = BaseCardData>() {
+ return defineComponent({
+ extends: VueCardStack,
+ props: {
+ ...VueCardStack.props,
+ cards: {
+ type: Array as PropType<T[]>,
+ required: true
+ }
+ }
+ });
+}Option 2: Use a HOC (Higher-Order Component) pattern
export function createVueCardStack<T extends BaseCardData = BaseCardData>() {
return (VueCardStack as any) as DefineComponent<{
cards: T[];
// ... other props from VueCardStack
}>;
}This approach would provide better type safety and reduce the risk of prop/slot definitions becoming stale.
🤖 Prompt for AI Agents
In packages/vue/src/components/VueCardStackDefineComponent.ts lines 8 to 49,
replace the current type assertion approach with a more type-safe method by
using Vue's defineComponent with generic support or a Higher-Order Component
pattern. This means you should avoid manually asserting the component type and
instead create the component using defineComponent to infer props and slots
properly or cast VueCardStack to a DefineComponent with the appropriate generic
props. This will improve type safety, maintainability, and keep prop and slot
definitions in sync with the actual component implementation.
Introduces a new @card-stack/eslint package with a shared ESLint configuration supporting TypeScript and Vue 3. Adds .eslintrc.js files to the root, examples/vue, and packages/vue to extend the shared config. Updates package.json scripts and devDependencies to support linting and formatting for Vue files. Registers the new tooling/eslint workspace in pnpm-workspace.yaml.
Enhances ESLint base and Vue configs with improved rules and parser options, including better globals and stricter TypeScript checks. Updates @typescript-eslint packages to 8.35.0 and aligns all TypeScript dependencies to ^5.5.0 across the repo for consistency.
Refactored VueCardStack component and related composables for improved code style and consistency. Added Prettier and TypeScript shared configs as workspace packages, updated Prettier and ESLint configs to use them, and introduced Prettier plugin for Vue. Updated package and lock files to reflect new dependencies and configuration structure.
Split Prettier configuration into base and Vue-specific configs. Updated package.json to use the new Vue config in the Vue package. Adjusted exports in tooling/prettier/package.json to expose both base and Vue configs, and removed the old index.mjs file.
Refined type definitions for Vue components and slots to use more accurate typings, such as VNode and Record<string, unknown>. Updated debounce and throttle utilities for better type safety. Also updated prettier-plugin-tailwindcss to v0.6.13 in tooling.
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: 1
🧹 Nitpick comments (2)
.gitignore (2)
3-4: Yarn-specific PnP artifacts probably unnecessary after the switch to pnpm
.pnpand.pnp.jsare generated by Yarn Plug-n-Play. Given the repo now relies on pnpm workspaces, keeping these patterns may create confusion about the supported tooling.-.pnp -.pnp.js
10-12: Duplicatedistignore rules – keep the recursive one for clarity
dist/is fully covered by**/dist/. Dropping the top-level pattern reduces noise without changing behaviour.-dist/ **/dist/
📜 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 (32)
.gitignore(1 hunks).vscode/extensions.json(1 hunks)examples/vue/eslint.config.mjs(1 hunks)examples/vue/package.json(1 hunks)examples/vue/src/App.vue(1 hunks)examples/vue/src/env.d.ts(1 hunks)examples/vue/src/main.ts(1 hunks)examples/vue/src/types.ts(1 hunks)examples/vue/turbo.json(1 hunks)package.json(1 hunks)packages/vue/eslint.config.mjs(1 hunks)packages/vue/package.json(1 hunks)packages/vue/src/components/VueCardStack.vue(1 hunks)packages/vue/src/components/VueCardStackDefineComponent.ts(1 hunks)packages/vue/src/composables/useCardStack.ts(1 hunks)packages/vue/src/composables/useDragHandling.ts(1 hunks)packages/vue/src/composables/useStackCalculations.ts(1 hunks)packages/vue/src/env.d.ts(1 hunks)packages/vue/src/index.ts(1 hunks)packages/vue/src/types/index.ts(1 hunks)packages/vue/src/utils/debounce.ts(1 hunks)packages/vue/turbo.json(1 hunks)pnpm-workspace.yaml(1 hunks)tooling/eslint/base.js(1 hunks)tooling/eslint/package.json(1 hunks)tooling/eslint/vue.js(1 hunks)tooling/prettier/index.mjs(1 hunks)tooling/prettier/package.json(1 hunks)tooling/prettier/tsconfig.json(1 hunks)tooling/typescript/base.json(1 hunks)tooling/typescript/package.json(1 hunks)turbo.json(1 hunks)
✅ Files skipped from review due to trivial changes (14)
- tooling/typescript/package.json
- examples/vue/eslint.config.mjs
- tooling/prettier/tsconfig.json
- packages/vue/eslint.config.mjs
- .vscode/extensions.json
- tooling/eslint/base.js
- tooling/typescript/base.json
- tooling/prettier/index.mjs
- packages/vue/turbo.json
- turbo.json
- tooling/eslint/vue.js
- examples/vue/turbo.json
- tooling/eslint/package.json
- tooling/prettier/package.json
🚧 Files skipped from review as they are similar to previous changes (15)
- examples/vue/src/main.ts
- examples/vue/src/types.ts
- examples/vue/src/env.d.ts
- pnpm-workspace.yaml
- packages/vue/package.json
- packages/vue/src/components/VueCardStackDefineComponent.ts
- packages/vue/src/composables/useDragHandling.ts
- packages/vue/src/index.ts
- packages/vue/src/composables/useStackCalculations.ts
- examples/vue/package.json
- examples/vue/src/App.vue
- packages/vue/src/utils/debounce.ts
- package.json
- packages/vue/src/components/VueCardStack.vue
- packages/vue/src/types/index.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/vue/src/composables/useCardStack.ts (4)
packages/vue/src/types/index.ts (4)
BaseCardData(6-9)CardStackConfig(14-33)InternalCard(38-61)DragEvent(66-66)packages/vue/src/composables/useStackCalculations.ts (1)
useStackCalculations(7-120)packages/vue/src/composables/useDragHandling.ts (1)
useDragHandling(7-111)packages/vue/src/utils/debounce.ts (1)
debounce(9-24)
🔇 Additional comments (14)
.gitignore (1)
21-24: Verify that the broad.env*ignore does not block checked-in template files
The pattern ignores every.env*, then re-includes only.env.example.
If you need other templates such as.env.development.example, add explicit negations now to avoid accidental omission.packages/vue/src/composables/useCardStack.ts (12)
1-5: LGTM: Clean and well-organized imports.The imports are well-structured with clear separation between types, utilities, composables, and Vue APIs. All imports appear to be used within the composable.
7-15: LGTM: Well-designed function signature with good TypeScript generics.The function signature properly uses generics to extend BaseCardData and accepts appropriate reactive references. The emit parameter could potentially use Vue's Emits type for stronger typing, but the current approach is acceptable and functional.
16-25: LGTM: Efficient reactive state management.Good use of
shallowReffor the stack array to optimize performance since deep reactivity isn't needed for the card objects. The composable initialization follows Vue 3 composition patterns well.
49-62: LGTM: Proper use of nextTick for DOM-dependent calculations.The rebuild function correctly uses
nextTickto ensure DOM updates are complete before recalculating card positions and properties. The spread operator usage preserves existing card data while updating calculated defaults.
64-72: LGTM: Efficient resize handling with appropriate debouncing.The debounced resize handler with 250ms delay is well-implemented to prevent excessive calculations during window resizing. The logic correctly updates the width and triggers a rebuild.
74-94: LGTM: Clean implementation of circular navigation.The navigation functions correctly implement circular card movement by shifting cards between the front and back of the stack array. The logic properly handles the rotation and triggers rebuild to update the visual state.
96-133: LGTM: Complex but well-structured drag update logic.The
moveStackfunction handles real-time drag updates effectively with appropriate calculations for position and scale transformations. The normalized progress emission is useful for external components to track drag state. The complex mathematical calculations for smooth drag transitions appear correct.
135-154: LGTM: Proper end-of-drag handling with threshold-based card switching.The function correctly calculates the distance travelled and uses the
shouldChangeCardlogic to determine whether to switch cards or revert to the original position. Emittingmovewith 0 appropriately resets the progress state.
156-181: LGTM: Proper event listener management for drag interactions.The event handlers correctly manage document-level event listeners to handle cases where the mouse/touch moves outside the element during drag. The conditional check in
onDragprevents errors from null drag data.
183-189: LGTM: Safe computed property with proper fallback handling.The
originalActiveCardIndexcomputed property correctly maps from the internal stack index to the original card index with appropriate null safety using optional chaining and a sensible fallback value.
191-208: LGTM: Comprehensive lifecycle management with proper cleanup.The lifecycle hooks properly initialize the component and handle all event listener registration and cleanup. The conditional checks for
elementRef.valueprovide appropriate safety, and all listeners added inonMountedare correctly removed inonBeforeUnmount.
210-231: LGTM: Well-structured API with appropriate encapsulation.The return object provides a clean, well-organized API that exposes necessary state and methods while keeping internal complexity private. The commented sections make it easy for consumers to understand what's available.
packages/vue/src/env.d.ts (1)
1-5: LGTM: Standard TypeScript declaration for Vue SFC support.This is a proper TypeScript module declaration that enables TypeScript recognition of
.vuefiles. TheDefineComponenttyping withRecord<string, unknown>provides appropriate flexibility for generic Vue component imports while maintaining type safety.
| const init = () => { | ||
| // Move bottom card to top of stack (positioned offscreen) | ||
| const cardsCopy = [...cards.value] | ||
| const lastCard = cardsCopy.pop() | ||
| if (lastCard) { | ||
| cardsCopy.unshift(lastCard) | ||
| } | ||
|
|
||
| stack.value = cardsCopy.map((card, index) => { | ||
| const defaults = calculations.cardDefaults.value[index] | ||
| return { | ||
| _id: Date.now() + index, | ||
| _index: index, | ||
| ...card, | ||
| ...defaults | ||
| } as T & InternalCard | ||
| }) | ||
| } |
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
Suggest improving ID generation to avoid potential duplicates.
The card rotation logic is correct, but using Date.now() + index for ID generation could create duplicate IDs if the function is called multiple times within the same millisecond or if there are timing issues.
Consider using a more robust ID generation approach:
- _id: Date.now() + index,
+ _id: crypto.randomUUID?.() || `${Date.now()}-${Math.random()}`,Or use a simple counter for sequential IDs if uniqueness within the component is sufficient.
📝 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.
| const init = () => { | |
| // Move bottom card to top of stack (positioned offscreen) | |
| const cardsCopy = [...cards.value] | |
| const lastCard = cardsCopy.pop() | |
| if (lastCard) { | |
| cardsCopy.unshift(lastCard) | |
| } | |
| stack.value = cardsCopy.map((card, index) => { | |
| const defaults = calculations.cardDefaults.value[index] | |
| return { | |
| _id: Date.now() + index, | |
| _index: index, | |
| ...card, | |
| ...defaults | |
| } as T & InternalCard | |
| }) | |
| } | |
| const init = () => { | |
| // Move bottom card to top of stack (positioned offscreen) | |
| const cardsCopy = [...cards.value] | |
| const lastCard = cardsCopy.pop() | |
| if (lastCard) { | |
| cardsCopy.unshift(lastCard) | |
| } | |
| stack.value = cardsCopy.map((card, index) => { | |
| const defaults = calculations.cardDefaults.value[index] | |
| return { | |
| _id: crypto.randomUUID?.() || `${Date.now()}-${Math.random()}`, | |
| _index: index, | |
| ...card, | |
| ...defaults | |
| } as T & InternalCard | |
| }) | |
| } |
🤖 Prompt for AI Agents
In packages/vue/src/composables/useCardStack.ts around lines 30 to 47, the
current ID generation using Date.now() + index can produce duplicate IDs if
called rapidly. Replace this with a more reliable method such as a UUID
generator or maintain a simple incrementing counter within the component to
ensure unique IDs for each card instance.
Swapped 'format' and 'format:fix' scripts for consistency in both example and package Vue projects. Improved formatting in VueCardStack and App.vue templates for readability. Updated VueCardStackDefineComponent for better type clarity. Adjusted ESLint config to disable formatting rules that conflict with Prettier.
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 (1)
demos/vue/src/App.vue (1)
32-69: Consider improving template formatting for better readability.While the template logic is correct and the scoped slots are properly implemented, the formatting has inconsistent spacing and unusual line breaks that make it harder to read.
Consider reformatting for better readability:
-<template> - - <div class="app"> - - <h1>Vue Card Stack Demo</h1> - <VueCardStack +<template> + <div class="app"> + <h1>Vue Card Stack Demo</h1> + <VueCardStack :cards="cards" :stack-width="460" :card-width="300" :card-height="460" :max-visible-cards="6" @move="onMove" - > <template #card="{ card }" - > - <div class="card" :style="{ background: card.data.background }"> - - <p v-if="card.data.title"> {{ card.data.title }} </p> - - </div> - </template - > <template #nav="{ activeCardIndex, onNext, onPrevious }" - > + > + <template #card="{ card }"> + <div class="card" :style="{ background: card.data.background }"> + <p v-if="card.data.title">{{ card.data.title }}</p> + </div> + </template> + + <template #nav="{ activeCardIndex, onNext, onPrevious }"> <nav class="nav"> - - <div class="counter"> {{ (activeCardIndex ?? 0) + 1 }}/{{ cards.length }} </div> - <button class="button" @click="onPrevious"> Previous </button> <button - class="button" - @click="onNext" - > - Next </button - > + <div class="counter">{{ (activeCardIndex ?? 0) + 1 }}/{{ cards.length }}</div> + <button class="button" @click="onPrevious">Previous</button> + <button class="button" @click="onNext">Next</button> </nav> - </template - > </VueCardStack - > + </template> + </VueCardStack> </div> - </template>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
demos/vue/public/vite.svgis excluded by!**/*.svgpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (19)
demos/vue/.gitignore(1 hunks)demos/vue/eslint.config.mjs(1 hunks)demos/vue/index.html(1 hunks)demos/vue/package.json(1 hunks)demos/vue/src/App.vue(1 hunks)demos/vue/src/main.ts(1 hunks)demos/vue/src/types.ts(1 hunks)demos/vue/src/vite-env.d.ts(1 hunks)demos/vue/tsconfig.app.json(1 hunks)demos/vue/tsconfig.json(1 hunks)demos/vue/tsconfig.node.json(1 hunks)demos/vue/vite.config.ts(1 hunks)packages/vue/package.json(1 hunks)packages/vue/src/components/VueCardStack.vue(1 hunks)packages/vue/src/components/VueCardStackDefineComponent.ts(1 hunks)packages/vue/src/index.ts(1 hunks)packages/vue/tsconfig.json(1 hunks)pnpm-workspace.yaml(1 hunks)tooling/eslint/vue.js(1 hunks)
✅ Files skipped from review due to trivial changes (8)
- demos/vue/src/vite-env.d.ts
- demos/vue/tsconfig.json
- demos/vue/vite.config.ts
- demos/vue/src/types.ts
- demos/vue/index.html
- demos/vue/.gitignore
- demos/vue/eslint.config.mjs
- demos/vue/package.json
🚧 Files skipped from review as they are similar to previous changes (7)
- packages/vue/tsconfig.json
- pnpm-workspace.yaml
- packages/vue/src/index.ts
- tooling/eslint/vue.js
- packages/vue/src/components/VueCardStackDefineComponent.ts
- packages/vue/package.json
- packages/vue/src/components/VueCardStack.vue
🧰 Additional context used
🪛 Biome (1.9.4)
demos/vue/tsconfig.app.json
[error] 6-6: JSON standard does not allow comments.
(parse)
[error] 7-7: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 7-7: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 7-7: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 7-7: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 8-8: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 8-8: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 8-8: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 8-8: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 9-9: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 9-9: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 9-9: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 9-9: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 10-10: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 10-10: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 10-10: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 10-10: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 11-11: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 11-11: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 11-11: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 11-11: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 12-12: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 12-12: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 12-12: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 13-13: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 14-14: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 14-14: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 14-14: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 14-15: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
demos/vue/tsconfig.node.json
[error] 9-9: JSON standard does not allow comments.
(parse)
[error] 10-10: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 10-10: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 10-10: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 10-10: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 11-11: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 11-11: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 11-11: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 11-11: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 12-12: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 12-12: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 12-12: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 12-12: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 13-13: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 13-13: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 13-13: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 13-13: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 14-14: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 14-14: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 14-14: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 14-16: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 16-16: JSON standard does not allow comments.
(parse)
[error] 17-17: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 17-17: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 17-17: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 17-17: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 18-18: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 18-18: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 18-18: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 18-18: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 19-19: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 19-19: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 19-19: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 19-19: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 20-20: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 20-20: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 20-20: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 20-20: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 21-21: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 21-21: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 21-21: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 21-21: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 22-22: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 22-22: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 22-22: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 23-23: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 24-24: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 24-24: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 24-24: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
[error] 24-25: End of file expected
Use an array for a sequence of values: [1, 2]
(parse)
🔇 Additional comments (5)
demos/vue/src/main.ts (1)
1-5: Clean and standard Vue 3 entry point implementation.The bootstrap code follows Vue 3 best practices with proper imports and app mounting. The implementation is minimal and correct.
demos/vue/tsconfig.app.json (1)
1-15: Well-configured TypeScript setup with appropriate strict settings.The configuration properly extends the Vue base config and enables strict type checking options that will help maintain code quality. The build info caching and file inclusion patterns are correctly set up.
Note: The static analysis errors about JSON comments are false positives - TypeScript config files support comments (JSONC format).
demos/vue/tsconfig.node.json (1)
1-25: Appropriate TypeScript configuration for bundler/build tooling.The configuration correctly targets ES2023 with bundler mode settings and strict linting options. Including only the Vite config file is appropriate for this Node.js-specific TypeScript config.
demos/vue/src/App.vue (2)
1-30: Excellent use of Vue 3 Composition API with strong TypeScript typing.The component demonstrates best practices with:
- Proper use of
<script setup lang="ts">- Strongly typed component creation via generic factory function
- Reactive data management with
ref()- Clean event handling
The implementation showcases the new Vue 3 card stack component effectively.
71-123: Clean and well-structured CSS styles.The styles provide good visual design with:
- Proper flexbox layout for centering
- Consistent spacing and typography
- Good button hover states
- Appropriate border radius and colors
The styling effectively supports the card stack demo functionality.
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: 6
♻️ Duplicate comments (3)
packages/vue/src/composables/useDragHandling.ts (2)
156-166: Critical: Sensitivity calculation is inverted.This issue was previously identified and remains unaddressed. The current formula produces counterintuitive behavior where higher sensitivity values require MORE drag distance instead of LESS.
185-194: Same inverted sensitivity calculation in getThresholdDistance.This computed property has the same inverted sensitivity calculation issue.
Apply this diff to fix both occurrences:
const getThresholdDistance = computed((): number => { try { return ( - (config.value.cardWidth + config.value.paddingHorizontal) / (1 / config.value.sensitivity) + (config.value.cardWidth + config.value.paddingHorizontal) * config.value.sensitivity ) } catch (error) {packages/vue/src/composables/useCardStack.ts (1)
129-137: Improve ID generation to avoid potential duplicates.While adding
Math.random()reduces collision risk, it's still not guaranteed to be unique. Consider using a more robust approach.Apply this diff for more reliable ID generation:
- _id: Date.now() + index + Math.random(), // Ensure unique IDs + _id: card._id ?? `${Date.now()}-${index}-${Math.random().toString(36).substr(2, 9)}`,Or use a UUID if available:
- _id: Date.now() + index + Math.random(), // Ensure unique IDs + _id: card._id ?? (crypto.randomUUID?.() || `${Date.now()}-${Math.random()}`),
🧹 Nitpick comments (11)
tooling/eslint/package.json (1)
41-44: Consider addingnpmto the engines blockTooling users on plain npm will not receive an engine-mismatch warning and may unknowingly use an older runtime.
"engines": { "node": ">=18.0.0", - "pnpm": ">=8.0.0" + "pnpm": ">=8.0.0", + "npm": ">=9.0.0" },tooling/typescript/base.json (2)
5-13:allowJs+checkJs+ strict flags will surface thousands of JS errorsWith
allowJs: true, all.jsfiles in the workspace are type-checked under strict mode.
Unless every package is 100 % TS-compatible JavaScript, this will be extremely noisy and slow incremental builds.Consider:
- "allowJs": true, - "checkJs": true, + // JS is compiled only when a package explicitly opts-in + "allowJs": false, + "checkJs": false,or documenting an opt-in per-package override.
6-7: Missing Node types fromlibarray
"lib": ["DOM", ...]omits"DOM.Iterable","ES2022.Array", and most importantly"DOM" includes no Node globals. Any back-end or build-tooling file that usesprocess,Buffer`, etc. will lack type definitions.If the base config is meant for both browser and tooling code, append
"DOM","DOM.Iterable","ES2022","ESNext.AsyncIterable","DOM" ,"DOM.Iterable","ES2022","ESNext.AsyncIterable","DOM","ES2022"]maybe mixture.Better: split into browser vs Node presets.
tooling/typescript/package.json (1)
30-37: Export does not expose the preset at package rootConsumers commonly import as:
{ "extends": "@card-stack/tsconfig" }That requires the root export (
".") to resolve to the config file:"exports": { - "./base.json": "./base.json", + ".": "./base.json", + "./base.json": "./base.json", "./package.json": "./package.json" },tooling/eslint/README.md (1)
148-151: Markdown-lint: MD036 – emphasis used as heading
**Made with ❤️ by ReactivePixels**triggers MD036.
If you want a separator/header style, use an<h3>or plain text to avoid automated lint failures.-**Made with ❤️ by ReactivePixels** +### Made with ❤️ by ReactivePixelstooling/typescript/README.md (1)
152-152: Add hyphen to "OS-specific" for grammatical correctness.When used as a modifier, "OS-specific" should be hyphenated.
-- IDE and OS specific files +- IDE and OS-specific filespackages/vue/src/components/VueCardStack.vue (3)
73-89: Consider reactive prop validationThe prop validation only runs once during setup. Consider moving this to a watchEffect or computed property to ensure props remain valid if they change dynamically.
-// Validate props on setup -try { - validateProps() -} catch (err) { - error.value = err as Error -} +// Validate props reactively +watchEffect(() => { + try { + validateProps() + error.value = null + } catch (err) { + error.value = err as Error + } +})
145-152: Complete keyboard navigation implementationThe Home and End key handlers are not implemented. These are important for accessibility.
Would you like me to implement the navigation to first/last card functionality or create an issue to track this?
case 'Home': event.preventDefault() - // Move to first card (implement if needed) + // Navigate to first card + void onFirst?.() // Needs to be exposed from useCardStack break case 'End': event.preventDefault() - // Move to last card (implement if needed) + // Navigate to last card + void onLast?.() // Needs to be exposed from useCardStack break
223-228: Simplify card data transformation for better readabilityThe inline destructuring and spread operation is complex. Consider extracting this to a computed property or method for clarity.
-:card="{ - ...card, - $index: index, - data: (({ _id, _index, ...rest }) => rest)(card) -}" +:card="getCardSlotProps(card, index)"Add this method to the script:
const getCardSlotProps = (card: InternalCard, index: number) => ({ ...card, $index: index, data: omit(card, ['_id', '_index']) })packages/vue/README.md (2)
6-7: Use proper heading instead of bold textFor better document structure and accessibility, use a proper heading tag instead of bold emphasis.
- -**A performant, accessible card stack component for Vue 3 with drag-to-swipe functionality** - + +### A performant, accessible card stack component for Vue 3 with drag-to-swipe functionality +
637-637: Update donation link placeholderThe "Buy us a coffee" link contains a placeholder username.
-- ☕ [Buying us a coffee](https://buymeacoffee.com/your-username) +- ☕ [Buying us a coffee](https://buymeacoffee.com/reactivepixels)
📜 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 (29)
.editorconfig(1 hunks).vscode/extensions.json(1 hunks)demos/vue/eslint.config.mjs(1 hunks)demos/vue/src/App.vue(1 hunks)demos/vue/src/main.ts(1 hunks)package.json(1 hunks)packages/vue/.eslintignore(1 hunks)packages/vue/README.md(1 hunks)packages/vue/eslint.config.mjs(1 hunks)packages/vue/src/components/VueCardStack.vue(1 hunks)packages/vue/src/components/VueCardStackDefineComponent.ts(1 hunks)packages/vue/src/composables/useCardStack.ts(1 hunks)packages/vue/src/composables/useDragHandling.ts(1 hunks)packages/vue/src/composables/useStackCalculations.ts(1 hunks)packages/vue/src/index.ts(1 hunks)packages/vue/src/types/index.ts(1 hunks)packages/vue/src/utils/debounce.ts(1 hunks)packages/vue/vite.config.ts(1 hunks)tooling/eslint/README.md(1 hunks)tooling/eslint/base.js(1 hunks)tooling/eslint/package.json(1 hunks)tooling/eslint/vue.js(1 hunks)tooling/prettier/README.md(1 hunks)tooling/prettier/index.mjs(1 hunks)tooling/prettier/package.json(1 hunks)tooling/typescript/README.md(1 hunks)tooling/typescript/base.json(1 hunks)tooling/typescript/package.json(1 hunks)turbo.json(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- packages/vue/.eslintignore
- .editorconfig
🚧 Files skipped from review as they are similar to previous changes (9)
- .vscode/extensions.json
- demos/vue/eslint.config.mjs
- packages/vue/eslint.config.mjs
- packages/vue/src/components/VueCardStackDefineComponent.ts
- demos/vue/src/main.ts
- turbo.json
- package.json
- packages/vue/vite.config.ts
- demos/vue/src/App.vue
🧰 Additional context used
🧬 Code Graph Analysis (4)
packages/vue/src/composables/useDragHandling.ts (2)
packages/vue/src/index.ts (1)
useDragHandling(58-58)packages/vue/src/types/index.ts (3)
CardStackConfig(36-104)DragEvent(141-141)DragData(244-249)
packages/vue/src/composables/useStackCalculations.ts (2)
packages/vue/src/index.ts (1)
useStackCalculations(59-59)packages/vue/src/types/index.ts (2)
BaseCardData(17-28)CardStackConfig(36-104)
packages/vue/src/composables/useCardStack.ts (5)
packages/vue/src/index.ts (4)
useCardStack(57-57)useStackCalculations(59-59)useDragHandling(58-58)debounce(62-62)packages/vue/src/types/index.ts (5)
BaseCardData(17-28)CardStackConfig(36-104)InternalCard(112-135)CARD_STACK_CONSTANTS(254-281)DragEvent(141-141)packages/vue/src/composables/useStackCalculations.ts (1)
useStackCalculations(34-316)packages/vue/src/composables/useDragHandling.ts (1)
useDragHandling(29-234)packages/vue/src/utils/debounce.ts (1)
debounce(47-86)
packages/vue/src/utils/debounce.ts (1)
packages/vue/src/index.ts (2)
debounce(62-62)throttle(62-62)
🪛 Biome (1.9.4)
tooling/eslint/vue.js
[error] 79-79: This property value named vue/prefer-template is later overwritten by an object member with the same name.
Overwritten with this value.
If an object property with the same name is defined multiple times (except when combining a getter with a setter), only the last definition makes it into the object and previous definitions are ignored.
Unsafe fix: Remove this property value named vue/prefer-template
(lint/suspicious/noDuplicateObjectKeys)
🪛 markdownlint-cli2 (0.17.2)
packages/vue/README.md
7-7: Emphasis used instead of a heading
null
(MD036, no-emphasis-as-heading)
tooling/eslint/README.md
150-150: Emphasis used instead of a heading
null
(MD036, no-emphasis-as-heading)
tooling/prettier/README.md
214-214: Emphasis used instead of a heading
null
(MD036, no-emphasis-as-heading)
🪛 LanguageTool
tooling/typescript/README.md
[uncategorized] ~152-~152: When ‘OS-specific’ is used as a modifier, it is usually spelled with a hyphen.
Context: ...s - Cache and temporary files - IDE and OS specific files ## Vue 3 Integration ### JSX Co...
(SPECIFIC_HYPHEN)
🔇 Additional comments (10)
tooling/eslint/package.json (1)
45-48: ```shell
#!/bin/bash
set -eecho "eslint-plugin-vue@latest peerDependencies:"
curl -s https://registry.npmjs.org/eslint-plugin-vue/latest | jq '.peerDependencies'echo -e "\neslint-config-prettier@latest peerDependencies:"
curl -s https://registry.npmjs.org/eslint-config-prettier/latest | jq '.peerDependencies'echo -e "\n@eslint/js@latest peerDependencies:"
curl -s https://registry.npmjs.org/@eslint/js/latest | jq '.peerDependencies'</details> <details> <summary>tooling/prettier/package.json (1)</summary> `44-50`: **Verify plugin compatibility with Prettier 3** `@trivago/prettier-plugin-sort-imports@5.2.2` has not released a Prettier 3 compatible build at the time of writing. Projects will error with:Error: Cannot find module 'prettier/parser' …
Double-check the plugin’s changelog or lock to Prettier 2 until an update lands. </details> <details> <summary>tooling/prettier/README.md (1)</summary> `1-215`: **LGTM! Comprehensive and well-structured documentation.** The README provides excellent coverage of the Prettier configuration features, usage, and integration options. The documentation is clear and includes helpful examples for various use cases. </details> <details> <summary>tooling/typescript/README.md (1)</summary> `1-255`: **Excellent TypeScript configuration documentation!** The README provides thorough coverage of the TypeScript configuration features, strict mode benefits, performance optimizations, and Vue 3 integration. The examples and troubleshooting sections are particularly helpful. </details> <details> <summary>tooling/prettier/index.mjs (1)</summary> `1-127`: **Well-crafted Prettier configuration with excellent documentation!** The configuration provides sensible defaults and comprehensive import sorting rules. The language-specific overrides are appropriate, and the JSDoc documentation clearly explains the purpose and features. </details> <details> <summary>packages/vue/src/composables/useDragHandling.ts (1)</summary> `1-235`: **Good drag handling implementation with comprehensive error handling.** Apart from the sensitivity calculation issue, the composable is well-structured with: - Proper touch/mouse event unification - Comprehensive error handling - Clear documentation - Performance optimizations Once the sensitivity calculation is fixed, this will be a solid implementation. </details> <details> <summary>packages/vue/src/composables/useStackCalculations.ts (2)</summary> `160-175`: **Great job fixing the division by zero issue!** The guard condition `if (visibleCards <= 2) return 0` properly prevents the division by zero error that was previously identified. The implementation is now safe and handles edge cases correctly. --- `1-317`: **Excellent stack calculations implementation!** This composable demonstrates high-quality code with: - Comprehensive error handling throughout - Performance optimizations with caching and memoization - Clear, detailed documentation - Well-structured computed properties - Sound mathematical calculations The calculations for card positioning, scaling, and visibility are well-thought-out and properly implemented. </details> <details> <summary>tooling/eslint/base.js (1)</summary> `1-190`: **Well-structured ESLint configuration with modern best practices!** The configuration properly uses the modern `projectService` approach for type-aware linting and includes comprehensive rules for code quality, performance, and maintainability. The placement of Prettier config at the end ensures proper rule override precedence. </details> <details> <summary>packages/vue/src/utils/debounce.ts (1)</summary> `1-170`: **Excellent implementation of debounce and throttle utilities!** The functions are well-documented, properly typed with generics, include comprehensive input validation, and provide useful cancel/flush methods for advanced control. The implementations follow standard patterns correctly. </details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
| "@eslint/js": "^9.15.0", | ||
| "eslint-config-prettier": "^9.1.0", | ||
| "eslint-config-turbo": "^2.2.3", | ||
| "eslint-plugin-vue": "^9.33.0", | ||
| "globals": "^15.12.0", | ||
| "typescript-eslint": "^8.15.0" | ||
| }, |
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.
Incorrect typescript-eslint package name
There is no package published simply as typescript-eslint.
The maintained packages are scoped under @typescript-eslint/* (e.g. @typescript-eslint/eslint-plugin, @typescript-eslint/parser). Installing the current entry will resolve to an unmaintained placeholder and break consumers that rely on the rules/parser.
- "typescript-eslint": "^8.15.0"
+ "@typescript-eslint/eslint-plugin": "^8.15.0",
+ "@typescript-eslint/parser": "^8.15.0"📝 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.
| "@eslint/js": "^9.15.0", | |
| "eslint-config-prettier": "^9.1.0", | |
| "eslint-config-turbo": "^2.2.3", | |
| "eslint-plugin-vue": "^9.33.0", | |
| "globals": "^15.12.0", | |
| "typescript-eslint": "^8.15.0" | |
| }, | |
| "@eslint/js": "^9.15.0", | |
| "eslint-config-prettier": "^9.1.0", | |
| "eslint-config-turbo": "^2.2.3", | |
| "eslint-plugin-vue": "^9.33.0", | |
| "globals": "^15.12.0", | |
| "@typescript-eslint/eslint-plugin": "^8.15.0", | |
| "@typescript-eslint/parser": "^8.15.0" |
🤖 Prompt for AI Agents
In tooling/eslint/package.json around lines 50 to 56, the dependency
"typescript-eslint" is incorrectly named and does not exist as a standalone
package. Replace "typescript-eslint" with the correct scoped packages such as
"@typescript-eslint/eslint-plugin" and/or "@typescript-eslint/parser" depending
on what is needed for your ESLint setup to ensure proper functionality and avoid
breaking consumers.
| "vue/no-useless-v-bind": "error", | ||
| "vue/no-v-text-v-html-on-component": "error", | ||
| "vue/padding-line-between-blocks": "error", | ||
| "vue/prefer-template": "error", |
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 property definition.
This vue/prefer-template rule is defined again at line 143, making this declaration redundant.
Apply this diff to remove the duplicate:
- "vue/prefer-template": "error",📝 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.
| "vue/prefer-template": "error", |
🧰 Tools
🪛 Biome (1.9.4)
[error] 79-79: This property value named vue/prefer-template is later overwritten by an object member with the same name.
Overwritten with this value.
If an object property with the same name is defined multiple times (except when combining a getter with a setter), only the last definition makes it into the object and previous definitions are ignored.
Unsafe fix: Remove this property value named vue/prefer-template
(lint/suspicious/noDuplicateObjectKeys)
🤖 Prompt for AI Agents
In tooling/eslint/vue.js at line 79, the rule "vue/prefer-template" is defined
twice, once here and again at line 143. Remove the duplicate definition at line
79 to avoid redundancy and potential conflicts, keeping only the definition at
line 143.
| export const VueCardStackPlugin = { | ||
| /** | ||
| * Install the plugin by registering the VueCardStack component globally. | ||
| * | ||
| * @param app - The Vue application instance | ||
| * @param options - Optional configuration for the plugin | ||
| */ | ||
| install: (app: App, options?: { componentName?: string }) => { | ||
| const componentName = options?.componentName ?? 'VueCardStack' | ||
|
|
||
| try { | ||
| app.component(componentName, VueCardStack) | ||
| } catch (error) { | ||
| console.error(`Failed to register ${componentName} component:`, error) | ||
| throw new Error(`VueCardStackPlugin installation failed: ${String(error)}`) | ||
| } | ||
| } | ||
| } |
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
Consider more graceful error handling for plugin installation.
Throwing an error during plugin installation might be too aggressive and could break the entire application initialization. Consider logging a warning instead of throwing, as is common practice with Vue plugins.
Apply this diff for more graceful error handling:
install: (app: App, options?: { componentName?: string }) => {
const componentName = options?.componentName ?? 'VueCardStack'
try {
app.component(componentName, VueCardStack)
} catch (error) {
console.error(`Failed to register ${componentName} component:`, error)
- throw new Error(`VueCardStackPlugin installation failed: ${String(error)}`)
+ // Don't throw to avoid breaking the entire app initialization
+ console.warn(`VueCardStackPlugin: Component registration failed but plugin installation will continue`)
}
}📝 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 VueCardStackPlugin = { | |
| /** | |
| * Install the plugin by registering the VueCardStack component globally. | |
| * | |
| * @param app - The Vue application instance | |
| * @param options - Optional configuration for the plugin | |
| */ | |
| install: (app: App, options?: { componentName?: string }) => { | |
| const componentName = options?.componentName ?? 'VueCardStack' | |
| try { | |
| app.component(componentName, VueCardStack) | |
| } catch (error) { | |
| console.error(`Failed to register ${componentName} component:`, error) | |
| throw new Error(`VueCardStackPlugin installation failed: ${String(error)}`) | |
| } | |
| } | |
| } | |
| export const VueCardStackPlugin = { | |
| /** | |
| * Install the plugin by registering the VueCardStack component globally. | |
| * | |
| * @param app - The Vue application instance | |
| * @param options - Optional configuration for the plugin | |
| */ | |
| install: (app: App, options?: { componentName?: string }) => { | |
| const componentName = options?.componentName ?? 'VueCardStack' | |
| try { | |
| app.component(componentName, VueCardStack) | |
| } catch (error) { | |
| console.error(`Failed to register ${componentName} component:`, error) | |
| // Don't throw to avoid breaking the entire app initialization | |
| console.warn(`VueCardStackPlugin: Component registration failed but plugin installation will continue`) | |
| } | |
| } | |
| } |
🤖 Prompt for AI Agents
In packages/vue/src/index.ts around lines 82 to 99, the plugin installation
currently throws an error if component registration fails, which can disrupt app
initialization. Modify the catch block to log a warning or error message without
throwing, allowing the app to continue running gracefully even if the plugin
fails to install.
| if (cfg.speed < 0.1 || cfg.speed > 5) { | ||
| throw new Error('Animation speed must be between 0.1 and 5 seconds') | ||
| } |
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.
Use constants for speed validation to maintain consistency.
The hardcoded value of 5 seconds doesn't match the CARD_STACK_CONSTANTS.MAX_SPEED which is 2.0 seconds according to the types file.
Apply this diff to use the constant:
- if (cfg.speed < 0.1 || cfg.speed > 5) {
- throw new Error('Animation speed must be between 0.1 and 5 seconds')
+ if (cfg.speed < CARD_STACK_CONSTANTS.MIN_SPEED || cfg.speed > CARD_STACK_CONSTANTS.MAX_SPEED) {
+ throw new Error(`Animation speed must be between ${CARD_STACK_CONSTANTS.MIN_SPEED} and ${CARD_STACK_CONSTANTS.MAX_SPEED} seconds`)
}📝 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.
| if (cfg.speed < 0.1 || cfg.speed > 5) { | |
| throw new Error('Animation speed must be between 0.1 and 5 seconds') | |
| } | |
| if (cfg.speed < CARD_STACK_CONSTANTS.MIN_SPEED || cfg.speed > CARD_STACK_CONSTANTS.MAX_SPEED) { | |
| throw new Error(`Animation speed must be between ${CARD_STACK_CONSTANTS.MIN_SPEED} and ${CARD_STACK_CONSTANTS.MAX_SPEED} seconds`) | |
| } |
🤖 Prompt for AI Agents
In packages/vue/src/composables/useCardStack.ts around lines 95 to 97, the speed
validation uses hardcoded values 0.1 and 5, but the maximum speed should match
the constant CARD_STACK_CONSTANTS.MAX_SPEED (2.0). Replace the hardcoded upper
limit 5 with CARD_STACK_CONSTANTS.MAX_SPEED to ensure consistency with the
defined constants.
|
|
||
| <div align="center"> | ||
|
|
||
|  |
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.
Replace placeholder URLs with actual links
The README contains placeholder URLs that need to be updated before release:
- Demo GIF URL (line 5)
- Live demo link (line 14)
- Documentation link (line 14)
- Examples link (line 14)
-
+
-[Live Demo](https://your-demo-link.com) | [Documentation](https://your-docs-link.com) | [Examples](https://github.com/your-username/vue-card-stack/tree/main/examples)
+[Live Demo](https://rodleviton.github.io/vue-card-stack/) | [Documentation](https://rodleviton.github.io/vue-card-stack/docs) | [Examples](https://github.com/rodleviton/vue-card-stack/tree/main/examples)Also applies to: 14-14
🤖 Prompt for AI Agents
In packages/vue/README.md at lines 5 and 14, replace all placeholder URLs with
the actual, correct links for the demo GIF, live demo, documentation, and
examples. Update the demo GIF URL on line 5 and the live demo, documentation,
and examples URLs on line 14 to point to the real resources before release.
| */ | ||
| export interface NavSlotProps { | ||
| /** Current active card index (0-based) */ | ||
| activeCardIndex: number | ||
| /** Function to move to the next card */ | ||
| onNext: () => void | ||
| /** Function to move to the previous card */ | ||
| onPrevious: () => void | ||
| } |
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.
NavSlotProps interface is incomplete
The NavSlotProps interface is missing properties that are actually passed to the navigation slot in the component (totalCards, isDragging).
export interface NavSlotProps {
/** Current active card index (0-based) */
activeCardIndex: number
/** Function to move to the next card */
onNext: () => void
/** Function to move to the previous card */
onPrevious: () => void
+ /** Total number of cards in the stack */
+ totalCards: number
+ /** Whether a card is currently being dragged */
+ isDragging: boolean
}📝 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 interface NavSlotProps { | |
| /** Current active card index (0-based) */ | |
| activeCardIndex: number | |
| /** Function to move to the next card */ | |
| onNext: () => void | |
| /** Function to move to the previous card */ | |
| onPrevious: () => void | |
| } | |
| export interface NavSlotProps { | |
| /** Current active card index (0-based) */ | |
| activeCardIndex: number | |
| /** Function to move to the next card */ | |
| onNext: () => void | |
| /** Function to move to the previous card */ | |
| onPrevious: () => void | |
| /** Total number of cards in the stack */ | |
| totalCards: number | |
| /** Whether a card is currently being dragged */ | |
| isDragging: boolean | |
| } |
🤖 Prompt for AI Agents
In packages/vue/src/types/index.ts between lines 190 and 198, the NavSlotProps
interface is missing the totalCards and isDragging properties that are passed to
the navigation slot. Add totalCards as a number and isDragging as a boolean to
the interface to accurately reflect all props provided to the navigation slot.
Summary by CodeRabbit
New Features
Refactor
Chores
.gitignorerules for broader development scenarios.Documentation
Style
Revert