Skip to content
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

Fix/hover variants #34

Merged
merged 3 commits into from
Jan 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions docs/content/2.components/3.layout-group.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,14 @@ Controls how the layout group inherits properties from its parent group. It can

## `Slots`

### `default`: The default slot receives forceRender function:
`default`: The default slot receives forceRender function:

- forceRender: A function that, when called, forces the slot Motion component to calculate its layout.

::alert{type="warning" icon="lucide:triangle-alert"}
When a `Motion` component is wrapped by `LayoutGroup`, its update will trigger layout updates for all `Motion` components under the `LayoutGroup`, so it's better to trigger the `Motion` update instead of calling forceRender
::

```vue
<LayoutGroup>
<template #default="{ forceRender }">
Expand All @@ -38,7 +42,7 @@ Controls how the layout group inherits properties from its parent group. It can
</LayoutGroup>
```

## useLayoutGroup Hook
## useLayoutGroup

The `useLayoutGroup` hook provides access to the layout group context, allowing components to participate in the layoutGroup and respond to forced layout.

Expand Down
28 changes: 28 additions & 0 deletions packages/motion/src/components/__tests__/gesture.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/** @jsxRuntime classic */
/** @jsxImportSource vue */
import { mount } from '@vue/test-utils'
import Motion from '../Motion.vue'
import { describe, expect, it } from 'vitest'
import { delay } from '@/shared/test'

describe('gesture', () => {
it('hover effect triggered by parent', async () => {
const wrapper = mount({
setup() {
return () => (
// @ts-ignore
<Motion hover="hover" data-testid="motion">
{/* @ts-ignore */}
Comment on lines +13 to +15

Choose a reason for hiding this comment

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

The use of @ts-ignore to bypass TypeScript's static type checking can lead to unnoticed type errors and reduce the code's maintainability. It's recommended to address the underlying type issues rather than using @ts-ignore. This might involve updating type definitions or adjusting the usage to align with expected types.

<Motion data-testid="motion-child" variants={{ hover: { scale: 1.2 } }} />
</Motion>
)
},
})
wrapper.find('[data-testid="motion"]').trigger('pointerenter')
await delay(300)
expect(wrapper.find('[data-testid="motion-child"]').element.getAttribute('style')).toBe('transform: scale(1.2);')
wrapper.find('[data-testid="motion"]').trigger('pointerleave')
await delay(300)
Comment on lines +22 to +25

Choose a reason for hiding this comment

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

The test relies on hardcoded delays (await delay(300)) to account for animations, which can lead to flaky tests. Instead, consider using more reliable synchronization mechanisms like waiting for specific changes in the DOM or using animation hooks provided by the framework to ensure the test's reliability and robustness.

expect(wrapper.find('[data-testid="motion-child"]').element.getAttribute('style')).toBe('transform: none;')
})
})
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { Transition, TransitionGroup, onMounted, onUnmounted } from 'vue'
import { Transition, TransitionGroup, computed, onMounted, onUnmounted } from 'vue'
import { mountedStates } from '@/state'
import { doneCallbacks, provideAnimatePresence, removeDoneCallback } from '@/components/presence'
import type { AnimatePresenceProps } from './types'
Expand Down Expand Up @@ -83,15 +83,25 @@ function exit(el: Element, done: VoidFunction) {
el.addEventListener('motioncomplete', doneCallback)
state.setActive('exit', true)
}

const transitionProps = computed(() => {
if (props.multiple) {
return {
tag: props.as,
}
}
return {
mode: props.mode === 'wait' ? 'out-in' : undefined,
}
})
</script>

<template>
<!-- 根据multiple属性动态选择Transition或TransitionGroup组件 -->
<!-- @vue-ignore -->
<component
:is="multiple ? TransitionGroup : Transition"
:tag="multiple ? as : undefined"
:css="false"
:mode="mode === 'wait' ? 'out-in' : undefined"
v-bind="transitionProps"
@enter="enter"
@leave="exit"
>
Expand Down
1 change: 1 addition & 0 deletions packages/motion/src/shared/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const delay = (ms: number) => new Promise(r => setTimeout(r, ms))
3 changes: 1 addition & 2 deletions packages/motion/src/state/motion-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ export class MotionState {
return
this.activeStates[name] = isActive
this.visualElement.variantChildren?.forEach((child) => {
((child as any).state as MotionState).setActive(name, isActive, false)
((child as any).state as MotionState).setActive(name, isActive, !isActive)
})

Choose a reason for hiding this comment

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

The recursive call to setActive inverts the isActive flag, which could lead to unintended toggling of state in child elements. This might cause inconsistent behavior in animations or state transitions.

Suggested Fix:
Ensure the isActive flag is passed correctly to child elements without inversion unless specifically required by the design:

child.setActive(name, isActive, isAnimate)

if (isAnimate) {
this.animateUpdates()
Expand Down Expand Up @@ -288,7 +288,6 @@ export class MotionState {
getChildAnimations = getAnimations
childAnimations = animations
}

// Wait for all animation states to read from the DOM
// yield

Expand Down
4 changes: 2 additions & 2 deletions packages/motion/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@
// Set to empty to avoid accidental inclusion of unwanted types
"types": []
},
"include": ["./src/**/*.vue", "./src/**/*.ts"],
"exclude": ["node_modules", "**/__tests__/*"]
"include": ["./src/**/*.vue", "./src/**/*.ts", "./src/**/*.tsx"],
"exclude": ["node_modules"]
}
2 changes: 1 addition & 1 deletion packages/motion/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default defineConfig({
dts({
cleanVueFileName: true,
outDir: 'dist',
exclude: ['src/test/**', 'src/**/story/**', 'src/**/*.story.vue'],
exclude: ['src/**/__tests__/**', 'src/**/story/**', 'src/**/*.story.vue'],
afterBuild: async () => {
// pnpm build:plugins
execSync('pnpm build:plugins', { stdio: 'inherit', cwd: path.resolve(__dirname, '../plugins') })

Choose a reason for hiding this comment

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

Using execSync to execute shell commands can lead to potential security risks if not properly sanitized and can block the Node.js event loop, affecting performance. Consider using the asynchronous exec function to avoid blocking and add error handling to manage any failures gracefully.

Suggested Change:

import { exec } from 'node:child_process';

// Replace execSync with exec
exec('pnpm build:plugins', { stdio: 'inherit', cwd: path.resolve(__dirname, '../plugins') }, (error, stdout, stderr) => {
  if (error) {
    console.error('Error executing build:plugins:', stderr);
    throw error;
  }
  console.log(stdout);
});

Choose a reason for hiding this comment

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

The current implementation does not handle errors that may occur during the execution of the pnpm build:plugins command. This can cause the build process to fail without adequate logging or error handling, making debugging more difficult.

Recommendation:
Implement error handling for the command execution to ensure that any issues are properly logged and managed. This could involve checking the exit status of the command and logging any errors encountered during its execution.

Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
"baseUrl": "."
},
"include": ["./packages/**/*"],
"exclude": ["node_modules", "**/__tests__/*"]
"exclude": ["node_modules"]
}
Loading