Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ yarn add @untemps/svelte-use-tooltip

<div use:useTooltip={{
contentSelector: '.tooltip__content',
contentClone: false,
contentActions: {
'*': {
eventType: 'click',
Expand Down Expand Up @@ -114,7 +113,6 @@ yarn add @untemps/svelte-use-tooltip
|---------------------------|---------|-------------------|-----------------------------------------------------------------------------------------------------------------|
| `content` | string | null | Text content to display in the tooltip. |
| `contentSelector` | string | null | Selector of the content to display in the tooltip. |
| `contentClone` | boolean | false | Flag to clone the content to display in the tooltip. If false, the content is removed from its previous parent. |
| `contentActions` | object | null | Configuration of the tooltip actions (see [Content Actions](#content-actions)). |
| `containerClassName` | string | '__tooltip' | Class name to apply to the tooltip container. |
| `position` | string | 'top' | Position of the tooltip. Available values: 'top', 'bottom', 'left', 'right' |
Expand All @@ -126,6 +124,18 @@ yarn add @untemps/svelte-use-tooltip
| `offset` | number | 10 | Distance between the tooltip and the target in pixels. |
| `disabled` | boolean | false | Flag to disable the tooltip content. |

### Content and Content Selector

The tooltip content can be specified either by the `content` prop or the `contentSelector` prop.

`content` must be a text string that will be displayed as is in the tooltip.

It's useful for most of the use cases of a tooltip however sometimes you need to display some more complex content, with interactive elements or formatted text.

To do so, you may use the `contentSelector` prop that allows to specify the selector of an element from the DOM.

The best option is to use a [template](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template) HTML element although you may also use a plain element. In this case, **it will remain in the DOM and will be clones in the tooltip**.

### Content Actions

The `contentActions` prop allows to handle interactions within the tooltip content.
Expand All @@ -141,7 +151,6 @@ One event by element is possible so far as elements are referenced by selector.

<div use:useTooltip={{
contentSelector: '#content',
contentClone: false,
contentActions: {
'#button1': {
eventType: 'mouseenter',
Expand Down
74 changes: 35 additions & 39 deletions dev/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
use:useTooltip={{
position: tooltipPosition,
content: tooltipTextContent,
contentSelector: !tooltipTextContent?.length ? '.tooltip__content' : null,
contentClone: true,
contentSelector: !tooltipTextContent?.length ? '#tooltip-template' : null,
contentActions: {
'*': {
eventType: 'click',
Expand All @@ -40,20 +39,17 @@
enterDelay: tooltipEnterDelay,
leaveDelay: tooltipLeaveDelay,
offset: tooltipOffset,
disabled: isTooltipDisabled
disabled: isTooltipDisabled,
}}
class="target"
>
Hover me
</div>
<template id="tooltip-template">
<span class="tooltip__content">Hi! I'm a <i>fancy</i> <strong>tooltip</strong>!</span>
</template>
<form class="settings__form">
<h1>Settings</h1>
<fieldset>
<label>
Default Tooltip Content:
<span class="tooltip__content">Hi! I'm a <i>fancy</i> <strong>tooltip</strong>!</span>
</label>
</fieldset>
<fieldset>
<label>
Tooltip Text Content:
Expand Down Expand Up @@ -204,36 +200,36 @@
}

:global(.tooltip::after) {
content: '';
position: absolute;
margin-left: -5px;
border-width: 5px;
border-style: solid;
}

:global(.tooltip-top::after) {
bottom: -10px;
left: 50%;
border-color: #ee7008 transparent transparent transparent;
}

:global(.tooltip-bottom::after) {
top: -10px;
left: 50%;
border-color: transparent transparent #ee7008 transparent;
}

:global(.tooltip-left::after) {
top: calc(50% - 5px);
right: -10px;
border-color: transparent transparent transparent #ee7008;
}

:global(.tooltip-right::after) {
top: calc(50% - 5px);
left: -5px;
border-color: transparent #ee7008 transparent transparent;
}
content: '';
position: absolute;
margin-left: -5px;
border-width: 5px;
border-style: solid;
}

:global(.tooltip-top::after) {
bottom: -10px;
left: 50%;
border-color: #ee7008 transparent transparent transparent;
}

:global(.tooltip-bottom::after) {
top: -10px;
left: 50%;
border-color: transparent transparent #ee7008 transparent;
}

:global(.tooltip-left::after) {
top: calc(50% - 5px);
right: -10px;
border-color: transparent transparent transparent #ee7008;
}

:global(.tooltip-right::after) {
top: calc(50% - 5px);
left: -5px;
border-color: transparent #ee7008 transparent transparent;
}

@keyframes fadeIn {
from {
Expand Down
64 changes: 60 additions & 4 deletions jest/jest.setup.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import { fireEvent } from '@testing-library/svelte'

const { toBeInTheDocument, toHaveAttribute, toHaveStyle } = require('@testing-library/jest-dom/matchers')
import '@testing-library/jest-dom/extend-expect'

expect.extend({ toBeInTheDocument, toHaveAttribute, toHaveStyle })

global._createElement = (id = 'foo', parent, attrs) => {
const el = document.createElement('div')
el.setAttribute('id', id)
global._createAndAddElement = (tagName, attrs, parent) => {
const el = document.createElement(tagName)
el.setAttribute('id', 'foo')
for (let key in attrs) {
el.setAttribute(key, attrs[key])
}
;(parent || document.body).appendChild(el)
return el
}

global._removeElement = (selector) => {
global._destroyElement = (selector) => {
const el = document.querySelector(selector)
if (!!el) {
el.parentNode.removeChild(el)
Expand All @@ -27,6 +29,60 @@ global._modifyElement = (selector, attributeName, attributeValue) => {
}
}

global._getElement = (selector) => {
return document.querySelector(selector)
}

global._sleep = (ms = 100) => {
return new Promise((resolve) => setTimeout(resolve, ms))
}

global._enter = async (trigger) =>
new Promise(async (resolve) => {
await fireEvent.mouseOver(trigger) // fireEvent.mouseEnter only works if mouseOver is triggered before
await fireEvent.mouseEnter(trigger)
await _sleep(1)
resolve()
})

global._leave = async (trigger) =>
new Promise(async (resolve) => {
await fireEvent.mouseLeave(trigger)
await _sleep(1)
resolve()
})

global._enterAndLeave = async (trigger) =>
new Promise(async (resolve) => {
await _enter(trigger)
await _leave(trigger)
resolve()
})

global._focus = async (trigger) =>
new Promise(async (resolve) => {
await fireEvent.focusIn(trigger)
await _sleep(1)
resolve()
})

global._blur = async (trigger) =>
new Promise(async (resolve) => {
await fireEvent.focusOut(trigger)
await _sleep(1)
resolve()
})

global._focusAndBlur = async (trigger) =>
new Promise(async (resolve) => {
await _focus(trigger)
await _blur(trigger)
resolve()
})

global._keyDown = async (trigger, key) =>
new Promise(async (resolve) => {
await fireEvent.keyDown(trigger, key || { key: 'Escape', code: 'Escape', charCode: 27 })
await _sleep(1)
resolve()
})
9 changes: 2 additions & 7 deletions src/Tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ class Tooltip {
#content = null
#contentSelector = null
#contentActions = null
#contentClone = false
#containerClassName = null
#position = null
#animated = false
Expand All @@ -38,7 +37,6 @@ class Tooltip {
target,
content,
contentSelector,
contentClone,
contentActions,
containerClassName,
position,
Expand All @@ -53,7 +51,6 @@ class Tooltip {
this.#target = target
this.#content = content
this.#contentSelector = contentSelector
this.#contentClone = contentClone || false
this.#contentActions = contentActions
this.#containerClassName = containerClassName
this.#position = position || 'top'
Expand All @@ -80,7 +77,6 @@ class Tooltip {
update(
content,
contentSelector,
contentClone,
contentActions,
containerClassName,
position,
Expand All @@ -101,7 +97,6 @@ class Tooltip {

this.#content = content
this.#contentSelector = contentSelector
this.#contentClone = contentClone || false
this.#contentActions = contentActions
this.#containerClassName = containerClassName
this.#position = position || 'top'
Expand Down Expand Up @@ -195,9 +190,9 @@ class Tooltip {
this.#observer
.wait(this.#contentSelector, null, { events: [DOMObserver.EXIST, DOMObserver.ADD] })
.then(({ node }) => {
const child = this.#contentClone ? node.cloneNode(true) : node
const child = node.content ? node.content.firstElementChild : node
child.setAttribute('style', 'position: relative')
this.#tooltip.appendChild(child)
this.#tooltip.appendChild(child.cloneNode(true))
})
} else if (this.#content) {
const child = document.createTextNode(this.#content)
Expand Down
Loading