@clayui/tooltip 3.75.2 → 3.78.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.
@@ -0,0 +1,170 @@
1
+ /**
2
+ * SPDX-FileCopyrightText: © 2019 Liferay, Inc. <https://liferay.com>
3
+ * SPDX-License-Identifier: BSD-3-Clause
4
+ */
5
+
6
+ import React, {useCallback, useRef} from 'react';
7
+
8
+ function matches(
9
+ element: HTMLElement & {
10
+ msMatchesSelector?: HTMLElement['matches'];
11
+ },
12
+ selectorString: string
13
+ ) {
14
+ if (element.matches) {
15
+ return element.matches(selectorString);
16
+ } else if (element.msMatchesSelector) {
17
+ return element.msMatchesSelector(selectorString);
18
+ } else if (element.webkitMatchesSelector) {
19
+ return element.webkitMatchesSelector(selectorString);
20
+ } else {
21
+ return false;
22
+ }
23
+ }
24
+
25
+ function closestAncestor(node: HTMLElement, s: string) {
26
+ const element = node;
27
+ let ancestor: HTMLElement | null = node;
28
+
29
+ if (!document.documentElement.contains(element)) {
30
+ return null;
31
+ }
32
+
33
+ do {
34
+ if (matches(ancestor, s)) {
35
+ return ancestor;
36
+ }
37
+
38
+ ancestor = ancestor.parentElement;
39
+ } while (ancestor !== null);
40
+
41
+ return null;
42
+ }
43
+
44
+ type Props = {
45
+ onHide: () => void;
46
+ onClick: () => void;
47
+ tooltipRef: React.MutableRefObject<HTMLElement | null>;
48
+ };
49
+
50
+ export function useClosestTitle(props: Props) {
51
+ const targetRef = useRef<HTMLElement | null>(null);
52
+ const titleNodeRef = useRef<HTMLElement | null>(null);
53
+
54
+ const saveTitle = useCallback((element: HTMLElement) => {
55
+ titleNodeRef.current = element;
56
+
57
+ const title = element.getAttribute('title');
58
+
59
+ if (title) {
60
+ element.setAttribute('data-restore-title', title);
61
+ element.removeAttribute('title');
62
+ } else if (element.tagName === 'svg') {
63
+ const titleTag = element.querySelector('title');
64
+
65
+ if (titleTag) {
66
+ element.setAttribute('data-restore-title', titleTag.innerHTML);
67
+
68
+ titleTag.remove();
69
+ }
70
+ }
71
+ }, []);
72
+
73
+ const restoreTitle = useCallback(() => {
74
+ const element = titleNodeRef.current;
75
+
76
+ if (element) {
77
+ const title = element.getAttribute('data-restore-title');
78
+
79
+ if (title) {
80
+ if (element.tagName === 'svg') {
81
+ const titleTag = document.createElement('title');
82
+
83
+ titleTag.innerHTML = title;
84
+
85
+ element.appendChild(titleTag);
86
+ } else {
87
+ element.setAttribute('title', title);
88
+ }
89
+
90
+ element.removeAttribute('data-restore-title');
91
+ }
92
+
93
+ titleNodeRef.current = null;
94
+ }
95
+ }, []);
96
+
97
+ const onClick = useCallback((event?: any) => {
98
+ props.onClick();
99
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
100
+ onHide(event);
101
+ }, []);
102
+
103
+ const onHide = useCallback((event?: any) => {
104
+ if (
105
+ event &&
106
+ (props.tooltipRef.current?.contains(event.relatedTarget) ||
107
+ targetRef.current?.contains(event.relatedTarget))
108
+ ) {
109
+ return null;
110
+ }
111
+
112
+ props.onHide();
113
+
114
+ restoreTitle();
115
+
116
+ if (targetRef.current) {
117
+ targetRef.current.removeEventListener('click', onClick);
118
+ targetRef.current = null;
119
+ }
120
+ }, []);
121
+
122
+ const getProps = useCallback(
123
+ (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
124
+ if (targetRef.current) {
125
+ props.onClick();
126
+
127
+ if (onHide(event) === null) {
128
+ return;
129
+ }
130
+ }
131
+
132
+ const target = event.target as HTMLElement;
133
+
134
+ const hasTitle =
135
+ target &&
136
+ (target.hasAttribute('[title]') ||
137
+ target.hasAttribute('[data-title]'));
138
+
139
+ const node = hasTitle
140
+ ? target
141
+ : closestAncestor(target, '[title], [data-title]');
142
+
143
+ if (node) {
144
+ targetRef.current = target;
145
+
146
+ target.addEventListener('click', onClick);
147
+
148
+ const title =
149
+ node.getAttribute('title') ||
150
+ node.getAttribute('data-title') ||
151
+ '';
152
+
153
+ saveTitle(node);
154
+
155
+ return {
156
+ align: node.getAttribute('data-tooltip-align'),
157
+ delay: node.getAttribute('data-tooltip-delay'),
158
+ floating: Boolean(
159
+ node.getAttribute('data-tooltip-floating')
160
+ ),
161
+ setAsHTML: !!node.getAttribute('data-title-set-as-html'),
162
+ title,
163
+ };
164
+ }
165
+ },
166
+ []
167
+ );
168
+
169
+ return {getProps, onHide, target: targetRef, titleNode: titleNodeRef};
170
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * SPDX-FileCopyrightText: © 2019 Liferay, Inc. <https://liferay.com>
3
+ * SPDX-License-Identifier: BSD-3-Clause
4
+ */
5
+
6
+ import {useCallback, useRef, useState} from 'react';
7
+
8
+ type Props = {
9
+ delay?: number;
10
+ };
11
+
12
+ export function useTooltipState({delay = 600}: Props) {
13
+ const [isOpen, setOpen] = useState(false);
14
+
15
+ const timeoutIdRef = useRef<any>();
16
+
17
+ const open = useCallback((immediate: boolean, customDelay?: number) => {
18
+ if (!immediate) {
19
+ clearTimeout(timeoutIdRef.current);
20
+
21
+ timeoutIdRef.current = setTimeout(
22
+ () => {
23
+ setOpen(true);
24
+ },
25
+ customDelay !== undefined ? customDelay : delay
26
+ );
27
+ } else {
28
+ setOpen(true);
29
+ }
30
+ }, []);
31
+
32
+ const close = useCallback(() => {
33
+ clearTimeout(timeoutIdRef.current);
34
+
35
+ setOpen(false);
36
+ }, []);
37
+
38
+ return {
39
+ close,
40
+ isOpen,
41
+ open,
42
+ };
43
+ }