Add support for <Tippy> as a child (issue #123 in 6.x)

Having <Tippy> as a child of an element to tooltip was a nice use-case
in 4.x. See https://github.com/KABBOUCHI/vue-tippy/issues/123.
We re-add this in a similar manner.

Using to="parent" (as a fixed string), one can now use either the main
<Tippy> slot ("default") or its specific "content" slot to specify
the tooltip content.
The tooltip will be triggered on the parent element without
adding a specifc Tippy node to the DOM.

This should provides a non-interfering way to specify tooltips.

Implementation:
For the to="parent" case, we need to find the parent DOM element, but in
the "worst" case <Tippy> won't render any DOM nodes at all, which could
help us to find the parent.
Instead, we initially render a hidden <span> (and the tooltip content).
Using the span as a template ref ('findParentHelper'), we can get the
parent and assign that to the actual 'elem' ref. This will trigger a
re-render, where we can drop the helper <span> again.
This commit is contained in:
Konrad Kügler
2023-07-31 21:28:18 +02:00
parent 56ddee444a
commit 44b67e46b9
3 changed files with 72 additions and 3 deletions
+14
View File
@@ -70,6 +70,20 @@ Mount tippy on the child node instead of default tag
<template #content>Hi!</template>
</tippy>
```
### Example 3
Tippy as a child using `to="parent"`. \
Works like `:tag="null"`, but applies the tooltip to the parent element instead of the child.
```html
<button>
<tippy to="parent" content-tag="div" ontent-class="content-wrapper">
Hi!
</tippy>
Tippy!
</button>
```
## Singleton
### Example 1
+27
View File
@@ -88,6 +88,33 @@
</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
+31 -3
View File
@@ -89,6 +89,7 @@ const TippyComponent = defineComponent({
emits: ['state'],
setup(props, { slots, emit, expose }) {
const elem = ref<Element>()
const findParentHelper = ref<HTMLElement>()
const contentElem = ref<Element>()
const mounted = ref(false)
@@ -109,13 +110,24 @@ const TippyComponent = defineComponent({
if (props.to) {
if (typeof Element !== 'undefined' && props.to instanceof Element) {
target = () => props.to
} else if (props.to === 'parent') {
target = () => {
let el = elem.value
if (!el) {
el = elem.value = findParentHelper.value!.parentElement as HTMLElement
}
return el
}
} else if (typeof props.to === 'string' || props.to instanceof String) {
target = () => document.querySelector(props.to as any)
}
}
const tippy = useTippy(target, getOptions())
const contentSlot = slots.content
let contentSlot = slots.content
if (!contentSlot && props.to === 'parent') {
contentSlot = slots.default
}
onMounted(() => {
mounted.value = true
@@ -147,8 +159,6 @@ const TippyComponent = defineComponent({
expose(exposed)
return () => {
const slot = slots.default ? slots.default(exposed) : []
const contentTag = typeof props.contentTag === 'string' ? props.contentTag as string : props.contentTag
const content = contentSlot
? h(
@@ -162,6 +172,24 @@ const TippyComponent = defineComponent({
)
: null
if (props.to === 'parent') {
const result = []
if (!elem.value) {
const findParentHelperNode = h('span', {
ref: findParentHelper,
'data-v-tippy': '',
style: { display: 'none' },
})
result.push(findParentHelperNode)
}
if (content) {
result.push(content)
}
return result
}
const slot = slots.default ? slots.default(exposed) : []
if (!props.tag) {
const trigger = h(slot[0] as any, {
ref: elem, 'data-v-tippy': ''