react-tooltip 5.26.4 → 6.0.0-beta.1179.rc.1

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.
@@ -5,9 +5,9 @@
5
5
  * @copyright ReactTooltip Team
6
6
  * @license MIT
7
7
  */
8
- import React, { useLayoutEffect, useEffect, createContext, useState, useCallback, useMemo, useContext, useRef, useImperativeHandle } from 'react';
8
+ import React, { useLayoutEffect, useEffect, useRef, useState, useCallback, useImperativeHandle } from 'react';
9
9
  import { arrow, computePosition, offset, flip, shift, autoUpdate } from '@floating-ui/dom';
10
- import classNames from 'classnames';
10
+ import clsx from 'clsx';
11
11
 
12
12
  // This is the ID for the core styles of ReactTooltip
13
13
  const REACT_TOOLTIP_CORE_STYLES_ID = 'react-tooltip-core-styles';
@@ -73,28 +73,6 @@ function injectStyle({ css, id = REACT_TOOLTIP_BASE_STYLES_ID, type = 'base', re
73
73
  }
74
74
  injected[type] = true;
75
75
  }
76
- /**
77
- * @deprecated Use the `disableStyleInjection` tooltip prop instead.
78
- * See https://react-tooltip.com/docs/examples/styling#disabling-reacttooltip-css
79
- */
80
- function removeStyle({ type = 'base', id = REACT_TOOLTIP_BASE_STYLES_ID, } = {}) {
81
- if (!injected[type]) {
82
- return;
83
- }
84
- if (type === 'core') {
85
- // eslint-disable-next-line no-param-reassign
86
- id = REACT_TOOLTIP_CORE_STYLES_ID;
87
- }
88
- const style = document.getElementById(id);
89
- if ((style === null || style === void 0 ? void 0 : style.tagName) === 'style') {
90
- style === null || style === void 0 ? void 0 : style.remove();
91
- }
92
- else {
93
- // eslint-disable-next-line no-console
94
- console.warn(`[react-tooltip] Failed to remove 'style' element with id '${id}'. Call \`injectStyle()\` first`);
95
- }
96
- injected[type] = false;
97
- }
98
76
 
