react-tooltip 6.0.0-beta.1179.rc.16 → 6.0.0-beta.1179.rc.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/react-tooltip.cjs +638 -403
- package/dist/react-tooltip.cjs.map +1 -1
- package/dist/react-tooltip.css +2 -1
- package/dist/react-tooltip.min.cjs +2 -2
- package/dist/react-tooltip.min.cjs.map +1 -1
- package/dist/react-tooltip.min.css +1 -1
- package/dist/react-tooltip.min.mjs +2 -2
- package/dist/react-tooltip.min.mjs.map +1 -1
- package/dist/react-tooltip.mjs +639 -404
- package/dist/react-tooltip.mjs.map +1 -1
- package/dist/react-tooltip.umd.js +638 -403
- package/dist/react-tooltip.umd.js.map +1 -1
- package/dist/react-tooltip.umd.min.js +2 -2
- package/dist/react-tooltip.umd.min.js.map +1 -1
- package/package.json +6 -6
package/dist/react-tooltip.cjs
CHANGED
|
@@ -84,13 +84,10 @@ function injectStyle({ css, id = REACT_TOOLTIP_BASE_STYLES_ID, type = 'base', re
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}),
|
|
92
|
-
dom.shift({ padding: 5 }),
|
|
93
|
-
], border, arrowSize = 8, }) => {
|
|
87
|
+
// Hoisted constant middlewares — these configs never change
|
|
88
|
+
const defaultFlip = dom.flip({ fallbackAxisSideDirection: 'start' });
|
|
89
|
+
const defaultShift = dom.shift({ padding: 5 });
|
|
90
|
+
const computeTooltipPosition = async ({ elementReference = null, tooltipReference = null, tooltipArrowReference = null, place = 'top', offset: offsetValue = 10, strategy = 'absolute', middlewares = [dom.offset(Number(offsetValue)), defaultFlip, defaultShift], border, arrowSize = 8, }) => {
|
|
94
91
|
if (!elementReference) {
|
|
95
92
|
// elementReference can be null or undefined and we will not compute the position
|
|
96
93
|
// console.error('The reference element for tooltip was not defined: ', elementReference)
|
|
@@ -177,6 +174,7 @@ const cssTimeToMs = (time) => {
|
|
|
177
174
|
*/
|
|
178
175
|
const debounce = (func, wait, immediate) => {
|
|
179
176
|
let timeout = null;
|
|
177
|
+
let currentFunc = func;
|
|
180
178
|
const debounced = function debounced(...args) {
|
|
181
179
|
const later = () => {
|
|
182
180
|
timeout = null;
|
|
@@ -186,7 +184,7 @@ const debounce = (func, wait, immediate) => {
|
|
|
186
184
|
* there's no need to clear the timeout
|
|
187
185
|
* since we expect it to resolve and set `timeout = null`
|
|
188
186
|
*/
|
|
189
|
-
|
|
187
|
+
currentFunc.apply(this, args);
|
|
190
188
|
timeout = setTimeout(later, wait);
|
|
191
189
|
}
|
|
192
190
|
};
|
|
@@ -199,36 +197,12 @@ const debounce = (func, wait, immediate) => {
|
|
|
199
197
|
clearTimeout(timeout);
|
|
200
198
|
timeout = null;
|
|
201
199
|
};
|
|
200
|
+
debounced.setCallback = (newFunc) => {
|
|
201
|
+
currentFunc = newFunc;
|
|
202
|
+
};
|
|
202
203
|
return debounced;
|
|
203
204
|
};
|
|
204
205
|
|
|
205
|
-
const isObject = (object) => {
|
|
206
|
-
return object !== null && !Array.isArray(object) && typeof object === 'object';
|
|
207
|
-
};
|
|
208
|
-
const deepEqual = (object1, object2) => {
|
|
209
|
-
if (object1 === object2) {
|
|
210
|
-
return true;
|
|
211
|
-
}
|
|
212
|
-
if (Array.isArray(object1) && Array.isArray(object2)) {
|
|
213
|
-
if (object1.length !== object2.length) {
|
|
214
|
-
return false;
|
|
215
|
-
}
|
|
216
|
-
return object1.every((val, index) => deepEqual(val, object2[index]));
|
|
217
|
-
}
|
|
218
|
-
if (Array.isArray(object1) !== Array.isArray(object2)) {
|
|
219
|
-
return false;
|
|
220
|
-
}
|
|
221
|
-
if (!isObject(object1) || !isObject(object2)) {
|
|
222
|
-
return object1 === object2;
|
|
223
|
-
}
|
|
224
|
-
const keys1 = Object.keys(object1);
|
|
225
|
-
const keys2 = Object.keys(object2);
|
|
226
|
-
if (keys1.length !== keys2.length) {
|
|
227
|
-
return false;
|
|
228
|
-
}
|
|
229
|
-
return keys1.every((key) => deepEqual(object1[key], object2[key]));
|
|
230
|
-
};
|
|
231
|
-
|
|
232
206
|
const isScrollable = (node) => {
|
|
233
207
|
if (!(node instanceof HTMLElement || node instanceof SVGElement)) {
|
|
234
208
|
return false;
|
|
@@ -298,6 +272,14 @@ var styles = {"tooltip":"styles-module_tooltip__mnnfp","content":"styles-module_
|
|
|
298
272
|
|
|
299
273
|
const registry = new Map();
|
|
300
274
|
let documentObserver = null;
|
|
275
|
+
/**
|
|
276
|
+
* Extract a tooltip ID from a simple `[data-tooltip-id='value']` selector.
|
|
277
|
+
* Returns null for complex or custom selectors.
|
|
278
|
+
*/
|
|
279
|
+
function extractTooltipId(selector) {
|
|
280
|
+
const match = selector.match(/^\[data-tooltip-id=(['"])((?:\\.|(?!\1).)*)\1\]$/);
|
|
281
|
+
return match ? match[2].replace(/\\(['"])/g, '$1') : null;
|
|
282
|
+
}
|
|
301
283
|
function areAnchorListsEqual(left, right) {
|
|
302
284
|
if (left.length !== right.length) {
|
|
303
285
|
return false;
|
|
@@ -319,8 +301,7 @@ function readAnchorsForSelector(selector) {
|
|
|
319
301
|
}
|
|
320
302
|
}
|
|
321
303
|
function notifySubscribers(entry) {
|
|
322
|
-
|
|
323
|
-
entry.subscribers.forEach((subscriber) => subscriber(anchors, entry.error));
|
|
304
|
+
entry.subscribers.forEach((subscriber) => subscriber(entry.anchors, entry.error));
|
|
324
305
|
}
|
|
325
306
|
function refreshEntry(selector, entry) {
|
|
326
307
|
var _a, _b, _c, _d;
|
|
@@ -344,12 +325,117 @@ function refreshAllEntries() {
|
|
|
344
325
|
refreshEntry(selector, entry);
|
|
345
326
|
});
|
|
346
327
|
}
|
|
328
|
+
let refreshScheduled = false;
|
|
329
|
+
let pendingTooltipIds = null;
|
|
330
|
+
let pendingFullRefresh = false;
|
|
331
|
+
function scheduleRefresh(affectedTooltipIds) {
|
|
332
|
+
if (affectedTooltipIds) {
|
|
333
|
+
if (!pendingTooltipIds) {
|
|
334
|
+
pendingTooltipIds = new Set();
|
|
335
|
+
}
|
|
336
|
+
affectedTooltipIds.forEach((id) => pendingTooltipIds.add(id));
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
pendingFullRefresh = true;
|
|
340
|
+
}
|
|
341
|
+
if (refreshScheduled) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
refreshScheduled = true;
|
|
345
|
+
const flush = () => {
|
|
346
|
+
refreshScheduled = false;
|
|
347
|
+
const fullRefresh = pendingFullRefresh;
|
|
348
|
+
const ids = pendingTooltipIds;
|
|
349
|
+
pendingFullRefresh = false;
|
|
350
|
+
pendingTooltipIds = null;
|
|
351
|
+
if (fullRefresh) {
|
|
352
|
+
refreshAllEntries();
|
|
353
|
+
}
|
|
354
|
+
else if (ids && ids.size > 0) {
|
|
355
|
+
refreshEntriesForTooltipIds(ids);
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
if (typeof requestAnimationFrame === 'function') {
|
|
359
|
+
requestAnimationFrame(flush);
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
Promise.resolve().then(flush);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Only refresh entries whose tooltipId is in the affected set,
|
|
367
|
+
* plus any entries with custom (non-tooltipId) selectors.
|
|
368
|
+
*/
|
|
369
|
+
function refreshEntriesForTooltipIds(affectedIds) {
|
|
370
|
+
registry.forEach((entry, selector) => {
|
|
371
|
+
if (entry.tooltipId === null || affectedIds.has(entry.tooltipId)) {
|
|
372
|
+
refreshEntry(selector, entry);
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Collect tooltip IDs from mutation records. Returns null when targeted
|
|
378
|
+
* analysis is not worthwhile (few registry entries, or too many nodes to scan).
|
|
379
|
+
*/
|
|
380
|
+
function collectAffectedTooltipIds(records) {
|
|
381
|
+
var _a;
|
|
382
|
+
// Targeted refresh only pays off when there are many distinct selectors.
|
|
383
|
+
// With few entries, full refresh is already cheap — skip the analysis overhead.
|
|
384
|
+
if (registry.size <= 4) {
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
const ids = new Set();
|
|
388
|
+
for (const record of records) {
|
|
389
|
+
if (record.type === 'attributes') {
|
|
390
|
+
const target = record.target;
|
|
391
|
+
const currentId = (_a = target.getAttribute) === null || _a === void 0 ? void 0 : _a.call(target, 'data-tooltip-id');
|
|
392
|
+
if (currentId)
|
|
393
|
+
ids.add(currentId);
|
|
394
|
+
if (record.oldValue)
|
|
395
|
+
ids.add(record.oldValue);
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
if (record.type === 'childList') {
|
|
399
|
+
const gatherIds = (nodes) => {
|
|
400
|
+
var _a, _b;
|
|
401
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
402
|
+
const node = nodes[i];
|
|
403
|
+
if (node.nodeType !== Node.ELEMENT_NODE)
|
|
404
|
+
continue;
|
|
405
|
+
const el = node;
|
|
406
|
+
const id = (_a = el.getAttribute) === null || _a === void 0 ? void 0 : _a.call(el, 'data-tooltip-id');
|
|
407
|
+
if (id)
|
|
408
|
+
ids.add(id);
|
|
409
|
+
// For large subtrees, bail out to full refresh to avoid double-scanning
|
|
410
|
+
const descendants = (_b = el.querySelectorAll) === null || _b === void 0 ? void 0 : _b.call(el, '[data-tooltip-id]');
|
|
411
|
+
if (descendants) {
|
|
412
|
+
if (descendants.length > 50) {
|
|
413
|
+
return true; // signal bail-out
|
|
414
|
+
}
|
|
415
|
+
for (let j = 0; j < descendants.length; j++) {
|
|
416
|
+
const descId = descendants[j].getAttribute('data-tooltip-id');
|
|
417
|
+
if (descId)
|
|
418
|
+
ids.add(descId);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return false;
|
|
423
|
+
};
|
|
424
|
+
if (gatherIds(record.addedNodes) || gatherIds(record.removedNodes)) {
|
|
425
|
+
return null; // large mutation — full refresh is cheaper
|
|
426
|
+
}
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
return ids;
|
|
431
|
+
}
|
|
347
432
|
function ensureDocumentObserver() {
|
|
348
433
|
if (documentObserver || typeof MutationObserver === 'undefined') {
|
|
349
434
|
return;
|
|
350
435
|
}
|
|
351
|
-
documentObserver = new MutationObserver(() => {
|
|
352
|
-
|
|
436
|
+
documentObserver = new MutationObserver((records) => {
|
|
437
|
+
const affectedIds = collectAffectedTooltipIds(records);
|
|
438
|
+
scheduleRefresh(affectedIds);
|
|
353
439
|
});
|
|
354
440
|
documentObserver.observe(document.body, {
|
|
355
441
|
childList: true,
|
|
@@ -374,6 +460,7 @@ function subscribeAnchorSelector(selector, subscriber) {
|
|
|
374
460
|
anchors: initialState.anchors,
|
|
375
461
|
error: initialState.error,
|
|
376
462
|
subscribers: new Set(),
|
|
463
|
+
tooltipId: extractTooltipId(selector),
|
|
377
464
|
};
|
|
378
465
|
registry.set(selector, entry);
|
|
379
466
|
}
|
|
@@ -417,7 +504,8 @@ const useTooltipAnchors = ({ id, anchorSelect, imperativeAnchorSelect, activeAnc
|
|
|
417
504
|
catch (_a) {
|
|
418
505
|
return false;
|
|
419
506
|
}
|
|
420
|
-
|
|
507
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
508
|
+
}, [activeAnchor, selector, anchorElements]);
|
|
421
509
|
React.useEffect(() => {
|
|
422
510
|
if (!selector || !trackAnchors) {
|
|
423
511
|
setRawAnchorElements([]);
|
|
@@ -454,141 +542,75 @@ const useTooltipAnchors = ({ id, anchorSelect, imperativeAnchorSelect, activeAnc
|
|
|
454
542
|
};
|
|
455
543
|
};
|
|
456
544
|
|
|
545
|
+
/**
|
|
546
|
+
* Shared document event delegation.
|
|
547
|
+
*
|
|
548
|
+
* Instead of N tooltips each calling document.addEventListener(type, handler),
|
|
549
|
+
* we maintain ONE document listener per event type. When the event fires,
|
|
550
|
+
* we iterate through all registered handlers for that type.
|
|
551
|
+
*
|
|
552
|
+
* This reduces document-level listeners from O(N × eventTypes) to O(eventTypes).
|
|
553
|
+
*/
|
|
554
|
+
const handlersByType = new Map();
|
|
555
|
+
function getOrCreateSet(eventType) {
|
|
556
|
+
let set = handlersByType.get(eventType);
|
|
557
|
+
if (!set) {
|
|
558
|
+
set = new Set();
|
|
559
|
+
handlersByType.set(eventType, set);
|
|
560
|
+
document.addEventListener(eventType, dispatch);
|
|
561
|
+
}
|
|
562
|
+
return set;
|
|
563
|
+
}
|
|
564
|
+
function dispatch(event) {
|
|
565
|
+
const handlers = handlersByType.get(event.type);
|
|
566
|
+
if (handlers) {
|
|
567
|
+
// Safe to iterate directly — mutations (add/remove) only happen in
|
|
568
|
+
// setup/cleanup, not during dispatch. Set iteration is stable for
|
|
569
|
+
// entries that existed when iteration began.
|
|
570
|
+
handlers.forEach((handler) => {
|
|
571
|
+
handler(event);
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Register a handler for a document-level event type.
|
|
577
|
+
* Returns an unsubscribe function.
|
|
578
|
+
*/
|
|
579
|
+
function addDelegatedEventListener(eventType, handler) {
|
|
580
|
+
const set = getOrCreateSet(eventType);
|
|
581
|
+
set.add(handler);
|
|
582
|
+
return () => {
|
|
583
|
+
set.delete(handler);
|
|
584
|
+
if (set.size === 0) {
|
|
585
|
+
handlersByType.delete(eventType);
|
|
586
|
+
document.removeEventListener(eventType, dispatch);
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
|
|
457
591
|
const useTooltipEvents = ({ activeAnchor, anchorElements, anchorSelector, clickable, closeEvents, delayHide, delayShow, disableTooltip, float, globalCloseEvents, handleHideTooltipDelayed, handleShow, handleShowTooltipDelayed, handleTooltipPosition, hoveringTooltip, imperativeModeOnly, lastFloatPosition, openEvents, openOnClick, setActiveAnchor, show, tooltipHideDelayTimerRef, tooltipRef, tooltipShowDelayTimerRef, updateTooltipPosition, }) => {
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
}
|
|
481
|
-
catch (_c) {
|
|
482
|
-
return null;
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
return ((_b = anchorElements.find((anchor) => anchor === targetElement || anchor.contains(targetElement))) !== null && _b !== void 0 ? _b : null);
|
|
486
|
-
};
|
|
487
|
-
const handlePointerMove = (event) => {
|
|
488
|
-
if (!event) {
|
|
489
|
-
return;
|
|
490
|
-
}
|
|
491
|
-
if (!activeAnchor) {
|
|
492
|
-
return;
|
|
493
|
-
}
|
|
494
|
-
const targetAnchor = resolveAnchorElement(event.target);
|
|
495
|
-
if (targetAnchor !== activeAnchor) {
|
|
496
|
-
return;
|
|
497
|
-
}
|
|
498
|
-
const mouseEvent = event;
|
|
499
|
-
const mousePosition = {
|
|
500
|
-
x: mouseEvent.clientX,
|
|
501
|
-
y: mouseEvent.clientY,
|
|
502
|
-
};
|
|
503
|
-
handleTooltipPosition(mousePosition);
|
|
504
|
-
lastFloatPosition.current = mousePosition;
|
|
505
|
-
};
|
|
506
|
-
const handleClickOutsideAnchors = (event) => {
|
|
507
|
-
var _a;
|
|
508
|
-
if (!show) {
|
|
509
|
-
return;
|
|
510
|
-
}
|
|
511
|
-
const target = event.target;
|
|
512
|
-
if (!(target === null || target === void 0 ? void 0 : target.isConnected)) {
|
|
513
|
-
return;
|
|
514
|
-
}
|
|
515
|
-
if ((_a = tooltipRef.current) === null || _a === void 0 ? void 0 : _a.contains(target)) {
|
|
516
|
-
return;
|
|
517
|
-
}
|
|
518
|
-
if (activeAnchor === null || activeAnchor === void 0 ? void 0 : activeAnchor.contains(target)) {
|
|
519
|
-
return;
|
|
520
|
-
}
|
|
521
|
-
if (anchorElements.some((anchor) => anchor === null || anchor === void 0 ? void 0 : anchor.contains(target))) {
|
|
522
|
-
return;
|
|
523
|
-
}
|
|
524
|
-
handleShow(false);
|
|
525
|
-
clearTimeoutRef(tooltipShowDelayTimerRef);
|
|
526
|
-
};
|
|
527
|
-
const handleShowTooltip = (anchor) => {
|
|
528
|
-
if (!anchor) {
|
|
529
|
-
return;
|
|
530
|
-
}
|
|
531
|
-
if (!anchor.isConnected) {
|
|
532
|
-
setActiveAnchor(null);
|
|
533
|
-
return;
|
|
534
|
-
}
|
|
535
|
-
if (disableTooltip === null || disableTooltip === void 0 ? void 0 : disableTooltip(anchor)) {
|
|
536
|
-
return;
|
|
537
|
-
}
|
|
538
|
-
if (delayShow) {
|
|
539
|
-
handleShowTooltipDelayed();
|
|
540
|
-
}
|
|
541
|
-
else {
|
|
542
|
-
handleShow(true);
|
|
543
|
-
}
|
|
544
|
-
if (delayShow && activeAnchor && anchor !== activeAnchor) {
|
|
545
|
-
// Moving to a different anchor while one is already active — defer the anchor
|
|
546
|
-
// switch until the show delay fires to prevent content/position from updating
|
|
547
|
-
// before visibility transitions complete.
|
|
548
|
-
if (tooltipShowDelayTimerRef.current) {
|
|
549
|
-
clearTimeout(tooltipShowDelayTimerRef.current);
|
|
550
|
-
}
|
|
551
|
-
tooltipShowDelayTimerRef.current = setTimeout(() => {
|
|
552
|
-
setActiveAnchor(anchor);
|
|
553
|
-
handleShow(true);
|
|
554
|
-
}, delayShow);
|
|
555
|
-
}
|
|
556
|
-
else {
|
|
557
|
-
setActiveAnchor(anchor);
|
|
558
|
-
}
|
|
559
|
-
if (tooltipHideDelayTimerRef.current) {
|
|
560
|
-
clearTimeout(tooltipHideDelayTimerRef.current);
|
|
561
|
-
}
|
|
562
|
-
};
|
|
563
|
-
const handleHideTooltip = () => {
|
|
564
|
-
if (clickable) {
|
|
565
|
-
handleHideTooltipDelayed(delayHide || 100);
|
|
566
|
-
}
|
|
567
|
-
else if (delayHide) {
|
|
568
|
-
handleHideTooltipDelayed();
|
|
569
|
-
}
|
|
570
|
-
else {
|
|
571
|
-
handleShow(false);
|
|
572
|
-
}
|
|
573
|
-
if (tooltipShowDelayTimerRef.current) {
|
|
574
|
-
clearTimeout(tooltipShowDelayTimerRef.current);
|
|
575
|
-
}
|
|
576
|
-
};
|
|
577
|
-
const internalDebouncedHandleShowTooltip = debounce(handleShowTooltip, 50);
|
|
578
|
-
const internalDebouncedHandleHideTooltip = debounce(handleHideTooltip, 50);
|
|
579
|
-
const debouncedHandleShowTooltip = (anchor) => {
|
|
580
|
-
internalDebouncedHandleHideTooltip.cancel();
|
|
581
|
-
internalDebouncedHandleShowTooltip(anchor);
|
|
582
|
-
};
|
|
583
|
-
const debouncedHandleHideTooltip = () => {
|
|
584
|
-
internalDebouncedHandleShowTooltip.cancel();
|
|
585
|
-
internalDebouncedHandleHideTooltip();
|
|
586
|
-
};
|
|
587
|
-
const handleScrollResize = () => {
|
|
588
|
-
handleShow(false);
|
|
589
|
-
};
|
|
590
|
-
const hasClickEvent = openOnClick || (openEvents === null || openEvents === void 0 ? void 0 : openEvents.click) || (openEvents === null || openEvents === void 0 ? void 0 : openEvents.dblclick) || (openEvents === null || openEvents === void 0 ? void 0 : openEvents.mousedown);
|
|
591
|
-
const actualOpenEvents = openEvents
|
|
592
|
+
// Ref-stable debounced handlers — avoids recreating debounce instances on every effect run
|
|
593
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
594
|
+
const debouncedShowRef = React.useRef(debounce((_anchor) => { }, 50));
|
|
595
|
+
const debouncedHideRef = React.useRef(debounce(() => { }, 50));
|
|
596
|
+
// Cache scroll parents — only recompute when the element actually changes
|
|
597
|
+
const anchorScrollParentRef = React.useRef(null);
|
|
598
|
+
const tooltipScrollParentRef = React.useRef(null);
|
|
599
|
+
const prevAnchorRef = React.useRef(null);
|
|
600
|
+
const prevTooltipRef = React.useRef(null);
|
|
601
|
+
if (activeAnchor !== prevAnchorRef.current) {
|
|
602
|
+
prevAnchorRef.current = activeAnchor;
|
|
603
|
+
anchorScrollParentRef.current = getScrollParent(activeAnchor);
|
|
604
|
+
}
|
|
605
|
+
const currentTooltipEl = tooltipRef.current;
|
|
606
|
+
if (currentTooltipEl !== prevTooltipRef.current) {
|
|
607
|
+
prevTooltipRef.current = currentTooltipEl;
|
|
608
|
+
tooltipScrollParentRef.current = getScrollParent(currentTooltipEl);
|
|
609
|
+
}
|
|
610
|
+
// Memoize event config objects — only rebuild when the relevant props change
|
|
611
|
+
const hasClickEvent = openOnClick || (openEvents === null || openEvents === void 0 ? void 0 : openEvents.click) || (openEvents === null || openEvents === void 0 ? void 0 : openEvents.dblclick) || (openEvents === null || openEvents === void 0 ? void 0 : openEvents.mousedown);
|
|
612
|
+
const actualOpenEvents = React.useMemo(() => {
|
|
613
|
+
const events = openEvents
|
|
592
614
|
? { ...openEvents }
|
|
593
615
|
: {
|
|
594
616
|
mouseenter: true,
|
|
@@ -598,13 +620,25 @@ const useTooltipEvents = ({ activeAnchor, anchorElements, anchorSelector, clicka
|
|
|
598
620
|
mousedown: false,
|
|
599
621
|
};
|
|
600
622
|
if (!openEvents && openOnClick) {
|
|
601
|
-
Object.assign(
|
|
623
|
+
Object.assign(events, {
|
|
602
624
|
mouseenter: false,
|
|
603
625
|
focus: false,
|
|
604
626
|
click: true,
|
|
605
627
|
});
|
|
606
628
|
}
|
|
607
|
-
|
|
629
|
+
if (imperativeModeOnly) {
|
|
630
|
+
Object.assign(events, {
|
|
631
|
+
mouseenter: false,
|
|
632
|
+
focus: false,
|
|
633
|
+
click: false,
|
|
634
|
+
dblclick: false,
|
|
635
|
+
mousedown: false,
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
return events;
|
|
639
|
+
}, [openEvents, openOnClick, imperativeModeOnly]);
|
|
640
|
+
const actualCloseEvents = React.useMemo(() => {
|
|
641
|
+
const events = closeEvents
|
|
608
642
|
? { ...closeEvents }
|
|
609
643
|
: {
|
|
610
644
|
mouseleave: true,
|
|
@@ -614,12 +648,24 @@ const useTooltipEvents = ({ activeAnchor, anchorElements, anchorSelector, clicka
|
|
|
614
648
|
mouseup: false,
|
|
615
649
|
};
|
|
616
650
|
if (!closeEvents && openOnClick) {
|
|
617
|
-
Object.assign(
|
|
651
|
+
Object.assign(events, {
|
|
618
652
|
mouseleave: false,
|
|
619
653
|
blur: false,
|
|
620
654
|
});
|
|
621
655
|
}
|
|
622
|
-
|
|
656
|
+
if (imperativeModeOnly) {
|
|
657
|
+
Object.assign(events, {
|
|
658
|
+
mouseleave: false,
|
|
659
|
+
blur: false,
|
|
660
|
+
click: false,
|
|
661
|
+
dblclick: false,
|
|
662
|
+
mouseup: false,
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
return events;
|
|
666
|
+
}, [closeEvents, openOnClick, imperativeModeOnly]);
|
|
667
|
+
const actualGlobalCloseEvents = React.useMemo(() => {
|
|
668
|
+
const events = globalCloseEvents
|
|
623
669
|
? { ...globalCloseEvents }
|
|
624
670
|
: {
|
|
625
671
|
escape: false,
|
|
@@ -628,108 +674,157 @@ const useTooltipEvents = ({ activeAnchor, anchorElements, anchorSelector, clicka
|
|
|
628
674
|
clickOutsideAnchor: hasClickEvent || false,
|
|
629
675
|
};
|
|
630
676
|
if (imperativeModeOnly) {
|
|
631
|
-
Object.assign(
|
|
632
|
-
mouseenter: false,
|
|
633
|
-
focus: false,
|
|
634
|
-
click: false,
|
|
635
|
-
dblclick: false,
|
|
636
|
-
mousedown: false,
|
|
637
|
-
});
|
|
638
|
-
Object.assign(actualCloseEvents, {
|
|
639
|
-
mouseleave: false,
|
|
640
|
-
blur: false,
|
|
641
|
-
click: false,
|
|
642
|
-
dblclick: false,
|
|
643
|
-
mouseup: false,
|
|
644
|
-
});
|
|
645
|
-
Object.assign(actualGlobalCloseEvents, {
|
|
677
|
+
Object.assign(events, {
|
|
646
678
|
escape: false,
|
|
647
679
|
scroll: false,
|
|
648
680
|
resize: false,
|
|
649
681
|
clickOutsideAnchor: false,
|
|
650
682
|
});
|
|
651
683
|
}
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
684
|
+
return events;
|
|
685
|
+
}, [globalCloseEvents, hasClickEvent, imperativeModeOnly]);
|
|
686
|
+
// --- Refs for values read inside event handlers (avoids effect deps) ---
|
|
687
|
+
const activeAnchorRef = React.useRef(activeAnchor);
|
|
688
|
+
activeAnchorRef.current = activeAnchor;
|
|
689
|
+
const showRef = React.useRef(show);
|
|
690
|
+
showRef.current = show;
|
|
691
|
+
const anchorElementsRef = React.useRef(anchorElements);
|
|
692
|
+
anchorElementsRef.current = anchorElements;
|
|
693
|
+
const handleShowRef = React.useRef(handleShow);
|
|
694
|
+
handleShowRef.current = handleShow;
|
|
695
|
+
const handleTooltipPositionRef = React.useRef(handleTooltipPosition);
|
|
696
|
+
handleTooltipPositionRef.current = handleTooltipPosition;
|
|
697
|
+
const updateTooltipPositionRef = React.useRef(updateTooltipPosition);
|
|
698
|
+
updateTooltipPositionRef.current = updateTooltipPosition;
|
|
699
|
+
// --- Handler refs (updated every render, read via ref indirection in effects) ---
|
|
700
|
+
const resolveAnchorElementRef = React.useRef(() => null);
|
|
701
|
+
const handleShowTooltipRef = React.useRef(() => { });
|
|
702
|
+
const handleHideTooltipRef = React.useRef(() => { });
|
|
703
|
+
const dataTooltipId = anchorSelector ? parseDataTooltipIdSelector(anchorSelector) : null;
|
|
704
|
+
resolveAnchorElementRef.current = (target) => {
|
|
705
|
+
var _a, _b;
|
|
706
|
+
const targetElement = target;
|
|
707
|
+
if (!(targetElement === null || targetElement === void 0 ? void 0 : targetElement.isConnected)) {
|
|
708
|
+
return null;
|
|
709
|
+
}
|
|
710
|
+
if (dataTooltipId) {
|
|
711
|
+
const matchedAnchor = resolveDataTooltipAnchor(targetElement, dataTooltipId);
|
|
712
|
+
if (matchedAnchor && !(disableTooltip === null || disableTooltip === void 0 ? void 0 : disableTooltip(matchedAnchor))) {
|
|
713
|
+
return matchedAnchor;
|
|
714
|
+
}
|
|
659
715
|
}
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
716
|
+
else if (anchorSelector) {
|
|
717
|
+
try {
|
|
718
|
+
const matchedAnchor = (_a = (targetElement.matches(anchorSelector)
|
|
719
|
+
? targetElement
|
|
720
|
+
: targetElement.closest(anchorSelector))) !== null && _a !== void 0 ? _a : null;
|
|
721
|
+
if (matchedAnchor && !(disableTooltip === null || disableTooltip === void 0 ? void 0 : disableTooltip(matchedAnchor))) {
|
|
722
|
+
return matchedAnchor;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
catch (_c) {
|
|
726
|
+
return null;
|
|
727
|
+
}
|
|
663
728
|
}
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
});
|
|
729
|
+
return ((_b = anchorElementsRef.current.find((anchor) => anchor === targetElement || anchor.contains(targetElement))) !== null && _b !== void 0 ? _b : null);
|
|
730
|
+
};
|
|
731
|
+
handleShowTooltipRef.current = (anchor) => {
|
|
732
|
+
if (!anchor) {
|
|
733
|
+
return;
|
|
670
734
|
}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
735
|
+
if (!anchor.isConnected) {
|
|
736
|
+
setActiveAnchor(null);
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
739
|
+
if (disableTooltip === null || disableTooltip === void 0 ? void 0 : disableTooltip(anchor)) {
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
if (delayShow) {
|
|
743
|
+
handleShowTooltipDelayed();
|
|
744
|
+
}
|
|
745
|
+
else {
|
|
746
|
+
handleShow(true);
|
|
747
|
+
}
|
|
748
|
+
if (delayShow && activeAnchorRef.current && anchor !== activeAnchorRef.current) {
|
|
749
|
+
// Moving to a different anchor while one is already active — defer the anchor
|
|
750
|
+
// switch until the show delay fires to prevent content/position from updating
|
|
751
|
+
// before visibility transitions complete.
|
|
752
|
+
if (tooltipShowDelayTimerRef.current) {
|
|
753
|
+
clearTimeout(tooltipShowDelayTimerRef.current);
|
|
674
754
|
}
|
|
755
|
+
tooltipShowDelayTimerRef.current = setTimeout(() => {
|
|
756
|
+
setActiveAnchor(anchor);
|
|
757
|
+
handleShow(true);
|
|
758
|
+
}, delayShow);
|
|
759
|
+
}
|
|
760
|
+
else {
|
|
761
|
+
setActiveAnchor(anchor);
|
|
762
|
+
}
|
|
763
|
+
if (tooltipHideDelayTimerRef.current) {
|
|
764
|
+
clearTimeout(tooltipHideDelayTimerRef.current);
|
|
765
|
+
}
|
|
766
|
+
};
|
|
767
|
+
handleHideTooltipRef.current = () => {
|
|
768
|
+
if (clickable) {
|
|
769
|
+
handleHideTooltipDelayed(delayHide || 100);
|
|
770
|
+
}
|
|
771
|
+
else if (delayHide) {
|
|
772
|
+
handleHideTooltipDelayed();
|
|
773
|
+
}
|
|
774
|
+
else {
|
|
675
775
|
handleShow(false);
|
|
676
|
-
};
|
|
677
|
-
if (actualGlobalCloseEvents.escape) {
|
|
678
|
-
window.addEventListener('keydown', handleEsc);
|
|
679
776
|
}
|
|
680
|
-
if (
|
|
681
|
-
|
|
777
|
+
if (tooltipShowDelayTimerRef.current) {
|
|
778
|
+
clearTimeout(tooltipShowDelayTimerRef.current);
|
|
682
779
|
}
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
780
|
+
};
|
|
781
|
+
// Update debounced callbacks to always delegate to latest handler refs
|
|
782
|
+
const debouncedShow = debouncedShowRef.current;
|
|
783
|
+
const debouncedHide = debouncedHideRef.current;
|
|
784
|
+
debouncedShow.setCallback((anchor) => handleShowTooltipRef.current(anchor));
|
|
785
|
+
debouncedHide.setCallback(() => handleHideTooltipRef.current());
|
|
786
|
+
// --- Effect 1: Delegated anchor events + tooltip hover ---
|
|
787
|
+
// Only re-runs when the set of active event types or interaction mode changes.
|
|
788
|
+
// Handlers read reactive values (activeAnchor, show, etc.) from refs at invocation
|
|
789
|
+
// time, so this effect is decoupled from show/hide state changes.
|
|
790
|
+
React.useEffect(() => {
|
|
791
|
+
const cleanupFns = [];
|
|
792
|
+
const addDelegatedListener = (eventType, listener) => {
|
|
793
|
+
cleanupFns.push(addDelegatedEventListener(eventType, listener));
|
|
694
794
|
};
|
|
695
|
-
const
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
795
|
+
const activeAnchorContainsTarget = (event) => { var _a; return Boolean((event === null || event === void 0 ? void 0 : event.target) && ((_a = activeAnchorRef.current) === null || _a === void 0 ? void 0 : _a.contains(event.target))); };
|
|
796
|
+
const debouncedHandleShowTooltip = (anchor) => {
|
|
797
|
+
debouncedHide.cancel();
|
|
798
|
+
debouncedShow(anchor);
|
|
799
|
+
};
|
|
800
|
+
const debouncedHandleHideTooltip = () => {
|
|
801
|
+
debouncedShow.cancel();
|
|
802
|
+
debouncedHide();
|
|
700
803
|
};
|
|
701
|
-
const regularEvents = ['mouseover', 'mouseout', 'mouseenter', 'mouseleave', 'focus', 'blur'];
|
|
702
|
-
const clickEvents = ['click', 'dblclick', 'mousedown', 'mouseup'];
|
|
703
|
-
const delegatedEvents = [];
|
|
704
804
|
const addDelegatedHoverOpenListener = () => {
|
|
705
|
-
|
|
706
|
-
event
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
}
|
|
716
|
-
debouncedHandleShowTooltip(anchor);
|
|
717
|
-
},
|
|
805
|
+
addDelegatedListener('mouseover', (event) => {
|
|
806
|
+
const anchor = resolveAnchorElementRef.current(event.target);
|
|
807
|
+
if (!anchor) {
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
const relatedAnchor = resolveAnchorElementRef.current(event.relatedTarget);
|
|
811
|
+
if (relatedAnchor === anchor) {
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
debouncedHandleShowTooltip(anchor);
|
|
718
815
|
});
|
|
719
816
|
};
|
|
720
817
|
const addDelegatedHoverCloseListener = () => {
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
debouncedHandleHideTooltip();
|
|
732
|
-
},
|
|
818
|
+
addDelegatedListener('mouseout', (event) => {
|
|
819
|
+
var _a;
|
|
820
|
+
if (!activeAnchorContainsTarget(event)) {
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
const relatedTarget = event.relatedTarget;
|
|
824
|
+
if ((_a = activeAnchorRef.current) === null || _a === void 0 ? void 0 : _a.contains(relatedTarget)) {
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
debouncedHandleHideTooltip();
|
|
733
828
|
});
|
|
734
829
|
};
|
|
735
830
|
if (actualOpenEvents.mouseenter) {
|
|
@@ -745,37 +840,48 @@ const useTooltipEvents = ({ activeAnchor, anchorElements, anchorSelector, clicka
|
|
|
745
840
|
addDelegatedHoverCloseListener();
|
|
746
841
|
}
|
|
747
842
|
if (actualOpenEvents.focus) {
|
|
748
|
-
|
|
749
|
-
event
|
|
750
|
-
listener: (event) => {
|
|
751
|
-
debouncedHandleShowTooltip(resolveAnchorElement(event.target));
|
|
752
|
-
},
|
|
843
|
+
addDelegatedListener('focusin', (event) => {
|
|
844
|
+
debouncedHandleShowTooltip(resolveAnchorElementRef.current(event.target));
|
|
753
845
|
});
|
|
754
846
|
}
|
|
755
847
|
if (actualCloseEvents.blur) {
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
debouncedHandleHideTooltip();
|
|
767
|
-
},
|
|
848
|
+
addDelegatedListener('focusout', (event) => {
|
|
849
|
+
var _a;
|
|
850
|
+
if (!activeAnchorContainsTarget(event)) {
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
const relatedTarget = event.relatedTarget;
|
|
854
|
+
if ((_a = activeAnchorRef.current) === null || _a === void 0 ? void 0 : _a.contains(relatedTarget)) {
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
debouncedHandleHideTooltip();
|
|
768
858
|
});
|
|
769
859
|
}
|
|
860
|
+
const regularEvents = ['mouseover', 'mouseout', 'mouseenter', 'mouseleave', 'focus', 'blur'];
|
|
861
|
+
const clickEvents = ['click', 'dblclick', 'mousedown', 'mouseup'];
|
|
862
|
+
const handleClickOpenTooltipAnchor = (event) => {
|
|
863
|
+
var _a;
|
|
864
|
+
const anchor = resolveAnchorElementRef.current((_a = event === null || event === void 0 ? void 0 : event.target) !== null && _a !== void 0 ? _a : null);
|
|
865
|
+
if (!anchor) {
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
if (showRef.current && activeAnchorRef.current === anchor) {
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
handleShowTooltipRef.current(anchor);
|
|
872
|
+
};
|
|
873
|
+
const handleClickCloseTooltipAnchor = (event) => {
|
|
874
|
+
if (!showRef.current || !activeAnchorContainsTarget(event)) {
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
handleHideTooltipRef.current();
|
|
878
|
+
};
|
|
770
879
|
Object.entries(actualOpenEvents).forEach(([event, enabled]) => {
|
|
771
880
|
if (!enabled || regularEvents.includes(event)) {
|
|
772
881
|
return;
|
|
773
882
|
}
|
|
774
883
|
if (clickEvents.includes(event)) {
|
|
775
|
-
|
|
776
|
-
event,
|
|
777
|
-
listener: handleClickOpenTooltipAnchor,
|
|
778
|
-
});
|
|
884
|
+
addDelegatedListener(event, handleClickOpenTooltipAnchor);
|
|
779
885
|
}
|
|
780
886
|
});
|
|
781
887
|
Object.entries(actualCloseEvents).forEach(([event, enabled]) => {
|
|
@@ -783,33 +889,110 @@ const useTooltipEvents = ({ activeAnchor, anchorElements, anchorSelector, clicka
|
|
|
783
889
|
return;
|
|
784
890
|
}
|
|
785
891
|
if (clickEvents.includes(event)) {
|
|
786
|
-
|
|
787
|
-
event,
|
|
788
|
-
listener: handleClickCloseTooltipAnchor,
|
|
789
|
-
});
|
|
892
|
+
addDelegatedListener(event, handleClickCloseTooltipAnchor);
|
|
790
893
|
}
|
|
791
894
|
});
|
|
792
895
|
if (float) {
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
896
|
+
addDelegatedListener('pointermove', (event) => {
|
|
897
|
+
const currentActiveAnchor = activeAnchorRef.current;
|
|
898
|
+
if (!currentActiveAnchor) {
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
const targetAnchor = resolveAnchorElementRef.current(event.target);
|
|
902
|
+
if (targetAnchor !== currentActiveAnchor) {
|
|
903
|
+
return;
|
|
904
|
+
}
|
|
905
|
+
const mouseEvent = event;
|
|
906
|
+
const mousePosition = {
|
|
907
|
+
x: mouseEvent.clientX,
|
|
908
|
+
y: mouseEvent.clientY,
|
|
909
|
+
};
|
|
910
|
+
handleTooltipPositionRef.current(mousePosition);
|
|
911
|
+
lastFloatPosition.current = mousePosition;
|
|
796
912
|
});
|
|
797
913
|
}
|
|
914
|
+
const tooltipElement = tooltipRef.current;
|
|
798
915
|
const handleMouseOverTooltip = () => {
|
|
799
916
|
hoveringTooltip.current = true;
|
|
800
917
|
};
|
|
801
918
|
const handleMouseOutTooltip = () => {
|
|
802
919
|
hoveringTooltip.current = false;
|
|
803
|
-
|
|
920
|
+
handleHideTooltipRef.current();
|
|
804
921
|
};
|
|
805
922
|
const addHoveringTooltipListeners = clickable && (actualCloseEvents.mouseout || actualCloseEvents.mouseleave);
|
|
806
923
|
if (addHoveringTooltipListeners) {
|
|
807
924
|
tooltipElement === null || tooltipElement === void 0 ? void 0 : tooltipElement.addEventListener('mouseover', handleMouseOverTooltip);
|
|
808
925
|
tooltipElement === null || tooltipElement === void 0 ? void 0 : tooltipElement.addEventListener('mouseout', handleMouseOutTooltip);
|
|
809
926
|
}
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
927
|
+
return () => {
|
|
928
|
+
cleanupFns.forEach((fn) => fn());
|
|
929
|
+
if (addHoveringTooltipListeners) {
|
|
930
|
+
tooltipElement === null || tooltipElement === void 0 ? void 0 : tooltipElement.removeEventListener('mouseover', handleMouseOverTooltip);
|
|
931
|
+
tooltipElement === null || tooltipElement === void 0 ? void 0 : tooltipElement.removeEventListener('mouseout', handleMouseOutTooltip);
|
|
932
|
+
}
|
|
933
|
+
debouncedShow.cancel();
|
|
934
|
+
debouncedHide.cancel();
|
|
935
|
+
};
|
|
936
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
937
|
+
}, [actualOpenEvents, actualCloseEvents, float, clickable]);
|
|
938
|
+
// --- Effect 2: Global close events + auto-update ---
|
|
939
|
+
// Re-runs when the global close config changes, or when the active anchor changes
|
|
940
|
+
// (for scroll parent listeners and floating-ui autoUpdate).
|
|
941
|
+
React.useEffect(() => {
|
|
942
|
+
const handleScrollResize = () => {
|
|
943
|
+
handleShowRef.current(false);
|
|
944
|
+
};
|
|
945
|
+
const tooltipScrollParent = tooltipScrollParentRef.current;
|
|
946
|
+
const anchorScrollParent = anchorScrollParentRef.current;
|
|
947
|
+
if (actualGlobalCloseEvents.scroll) {
|
|
948
|
+
window.addEventListener('scroll', handleScrollResize);
|
|
949
|
+
anchorScrollParent === null || anchorScrollParent === void 0 ? void 0 : anchorScrollParent.addEventListener('scroll', handleScrollResize);
|
|
950
|
+
tooltipScrollParent === null || tooltipScrollParent === void 0 ? void 0 : tooltipScrollParent.addEventListener('scroll', handleScrollResize);
|
|
951
|
+
}
|
|
952
|
+
let updateTooltipCleanup = null;
|
|
953
|
+
if (actualGlobalCloseEvents.resize) {
|
|
954
|
+
window.addEventListener('resize', handleScrollResize);
|
|
955
|
+
}
|
|
956
|
+
else if (activeAnchor && tooltipRef.current) {
|
|
957
|
+
updateTooltipCleanup = dom.autoUpdate(activeAnchor, tooltipRef.current, () => updateTooltipPositionRef.current(), {
|
|
958
|
+
ancestorResize: true,
|
|
959
|
+
elementResize: true,
|
|
960
|
+
layoutShift: true,
|
|
961
|
+
});
|
|
962
|
+
}
|
|
963
|
+
const handleEsc = (event) => {
|
|
964
|
+
if (event.key !== 'Escape') {
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
handleShowRef.current(false);
|
|
968
|
+
};
|
|
969
|
+
if (actualGlobalCloseEvents.escape) {
|
|
970
|
+
window.addEventListener('keydown', handleEsc);
|
|
971
|
+
}
|
|
972
|
+
const handleClickOutsideAnchors = (event) => {
|
|
973
|
+
var _a, _b;
|
|
974
|
+
if (!showRef.current) {
|
|
975
|
+
return;
|
|
976
|
+
}
|
|
977
|
+
const target = event.target;
|
|
978
|
+
if (!(target === null || target === void 0 ? void 0 : target.isConnected)) {
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
if ((_a = tooltipRef.current) === null || _a === void 0 ? void 0 : _a.contains(target)) {
|
|
982
|
+
return;
|
|
983
|
+
}
|
|
984
|
+
if ((_b = activeAnchorRef.current) === null || _b === void 0 ? void 0 : _b.contains(target)) {
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
if (anchorElementsRef.current.some((anchor) => anchor === null || anchor === void 0 ? void 0 : anchor.contains(target))) {
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
handleShowRef.current(false);
|
|
991
|
+
clearTimeoutRef(tooltipShowDelayTimerRef);
|
|
992
|
+
};
|
|
993
|
+
if (actualGlobalCloseEvents.clickOutsideAnchor) {
|
|
994
|
+
window.addEventListener('click', handleClickOutsideAnchors);
|
|
995
|
+
}
|
|
813
996
|
return () => {
|
|
814
997
|
if (actualGlobalCloseEvents.scroll) {
|
|
815
998
|
window.removeEventListener('scroll', handleScrollResize);
|
|
@@ -822,51 +1005,19 @@ const useTooltipEvents = ({ activeAnchor, anchorElements, anchorSelector, clicka
|
|
|
822
1005
|
if (updateTooltipCleanup) {
|
|
823
1006
|
updateTooltipCleanup();
|
|
824
1007
|
}
|
|
825
|
-
if (actualGlobalCloseEvents.clickOutsideAnchor) {
|
|
826
|
-
window.removeEventListener('click', handleClickOutsideAnchors);
|
|
827
|
-
}
|
|
828
1008
|
if (actualGlobalCloseEvents.escape) {
|
|
829
1009
|
window.removeEventListener('keydown', handleEsc);
|
|
830
1010
|
}
|
|
831
|
-
if (
|
|
832
|
-
|
|
833
|
-
tooltipElement === null || tooltipElement === void 0 ? void 0 : tooltipElement.removeEventListener('mouseout', handleMouseOutTooltip);
|
|
1011
|
+
if (actualGlobalCloseEvents.clickOutsideAnchor) {
|
|
1012
|
+
window.removeEventListener('click', handleClickOutsideAnchors);
|
|
834
1013
|
}
|
|
835
|
-
delegatedEvents.forEach(({ event, listener }) => {
|
|
836
|
-
document.removeEventListener(event, listener);
|
|
837
|
-
});
|
|
838
|
-
internalDebouncedHandleShowTooltip.cancel();
|
|
839
|
-
internalDebouncedHandleHideTooltip.cancel();
|
|
840
1014
|
};
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
anchorElements,
|
|
844
|
-
anchorSelector,
|
|
845
|
-
clickable,
|
|
846
|
-
closeEvents,
|
|
847
|
-
delayHide,
|
|
848
|
-
delayShow,
|
|
849
|
-
disableTooltip,
|
|
850
|
-
float,
|
|
851
|
-
globalCloseEvents,
|
|
852
|
-
handleHideTooltipDelayed,
|
|
853
|
-
handleShow,
|
|
854
|
-
handleShowTooltipDelayed,
|
|
855
|
-
handleTooltipPosition,
|
|
856
|
-
imperativeModeOnly,
|
|
857
|
-
lastFloatPosition,
|
|
858
|
-
openEvents,
|
|
859
|
-
openOnClick,
|
|
860
|
-
setActiveAnchor,
|
|
861
|
-
show,
|
|
862
|
-
tooltipHideDelayTimerRef,
|
|
863
|
-
tooltipRef,
|
|
864
|
-
tooltipShowDelayTimerRef,
|
|
865
|
-
updateTooltipPosition,
|
|
866
|
-
hoveringTooltip,
|
|
867
|
-
]);
|
|
1015
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1016
|
+
}, [actualGlobalCloseEvents, activeAnchor]);
|
|
868
1017
|
};
|
|
869
1018
|
|
|
1019
|
+
// Shared across all tooltip instances — the CSS variable is on :root and never changes per-instance
|
|
1020
|
+
let globalTransitionShowDelay = null;
|
|
870
1021
|
const Tooltip = ({
|
|
871
1022
|
// props
|
|
872
1023
|
forwardRef, id, className, classNameArrow, variant = 'dark', portalRoot, anchorSelect, place = 'top', offset = 10, openOnClick = false, positionStrategy = 'absolute', middlewares, wrapper: WrapperElement, delayShow = 0, delayHide = 0, autoClose, float = false, hidden = false, noArrow = false, clickable = false, openEvents, closeEvents, globalCloseEvents, imperativeModeOnly, style: externalStyles, position, afterShow, afterHide, disableTooltip,
|
|
@@ -891,6 +1042,18 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
|
|
|
891
1042
|
const lastFloatPosition = React.useRef(null);
|
|
892
1043
|
const hoveringTooltip = React.useRef(false);
|
|
893
1044
|
const mounted = React.useRef(false);
|
|
1045
|
+
const virtualElementRef = React.useRef({
|
|
1046
|
+
getBoundingClientRect: () => ({
|
|
1047
|
+
x: 0,
|
|
1048
|
+
y: 0,
|
|
1049
|
+
width: 0,
|
|
1050
|
+
height: 0,
|
|
1051
|
+
top: 0,
|
|
1052
|
+
left: 0,
|
|
1053
|
+
right: 0,
|
|
1054
|
+
bottom: 0,
|
|
1055
|
+
}),
|
|
1056
|
+
});
|
|
894
1057
|
/**
|
|
895
1058
|
* useLayoutEffect runs before useEffect,
|
|
896
1059
|
* but should be used carefully because of caveats
|
|
@@ -988,8 +1151,11 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
|
|
|
988
1151
|
/**
|
|
989
1152
|
* see `onTransitionEnd` on tooltip wrapper
|
|
990
1153
|
*/
|
|
991
|
-
|
|
992
|
-
|
|
1154
|
+
if (globalTransitionShowDelay === null) {
|
|
1155
|
+
const style = getComputedStyle(document.body);
|
|
1156
|
+
globalTransitionShowDelay = cssTimeToMs(style.getPropertyValue('--rt-transition-show-delay'));
|
|
1157
|
+
}
|
|
1158
|
+
const transitionShowDelay = globalTransitionShowDelay;
|
|
993
1159
|
missedTransitionTimerRef.current = setTimeout(() => {
|
|
994
1160
|
/**
|
|
995
1161
|
* if the tooltip switches from `show === true` to `show === false` too fast
|
|
@@ -1020,9 +1186,26 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
|
|
|
1020
1186
|
if (!mounted.current) {
|
|
1021
1187
|
return;
|
|
1022
1188
|
}
|
|
1023
|
-
setComputedPosition((oldComputedPosition) =>
|
|
1024
|
-
|
|
1025
|
-
|
|
1189
|
+
setComputedPosition((oldComputedPosition) => {
|
|
1190
|
+
if (oldComputedPosition.place === newComputedPosition.place &&
|
|
1191
|
+
oldComputedPosition.tooltipStyles.left === newComputedPosition.tooltipStyles.left &&
|
|
1192
|
+
oldComputedPosition.tooltipStyles.top === newComputedPosition.tooltipStyles.top &&
|
|
1193
|
+
oldComputedPosition.tooltipStyles.border === newComputedPosition.tooltipStyles.border &&
|
|
1194
|
+
oldComputedPosition.tooltipArrowStyles.left ===
|
|
1195
|
+
newComputedPosition.tooltipArrowStyles.left &&
|
|
1196
|
+
oldComputedPosition.tooltipArrowStyles.top === newComputedPosition.tooltipArrowStyles.top &&
|
|
1197
|
+
oldComputedPosition.tooltipArrowStyles.right ===
|
|
1198
|
+
newComputedPosition.tooltipArrowStyles.right &&
|
|
1199
|
+
oldComputedPosition.tooltipArrowStyles.bottom ===
|
|
1200
|
+
newComputedPosition.tooltipArrowStyles.bottom &&
|
|
1201
|
+
oldComputedPosition.tooltipArrowStyles.borderBottom ===
|
|
1202
|
+
newComputedPosition.tooltipArrowStyles.borderBottom &&
|
|
1203
|
+
oldComputedPosition.tooltipArrowStyles.borderRight ===
|
|
1204
|
+
newComputedPosition.tooltipArrowStyles.borderRight) {
|
|
1205
|
+
return oldComputedPosition;
|
|
1206
|
+
}
|
|
1207
|
+
return newComputedPosition;
|
|
1208
|
+
});
|
|
1026
1209
|
}, []);
|
|
1027
1210
|
const handleShowTooltipDelayed = React.useCallback((delay = delayShow) => {
|
|
1028
1211
|
if (tooltipShowDelayTimerRef.current) {
|
|
@@ -1050,24 +1233,20 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
|
|
|
1050
1233
|
}, [delayHide, handleShow]);
|
|
1051
1234
|
const handleTooltipPosition = React.useCallback(({ x, y }) => {
|
|
1052
1235
|
var _a;
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
bottom: y,
|
|
1064
|
-
};
|
|
1065
|
-
},
|
|
1066
|
-
};
|
|
1236
|
+
virtualElementRef.current.getBoundingClientRect = () => ({
|
|
1237
|
+
x,
|
|
1238
|
+
y,
|
|
1239
|
+
width: 0,
|
|
1240
|
+
height: 0,
|
|
1241
|
+
top: y,
|
|
1242
|
+
left: x,
|
|
1243
|
+
right: x,
|
|
1244
|
+
bottom: y,
|
|
1245
|
+
});
|
|
1067
1246
|
computeTooltipPosition({
|
|
1068
1247
|
place: (_a = imperativeOptions === null || imperativeOptions === void 0 ? void 0 : imperativeOptions.place) !== null && _a !== void 0 ? _a : place,
|
|
1069
1248
|
offset,
|
|
1070
|
-
elementReference:
|
|
1249
|
+
elementReference: virtualElementRef.current,
|
|
1071
1250
|
tooltipReference: tooltipRef.current,
|
|
1072
1251
|
tooltipArrowReference: tooltipArrowRef.current,
|
|
1073
1252
|
strategy: positionStrategy,
|
|
@@ -1193,6 +1372,8 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
|
|
|
1193
1372
|
tooltipShowDelayTimerRef,
|
|
1194
1373
|
updateTooltipPosition,
|
|
1195
1374
|
});
|
|
1375
|
+
const updateTooltipPositionRef = React.useRef(updateTooltipPosition);
|
|
1376
|
+
updateTooltipPositionRef.current = updateTooltipPosition;
|
|
1196
1377
|
React.useEffect(() => {
|
|
1197
1378
|
if (!rendered) {
|
|
1198
1379
|
return;
|
|
@@ -1211,7 +1392,7 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
|
|
|
1211
1392
|
}
|
|
1212
1393
|
timeoutId = setTimeout(() => {
|
|
1213
1394
|
if (mounted.current) {
|
|
1214
|
-
|
|
1395
|
+
updateTooltipPositionRef.current();
|
|
1215
1396
|
}
|
|
1216
1397
|
timeoutId = null;
|
|
1217
1398
|
}, 0);
|
|
@@ -1223,7 +1404,7 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
|
|
|
1223
1404
|
clearTimeout(timeoutId);
|
|
1224
1405
|
}
|
|
1225
1406
|
};
|
|
1226
|
-
}, [content, contentWrapperRef, rendered
|
|
1407
|
+
}, [content, contentWrapperRef, rendered]);
|
|
1227
1408
|
React.useEffect(() => {
|
|
1228
1409
|
var _a;
|
|
1229
1410
|
const shouldResolveInitialActiveAnchor = rendered || defaultIsOpen || Boolean(isOpen);
|
|
@@ -1284,7 +1465,20 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
|
|
|
1284
1465
|
}, [delayShow, handleShowTooltipDelayed]);
|
|
1285
1466
|
const actualContent = (_a = imperativeOptions === null || imperativeOptions === void 0 ? void 0 : imperativeOptions.content) !== null && _a !== void 0 ? _a : content;
|
|
1286
1467
|
const hasContent = actualContent !== null && actualContent !== undefined;
|
|
1287
|
-
const canShow = show &&
|
|
1468
|
+
const canShow = show && computedPosition.tooltipStyles.left !== undefined;
|
|
1469
|
+
const tooltipStyle = React.useMemo(() => ({
|
|
1470
|
+
...externalStyles,
|
|
1471
|
+
...computedPosition.tooltipStyles,
|
|
1472
|
+
opacity: opacity !== undefined && canShow ? opacity : undefined,
|
|
1473
|
+
}), [externalStyles, computedPosition.tooltipStyles, opacity, canShow]);
|
|
1474
|
+
const arrowBackground = React.useMemo(() => arrowColor
|
|
1475
|
+
? `linear-gradient(to right bottom, transparent 50%, ${arrowColor} 50%)`
|
|
1476
|
+
: undefined, [arrowColor]);
|
|
1477
|
+
const arrowStyle = React.useMemo(() => ({
|
|
1478
|
+
...computedPosition.tooltipArrowStyles,
|
|
1479
|
+
background: arrowBackground,
|
|
1480
|
+
'--rt-arrow-size': `${arrowSize}px`,
|
|
1481
|
+
}), [computedPosition.tooltipArrowStyles, arrowBackground, arrowSize]);
|
|
1288
1482
|
React.useImperativeHandle(forwardRef, () => ({
|
|
1289
1483
|
open: (options) => {
|
|
1290
1484
|
let imperativeAnchor = null;
|
|
@@ -1339,19 +1533,9 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
|
|
|
1339
1533
|
setRendered(false);
|
|
1340
1534
|
setImperativeOptions(null);
|
|
1341
1535
|
afterHide === null || afterHide === void 0 ? void 0 : afterHide();
|
|
1342
|
-
}, style:
|
|
1343
|
-
...externalStyles,
|
|
1344
|
-
...computedPosition.tooltipStyles,
|
|
1345
|
-
opacity: opacity !== undefined && canShow ? opacity : undefined,
|
|
1346
|
-
}, ref: tooltipRef },
|
|
1536
|
+
}, style: tooltipStyle, ref: tooltipRef },
|
|
1347
1537
|
React.createElement(WrapperElement, { className: clsx('react-tooltip-content-wrapper', coreStyles['content'], styles['content']) }, actualContent),
|
|
1348
|
-
React.createElement(WrapperElement, { className: clsx('react-tooltip-arrow', coreStyles['arrow'], styles['arrow'], classNameArrow, noArrow && coreStyles['noArrow']), style:
|
|
1349
|
-
...computedPosition.tooltipArrowStyles,
|
|
1350
|
-
background: arrowColor
|
|
1351
|
-
? `linear-gradient(to right bottom, transparent 50%, ${arrowColor} 50%)`
|
|
1352
|
-
: undefined,
|
|
1353
|
-
'--rt-arrow-size': `${arrowSize}px`,
|
|
1354
|
-
}, ref: tooltipArrowRef }))) : null;
|
|
1538
|
+
React.createElement(WrapperElement, { className: clsx('react-tooltip-arrow', coreStyles['arrow'], styles['arrow'], classNameArrow, noArrow && coreStyles['noArrow']), style: arrowStyle, ref: tooltipArrowRef }))) : null;
|
|
1355
1539
|
if (!tooltipNode) {
|
|
1356
1540
|
return null;
|
|
1357
1541
|
}
|
|
@@ -1362,12 +1546,82 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
|
|
|
1362
1546
|
};
|
|
1363
1547
|
var Tooltip$1 = React.memo(Tooltip);
|
|
1364
1548
|
|
|
1549
|
+
/**
|
|
1550
|
+
* Shared MutationObserver for data-tooltip-* attribute changes.
|
|
1551
|
+
* Instead of N observers (one per tooltip), a single observer watches
|
|
1552
|
+
* all active anchors and dispatches changes to registered callbacks.
|
|
1553
|
+
*/
|
|
1554
|
+
const observedElements = new Map();
|
|
1555
|
+
let sharedObserver = null;
|
|
1556
|
+
const observerConfig = {
|
|
1557
|
+
attributes: true,
|
|
1558
|
+
childList: false,
|
|
1559
|
+
subtree: false,
|
|
1560
|
+
};
|
|
1561
|
+
function getObserver() {
|
|
1562
|
+
if (!sharedObserver) {
|
|
1563
|
+
sharedObserver = new MutationObserver((mutationList) => {
|
|
1564
|
+
var _a;
|
|
1565
|
+
for (const mutation of mutationList) {
|
|
1566
|
+
if (mutation.type !== 'attributes' ||
|
|
1567
|
+
!((_a = mutation.attributeName) === null || _a === void 0 ? void 0 : _a.startsWith('data-tooltip-'))) {
|
|
1568
|
+
continue;
|
|
1569
|
+
}
|
|
1570
|
+
const target = mutation.target;
|
|
1571
|
+
const callbacks = observedElements.get(target);
|
|
1572
|
+
if (callbacks) {
|
|
1573
|
+
callbacks.forEach((cb) => cb(target));
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
});
|
|
1577
|
+
}
|
|
1578
|
+
return sharedObserver;
|
|
1579
|
+
}
|
|
1580
|
+
function observeAnchorAttributes(element, callback) {
|
|
1581
|
+
const observer = getObserver();
|
|
1582
|
+
let callbacks = observedElements.get(element);
|
|
1583
|
+
if (!callbacks) {
|
|
1584
|
+
callbacks = new Set();
|
|
1585
|
+
observedElements.set(element, callbacks);
|
|
1586
|
+
observer.observe(element, observerConfig);
|
|
1587
|
+
}
|
|
1588
|
+
callbacks.add(callback);
|
|
1589
|
+
return () => {
|
|
1590
|
+
const cbs = observedElements.get(element);
|
|
1591
|
+
if (cbs) {
|
|
1592
|
+
cbs.delete(callback);
|
|
1593
|
+
if (cbs.size === 0) {
|
|
1594
|
+
observedElements.delete(element);
|
|
1595
|
+
// MutationObserver doesn't have unobserve — if no elements left, disconnect & reset
|
|
1596
|
+
if (observedElements.size === 0) {
|
|
1597
|
+
observer.disconnect();
|
|
1598
|
+
}
|
|
1599
|
+
else {
|
|
1600
|
+
// Re-observe remaining elements (MutationObserver has no per-target unobserve)
|
|
1601
|
+
observer.disconnect();
|
|
1602
|
+
observedElements.forEach((_cbs, el) => {
|
|
1603
|
+
observer.observe(el, observerConfig);
|
|
1604
|
+
});
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
};
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1365
1611
|
const TooltipController = React.forwardRef(({ id, anchorSelect, content, render, className, classNameArrow, variant = 'dark', portalRoot, place = 'top', offset = 10, wrapper = 'div', children = null, openOnClick = false, positionStrategy = 'absolute', middlewares, delayShow = 0, delayHide = 0, autoClose, float = false, hidden = false, noArrow = false, clickable = false, openEvents, closeEvents, globalCloseEvents, imperativeModeOnly = false, style, position, isOpen, defaultIsOpen = false, disableStyleInjection = false, border, opacity, arrowColor, arrowSize, setIsOpen, afterShow, afterHide, disableTooltip, role = 'tooltip', }, ref) => {
|
|
1366
1612
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1367
1613
|
const [activeAnchor, setActiveAnchor] = React.useState(null);
|
|
1368
1614
|
const [anchorDataAttributes, setAnchorDataAttributes] = React.useState({});
|
|
1369
1615
|
const previousActiveAnchorRef = React.useRef(null);
|
|
1370
1616
|
const styleInjectionRef = React.useRef(disableStyleInjection);
|
|
1617
|
+
const handleSetActiveAnchor = React.useCallback((anchor) => {
|
|
1618
|
+
setActiveAnchor((prev) => {
|
|
1619
|
+
if (!(anchor === null || anchor === void 0 ? void 0 : anchor.isSameNode(prev))) {
|
|
1620
|
+
previousActiveAnchorRef.current = prev;
|
|
1621
|
+
}
|
|
1622
|
+
return anchor;
|
|
1623
|
+
});
|
|
1624
|
+
}, []);
|
|
1371
1625
|
/* c8 ignore start */
|
|
1372
1626
|
const getDataAttributesFromAnchorElement = (elementReference) => {
|
|
1373
1627
|
const dataAttributes = elementReference === null || elementReference === void 0 ? void 0 : elementReference.getAttributeNames().reduce((acc, name) => {
|
|
@@ -1399,37 +1653,24 @@ const TooltipController = React.forwardRef(({ id, anchorSelect, content, render,
|
|
|
1399
1653
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1400
1654
|
}, []);
|
|
1401
1655
|
React.useEffect(() => {
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1656
|
+
if (!activeAnchor) {
|
|
1657
|
+
setAnchorDataAttributes({});
|
|
1658
|
+
return () => { };
|
|
1659
|
+
}
|
|
1660
|
+
const updateAttributes = (element) => {
|
|
1661
|
+
const attrs = getDataAttributesFromAnchorElement(element);
|
|
1662
|
+
setAnchorDataAttributes((prev) => {
|
|
1663
|
+
const keys = Object.keys(attrs);
|
|
1664
|
+
const prevKeys = Object.keys(prev);
|
|
1665
|
+
if (keys.length === prevKeys.length && keys.every((key) => attrs[key] === prev[key])) {
|
|
1666
|
+
return prev;
|
|
1409
1667
|
}
|
|
1410
|
-
|
|
1411
|
-
const dataAttributes = getDataAttributesFromAnchorElement(activeAnchor);
|
|
1412
|
-
setAnchorDataAttributes(dataAttributes);
|
|
1668
|
+
return attrs;
|
|
1413
1669
|
});
|
|
1414
1670
|
};
|
|
1415
|
-
|
|
1416
|
-
const
|
|
1417
|
-
|
|
1418
|
-
// to stay watching `data-attributes-*` from anchor element
|
|
1419
|
-
const observerConfig = { attributes: true, childList: false, subtree: false };
|
|
1420
|
-
if (activeAnchor) {
|
|
1421
|
-
const dataAttributes = getDataAttributesFromAnchorElement(activeAnchor);
|
|
1422
|
-
setAnchorDataAttributes(dataAttributes);
|
|
1423
|
-
// Start observing the target node for configured mutations
|
|
1424
|
-
observer.observe(activeAnchor, observerConfig);
|
|
1425
|
-
}
|
|
1426
|
-
else {
|
|
1427
|
-
setAnchorDataAttributes({});
|
|
1428
|
-
}
|
|
1429
|
-
return () => {
|
|
1430
|
-
// Remove the observer when the tooltip is destroyed
|
|
1431
|
-
observer.disconnect();
|
|
1432
|
-
};
|
|
1671
|
+
updateAttributes(activeAnchor);
|
|
1672
|
+
const unsubscribe = observeAnchorAttributes(activeAnchor, updateAttributes);
|
|
1673
|
+
return unsubscribe;
|
|
1433
1674
|
}, [activeAnchor, anchorSelect]);
|
|
1434
1675
|
React.useEffect(() => {
|
|
1435
1676
|
/* c8 ignore start */
|
|
@@ -1510,14 +1751,7 @@ const TooltipController = React.forwardRef(({ id, anchorSelect, content, render,
|
|
|
1510
1751
|
disableTooltip,
|
|
1511
1752
|
activeAnchor,
|
|
1512
1753
|
previousActiveAnchor: previousActiveAnchorRef.current,
|
|
1513
|
-
setActiveAnchor:
|
|
1514
|
-
setActiveAnchor((prev) => {
|
|
1515
|
-
if (!(anchor === null || anchor === void 0 ? void 0 : anchor.isSameNode(prev))) {
|
|
1516
|
-
previousActiveAnchorRef.current = prev;
|
|
1517
|
-
}
|
|
1518
|
-
return anchor;
|
|
1519
|
-
});
|
|
1520
|
-
},
|
|
1754
|
+
setActiveAnchor: handleSetActiveAnchor,
|
|
1521
1755
|
role,
|
|
1522
1756
|
};
|
|
1523
1757
|
return React.createElement(Tooltip$1, { ...props });
|
|
@@ -1544,7 +1778,6 @@ const TooltipCoreStyles = `:root {
|
|
|
1544
1778
|
left: 0;
|
|
1545
1779
|
pointer-events: none;
|
|
1546
1780
|
opacity: 0;
|
|
1547
|
-
will-change: opacity;
|
|
1548
1781
|
}
|
|
1549
1782
|
|
|
1550
1783
|
.core-styles-module_fixed__pcSol {
|
|
@@ -1575,11 +1808,13 @@ const TooltipCoreStyles = `:root {
|
|
|
1575
1808
|
.core-styles-module_show__Nt9eE {
|
|
1576
1809
|
opacity: var(--rt-opacity);
|
|
1577
1810
|
transition: opacity var(--rt-transition-show-delay) ease-out;
|
|
1811
|
+
will-change: opacity;
|
|
1578
1812
|
}
|
|
1579
1813
|
|
|
1580
1814
|
.core-styles-module_closing__sGnxF {
|
|
1581
1815
|
opacity: 0;
|
|
1582
1816
|
transition: opacity var(--rt-transition-closing-delay) ease-in;
|
|
1817
|
+
will-change: opacity;
|
|
1583
1818
|
}
|
|
1584
1819
|
|
|
1585
1820
|
`;
|