Skip to content

Commit 43d7131

Browse files
committed
feat(CTooltip): add CTooltip component
1 parent 2084775 commit 43d7131

File tree

5 files changed

+263
-2
lines changed

5 files changed

+263
-2
lines changed

docs/api/tooltip/CTooltip.api.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
### CTooltip
2+
3+
```jsx
4+
import { CTooltip } from '@coreui/vue'
5+
// or
6+
import CTooltip from '@coreui/vue/src/components/tooltip/CTooltip'
7+
```
8+
9+
#### Props
10+
11+
| Prop name | Description | Type | Values | Default |
12+
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ------------------------------- | ------- |
13+
| **content** | Content for your component. If you want to pass non-string value please use dedicated slot `<template #content>...</template>` | string | - | - |
14+
| **offset** | Offset of the tooltip relative to its target. | array | - | [0, 0] |
15+
| **placement** | Describes the placement of your component after Popper.js has applied all the modifiers that may have flipped or altered the originally provided placement property. | Placement | - | 'top' |
16+
| **trigger** | Sets which event handlers you’d like provided to your toggle prop. You can specify one trigger or an array of them. | string \| string[] | `'click'`, `'focus'`, `'hover'` | 'hover' |
17+
| **visible** | Toggle the visibility of tooltip component. | boolean | - | |
18+
19+
#### Events
20+
21+
| Event name | Description | Properties |
22+
| ---------- | -------------------------------------------------------- | ---------- |
23+
| **hide** | Callback fired when the component requests to be hidden. |
24+
| **show** | Callback fired when the component requests to be shown. |

docs/components/tooltip.md

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
---
2-
title: Vue Tooltip Directive
2+
title: Vue Tooltip Component and Directive
33
name: Tooltip
44
description: Documentation and examples for adding Vue Tooltips.
55
---
66

