reactive singleton

This commit is contained in:
Georges KABBOUCHI
2024-06-26 20:18:11 +03:00
parent 6b30c17a37
commit 8bfb1ecfda
8 changed files with 688 additions and 536 deletions
+2 -2
View File
@@ -91,8 +91,8 @@ useTippy(btn, {
```vue ```vue
<template> <template>
<div> <div>
<button :ref="v => singletons.push(v)" v-tippy="'Tooltip 1'">Button 1</button> <button ref="singletons" v-tippy="'Tooltip 1'">Button 1</button>
<button :ref="v => singletons.push(v)" v-tippy="'Tooltip 2'">Button 2</button> <button ref="singletons" v-tippy="'Tooltip 2'">Button 2</button>
</div> </div>
</template> </template>
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "vue-tippy", "name": "vue-tippy",
"version": "6.4.1", "version": "6.4.2",
"main": "index.js", "main": "index.js",
"module": "dist/vue-tippy.mjs", "module": "dist/vue-tippy.mjs",
"unpkg": "dist/vue-tippy.iife.js", "unpkg": "dist/vue-tippy.iife.js",
@@ -68,7 +68,7 @@
"ts-loader": "^8.0.2", "ts-loader": "^8.0.2",
"ts-node": "^8.10.2", "ts-node": "^8.10.2",
"typescript": "^4.1.3", "typescript": "^4.1.3",
"vue": "^3.2.0", "vue": "3.2.47",
"vue-loader": "^16.0.0-beta.8", "vue-loader": "^16.0.0-beta.8",
"vue-router": "4", "vue-router": "4",
"webpack": "^4.44.1", "webpack": "^4.44.1",
+478 -462
View File
@@ -1,486 +1,502 @@
<template> <template>
<div>
<div> <div>
<span class="font-semibold mr-4" <div>
>Tippy Component + custom element target:</span <span class="font-semibold mr-4"
> >Tippy Component + custom element target:</span
>
<tippy content="test" to="#btn123"></tippy> <tippy content="test" to="#btn123"></tippy>
<button <button
id="btn123" id="btn123"
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg" class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
> >
Hi Hi
</button> </button>
</div>
<div class="mt-6">
<span class="font-semibold mr-4">Tippy Component:</span>
<tippy
content="test"
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
>
Hi
</tippy>
</div>
<div class="mt-6">
<span class="font-semibold mr-4"
>Tippy Component with content slot:</span
>
<tippy
interactive
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
>
Hi
<template #content>
<button
class="text-sm py-2 px-3 bg-gray-100 text-black rounded-lg"
@click="counter++"
>
Counter {{ counter }} (click to increase)
</button>
</template>
</tippy>
</div>
<div class="mt-6">
<span class="font-semibold mr-4"
>Tippy Component with component content slot:</span
>
<tippy
interactive
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
>
Hi
<template #content>
<counter />
</template>
</tippy>
</div>
<div class="mt-6">
<span class="font-semibold mr-4"
>Tippy component + content slot data</span
>
<tippy interactive :hideOnClick="false" trigger="manual">
<template #default="{ show }">
<button
@click="show"
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
>
Hi
</button>
</template>
<template #content="{ tippy, hide }" class="relative">
<button
class="absolute top-0 right-0 m-2 w-6 h-6 bg-white text-black rounded"
@click="hide()"
>
&times;
</button>
<pre class="p-4">{{ tippy && tippy.state }}</pre>
</template>
</tippy>
</div>
<div class="mt-6">
<span class="font-semibold mr-4"
>Tippy as a child component with prop content:</span
>
<button class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg">
Hi
<tippy to="parent" content="Test"></tippy>
</button>
</div>
<div class="mt-6">
<span class="font-semibold mr-4"
>Tippy as a child component with #content template:</span
>
<button class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg">
Hi
<tippy to="parent"><template #content>Test</template></tippy>
</button>
</div>
<div class="mt-6">
<span class="font-semibold mr-4"
>Tippy as a child component with direct content:</span
>
<button class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg">
Hi
<tippy to="parent">{{ counter }} and counting</tippy>
</button>
</div>
<div class="mt-6">
<span class="font-semibold mr-4"
>useTippy + callbacks(console.log):</span
>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="button"
>
My Button
</button>
</div>
<div class="mt-6">
<span class="font-semibold mr-4">useTippy + h(tag) content:</span>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="button2"
>
My Button 2
</button>
</div>
<div class="mt-6">
<span class="font-semibold mr-4"
>useTippy + h (reactive) content:</span
>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="button3"
>
My Button 3
</button>
</div>
<div class="mt-6">
<span class="font-semibold mr-4">useTippy + h(SFC) content:</span>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="button4"
>
My Button 4
</button>
</div>
<div class="mt-6">
<span class="font-semibold mr-4">useTippy + SFC content:</span>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="button5"
>
My Button 5
</button>
</div>
<div class="mt-6">
<span class="font-semibold mr-4">useTippy + reactive options:</span>
<button
class="mr-4 text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
@click="button6Inc"
>
My Button 6 - Inc & Refresh
</button>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="button6"
>
My Button 6
</button>
</div>
<div class="mt-6">
<span ref="target7" class="font-semibold mr-4"
>useTippy + triggerTarget:</span
>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="button7"
>
My Button 7
</button>
</div>
<div class="mt-6">
<span class="font-semibold mr-4"
>Tippy component + change content and props realtime using
component ref:</span
>
<tippy ref="tippyComponent1" @create="log" @hide="log">
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
>
Tippy Component + h(SFC) content
</button>
</tippy>
</div>
<div class="mt-6">
<span class="font-semibold mr-4">v-tippy:</span>
<button
class="text-sm py-2 px-3 mr-4 bg-gray-900 text-white rounded-lg"
@tippyMount="() => log('v-tippy mounted')"
v-tippy="{ content: 'Hello ' + counter }"
>
Tippy directive
</button>
<button
class="text-sm py-2 px-3 mr-4 bg-gray-900 text-white rounded-lg"
v-tippy="'Passing in a string'"
>
Tippy directive with a string
</button>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
v-tippy="`Hello ${counter}`"
>
Tippy directive with template literals
</button>
</div>
<div class="mt-6 space-x-2">
<span class="font-semibold mr-4"
>Singleton tippy with a transition:</span
>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="singleton1"
>
singleton1
</button>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="singleton2"
>
singleton2
</button>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="singleton3"
>
singleton3
</button>
</div>
<div class="mt-6 space-x-2">
<span class="font-semibold mr-4"
>Singleton v-tippy with a transition:</span
>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="singletons"
v-tippy="{ content: 'Tooltip 1' }"
>
singleton1
</button>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="singletons"
v-tippy="{ content: 'Tooltip 2' }"
>
singleton2
</button>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="singletons"
v-tippy="{ content: 'Tooltip 3' }"
>
singleton3
</button>
</div>
<div class="mt-6">
<span class="font-semibold mr-4">v-tippy with modifiers</span>
<button
class="text-sm py-2 px-3 mr-4 bg-gray-900 text-white rounded-lg"
v-tippy.left.arrow="'Hello'"
>
Tippy
</button>
</div>
</div> </div>
<div class="mt-6">
<span class="font-semibold mr-4">Tippy Component:</span>
<tippy
content="test"
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
>
Hi
</tippy>
</div>
<div class="mt-6">
<span class="font-semibold mr-4">Tippy Component with content slot:</span>
<tippy
interactive
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
>
Hi
<template #content>
<button
class="text-sm py-2 px-3 bg-gray-100 text-black rounded-lg"
@click="counter++"
>
Counter {{ counter }} (click to increase)
</button>
</template>
</tippy>
</div>
<div class="mt-6">
<span class="font-semibold mr-4"
>Tippy Component with component content slot:</span
>
<tippy
interactive
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
>
Hi
<template #content>
<counter />
</template>
</tippy>
</div>
<div class="mt-6">
<span class="font-semibold mr-4"
>Tippy component + content slot data</span
>
<tippy interactive :hideOnClick="false" trigger="manual">
<template #default="{ show }">
<button
@click="show"
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
>
Hi
</button>
</template>
<template #content="{ tippy, hide }" class="relative">
<button
class="absolute top-0 right-0 m-2 w-6 h-6 bg-white text-black rounded"
@click="hide()"
>
&times;
</button>
<pre class="p-4">{{ tippy && tippy.state }}</pre>
</template>
</tippy>
</div>
<div class="mt-6">
<span class="font-semibold mr-4">Tippy as a child component with prop content:</span>
<button class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg">
Hi
<tippy to="parent" content="Test"></tippy>
</button>
</div>
<div class="mt-6">
<span class="font-semibold mr-4">Tippy as a child component with #content template:</span>
<button class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg">
Hi
<tippy to="parent"><template #content>Test</template></tippy>
</button>
</div>
<div class="mt-6">
<span class="font-semibold mr-4">Tippy as a child component with direct content:</span>
<button class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg">
Hi
<tippy to="parent">{{counter}} and counting</tippy>
</button>
</div>
<div class="mt-6">
<span class="font-semibold mr-4">useTippy + callbacks(console.log):</span>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="button"
>
My Button
</button>
</div>
<div class="mt-6">
<span class="font-semibold mr-4">useTippy + h(tag) content:</span>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="button2"
>
My Button 2
</button>
</div>
<div class="mt-6">
<span class="font-semibold mr-4">useTippy + h (reactive) content:</span>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="button3"
>
My Button 3
</button>
</div>
<div class="mt-6">
<span class="font-semibold mr-4">useTippy + h(SFC) content:</span>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="button4"
>
My Button 4
</button>
</div>
<div class="mt-6">
<span class="font-semibold mr-4">useTippy + SFC content:</span>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="button5"
>
My Button 5
</button>
</div>
<div class="mt-6">
<span class="font-semibold mr-4">useTippy + reactive options:</span>
<button
class="mr-4 text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
@click="button6Inc"
>
My Button 6 - Inc & Refresh
</button>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="button6"
>
My Button 6
</button>
</div>
<div class="mt-6">
<span ref="target7" class="font-semibold mr-4"
>useTippy + triggerTarget:</span
>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="button7"
>
My Button 7
</button>
</div>
<div class="mt-6">
<span class="font-semibold mr-4"
>Tippy component + change content and props realtime using component
ref:</span
>
<tippy ref="tippyComponent1" @create="log" @hide="log">
<button class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg">
Tippy Component + h(SFC) content
</button>
</tippy>
</div>
<div class="mt-6">
<span class="font-semibold mr-4">v-tippy:</span>
<button
class="text-sm py-2 px-3 mr-4 bg-gray-900 text-white rounded-lg"
@tippyMount="() => log('v-tippy mounted')"
v-tippy="{ content: 'Hello ' + counter }"
>
Tippy directive
</button>
<button
class="text-sm py-2 px-3 mr-4 bg-gray-900 text-white rounded-lg"
v-tippy="'Passing in a string'"
>
Tippy directive with a string
</button>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
v-tippy="`Hello ${counter}`"
>
Tippy directive with template literals
</button>
</div>
<div class="mt-6 space-x-2">
<span class="font-semibold mr-4">Singleton tippy with a transition:</span>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="singleton1"
>
singleton1
</button>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="singleton2"
>
singleton2
</button>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
ref="singleton3"
>
singleton3
</button>
</div>
<div class="mt-6 space-x-2">
<span class="font-semibold mr-4"
>Singleton v-tippy with a transition:</span
>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
:ref="v => singletons.push(v)"
v-tippy="{ content: 'Tooltip 1' }"
>
singleton1
</button>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
:ref="v => singletons.push(v)"
v-tippy="{ content: 'Tooltip 2' }"
>
singleton2
</button>
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
:ref="v => singletons.push(v)"
v-tippy="{ content: 'Tooltip 3' }"
>
singleton3
</button>
</div>
<div class="mt-6">
<span class="font-semibold mr-4">v-tippy with modifiers</span>
<button
class="text-sm py-2 px-3 mr-4 bg-gray-900 text-white rounded-lg"
v-tippy.left.arrow="'Hello'"
>
Tippy
</button>
</div>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { import {
defineComponent, defineComponent,
ref, ref,
h, h,
computed, computed,
reactive, reactive,
onMounted, onMounted,
onUnmounted, onUnmounted,
watch, watch,
} from 'vue' } from 'vue'
import { useSingleton, useTippy, TippyOptions, TippyComponent } from '../../src' import { useSingleton, useTippy, TippyOptions, TippyComponent } from '../../src'
import Counter from '../components/Counter.vue' import Counter from '../components/Counter.vue'
function useMousePosition() { function useMousePosition() {
const x = ref(0) const x = ref(0)
const y = ref(0) const y = ref(0)
function handler(e: MouseEvent) { function handler(e: MouseEvent) {
x.value = e.clientX x.value = e.clientX
y.value = e.clientY y.value = e.clientY
}
onMounted(() => {
window.addEventListener('mousemove', handler, false)
})
onUnmounted(() => {
window.removeEventListener('mousemove', handler, false)
})
return {
x,
y,
}
}
export default defineComponent({
setup() {
const counter = ref<number>(0)
setInterval(() => counter.value++, 1000)
const button = ref<HTMLButtonElement>()
const button2 = ref<HTMLButtonElement>()
const button3 = ref<HTMLButtonElement>()
const button4 = ref<HTMLButtonElement>()
const button5 = ref<HTMLButtonElement>()
const button6 = ref<HTMLButtonElement>()
const button7 = ref<HTMLButtonElement>()
const target7 = ref<HTMLButtonElement>()
useTippy(button, {
content: 'Test',
onMount() {
console.log('here')
},
})
useTippy(button2, {
content: h('h1', 'hi'),
})
useTippy(button3, {
content: computed(() =>
h(
'button',
{
onClick: () => {
counter.value++
},
},
'Counter ' + counter.value
)
),
showOnCreate: true,
interactive: true,
})
useTippy(button4, {
content: h(Counter),
interactive: true,
showOnCreate: true,
})
useTippy(button5, {
content: defineComponent(() => {
return () => h('p', 'Hellooooo')
}),
interactive: true,
showOnCreate: true,
})
const options = reactive<TippyOptions>({
content: '1',
sticky: true,
showOnCreate: true,
hideOnClick: false,
trigger: 'manual',
})
useTippy(button6, options)
const button6Inc = () => {
options.content = String(parseInt(options.content) + 1)
} }
useTippy(target7, {
content: 'Triggered by button7',
placement: 'bottom',
triggerTarget: button7,
})
const { x, y } = useMousePosition()
const { tippy } = useTippy(() => document.body, {
content: computed(() => `(${x.value},${y.value})`),
showOnCreate: true,
trigger: 'manual',
// sticky: true, // slow?
placement: 'top',
hideOnClick: false,
arrow: `<svg style="color: black;width:20px;height:20px" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-8.707l-3-3a1 1 0 00-1.414 0l-3 3a1 1 0 001.414 1.414L9 9.414V13a1 1 0 102 0V9.414l1.293 1.293a1 1 0 001.414-1.414z" clip-rule="evenodd"></path></svg>`,
getReferenceClientRect: function() {
return {
width: 0,
height: 0,
top: y.value,
right: x.value,
bottom: y.value,
left: x.value,
}
},
})
watch([x, y], () => tippy.value?.popperInstance?.update())
const tippyComponent1 = ref<TippyComponent>()
onMounted(() => { onMounted(() => {
tippyComponent1.value?.setProps({ window.addEventListener('mousemove', handler, false)
interactive: true,
offset: [0, 30],
placement: 'top',
})
tippyComponent1.value?.setContent(
h(Counter, {
initialValue: 42,
})
)
}) })
const singleton1 = ref() onUnmounted(() => {
const singleton2 = ref() window.removeEventListener('mousemove', handler, false)
const singleton3 = ref()
const { tippy: tippySingleton1 } = useTippy(singleton1, {
content: 'Singleton 1',
})
const { tippy: tippySingleton2 } = useTippy(singleton2, {
content: '<b>Singleton 2</b>',
})
const { tippy: tippySingleton3 } = useTippy(singleton3, {
content: 'Singleton 3',
})
useSingleton([tippySingleton1, tippySingleton2, tippySingleton3], {
placement: 'top',
moveTransition: 'transform 0.2s ease-out',
})
const singletons = ref([])
useSingleton(singletons, {
placement: 'top',
moveTransition: 'transform 0.2s ease-out',
}) })
return { return {
singleton1, x,
singleton2, y,
singleton3,
singletons,
counter,
button,
button2,
button3,
button4,
button5,
button6,
button6Inc,
button7,
target7,
tippyComponent1,
log: console.log,
} }
}, }
export default defineComponent({
setup() {
const counter = ref<number>(0)
setInterval(() => counter.value++, 1000)
const button = ref<HTMLButtonElement>()
const button2 = ref<HTMLButtonElement>()
const button3 = ref<HTMLButtonElement>()
const button4 = ref<HTMLButtonElement>()
const button5 = ref<HTMLButtonElement>()
const button6 = ref<HTMLButtonElement>()
const button7 = ref<HTMLButtonElement>()
const target7 = ref<HTMLButtonElement>()
useTippy(button, {
content: 'Test',
onMount() {
console.log('here')
},
})
useTippy(button2, {
content: h('h1', 'hi'),
})
useTippy(button3, {
content: computed(() =>
h(
'button',
{
onClick: () => {
counter.value++
},
},
'Counter ' + counter.value
)
),
showOnCreate: true,
interactive: true,
})
useTippy(button4, {
content: h(Counter),
interactive: true,
showOnCreate: true,
})
useTippy(button5, {
content: defineComponent(() => {
return () => h('p', 'Hellooooo')
}),
interactive: true,
showOnCreate: true,
})
const options = reactive<TippyOptions>({
content: '1',
sticky: true,
showOnCreate: true,
hideOnClick: false,
trigger: 'manual',
})
useTippy(button6, options)
const button6Inc = () => {
options.content = String(parseInt(options.content) + 1)
}
useTippy(target7, {
content: 'Triggered by button7',
placement: 'bottom',
triggerTarget: button7,
})
const { x, y } = useMousePosition()
const { tippy } = useTippy(() => document.body, {
content: computed(() => `(${x.value},${y.value})`),
showOnCreate: true,
trigger: 'manual',
// sticky: true, // slow?
placement: 'top',
hideOnClick: false,
arrow: `<svg style="color: black;width:20px;height:20px" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-8.707l-3-3a1 1 0 00-1.414 0l-3 3a1 1 0 001.414 1.414L9 9.414V13a1 1 0 102 0V9.414l1.293 1.293a1 1 0 001.414-1.414z" clip-rule="evenodd"></path></svg>`,
getReferenceClientRect: function () {
return {
width: 0,
height: 0,
top: y.value,
right: x.value,
bottom: y.value,
left: x.value,
}
},
})
watch([x, y], () => tippy.value?.popperInstance?.update())
const tippyComponent1 = ref<TippyComponent>()
onMounted(() => {
tippyComponent1.value?.setProps({
interactive: true,
offset: [0, 30],
placement: 'top',
})
tippyComponent1.value?.setContent(
h(Counter, {
initialValue: 42,
})
)
})
const singleton1 = ref()
const singleton2 = ref()
const singleton3 = ref()
const { tippy: tippySingleton1 } = useTippy(singleton1, {
content: 'Singleton 1',
})
const { tippy: tippySingleton2 } = useTippy(singleton2, {
content: '<b>Singleton 2</b>',
})
const { tippy: tippySingleton3 } = useTippy(singleton3, {
content: 'Singleton 3',
})
useSingleton([tippySingleton1, tippySingleton2, tippySingleton3], {
placement: 'top',
moveTransition: 'transform 0.2s ease-out',
})
const singletons = ref([])
useSingleton(singletons, {
placement: 'top',
moveTransition: 'transform 0.2s ease-out',
})
return {
singleton1,
singleton2,
singleton3,
singletons,
counter,
button,
button2,
button3,
button4,
button5,
button6,
button6Inc,
button7,
target7,
tippyComponent1,
log: console.log,
}
},
}) })
</script> </script>
+74 -18
View File
@@ -1,23 +1,79 @@
<template> <template>
<div class="grid grid-cols-4 gap-4 "> <div class="space-y-5">
<tippy-singleton move-transition="transform 0.2s ease-out" placement="top"> <div class="grid grid-cols-4 gap-4">
<tippy <tippy-singleton
v-for="i in 10" move-transition="transform 0.2s ease-out"
:key="i" placement="top"
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg" >
> <tippy
<template #content> v-for="i in count"
<div>Working tooltip</div> :key="i"
</template> class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
Button {{ i }} tag="button"
</tippy> >
</tippy-singleton> <template #content>
</div> <div>Working tooltip</div>
</template>
Button {{ i }}
</tippy>
</tippy-singleton>
</div>
<hr />
<div class="grid grid-cols-4 gap-4">
<button
ref="tippyRefs"
v-tippy="`Tooltip ${i}`"
v-for="i in count"
:key="i"
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
>
Button {{ i }}
</button>
</div>
<hr />
<div class="flex items-center w-full">
<button
class="text-sm py-2 px-3 bg-gray-900 text-white rounded-lg"
@click="count++"
>
Add buttons
</button>
</div>
</div>
</template> </template>
<script> <script>
import { ref } from "vue"; import { ref, watch } from 'vue'
import { useSingleton } from '../../src'
export default { export default {
name: "App", name: 'App',
}; setup() {
</script> const tippyRefs = ref([])
useSingleton(tippyRefs, {
moveTransition: 'transform 0.2s ease-out',
delay: [250, 50],
placement: 'bottom',
})
watch(tippyRefs, () => {
console.log('tippyRefs', tippyRefs.value)
})
return {
tippyRefs,
log: console.log,
}
},
data() {
return {
count: 10,
}
},
}
</script>
+13 -3
View File
@@ -44,7 +44,6 @@ Object.keys(tippy.defaultProps).forEach((prop: string) => {
} }
}) })
const TippySingleton = defineComponent({ const TippySingleton = defineComponent({
props, props,
setup(props) { setup(props) {
@@ -61,9 +60,20 @@ const TippySingleton = defineComponent({
this.instances = Array.from(elements) this.instances = Array.from(elements)
.map((el: any) => el._tippy) .map((el: any) => el._tippy)
.filter(Boolean) .filter(Boolean)
this.singleton?.setInstances(this.instances)
}, },
updated() {
const parent = this.$el?.parentElement
if (parent) {
const elements = parent.querySelectorAll('[data-v-tippy]')
this.instances = Array.from(elements)
.map((el: any) => el._tippy)
.filter(Boolean)
}
},
render() { render() {
let slot = this.$slots.default ? this.$slots.default() : [] let slot = this.$slots.default ? this.$slots.default() : []
+16 -5
View File
@@ -5,7 +5,7 @@ import {
Instance, Instance,
Props, Props,
} from 'tippy.js' } from 'tippy.js'
import { onMounted, ref } from 'vue' import { onMounted, ref, watch } from 'vue'
export function useSingleton( export function useSingleton(
instances: TippyInstances, instances: TippyInstances,
@@ -13,12 +13,12 @@ export function useSingleton(
) { ) {
const singleton = ref<ReturnType<typeof createSingleton>>() const singleton = ref<ReturnType<typeof createSingleton>>()
onMounted(() => { const getTippyInstances = () => {
const pendingTippyInstances: TippyInstance[] = Array.isArray(instances) const pendingTippyInstances: TippyInstance[] = Array.isArray(instances)
? instances.map(i => i.value) ? instances.map(i => i.value)
: typeof instances === 'function' : typeof instances === 'function'
? instances() ? instances()
: instances.value : instances.value
const tippyInstances: Instance<any>[] = pendingTippyInstances const tippyInstances: Instance<any>[] = pendingTippyInstances
.map((instance: TippyInstance) => { .map((instance: TippyInstance) => {
@@ -30,14 +30,25 @@ export function useSingleton(
}) })
.filter(Boolean) .filter(Boolean)
return tippyInstances
}
onMounted(() => {
singleton.value = createSingleton( singleton.value = createSingleton(
tippyInstances, getTippyInstances(),
optionalProps optionalProps
? { allowHTML: true, ...optionalProps } ? { allowHTML: true, ...optionalProps }
: { allowHTML: true } : { allowHTML: true }
) )
}) })
watch(
Array.isArray(instances) ? () => instances.map(i => i.value) : instances,
() => {
singleton.value?.setInstances(getTippyInstances())
}
)
return { return {
singleton, singleton,
} }
+12 -11
View File
@@ -28,11 +28,11 @@ export function useTippy(
el: Element | (() => Element) | Ref<Element> | Ref<Element | undefined>, el: Element | (() => Element) | Ref<Element> | Ref<Element | undefined>,
opts: TippyOptions = {}, opts: TippyOptions = {},
settings: { settings: {
mount: boolean, mount: boolean
appName: string, appName: string
} = { mount: true, appName: 'Tippy' } } = { mount: true, appName: 'Tippy' }
) { ) {
settings = Object.assign({ mount: true, appName: 'Tippy' }, settings); settings = Object.assign({ mount: true, appName: 'Tippy' }, settings)
const vm = getCurrentInstance() const vm = getCurrentInstance()
const instance = ref<Instance>() const instance = ref<Instance>()
@@ -62,13 +62,12 @@ export function useTippy(
? content.value ? content.value
: content : content
if (isVNode(unwrappedContent)) { if (isVNode(unwrappedContent)) {
if (!headlessApp.value) { if (!headlessApp.value) {
headlessApp.value = createApp({ headlessApp.value = createApp({
name: settings.appName, name: settings.appName,
setup: () => { setup: () => {
return () => isRef(content) ? content.value : content return () => (isRef(content) ? content.value : content)
}, },
}) })
@@ -84,7 +83,7 @@ export function useTippy(
headlessApp.value = createApp({ headlessApp.value = createApp({
name: settings.appName, name: settings.appName,
setup: () => { setup: () => {
return () => h(isRef(content) ? content.value : content as any) return () => h(isRef(content) ? content.value : (content as any))
}, },
}) })
@@ -128,7 +127,9 @@ export function useTippy(
options.plugins = [] options.plugins = []
} }
options.plugins = options.plugins.filter((plugin: any) => plugin.name !== 'vueTippyReactiveState'); options.plugins = options.plugins.filter(
(plugin: any) => plugin.name !== 'vueTippyReactiveState'
)
options.plugins.push({ options.plugins.push({
name: 'vueTippyReactiveState', name: 'vueTippyReactiveState',
@@ -161,7 +162,7 @@ export function useTippy(
state.value.isDestroyed = true state.value.isDestroyed = true
}, },
} }
} },
}) })
return options as Props return options as Props
@@ -192,7 +193,7 @@ export function useTippy(
try { try {
//@ts-ignore //@ts-ignore
// delete instance.value.reference.$tippy // delete instance.value.reference.$tippy
} catch (error) { } } catch (error) {}
instance.value.destroy() instance.value.destroy()
instance.value = undefined instance.value = undefined
@@ -212,12 +213,12 @@ export function useTippy(
const disable = () => { const disable = () => {
instance.value?.disable() instance.value?.disable()
state.value.isEnabled = false; state.value.isEnabled = false
} }
const enable = () => { const enable = () => {
instance.value?.enable() instance.value?.enable()
state.value.isEnabled = true; state.value.isEnabled = true
} }
const unmount = () => { const unmount = () => {
+91 -33
View File
@@ -251,6 +251,16 @@
estree-walker "^2.0.2" estree-walker "^2.0.2"
source-map "^0.6.1" source-map "^0.6.1"
"@vue/compiler-core@3.2.47":
version "3.2.47"
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.47.tgz#3e07c684d74897ac9aa5922c520741f3029267f8"
integrity sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==
dependencies:
"@babel/parser" "^7.16.4"
"@vue/shared" "3.2.47"
estree-walker "^2.0.2"
source-map "^0.6.1"
"@vue/compiler-dom@3.2.37": "@vue/compiler-dom@3.2.37":
version "3.2.37" version "3.2.37"
resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.37.tgz#10d2427a789e7c707c872da9d678c82a0c6582b5" resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.37.tgz#10d2427a789e7c707c872da9d678c82a0c6582b5"
@@ -259,7 +269,31 @@
"@vue/compiler-core" "3.2.37" "@vue/compiler-core" "3.2.37"
"@vue/shared" "3.2.37" "@vue/shared" "3.2.37"
"@vue/compiler-sfc@3.2.37", "@vue/compiler-sfc@^3.2.0": "@vue/compiler-dom@3.2.47":
version "3.2.47"
resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.47.tgz#a0b06caf7ef7056939e563dcaa9cbde30794f305"
integrity sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==
dependencies:
"@vue/compiler-core" "3.2.47"
"@vue/shared" "3.2.47"
"@vue/compiler-sfc@3.2.47":
version "3.2.47"
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz#1bdc36f6cdc1643f72e2c397eb1a398f5004ad3d"
integrity sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==
dependencies:
"@babel/parser" "^7.16.4"
"@vue/compiler-core" "3.2.47"
"@vue/compiler-dom" "3.2.47"
"@vue/compiler-ssr" "3.2.47"
"@vue/reactivity-transform" "3.2.47"
"@vue/shared" "3.2.47"
estree-walker "^2.0.2"
magic-string "^0.25.7"
postcss "^8.1.10"
source-map "^0.6.1"
"@vue/compiler-sfc@^3.2.0":
version "3.2.37" version "3.2.37"
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.37.tgz#3103af3da2f40286edcd85ea495dcb35bc7f5ff4" resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.37.tgz#3103af3da2f40286edcd85ea495dcb35bc7f5ff4"
integrity sha512-+7i/2+9LYlpqDv+KTtWhOZH+pa8/HnX/905MdVmAcI/mPQOBwkHHIzrsEsucyOIZQYMkXUiTkmZq5am/NyXKkg== integrity sha512-+7i/2+9LYlpqDv+KTtWhOZH+pa8/HnX/905MdVmAcI/mPQOBwkHHIzrsEsucyOIZQYMkXUiTkmZq5am/NyXKkg==
@@ -283,6 +317,14 @@
"@vue/compiler-dom" "3.2.37" "@vue/compiler-dom" "3.2.37"
"@vue/shared" "3.2.37" "@vue/shared" "3.2.37"
"@vue/compiler-ssr@3.2.47":
version "3.2.47"
resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.2.47.tgz#35872c01a273aac4d6070ab9d8da918ab13057ee"
integrity sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==
dependencies:
"@vue/compiler-dom" "3.2.47"
"@vue/shared" "3.2.47"
"@vue/reactivity-transform@3.2.37": "@vue/reactivity-transform@3.2.37":
version "3.2.37" version "3.2.37"
resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.37.tgz#0caa47c4344df4ae59f5a05dde2a8758829f8eca" resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.37.tgz#0caa47c4344df4ae59f5a05dde2a8758829f8eca"
@@ -294,43 +336,59 @@
estree-walker "^2.0.2" estree-walker "^2.0.2"
magic-string "^0.25.7" magic-string "^0.25.7"
"@vue/reactivity@3.2.37": "@vue/reactivity-transform@3.2.47":
version "3.2.37" version "3.2.47"
resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.2.37.tgz#5bc3847ac58828e2b78526e08219e0a1089f8848" resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.47.tgz#e45df4d06370f8abf29081a16afd25cffba6d84e"
integrity sha512-/7WRafBOshOc6m3F7plwzPeCu/RCVv9uMpOwa/5PiY1Zz+WLVRWiy0MYKwmg19KBdGtFWsmZ4cD+LOdVPcs52A== integrity sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==
dependencies: dependencies:
"@vue/shared" "3.2.37" "@babel/parser" "^7.16.4"
"@vue/compiler-core" "3.2.47"
"@vue/shared" "3.2.47"
estree-walker "^2.0.2"
magic-string "^0.25.7"
"@vue/runtime-core@3.2.37": "@vue/reactivity@3.2.47":
version "3.2.37" version "3.2.47"
resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.2.37.tgz#7ba7c54bb56e5d70edfc2f05766e1ca8519966e3" resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.2.47.tgz#1d6399074eadfc3ed35c727e2fd707d6881140b6"
integrity sha512-JPcd9kFyEdXLl/i0ClS7lwgcs0QpUAWj+SKX2ZC3ANKi1U4DOtiEr6cRqFXsPwY5u1L9fAjkinIdB8Rz3FoYNQ== integrity sha512-7khqQ/75oyyg+N/e+iwV6lpy1f5wq759NdlS1fpAhFXa8VeAIKGgk2E/C4VF59lx5b+Ezs5fpp/5WsRYXQiKxQ==
dependencies: dependencies:
"@vue/reactivity" "3.2.37" "@vue/shared" "3.2.47"
"@vue/shared" "3.2.37"
"@vue/runtime-dom@3.2.37": "@vue/runtime-core@3.2.47":
version "3.2.37" version "3.2.47"
resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.2.37.tgz#002bdc8228fa63949317756fb1e92cdd3f9f4bbd" resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.2.47.tgz#406ebade3d5551c00fc6409bbc1eeb10f32e121d"
integrity sha512-HimKdh9BepShW6YozwRKAYjYQWg9mQn63RGEiSswMbW+ssIht1MILYlVGkAGGQbkhSh31PCdoUcfiu4apXJoPw== integrity sha512-RZxbLQIRB/K0ev0K9FXhNbBzT32H9iRtYbaXb0ZIz2usLms/D55dJR2t6cIEUn6vyhS3ALNvNthI+Q95C+NOpA==
dependencies: dependencies:
"@vue/runtime-core" "3.2.37" "@vue/reactivity" "3.2.47"
"@vue/shared" "3.2.37" "@vue/shared" "3.2.47"
"@vue/runtime-dom@3.2.47":
version "3.2.47"
resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.2.47.tgz#93e760eeaeab84dedfb7c3eaf3ed58d776299382"
integrity sha512-ArXrFTjS6TsDei4qwNvgrdmHtD930KgSKGhS5M+j8QxXrDJYLqYw4RRcDy1bz1m1wMmb6j+zGLifdVHtkXA7gA==
dependencies:
"@vue/runtime-core" "3.2.47"
"@vue/shared" "3.2.47"
csstype "^2.6.8" csstype "^2.6.8"
"@vue/server-renderer@3.2.37": "@vue/server-renderer@3.2.47":
version "3.2.37" version "3.2.47"
resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.2.37.tgz#840a29c8dcc29bddd9b5f5ffa22b95c0e72afdfc" resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.2.47.tgz#8aa1d1871fc4eb5a7851aa7f741f8f700e6de3c0"
integrity sha512-kLITEJvaYgZQ2h47hIzPh2K3jG8c1zCVbp/o/bzQOyvzaKiCquKS7AaioPI28GNxIsE/zSx+EwWYsNxDCX95MA== integrity sha512-dN9gc1i8EvmP9RCzvneONXsKfBRgqFeFZLurmHOveL7oH6HiFXJw5OGu294n1nHc/HMgTy6LulU/tv5/A7f/LA==
dependencies: dependencies:
"@vue/compiler-ssr" "3.2.37" "@vue/compiler-ssr" "3.2.47"
"@vue/shared" "3.2.37" "@vue/shared" "3.2.47"
"@vue/shared@3.2.37": "@vue/shared@3.2.37":
version "3.2.37" version "3.2.37"
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.37.tgz#8e6adc3f2759af52f0e85863dfb0b711ecc5c702" resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.37.tgz#8e6adc3f2759af52f0e85863dfb0b711ecc5c702"
integrity sha512-4rSJemR2NQIo9Klm1vabqWjD8rs/ZaJSzMxkMNeJS6lHiUjjUeYFbooN19NgFjztubEKh3WlZUeOLVdbbUWHsw== integrity sha512-4rSJemR2NQIo9Klm1vabqWjD8rs/ZaJSzMxkMNeJS6lHiUjjUeYFbooN19NgFjztubEKh3WlZUeOLVdbbUWHsw==
"@vue/shared@3.2.47":
version "3.2.47"
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.47.tgz#e597ef75086c6e896ff5478a6bfc0a7aa4bbd14c"
integrity sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==
"@webassemblyjs/ast@1.9.0": "@webassemblyjs/ast@1.9.0":
version "1.9.0" version "1.9.0"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964"
@@ -5823,16 +5881,16 @@ vue-router@4:
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.0.3.tgz#8b26050c88b2dec7e27a88835f71046b365823ec" resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.0.3.tgz#8b26050c88b2dec7e27a88835f71046b365823ec"
integrity sha512-AD1OjtVPyQHTSpoRsEGfPpxRQwhAhxcacOYO3zJ3KNkYP/r09mileSp6kdMQKhZWP2cFsPR3E2M3PZguSN5/ww== integrity sha512-AD1OjtVPyQHTSpoRsEGfPpxRQwhAhxcacOYO3zJ3KNkYP/r09mileSp6kdMQKhZWP2cFsPR3E2M3PZguSN5/ww==
vue@^3.2.0: vue@3.2.47:
version "3.2.37" version "3.2.47"
resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.37.tgz#da220ccb618d78579d25b06c7c21498ca4e5452e" resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.47.tgz#3eb736cbc606fc87038dbba6a154707c8a34cff0"
integrity sha512-bOKEZxrm8Eh+fveCqS1/NkG/n6aMidsI6hahas7pa0w/l7jkbssJVsRhVDs07IdDq7h9KHswZOgItnwJAgtVtQ== integrity sha512-60188y/9Dc9WVrAZeUVSDxRQOZ+z+y5nO2ts9jWXSTkMvayiWxCWOWtBQoYjLeccfXkiiPZWAHcV+WTPhkqJHQ==
dependencies: dependencies:
"@vue/compiler-dom" "3.2.37" "@vue/compiler-dom" "3.2.47"
"@vue/compiler-sfc" "3.2.37" "@vue/compiler-sfc" "3.2.47"
"@vue/runtime-dom" "3.2.37" "@vue/runtime-dom" "3.2.47"
"@vue/server-renderer" "3.2.37" "@vue/server-renderer" "3.2.47"
"@vue/shared" "3.2.37" "@vue/shared" "3.2.47"
watchpack-chokidar2@^2.0.1: watchpack-chokidar2@^2.0.1:
version "2.0.1" version "2.0.1"