react-tooltip 5.10.1-beta.5 → 5.10.2-beta.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.
@@ -0,0 +1,841 @@
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react/jsx-runtime'), require('react'), require('classnames'), require('@floating-ui/dom')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', 'react/jsx-runtime', 'react', 'classnames', '@floating-ui/dom'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ReactTooltip = {}, global.jsxRuntime, global.React, global.classNames, global.dom));
5
+ })(this, (function (exports, jsxRuntime, react, classNames, dom) { 'use strict';
6
+
7
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
8
+
9
+ var classNames__default = /*#__PURE__*/_interopDefaultLegacy(classNames);
10
+
11
+ /* eslint-disable @typescript-eslint/no-explicit-any */
12
+ /**
13
+ * This function debounce the received function
14
+ * @param { function } func Function to be debounced
15
+ * @param { number } wait Time to wait before execut the function
16
+ * @param { boolean } immediate Param to define if the function will be executed immediately
17
+ */
18
+ const debounce = (func, wait, immediate) => {
19
+ let timeout = null;
20
+ return function debounced(...args) {
21
+ const later = () => {
22
+ timeout = null;
23
+ if (!immediate) {
24
+ func.apply(this, args);
25
+ }
26
+ };
27
+ if (timeout) {
28
+ clearTimeout(timeout);
29
+ }
30
+ timeout = setTimeout(later, wait);
31
+ };
32
+ };
33
+
34
+ const DEFAULT_TOOLTIP_ID = 'DEFAULT_TOOLTIP_ID';
35
+ const DEFAULT_CONTEXT_DATA = {
36
+ anchorRefs: new Set(),
37
+ activeAnchor: { current: null },
38
+ attach: () => {
39
+ /* attach anchor element */
40
+ },
41
+ detach: () => {
42
+ /* detach anchor element */
43
+ },
44
+ setActiveAnchor: () => {
45
+ /* set active anchor */
46
+ },
47
+ };
48
+ const DEFAULT_CONTEXT_DATA_WRAPPER = {
49
+ getTooltipData: () => DEFAULT_CONTEXT_DATA,
50
+ };
51
+ const TooltipContext = react.createContext(DEFAULT_CONTEXT_DATA_WRAPPER);
52
+ /**
53
+ * @deprecated Use the `data-tooltip-id` attribute, or the `anchorSelect` prop instead.
54
+ * See https://react-tooltip.com/docs/getting-started
55
+ */
56
+ const TooltipProvider = ({ children }) => {
57
+ const [anchorRefMap, setAnchorRefMap] = react.useState({
58
+ [DEFAULT_TOOLTIP_ID]: new Set(),
59
+ });
60
+ const [activeAnchorMap, setActiveAnchorMap] = react.useState({
61
+ [DEFAULT_TOOLTIP_ID]: { current: null },
62
+ });
63
+ const attach = (tooltipId, ...refs) => {
64
+ setAnchorRefMap((oldMap) => {
65
+ var _a;
66
+ const tooltipRefs = (_a = oldMap[tooltipId]) !== null && _a !== void 0 ? _a : new Set();
67
+ refs.forEach((ref) => tooltipRefs.add(ref));
68
+ // create new object to trigger re-render
69
+ return { ...oldMap, [tooltipId]: new Set(tooltipRefs) };
70
+ });
71
+ };
72
+ const detach = (tooltipId, ...refs) => {
73
+ setAnchorRefMap((oldMap) => {
74
+ const tooltipRefs = oldMap[tooltipId];
75
+ if (!tooltipRefs) {
76
+ // tooltip not found
77
+ // maybe thow error?
78
+ return oldMap;
79
+ }
80
+ refs.forEach((ref) => tooltipRefs.delete(ref));
81
+ // create new object to trigger re-render
82
+ return { ...oldMap };
83
+ });
84
+ };
85
+ const setActiveAnchor = (tooltipId, ref) => {
86
+ setActiveAnchorMap((oldMap) => {
87
+ var _a;
88
+ if (((_a = oldMap[tooltipId]) === null || _a === void 0 ? void 0 : _a.current) === ref.current) {
89
+ return oldMap;
90
+ }
91
+ // create new object to trigger re-render
92
+ return { ...oldMap, [tooltipId]: ref };
93
+ });
94
+ };
95
+ const getTooltipData = react.useCallback((tooltipId = DEFAULT_TOOLTIP_ID) => {
96
+ var _a, _b;
97
+ return ({
98
+ anchorRefs: (_a = anchorRefMap[tooltipId]) !== null && _a !== void 0 ? _a : new Set(),
99
+ activeAnchor: (_b = activeAnchorMap[tooltipId]) !== null && _b !== void 0 ? _b : { current: null },
100
+ attach: (...refs) => attach(tooltipId, ...refs),
101
+ detach: (...refs) => detach(tooltipId, ...refs),
102
+ setActiveAnchor: (ref) => setActiveAnchor(tooltipId, ref),
103
+ });
104
+ }, [anchorRefMap, activeAnchorMap, attach, detach]);
105
+ const context = react.useMemo(() => {
106
+ return {
107
+ getTooltipData,
108
+ };
109
+ }, [getTooltipData]);
110
+ return jsxRuntime.jsx(TooltipContext.Provider, { value: context, children: children });
111
+ };
112
+ function useTooltip(tooltipId = DEFAULT_TOOLTIP_ID) {
113
+ return react.useContext(TooltipContext).getTooltipData(tooltipId);
114
+ }
115
+
116
+ /**
117
+ * @deprecated Use the `data-tooltip-id` attribute, or the `anchorSelect` prop instead.
118
+ * See https://react-tooltip.com/docs/getting-started
119
+ */
120
+ const TooltipWrapper = ({ tooltipId, children, className, place, content, html, variant, offset, wrapper, events, positionStrategy, delayShow, delayHide, }) => {
121
+ const { attach, detach } = useTooltip(tooltipId);
122
+ const anchorRef = react.useRef(null);
123
+ react.useEffect(() => {
124
+ attach(anchorRef);
125
+ return () => {
126
+ detach(anchorRef);
127
+ };
128
+ }, []);
129
+ return (jsxRuntime.jsx("span", { ref: anchorRef, className: classNames__default["default"]('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: children }));
130
+ };
131
+
132
+ const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? react.useLayoutEffect : react.useEffect;
133
+
134
+ const computeTooltipPosition = async ({ elementReference = null, tooltipReference = null, tooltipArrowReference = null, place = 'top', offset: offsetValue = 10, strategy = 'absolute', middlewares = [dom.offset(Number(offsetValue)), dom.flip(), dom.shift({ padding: 5 })], }) => {
135
+ if (!elementReference) {
136
+ // elementReference can be null or undefined and we will not compute the position
137
+ // eslint-disable-next-line no-console
138
+ // console.error('The reference element for tooltip was not defined: ', elementReference)
139
+ return { tooltipStyles: {}, tooltipArrowStyles: {}, place };
140
+ }
141
+ if (tooltipReference === null) {
142
+ return { tooltipStyles: {}, tooltipArrowStyles: {}, place };
143
+ }
144
+ const middleware = middlewares;
145
+ if (tooltipArrowReference) {
146
+ middleware.push(dom.arrow({ element: tooltipArrowReference, padding: 5 }));
147
+ return dom.computePosition(elementReference, tooltipReference, {
148
+ placement: place,
149
+ strategy,
150
+ middleware,
151
+ }).then(({ x, y, placement, middlewareData }) => {
152
+ var _a, _b;
153
+ const styles = { left: `${x}px`, top: `${y}px` };
154
+ const { x: arrowX, y: arrowY } = (_a = middlewareData.arrow) !== null && _a !== void 0 ? _a : { x: 0, y: 0 };
155
+ const staticSide = (_b = {
156
+ top: 'bottom',
157
+ right: 'left',
158
+ bottom: 'top',
159
+ left: 'right',
160
+ }[placement.split('-')[0]]) !== null && _b !== void 0 ? _b : 'bottom';
161
+ const arrowStyle = {
162
+ left: arrowX != null ? `${arrowX}px` : '',
163
+ top: arrowY != null ? `${arrowY}px` : '',
164
+ right: '',
165
+ bottom: '',
166
+ [staticSide]: '-4px',
167
+ };
168
+ return { tooltipStyles: styles, tooltipArrowStyles: arrowStyle, place: placement };
169
+ });
170
+ }
171
+ return dom.computePosition(elementReference, tooltipReference, {
172
+ placement: 'bottom',
173
+ strategy,
174
+ middleware,
175
+ }).then(({ x, y, placement }) => {
176
+ const styles = { left: `${x}px`, top: `${y}px` };
177
+ return { tooltipStyles: styles, tooltipArrowStyles: {}, place: placement };
178
+ });
179
+ };
180
+
181
+ var styles = {"tooltip":"styles-module_tooltip__mnnfp","fixed":"styles-module_fixed__7ciUi","arrow":"styles-module_arrow__K0L3T","no-arrow":"styles-module_no-arrow__KcFZN","clickable":"styles-module_clickable__Bv9o7","show":"styles-module_show__2NboJ","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"};
182
+
183
+ const Tooltip = ({
184
+ // props
185
+ 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, noArrow = false, clickable = false, closeOnEsc = false, style: externalStyles, position, afterShow, afterHide,
186
+ // props handled by controller
187
+ content, isOpen, setIsOpen, activeAnchor, setActiveAnchor, }) => {
188
+ const tooltipRef = react.useRef(null);
189
+ const tooltipArrowRef = react.useRef(null);
190
+ const tooltipShowDelayTimerRef = react.useRef(null);
191
+ const tooltipHideDelayTimerRef = react.useRef(null);
192
+ const [actualPlacement, setActualPlacement] = react.useState(place);
193
+ const [inlineStyles, setInlineStyles] = react.useState({});
194
+ const [inlineArrowStyles, setInlineArrowStyles] = react.useState({});
195
+ const [show, setShow] = react.useState(false);
196
+ const [rendered, setRendered] = react.useState(false);
197
+ const wasShowing = react.useRef(false);
198
+ const lastFloatPosition = react.useRef(null);
199
+ /**
200
+ * @todo Remove this in a future version (provider/wrapper method is deprecated)
201
+ */
202
+ const { anchorRefs, setActiveAnchor: setProviderActiveAnchor } = useTooltip(id);
203
+ const hoveringTooltip = react.useRef(false);
204
+ const [anchorsBySelect, setAnchorsBySelect] = react.useState([]);
205
+ const mounted = react.useRef(false);
206
+ const shouldOpenOnClick = openOnClick || events.includes('click');
207
+ /**
208
+ * useLayoutEffect runs before useEffect,
209
+ * but should be used carefully because of caveats
210
+ * https://beta.reactjs.org/reference/react/useLayoutEffect#caveats
211
+ */
212
+ useIsomorphicLayoutEffect(() => {
213
+ mounted.current = true;
214
+ return () => {
215
+ mounted.current = false;
216
+ };
217
+ }, []);
218
+ react.useEffect(() => {
219
+ if (!show) {
220
+ /**
221
+ * this fixes weird behavior when switching between two anchor elements very quickly
222
+ * remove the timeout and switch quickly between two adjancent anchor elements to see it
223
+ *
224
+ * in practice, this means the tooltip is not immediately removed from the DOM on hide
225
+ */
226
+ const timeout = setTimeout(() => {
227
+ setRendered(false);
228
+ }, 150);
229
+ return () => {
230
+ clearTimeout(timeout);
231
+ };
232
+ }
233
+ return () => null;
234
+ }, [show]);
235
+ const handleShow = (value) => {
236
+ if (!mounted.current) {
237
+ return;
238
+ }
239
+ if (value) {
240
+ setRendered(true);
241
+ }
242
+ /**
243
+ * wait for the component to render and calculate position
244
+ * before actually showing
245
+ */
246
+ setTimeout(() => {
247
+ if (!mounted.current) {
248
+ return;
249
+ }
250
+ setIsOpen === null || setIsOpen === void 0 ? void 0 : setIsOpen(value);
251
+ if (isOpen === undefined) {
252
+ setShow(value);
253
+ }
254
+ }, 10);
255
+ };
256
+ /**
257
+ * this replicates the effect from `handleShow()`
258
+ * when `isOpen` is changed from outside
259
+ */
260
+ react.useEffect(() => {
261
+ if (isOpen === undefined) {
262
+ return () => null;
263
+ }
264
+ if (isOpen) {
265
+ setRendered(true);
266
+ }
267
+ const timeout = setTimeout(() => {
268
+ setShow(isOpen);
269
+ }, 10);
270
+ return () => {
271
+ clearTimeout(timeout);
272
+ };
273
+ }, [isOpen]);
274
+ react.useEffect(() => {
275
+ if (show === wasShowing.current) {
276
+ return;
277
+ }
278
+ wasShowing.current = show;
279
+ if (show) {
280
+ afterShow === null || afterShow === void 0 ? void 0 : afterShow();
281
+ }
282
+ else {
283
+ afterHide === null || afterHide === void 0 ? void 0 : afterHide();
284
+ }
285
+ }, [show]);
286
+ const handleShowTooltipDelayed = () => {
287
+ if (tooltipShowDelayTimerRef.current) {
288
+ clearTimeout(tooltipShowDelayTimerRef.current);
289
+ }
290
+ tooltipShowDelayTimerRef.current = setTimeout(() => {
291
+ handleShow(true);
292
+ }, delayShow);
293
+ };
294
+ const handleHideTooltipDelayed = (delay = delayHide) => {
295
+ if (tooltipHideDelayTimerRef.current) {
296
+ clearTimeout(tooltipHideDelayTimerRef.current);
297
+ }
298
+ tooltipHideDelayTimerRef.current = setTimeout(() => {
299
+ if (hoveringTooltip.current) {
300
+ return;
301
+ }
302
+ handleShow(false);
303
+ }, delay);
304
+ };
305
+ const handleShowTooltip = (event) => {
306
+ var _a;
307
+ if (!event) {
308
+ return;
309
+ }
310
+ if (delayShow) {
311
+ handleShowTooltipDelayed();
312
+ }
313
+ else {
314
+ handleShow(true);
315
+ }
316
+ const target = (_a = event.currentTarget) !== null && _a !== void 0 ? _a : event.target;
317
+ setActiveAnchor(target);
318
+ setProviderActiveAnchor({ current: target });
319
+ if (tooltipHideDelayTimerRef.current) {
320
+ clearTimeout(tooltipHideDelayTimerRef.current);
321
+ }
322
+ };
323
+ const handleHideTooltip = () => {
324
+ if (clickable) {
325
+ // allow time for the mouse to reach the tooltip, in case there's a gap
326
+ handleHideTooltipDelayed(delayHide || 100);
327
+ }
328
+ else if (delayHide) {
329
+ handleHideTooltipDelayed();
330
+ }
331
+ else {
332
+ handleShow(false);
333
+ }
334
+ if (tooltipShowDelayTimerRef.current) {
335
+ clearTimeout(tooltipShowDelayTimerRef.current);
336
+ }
337
+ };
338
+ const handleTooltipPosition = ({ x, y }) => {
339
+ const virtualElement = {
340
+ getBoundingClientRect() {
341
+ return {
342
+ x,
343
+ y,
344
+ width: 0,
345
+ height: 0,
346
+ top: y,
347
+ left: x,
348
+ right: x,
349
+ bottom: y,
350
+ };
351
+ },
352
+ };
353
+ computeTooltipPosition({
354
+ place,
355
+ offset,
356
+ elementReference: virtualElement,
357
+ tooltipReference: tooltipRef.current,
358
+ tooltipArrowReference: tooltipArrowRef.current,
359
+ strategy: positionStrategy,
360
+ middlewares,
361
+ }).then((computedStylesData) => {
362
+ if (Object.keys(computedStylesData.tooltipStyles).length) {
363
+ setInlineStyles(computedStylesData.tooltipStyles);
364
+ }
365
+ if (Object.keys(computedStylesData.tooltipArrowStyles).length) {
366
+ setInlineArrowStyles(computedStylesData.tooltipArrowStyles);
367
+ }
368
+ setActualPlacement(computedStylesData.place);
369
+ });
370
+ };
371
+ const handleMouseMove = (event) => {
372
+ if (!event) {
373
+ return;
374
+ }
375
+ const mouseEvent = event;
376
+ const mousePosition = {
377
+ x: mouseEvent.clientX,
378
+ y: mouseEvent.clientY,
379
+ };
380
+ handleTooltipPosition(mousePosition);
381
+ lastFloatPosition.current = mousePosition;
382
+ };
383
+ const handleClickTooltipAnchor = (event) => {
384
+ handleShowTooltip(event);
385
+ if (delayHide) {
386
+ handleHideTooltipDelayed();
387
+ }
388
+ };
389
+ const handleClickOutsideAnchors = (event) => {
390
+ var _a;
391
+ const anchorById = document.querySelector(`[id='${anchorId}']`);
392
+ const anchors = [anchorById, ...anchorsBySelect];
393
+ if (anchors.some((anchor) => anchor === null || anchor === void 0 ? void 0 : anchor.contains(event.target))) {
394
+ return;
395
+ }
396
+ if ((_a = tooltipRef.current) === null || _a === void 0 ? void 0 : _a.contains(event.target)) {
397
+ return;
398
+ }
399
+ handleShow(false);
400
+ };
401
+ const handleEsc = (event) => {
402
+ if (event.key !== 'Escape') {
403
+ return;
404
+ }
405
+ handleShow(false);
406
+ };
407
+ // debounce handler to prevent call twice when
408
+ // mouse enter and focus events being triggered toggether
409
+ const debouncedHandleShowTooltip = debounce(handleShowTooltip, 50);
410
+ const debouncedHandleHideTooltip = debounce(handleHideTooltip, 50);
411
+ react.useEffect(() => {
412
+ var _a, _b;
413
+ const elementRefs = new Set(anchorRefs);
414
+ anchorsBySelect.forEach((anchor) => {
415
+ elementRefs.add({ current: anchor });
416
+ });
417
+ const anchorById = document.querySelector(`[id='${anchorId}']`);
418
+ if (anchorById) {
419
+ elementRefs.add({ current: anchorById });
420
+ }
421
+ if (closeOnEsc) {
422
+ window.addEventListener('keydown', handleEsc);
423
+ }
424
+ const enabledEvents = [];
425
+ if (shouldOpenOnClick) {
426
+ window.addEventListener('click', handleClickOutsideAnchors);
427
+ enabledEvents.push({ event: 'click', listener: handleClickTooltipAnchor });
428
+ }
429
+ else {
430
+ enabledEvents.push({ event: 'mouseenter', listener: debouncedHandleShowTooltip }, { event: 'mouseleave', listener: debouncedHandleHideTooltip }, { event: 'focus', listener: debouncedHandleShowTooltip }, { event: 'blur', listener: debouncedHandleHideTooltip });
431
+ if (float) {
432
+ enabledEvents.push({
433
+ event: 'mousemove',
434
+ listener: handleMouseMove,
435
+ });
436
+ }
437
+ }
438
+ const handleMouseEnterTooltip = () => {
439
+ hoveringTooltip.current = true;
440
+ };
441
+ const handleMouseLeaveTooltip = () => {
442
+ hoveringTooltip.current = false;
443
+ handleHideTooltip();
444
+ };
445
+ if (clickable && !shouldOpenOnClick) {
446
+ (_a = tooltipRef.current) === null || _a === void 0 ? void 0 : _a.addEventListener('mouseenter', handleMouseEnterTooltip);
447
+ (_b = tooltipRef.current) === null || _b === void 0 ? void 0 : _b.addEventListener('mouseleave', handleMouseLeaveTooltip);
448
+ }
449
+ enabledEvents.forEach(({ event, listener }) => {
450
+ elementRefs.forEach((ref) => {
451
+ var _a;
452
+ (_a = ref.current) === null || _a === void 0 ? void 0 : _a.addEventListener(event, listener);
453
+ });
454
+ });
455
+ return () => {
456
+ var _a, _b;
457
+ if (shouldOpenOnClick) {
458
+ window.removeEventListener('click', handleClickOutsideAnchors);
459
+ }
460
+ if (closeOnEsc) {
461
+ window.removeEventListener('keydown', handleEsc);
462
+ }
463
+ if (clickable && !shouldOpenOnClick) {
464
+ (_a = tooltipRef.current) === null || _a === void 0 ? void 0 : _a.removeEventListener('mouseenter', handleMouseEnterTooltip);
465
+ (_b = tooltipRef.current) === null || _b === void 0 ? void 0 : _b.removeEventListener('mouseleave', handleMouseLeaveTooltip);
466
+ }
467
+ enabledEvents.forEach(({ event, listener }) => {
468
+ elementRefs.forEach((ref) => {
469
+ var _a;
470
+ (_a = ref.current) === null || _a === void 0 ? void 0 : _a.removeEventListener(event, listener);
471
+ });
472
+ });
473
+ };
474
+ /**
475
+ * rendered is also a dependency to ensure anchor observers are re-registered
476
+ * since `tooltipRef` becomes stale after removing/adding the tooltip to the DOM
477
+ */
478
+ }, [rendered, anchorRefs, anchorsBySelect, closeOnEsc, events]);
479
+ react.useEffect(() => {
480
+ let selector = anchorSelect !== null && anchorSelect !== void 0 ? anchorSelect : '';
481
+ if (!selector && id) {
482
+ selector = `[data-tooltip-id='${id}']`;
483
+ }
484
+ const documentObserverCallback = (mutationList) => {
485
+ const newAnchors = [];
486
+ mutationList.forEach((mutation) => {
487
+ if (mutation.type === 'attributes' && mutation.attributeName === 'data-tooltip-id') {
488
+ const newId = mutation.target.getAttribute('data-tooltip-id');
489
+ if (newId === id) {
490
+ newAnchors.push(mutation.target);
491
+ }
492
+ }
493
+ if (mutation.type !== 'childList') {
494
+ return;
495
+ }
496
+ if (activeAnchor) {
497
+ [...mutation.removedNodes].some((node) => {
498
+ var _a;
499
+ if ((_a = node === null || node === void 0 ? void 0 : node.contains) === null || _a === void 0 ? void 0 : _a.call(node, activeAnchor)) {
500
+ setRendered(false);
501
+ handleShow(false);
502
+ setActiveAnchor(null);
503
+ return true;
504
+ }
505
+ return false;
506
+ });
507
+ }
508
+ if (!selector) {
509
+ return;
510
+ }
511
+ try {
512
+ const elements = [...mutation.addedNodes].filter((node) => node.nodeType === 1);
513
+ newAnchors.push(
514
+ // the element itself is an anchor
515
+ ...elements.filter((element) => element.matches(selector)));
516
+ newAnchors.push(
517
+ // the element has children which are anchors
518
+ ...elements.flatMap((element) => [...element.querySelectorAll(selector)]));
519
+ }
520
+ catch (_a) {
521
+ /**
522
+ * invalid CSS selector.
523
+ * already warned on tooltip controller
524
+ */
525
+ }
526
+ });
527
+ if (newAnchors.length) {
528
+ setAnchorsBySelect((anchors) => [...anchors, ...newAnchors]);
529
+ }
530
+ };
531
+ const documentObserver = new MutationObserver(documentObserverCallback);
532
+ // watch for anchor being removed from the DOM
533
+ documentObserver.observe(document.body, {
534
+ childList: true,
535
+ subtree: true,
536
+ attributes: true,
537
+ attributeFilter: ['data-tooltip-id'],
538
+ });
539
+ return () => {
540
+ documentObserver.disconnect();
541
+ };
542
+ }, [id, anchorSelect, activeAnchor]);
543
+ react.useEffect(() => {
544
+ if (position) {
545
+ // if `position` is set, override regular and `float` positioning
546
+ handleTooltipPosition(position);
547
+ return;
548
+ }
549
+ if (float) {
550
+ if (lastFloatPosition.current) {
551
+ /*
552
+ Without this, changes to `content`, `place`, `offset`, ..., will only
553
+ trigger a position calculation after a `mousemove` event.
554
+
555
+ To see why this matters, comment this line, run `yarn dev` and click the
556
+ "Hover me!" anchor.
557
+ */
558
+ handleTooltipPosition(lastFloatPosition.current);
559
+ }
560
+ // if `float` is set, override regular positioning
561
+ return;
562
+ }
563
+ computeTooltipPosition({
564
+ place,
565
+ offset,
566
+ elementReference: activeAnchor,
567
+ tooltipReference: tooltipRef.current,
568
+ tooltipArrowReference: tooltipArrowRef.current,
569
+ strategy: positionStrategy,
570
+ middlewares,
571
+ }).then((computedStylesData) => {
572
+ if (!mounted.current) {
573
+ // invalidate computed positions after remount
574
+ return;
575
+ }
576
+ if (Object.keys(computedStylesData.tooltipStyles).length) {
577
+ setInlineStyles(computedStylesData.tooltipStyles);
578
+ }
579
+ if (Object.keys(computedStylesData.tooltipArrowStyles).length) {
580
+ setInlineArrowStyles(computedStylesData.tooltipArrowStyles);
581
+ }
582
+ setActualPlacement(computedStylesData.place);
583
+ });
584
+ }, [show, activeAnchor, content, place, offset, positionStrategy, position]);
585
+ react.useEffect(() => {
586
+ var _a;
587
+ const anchorById = document.querySelector(`[id='${anchorId}']`);
588
+ const anchors = [...anchorsBySelect, anchorById];
589
+ if (!activeAnchor || !anchors.includes(activeAnchor)) {
590
+ /**
591
+ * if there is no active anchor,
592
+ * or if the current active anchor is not amongst the allowed ones,
593
+ * reset it
594
+ */
595
+ setActiveAnchor((_a = anchorsBySelect[0]) !== null && _a !== void 0 ? _a : anchorById);
596
+ }
597
+ }, [anchorId, anchorsBySelect, activeAnchor]);
598
+ react.useEffect(() => {
599
+ return () => {
600
+ if (tooltipShowDelayTimerRef.current) {
601
+ clearTimeout(tooltipShowDelayTimerRef.current);
602
+ }
603
+ if (tooltipHideDelayTimerRef.current) {
604
+ clearTimeout(tooltipHideDelayTimerRef.current);
605
+ }
606
+ };
607
+ }, []);
608
+ react.useEffect(() => {
609
+ let selector = anchorSelect;
610
+ if (!selector && id) {
611
+ selector = `[data-tooltip-id='${id}']`;
612
+ }
613
+ if (!selector) {
614
+ return;
615
+ }
616
+ try {
617
+ const anchors = Array.from(document.querySelectorAll(selector));
618
+ setAnchorsBySelect(anchors);
619
+ }
620
+ catch (_a) {
621
+ // warning was already issued in the controller
622
+ setAnchorsBySelect([]);
623
+ }
624
+ }, [id, anchorSelect]);
625
+ const canShow = content && show && Object.keys(inlineStyles).length > 0;
626
+ return rendered ? (jsxRuntime.jsxs(WrapperElement, { id: id, role: "tooltip", className: classNames__default["default"]('react-tooltip', styles['tooltip'], styles[variant], className, `react-tooltip__place-${actualPlacement}`, {
627
+ [styles['show']]: canShow,
628
+ [styles['fixed']]: positionStrategy === 'fixed',
629
+ [styles['clickable']]: clickable,
630
+ }), style: { ...externalStyles, ...inlineStyles }, ref: tooltipRef, children: [content, jsxRuntime.jsx(WrapperElement, { className: classNames__default["default"]('react-tooltip-arrow', styles['arrow'], classNameArrow, {
631
+ /**
632
+ * changed from dash `no-arrow` to camelcase because of:
633
+ * https://github.com/indooorsman/esbuild-css-modules-plugin/issues/42
634
+ */
635
+ [styles['noArrow']]: noArrow,
636
+ }), style: inlineArrowStyles, ref: tooltipArrowRef })] })) : null;
637
+ };
638
+
639
+ const TooltipContent = ({ content }) => {
640
+ return jsxRuntime.jsx("span", { dangerouslySetInnerHTML: { __html: content } });
641
+ };
642
+
643
+ const TooltipController = ({ 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, noArrow = false, clickable = false, closeOnEsc = false, style, position, isOpen, setIsOpen, afterShow, afterHide, }) => {
644
+ const [tooltipContent, setTooltipContent] = react.useState(content);
645
+ const [tooltipHtml, setTooltipHtml] = react.useState(html);
646
+ const [tooltipPlace, setTooltipPlace] = react.useState(place);
647
+ const [tooltipVariant, setTooltipVariant] = react.useState(variant);
648
+ const [tooltipOffset, setTooltipOffset] = react.useState(offset);
649
+ const [tooltipDelayShow, setTooltipDelayShow] = react.useState(delayShow);
650
+ const [tooltipDelayHide, setTooltipDelayHide] = react.useState(delayHide);
651
+ const [tooltipFloat, setTooltipFloat] = react.useState(float);
652
+ const [tooltipWrapper, setTooltipWrapper] = react.useState(wrapper);
653
+ const [tooltipEvents, setTooltipEvents] = react.useState(events);
654
+ const [tooltipPositionStrategy, setTooltipPositionStrategy] = react.useState(positionStrategy);
655
+ const [activeAnchor, setActiveAnchor] = react.useState(null);
656
+ /**
657
+ * @todo Remove this in a future version (provider/wrapper method is deprecated)
658
+ */
659
+ const { anchorRefs, activeAnchor: providerActiveAnchor } = useTooltip(id);
660
+ const getDataAttributesFromAnchorElement = (elementReference) => {
661
+ const dataAttributes = elementReference === null || elementReference === void 0 ? void 0 : elementReference.getAttributeNames().reduce((acc, name) => {
662
+ var _a;
663
+ if (name.startsWith('data-tooltip-')) {
664
+ const parsedAttribute = name.replace(/^data-tooltip-/, '');
665
+ acc[parsedAttribute] = (_a = elementReference === null || elementReference === void 0 ? void 0 : elementReference.getAttribute(name)) !== null && _a !== void 0 ? _a : null;
666
+ }
667
+ return acc;
668
+ }, {});
669
+ return dataAttributes;
670
+ };
671
+ const applyAllDataAttributesFromAnchorElement = (dataAttributes) => {
672
+ const handleDataAttributes = {
673
+ place: (value) => {
674
+ var _a;
675
+ setTooltipPlace((_a = value) !== null && _a !== void 0 ? _a : place);
676
+ },
677
+ content: (value) => {
678
+ setTooltipContent(value !== null && value !== void 0 ? value : content);
679
+ },
680
+ html: (value) => {
681
+ setTooltipHtml(value !== null && value !== void 0 ? value : html);
682
+ },
683
+ variant: (value) => {
684
+ var _a;
685
+ setTooltipVariant((_a = value) !== null && _a !== void 0 ? _a : variant);
686
+ },
687
+ offset: (value) => {
688
+ setTooltipOffset(value === null ? offset : Number(value));
689
+ },
690
+ wrapper: (value) => {
691
+ var _a;
692
+ setTooltipWrapper((_a = value) !== null && _a !== void 0 ? _a : wrapper);
693
+ },
694
+ events: (value) => {
695
+ const parsed = value === null || value === void 0 ? void 0 : value.split(' ');
696
+ setTooltipEvents(parsed !== null && parsed !== void 0 ? parsed : events);
697
+ },
698
+ 'position-strategy': (value) => {
699
+ var _a;
700
+ setTooltipPositionStrategy((_a = value) !== null && _a !== void 0 ? _a : positionStrategy);
701
+ },
702
+ 'delay-show': (value) => {
703
+ setTooltipDelayShow(value === null ? delayShow : Number(value));
704
+ },
705
+ 'delay-hide': (value) => {
706
+ setTooltipDelayHide(value === null ? delayHide : Number(value));
707
+ },
708
+ float: (value) => {
709
+ setTooltipFloat(value === null ? float : value === 'true');
710
+ },
711
+ };
712
+ // reset unset data attributes to default values
713
+ // without this, data attributes from the last active anchor will still be used
714
+ Object.values(handleDataAttributes).forEach((handler) => handler(null));
715
+ Object.entries(dataAttributes).forEach(([key, value]) => {
716
+ var _a;
717
+ (_a = handleDataAttributes[key]) === null || _a === void 0 ? void 0 : _a.call(handleDataAttributes, value);
718
+ });
719
+ };
720
+ react.useEffect(() => {
721
+ setTooltipContent(content);
722
+ }, [content]);
723
+ react.useEffect(() => {
724
+ setTooltipHtml(html);
725
+ }, [html]);
726
+ react.useEffect(() => {
727
+ setTooltipPlace(place);
728
+ }, [place]);
729
+ react.useEffect(() => {
730
+ var _a;
731
+ const elementRefs = new Set(anchorRefs);
732
+ let selector = anchorSelect;
733
+ if (!selector && id) {
734
+ selector = `[data-tooltip-id='${id}']`;
735
+ }
736
+ if (selector) {
737
+ try {
738
+ const anchorsBySelect = document.querySelectorAll(selector);
739
+ anchorsBySelect.forEach((anchor) => {
740
+ elementRefs.add({ current: anchor });
741
+ });
742
+ }
743
+ catch (_b) {
744
+ {
745
+ // eslint-disable-next-line no-console
746
+ console.warn(`[react-tooltip] "${anchorSelect}" is not a valid CSS selector`);
747
+ }
748
+ }
749
+ }
750
+ const anchorById = document.querySelector(`[id='${anchorId}']`);
751
+ if (anchorById) {
752
+ elementRefs.add({ current: anchorById });
753
+ }
754
+ if (!elementRefs.size) {
755
+ return () => null;
756
+ }
757
+ const anchorElement = (_a = activeAnchor !== null && activeAnchor !== void 0 ? activeAnchor : anchorById) !== null && _a !== void 0 ? _a : providerActiveAnchor.current;
758
+ const observerCallback = (mutationList) => {
759
+ mutationList.forEach((mutation) => {
760
+ var _a;
761
+ if (!anchorElement ||
762
+ mutation.type !== 'attributes' ||
763
+ !((_a = mutation.attributeName) === null || _a === void 0 ? void 0 : _a.startsWith('data-tooltip-'))) {
764
+ return;
765
+ }
766
+ // make sure to get all set attributes, since all unset attributes are reset
767
+ const dataAttributes = getDataAttributesFromAnchorElement(anchorElement);
768
+ applyAllDataAttributesFromAnchorElement(dataAttributes);
769
+ });
770
+ };
771
+ // Create an observer instance linked to the callback function
772
+ const observer = new MutationObserver(observerCallback);
773
+ // do not check for subtree and childrens, we only want to know attribute changes
774
+ // to stay watching `data-attributes-*` from anchor element
775
+ const observerConfig = { attributes: true, childList: false, subtree: false };
776
+ if (anchorElement) {
777
+ const dataAttributes = getDataAttributesFromAnchorElement(anchorElement);
778
+ applyAllDataAttributesFromAnchorElement(dataAttributes);
779
+ // Start observing the target node for configured mutations
780
+ observer.observe(anchorElement, observerConfig);
781
+ }
782
+ return () => {
783
+ // Remove the observer when the tooltip is destroyed
784
+ observer.disconnect();
785
+ };
786
+ }, [anchorRefs, providerActiveAnchor, activeAnchor, anchorId, anchorSelect]);
787
+ /**
788
+ * content priority: children < renderContent or content < html
789
+ * children should be lower priority so that it can be used as the "default" content
790
+ */
791
+ let renderedContent = children;
792
+ if (render) {
793
+ renderedContent = render({ content: tooltipContent !== null && tooltipContent !== void 0 ? tooltipContent : null, activeAnchor });
794
+ }
795
+ else if (tooltipContent) {
796
+ renderedContent = tooltipContent;
797
+ }
798
+ if (tooltipHtml) {
799
+ renderedContent = jsxRuntime.jsx(TooltipContent, { content: tooltipHtml });
800
+ }
801
+ const props = {
802
+ id,
803
+ anchorId,
804
+ anchorSelect,
805
+ className,
806
+ classNameArrow,
807
+ content: renderedContent,
808
+ place: tooltipPlace,
809
+ variant: tooltipVariant,
810
+ offset: tooltipOffset,
811
+ wrapper: tooltipWrapper,
812
+ events: tooltipEvents,
813
+ openOnClick,
814
+ positionStrategy: tooltipPositionStrategy,
815
+ middlewares,
816
+ delayShow: tooltipDelayShow,
817
+ delayHide: tooltipDelayHide,
818
+ float: tooltipFloat,
819
+ noArrow,
820
+ clickable,
821
+ closeOnEsc,
822
+ style,
823
+ position,
824
+ isOpen,
825
+ setIsOpen,
826
+ afterShow,
827
+ afterHide,
828
+ activeAnchor,
829
+ setActiveAnchor: (anchor) => setActiveAnchor(anchor),
830
+ };
831
+ return jsxRuntime.jsx(Tooltip, { ...props });
832
+ };
833
+
834
+ exports.Tooltip = TooltipController;
835
+ exports.TooltipProvider = TooltipProvider;
836
+ exports.TooltipWrapper = TooltipWrapper;
837
+
838
+ Object.defineProperty(exports, '__esModule', { value: true });
839
+
840
+ }));
841
+ //# sourceMappingURL=react-tooltip.umd.js.map