7+
## Examples
8+
9+
Hover over the links below to see tooltips:
10+
711
::: demo
812
<p class="text-medium-emphasis">
913
Tight pants next level keffiyeh
@@ -43,8 +47,57 @@ description: Documentation and examples for adding Vue Tooltips.
4347
</p>
4448
```
4549

50+
### Component
51+
4652
Hover over the buttons below to see the four tooltips directions: top, right, bottom, and left. Directions are mirrored when using CoreUI in RTL.
4753

54+
::: demo
55+
<CTooltip content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="top">
56+
<template #toggler="{ on }">
57+
<CButton color="secondary" v-on="on">Tooltip on top</CButton>
58+
</template>
59+
</CTooltip>
60+
<CTooltip content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="right">
61+
<template #toggler="{ on }">
62+
<CButton color="secondary" v-on="on">Tooltip on right</CButton>
63+
</template>
64+
</CTooltip>
65+
<CTooltip content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="bottom">
66+
<template #toggler="{ on }">
67+
<CButton color="secondary" v-on="on">Tooltip on bottom</CButton>
68+
</template>
69+
</CTooltip>
70+
<CTooltip content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="left">
71+
<template #toggler="{ on }">
72+
<CButton color="secondary" v-on="on">Tooltip on left</CButton>
73+
</template>
74+
</CTooltip>
75+
:::
76+
```vue
77+
<CTooltip content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="top">
78+
<template #toggler="{ on }">
79+
<CButton color="secondary" v-on="on">Tooltip on top</CButton>
80+
</template>
81+
</CTooltip>
82+
<CTooltip content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="right">
83+
<template #toggler="{ on }">
84+
<CButton color="secondary" v-on="on">Tooltip on right</CButton>
85+
</template>
86+
</CTooltip>
87+
<CTooltip content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="bottom">
88+
<template #toggler="{ on }">
89+
<CButton color="secondary" v-on="on">Tooltip on bottom</CButton>
90+
</template>
91+
</CTooltip>
92+
<CTooltip content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus" placement="left">
93+
<template #toggler="{ on }">
94+
<CButton color="secondary" v-on="on">Tooltip on left</CButton>
95+
</template>
96+
</CTooltip>
97+
```
98+
99+
### Directive
100+
48101
::: demo
49102
<CButton color="secondary" v-c-tooltip="{content: 'Vivamus sagittis lacus vel augue laoreet rutrum faucibus.', placement: 'top'}">Tooltip on top</CButton>
50103
<CButton color="secondary" v-c-tooltip="{content: 'Vivamus sagittis lacus vel augue laoreet rutrum faucibus.', placement: 'right'}">Tooltip on right</CButton>
@@ -56,4 +109,8 @@ Hover over the buttons below to see the four tooltips directions: top, right, bo
56109
<CButton color="secondary" v-c-tooltip="{content: 'Vivamus sagittis lacus vel augue laoreet rutrum faucibus.', placement: 'right'}">Tooltip on right</CButton>
57110
<CButton color="secondary" v-c-tooltip="{content: 'Vivamus sagittis lacus vel augue laoreet rutrum faucibus.', placement: 'bottom'}">Tooltip on bottom</CButton>
58111
<CButton color="secondary" v-c-tooltip="{content: 'Vivamus sagittis lacus vel augue laoreet rutrum faucibus.', placement: 'left'}">Tooltip on left</CButton>
59-
```
112+
```
113+
114+
## API
115+
116+
!!!include(./docs/api/tooltip/CTooltip.api.md)!!!

src/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,5 @@ export * from './spinner'
3131
export * from './table'
3232
export * from './tabs'
3333
export * from './toast'
34+
export * from './tooltip'
3435
export * from './widgets'

src/components/tooltip/CTooltip.ts

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
import { defineComponent, h, PropType, ref, RendererElement, Teleport, Transition } from 'vue'
2+
import { createPopper, Placement } from '@popperjs/core'
3+
4+
const CTooltip = defineComponent({
5+
name: 'CTooltip',
6+
props: {
7+
/**
8+
* Content for your component. If you want to pass non-string value please use dedicated slot `<template #content>...</template>`
9+
*/
10+
content: {
11+
type: String,
12+
default: undefined,
13+
required: false,
14+
},
15+
/**
16+
* Offset of the tooltip relative to its target.
17+
*/
18+
offset: {
19+
type: Array,
20+
default: () => [0, 0],
21+
required: false,
22+
},
23+
/**
24+
* Describes the placement of your component after Popper.js has applied all the modifiers that may have flipped or altered the originally provided placement property.
25+
*/
26+
placement: {
27+
type: String as PropType<Placement>,
28+
default: 'top',
29+
required: false,
30+
validator: (value: string) => {
31+
return ['top', 'right', 'bottom', 'left'].includes(value)
32+
},
33+
},
34+
/**
35+
* Sets which event handlers you’d like provided to your toggle prop. You can specify one trigger or an array of them.
36+
*
37+
* @values 'click', 'focus', 'hover'
38+
*/
39+
trigger: {
40+
type: [String, Array] as PropType<string | string[]>,
41+
default: 'hover',
42+
required: false,
43+
validator: (value: string | string[]) => {
44+
if (typeof value === 'string') {
45+
return ['click', 'focus', 'hover'].includes(value)
46+
}
47+
if (Array.isArray(value)) {
48+
return value.every((e) => ['click', 'focus', 'hover'].includes(e))
49+
}
50+
return false
51+
},
52+
},
53+
/**
54+
* Toggle the visibility of tooltip component.
55+
*/
56+
visible: Boolean,
57+
},
58+
emits: [
59+
/**
60+
* Callback fired when the component requests to be hidden.
61+
*/
62+
'hide',
63+
/**
64+
* Callback fired when the component requests to be shown.
65+
*/
66+
'show',
67+
],
68+
setup(props, { slots, emit }) {
69+
const togglerRef = ref()
70+
const tooltipRef = ref()
71+
const popper = ref()
72+
const visible = ref(props.visible)
73+
74+
const handleEnter = (el: RendererElement, done: () => void) => {
75+
emit('show')
76+
initPopper()
77+
el.classList.add('show')
78+
el.addEventListener('transitionend', () => {
79+
done()
80+
})
81+
}
82+
83+
const handleLeave = (el: RendererElement, done: () => void) => {
84+
emit('hide')
85+
el.classList.remove('show')
86+
el.addEventListener('transitionend', () => {
87+
done()
88+
destroyPopper()
89+
})
90+
}
91+
92+
const handleToggle = (event: Event) => {
93+
togglerRef.value = event.target
94+
visible.value = !visible.value
95+
}
96+
97+
const initPopper = () => {
98+
if (togglerRef.value) {
99+
popper.value = createPopper(togglerRef.value, tooltipRef.value, {
100+
placement: props.placement,
101+
modifiers: [
102+
{
103+
name: 'offset',
104+
options: {
105+
offset: props.offset,
106+
},
107+
},
108+
],
109+
})
110+
}
111+
}
112+
113+
const destroyPopper = () => {
114+
if (popper.value) {
115+
popper.value.destroy()
116+
}
117+
popper.value = undefined
118+
}
119+
120+
return () => [
121+
h(
122+
Teleport,
123+
{
124+
to: 'body',
125+
},
126+
h(
127+
Transition,
128+
{
129+
onEnter: (el, done) => handleEnter(el, done),
130+
onLeave: (el, done) => handleLeave(el, done),
131+
},
132+
() =>
133+
visible.value &&
134+
h(
135+
'div',
136+
{
137+
class: 'tooltip fade bs-tooltip-auto',
138+
ref: tooltipRef,
139+
role: 'tooltip',
140+
},
141+
[
142+
h('div', { class: 'tooltip-arrow', 'data-popper-arrow': '' }),
143+
(props.content || slots.content) &&
144+
h(
145+
'div',
146+
{ class: 'tooltip-inner' },
147+
{
148+
default: () => (slots.content && slots.content()) || props.content,
149+
},
150+
),
151+
],
152+
),
153+
),
154+
),
155+
slots.toggler &&
156+
slots.toggler({
157+
on: {
158+
click: (event: Event) => props.trigger.includes('click') && handleToggle(event),
159+
blur: (event: Event) => props.trigger.includes('focus') && handleToggle(event),
160+
focus: (event: Event) => props.trigger.includes('focus') && handleToggle(event),
161+
mouseenter: (event: Event) => props.trigger.includes('hover') && handleToggle(event),
162+
mouseleave: (event: Event) => props.trigger.includes('hover') && handleToggle(event),
163+
},
164+
}),
165+
]
166+
},
167+
})
168+
169+
export { CTooltip }

src/components/tooltip/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { App } from 'vue'
2+
import { CTooltip } from './CTooltip'
3+
4+
const CTooltipPlugin = {
5+
install: (app: App): void => {
6+
app.component(CTooltip.name, CTooltip)
7+
},
8+
}
9+
10+
export { CTooltipPlugin, CTooltip }

0 commit comments

Comments
 (0)