99
77
  const computeTooltipPosition = async ({ elementReference = null, tooltipReference = null, tooltipArrowReference = null, place = 'top', offset: offsetValue = 10, strategy = 'absolute', middlewares = [
100
78
  offset(Number(offsetValue)),
@@ -178,7 +156,7 @@ const cssSupports = (property, value) => {
178
156
  };
179
157
 
180
158
  const cssTimeToMs = (time) => {
181
- const match = time.match(/^([\d.]+)(ms|s)$/);
159
+ const match = time.match(/^([\d.]+)(m?s)$/);
182
160
  if (!match) {
183
161
  return 0;
184
162
  }
@@ -198,11 +176,8 @@ const debounce = (func, wait, immediate) => {
198
176
  const debounced = function debounced(...args) {
199
177
  const later = () => {
200
178
  timeout = null;
201
- if (!immediate) {
202
- func.apply(this, args);
203
- }
204
179
  };
205
- if (immediate && !timeout) {
180
+ if (!timeout) {
206
181
  /**
207
182
  * there's no need to clear the timeout
208
183
  * since we expect it to resolve and set `timeout = null`
@@ -210,12 +185,6 @@ const debounce = (func, wait, immediate) => {
210
185
  func.apply(this, args);
211
186
  timeout = setTimeout(later, wait);
212
187
  }
213
- if (!immediate) {
214
- if (timeout) {
215
- clearTimeout(timeout);
216
- }
217
- timeout = setTimeout(later, wait);
218
- }
219
188
  };
220
189
  debounced.cancel = () => {
221
190
  /* c8 ignore start */
@@ -282,111 +251,13 @@ const getScrollParent = (node) => {
282
251
 
283
252
  const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
284
253
 
285
- const DEFAULT_TOOLTIP_ID = 'DEFAULT_TOOLTIP_ID';
286
- const DEFAULT_CONTEXT_DATA = {
287
- anchorRefs: new Set(),
288
- activeAnchor: { current: null },
289
- attach: () => {
290
- /* attach anchor element */
291
- },
292
- detach: () => {
293
- /* detach anchor element */
294
- },
295
- setActiveAnchor: () => {
296
- /* set active anchor */
297
- },
298
- };
299
- const DEFAULT_CONTEXT_DATA_WRAPPER = {
300
- getTooltipData: () => DEFAULT_CONTEXT_DATA,
301
- };
302
- const TooltipContext = createContext(DEFAULT_CONTEXT_DATA_WRAPPER);
303
- /**
304
- * @deprecated Use the `data-tooltip-id` attribute, or the `anchorSelect` prop instead.
305
- * See https://react-tooltip.com/docs/getting-started
306
- */
307
- const TooltipProvider = ({ children }) => {
308
- const [anchorRefMap, setAnchorRefMap] = useState({
309
- [DEFAULT_TOOLTIP_ID]: new Set(),
310
- });
311
- const [activeAnchorMap, setActiveAnchorMap] = useState({
312
- [DEFAULT_TOOLTIP_ID]: { current: null },
313
- });
314
- const attach = (tooltipId, ...refs) => {
315
- setAnchorRefMap((oldMap) => {
316
- var _a;
317
- const tooltipRefs = (_a = oldMap[tooltipId]) !== null && _a !== void 0 ? _a : new Set();
318
- refs.forEach((ref) => tooltipRefs.add(ref));
319
- // create new object to trigger re-render
320
- return { ...oldMap, [tooltipId]: new Set(tooltipRefs) };
321
- });
322
- };
323
- const detach = (tooltipId, ...refs) => {
324
- setAnchorRefMap((oldMap) => {
325
- const tooltipRefs = oldMap[tooltipId];
326
- if (!tooltipRefs) {
327
- // tooltip not found
328
- // maybe thow error?
329
- return oldMap;
330
- }
331
- refs.forEach((ref) => tooltipRefs.delete(ref));
332
- // create new object to trigger re-render
333
- return { ...oldMap };
334
- });
335
- };
336
- const setActiveAnchor = (tooltipId, ref) => {
337
- setActiveAnchorMap((oldMap) => {
338
- var _a;
339
- if (((_a = oldMap[tooltipId]) === null || _a === void 0 ? void 0 : _a.current) === ref.current) {
340
- return oldMap;
341
- }
342
- // create new object to trigger re-render
343
- return { ...oldMap, [tooltipId]: ref };
344
- });
345
- };
346
- const getTooltipData = useCallback((tooltipId = DEFAULT_TOOLTIP_ID) => {
347
- var _a, _b;
348
- return ({
349
- anchorRefs: (_a = anchorRefMap[tooltipId]) !== null && _a !== void 0 ? _a : new Set(),
350
- activeAnchor: (_b = activeAnchorMap[tooltipId]) !== null && _b !== void 0 ? _b : { current: null },
351
- attach: (...refs) => attach(tooltipId, ...refs),
352
- detach: (...refs) => detach(tooltipId, ...refs),
353
- setActiveAnchor: (ref) => setActiveAnchor(tooltipId, ref),
354
- });
355
- }, [anchorRefMap, activeAnchorMap, attach, detach]);
356
- const context = useMemo(() => {
357
- return {
358
- getTooltipData,
359
- };
360
- }, [getTooltipData]);
361
- return React.createElement(TooltipContext.Provider, { value: context }, children);
362
- };
363
- function useTooltip(tooltipId = DEFAULT_TOOLTIP_ID) {
364
- return useContext(TooltipContext).getTooltipData(tooltipId);
365
- }
366
-
367
- /**
368
- * @deprecated Use the `data-tooltip-id` attribute, or the `anchorSelect` prop instead.
369
- * See https://react-tooltip.com/docs/getting-started
370
- */
371
- const TooltipWrapper = ({ tooltipId, children, className, place, content, html, variant, offset, wrapper, events, positionStrategy, delayShow, delayHide, }) => {
372
- const { attach, detach } = useTooltip(tooltipId);
373
- const anchorRef = useRef(null);
374
- useEffect(() => {
375
- attach(anchorRef);
376
- return () => {
377
- detach(anchorRef);
378
- };
379
- }, []);
380
- return (React.createElement("span", { ref: anchorRef, className: classNames('react-tooltip-wrapper', className), "data-tooltip-place": place, "data-tooltip-content": content, "data-tooltip-html": html, "data-tooltip-variant": variant, "data-tooltip-offset": offset, "data-tooltip-wrapper": wrapper, "data-tooltip-events": events, "data-tooltip-position-strategy": positionStrategy, "data-tooltip-delay-show": delayShow, "data-tooltip-delay-hide": delayHide }, children));
381
- };
382
-
383
254
  var coreStyles = {"tooltip":"core-styles-module_tooltip__3vRRp","fixed":"core-styles-module_fixed__pcSol","arrow":"core-styles-module_arrow__cvMwQ","noArrow":"core-styles-module_noArrow__xock6","clickable":"core-styles-module_clickable__ZuTTB","show":"core-styles-module_show__Nt9eE","closing":"core-styles-module_closing__sGnxF"};
384
255
 
385
256
  var styles = {"tooltip":"styles-module_tooltip__mnnfp","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"};
386
257
 
387
258
  const Tooltip = ({
388
259
  // props
389
- forwardRef, id, className, classNameArrow, variant = 'dark', anchorId, anchorSelect, place = 'top', offset = 10, events = ['hover'], openOnClick = false, positionStrategy = 'absolute', middlewares, wrapper: WrapperElement, delayShow = 0, delayHide = 0, float = false, hidden = false, noArrow = false, clickable = false, closeOnEsc = false, closeOnScroll = false, closeOnResize = false, openEvents, closeEvents, globalCloseEvents, imperativeModeOnly, style: externalStyles, position, afterShow, afterHide,
260
+ forwardRef, id, className, classNameArrow, variant = 'dark', 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,
390
261
  // props handled by controller
391
262
  content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, activeAnchor, setActiveAnchor, border, opacity, arrowColor, role = 'tooltip', }) => {
392
263
  var _a;
@@ -405,79 +276,9 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, activeAnch
405
276
  const [imperativeOptions, setImperativeOptions] = useState(null);
406
277
  const wasShowing = useRef(false);
407
278
  const lastFloatPosition = useRef(null);
408
- /**
409
- * @todo Remove this in a future version (provider/wrapper method is deprecated)
410
- */
411
- const { anchorRefs, setActiveAnchor: setProviderActiveAnchor } = useTooltip(id);
412
279
  const hoveringTooltip = useRef(false);
413
- const [anchorsBySelect, setAnchorsBySelect] = useState([]);
280
+ const [anchorElements, setAnchorElements] = useState([]);
414
281
  const mounted = useRef(false);
415
- /**
416
- * @todo Update when deprecated stuff gets removed.
417
- */
418
- const shouldOpenOnClick = openOnClick || events.includes('click');
419
- const hasClickEvent = shouldOpenOnClick || (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);
420
- const actualOpenEvents = openEvents
421
- ? { ...openEvents }
422
- : {
423
- mouseenter: true,
424
- focus: true,
425
- click: false,
426
- dblclick: false,
427
- mousedown: false,
428
- };
429
- if (!openEvents && shouldOpenOnClick) {
430
- Object.assign(actualOpenEvents, {
431
- mouseenter: false,
432
- focus: false,
433
- click: true,
434
- });
435
- }
436
- const actualCloseEvents = closeEvents
437
- ? { ...closeEvents }
438
- : {
439
- mouseleave: true,
440
- blur: true,
441
- click: false,
442
- dblclick: false,
443
- mouseup: false,
444
- };
445
- if (!closeEvents && shouldOpenOnClick) {
446
- Object.assign(actualCloseEvents, {
447
- mouseleave: false,
448
- blur: false,
449
- });
450
- }
451
- const actualGlobalCloseEvents = globalCloseEvents
452
- ? { ...globalCloseEvents }
453
- : {
454
- escape: closeOnEsc || false,
455
- scroll: closeOnScroll || false,
456
- resize: closeOnResize || false,
457
- clickOutsideAnchor: hasClickEvent || false,
458
- };
459
- if (imperativeModeOnly) {
460
- Object.assign(actualOpenEvents, {
461
- mouseenter: false,
462
- focus: false,
463
- click: false,
464
- dblclick: false,
465
- mousedown: false,
466
- });
467
- Object.assign(actualCloseEvents, {
468
- mouseleave: false,
469
- blur: false,
470
- click: false,
471
- dblclick: false,
472
- mouseup: false,
473
- });
474
- Object.assign(actualGlobalCloseEvents, {
475
- escape: false,
476
- scroll: false,
477
- resize: false,
478
- clickOutsideAnchor: false,
479
- });
480
- }
481
282
  /**
482
283
  * useLayoutEffect runs before useEffect,
483
284
  * but should be used carefully because of caveats
@@ -489,7 +290,7 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, activeAnch
489
290
  mounted.current = false;
490
291
  };
491
292
  }, []);
492
- const handleShow = (value) => {
293
+ const handleShow = useCallback((value) => {
493
294
  if (!mounted.current) {
494
295
  return;
495
296
  }
@@ -509,7 +310,7 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, activeAnch
509
310
  setShow(value);
510
311
  }
511
312
  }, 10);
512
- };
313
+ }, [isOpen, setIsOpen]);
513
314
  /**
514
315
  * this replicates the effect from `handleShow()`
515
316
  * when `isOpen` is changed from outside
@@ -556,13 +357,13 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, activeAnch
556
357
  // +25ms just to make sure `onTransitionEnd` (if it gets fired) has time to run
557
358
  }, transitionShowDelay + 25);
558
359
  }
559
- }, [show]);
360
+ }, [afterHide, afterShow, show]);
560
361
  const handleComputedPosition = (newComputedPosition) => {
561
362
  setComputedPosition((oldComputedPosition) => deepEqual(oldComputedPosition, newComputedPosition)
562
363
  ? oldComputedPosition
563
364
  : newComputedPosition);
564
365
  };
565
- const handleShowTooltipDelayed = (delay = delayShow) => {
366
+ const handleShowTooltipDelayed = useCallback((delay = delayShow) => {
566
367
  if (tooltipShowDelayTimerRef.current) {
567
368
  clearTimeout(tooltipShowDelayTimerRef.current);
568
369
  }
@@ -574,8 +375,8 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, activeAnch
574
375
  tooltipShowDelayTimerRef.current = setTimeout(() => {
575
376
  handleShow(true);
576
377
  }, delay);
577
- };
578
- const handleHideTooltipDelayed = (delay = delayHide) => {
378
+ }, [delayShow, handleShow, rendered]);
379
+ const handleHideTooltipDelayed = useCallback((delay = delayHide) => {
579
380
  if (tooltipHideDelayTimerRef.current) {
580
381
  clearTimeout(tooltipHideDelayTimerRef.current);
581
382
  }
@@ -585,50 +386,8 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, activeAnch
585
386
  }
586
387
  handleShow(false);
587
388
  }, delay);
588
- };
589
- const handleShowTooltip = (event) => {
590
- var _a;
591
- if (!event) {
592
- return;
593
- }
594
- const target = ((_a = event.currentTarget) !== null && _a !== void 0 ? _a : event.target);
595
- if (!(target === null || target === void 0 ? void 0 : target.isConnected)) {
596
- /**
597
- * this happens when the target is removed from the DOM
598
- * at the same time the tooltip gets triggered
599
- */
600
- setActiveAnchor(null);
601
- setProviderActiveAnchor({ current: null });
602
- return;
603
- }
604
- if (delayShow) {
605
- handleShowTooltipDelayed();
606
- }
607
- else {
608
- handleShow(true);
609
- }
610
- setActiveAnchor(target);
611
- setProviderActiveAnchor({ current: target });
612
- if (tooltipHideDelayTimerRef.current) {
613
- clearTimeout(tooltipHideDelayTimerRef.current);
614
- }
615
- };
616
- const handleHideTooltip = () => {
617
- if (clickable) {
618
- // allow time for the mouse to reach the tooltip, in case there's a gap
619
- handleHideTooltipDelayed(delayHide || 100);
620
- }
621
- else if (delayHide) {
622
- handleHideTooltipDelayed();
623
- }
624
- else {
625
- handleShow(false);
626
- }
627
- if (tooltipShowDelayTimerRef.current) {
628
- clearTimeout(tooltipShowDelayTimerRef.current);
629
- }
630
- };
631
- const handleTooltipPosition = ({ x, y }) => {
389
+ }, [delayHide, handleShow]);
390
+ const handleTooltipPosition = useCallback(({ x, y }) => {
632
391
  var _a;
633
392
  const virtualElement = {
634
393
  getBoundingClientRect() {
@@ -656,58 +415,7 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, activeAnch
656
415
  }).then((computedStylesData) => {
657
416
  handleComputedPosition(computedStylesData);
658
417
  });
659
- };
660
- const handlePointerMove = (event) => {
661
- if (!event) {
662
- return;
663
- }
664
- const mouseEvent = event;
665
- const mousePosition = {
666
- x: mouseEvent.clientX,
667
- y: mouseEvent.clientY,
668
- };
669
- handleTooltipPosition(mousePosition);
670
- lastFloatPosition.current = mousePosition;
671
- };
672
- const handleClickOutsideAnchors = (event) => {
673
- var _a;
674
- if (!show) {
675
- return;
676
- }
677
- const target = event.target;
678
- if (!target.isConnected) {
679
- return;
680
- }
681
- if ((_a = tooltipRef.current) === null || _a === void 0 ? void 0 : _a.contains(target)) {
682
- return;
683
- }
684
- const anchorById = document.querySelector(`[id='${anchorId}']`);
685
- const anchors = [anchorById, ...anchorsBySelect];
686
- if (anchors.some((anchor) => anchor === null || anchor === void 0 ? void 0 : anchor.contains(target))) {
687
- return;
688
- }
689
- handleShow(false);
690
- if (tooltipShowDelayTimerRef.current) {
691
- clearTimeout(tooltipShowDelayTimerRef.current);
692
- }
693
- };
694
- // debounce handler to prevent call twice when
695
- // mouse enter and focus events being triggered toggether
696
- const internalDebouncedHandleShowTooltip = debounce(handleShowTooltip, 50, true);
697
- const internalDebouncedHandleHideTooltip = debounce(handleHideTooltip, 50, true);
698
- // If either of the functions is called while the other is still debounced,
699
- // reset the timeout. Otherwise if there is a sub-50ms (leave A, enter B, leave B)
700
- // sequence of events, the tooltip will stay open because the hide debounce
701
- // from leave A prevented the leave B event from calling it, leaving the
702
- // tooltip visible.
703
- const debouncedHandleShowTooltip = (e) => {
704
- internalDebouncedHandleHideTooltip.cancel();
705
- internalDebouncedHandleShowTooltip(e);
706
- };
707
- const debouncedHandleHideTooltip = () => {
708
- internalDebouncedHandleShowTooltip.cancel();
709
- internalDebouncedHandleHideTooltip();
710
- };
418
+ }, [imperativeOptions === null || imperativeOptions === void 0 ? void 0 : imperativeOptions.place, place, offset, positionStrategy, middlewares, border]);
711
419
  const updateTooltipPosition = useCallback(() => {
712
420
  var _a, _b;
713
421
  const actualPosition = (_a = imperativeOptions === null || imperativeOptions === void 0 ? void 0 : imperativeOptions.position) !== null && _a !== void 0 ? _a : position;
@@ -750,33 +458,184 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, activeAnch
750
458
  handleComputedPosition(computedStylesData);
751
459
  });
752
460
  }, [
753
- show,
461
+ imperativeOptions === null || imperativeOptions === void 0 ? void 0 : imperativeOptions.position,
462
+ imperativeOptions === null || imperativeOptions === void 0 ? void 0 : imperativeOptions.place,
463
+ position,
464
+ float,
754
465
  activeAnchor,
755
- content,
756
- externalStyles,
757
466
  place,
758
- imperativeOptions === null || imperativeOptions === void 0 ? void 0 : imperativeOptions.place,
759
467
  offset,
760
468
  positionStrategy,
761
- position,
762
- imperativeOptions === null || imperativeOptions === void 0 ? void 0 : imperativeOptions.position,
763
- float,
469
+ middlewares,
470
+ border,
471
+ handleTooltipPosition,
764
472
  ]);
765
473
  useEffect(() => {
766
- var _a, _b;
767
- const elementRefs = new Set(anchorRefs);
768
- anchorsBySelect.forEach((anchor) => {
769
- elementRefs.add({ current: anchor });
770
- });
771
- const anchorById = document.querySelector(`[id='${anchorId}']`);
772
- if (anchorById) {
773
- elementRefs.add({ current: anchorById });
774
- }
474
+ /**
475
+ * TODO(V6): break this effect down into callbacks for clarity
476
+ * - `handleKeyboardEvents()`
477
+ * - `handleMouseEvents()`
478
+ * - `handleGlobalCloseEvents()`
479
+ * - `handleAnchorEvents()`
480
+ * - ...
481
+ */
482
+ const handlePointerMove = (event) => {
483
+ if (!event) {
484
+ return;
485
+ }
486
+ const mouseEvent = event;
487
+ const mousePosition = {
488
+ x: mouseEvent.clientX,
489
+ y: mouseEvent.clientY,
490
+ };
491
+ handleTooltipPosition(mousePosition);
492
+ lastFloatPosition.current = mousePosition;
493
+ };
494
+ const handleClickOutsideAnchors = (event) => {
495
+ var _a;
496
+ if (!show) {
497
+ return;
498
+ }
499
+ const target = event.target;
500
+ if (!target.isConnected) {
501
+ return;
502
+ }
503
+ if ((_a = tooltipRef.current) === null || _a === void 0 ? void 0 : _a.contains(target)) {
504
+ return;
505
+ }
506
+ if (anchorElements.some((anchor) => anchor === null || anchor === void 0 ? void 0 : anchor.contains(target))) {
507
+ return;
508
+ }
509
+ handleShow(false);
510
+ if (tooltipShowDelayTimerRef.current) {
511
+ clearTimeout(tooltipShowDelayTimerRef.current);
512
+ }
513
+ };
514
+ const handleShowTooltip = (event) => {
515
+ var _a;
516
+ if (!event) {
517
+ return;
518
+ }
519
+ const target = ((_a = event.currentTarget) !== null && _a !== void 0 ? _a : event.target);
520
+ if (!(target === null || target === void 0 ? void 0 : target.isConnected)) {
521
+ /**
522
+ * this happens when the target is removed from the DOM
523
+ * at the same time the tooltip gets triggered
524
+ */
525
+ setActiveAnchor(null);
526
+ return;
527
+ }
528
+ if (delayShow) {
529
+ handleShowTooltipDelayed();
530
+ }
531
+ else {
532
+ handleShow(true);
533
+ }
534
+ setActiveAnchor(target);
535
+ if (tooltipHideDelayTimerRef.current) {
536
+ clearTimeout(tooltipHideDelayTimerRef.current);
537
+ }
538
+ };
539
+ const handleHideTooltip = () => {
540
+ if (clickable) {
541
+ // allow time for the mouse to reach the tooltip, in case there's a gap
542
+ handleHideTooltipDelayed(delayHide || 100);
543
+ }
544
+ else if (delayHide) {
545
+ handleHideTooltipDelayed();
546
+ }
547
+ else {
548
+ handleShow(false);
549
+ }
550
+ if (tooltipShowDelayTimerRef.current) {
551
+ clearTimeout(tooltipShowDelayTimerRef.current);
552
+ }
553
+ };
554
+ // debounce handler to prevent call twice when
555
+ // mouse enter and focus events being triggered toggether
556
+ const internalDebouncedHandleShowTooltip = debounce(handleShowTooltip, 50);
557
+ const internalDebouncedHandleHideTooltip = debounce(handleHideTooltip, 50);
558
+ // If either of the functions is called while the other is still debounced,
559
+ // reset the timeout. Otherwise if there is a sub-50ms (leave A, enter B, leave B)
560
+ // sequence of events, the tooltip will stay open because the hide debounce
561
+ // from leave A prevented the leave B event from calling it, leaving the
562
+ // tooltip visible.
563
+ const debouncedHandleShowTooltip = (e) => {
564
+ internalDebouncedHandleHideTooltip.cancel();
565
+ internalDebouncedHandleShowTooltip(e);
566
+ };
567
+ const debouncedHandleHideTooltip = () => {
568
+ internalDebouncedHandleShowTooltip.cancel();
569
+ internalDebouncedHandleHideTooltip();
570
+ };
775
571
  const handleScrollResize = () => {
776
572
  handleShow(false);
777
573
  };
778
- const anchorScrollParent = getScrollParent(activeAnchor);
574
+ 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);
575
+ const actualOpenEvents = openEvents
576
+ ? { ...openEvents }
577
+ : {
578
+ mouseenter: true,
579
+ focus: true,
580
+ click: false,
581
+ dblclick: false,
582
+ mousedown: false,
583
+ };
584
+ if (!openEvents && openOnClick) {
585
+ Object.assign(actualOpenEvents, {
586
+ mouseenter: false,
587
+ focus: false,
588
+ click: true,
589
+ });
590
+ }
591
+ const actualCloseEvents = closeEvents
592
+ ? { ...closeEvents }
593
+ : {
594
+ mouseleave: true,
595
+ blur: true,
596
+ click: false,
597
+ dblclick: false,
598
+ mouseup: false,
599
+ };
600
+ if (!closeEvents && openOnClick) {
601
+ Object.assign(actualCloseEvents, {
602
+ mouseleave: false,
603
+ blur: false,
604
+ });
605
+ }
606
+ const actualGlobalCloseEvents = globalCloseEvents
607
+ ? { ...globalCloseEvents }
608
+ : {
609
+ escape: false,
610
+ scroll: false,
611
+ resize: false,
612
+ clickOutsideAnchor: hasClickEvent || false,
613
+ };
614
+ if (imperativeModeOnly) {
615
+ Object.assign(actualOpenEvents, {
616
+ mouseenter: false,
617
+ focus: false,
618
+ click: false,
619
+ dblclick: false,
620
+ mousedown: false,
621
+ });
622
+ Object.assign(actualCloseEvents, {
623
+ mouseleave: false,
624
+ blur: false,
625
+ click: false,
626
+ dblclick: false,
627
+ mouseup: false,
628
+ });
629
+ Object.assign(actualGlobalCloseEvents, {
630
+ escape: false,
631
+ scroll: false,
632
+ resize: false,
633
+ clickOutsideAnchor: false,
634
+ });
635
+ }
636
+ const tooltipElement = tooltipRef.current;
779
637
  const tooltipScrollParent = getScrollParent(tooltipRef.current);
638
+ const anchorScrollParent = getScrollParent(activeAnchor);
780
639
  if (actualGlobalCloseEvents.scroll) {
781
640
  window.addEventListener('scroll', handleScrollResize);
782
641
  anchorScrollParent === null || anchorScrollParent === void 0 ? void 0 : anchorScrollParent.addEventListener('scroll', handleScrollResize);
@@ -869,17 +728,15 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, activeAnch
869
728
  if (clickable && !hasClickEvent) {
870
729
  // used to keep the tooltip open when hovering content.
871
730
  // not needed if using click events.
872
- (_a = tooltipRef.current) === null || _a === void 0 ? void 0 : _a.addEventListener('mouseenter', handleMouseEnterTooltip);
873
- (_b = tooltipRef.current) === null || _b === void 0 ? void 0 : _b.addEventListener('mouseleave', handleMouseLeaveTooltip);
731
+ tooltipElement === null || tooltipElement === void 0 ? void 0 : tooltipElement.addEventListener('mouseenter', handleMouseEnterTooltip);
732
+ tooltipElement === null || tooltipElement === void 0 ? void 0 : tooltipElement.addEventListener('mouseleave', handleMouseLeaveTooltip);
874
733
  }
875
734
  enabledEvents.forEach(({ event, listener }) => {
876
- elementRefs.forEach((ref) => {
877
- var _a;
878
- (_a = ref.current) === null || _a === void 0 ? void 0 : _a.addEventListener(event, listener);
735
+ anchorElements.forEach((anchor) => {
736
+ anchor.addEventListener(event, listener);
879
737
  });
880
738
  });
881
739
  return () => {
882
- var _a, _b;
883
740
  if (actualGlobalCloseEvents.scroll) {
884
741
  window.removeEventListener('scroll', handleScrollResize);
885
742
  anchorScrollParent === null || anchorScrollParent === void 0 ? void 0 : anchorScrollParent.removeEventListener('scroll', handleScrollResize);
@@ -898,13 +755,12 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, activeAnch
898
755
  window.removeEventListener('keydown', handleEsc);
899
756
  }
900
757
  if (clickable && !hasClickEvent) {
901
- (_a = tooltipRef.current) === null || _a === void 0 ? void 0 : _a.removeEventListener('mouseenter', handleMouseEnterTooltip);
902
- (_b = tooltipRef.current) === null || _b === void 0 ? void 0 : _b.removeEventListener('mouseleave', handleMouseLeaveTooltip);
758
+ tooltipElement === null || tooltipElement === void 0 ? void 0 : tooltipElement.removeEventListener('mouseenter', handleMouseEnterTooltip);
759
+ tooltipElement === null || tooltipElement === void 0 ? void 0 : tooltipElement.removeEventListener('mouseleave', handleMouseLeaveTooltip);
903
760
  }
904
761
  enabledEvents.forEach(({ event, listener }) => {
905
- elementRefs.forEach((ref) => {
906
- var _a;
907
- (_a = ref.current) === null || _a === void 0 ? void 0 : _a.removeEventListener(event, listener);
762
+ anchorElements.forEach((anchor) => {
763
+ anchor.removeEventListener(event, listener);
908
764
  });
909
765
  });
910
766
  };
@@ -914,61 +770,62 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, activeAnch
914
770
  */
915
771
  }, [
916
772
  activeAnchor,
917
- updateTooltipPosition,
918
- rendered,
919
- anchorRefs,
920
- anchorsBySelect,
921
- // the effect uses the `actual*Events` objects, but this should work
922
- openEvents,
773
+ anchorElements,
774
+ clickable,
923
775
  closeEvents,
924
- globalCloseEvents,
925
- shouldOpenOnClick,
926
- delayShow,
927
776
  delayHide,
777
+ delayShow,
778
+ float,
779
+ globalCloseEvents,
780
+ handleHideTooltipDelayed,
781
+ handleShow,
782
+ handleShowTooltipDelayed,
783
+ handleTooltipPosition,
784
+ imperativeModeOnly,
785
+ openEvents,
786
+ openOnClick,
787
+ setActiveAnchor,
788
+ show,
789
+ updateTooltipPosition,
928
790
  ]);
929
791
  useEffect(() => {
930
792
  var _a, _b;
793
+ /**
794
+ * TODO(V6): break down observer callback for clarity
795
+ * - `handleAddedAnchors()`
796
+ * - `handleRemovedAnchors()`
797
+ */
931
798
  let selector = (_b = (_a = imperativeOptions === null || imperativeOptions === void 0 ? void 0 : imperativeOptions.anchorSelect) !== null && _a !== void 0 ? _a : anchorSelect) !== null && _b !== void 0 ? _b : '';
932
799
  if (!selector && id) {
933
800
  selector = `[data-tooltip-id='${id.replace(/'/g, "\\'")}']`;
934
801
  }
935
802
  const documentObserverCallback = (mutationList) => {
936
- const newAnchors = [];
937
- const removedAnchors = [];
803
+ const addedAnchors = new Set();
804
+ const removedAnchors = new Set();
938
805
  mutationList.forEach((mutation) => {
939
806
  if (mutation.type === 'attributes' && mutation.attributeName === 'data-tooltip-id') {
940
- const newId = mutation.target.getAttribute('data-tooltip-id');
807
+ const target = mutation.target;
808
+ const newId = target.getAttribute('data-tooltip-id');
941
809
  if (newId === id) {
942
- newAnchors.push(mutation.target);
810
+ addedAnchors.add(target);
943
811
  }
944
812
  else if (mutation.oldValue === id) {
945
813
  // data-tooltip-id has now been changed, so we need to remove this anchor
946
- removedAnchors.push(mutation.target);
814
+ removedAnchors.add(target);
947
815
  }
948
816
  }
949
817
  if (mutation.type !== 'childList') {
950
818
  return;
951
819
  }
820
+ const removedNodes = [...mutation.removedNodes].filter((node) => node.nodeType === 1);
952
821
  if (activeAnchor) {
953
- const elements = [...mutation.removedNodes].filter((node) => node.nodeType === 1);
954
- if (selector) {
955
- try {
956
- removedAnchors.push(
957
- // the element itself is an anchor
958
- ...elements.filter((element) => element.matches(selector)));
959
- removedAnchors.push(
960
- // the element has children which are anchors
961
- ...elements.flatMap((element) => [...element.querySelectorAll(selector)]));
962
- }
963
- catch (_a) {
964
- /**
965
- * invalid CSS selector.
966
- * already warned on tooltip controller
967
- */
968
- }
969
- }
970
- elements.some((node) => {
822
+ removedNodes.some((node) => {
971
823
  var _a;
824
+ /**
825
+ * TODO(V6)
826
+ * - isn't `!activeAnchor.isConnected` better?
827
+ * - maybe move to `handleDisconnectedAnchor()`
828
+ */
972
829
  if ((_a = node === null || node === void 0 ? void 0 : node.contains) === null || _a === void 0 ? void 0 : _a.call(node, activeAnchor)) {
973
830
  setRendered(false);
974
831
  handleShow(false);
@@ -988,25 +845,67 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, activeAnch
988
845
  return;
989
846
  }
990
847
  try {
991
- const elements = [...mutation.addedNodes].filter((node) => node.nodeType === 1);
992
- newAnchors.push(
993
- // the element itself is an anchor
994
- ...elements.filter((element) => element.matches(selector)));
995
- newAnchors.push(
996
- // the element has children which are anchors
997
- ...elements.flatMap((element) => [...element.querySelectorAll(selector)]));
848
+ removedNodes.forEach((node) => {
849
+ const element = node;
850
+ if (element.matches(selector)) {
851
+ // the element itself is an anchor
852
+ removedAnchors.add(element);
853
+ }
854
+ else {
855
+ /**
856
+ * TODO(V6): do we care if an element which is an anchor,
857
+ * has children which are also anchors?
858
+ * (i.e. should we remove `else` and always do this)
859
+ */
860
+ // the element has children which are anchors
861
+ element
862
+ .querySelectorAll(selector)
863
+ .forEach((innerNode) => removedAnchors.add(innerNode));
864
+ }
865
+ });
866
+ }
867
+ catch (_a) {
868
+ /* c8 ignore start */
869
+ {
870
+ // eslint-disable-next-line no-console
871
+ console.warn(`[react-tooltip] "${selector}" is not a valid CSS selector`);
872
+ }
873
+ /* c8 ignore end */
874
+ }
875
+ try {
876
+ const addedNodes = [...mutation.addedNodes].filter((node) => node.nodeType === 1);
877
+ addedNodes.forEach((node) => {
878
+ const element = node;
879
+ if (element.matches(selector)) {
880
+ // the element itself is an anchor
881
+ addedAnchors.add(element);
882
+ }
883
+ else {
884
+ /**
885
+ * TODO(V6): do we care if an element which is an anchor,
886
+ * has children which are also anchors?
887
+ * (i.e. should we remove `else` and always do this)
888
+ */
889
+ // the element has children which are anchors
890
+ element
891
+ .querySelectorAll(selector)
892
+ .forEach((innerNode) => addedAnchors.add(innerNode));
893
+ }
894
+ });
998
895
  }
999
896
  catch (_b) {
1000
- /**
1001
- * invalid CSS selector.
1002
- * already warned on tooltip controller
1003
- */
897
+ /* c8 ignore start */
898
+ {
899
+ // eslint-disable-next-line no-console
900
+ console.warn(`[react-tooltip] "${selector}" is not a valid CSS selector`);
901
+ }
902
+ /* c8 ignore end */
1004
903
  }
1005
904
  });
1006
- if (newAnchors.length || removedAnchors.length) {
1007
- setAnchorsBySelect((anchors) => [
1008
- ...anchors.filter((anchor) => !removedAnchors.includes(anchor)),
1009
- ...newAnchors,
905
+ if (addedAnchors.size || removedAnchors.size) {
906
+ setAnchorElements((anchors) => [
907
+ ...anchors.filter((anchor) => !removedAnchors.has(anchor)),
908
+ ...addedAnchors,
1010
909
  ]);
1011
910
  }
1012
911
  };
@@ -1023,7 +922,7 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, activeAnch
1023
922
  return () => {
1024
923
  documentObserver.disconnect();
1025
924
  };
1026
- }, [id, anchorSelect, imperativeOptions === null || imperativeOptions === void 0 ? void 0 : imperativeOptions.anchorSelect, activeAnchor]);
925
+ }, [id, anchorSelect, imperativeOptions === null || imperativeOptions === void 0 ? void 0 : imperativeOptions.anchorSelect, activeAnchor, handleShow, setActiveAnchor]);
1027
926
  useEffect(() => {
1028
927
  updateTooltipPosition();
1029
928
  }, [updateTooltipPosition]);
@@ -1038,20 +937,18 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, activeAnch
1038
937
  return () => {
1039
938
  contentObserver.disconnect();
1040
939
  };
1041
- }, [content, contentWrapperRef === null || contentWrapperRef === void 0 ? void 0 : contentWrapperRef.current]);
940
+ }, [content, contentWrapperRef, updateTooltipPosition]);
1042
941
  useEffect(() => {
1043
942
  var _a;
1044
- const anchorById = document.querySelector(`[id='${anchorId}']`);
1045
- const anchors = [...anchorsBySelect, anchorById];
1046
- if (!activeAnchor || !anchors.includes(activeAnchor)) {
943
+ if (!activeAnchor || !anchorElements.includes(activeAnchor)) {
1047
944
  /**
1048
945
  * if there is no active anchor,
1049
946
  * or if the current active anchor is not amongst the allowed ones,
1050
947
  * reset it
1051
948
  */
1052
- setActiveAnchor((_a = anchorsBySelect[0]) !== null && _a !== void 0 ? _a : anchorById);
949
+ setActiveAnchor((_a = anchorElements[0]) !== null && _a !== void 0 ? _a : null);
1053
950
  }
1054
- }, [anchorId, anchorsBySelect, activeAnchor]);
951
+ }, [anchorElements, activeAnchor, setActiveAnchor]);
1055
952
  useEffect(() => {
1056
953
  if (defaultIsOpen) {
1057
954
  handleShow(true);
@@ -1064,7 +961,7 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, activeAnch
1064
961
  clearTimeout(tooltipHideDelayTimerRef.current);
1065
962
  }
1066
963
  };
1067
- }, []);
964
+ }, [defaultIsOpen, handleShow]);
1068
965
  useEffect(() => {
1069
966
  var _a;
1070
967
  let selector = (_a = imperativeOptions === null || imperativeOptions === void 0 ? void 0 : imperativeOptions.anchorSelect) !== null && _a !== void 0 ? _a : anchorSelect;
@@ -1076,11 +973,11 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, activeAnch
1076
973
  }
1077
974
  try {
1078
975
  const anchors = Array.from(document.querySelectorAll(selector));
1079
- setAnchorsBySelect(anchors);
976
+ setAnchorElements(anchors);
1080
977
  }
1081
978
  catch (_b) {
1082
979
  // warning was already issued in the controller
1083
- setAnchorsBySelect([]);
980
+ setAnchorElements([]);
1084
981
  }
1085
982
  }, [id, anchorSelect, imperativeOptions === null || imperativeOptions === void 0 ? void 0 : imperativeOptions.anchorSelect]);
1086
983
  useEffect(() => {
@@ -1088,7 +985,7 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, activeAnch
1088
985
  clearTimeout(tooltipShowDelayTimerRef.current);
1089
986
  handleShowTooltipDelayed(delayShow);
1090
987
  }
1091
- }, [delayShow]);
988
+ }, [delayShow, handleShowTooltipDelayed]);
1092
989
  const actualContent = (_a = imperativeOptions === null || imperativeOptions === void 0 ? void 0 : imperativeOptions.content) !== null && _a !== void 0 ? _a : content;
1093
990
  const canShow = show && Object.keys(computedPosition.tooltipStyles).length > 0;
1094
991
  useImperativeHandle(forwardRef, () => ({
@@ -1125,7 +1022,7 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, activeAnch
1125
1022
  place: computedPosition.place,
1126
1023
  isOpen: Boolean(rendered && !hidden && actualContent && canShow),
1127
1024
  }));
1128
- return rendered && !hidden && actualContent ? (React.createElement(WrapperElement, { id: id, role: role, className: classNames('react-tooltip', coreStyles['tooltip'], styles['tooltip'], styles[variant], className, `react-tooltip__place-${computedPosition.place}`, coreStyles[canShow ? 'show' : 'closing'], canShow ? 'react-tooltip__show' : 'react-tooltip__closing', positionStrategy === 'fixed' && coreStyles['fixed'], clickable && coreStyles['clickable']), onTransitionEnd: (event) => {
1025
+ return rendered && !hidden && actualContent ? (React.createElement(WrapperElement, { id: id, role: role, className: clsx('react-tooltip', coreStyles['tooltip'], styles['tooltip'], styles[variant], className, `react-tooltip__place-${computedPosition.place}`, coreStyles[canShow ? 'show' : 'closing'], canShow ? 'react-tooltip__show' : 'react-tooltip__closing', positionStrategy === 'fixed' && coreStyles['fixed'], clickable && coreStyles['clickable']), onTransitionEnd: (event) => {
1129
1026
  if (missedTransitionTimerRef.current) {
1130
1027
  clearTimeout(missedTransitionTimerRef.current);
1131
1028
  }
@@ -1141,7 +1038,7 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, activeAnch
1141
1038
  opacity: opacity !== undefined && canShow ? opacity : undefined,
1142
1039
  }, ref: tooltipRef },
1143
1040
  actualContent,
1144
- React.createElement(WrapperElement, { className: classNames('react-tooltip-arrow', coreStyles['arrow'], styles['arrow'], classNameArrow, noArrow && coreStyles['noArrow']), style: {
1041
+ React.createElement(WrapperElement, { className: clsx('react-tooltip-arrow', coreStyles['arrow'], styles['arrow'], classNameArrow, noArrow && coreStyles['noArrow']), style: {
1145
1042
  ...computedPosition.tooltipArrowStyles,
1146
1043
  background: arrowColor
1147
1044
  ? `linear-gradient(to right bottom, transparent 50%, ${arrowColor} 50%)`
@@ -1149,14 +1046,8 @@ content, contentWrapperRef, isOpen, defaultIsOpen = false, setIsOpen, activeAnch
1149
1046
  }, ref: tooltipArrowRef }))) : null;
1150
1047
  };
1151
1048
 
1152
- /* eslint-disable react/no-danger */
1153
- const TooltipContent = ({ content }) => {
1154
- return React.createElement("span", { dangerouslySetInnerHTML: { __html: content } });
1155
- };
1156
-
1157
- const TooltipController = React.forwardRef(({ id, anchorId, anchorSelect, content, html, render, className, classNameArrow, variant = 'dark', place = 'top', offset = 10, wrapper = 'div', children = null, events = ['hover'], openOnClick = false, positionStrategy = 'absolute', middlewares, delayShow = 0, delayHide = 0, float = false, hidden = false, noArrow = false, clickable = false, closeOnEsc = false, closeOnScroll = false, closeOnResize = false, openEvents, closeEvents, globalCloseEvents, imperativeModeOnly = false, style, position, isOpen, defaultIsOpen = false, disableStyleInjection = false, border, opacity, arrowColor, setIsOpen, afterShow, afterHide, role = 'tooltip', }, ref) => {
1049
+ const TooltipController = React.forwardRef(({ id, anchorSelect, content, render, className, classNameArrow, variant = 'dark', 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, setIsOpen, afterShow, afterHide, role = 'tooltip', }, ref) => {
1158
1050
  const [tooltipContent, setTooltipContent] = useState(content);
1159
- const [tooltipHtml, setTooltipHtml] = useState(html);
1160
1051
  const [tooltipPlace, setTooltipPlace] = useState(place);
1161
1052
  const [tooltipVariant, setTooltipVariant] = useState(variant);
1162
1053
  const [tooltipOffset, setTooltipOffset] = useState(offset);
@@ -1165,15 +1056,10 @@ const TooltipController = React.forwardRef(({ id, anchorId, anchorSelect, conten
1165
1056
  const [tooltipFloat, setTooltipFloat] = useState(float);
1166
1057
  const [tooltipHidden, setTooltipHidden] = useState(hidden);
1167
1058
  const [tooltipWrapper, setTooltipWrapper] = useState(wrapper);
1168
- const [tooltipEvents, setTooltipEvents] = useState(events);
1169
1059
  const [tooltipPositionStrategy, setTooltipPositionStrategy] = useState(positionStrategy);
1170
1060
  const [tooltipClassName, setTooltipClassName] = useState(null);
1171
1061
  const [activeAnchor, setActiveAnchor] = useState(null);
1172
1062
  const styleInjectionRef = useRef(disableStyleInjection);
1173
- /**
1174
- * @todo Remove this in a future version (provider/wrapper method is deprecated)
1175
- */
1176
- const { anchorRefs, activeAnchor: providerActiveAnchor } = useTooltip(id);
1177
1063
  const getDataAttributesFromAnchorElement = (elementReference) => {
1178
1064
  const dataAttributes = elementReference === null || elementReference === void 0 ? void 0 : elementReference.getAttributeNames().reduce((acc, name) => {
1179
1065
  var _a;
@@ -1185,7 +1071,7 @@ const TooltipController = React.forwardRef(({ id, anchorId, anchorSelect, conten
1185
1071
  }, {});
1186
1072
  return dataAttributes;
1187
1073
  };
1188
- const applyAllDataAttributesFromAnchorElement = (dataAttributes) => {
1074
+ const applyAllDataAttributesFromAnchorElement = useCallback((dataAttributes) => {
1189
1075
  const handleDataAttributes = {
1190
1076
  place: (value) => {
1191
1077
  var _a;
@@ -1194,9 +1080,6 @@ const TooltipController = React.forwardRef(({ id, anchorId, anchorSelect, conten
1194
1080
  content: (value) => {
1195
1081
  setTooltipContent(value !== null && value !== void 0 ? value : content);
1196
1082
  },
1197
- html: (value) => {
1198
- setTooltipHtml(value !== null && value !== void 0 ? value : html);
1199
- },
1200
1083
  variant: (value) => {
1201
1084
  var _a;
1202
1085
  setTooltipVariant((_a = value) !== null && _a !== void 0 ? _a : variant);
@@ -1208,10 +1091,6 @@ const TooltipController = React.forwardRef(({ id, anchorId, anchorSelect, conten
1208
1091
  var _a;
1209
1092
  setTooltipWrapper((_a = value) !== null && _a !== void 0 ? _a : wrapper);
1210
1093
  },
1211
- events: (value) => {
1212
- const parsed = value === null || value === void 0 ? void 0 : value.split(' ');
1213
- setTooltipEvents(parsed !== null && parsed !== void 0 ? parsed : events);
1214
- },
1215
1094
  'position-strategy': (value) => {
1216
1095
  var _a;
1217
1096
  setTooltipPositionStrategy((_a = value) !== null && _a !== void 0 ? _a : positionStrategy);
@@ -1239,13 +1118,21 @@ const TooltipController = React.forwardRef(({ id, anchorId, anchorSelect, conten
1239
1118
  var _a;
1240
1119
  (_a = handleDataAttributes[key]) === null || _a === void 0 ? void 0 : _a.call(handleDataAttributes, value);
1241
1120
  });
1242
- };
1121
+ }, [
1122
+ content,
1123
+ delayHide,
1124
+ delayShow,
1125
+ float,
1126
+ hidden,
1127
+ offset,
1128
+ place,
1129
+ positionStrategy,
1130
+ variant,
1131
+ wrapper,
1132
+ ]);
1243
1133
  useEffect(() => {
1244
1134
  setTooltipContent(content);
1245
1135
  }, [content]);
1246
- useEffect(() => {
1247
- setTooltipHtml(html);
1248
- }, [html]);
1249
1136
  useEffect(() => {
1250
1137
  setTooltipPlace(place);
1251
1138
  }, [place]);
@@ -1290,48 +1177,19 @@ const TooltipController = React.forwardRef(({ id, anchorId, anchorSelect, conten
1290
1177
  },
1291
1178
  }));
1292
1179
  }
1180
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1293
1181
  }, []);
1294
1182
  useEffect(() => {
1295
- var _a;
1296
- const elementRefs = new Set(anchorRefs);
1297
- let selector = anchorSelect;
1298
- if (!selector && id) {
1299
- selector = `[data-tooltip-id='${id.replace(/'/g, "\\'")}']`;
1300
- }
1301
- if (selector) {
1302
- try {
1303
- const anchorsBySelect = document.querySelectorAll(selector);
1304
- anchorsBySelect.forEach((anchor) => {
1305
- elementRefs.add({ current: anchor });
1306
- });
1307
- }
1308
- catch (_b) {
1309
- /* c8 ignore start */
1310
- {
1311
- // eslint-disable-next-line no-console
1312
- console.warn(`[react-tooltip] "${selector}" is not a valid CSS selector`);
1313
- }
1314
- /* c8 ignore end */
1315
- }
1316
- }
1317
- const anchorById = document.querySelector(`[id='${anchorId}']`);
1318
- if (anchorById) {
1319
- elementRefs.add({ current: anchorById });
1320
- }
1321
- if (!elementRefs.size) {
1322
- return () => null;
1323
- }
1324
- const anchorElement = (_a = activeAnchor !== null && activeAnchor !== void 0 ? activeAnchor : anchorById) !== null && _a !== void 0 ? _a : providerActiveAnchor.current;
1325
1183
  const observerCallback = (mutationList) => {
1326
1184
  mutationList.forEach((mutation) => {
1327
1185
  var _a;
1328
- if (!anchorElement ||
1186
+ if (!activeAnchor ||
1329
1187
  mutation.type !== 'attributes' ||
1330
1188
  !((_a = mutation.attributeName) === null || _a === void 0 ? void 0 : _a.startsWith('data-tooltip-'))) {
1331
1189
  return;
1332
1190
  }
1333
1191
  // make sure to get all set attributes, since all unset attributes are reset
1334
- const dataAttributes = getDataAttributesFromAnchorElement(anchorElement);
1192
+ const dataAttributes = getDataAttributesFromAnchorElement(activeAnchor);
1335
1193
  applyAllDataAttributesFromAnchorElement(dataAttributes);
1336
1194
  });
1337
1195
  };
@@ -1340,17 +1198,17 @@ const TooltipController = React.forwardRef(({ id, anchorId, anchorSelect, conten
1340
1198
  // do not check for subtree and childrens, we only want to know attribute changes
1341
1199
  // to stay watching `data-attributes-*` from anchor element
1342
1200
  const observerConfig = { attributes: true, childList: false, subtree: false };
1343
- if (anchorElement) {
1344
- const dataAttributes = getDataAttributesFromAnchorElement(anchorElement);
1201
+ if (activeAnchor) {
1202
+ const dataAttributes = getDataAttributesFromAnchorElement(activeAnchor);
1345
1203
  applyAllDataAttributesFromAnchorElement(dataAttributes);
1346
1204
  // Start observing the target node for configured mutations
1347
- observer.observe(anchorElement, observerConfig);
1205
+ observer.observe(activeAnchor, observerConfig);
1348
1206
  }
1349
1207
  return () => {
1350
1208
  // Remove the observer when the tooltip is destroyed
1351
1209
  observer.disconnect();
1352
1210
  };
1353
- }, [anchorRefs, providerActiveAnchor, activeAnchor, anchorId, anchorSelect]);
1211
+ }, [activeAnchor, anchorSelect, applyAllDataAttributesFromAnchorElement]);
1354
1212
  useEffect(() => {
1355
1213
  /* c8 ignore end */
1356
1214
  if (style === null || style === void 0 ? void 0 : style.border) {
@@ -1369,7 +1227,7 @@ const TooltipController = React.forwardRef(({ id, anchorId, anchorSelect, conten
1369
1227
  // eslint-disable-next-line no-console
1370
1228
  console.warn(`[react-tooltip] "${opacity}" is not a valid \`opacity\`.`);
1371
1229
  }
1372
- }, []);
1230
+ }, [border, opacity, style === null || style === void 0 ? void 0 : style.border, style === null || style === void 0 ? void 0 : style.opacity]);
1373
1231
  /**
1374
1232
  * content priority: children < render or content < html
1375
1233
  * children should be lower priority so that it can be used as the "default" content
@@ -1384,15 +1242,11 @@ const TooltipController = React.forwardRef(({ id, anchorId, anchorSelect, conten
1384
1242
  else if (tooltipContent) {
1385
1243
  renderedContent = tooltipContent;
1386
1244
  }
1387
- if (tooltipHtml) {
1388
- renderedContent = React.createElement(TooltipContent, { content: tooltipHtml });
1389
- }
1390
1245
  const props = {
1391
1246
  forwardRef: ref,
1392
1247
  id,
1393
- anchorId,
1394
1248
  anchorSelect,
1395
- className: classNames(className, tooltipClassName),
1249
+ className: clsx(className, tooltipClassName),
1396
1250
  classNameArrow,
1397
1251
  content: renderedContent,
1398
1252
  contentWrapperRef,
@@ -1400,7 +1254,6 @@ const TooltipController = React.forwardRef(({ id, anchorId, anchorSelect, conten
1400
1254
  variant: tooltipVariant,
1401
1255
  offset: tooltipOffset,
1402
1256
  wrapper: tooltipWrapper,
1403
- events: tooltipEvents,
1404
1257
  openOnClick,
1405
1258
  positionStrategy: tooltipPositionStrategy,
1406
1259
  middlewares,
@@ -1410,9 +1263,6 @@ const TooltipController = React.forwardRef(({ id, anchorId, anchorSelect, conten
1410
1263
  hidden: tooltipHidden,
1411
1264
  noArrow,
1412
1265
  clickable,
1413
- closeOnEsc,
1414
- closeOnScroll,
1415
- closeOnResize,
1416
1266
  openEvents,
1417
1267
  closeEvents,
1418
1268
  globalCloseEvents,
@@ -1428,7 +1278,7 @@ const TooltipController = React.forwardRef(({ id, anchorId, anchorSelect, conten
1428
1278
  afterShow,
1429
1279
  afterHide,
1430
1280
  activeAnchor,
1431
- setActiveAnchor: (anchor) => setActiveAnchor(anchor),
1281
+ setActiveAnchor,
1432
1282
  role,
1433
1283
  };
1434
1284
  return React.createElement(Tooltip, { ...props });
@@ -1556,4 +1406,5 @@ if (typeof window !== 'undefined') {
1556
1406
  }));
1557
1407
  }
1558
1408
 
1559
- export { TooltipController as Tooltip, TooltipProvider, TooltipWrapper, removeStyle };
1409
+ export { TooltipController as Tooltip };
1410
+ //# sourceMappingURL=react-tooltip.mjs.map