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

feat(vue): allow useAutoAnimate with Vue component ref #186

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

marshallswain
Copy link
Sponsor

This adds support for using useAutoAnimate with a component as the parent.

When you add ref="parent" to a component, the element is found at parent.value.$el. This update checks for component elements or a plain HTML element ref.

Without this change, you have to create a proxy ref to extract the element in the onMounted hook, like this:

<script setup lang="ts">
const [autoAnimateParent, enable] = useAutoAnimate()

// create a "proxy" dragParent ref which will hold a ref to the component.
const dragParent = ref()

// assign the component's $el to the autoAnimateParent once the DOM mounts
onMounted(() => (autoAnimateParent.value = dragParent.value?.$el))
</script>

<template>
  <VueDraggable
    ref="dragParent"
    v-model="items"
    :animation="300"
  >
    <!-- ... -->
  </VueDraggable>
</template>

This PR doesn't address the types. I'm not sure the best way to handle that. I did pull the code into a local repo to try it out and took this screenshot of the type issue.

Screenshot 2023-12-19 at 7 39 52 PM

If you want to instruct me how to proceed on the types, I'll update the code. Or feel free to edit this PR directly.

This adds support for using `useAutoAnimate` with a component as the parent.  

When you add `ref="parent"` to a component, the element is found at `parent.value.$el`.  This update checks for component elements or a plain HTML element ref.
Copy link

vercel bot commented Dec 20, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
auto-animate ✅ Ready (Inspect) Visit Preview 💬 Add feedback Dec 20, 2023 3:47am

@marshallswain
Copy link
Sponsor Author

I just noticed this other PR. #159

I think their objective is the same, based on this comment: #159 (comment).

@marshallswain
Copy link
Sponsor Author

Sorry about being lazy with the types. I'm not a TS ninja by any means, but I took a crack at it. Maybe you'll see a more optimal way to handle the ElementOrComponentRef type:

import { onMounted, ref, watchEffect } from 'vue'
import type { Directive, Plugin, Ref } from 'vue'
import type {
  AnimationController,
  AutoAnimateOptions,
  AutoAnimationPlugin,
} from '@formkit/auto-animate'
import autoAnimate, { vAutoAnimate as autoAnimateDirective,
} from '@formkit/auto-animate'

export const vAutoAnimate: Directive<
  HTMLElement,
  Partial<AutoAnimateOptions>
> = autoAnimateDirective

export const autoAnimatePlugin: Plugin = {
  install(app) {
    app.directive('auto-animate', vAutoAnimate)
  },
}

export type ElementOrComponentRef<T extends Element> = T & { $el?: Element }

/**
 * AutoAnimate hook for adding dead-simple transitions and animations to Vue.
 * @param options - Auto animate options or a plugin
 * @returns A template ref. Use the `ref` attribute of your parent element
 * to store the element in this template ref.
 */
export function useAutoAnimate<T extends Element>(
  options?: Partial<AutoAnimateOptions> | AutoAnimationPlugin,
): [Ref<ElementOrComponentRef<T>>, (enabled: boolean) => void] {
  const element = ref<ElementOrComponentRef<T>>()
  let controller: AnimationController | undefined
  function setEnabled(enabled: boolean) {
    if (controller)
      enabled ? controller.enable() : controller.disable()
  }
  onMounted(() => {
    watchEffect(() => {
      const el = element.value?.$el || element.value
      if (el instanceof HTMLElement)
        controller = autoAnimate(el, options || {})
    })
  })

  return [element as Ref<T>, setEnabled]
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant