Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@vaadin/tooltip

Package Overview
Dependencies
Maintainers
12
Versions
295
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@vaadin/tooltip - npm Package Compare versions

Comparing version 24.2.0-beta2 to 24.2.0-beta3

src/vaadin-tooltip-mixin.d.ts

20

package.json
{
"name": "@vaadin/tooltip",
"version": "24.2.0-beta2",
"version": "24.2.0-beta3",
"publishConfig": {

@@ -24,2 +24,5 @@ "access": "public"

"src",
"!src/vaadin-lit-tooltip-overlay.js",
"!src/vaadin-lit-tooltip.d.ts",
"!src/vaadin-lit-tooltip.js",
"theme",

@@ -38,9 +41,10 @@ "vaadin-*.d.ts",

"dependencies": {
"@open-wc/dedupe-mixin": "^1.3.0",
"@polymer/polymer": "^3.0.0",
"@vaadin/a11y-base": "24.2.0-beta2",
"@vaadin/component-base": "24.2.0-beta2",
"@vaadin/overlay": "24.2.0-beta2",
"@vaadin/vaadin-lumo-styles": "24.2.0-beta2",
"@vaadin/vaadin-material-styles": "24.2.0-beta2",
"@vaadin/vaadin-themable-mixin": "24.2.0-beta2"
"@vaadin/a11y-base": "24.2.0-beta3",
"@vaadin/component-base": "24.2.0-beta3",
"@vaadin/overlay": "24.2.0-beta3",
"@vaadin/vaadin-lumo-styles": "24.2.0-beta3",
"@vaadin/vaadin-material-styles": "24.2.0-beta3",
"@vaadin/vaadin-themable-mixin": "24.2.0-beta3"
},

@@ -56,3 +60,3 @@ "devDependencies": {

],
"gitHead": "4b852f9a12d4dade7f0fb3c73b7212436cebf310"
"gitHead": "91ea11e7ad706065340acdb93b92316919ce5e69"
}

116

src/vaadin-tooltip-overlay.js

@@ -9,43 +9,7 @@ /**

import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
import { OverlayMixin } from '@vaadin/overlay/src/vaadin-overlay-mixin.js';
import { PositionMixin } from '@vaadin/overlay/src/vaadin-overlay-position-mixin.js';
import { overlayStyles } from '@vaadin/overlay/src/vaadin-overlay-styles.js';
import { css, registerStyles, ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
import { registerStyles, ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
import { TooltipOverlayMixin } from './vaadin-tooltip-overlay-mixin.js';
import { tooltipOverlayStyles } from './vaadin-tooltip-overlay-styles.js';
const tooltipOverlayStyles = css`
:host {
z-index: 1100;
}
[part='overlay'] {
max-width: 40ch;
}
:host([position^='top'][top-aligned]) [part='overlay'],
:host([position^='bottom'][top-aligned]) [part='overlay'] {
margin-top: var(--vaadin-tooltip-offset-top, 0);
}
:host([position^='top'][bottom-aligned]) [part='overlay'],
:host([position^='bottom'][bottom-aligned]) [part='overlay'] {
margin-bottom: var(--vaadin-tooltip-offset-bottom, 0);
}
:host([position^='start'][start-aligned]) [part='overlay'],
:host([position^='end'][start-aligned]) [part='overlay'] {
margin-inline-start: var(--vaadin-tooltip-offset-start, 0);
}
:host([position^='start'][end-aligned]) [part='overlay'],
:host([position^='end'][end-aligned]) [part='overlay'] {
margin-inline-end: var(--vaadin-tooltip-offset-end, 0);
}
@media (forced-colors: active) {
[part='overlay'] {
outline: 1px dashed;
}
}
`;
registerStyles('vaadin-tooltip-overlay', [overlayStyles, tooltipOverlayStyles], {

@@ -61,8 +25,7 @@ moduleId: 'vaadin-tooltip-overlay-styles',

* @mixes DirMixin
* @mixes OverlayMixin
* @mixes PositionMixin
* @mixes ThemableMixin
* @mixes TooltipOverlayMixin
* @private
*/
class TooltipOverlay extends PositionMixin(OverlayMixin(DirMixin(ThemableMixin(PolymerElement)))) {
class TooltipOverlay extends TooltipOverlayMixin(DirMixin(ThemableMixin(PolymerElement))) {
static get is() {

@@ -81,11 +44,2 @@ return 'vaadin-tooltip-overlay';

static get properties() {
return {
position: {
type: String,
reflectToAttribute: true,
},
};
}
/** @protected */

@@ -101,64 +55,4 @@ ready() {

}
requestContentUpdate() {
super.requestContentUpdate();
this.toggleAttribute('hidden', this.textContent.trim() === '');
// Copy custom properties from the tooltip
if (this.positionTarget && this.owner) {
const style = getComputedStyle(this.owner);
['top', 'bottom', 'start', 'end'].forEach((prop) => {
this.style.setProperty(
`--vaadin-tooltip-offset-${prop}`,
style.getPropertyValue(`--vaadin-tooltip-offset-${prop}`),
);
});
}
}
/**
* @protected
* @override
*/
_updatePosition() {
super._updatePosition();
if (!this.positionTarget) {
return;
}
// Center the tooltip overlay horizontally
if (this.position === 'bottom' || this.position === 'top') {
const targetRect = this.positionTarget.getBoundingClientRect();
const overlayRect = this.$.overlay.getBoundingClientRect();
const offset = targetRect.width / 2 - overlayRect.width / 2;
if (this.style.left) {
const left = overlayRect.left + offset;
if (left > 0) {
this.style.left = `${left}px`;
}
}
if (this.style.right) {
const right = parseFloat(this.style.right) + offset;
if (right > 0) {
this.style.right = `${right}px`;
}
}
}
// Center the tooltip overlay vertically
if (this.position === 'start' || this.position === 'end') {
const targetRect = this.positionTarget.getBoundingClientRect();
const overlayRect = this.$.overlay.getBoundingClientRect();
const offset = targetRect.height / 2 - overlayRect.height / 2;
this.style.top = `${overlayRect.top + offset}px`;
}
}
}
defineCustomElement(TooltipOverlay);

@@ -8,18 +8,6 @@ /**

import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
import { OverlayClassMixin } from '@vaadin/component-base/src/overlay-class-mixin.js';
import { ThemePropertyMixin } from '@vaadin/vaadin-themable-mixin/vaadin-theme-property-mixin.js';
import { TooltipMixin } from './vaadin-tooltip-mixin.js';
export type TooltipPosition =
| 'bottom-end'
| 'bottom-start'
| 'bottom'
| 'end-bottom'
| 'end-top'
| 'end'
| 'start-bottom'
| 'start-top'
| 'start'
| 'top-end'
| 'top-start'
| 'top';
export { TooltipPosition } from './vaadin-tooltip-mixin.js';

@@ -64,114 +52,4 @@ /**

*/
declare class Tooltip extends OverlayClassMixin(ThemePropertyMixin(ControllerMixin(ElementMixin(HTMLElement)))) {
/**
* Sets the default focus delay to be used by all tooltip instances,
* except for those that have focus delay configured using property.
*/
static setDefaultFocusDelay(focusDelay: number): void;
declare class Tooltip extends TooltipMixin(ThemePropertyMixin(ControllerMixin(ElementMixin(HTMLElement)))) {}
/**
* Sets the default hide delay to be used by all tooltip instances,
* except for those that have hide delay configured using property.
*/
static setDefaultHideDelay(hideDelay: number): void;
/**
* Sets the default hover delay to be used by all tooltip instances,
* except for those that have hover delay configured using property.
*/
static setDefaultHoverDelay(delay: number): void;
/**
* Element used to link with the `aria-describedby`
* attribute. Supports array of multiple elements.
* When not set, defaults to `target`.
*/
ariaTarget: HTMLElement | HTMLElement[] | undefined;
/**
* Object with properties passed to `generator` and
* `shouldShow` functions for generating tooltip text
* or detecting whether to show the tooltip or not.
*/
context: Record<string, unknown>;
/**
* The delay in milliseconds before the tooltip
* is opened on keyboard focus, when not in manual mode.
* @attr {number} focus-delay
*/
focusDelay: number;
/**
* The id of the element used as a tooltip trigger.
* The element should be in the DOM by the time when
* the attribute is set, otherwise a warning is shown.
*/
for: string | undefined;
/**
* The delay in milliseconds before the tooltip
* is closed on losing hover, when not in manual mode.
* On blur, the tooltip is closed immediately.
* @attr {number} hide-delay
*/
hideDelay: number;
/**
* The delay in milliseconds before the tooltip
* is opened on hover, when not in manual mode.
* @attr {number} hover-delay
*/
hoverDelay: number;
/**
* When true, the tooltip is controlled programmatically
* instead of reacting to focus and mouse events.
*/
manual: boolean;
/**
* When true, the tooltip is opened programmatically.
* Only works if `manual` is set to `true`.
*/
opened: boolean;
/**
* Position of the tooltip with respect to its target.
* Supported values: `top-start`, `top`, `top-end`,
* `bottom-start`, `bottom`, `bottom-end`, `start-top`,
* `start`, `start-bottom`, `end-top`, `end`, `end-bottom`.
*/
position: TooltipPosition;
/**
* Function used to detect whether to show the tooltip based on a condition,
* called every time the tooltip is about to be shown on hover and focus.
* The function takes two parameters: `target` and `context`, which contain
* values of the corresponding tooltip properties at the time of calling.
* The tooltip is only shown when the function invocation returns `true`.
*/
shouldShow: (target: HTMLElement, context?: Record<string, unknown>) => boolean;
/**
* Reference to the element used as a tooltip trigger.
* The target must be placed in the same shadow scope.
* Defaults to an element referenced with `for`.
*/
target: HTMLElement | undefined;
/**
* String used as a tooltip content.
*/
text: string | null | undefined;
/**
* Function used to generate the tooltip content.
* When provided, it overrides the `text` property.
* Use the `context` property to provide argument
* that can be passed to the generator function.
*/
generator: (context: Record<string, unknown>) => string;
}
declare global {

@@ -178,0 +56,0 @@ interface HTMLElementTagNameMap {

@@ -8,215 +8,9 @@ /**

import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
import { isKeyboardActive } from '@vaadin/a11y-base/src/focus-utils.js';
import { microTask } from '@vaadin/component-base/src/async.js';
import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
import { Debouncer } from '@vaadin/component-base/src/debounce.js';
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
import { addValueToAttribute, removeValueFromAttribute } from '@vaadin/component-base/src/dom-utils.js';
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
import { OverlayClassMixin } from '@vaadin/component-base/src/overlay-class-mixin.js';
import { SlotController } from '@vaadin/component-base/src/slot-controller.js';
import { generateUniqueId } from '@vaadin/component-base/src/unique-id-utils.js';
import { ThemePropertyMixin } from '@vaadin/vaadin-themable-mixin/vaadin-theme-property-mixin.js';
import { TooltipMixin } from './vaadin-tooltip-mixin.js';
const DEFAULT_DELAY = 500;
let defaultFocusDelay = DEFAULT_DELAY;
let defaultHoverDelay = DEFAULT_DELAY;
let defaultHideDelay = DEFAULT_DELAY;
const closing = new Set();
let warmedUp = false;
let warmUpTimeout = null;
let cooldownTimeout = null;
/**
* Resets the global tooltip warmup and cooldown state.
* Only for internal use in tests.
* @private
*/
export function resetGlobalTooltipState() {
warmedUp = false;
clearTimeout(warmUpTimeout);
clearTimeout(cooldownTimeout);
closing.clear();
}
/**
* Controller for handling tooltip opened state.
*/
class TooltipStateController {
constructor(host) {
this.host = host;
}
/** @private */
get openedProp() {
return this.host.manual ? 'opened' : '_autoOpened';
}
/** @private */
get focusDelay() {
const tooltip = this.host;
return tooltip.focusDelay != null && tooltip.focusDelay > 0 ? tooltip.focusDelay : defaultFocusDelay;
}
/** @private */
get hoverDelay() {
const tooltip = this.host;
return tooltip.hoverDelay != null && tooltip.hoverDelay > 0 ? tooltip.hoverDelay : defaultHoverDelay;
}
/** @private */
get hideDelay() {
const tooltip = this.host;
return tooltip.hideDelay != null && tooltip.hideDelay > 0 ? tooltip.hideDelay : defaultHideDelay;
}
/**
* Whether closing is currently in progress.
* @return {boolean}
*/
get isClosing() {
return closing.has(this.host);
}
/**
* Schedule opening the tooltip.
* @param {Object} options
*/
open(options = { immediate: false }) {
const { immediate, hover, focus } = options;
const isHover = hover && this.hoverDelay > 0;
const isFocus = focus && this.focusDelay > 0;
if (!immediate && (isHover || isFocus) && !this.__closeTimeout) {
this.__warmupTooltip(isFocus);
} else {
this.__showTooltip();
}
}
/**
* Schedule closing the tooltip.
* @param {boolean} immediate
*/
close(immediate) {
if (!immediate && this.hideDelay > 0) {
this.__scheduleClose();
} else {
this.__abortClose();
this._setOpened(false);
}
this.__abortWarmUp();
if (warmedUp) {
// Re-start cooldown timer on each tooltip closing.
this.__abortCooldown();
this.__scheduleCooldown();
}
}
/** @private */
_isOpened() {
return this.host[this.openedProp];
}
/** @private */
_setOpened(opened) {
this.host[this.openedProp] = opened;
}
/** @private */
__flushClosingTooltips() {
closing.forEach((tooltip) => {
tooltip._stateController.close(true);
closing.delete(tooltip);
});
}
/** @private */
__showTooltip() {
this.__abortClose();
this.__flushClosingTooltips();
this._setOpened(true);
warmedUp = true;
// Abort previously scheduled timers.
this.__abortWarmUp();
this.__abortCooldown();
}
/** @private */
__warmupTooltip(isFocus) {
if (!this._isOpened()) {
// First tooltip is opened, warm up.
if (!warmedUp) {
this.__scheduleWarmUp(isFocus);
} else {
// Warmed up, show another tooltip.
this.__showTooltip();
}
}
}
/** @private */
__abortClose() {
if (this.__closeTimeout) {
clearTimeout(this.__closeTimeout);
this.__closeTimeout = null;
}
}
/** @private */
__abortCooldown() {
if (cooldownTimeout) {
clearTimeout(cooldownTimeout);
cooldownTimeout = null;
}
}
/** @private */
__abortWarmUp() {
if (warmUpTimeout) {
clearTimeout(warmUpTimeout);
warmUpTimeout = null;
}
}
/** @private */
__scheduleClose() {
if (this._isOpened()) {
closing.add(this.host);
this.__closeTimeout = setTimeout(() => {
closing.delete(this.host);
this.__closeTimeout = null;
this._setOpened(false);
}, this.hideDelay);
}
}
/** @private */
__scheduleCooldown() {
cooldownTimeout = setTimeout(() => {
cooldownTimeout = null;
warmedUp = false;
}, this.hideDelay);
}
/** @private */
__scheduleWarmUp(isFocus) {
const delay = isFocus ? this.focusDelay : this.hoverDelay;
warmUpTimeout = setTimeout(() => {
warmUpTimeout = null;
warmedUp = true;
this.__showTooltip();
}, delay);
}
}
/**
* `<vaadin-tooltip>` is a Web Component for creating tooltips.

@@ -263,6 +57,6 @@ *

* @mixes ElementMixin
* @mixes OverlayClassMixin
* @mixes ThemePropertyMixin
* @mixes TooltipMixin
*/
class Tooltip extends OverlayClassMixin(ThemePropertyMixin(ElementMixin(ControllerMixin(PolymerElement)))) {
class Tooltip extends TooltipMixin(ThemePropertyMixin(ElementMixin(ControllerMixin(PolymerElement)))) {
static get is() {

@@ -297,589 +91,2 @@ return 'vaadin-tooltip';

}
static get properties() {
return {
/**
* Element used to link with the `aria-describedby`
* attribute. Supports array of multiple elements.
* When not set, defaults to `target`.
*/
ariaTarget: {
type: Object,
},
/**
* Object with properties passed to `generator` and
* `shouldShow` functions for generating tooltip text
* or detecting whether to show the tooltip or not.
*/
context: {
type: Object,
value: () => {
return {};
},
},
/**
* The delay in milliseconds before the tooltip
* is opened on keyboard focus, when not in manual mode.
* @attr {number} focus-delay
*/
focusDelay: {
type: Number,
},
/**
* The id of the element used as a tooltip trigger.
* The element should be in the DOM by the time when
* the attribute is set, otherwise a warning is shown.
*/
for: {
type: String,
observer: '__forChanged',
},
/**
* The delay in milliseconds before the tooltip
* is closed on losing hover, when not in manual mode.
* On blur, the tooltip is closed immediately.
* @attr {number} hide-delay
*/
hideDelay: {
type: Number,
},
/**
* The delay in milliseconds before the tooltip
* is opened on hover, when not in manual mode.
* @attr {number} hover-delay
*/
hoverDelay: {
type: Number,
},
/**
* When true, the tooltip is controlled programmatically
* instead of reacting to focus and mouse events.
*/
manual: {
type: Boolean,
value: false,
},
/**
* When true, the tooltip is opened programmatically.
* Only works if `manual` is set to `true`.
*/
opened: {
type: Boolean,
value: false,
},
/**
* Position of the tooltip with respect to its target.
* Supported values: `top-start`, `top`, `top-end`,
* `bottom-start`, `bottom`, `bottom-end`, `start-top`,
* `start`, `start-bottom`, `end-top`, `end`, `end-bottom`.
*/
position: {
type: String,
},
/**
* Function used to detect whether to show the tooltip based on a condition,
* called every time the tooltip is about to be shown on hover and focus.
* The function takes two parameters: `target` and `context`, which contain
* values of the corresponding tooltip properties at the time of calling.
* The tooltip is only shown when the function invocation returns `true`.
*/
shouldShow: {
type: Object,
value: () => {
return (_target, _context) => true;
},
},
/**
* Reference to the element used as a tooltip trigger.
* The target must be placed in the same shadow scope.
* Defaults to an element referenced with `for`.
*/
target: {
type: Object,
observer: '__targetChanged',
},
/**
* String used as a tooltip content.
*/
text: {
type: String,
observer: '__textChanged',
},
/**
* Function used to generate the tooltip content.
* When provided, it overrides the `text` property.
* Use the `context` property to provide argument
* that can be passed to the generator function.
*/
generator: {
type: Object,
},
/**
* Set to true when the overlay is opened using auto-added
* event listeners: mouseenter and focusin (keyboard only).
* @protected
*/
_autoOpened: {
type: Boolean,
observer: '__autoOpenedChanged',
},
/**
* Default value used when `position` property is not set.
* @protected
*/
_position: {
type: String,
value: 'bottom',
},
/**
* Element used to link with the `aria-describedby`
* attribute. When not set, defaults to `target`.
* @protected
*/
_effectiveAriaTarget: {
type: Object,
computed: '__computeAriaTarget(ariaTarget, target)',
observer: '__effectiveAriaTargetChanged',
},
/** @private */
__effectivePosition: {
type: String,
computed: '__computePosition(position, _position)',
},
/** @private */
__isTargetHidden: {
type: Boolean,
value: false,
},
/** @private */
_isConnected: {
type: Boolean,
},
/** @private */
_srLabel: {
type: Object,
},
/** @private */
_overlayContent: {
type: String,
},
};
}
static get observers() {
return [
'__generatorChanged(_overlayElement, generator, context)',
'__updateSrLabelText(_srLabel, _overlayContent)',
];
}
/**
* Sets the default focus delay to be used by all tooltip instances,
* except for those that have focus delay configured using property.
*
* @param {number} delay
*/
static setDefaultFocusDelay(focusDelay) {
defaultFocusDelay = focusDelay != null && focusDelay >= 0 ? focusDelay : DEFAULT_DELAY;
}
/**
* Sets the default hide delay to be used by all tooltip instances,
* except for those that have hide delay configured using property.
*
* @param {number} hideDelay
*/
static setDefaultHideDelay(hideDelay) {
defaultHideDelay = hideDelay != null && hideDelay >= 0 ? hideDelay : DEFAULT_DELAY;
}
/**
* Sets the default hover delay to be used by all tooltip instances,
* except for those that have hover delay configured using property.
*
* @param {number} delay
*/
static setDefaultHoverDelay(hoverDelay) {
defaultHoverDelay = hoverDelay != null && hoverDelay >= 0 ? hoverDelay : DEFAULT_DELAY;
}
constructor() {
super();
this._uniqueId = `vaadin-tooltip-${generateUniqueId()}`;
this._renderer = this.__tooltipRenderer.bind(this);
this.__onFocusin = this.__onFocusin.bind(this);
this.__onFocusout = this.__onFocusout.bind(this);
this.__onMouseDown = this.__onMouseDown.bind(this);
this.__onMouseEnter = this.__onMouseEnter.bind(this);
this.__onMouseLeave = this.__onMouseLeave.bind(this);
this.__onKeyDown = this.__onKeyDown.bind(this);
this.__onOverlayOpen = this.__onOverlayOpen.bind(this);
this.__targetVisibilityObserver = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => this.__onTargetVisibilityChange(entry.isIntersecting));
},
{ threshold: 0 },
);
this._stateController = new TooltipStateController(this);
}
/** @protected */
connectedCallback() {
super.connectedCallback();
this._isConnected = true;
document.body.addEventListener('vaadin-overlay-open', this.__onOverlayOpen);
}
/** @protected */
disconnectedCallback() {
super.disconnectedCallback();
if (this._autoOpened) {
this._stateController.close(true);
}
this._isConnected = false;
document.body.removeEventListener('vaadin-overlay-open', this.__onOverlayOpen);
}
/** @protected */
ready() {
super.ready();
this._srLabelController = new SlotController(this, 'sr-label', 'div', {
initializer: (element) => {
element.id = this._uniqueId;
element.setAttribute('role', 'tooltip');
this._srLabel = element;
},
});
this.addController(this._srLabelController);
}
/** @private */
__computeAriaTarget(ariaTarget, target) {
const isElementNode = (el) => el && el.nodeType === Node.ELEMENT_NODE;
const isAriaTargetSet = Array.isArray(ariaTarget) ? ariaTarget.some(isElementNode) : ariaTarget;
return isAriaTargetSet ? ariaTarget : target;
}
/** @private */
__computeHorizontalAlign(position) {
return ['top-end', 'bottom-end', 'start-top', 'start', 'start-bottom'].includes(position) ? 'end' : 'start';
}
/** @private */
__computeNoHorizontalOverlap(position) {
return ['start-top', 'start', 'start-bottom', 'end-top', 'end', 'end-bottom'].includes(position);
}
/** @private */
__computeNoVerticalOverlap(position) {
return ['top-start', 'top-end', 'top', 'bottom-start', 'bottom', 'bottom-end'].includes(position);
}
/** @private */
__computeVerticalAlign(position) {
return ['top-start', 'top-end', 'top', 'start-bottom', 'end-bottom'].includes(position) ? 'bottom' : 'top';
}
/** @private */
__computeOpened(manual, opened, autoOpened, connected) {
return connected && (manual ? opened : autoOpened);
}
/** @private */
__computePosition(position, defaultPosition) {
return position || defaultPosition;
}
/** @private */
__tooltipRenderer(root) {
root.textContent = typeof this.generator === 'function' ? this.generator(this.context) : this.text;
// Update the sr-only label text content
this._overlayContent = root.textContent;
}
/** @private */
__effectiveAriaTargetChanged(ariaTarget, oldAriaTarget) {
if (oldAriaTarget) {
[oldAriaTarget].flat().forEach((target) => {
removeValueFromAttribute(target, 'aria-describedby', this._uniqueId);
});
}
if (ariaTarget) {
[ariaTarget].flat().forEach((target) => {
addValueToAttribute(target, 'aria-describedby', this._uniqueId);
});
}
}
/** @private */
__autoOpenedChanged(opened, oldOpened) {
if (opened) {
document.addEventListener('keydown', this.__onKeyDown, true);
} else if (oldOpened) {
document.removeEventListener('keydown', this.__onKeyDown, true);
}
}
/** @private */
__forChanged(forId) {
if (forId) {
this.__setTargetByIdDebouncer = Debouncer.debounce(this.__setTargetByIdDebouncer, microTask, () =>
this.__setTargetById(forId),
);
}
}
/** @private */
__setTargetById(targetId) {
if (!this.isConnected) {
return;
}
const target = this.getRootNode().getElementById(targetId);
if (target) {
this.target = target;
} else {
console.warn(`No element with id="${targetId}" found to show tooltip.`);
}
}
/** @private */
__targetChanged(target, oldTarget) {
if (oldTarget) {
oldTarget.removeEventListener('mouseenter', this.__onMouseEnter);
oldTarget.removeEventListener('mouseleave', this.__onMouseLeave);
oldTarget.removeEventListener('focusin', this.__onFocusin);
oldTarget.removeEventListener('focusout', this.__onFocusout);
oldTarget.removeEventListener('mousedown', this.__onMouseDown);
this.__targetVisibilityObserver.unobserve(oldTarget);
}
if (target) {
target.addEventListener('mouseenter', this.__onMouseEnter);
target.addEventListener('mouseleave', this.__onMouseLeave);
target.addEventListener('focusin', this.__onFocusin);
target.addEventListener('focusout', this.__onFocusout);
target.addEventListener('mousedown', this.__onMouseDown);
// Wait before observing to avoid Chrome issue.
requestAnimationFrame(() => {
this.__targetVisibilityObserver.observe(target);
});
}
}
/** @private */
__onFocusin(event) {
if (this.manual) {
return;
}
// Only open on keyboard focus.
if (!isKeyboardActive()) {
return;
}
// Do not re-open while focused if closed on Esc or mousedown.
if (this.target.contains(event.relatedTarget)) {
return;
}
if (!this.__isShouldShow()) {
return;
}
this.__focusInside = true;
if (!this.__isTargetHidden && (!this.__hoverInside || !this._autoOpened)) {
this._stateController.open({ focus: true });
}
}
/** @private */
__onFocusout(event) {
if (this.manual) {
return;
}
// Do not close when moving focus within a component.
if (this.target.contains(event.relatedTarget)) {
return;
}
this.__focusInside = false;
if (!this.__hoverInside) {
this._stateController.close(true);
}
}
/** @private */
__onKeyDown(event) {
if (event.key === 'Escape') {
event.stopPropagation();
this._stateController.close(true);
}
}
/** @private */
__onMouseDown() {
this._stateController.close(true);
}
/** @private */
__onMouseEnter() {
if (this.manual) {
return;
}
if (!this.__isShouldShow()) {
return;
}
if (this.__hoverInside) {
// Already hovering inside the element, do nothing.
return;
}
this.__hoverInside = true;
if (!this.__isTargetHidden && (!this.__focusInside || !this._autoOpened)) {
this._stateController.open({ hover: true });
}
}
/** @private */
__onMouseLeave(event) {
if (event.relatedTarget !== this._overlayElement) {
this.__handleMouseLeave();
}
}
/** @private */
__onOverlayMouseEnter() {
// Retain opened state when moving pointer over the overlay.
// Closing can start due to an offset between the target and
// the overlay itself. If that's the case, re-open overlay.
// See https://github.com/vaadin/web-components/issues/6316
if (this._stateController.isClosing) {
this._stateController.open({ immediate: true });
}
}
/** @private */
__onOverlayMouseLeave(event) {
if (event.relatedTarget !== this.target) {
this.__handleMouseLeave();
}
}
/** @private */
__handleMouseLeave() {
if (this.manual) {
return;
}
this.__hoverInside = false;
if (!this.__focusInside) {
this._stateController.close();
}
}
/** @private */
__onOverlayOpen() {
if (this.manual) {
return;
}
// Close tooltip if another overlay is opened on top of the tooltip's overlay
if (this._overlayElement.opened && !this._overlayElement._last) {
this._stateController.close(true);
}
}
/** @private */
__onTargetVisibilityChange(isVisible) {
const oldHidden = this.__isTargetHidden;
this.__isTargetHidden = !isVisible;
// Open the overlay when the target becomes visible and has focus or hover.
if (oldHidden && isVisible && (this.__focusInside || this.__hoverInside)) {
this._stateController.open({ immediate: true });
return;
}
// Close the overlay when the target is no longer fully visible.
if (!isVisible && this._autoOpened) {
this._stateController.close(true);
}
}
/** @private */
__isShouldShow() {
if (typeof this.shouldShow === 'function' && this.shouldShow(this.target, this.context) !== true) {
return false;
}
return true;
}
/** @private */
__textChanged(text, oldText) {
if (this._overlayElement && (text || oldText)) {
this._overlayElement.requestContentUpdate();
}
}
/** @private */
__generatorChanged(overlayElement, generator, context) {
if (overlayElement) {
if (generator !== this.__oldTextGenerator || context !== this.__oldContext) {
overlayElement.requestContentUpdate();
}
this.__oldTextGenerator = generator;
this.__oldContext = context;
}
}
/** @private */
__updateSrLabelText(srLabel, textContent) {
if (srLabel) {
srLabel.textContent = textContent;
}
}
}

@@ -886,0 +93,0 @@

{
"$schema": "https://json.schemastore.org/web-types",
"name": "@vaadin/tooltip",
"version": "24.2.0-beta2",
"version": "24.2.0-beta3",
"description-markup": "markdown",

@@ -11,3 +11,3 @@ "contributions": {

"name": "vaadin-tooltip",
"description": "`<vaadin-tooltip>` is a Web Component for creating tooltips.\n\n```html\n<button id=\"confirm\">Confirm</button>\n<vaadin-tooltip text=\"Click to save changes\" for=\"confirm\"></vaadin-tooltip>\n```\n\n### Styling\n\n`<vaadin-tooltip>` uses `<vaadin-tooltip-overlay>` internal\nthemable component as the actual visible overlay.\n\nSee [`<vaadin-overlay>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-beta2/#/elements/vaadin-overlay) documentation\nfor `<vaadin-tooltip-overlay>` parts.\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n-----------------|----------------------------------------\n`position` | Reflects the `position` property value.\n\nNote: the `theme` attribute value set on `<vaadin-tooltip>` is\npropagated to the internal `<vaadin-tooltip-overlay>` component.\n\n### Custom CSS Properties\n\nThe following custom CSS properties are available on the `<vaadin-tooltip>` element:\n\nCustom CSS property | Description\n---------------------------------|-------------\n`--vaadin-tooltip-offset-top` | Used as an offset when the tooltip is aligned vertically below the target\n`--vaadin-tooltip-offset-bottom` | Used as an offset when the tooltip is aligned vertically above the target\n`--vaadin-tooltip-offset-start` | Used as an offset when the tooltip is aligned horizontally after the target\n`--vaadin-tooltip-offset-end` | Used as an offset when the tooltip is aligned horizontally before the target\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
"description": "`<vaadin-tooltip>` is a Web Component for creating tooltips.\n\n```html\n<button id=\"confirm\">Confirm</button>\n<vaadin-tooltip text=\"Click to save changes\" for=\"confirm\"></vaadin-tooltip>\n```\n\n### Styling\n\n`<vaadin-tooltip>` uses `<vaadin-tooltip-overlay>` internal\nthemable component as the actual visible overlay.\n\nSee [`<vaadin-overlay>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-beta3/#/elements/vaadin-overlay) documentation\nfor `<vaadin-tooltip-overlay>` parts.\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n-----------------|----------------------------------------\n`position` | Reflects the `position` property value.\n\nNote: the `theme` attribute value set on `<vaadin-tooltip>` is\npropagated to the internal `<vaadin-tooltip-overlay>` component.\n\n### Custom CSS Properties\n\nThe following custom CSS properties are available on the `<vaadin-tooltip>` element:\n\nCustom CSS property | Description\n---------------------------------|-------------\n`--vaadin-tooltip-offset-top` | Used as an offset when the tooltip is aligned vertically below the target\n`--vaadin-tooltip-offset-bottom` | Used as an offset when the tooltip is aligned vertically above the target\n`--vaadin-tooltip-offset-start` | Used as an offset when the tooltip is aligned horizontally after the target\n`--vaadin-tooltip-offset-end` | Used as an offset when the tooltip is aligned horizontally before the target\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
"attributes": [

@@ -183,2 +183,13 @@ {

{
"name": "generator",
"description": "Function used to generate the tooltip content.\nWhen provided, it overrides the `text` property.\nUse the `context` property to provide argument\nthat can be passed to the generator function.",
"value": {
"type": [
"Object",
"null",
"undefined"
]
}
},
{
"name": "hideDelay",

@@ -270,13 +281,2 @@ "description": "The delay in milliseconds before the tooltip\nis closed on losing hover, when not in manual mode.\nOn blur, the tooltip is closed immediately.",

}
},
{
"name": "generator",
"description": "Function used to generate the tooltip content.\nWhen provided, it overrides the `text` property.\nUse the `context` property to provide argument\nthat can be passed to the generator function.",
"value": {
"type": [
"Object",
"null",
"undefined"
]
}
}

@@ -283,0 +283,0 @@ ],

{
"$schema": "https://json.schemastore.org/web-types",
"name": "@vaadin/tooltip",
"version": "24.2.0-beta2",
"version": "24.2.0-beta3",
"description-markup": "markdown",

@@ -19,3 +19,3 @@ "framework": "lit",

"name": "vaadin-tooltip",
"description": "`<vaadin-tooltip>` is a Web Component for creating tooltips.\n\n```html\n<button id=\"confirm\">Confirm</button>\n<vaadin-tooltip text=\"Click to save changes\" for=\"confirm\"></vaadin-tooltip>\n```\n\n### Styling\n\n`<vaadin-tooltip>` uses `<vaadin-tooltip-overlay>` internal\nthemable component as the actual visible overlay.\n\nSee [`<vaadin-overlay>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-beta2/#/elements/vaadin-overlay) documentation\nfor `<vaadin-tooltip-overlay>` parts.\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n-----------------|----------------------------------------\n`position` | Reflects the `position` property value.\n\nNote: the `theme` attribute value set on `<vaadin-tooltip>` is\npropagated to the internal `<vaadin-tooltip-overlay>` component.\n\n### Custom CSS Properties\n\nThe following custom CSS properties are available on the `<vaadin-tooltip>` element:\n\nCustom CSS property | Description\n---------------------------------|-------------\n`--vaadin-tooltip-offset-top` | Used as an offset when the tooltip is aligned vertically below the target\n`--vaadin-tooltip-offset-bottom` | Used as an offset when the tooltip is aligned vertically above the target\n`--vaadin-tooltip-offset-start` | Used as an offset when the tooltip is aligned horizontally after the target\n`--vaadin-tooltip-offset-end` | Used as an offset when the tooltip is aligned horizontally before the target\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
"description": "`<vaadin-tooltip>` is a Web Component for creating tooltips.\n\n```html\n<button id=\"confirm\">Confirm</button>\n<vaadin-tooltip text=\"Click to save changes\" for=\"confirm\"></vaadin-tooltip>\n```\n\n### Styling\n\n`<vaadin-tooltip>` uses `<vaadin-tooltip-overlay>` internal\nthemable component as the actual visible overlay.\n\nSee [`<vaadin-overlay>`](https://cdn.vaadin.com/vaadin-web-components/24.2.0-beta3/#/elements/vaadin-overlay) documentation\nfor `<vaadin-tooltip-overlay>` parts.\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n-----------------|----------------------------------------\n`position` | Reflects the `position` property value.\n\nNote: the `theme` attribute value set on `<vaadin-tooltip>` is\npropagated to the internal `<vaadin-tooltip-overlay>` component.\n\n### Custom CSS Properties\n\nThe following custom CSS properties are available on the `<vaadin-tooltip>` element:\n\nCustom CSS property | Description\n---------------------------------|-------------\n`--vaadin-tooltip-offset-top` | Used as an offset when the tooltip is aligned vertically below the target\n`--vaadin-tooltip-offset-bottom` | Used as an offset when the tooltip is aligned vertically above the target\n`--vaadin-tooltip-offset-start` | Used as an offset when the tooltip is aligned horizontally after the target\n`--vaadin-tooltip-offset-end` | Used as an offset when the tooltip is aligned horizontally before the target\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
"extension": true,

@@ -73,2 +73,9 @@ "attributes": [

{
"name": ".generator",
"description": "Function used to generate the tooltip content.\nWhen provided, it overrides the `text` property.\nUse the `context` property to provide argument\nthat can be passed to the generator function.",
"value": {
"kind": "expression"
}
},
{
"name": ".hideDelay",

@@ -114,9 +121,2 @@ "description": "The delay in milliseconds before the tooltip\nis closed on losing hover, when not in manual mode.\nOn blur, the tooltip is closed immediately.",

}
},
{
"name": ".generator",
"description": "Function used to generate the tooltip content.\nWhen provided, it overrides the `text` property.\nUse the `context` property to provide argument\nthat can be passed to the generator function.",
"value": {
"kind": "expression"
}
}

@@ -123,0 +123,0 @@ ]

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc