Open mattbryson opened 2 weeks ago
I found what was going on. When using the directive, it uses the mounted
lifecycle hook, but that is for the parent component, NOT the element that the directive is on.
So for elements added after mounted
they are not added to singleton group.
For now I have a patch to get it working for anyone with this issue, which I can make into a pull request at some point.
Add this file to your project.
import { DirectiveHook, ObjectDirective, Ref, ref, watchEffect } from 'vue';
import { CreateSingletonProps, Instance } from 'tippy.js';
import { directive, useSingleton as orig_useSingleton } from 'vue-tippy';
/**
* Custom useSingleton function to keep a reference to the instances it manages.
* Tippy.js does not expose this (that I can see), so we ned to to hold on to it
* externally, and then re apply it when it changes
*/
function useSingleton(opts?:Partial<CreateSingletonProps>) {
const instances:Ref<Instance[]> = ref([]);
const data = orig_useSingleton(instances, opts);
watchEffect(() => {
if(data.singleton.value) {
data.singleton.value.setInstances( instances.value );
}
});
return {
...data,
instances
};
}
// Clone the exisitng Tippy directive, and swap the mounted for created....
const vTippyPatched:ObjectDirective & { orig_mounted?:DirectiveHook<any, null, any> } = {...directive};
vTippyPatched.orig_mounted = vTippyPatched.mounted;
delete vTippyPatched.mounted;
vTippyPatched.created = (el, binding, vnode, prevVNode) => {
const opts = typeof binding.value === "string" ? { content: binding.value } : binding.value || {}
// call the orig mounted logic
if(vTippyPatched.orig_mounted) {
vTippyPatched.orig_mounted(el, binding, vnode, prevVNode);
// if we have a singleton options, append this to its instance list
if(el._tippy && opts.singleton) {
opts.singleton.instances.value.push(el._tippy);
}
}
}
export { useSingleton, vTippyPatched };
To replace the current v-tippy
directive with this one, you can do the following....
import { vTippyPatched } from '@app/directives/tippyPatch';
.....
app.use(VueTippy, {directive: 'tippy-orig'});
// Patch the Tippy directive to support singleton
app.directive('tippy', vTippyPatched);
And then to use it, do the following....
<script>
import { useSingleton } from '@app/directives/tippyPatch';
const singleton = useSingleton({moveTransition: 'transform 0.2s ease-out', delay:[1000,500]});
</script>
<template>
<button v-tippy="{content:'One', singleton}" >One</button>
<button v-tippy="{content:'Two', singleton}" >Two</button>
<button v-tippy="{content:'Three', singleton}" >Three</button>
</template>
I'm trying to group a few Buttons using the
useSingleton
approach.This works when the Buttons are present when the component mounts, but if they are conditionally added later, they just use the default Tippy settings, not the singleton settings.
See a working demo here
It does work if you use the
<tippy>
and<tippy-singleton>
components, but not if you mix thev-tippy
directive, and theuseSingleton
composition API as per the example https://vue-tippy.netlify.app/flavor/composition-api#example-1-1I have tried calling
useSingleton
after they are added, have tried delaying adding them to theinstances
array etc etc but nothing I do appears to work.Any ideas on how to get this working?