react-tooltip 6.0.0-beta.1179.rc.8 → 6.0.0

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.
@@ -44,11 +44,9 @@ function injectStyle({ css, id = REACT_TOOLTIP_BASE_STYLES_ID, type = 'base', re
44
44
  return;
45
45
  }
46
46
  if (type === 'core') {
47
- // eslint-disable-next-line no-param-reassign
48
47
  id = REACT_TOOLTIP_CORE_STYLES_ID;
49
48
  }
50
49
  if (!ref) {
51
- // eslint-disable-next-line no-param-reassign
52
50
  ref = {};
53
51
  }
54
52
  const { insertAt } = ref;
@@ -79,7 +77,6 @@ function injectStyle({ css, id = REACT_TOOLTIP_BASE_STYLES_ID, type = 'base', re
79
77
  style.appendChild(document.createTextNode(css));
80
78
  }
81
79
  if (typeof state[type] !== 'undefined') {
82
- // eslint-disable-next-line no-param-reassign
83
80
  state[type] = true;
84
81
  }
85
82
  else {
@@ -87,16 +84,12 @@ function injectStyle({ css, id = REACT_TOOLTIP_BASE_STYLES_ID, type = 'base', re
87
84
  }
88
85
  }
89
86
 
90
- const computeTooltipPosition = async ({ elementReference = null, tooltipReference = null, tooltipArrowReference = null, place = 'top', offset: offsetValue = 10, strategy = 'absolute', middlewares = [
91
- dom.offset(Number(offsetValue)),
92
- dom.flip({
93
- fallbackAxisSideDirection: 'start',
94
- }),
95
- dom.shift({ padding: 5 }),
96
- ], 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, }) => {
97
91
  if (!elementReference) {
98
92
  // elementReference can be null or undefined and we will not compute the position
99
- // eslint-disable-next-line no-console
100
93
  // console.error('The reference element for tooltip was not defined: ', elementReference)
101
94
  return { tooltipStyles: {}, tooltipArrowStyles: {}, place };
102
95
  }
@@ -181,6 +174,7 @@ const cssTimeToMs = (time) => {
181
174
  */
182
175
  const debounce = (func, wait, immediate) => {
183
176
  let timeout = null;
177
+ let currentFunc = func;
184
178
  const debounced = function debounced(...args) {
185
179
  const later = () => {
186
180
  timeout = null;
@@ -190,7 +184,7 @@ const debounce = (func, wait, immediate) => {
190
184
  * there's no need to clear the timeout
191
185
  * since we expect it to resolve and set `timeout = null`
192
186
  */
193
- func.apply(this, args);
187
+ currentFunc.apply(this, args);
194
188
  timeout = setTimeout(later, wait);
195
189
  }
196
190
  };
@@ -203,36 +197,12 @@ const debounce = (func, wait, immediate) => {
203
197
  clearTimeout(timeout);
204
198
  timeout = null;
205
199
  };
200
+ debounced.setCallback = (newFunc) => {
201
+ currentFunc = newFunc;
202
+ };
206
203
  return debounced;
207
204
  };
208
205
 
209
- const isObject = (object) => {
210
- return object !== null && !Array.isArray(object) && typeof object === 'object';
211
- };
212
- const deepEqual = (object1, object2) => {
213
- if (object1 === object2) {
214
- return true;
215
- }
216
- if (Array.isArray(object1) && Array.isArray(object2)) {
217
- if (object1.length !== object2.length) {
218
- return false;
219
- }
220
- return object1.every((val, index) => deepEqual(val, object2[index]));
221
- }
222
- if (Array.isArray(object1) !== Array.isArray(object2)) {
223
- return false;
224
- }
225
- if (!isObject(object1) || !isObject(object2)) {
226
- return object1 === object2;
227
- }
228
- const keys1 = Object.keys(object1);
229
- const keys2 = Object.keys(object2);
230
- if (keys1.length !== keys2.length) {
231
- return false;
232
- }
233
- return keys1.every((key) => deepEqual(object1[key], object2[key]));
234
- };
235
-
236
206
  const isScrollable = (node) => {
237
207
  if (!(node instanceof HTMLElement || node instanceof SVGElement)) {
238
208
  return false;
@@ -273,17 +243,43 @@ const useIsomorphicLayoutEffect = isHopefullyDomEnvironment ? React.useLayoutEff
273
243
  const clearTimeoutRef = (ref) => {
274
244
  if (ref.current) {
275
245
  clearTimeout(ref.current);
276
- // eslint-disable-next-line no-param-reassign
277
246
  ref.current = null;
278
247
  }
279
248
  };
280
249
 
250
+ function parseDataTooltipIdSelector(selector) {
251
+ const match = selector.match(/^\[data-tooltip-id=(['"])((?:\\.|(?!\1).)*)\1\]$/);
252
+ if (!match) {
253
+ return null;
254
+ }
255
+ return match[2].replace(/\\(['"])/g, '$1');
256
+ }
257
+
258
+ function resolveDataTooltipAnchor(targetElement, tooltipId) {
259
+ let currentElement = targetElement;
260
+ while (currentElement) {
261
+ if (currentElement.dataset.tooltipId === tooltipId) {
262
+ return currentElement;
263
+ }
264
+ currentElement = currentElement.parentElement;
265
+ }
266
+ return null;
267
+ }
268
+
281
269
  var coreStyles = {"tooltip":"core-styles-module_tooltip__3vRRp","fixed":"core-styles-module_fixed__pcSol","arrow":"core-styles-module_arrow__cvMwQ","content":"core-styles-module_content__BRKdB","noArrow":"core-styles-module_noArrow__xock6","clickable":"core-styles-module_clickable__ZuTTB","show":"core-styles-module_show__Nt9eE","closing":"core-styles-module_closing__sGnxF"};
282
270
 
283
271
  var styles = {"tooltip":"styles-module_tooltip__mnnfp","content":"styles-module_content__ydYdI","arrow":"styles-module_arrow__K0L3T","dark":"styles-module_dark__xNqje","light":"styles-module_light__Z6W-X","success":"styles-module_success__A2AKt","warning":"styles-module_warning__SCK0X","error":"styles-module_error__JvumD","info":"styles-module_info__BWdHW"};
284
272
 
285
273
  const registry = new Map();
286
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
+ }
287
283
  function areAnchorListsEqual(left, right) {
288
284
  if (left.length !== right.length) {
289
285
  return false;
@@ -305,8 +301,7 @@ function readAnchorsForSelector(selector) {
305
301
  }
306
302
  }
307
303
  function notifySubscribers(entry) {
308
- const anchors = [...entry.anchors];
309
- entry.subscribers.forEach((subscriber) => subscriber(anchors, entry.error));
304
+ entry.subscribers.forEach((subscriber) => subscriber(entry.anchors, entry.error));
310
305
  }
311
306
  function refreshEntry(selector, entry) {
312
307
  var _a, _b, _c, _d;
@@ -330,12 +325,117 @@ function refreshAllEntries() {
330
325
  refreshEntry(selector, entry);
331
326
  });
332
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
+ }
333
432
  function ensureDocumentObserver() {
334
433
  if (documentObserver || typeof MutationObserver === 'undefined') {
335
434
  return;
336
435
  }
337
- documentObserver = new MutationObserver(() => {
338
- refreshAllEntries();
436
+ documentObserver = new MutationObserver((records) => {
437
+ const affectedIds = collectAffectedTooltipIds(records);
438
+ scheduleRefresh(affectedIds);
339
439
  });
340
440
  documentObserver.observe(document.body, {
341
441
  childList: true,
@@ -360,6 +460,7 @@ function subscribeAnchorSelector(selector, subscriber) {
360
460
  anchors: initialState.anchors,
361
461
  error: initialState.error,
362
462
  subscribers: new Set(),
463
+ tooltipId: extractTooltipId(selector),
363
464
  };
364
465
  registry.set(selector, entry);
365
466
  }
@@ -387,7 +488,7 @@ const getAnchorSelector = ({ id, anchorSelect, imperativeAnchorSelect, }) => {
387
488
  }
388
489
  return selector;
389
490
  };
390
- const useTooltipAnchors = ({ id, anchorSelect, imperativeAnchorSelect, activeAnchor, disableTooltip, onActiveAnchorRemoved, }) => {
491
+ const useTooltipAnchors = ({ id, anchorSelect, imperativeAnchorSelect, activeAnchor, disableTooltip, onActiveAnchorRemoved, trackAnchors, }) => {
391
492
  const [rawAnchorElements, setRawAnchorElements] = React.useState([]);
392
493
  const [selectorError, setSelectorError] = React.useState(null);
393
494
  const warnedSelectorRef = React.useRef(null);
@@ -403,9 +504,10 @@ const useTooltipAnchors = ({ id, anchorSelect, imperativeAnchorSelect, activeAnc
403
504
  catch (_a) {
404
505
  return false;
405
506
  }
406
- }, [activeAnchor, selector]);
507
+ // eslint-disable-next-line react-hooks/exhaustive-deps
508
+ }, [activeAnchor, selector, anchorElements]);
407
509
  React.useEffect(() => {
408
- if (!selector) {
510
+ if (!selector || !trackAnchors) {
409
511
  setRawAnchorElements([]);
410
512
  setSelectorError(null);
411
513
  return undefined;
@@ -414,7 +516,7 @@ const useTooltipAnchors = ({ id, anchorSelect, imperativeAnchorSelect, activeAnc
414
516
  setRawAnchorElements(anchors);
415
517
  setSelectorError(error);
416
518
  });
417
- }, [selector]);
519
+ }, [selector, trackAnchors]);
418
520
  React.useEffect(() => {
419
521
  if (!selectorError || warnedSelectorRef.current === selector) {
420
522
  return;
@@ -434,111 +536,81 @@ const useTooltipAnchors = ({ id, anchorSelect, imperativeAnchorSelect, activeAnc
434
536
  onActiveAnchorRemoved();
435
537
  }
436
538
  }, [activeAnchor, anchorElements, activeAnchorMatchesSelector, onActiveAnchorRemoved]);
437
- return anchorElements;
539
+ return {
540
+ anchorElements,
541
+ selector,
542
+ };
438
543
  };
439
544
 
440
- const useTooltipEvents = ({ activeAnchor, anchorElements, clickable, closeEvents, delayHide, delayShow, disableTooltip, float, globalCloseEvents, handleHideTooltipDelayed, handleShow, handleShowTooltipDelayed, handleTooltipPosition, hoveringTooltip, imperativeModeOnly, lastFloatPosition, openEvents, openOnClick, setActiveAnchor, show, tooltipHideDelayTimerRef, tooltipRef, tooltipShowDelayTimerRef, updateTooltipPosition, }) => {
441
- React.useEffect(() => {
442
- const resolveAnchorElement = (target) => {
443
- var _a;
444
- const targetElement = target;
445
- if (!(targetElement === null || targetElement === void 0 ? void 0 : targetElement.isConnected)) {
446
- return null;
447
- }
448
- return ((_a = anchorElements.find((anchor) => anchor === targetElement || anchor.contains(targetElement))) !== null && _a !== void 0 ? _a : null);
449
- };
450
- const handlePointerMove = (event) => {
451
- if (!event) {
452
- return;
453
- }
454
- if (!activeAnchor) {
455
- return;
456
- }
457
- const targetAnchor = resolveAnchorElement(event.target);
458
- if (targetAnchor !== activeAnchor) {
459
- return;
460
- }
461
- const mouseEvent = event;
462
- const mousePosition = {
463
- x: mouseEvent.clientX,
464
- y: mouseEvent.clientY,
465
- };
466
- handleTooltipPosition(mousePosition);
467
- // eslint-disable-next-line no-param-reassign
468
- lastFloatPosition.current = mousePosition;
469
- };
470
- const handleClickOutsideAnchors = (event) => {
471
- var _a;
472
- if (!show) {
473
- return;
474
- }
475
- const target = event.target;
476
- if (!target.isConnected) {
477
- return;
478
- }
479
- if ((_a = tooltipRef.current) === null || _a === void 0 ? void 0 : _a.contains(target)) {
480
- return;
481
- }
482
- if (activeAnchor === null || activeAnchor === void 0 ? void 0 : activeAnchor.contains(target)) {
483
- return;
484
- }
485
- if (anchorElements.some((anchor) => anchor === null || anchor === void 0 ? void 0 : anchor.contains(target))) {
486
- return;
487
- }
488
- handleShow(false);
489
- clearTimeoutRef(tooltipShowDelayTimerRef);
490
- };
491
- const handleShowTooltip = (anchor) => {
492
- if (!anchor) {
493
- return;
494
- }
495
- if (!anchor.isConnected) {
496
- setActiveAnchor(null);
497
- return;
498
- }
499
- if (disableTooltip === null || disableTooltip === void 0 ? void 0 : disableTooltip(anchor)) {
500
- return;
501
- }
502
- if (delayShow) {
503
- handleShowTooltipDelayed();
504
- }
505
- else {
506
- handleShow(true);
507
- }
508
- setActiveAnchor(anchor);
509
- if (tooltipHideDelayTimerRef.current) {
510
- clearTimeout(tooltipHideDelayTimerRef.current);
511
- }
512
- };
513
- const handleHideTooltip = () => {
514
- if (clickable) {
515
- handleHideTooltipDelayed(delayHide || 100);
516
- }
517
- else if (delayHide) {
518
- handleHideTooltipDelayed();
519
- }
520
- else {
521
- handleShow(false);
522
- }
523
- if (tooltipShowDelayTimerRef.current) {
524
- clearTimeout(tooltipShowDelayTimerRef.current);
525
- }
526
- };
527
- const internalDebouncedHandleShowTooltip = debounce(handleShowTooltip, 50);
528
- const internalDebouncedHandleHideTooltip = debounce(handleHideTooltip, 50);
529
- const debouncedHandleShowTooltip = (anchor) => {
530
- internalDebouncedHandleHideTooltip.cancel();
531
- internalDebouncedHandleShowTooltip(anchor);
532
- };
533
- const debouncedHandleHideTooltip = () => {
534
- internalDebouncedHandleShowTooltip.cancel();
535
- internalDebouncedHandleHideTooltip();
536
- };
537
- const handleScrollResize = () => {
538
- handleShow(false);
539
- };
540
- 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);
541
- const actualOpenEvents = openEvents
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
+
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, }) => {
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
542
614
  ? { ...openEvents }
543
615
  : {
544
616
  mouseenter: true,
@@ -548,13 +620,25 @@ const useTooltipEvents = ({ activeAnchor, anchorElements, clickable, closeEvents
548
620
  mousedown: false,
549
621
  };
550
622
  if (!openEvents && openOnClick) {
551
- Object.assign(actualOpenEvents, {
623
+ Object.assign(events, {
552
624
  mouseenter: false,
553
625
  focus: false,
554
626
  click: true,
555
627
  });
556
628
  }
557
- const actualCloseEvents = closeEvents
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
558
642
  ? { ...closeEvents }
559
643
  : {
560
644
  mouseleave: true,
@@ -564,12 +648,24 @@ const useTooltipEvents = ({ activeAnchor, anchorElements, clickable, closeEvents
564
648
  mouseup: false,
565
649
  };
566
650
  if (!closeEvents && openOnClick) {
567
- Object.assign(actualCloseEvents, {
651
+ Object.assign(events, {
568
652
  mouseleave: false,
569
653
  blur: false,
570
654
  });
571
655
  }
572
- const actualGlobalCloseEvents = globalCloseEvents
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
573
669
  ? { ...globalCloseEvents }
574
670
  : {
575
671
  escape: false,
@@ -578,108 +674,157 @@ const useTooltipEvents = ({ activeAnchor, anchorElements, clickable, closeEvents
578
674
  clickOutsideAnchor: hasClickEvent || false,
579
675
  };
580
676
  if (imperativeModeOnly) {
581
- Object.assign(actualOpenEvents, {
582
- mouseenter: false,
583
- focus: false,
584
- click: false,
585
- dblclick: false,
586
- mousedown: false,
587
- });
588
- Object.assign(actualCloseEvents, {
589
- mouseleave: false,
590
- blur: false,
591
- click: false,
592
- dblclick: false,
593
- mouseup: false,
594
- });
595
- Object.assign(actualGlobalCloseEvents, {
677
+ Object.assign(events, {
596
678
  escape: false,
597
679
  scroll: false,
598
680
  resize: false,
599
681
  clickOutsideAnchor: false,
600
682
  });
601
683
  }
602
- const tooltipElement = tooltipRef.current;
603
- const tooltipScrollParent = getScrollParent(tooltipRef.current);
604
- const anchorScrollParent = getScrollParent(activeAnchor);
605
- if (actualGlobalCloseEvents.scroll) {
606
- window.addEventListener('scroll', handleScrollResize);
607
- anchorScrollParent === null || anchorScrollParent === void 0 ? void 0 : anchorScrollParent.addEventListener('scroll', handleScrollResize);
608
- tooltipScrollParent === null || tooltipScrollParent === void 0 ? void 0 : tooltipScrollParent.addEventListener('scroll', handleScrollResize);
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;
609
709
  }
610
- let updateTooltipCleanup = null;
611
- if (actualGlobalCloseEvents.resize) {
612
- window.addEventListener('resize', handleScrollResize);
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
+ }
613
715
  }
614
- else if (activeAnchor && tooltipRef.current) {
615
- updateTooltipCleanup = dom.autoUpdate(activeAnchor, tooltipRef.current, updateTooltipPosition, {
616
- ancestorResize: true,
617
- elementResize: true,
618
- layoutShift: true,
619
- });
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
+ }
620
728
  }
621
- const handleEsc = (event) => {
622
- if (event.key !== 'Escape') {
623
- return;
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;
734
+ }
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);
624
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 {
625
775
  handleShow(false);
626
- };
627
- if (actualGlobalCloseEvents.escape) {
628
- window.addEventListener('keydown', handleEsc);
629
776
  }
630
- if (actualGlobalCloseEvents.clickOutsideAnchor) {
631
- window.addEventListener('click', handleClickOutsideAnchors);
777
+ if (tooltipShowDelayTimerRef.current) {
778
+ clearTimeout(tooltipShowDelayTimerRef.current);
632
779
  }
633
- const activeAnchorContainsTarget = (event) => Boolean((event === null || event === void 0 ? void 0 : event.target) && (activeAnchor === null || activeAnchor === void 0 ? void 0 : activeAnchor.contains(event.target)));
634
- const handleClickOpenTooltipAnchor = (event) => {
635
- var _a;
636
- const anchor = resolveAnchorElement((_a = event === null || event === void 0 ? void 0 : event.target) !== null && _a !== void 0 ? _a : null);
637
- if (!anchor) {
638
- return;
639
- }
640
- if (show && activeAnchor === anchor) {
641
- return;
642
- }
643
- handleShowTooltip(anchor);
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));
644
794
  };
645
- const handleClickCloseTooltipAnchor = (event) => {
646
- if (!show || !activeAnchorContainsTarget(event)) {
647
- return;
648
- }
649
- handleHideTooltip();
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();
650
803
  };
651
- const regularEvents = ['mouseover', 'mouseout', 'mouseenter', 'mouseleave', 'focus', 'blur'];
652
- const clickEvents = ['click', 'dblclick', 'mousedown', 'mouseup'];
653
- const delegatedEvents = [];
654
804
  const addDelegatedHoverOpenListener = () => {
655
- delegatedEvents.push({
656
- event: 'mouseover',
657
- listener: (event) => {
658
- const anchor = resolveAnchorElement(event.target);
659
- if (!anchor) {
660
- return;
661
- }
662
- const relatedAnchor = resolveAnchorElement(event.relatedTarget);
663
- if (relatedAnchor === anchor) {
664
- return;
665
- }
666
- debouncedHandleShowTooltip(anchor);
667
- },
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);
668
815
  });
669
816
  };
670
817
  const addDelegatedHoverCloseListener = () => {
671
- delegatedEvents.push({
672
- event: 'mouseout',
673
- listener: (event) => {
674
- if (!activeAnchorContainsTarget(event)) {
675
- return;
676
- }
677
- const relatedTarget = event.relatedTarget;
678
- if (activeAnchor === null || activeAnchor === void 0 ? void 0 : activeAnchor.contains(relatedTarget)) {
679
- return;
680
- }
681
- debouncedHandleHideTooltip();
682
- },
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();
683
828
  });
684
829
  };
685
830
  if (actualOpenEvents.mouseenter) {
@@ -695,37 +840,48 @@ const useTooltipEvents = ({ activeAnchor, anchorElements, clickable, closeEvents
695
840
  addDelegatedHoverCloseListener();
696
841
  }
697
842
  if (actualOpenEvents.focus) {
698
- delegatedEvents.push({
699
- event: 'focusin',
700
- listener: (event) => {
701
- debouncedHandleShowTooltip(resolveAnchorElement(event.target));
702
- },
843
+ addDelegatedListener('focusin', (event) => {
844
+ debouncedHandleShowTooltip(resolveAnchorElementRef.current(event.target));
703
845
  });
704
846
  }
705
847
  if (actualCloseEvents.blur) {
706
- delegatedEvents.push({
707
- event: 'focusout',
708
- listener: (event) => {
709
- if (!activeAnchorContainsTarget(event)) {
710
- return;
711
- }
712
- const relatedTarget = event.relatedTarget;
713
- if (activeAnchor === null || activeAnchor === void 0 ? void 0 : activeAnchor.contains(relatedTarget)) {
714
- return;
715
- }
716
- debouncedHandleHideTooltip();
717
- },
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();
718
858
  });
719
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
+ };
720
879
  Object.entries(actualOpenEvents).forEach(([event, enabled]) => {
721
880
  if (!enabled || regularEvents.includes(event)) {
722
881
  return;
723
882
  }
724
883
  if (clickEvents.includes(event)) {
725
- delegatedEvents.push({
726
- event,
727
- listener: handleClickOpenTooltipAnchor,
728
- });
884
+ addDelegatedListener(event, handleClickOpenTooltipAnchor);
729
885
  }
730
886
  });
731
887
  Object.entries(actualCloseEvents).forEach(([event, enabled]) => {
@@ -733,38 +889,111 @@ const useTooltipEvents = ({ activeAnchor, anchorElements, clickable, closeEvents
733
889
  return;
734
890
  }
735
891
  if (clickEvents.includes(event)) {
736
- delegatedEvents.push({
737
- event,
738
- listener: handleClickCloseTooltipAnchor,
739
- });
892
+ addDelegatedListener(event, handleClickCloseTooltipAnchor);
740
893
  }
741
894
  });
742
895
  if (float) {
743
- delegatedEvents.push({
744
- event: 'pointermove',
745
- listener: handlePointerMove,
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;
746
912
  });
747
913
  }
914
+ const tooltipElement = tooltipRef.current;
748
915
  const handleMouseOverTooltip = () => {
749
- // eslint-disable-next-line no-param-reassign
750
916
  hoveringTooltip.current = true;
751
917
  };
752
918
  const handleMouseOutTooltip = () => {
753
- // eslint-disable-next-line no-param-reassign
754
919
  hoveringTooltip.current = false;
755
- handleHideTooltip();
920
+ handleHideTooltipRef.current();
756
921
  };
757
922
  const addHoveringTooltipListeners = clickable && (actualCloseEvents.mouseout || actualCloseEvents.mouseleave);
758
923
  if (addHoveringTooltipListeners) {
759
924
  tooltipElement === null || tooltipElement === void 0 ? void 0 : tooltipElement.addEventListener('mouseover', handleMouseOverTooltip);
760
925
  tooltipElement === null || tooltipElement === void 0 ? void 0 : tooltipElement.addEventListener('mouseout', handleMouseOutTooltip);
761
926
  }
762
- delegatedEvents.forEach(({ event, listener }) => {
763
- document.addEventListener(event, listener);
764
- });
765
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);
766
991
  clearTimeoutRef(tooltipShowDelayTimerRef);
767
- clearTimeoutRef(tooltipHideDelayTimerRef);
992
+ };
993
+ if (actualGlobalCloseEvents.clickOutsideAnchor) {
994
+ window.addEventListener('click', handleClickOutsideAnchors);
995
+ }
996
+ return () => {
768
997
  if (actualGlobalCloseEvents.scroll) {
769
998
  window.removeEventListener('scroll', handleScrollResize);
770
999
  anchorScrollParent === null || anchorScrollParent === void 0 ? void 0 : anchorScrollParent.removeEventListener('scroll', handleScrollResize);
@@ -776,53 +1005,22 @@ const useTooltipEvents = ({ activeAnchor, anchorElements, clickable, closeEvents
776
1005
  if (updateTooltipCleanup) {
777
1006
  updateTooltipCleanup();
778
1007
  }
779
- if (actualGlobalCloseEvents.clickOutsideAnchor) {
780
- window.removeEventListener('click', handleClickOutsideAnchors);
781
- }
782
1008
  if (actualGlobalCloseEvents.escape) {
783
1009
  window.removeEventListener('keydown', handleEsc);
784
1010
  }
785
- if (addHoveringTooltipListeners) {
786
- tooltipElement === null || tooltipElement === void 0 ? void 0 : tooltipElement.removeEventListener('mouseover', handleMouseOverTooltip);
787
- tooltipElement === null || tooltipElement === void 0 ? void 0 : tooltipElement.removeEventListener('mouseout', handleMouseOutTooltip);
1011
+ if (actualGlobalCloseEvents.clickOutsideAnchor) {
1012
+ window.removeEventListener('click', handleClickOutsideAnchors);
788
1013
  }
789
- delegatedEvents.forEach(({ event, listener }) => {
790
- document.removeEventListener(event, listener);
791
- });
792
- internalDebouncedHandleShowTooltip.cancel();
793
- internalDebouncedHandleHideTooltip.cancel();
794
1014
  };
795
- }, [
796
- activeAnchor,
797
- anchorElements,
798
- clickable,
799
- closeEvents,
800
- delayHide,
801
- delayShow,
802
- disableTooltip,
803
- float,
804
- globalCloseEvents,
805
- handleHideTooltipDelayed,
806
- handleShow,
807
- handleShowTooltipDelayed,
808
- handleTooltipPosition,
809
- imperativeModeOnly,
810
- lastFloatPosition,
811
- openEvents,
812
- openOnClick,
813
- setActiveAnchor,
814
- show,
815
- tooltipHideDelayTimerRef,
816
- tooltipRef,
817
- tooltipShowDelayTimerRef,
818
- updateTooltipPosition,
819
- hoveringTooltip,
820
- ]);
1015
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1016
+ }, [actualGlobalCloseEvents, activeAnchor]);
821
1017
  };
822
1018
 
1019
+ // Shared across all tooltip instances — the CSS variable is on :root and never changes per-instance
1020
+ let globalTransitionShowDelay = null;
823
1021
  const Tooltip = ({
824
1022
  // props
825
- forwardRef, id, className, classNameArrow, variant = 'dark', portalRoot, anchorSelect, place = 'top', offset = 10, openOnClick = false, positionStrategy = 'absolute', middlewares, wrapper: WrapperElement, delayShow = 0, delayHide = 0, float = false, hidden = false, noArrow = false, clickable = false, openEvents, closeEvents, globalCloseEvents, imperativeModeOnly, style: externalStyles, position, afterShow, afterHide, disableTooltip,
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,
826
1024
  // props handled by controller
827
1025
  content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousActiveAnchor, activeAnchor, setActiveAnchor, border, opacity, arrowColor, arrowSize = 8, role = 'tooltip', }) => {
828
1026
  var _a;
@@ -830,6 +1028,7 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
830
1028
  const tooltipArrowRef = React.useRef(null);
831
1029
  const tooltipShowDelayTimerRef = React.useRef(null);
832
1030
  const tooltipHideDelayTimerRef = React.useRef(null);
1031
+ const tooltipAutoCloseTimerRef = React.useRef(null);
833
1032
  const missedTransitionTimerRef = React.useRef(null);
834
1033
  const [computedPosition, setComputedPosition] = React.useState({
835
1034
  tooltipStyles: {},
@@ -843,6 +1042,18 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
843
1042
  const lastFloatPosition = React.useRef(null);
844
1043
  const hoveringTooltip = React.useRef(false);
845
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
+ });
846
1057
  /**
847
1058
  * useLayoutEffect runs before useEffect,
848
1059
  * but should be used carefully because of caveats
@@ -903,7 +1114,6 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
903
1114
  else {
904
1115
  removeAriaDescribedBy(activeAnchor);
905
1116
  }
906
- // eslint-disable-next-line consistent-return
907
1117
  return () => {
908
1118
  // cleanup aria-describedby when the tooltip is closed
909
1119
  removeAriaDescribedBy(activeAnchor);
@@ -941,8 +1151,11 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
941
1151
  /**
942
1152
  * see `onTransitionEnd` on tooltip wrapper
943
1153
  */
944
- const style = getComputedStyle(document.body);
945
- const transitionShowDelay = cssTimeToMs(style.getPropertyValue('--rt-transition-show-delay'));
1154
+ if (globalTransitionShowDelay === null) {
1155
+ const style = getComputedStyle(document.body);
1156
+ globalTransitionShowDelay = cssTimeToMs(style.getPropertyValue('--rt-transition-show-delay'));
1157
+ }
1158
+ const transitionShowDelay = globalTransitionShowDelay;
946
1159
  missedTransitionTimerRef.current = setTimeout(() => {
947
1160
  /**
948
1161
  * if the tooltip switches from `show === true` to `show === false` too fast
@@ -955,13 +1168,44 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
955
1168
  }, transitionShowDelay + 25);
956
1169
  }
957
1170
  }, [afterHide, afterShow, show]);
1171
+ React.useEffect(() => {
1172
+ clearTimeoutRef(tooltipAutoCloseTimerRef);
1173
+ if (!show || !autoClose || autoClose <= 0) {
1174
+ return () => {
1175
+ clearTimeoutRef(tooltipAutoCloseTimerRef);
1176
+ };
1177
+ }
1178
+ tooltipAutoCloseTimerRef.current = setTimeout(() => {
1179
+ handleShow(false);
1180
+ }, autoClose);
1181
+ return () => {
1182
+ clearTimeoutRef(tooltipAutoCloseTimerRef);
1183
+ };
1184
+ }, [activeAnchor, autoClose, handleShow, show]);
958
1185
  const handleComputedPosition = React.useCallback((newComputedPosition) => {
959
1186
  if (!mounted.current) {
960
1187
  return;
961
1188
  }
962
- setComputedPosition((oldComputedPosition) => deepEqual(oldComputedPosition, newComputedPosition)
963
- ? oldComputedPosition
964
- : newComputedPosition);
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
+ });
965
1209
  }, []);
966
1210
  const handleShowTooltipDelayed = React.useCallback((delay = delayShow) => {
967
1211
  if (tooltipShowDelayTimerRef.current) {
@@ -989,24 +1233,20 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
989
1233
  }, [delayHide, handleShow]);
990
1234
  const handleTooltipPosition = React.useCallback(({ x, y }) => {
991
1235
  var _a;
992
- const virtualElement = {
993
- getBoundingClientRect() {
994
- return {
995
- x,
996
- y,
997
- width: 0,
998
- height: 0,
999
- top: y,
1000
- left: x,
1001
- right: x,
1002
- bottom: y,
1003
- };
1004
- },
1005
- };
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
+ });
1006
1246
  computeTooltipPosition({
1007
1247
  place: (_a = imperativeOptions === null || imperativeOptions === void 0 ? void 0 : imperativeOptions.place) !== null && _a !== void 0 ? _a : place,
1008
1248
  offset,
1009
- elementReference: virtualElement,
1249
+ elementReference: virtualElementRef.current,
1010
1250
  tooltipReference: tooltipRef.current,
1011
1251
  tooltipArrowReference: tooltipArrowRef.current,
1012
1252
  strategy: positionStrategy,
@@ -1089,18 +1329,26 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
1089
1329
  setActiveAnchor(null);
1090
1330
  clearTimeoutRef(tooltipShowDelayTimerRef);
1091
1331
  clearTimeoutRef(tooltipHideDelayTimerRef);
1332
+ clearTimeoutRef(tooltipAutoCloseTimerRef);
1092
1333
  }, [handleShow, setActiveAnchor]);
1093
- const anchorElements = useTooltipAnchors({
1334
+ const shouldTrackAnchors = rendered ||
1335
+ defaultIsOpen ||
1336
+ Boolean(isOpen) ||
1337
+ Boolean(activeAnchor) ||
1338
+ Boolean(imperativeOptions === null || imperativeOptions === void 0 ? void 0 : imperativeOptions.anchorSelect);
1339
+ const { anchorElements, selector: anchorSelector } = useTooltipAnchors({
1094
1340
  id,
1095
1341
  anchorSelect,
1096
1342
  imperativeAnchorSelect: imperativeOptions === null || imperativeOptions === void 0 ? void 0 : imperativeOptions.anchorSelect,
1097
1343
  activeAnchor,
1098
1344
  disableTooltip,
1099
1345
  onActiveAnchorRemoved: handleActiveAnchorRemoved,
1346
+ trackAnchors: shouldTrackAnchors,
1100
1347
  });
1101
1348
  useTooltipEvents({
1102
1349
  activeAnchor,
1103
1350
  anchorElements,
1351
+ anchorSelector,
1104
1352
  clickable,
1105
1353
  closeEvents,
1106
1354
  delayHide,
@@ -1124,11 +1372,16 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
1124
1372
  tooltipShowDelayTimerRef,
1125
1373
  updateTooltipPosition,
1126
1374
  });
1375
+ const updateTooltipPositionRef = React.useRef(updateTooltipPosition);
1376
+ updateTooltipPositionRef.current = updateTooltipPosition;
1127
1377
  React.useEffect(() => {
1378
+ if (!rendered) {
1379
+ return;
1380
+ }
1128
1381
  updateTooltipPosition();
1129
- }, [updateTooltipPosition]);
1382
+ }, [rendered, updateTooltipPosition]);
1130
1383
  React.useEffect(() => {
1131
- if (!(contentWrapperRef === null || contentWrapperRef === void 0 ? void 0 : contentWrapperRef.current)) {
1384
+ if (!rendered || !(contentWrapperRef === null || contentWrapperRef === void 0 ? void 0 : contentWrapperRef.current)) {
1132
1385
  return () => null;
1133
1386
  }
1134
1387
  let timeoutId = null;
@@ -1139,7 +1392,7 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
1139
1392
  }
1140
1393
  timeoutId = setTimeout(() => {
1141
1394
  if (mounted.current) {
1142
- updateTooltipPosition();
1395
+ updateTooltipPositionRef.current();
1143
1396
  }
1144
1397
  timeoutId = null;
1145
1398
  }, 0);
@@ -1151,9 +1404,13 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
1151
1404
  clearTimeout(timeoutId);
1152
1405
  }
1153
1406
  };
1154
- }, [content, contentWrapperRef, updateTooltipPosition]);
1407
+ }, [content, contentWrapperRef, rendered]);
1155
1408
  React.useEffect(() => {
1156
1409
  var _a;
1410
+ const shouldResolveInitialActiveAnchor = rendered || defaultIsOpen || Boolean(isOpen);
1411
+ if (!shouldResolveInitialActiveAnchor) {
1412
+ return;
1413
+ }
1157
1414
  const activeAnchorMatchesImperativeSelector = (() => {
1158
1415
  if (!activeAnchor || !(imperativeOptions === null || imperativeOptions === void 0 ? void 0 : imperativeOptions.anchorSelect)) {
1159
1416
  return false;
@@ -1176,7 +1433,15 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
1176
1433
  }
1177
1434
  setActiveAnchor((_a = anchorElements[0]) !== null && _a !== void 0 ? _a : null);
1178
1435
  }
1179
- }, [anchorElements, activeAnchor, imperativeOptions === null || imperativeOptions === void 0 ? void 0 : imperativeOptions.anchorSelect, setActiveAnchor]);
1436
+ }, [
1437
+ activeAnchor,
1438
+ anchorElements,
1439
+ defaultIsOpen,
1440
+ imperativeOptions === null || imperativeOptions === void 0 ? void 0 : imperativeOptions.anchorSelect,
1441
+ isOpen,
1442
+ rendered,
1443
+ setActiveAnchor,
1444
+ ]);
1180
1445
  React.useEffect(() => {
1181
1446
  if (defaultIsOpen) {
1182
1447
  handleShow(true);
@@ -1184,6 +1449,7 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
1184
1449
  return () => {
1185
1450
  clearTimeoutRef(tooltipShowDelayTimerRef);
1186
1451
  clearTimeoutRef(tooltipHideDelayTimerRef);
1452
+ clearTimeoutRef(tooltipAutoCloseTimerRef);
1187
1453
  clearTimeoutRef(missedTransitionTimerRef);
1188
1454
  };
1189
1455
  }, [defaultIsOpen, handleShow]);
@@ -1199,7 +1465,20 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
1199
1465
  }, [delayShow, handleShowTooltipDelayed]);
1200
1466
  const actualContent = (_a = imperativeOptions === null || imperativeOptions === void 0 ? void 0 : imperativeOptions.content) !== null && _a !== void 0 ? _a : content;
1201
1467
  const hasContent = actualContent !== null && actualContent !== undefined;
1202
- const canShow = show && Object.keys(computedPosition.tooltipStyles).length > 0;
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]);
1203
1482
  React.useImperativeHandle(forwardRef, () => ({
1204
1483
  open: (options) => {
1205
1484
  let imperativeAnchor = null;
@@ -1242,6 +1521,7 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
1242
1521
  // Final cleanup to ensure no memory leaks
1243
1522
  clearTimeoutRef(tooltipShowDelayTimerRef);
1244
1523
  clearTimeoutRef(tooltipHideDelayTimerRef);
1524
+ clearTimeoutRef(tooltipAutoCloseTimerRef);
1245
1525
  clearTimeoutRef(missedTransitionTimerRef);
1246
1526
  };
1247
1527
  }, []);
@@ -1253,19 +1533,9 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
1253
1533
  setRendered(false);
1254
1534
  setImperativeOptions(null);
1255
1535
  afterHide === null || afterHide === void 0 ? void 0 : afterHide();
1256
- }, style: {
1257
- ...externalStyles,
1258
- ...computedPosition.tooltipStyles,
1259
- opacity: opacity !== undefined && canShow ? opacity : undefined,
1260
- }, ref: tooltipRef },
1536
+ }, style: tooltipStyle, ref: tooltipRef },
1261
1537
  React.createElement(WrapperElement, { className: clsx('react-tooltip-content-wrapper', coreStyles['content'], styles['content']) }, actualContent),
1262
- React.createElement(WrapperElement, { className: clsx('react-tooltip-arrow', coreStyles['arrow'], styles['arrow'], classNameArrow, noArrow && coreStyles['noArrow']), style: {
1263
- ...computedPosition.tooltipArrowStyles,
1264
- background: arrowColor
1265
- ? `linear-gradient(to right bottom, transparent 50%, ${arrowColor} 50%)`
1266
- : undefined,
1267
- '--rt-arrow-size': `${arrowSize}px`,
1268
- }, 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;
1269
1539
  if (!tooltipNode) {
1270
1540
  return null;
1271
1541
  }
@@ -1276,12 +1546,82 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, previousAc
1276
1546
  };
1277
1547
  var Tooltip$1 = React.memo(Tooltip);
1278
1548
 
1279
- 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, 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) => {
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
+
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) => {
1280
1612
  var _a, _b, _c, _d, _e, _f, _g, _h;
1281
1613
  const [activeAnchor, setActiveAnchor] = React.useState(null);
1282
1614
  const [anchorDataAttributes, setAnchorDataAttributes] = React.useState({});
1283
1615
  const previousActiveAnchorRef = React.useRef(null);
1284
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
+ }, []);
1285
1625
  /* c8 ignore start */
1286
1626
  const getDataAttributesFromAnchorElement = (elementReference) => {
1287
1627
  const dataAttributes = elementReference === null || elementReference === void 0 ? void 0 : elementReference.getAttributeNames().reduce((acc, name) => {
@@ -1313,37 +1653,24 @@ const TooltipController = React.forwardRef(({ id, anchorSelect, content, render,
1313
1653
  // eslint-disable-next-line react-hooks/exhaustive-deps
1314
1654
  }, []);
1315
1655
  React.useEffect(() => {
1316
- const observerCallback = (mutationList) => {
1317
- mutationList.forEach((mutation) => {
1318
- var _a;
1319
- if (!activeAnchor ||
1320
- mutation.type !== 'attributes' ||
1321
- !((_a = mutation.attributeName) === null || _a === void 0 ? void 0 : _a.startsWith('data-tooltip-'))) {
1322
- return;
1323
- }
1324
- // make sure to get all set attributes, since all unset attributes are reset
1325
- const dataAttributes = getDataAttributesFromAnchorElement(activeAnchor);
1326
- setAnchorDataAttributes(dataAttributes);
1327
- });
1328
- };
1329
- // Create an observer instance linked to the callback function
1330
- const observer = new MutationObserver(observerCallback);
1331
- // do not check for subtree and childrens, we only want to know attribute changes
1332
- // to stay watching `data-attributes-*` from anchor element
1333
- const observerConfig = { attributes: true, childList: false, subtree: false };
1334
- if (activeAnchor) {
1335
- const dataAttributes = getDataAttributesFromAnchorElement(activeAnchor);
1336
- setAnchorDataAttributes(dataAttributes);
1337
- // Start observing the target node for configured mutations
1338
- observer.observe(activeAnchor, observerConfig);
1339
- }
1340
- else {
1656
+ if (!activeAnchor) {
1341
1657
  setAnchorDataAttributes({});
1658
+ return () => { };
1342
1659
  }
1343
- return () => {
1344
- // Remove the observer when the tooltip is destroyed
1345
- observer.disconnect();
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;
1667
+ }
1668
+ return attrs;
1669
+ });
1346
1670
  };
1671
+ updateAttributes(activeAnchor);
1672
+ const unsubscribe = observeAnchorAttributes(activeAnchor, updateAttributes);
1673
+ return unsubscribe;
1347
1674
  }, [activeAnchor, anchorSelect]);
1348
1675
  React.useEffect(() => {
1349
1676
  /* c8 ignore start */
@@ -1367,6 +1694,9 @@ const TooltipController = React.forwardRef(({ id, anchorSelect, content, render,
1367
1694
  const tooltipDelayHide = anchorDataAttributes['delay-hide'] == null
1368
1695
  ? delayHide
1369
1696
  : Number(anchorDataAttributes['delay-hide']);
1697
+ const tooltipAutoClose = anchorDataAttributes['auto-close'] == null
1698
+ ? autoClose
1699
+ : Number(anchorDataAttributes['auto-close']);
1370
1700
  const tooltipFloat = anchorDataAttributes.float == null ? float : anchorDataAttributes.float === 'true';
1371
1701
  const tooltipHidden = anchorDataAttributes.hidden == null ? hidden : anchorDataAttributes.hidden === 'true';
1372
1702
  const tooltipClassName = (_f = anchorDataAttributes['class-name']) !== null && _f !== void 0 ? _f : null;
@@ -1398,6 +1728,7 @@ const TooltipController = React.forwardRef(({ id, anchorSelect, content, render,
1398
1728
  middlewares,
1399
1729
  delayShow: tooltipDelayShow,
1400
1730
  delayHide: tooltipDelayHide,
1731
+ autoClose: tooltipAutoClose,
1401
1732
  float: tooltipFloat,
1402
1733
  hidden: tooltipHidden,
1403
1734
  noArrow,
@@ -1420,19 +1751,12 @@ const TooltipController = React.forwardRef(({ id, anchorSelect, content, render,
1420
1751
  disableTooltip,
1421
1752
  activeAnchor,
1422
1753
  previousActiveAnchor: previousActiveAnchorRef.current,
1423
- setActiveAnchor: (anchor) => {
1424
- setActiveAnchor((prev) => {
1425
- if (!(anchor === null || anchor === void 0 ? void 0 : anchor.isSameNode(prev))) {
1426
- previousActiveAnchorRef.current = prev;
1427
- }
1428
- return anchor;
1429
- });
1430
- },
1754
+ setActiveAnchor: handleSetActiveAnchor,
1431
1755
  role,
1432
1756
  };
1433
1757
  return React.createElement(Tooltip$1, { ...props });
1434
1758
  });
1435
- var TooltipController$1 = React.memo(TooltipController);
1759
+ var TooltipController_default = React.memo(TooltipController);
1436
1760
 
1437
1761
  // those content will be replaced in build time with the `react-tooltip.css` builded content
1438
1762
  const TooltipCoreStyles = `:root {
@@ -1454,7 +1778,6 @@ const TooltipCoreStyles = `:root {
1454
1778
  left: 0;
1455
1779
  pointer-events: none;
1456
1780
  opacity: 0;
1457
- will-change: opacity;
1458
1781
  }
1459
1782
 
1460
1783
  .core-styles-module_fixed__pcSol {
@@ -1485,11 +1808,13 @@ const TooltipCoreStyles = `:root {
1485
1808
  .core-styles-module_show__Nt9eE {
1486
1809
  opacity: var(--rt-opacity);
1487
1810
  transition: opacity var(--rt-transition-show-delay) ease-out;
1811
+ will-change: opacity;
1488
1812
  }
1489
1813
 
1490
1814
  .core-styles-module_closing__sGnxF {
1491
1815
  opacity: 0;
1492
1816
  transition: opacity var(--rt-transition-closing-delay) ease-in;
1817
+ will-change: opacity;
1493
1818
  }
1494
1819
 
1495
1820
  `;
@@ -1570,5 +1895,5 @@ if (typeof window !== 'undefined') {
1570
1895
  }));
1571
1896
  }
1572
1897
 
1573
- exports.Tooltip = TooltipController$1;
1898
+ exports.Tooltip = TooltipController_default;
1574
1899
  //# sourceMappingURL=react-tooltip.cjs.map