From 48dcff181b3ea347b92fb02eda554938253a734d Mon Sep 17 00:00:00 2001 From: untemps Date: Sat, 22 Jan 2022 21:14:16 +0100 Subject: [PATCH 1/5] feat: Animate DOM addition and removal, #2 --- src/__tests__/useTooltip.test.js | 10 ++++--- src/useTooltip.css | 25 +++++++++++++++++ src/useTooltip.js | 48 ++++++++++++++++++++++++++------ 3 files changed, 71 insertions(+), 12 deletions(-) diff --git a/src/__tests__/useTooltip.test.js b/src/__tests__/useTooltip.test.js index 66b646f..138e1cb 100644 --- a/src/__tests__/useTooltip.test.js +++ b/src/__tests__/useTooltip.test.js @@ -48,7 +48,7 @@ describe('useTooltip', () => { action = useTooltip(target, options) await fireEvent.mouseOver(target) // fireEvent.mouseEnter only works if mouseOver is triggered before await fireEvent.mouseEnter(target) - expect(template).toBeVisible() + expect(template).toBeInTheDocument() }) it('Hides tooltip on mouse leave', async () => { @@ -56,7 +56,8 @@ describe('useTooltip', () => { await fireEvent.mouseOver(target) // fireEvent.mouseEnter only works if mouseOver is triggered before await fireEvent.mouseEnter(target) await fireEvent.mouseLeave(target) - expect(template).not.toBeVisible() + await fireEvent.animationEnd(template.parentNode) + expect(template).not.toBeInTheDocument() }) }) @@ -97,7 +98,7 @@ describe('useTooltip', () => { await fireEvent.mouseEnter(target) await fireEvent.click(template) expect(contentAction.callback).toHaveBeenCalledWith(contentAction.callbackParams[0], expect.any(Event)) - expect(template).toBeVisible() + expect(template).toBeInTheDocument() }) it('Closes tooltip after triggering callback', async () => { @@ -108,7 +109,8 @@ describe('useTooltip', () => { await fireEvent.mouseEnter(target) await fireEvent.click(template) expect(contentAction.callback).toHaveBeenCalledWith(contentAction.callbackParams[0], expect.any(Event)) - expect(template).not.toBeVisible() + await fireEvent.animationEnd(template.parentNode) + expect(template).not.toBeInTheDocument() }) it('Triggers new callback on tooltip click after update', async () => { diff --git a/src/useTooltip.css b/src/useTooltip.css index 068ca50..136d61c 100644 --- a/src/useTooltip.css +++ b/src/useTooltip.css @@ -39,4 +39,29 @@ top: calc(50% - 5px); left: -5px; border-color: transparent black transparent transparent; +} + +.__tooltip__show { + animation: fadeIn .2s linear forwards; +} + +.__tooltip__hide { + animation: fadeOut .2s linear forwards; +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} +@keyframes fadeOut { + from { + opacity: 1; + } + to { + opacity: 0; + } } \ No newline at end of file diff --git a/src/useTooltip.js b/src/useTooltip.js index df44a23..bacd21f 100644 --- a/src/useTooltip.js +++ b/src/useTooltip.js @@ -137,6 +137,8 @@ export class Tooltip { } #appendContainerToTarget() { + await this.#manageTransition(1) + this.#target.appendChild(this.#container) if (this.#actions) { @@ -156,17 +158,47 @@ export class Tooltip { } } - #removeContainerFromTarget() { - if (this.#target.contains(this.#container)) { - this.#target.removeChild(this.#container) - } + async #removeContainerFromTarget() { + await this.#manageTransition(0) + + this.#container.remove() this.#events.forEach(({ trigger, eventType, listener }) => trigger.removeEventListener(eventType, listener)) this.#events = [] } - #onTargetEnter() { - this.#appendContainerToTarget() + #manageTransition(direction) { + return new Promise((resolve) => { + let classToAdd, classToRemove + switch(direction) { + case 1: { + classToAdd = '__tooltip__show' + classToRemove = '__tooltip__hide' + break + } + default: { + classToAdd = '__tooltip__hide' + classToRemove = '__tooltip__show' + } + } + this.#container.classList.add(classToAdd) + this.#container.classList.remove(classToRemove) + + if(direction === 1) { + resolve() + } + + const onTransitionEnd = () => { + this.#container.removeEventListener("animationend", onTransitionEnd) + this.#container.classList.remove(classToAdd) + resolve() + } + this.#container.addEventListener("animationend", onTransitionEnd) + }) + } + + async #onTargetEnter() { + await this.#appendContainerToTarget() Tooltip.#observer.wait(`#tooltip`, null, { events: [DOMObserver.EXIST] }).then(({ node }) => { const { width: targetWidth, height: targetHeight } = this.#target.getBoundingClientRect() @@ -203,8 +235,8 @@ export class Tooltip { }) } - #onTargetLeave() { - this.#removeContainerFromTarget() + async #onTargetLeave() { + await this.#removeContainerFromTarget() } } From 6e6359fc8e7e4d3785e2e6a0110fd0b80a7d1dbd Mon Sep 17 00:00:00 2001 From: untemps Date: Sun, 23 Jan 2022 13:42:12 +0100 Subject: [PATCH 2/5] feat: Add prop to enable tooltip animation, #2 --- dev/src/App.svelte | 8 ++++++++ src/__tests__/useTooltip.test.js | 25 +++++++++++++++++++++++++ src/useTooltip.js | 24 ++++++++++++++++-------- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/dev/src/App.svelte b/dev/src/App.svelte index 204f071..d85370d 100644 --- a/dev/src/App.svelte +++ b/dev/src/App.svelte @@ -4,6 +4,7 @@ let tooltipPosition = 'top' let useCustomTooltipClass = false let isTooltipDisabled = false + let animateTooltip = false const _onTooltipClick = (arg, event) => { console.log(arg) @@ -26,6 +27,7 @@ }, contentClassName: useCustomTooltipClass ? 'tooltip' : null, disabled: isTooltipDisabled, + animated: animateTooltip }} class="target">Hover me Hi! I'm a fancy tooltip!
@@ -47,6 +49,12 @@ +
+ +
+
+ +
+
+ +