- I'm not just a tooltip, I'm a tooltip with HTML!
-
- Hover me
+Hover me
+
+ I'm not just a tooltip, I'm a tooltip with HTML!
```
@@ -340,9 +337,10 @@ const App = () => (
Use the `--max-width` custom property to change the width the tooltip can grow to before wrapping occurs.
```html {.example}
-
- Hover me
+
+ This tooltip will wrap after only 80 pixels.
+Hover me
```
{% raw %}
@@ -364,20 +362,20 @@ Tooltips will be clipped if they're inside a container that has `overflow: auto|
```html {.example}
-
- No Hoist
-
+ This is a tooltip
+ No Hoist
-
- Hoist
+
+ This is a tooltip
+ Hoist
diff --git a/src/components/details/details.ts b/src/components/details/details.ts
index 467fe7d8f..fc2900f72 100644
--- a/src/components/details/details.ts
+++ b/src/components/details/details.ts
@@ -1,5 +1,5 @@
import '../icon/icon.js';
-import { animate, parseDuration, stopAnimations } from '../../internal/animate.js';
+import { animate, parseDuration } from '../../internal/animate.js';
import { classMap } from 'lit/directives/class-map.js';
import { customElement, property, query } from 'lit/decorators.js';
import { html } from 'lit';
@@ -144,7 +144,6 @@ export default class WaDetails extends WebAwesomeElement {
return;
}
- await stopAnimations(this.body);
const duration = parseDuration(getComputedStyle(this.body).getPropertyValue('--show-duration'));
// We can't animate to 'auto', so use the scroll height for now
await animate(
@@ -171,7 +170,6 @@ export default class WaDetails extends WebAwesomeElement {
return;
}
- await stopAnimations(this.body);
const duration = parseDuration(getComputedStyle(this.body).getPropertyValue('--hide-duration'));
// We can't animate from 'auto', so use the scroll height for now
await animate(
diff --git a/src/components/tooltip/tooltip.ts b/src/components/tooltip/tooltip.ts
index 93434ce8d..f3abf74dc 100644
--- a/src/components/tooltip/tooltip.ts
+++ b/src/components/tooltip/tooltip.ts
@@ -1,4 +1,4 @@
-import { animateWithClass, stopAnimations } from '../../internal/animate.js';
+import { animateWithClass } from '../../internal/animate.js';
import { classMap } from 'lit/directives/class-map.js';
import { customElement, property, query, state } from 'lit/decorators.js';
import { html } from 'lit';
@@ -149,28 +149,19 @@ export default class WaTooltip extends WebAwesomeElement {
}
};
- private handleClick = (e: Event) => {
+ private handleClick = () => {
if (this.hasTrigger('click')) {
if (this.open) {
this.hide();
} else {
-
- let anchor = undefined
- if (e.currentTarget !== this) {
- anchor = e.currentTarget as HTMLElement
- }
- this.show(anchor);
+ this.show();
}
}
};
- private handleFocus = (e: Event) => {
+ private handleFocus = () => {
if (this.hasTrigger('focus')) {
- let anchor = undefined
- if (e.currentTarget !== this) {
- anchor = e.currentTarget as HTMLElement
- }
- this.show(anchor);
+ this.show();
}
};
@@ -182,15 +173,11 @@ export default class WaTooltip extends WebAwesomeElement {
}
};
- private handleMouseOver = (e: Event) => {
+ private handleMouseOver = () => {
if (this.hasTrigger('hover')) {
clearTimeout(this.hoverTimeout);
- let anchor = undefined
- if (e.currentTarget !== this) {
- anchor = e.currentTarget as HTMLElement
- }
- this.hoverTimeout = window.setTimeout(() => this.show(anchor), this.showDelay);
+ this.hoverTimeout = window.setTimeout(() => this.show(), this.showDelay);
}
};
@@ -233,7 +220,6 @@ export default class WaTooltip extends WebAwesomeElement {
this.body.hidden = false;
this.popup.active = true;
- await stopAnimations(this.popup.popup);
await animateWithClass(this.popup.popup, 'show-with-scale');
this.popup.reposition();
@@ -250,7 +236,6 @@ export default class WaTooltip extends WebAwesomeElement {
this.closeWatcher?.destroy();
document.removeEventListener('keydown', this.handleDocumentKeyDown);
- await stopAnimations(this.popup.popup);
await animateWithClass(this.popup.popup, 'hide-with-scale');
this.popup.active = false;
this.body.hidden = true;
@@ -320,15 +305,11 @@ export default class WaTooltip extends WebAwesomeElement {
}
/** Shows the tooltip. */
- async show(anchor?: HTMLElement) {
+ async show() {
if (this.open) {
return undefined;
}
- if (anchor) {
- this.anchor = anchor
- }
-
this.open = true;
return waitForEvent(this, 'wa-after-show');
}
diff --git a/src/components/tree-item/tree-item.ts b/src/components/tree-item/tree-item.ts
index 3182253e4..48364eddc 100644
--- a/src/components/tree-item/tree-item.ts
+++ b/src/components/tree-item/tree-item.ts
@@ -1,7 +1,7 @@
import '../checkbox/checkbox.js';
import '../icon/icon.js';
import '../spinner/spinner.js';
-import { animate, parseDuration, stopAnimations } from '../../internal/animate.js';
+import { animate, parseDuration } from '../../internal/animate.js';
import { classMap } from 'lit/directives/class-map.js';
import { customElement, property, query, state } from 'lit/decorators.js';
import { html } from 'lit';
@@ -122,8 +122,6 @@ export default class WaTreeItem extends WebAwesomeElement {
private async animateCollapse() {
this.dispatchEvent(new WaCollapseEvent());
- await stopAnimations(this.childrenContainer);
-
const duration = parseDuration(getComputedStyle(this.childrenContainer).getPropertyValue('--hide-duration'));
await animate(
this.childrenContainer,
@@ -159,7 +157,6 @@ export default class WaTreeItem extends WebAwesomeElement {
private async animateExpand() {
this.dispatchEvent(new WaExpandEvent());
- await stopAnimations(this.childrenContainer);
this.childrenContainer.hidden = false;
// We can't animate to 'auto', so use the scroll height for now
const duration = parseDuration(getComputedStyle(this.childrenContainer).getPropertyValue('--show-duration'));
diff --git a/src/internal/animate.ts b/src/internal/animate.ts
index 2d5a84a32..c6c90778b 100644
--- a/src/internal/animate.ts
+++ b/src/internal/animate.ts
@@ -11,14 +11,29 @@ export async function animate(el: Element, keyframes: Keyframe[], options?: Keyf
*/
export function animateWithClass(el: Element, className: string) {
return new Promise(resolve => {
+ el.classList.remove(className)
+ const controller = new AbortController()
+ const { signal } = controller
+
el.classList.add(className);
el.addEventListener(
'animationend',
() => {
el.classList.remove(className);
resolve();
+ controller.abort()
},
- { once: true }
+ { once: true, signal }
+ );
+
+ el.addEventListener(
+ 'animationcancel',
+ () => {
+ el.classList.remove(className);
+ resolve();
+ controller.abort()
+ },
+ { once: true, signal }
);
});
}
@@ -43,20 +58,3 @@ export function prefersReducedMotion() {
const query = window.matchMedia('(prefers-reduced-motion: reduce)');
return query.matches;
}
-
-/**
- * Stops all active animations on the target element. Returns a promise that resolves after all animations are canceled.
- */
-export function stopAnimations(el: HTMLElement) {
- return Promise.all(
- el.getAnimations().map(animation => {
- return new Promise(resolve => {
- const handleAnimationEvent = requestAnimationFrame(resolve);
-
- animation.addEventListener('cancel', () => handleAnimationEvent, { once: true });
- animation.addEventListener('finish', () => handleAnimationEvent, { once: true });
- animation.cancel();
- });
- })
- );
-}