Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
f5fb681802
|
|||
|
39acbac0f1
|
|||
|
70991f6769
|
|||
|
49fe8cb238
|
|||
|
04e29c7987
|
|||
|
f1e8f86ce9
|
|||
|
9bbc4502fc
|
|||
|
9eb2ea5811
|
|||
|
9d5ed83f5b
|
940
.yarn/releases/yarn-4.14.1.cjs
vendored
Executable file
940
.yarn/releases/yarn-4.14.1.cjs
vendored
Executable file
File diff suppressed because one or more lines are too long
942
.yarn/releases/yarn-4.9.4.cjs
vendored
942
.yarn/releases/yarn-4.9.4.cjs
vendored
File diff suppressed because one or more lines are too long
@@ -1,5 +1,3 @@
|
|||||||
compressionLevel: mixed
|
|
||||||
|
|
||||||
enableGlobalCache: false
|
enableGlobalCache: false
|
||||||
|
|
||||||
yarnPath: .yarn/releases/yarn-4.9.4.cjs
|
yarnPath: .yarn/releases/yarn-4.14.1.cjs
|
||||||
|
|||||||
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,3 +1,17 @@
|
|||||||
|
## v7.0.1
|
||||||
|
|
||||||
|
- Исправление работы анимации
|
||||||
|
|
||||||
|
## v7.0.0
|
||||||
|
|
||||||
|
- Изменено значение по умолчанию для параметра `trigger`
|
||||||
|
- Рефакторинг кода и устранение ошибок
|
||||||
|
|
||||||
|
## v6.0.0
|
||||||
|
|
||||||
|
- Корректная работа сообытий mouseenter/mouseleave на тач-устройствах
|
||||||
|
- Предовтращаем лишние показы всплывающей подсказки
|
||||||
|
|
||||||
## v5.0.0
|
## v5.0.0
|
||||||
|
|
||||||
- Регистрируем сообытия mouseenter/mouseleave на тач-устройствах
|
- Регистрируем сообытия mouseenter/mouseleave на тач-устройствах
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ createTooltip(document.querySelector('button'), 'Подсказка', {
|
|||||||
placement: 'top',
|
placement: 'top',
|
||||||
shiftPadding: [8, 0],
|
shiftPadding: [8, 0],
|
||||||
theme: 'light',
|
theme: 'light',
|
||||||
trigger: 'mouseenter',
|
trigger: 'mouseenter click',
|
||||||
virtualReference: undefined,
|
virtualReference: undefined,
|
||||||
zIndex: '',
|
zIndex: '',
|
||||||
// Callback-функции, по умолчанию не заданы
|
// Callback-функции, по умолчанию не заданы
|
||||||
|
|||||||
152
index.js
152
index.js
@@ -13,11 +13,25 @@ const handleVisibilityChange = () => {
|
|||||||
if (document.hidden) {
|
if (document.hidden) {
|
||||||
// Скрываем все активные всплывающие подсказки
|
// Скрываем все активные всплывающие подсказки
|
||||||
for (const $tooltip of document.querySelectorAll('.tooltip')) {
|
for (const $tooltip of document.querySelectorAll('.tooltip')) {
|
||||||
if ($tooltip._reference?._tooltip?.isVisible) {
|
const ref = $tooltip._reference;
|
||||||
$tooltip._reference._tooltip.hide({ immediately: true });
|
if (ref?._tooltip) {
|
||||||
|
// Очищаем таймеры появления при скрытии страницы
|
||||||
|
clearTimeout(ref._tooltip._showTimeout);
|
||||||
|
if (ref._tooltip.isVisible) {
|
||||||
|
ref._tooltip.hide({ immediately: true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const templates = {
|
||||||
|
arrow: () => `
|
||||||
|
<div class="tooltip__arrow" style="pointer-events: none; position: absolute; transform: rotate(45deg);"></div>
|
||||||
|
`,
|
||||||
|
interactiveHelper: () => `
|
||||||
|
<div class="tooltip__interactive-helper" style="position: absolute; z-index: -1;"></div>
|
||||||
|
`,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createTooltip = ($el, content, options) => {
|
export const createTooltip = ($el, content, options) => {
|
||||||
@@ -37,7 +51,7 @@ export const createTooltip = ($el, content, options) => {
|
|||||||
placement: 'top',
|
placement: 'top',
|
||||||
shiftPadding: [8, 0],
|
shiftPadding: [8, 0],
|
||||||
theme: 'light',
|
theme: 'light',
|
||||||
trigger: 'mouseenter',
|
trigger: 'mouseenter click',
|
||||||
virtualReference: undefined,
|
virtualReference: undefined,
|
||||||
zIndex: '',
|
zIndex: '',
|
||||||
...options,
|
...options,
|
||||||
@@ -53,8 +67,6 @@ export const createTooltip = ($el, content, options) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let showTimeout;
|
|
||||||
let hideTimeout;
|
|
||||||
let rafId;
|
let rafId;
|
||||||
const listeners = [];
|
const listeners = [];
|
||||||
|
|
||||||
@@ -65,7 +77,11 @@ export const createTooltip = ($el, content, options) => {
|
|||||||
$container: undefined,
|
$container: undefined,
|
||||||
$arrow: undefined,
|
$arrow: undefined,
|
||||||
$interactive: undefined,
|
$interactive: undefined,
|
||||||
|
_showTimeout: undefined,
|
||||||
|
_hideTimeout: undefined,
|
||||||
|
_currentAnimation: undefined,
|
||||||
autoUpdateCleanup: () => {},
|
autoUpdateCleanup: () => {},
|
||||||
|
updatePosition: async () => {},
|
||||||
|
|
||||||
setContent(updatedContent) {
|
setContent(updatedContent) {
|
||||||
if (updatedContent !== undefined) {
|
if (updatedContent !== undefined) {
|
||||||
@@ -89,15 +105,7 @@ export const createTooltip = ($el, content, options) => {
|
|||||||
if (updatedOptions.arrow !== undefined && $el._tooltip.$tooltip) {
|
if (updatedOptions.arrow !== undefined && $el._tooltip.$tooltip) {
|
||||||
if (options.arrow) {
|
if (options.arrow) {
|
||||||
if (!$el._tooltip.$arrow) {
|
if (!$el._tooltip.$arrow) {
|
||||||
$el._tooltip.$tooltip.insertAdjacentHTML(
|
$el._tooltip.$tooltip.querySelector('.tooltip__root').insertAdjacentHTML('afterbegin', templates.arrow());
|
||||||
'afterbegin',
|
|
||||||
`
|
|
||||||
<div
|
|
||||||
class="tooltip__arrow"
|
|
||||||
style="pointer-events: none; position: absolute; transform: rotate(45deg);">
|
|
||||||
</div>
|
|
||||||
`,
|
|
||||||
);
|
|
||||||
$el._tooltip.$arrow = $el._tooltip.$tooltip.querySelector('.tooltip__arrow');
|
$el._tooltip.$arrow = $el._tooltip.$tooltip.querySelector('.tooltip__arrow');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -115,15 +123,7 @@ export const createTooltip = ($el, content, options) => {
|
|||||||
if ($el._tooltip.$tooltip) {
|
if ($el._tooltip.$tooltip) {
|
||||||
if (options.interactive) {
|
if (options.interactive) {
|
||||||
if (!$el._tooltip.$interactive) {
|
if (!$el._tooltip.$interactive) {
|
||||||
$el._tooltip.$tooltip.insertAdjacentHTML(
|
$el._tooltip.$tooltip.querySelector('.tooltip__root').insertAdjacentHTML('afterbegin', templates.interactiveHelper());
|
||||||
'afterbegin',
|
|
||||||
`
|
|
||||||
<div
|
|
||||||
class="tooltip__interactive-helper"
|
|
||||||
style="position: absolute; z-index: -1;">
|
|
||||||
</div>
|
|
||||||
`,
|
|
||||||
);
|
|
||||||
$el._tooltip.$interactive =
|
$el._tooltip.$interactive =
|
||||||
$el._tooltip.$tooltip.querySelector('.tooltip__interactive-helper');
|
$el._tooltip.$tooltip.querySelector('.tooltip__interactive-helper');
|
||||||
}
|
}
|
||||||
@@ -162,8 +162,9 @@ export const createTooltip = ($el, content, options) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
clearTimeout(showTimeout);
|
clearTimeout($el._tooltip._showTimeout);
|
||||||
clearTimeout(hideTimeout);
|
clearTimeout($el._tooltip._hideTimeout);
|
||||||
|
$el._tooltip._currentAnimation?.cancel();
|
||||||
cancelAnimationFrame(rafId);
|
cancelAnimationFrame(rafId);
|
||||||
|
|
||||||
$el._tooltip.$tooltip?.remove();
|
$el._tooltip.$tooltip?.remove();
|
||||||
@@ -178,6 +179,8 @@ export const createTooltip = ($el, content, options) => {
|
|||||||
}
|
}
|
||||||
listeners.length = 0;
|
listeners.length = 0;
|
||||||
|
|
||||||
|
document.body.removeEventListener('click', $el._tooltip.hideOnClickListener);
|
||||||
|
|
||||||
delete $el._tooltip;
|
delete $el._tooltip;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -187,7 +190,7 @@ export const createTooltip = ($el, content, options) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$el._tooltip.show = async ({ immediately } = {}) => {
|
$el._tooltip.show = async ({ immediately } = {}) => {
|
||||||
clearTimeout(hideTimeout);
|
clearTimeout($el._tooltip._hideTimeout);
|
||||||
|
|
||||||
if (!$el._tooltip.$tooltip) {
|
if (!$el._tooltip.$tooltip) {
|
||||||
const { computePosition, offset, flip, shift, arrow } = await import('@floating-ui/dom');
|
const { computePosition, offset, flip, shift, arrow } = await import('@floating-ui/dom');
|
||||||
@@ -199,26 +202,8 @@ export const createTooltip = ($el, content, options) => {
|
|||||||
|
|
||||||
$el._tooltip.$tooltip.innerHTML = `
|
$el._tooltip.$tooltip.innerHTML = `
|
||||||
<div class="tooltip__root">
|
<div class="tooltip__root">
|
||||||
${
|
${options.interactive ? templates.interactiveHelper() : ''}
|
||||||
options.interactive
|
${options.arrow ? templates.arrow() : ''}
|
||||||
? `
|
|
||||||
<div
|
|
||||||
class="tooltip__interactive-helper"
|
|
||||||
style="position: absolute; z-index: -1;">
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ''
|
|
||||||
}
|
|
||||||
${
|
|
||||||
options.arrow
|
|
||||||
? `
|
|
||||||
<div
|
|
||||||
class="tooltip__arrow"
|
|
||||||
style="pointer-events: none; position: absolute; transform: rotate(45deg);">
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ''
|
|
||||||
}
|
|
||||||
<div class="tooltip__container"></div>
|
<div class="tooltip__container"></div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -294,10 +279,18 @@ export const createTooltip = ($el, content, options) => {
|
|||||||
|
|
||||||
const { autoUpdate } = await import('@floating-ui/dom');
|
const { autoUpdate } = await import('@floating-ui/dom');
|
||||||
|
|
||||||
showTimeout = setTimeout(
|
$el._tooltip._showTimeout = setTimeout(
|
||||||
async () => {
|
async () => {
|
||||||
// Проверяем $el._tooltip на сущестование
|
const isMouseEnterTrigger = options.trigger.includes('mouseenter');
|
||||||
if (!$el._tooltip || $el._tooltip.isVisible) {
|
const isHovering = $el.matches(':hover');
|
||||||
|
|
||||||
|
// Проверяем $el._tooltip на сущестование и актуальность показа всплывающей подсказки
|
||||||
|
if (
|
||||||
|
!$el._tooltip ||
|
||||||
|
$el._tooltip.isVisible ||
|
||||||
|
(isMouseEnterTrigger && !isHovering) ||
|
||||||
|
document.hidden
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,10 +312,12 @@ export const createTooltip = ($el, content, options) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await $el._tooltip.$tooltip.querySelector('.tooltip__root').animate(options.animation[0], {
|
const animation = $el._tooltip.$tooltip.querySelector('.tooltip__root').animate(options.animation[0], {
|
||||||
duration: immediately ? 0 : options.duration[0],
|
duration: immediately ? 0 : options.duration[0],
|
||||||
easing: options.easing[0],
|
easing: options.easing[0],
|
||||||
}).finished;
|
});
|
||||||
|
$el._tooltip._currentAnimation = animation;
|
||||||
|
await animation.finished;
|
||||||
} catch {} // eslint-disable-line no-empty
|
} catch {} // eslint-disable-line no-empty
|
||||||
|
|
||||||
if (options.onShown) {
|
if (options.onShown) {
|
||||||
@@ -334,8 +329,8 @@ export const createTooltip = ($el, content, options) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
$el._tooltip.hide = ({ immediately } = {}) => {
|
$el._tooltip.hide = ({ immediately } = {}) => {
|
||||||
clearTimeout(showTimeout);
|
clearTimeout($el._tooltip._showTimeout);
|
||||||
hideTimeout = setTimeout(
|
$el._tooltip._hideTimeout = setTimeout(
|
||||||
async () => {
|
async () => {
|
||||||
// Проверяем $el._tooltip на сущестование
|
// Проверяем $el._tooltip на сущестование
|
||||||
if (!$el._tooltip || !$el._tooltip.isVisible) {
|
if (!$el._tooltip || !$el._tooltip.isVisible) {
|
||||||
@@ -346,11 +341,15 @@ export const createTooltip = ($el, content, options) => {
|
|||||||
options.onHide($el._tooltip);
|
options.onHide($el._tooltip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.body.removeEventListener('click', $el._tooltip.hideOnClickListener);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await $el._tooltip.$tooltip.querySelector('.tooltip__root').animate(options.animation[1], {
|
const animation = $el._tooltip.$tooltip.querySelector('.tooltip__root').animate(options.animation[1], {
|
||||||
duration: immediately ? 0 : options.duration[1],
|
duration: immediately ? 0 : options.duration[1],
|
||||||
easing: options.easing[1],
|
easing: options.easing[1],
|
||||||
}).finished;
|
});
|
||||||
|
$el._tooltip._currentAnimation = animation;
|
||||||
|
await animation.finished;
|
||||||
} catch {} // eslint-disable-line no-empty
|
} catch {} // eslint-disable-line no-empty
|
||||||
|
|
||||||
// Ещё одна проверка на сущестование $el._tooltip после await
|
// Ещё одна проверка на сущестование $el._tooltip после await
|
||||||
@@ -379,37 +378,47 @@ export const createTooltip = ($el, content, options) => {
|
|||||||
|
|
||||||
if (options.hideOnClick === 'all') {
|
if (options.hideOnClick === 'all') {
|
||||||
$el._tooltip.hide();
|
$el._tooltip.hide();
|
||||||
document.body.removeEventListener('click', $el._tooltip.hideOnClickListener);
|
|
||||||
} else if (options.hideOnClick === 'toggle') {
|
} else if (options.hideOnClick === 'toggle') {
|
||||||
if ($el.contains(target)) {
|
if ($el.contains(target)) {
|
||||||
$el._tooltip.hide();
|
$el._tooltip.hide();
|
||||||
document.body.removeEventListener('click', $el._tooltip.hideOnClickListener);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// options.hideOnClick === true
|
// options.hideOnClick === true
|
||||||
if ($el.contains(target) || !$el._tooltip.$tooltip.contains(target)) {
|
if ($el.contains(target) || !$el._tooltip.$tooltip.contains(target)) {
|
||||||
$el._tooltip.hide();
|
$el._tooltip.hide();
|
||||||
document.body.removeEventListener('click', $el._tooltip.hideOnClickListener);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$el._tooltip.clickListener = () => {
|
$el._tooltip.clickListener = () => {
|
||||||
|
if (document.hidden) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!$el._tooltip.isVisible) {
|
if (!$el._tooltip.isVisible) {
|
||||||
$el._tooltip.show();
|
$el._tooltip.show();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
$el._tooltip.mouseEnterListener = () => {
|
$el._tooltip.mouseEnterListener = (event) => {
|
||||||
|
if (event.pointerType !== 'mouse' || document.hidden) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
$el._tooltip.show();
|
$el._tooltip.show();
|
||||||
};
|
};
|
||||||
|
|
||||||
$el._tooltip.mouseLeaveListener = ({ relatedTarget }) => {
|
$el._tooltip.mouseLeaveListener = (event) => {
|
||||||
if (options.interactive && relatedTarget && $el._tooltip.$tooltip?.contains(relatedTarget)) {
|
if (event.pointerType !== 'mouse') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.interactive && event.relatedTarget && $el._tooltip.$tooltip?.contains(event.relatedTarget)) {
|
||||||
$el._tooltip.$tooltip.addEventListener(
|
$el._tooltip.$tooltip.addEventListener(
|
||||||
'mouseleave',
|
'pointerleave',
|
||||||
({ relatedTarget }) => {
|
(event) => {
|
||||||
if (!relatedTarget || !$el.contains(relatedTarget)) {
|
if (event.pointerType !== 'mouse') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!event.relatedTarget || !$el.contains(event.relatedTarget)) {
|
||||||
$el._tooltip.hide();
|
$el._tooltip.hide();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -421,6 +430,9 @@ export const createTooltip = ($el, content, options) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
$el._tooltip.focusListener = () => {
|
$el._tooltip.focusListener = () => {
|
||||||
|
if (document.hidden) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
$el._tooltip.show();
|
$el._tooltip.show();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -432,11 +444,11 @@ export const createTooltip = ($el, content, options) => {
|
|||||||
for (const trigger of options.trigger.split(' ')) {
|
for (const trigger of options.trigger.split(' ')) {
|
||||||
switch (trigger) {
|
switch (trigger) {
|
||||||
case 'mouseenter': {
|
case 'mouseenter': {
|
||||||
$el.addEventListener('mouseenter', $el._tooltip.mouseEnterListener);
|
$el.addEventListener('pointerenter', $el._tooltip.mouseEnterListener);
|
||||||
listeners.push({ el: $el, event: 'mouseenter', listener: $el._tooltip.mouseEnterListener });
|
listeners.push({ el: $el, event: 'pointerenter', listener: $el._tooltip.mouseEnterListener });
|
||||||
|
|
||||||
$el.addEventListener('mouseleave', $el._tooltip.mouseLeaveListener);
|
$el.addEventListener('pointerleave', $el._tooltip.mouseLeaveListener);
|
||||||
listeners.push({ el: $el, event: 'mouseleave', listener: $el._tooltip.mouseLeaveListener });
|
listeners.push({ el: $el, event: 'pointerleave', listener: $el._tooltip.mouseLeaveListener });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'click': {
|
case 'click': {
|
||||||
@@ -444,8 +456,8 @@ export const createTooltip = ($el, content, options) => {
|
|||||||
listeners.push({ el: $el, event: 'click', listener: $el._tooltip.clickListener });
|
listeners.push({ el: $el, event: 'click', listener: $el._tooltip.clickListener });
|
||||||
|
|
||||||
if (!options.interactive) {
|
if (!options.interactive) {
|
||||||
$el.addEventListener('mouseleave', $el._tooltip.mouseLeaveListener);
|
$el.addEventListener('pointerleave', $el._tooltip.mouseLeaveListener);
|
||||||
listeners.push({ el: $el, event: 'mouseleave', listener: $el._tooltip.mouseLeaveListener });
|
listeners.push({ el: $el, event: 'pointerleave', listener: $el._tooltip.mouseLeaveListener });
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "@advdominion/tooltip",
|
"name": "@advdominion/tooltip",
|
||||||
"version": "5.0.0",
|
"version": "7.0.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"packageManager": "yarn@4.9.4",
|
"packageManager": "yarn@4.14.1",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
Reference in New Issue
Block a user