@bikiran/utils 2.3.5 → 2.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/information-tooltip/InformationTooltip.d.ts +4 -0
- package/dist/components/information-tooltip/InformationTooltip.js +186 -22
- package/dist/components/information-tooltip/style/InfoTooltip.module.css +19 -25
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/index.ts +3 -1
- package/dist/lib/constants/index.d.ts +2 -0
- package/dist/lib/constants/index.js +12 -0
- package/dist/lib/constants/index.ts +14 -0
- package/dist/lib/types/assets.d.ts +12 -0
- package/dist/lib/types/assets.js +1 -0
- package/dist/lib/types/assets.ts +12 -0
- package/package.json +1 -1
|
@@ -6,6 +6,10 @@ type TProps = {
|
|
|
6
6
|
align?: "left" | "right" | "top" | "bottom";
|
|
7
7
|
fillColor?: string;
|
|
8
8
|
borderColor?: string;
|
|
9
|
+
trigger?: "hover" | "click";
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
delay?: number;
|
|
12
|
+
offset?: number;
|
|
9
13
|
};
|
|
10
14
|
declare const InformationTooltip: FC<TProps>;
|
|
11
15
|
export default InformationTooltip;
|
|
@@ -1,27 +1,191 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useRef, useEffect, useCallback } from "react";
|
|
3
|
+
import { createPortal } from "react-dom";
|
|
2
4
|
import { IconArrow, IconInfo } from "./icons";
|
|
3
5
|
import styles from "./style/InfoTooltip.module.css";
|
|
4
6
|
import { cn } from "../../lib/utils/cn";
|
|
5
|
-
const InformationTooltip = ({ children, content, className, align = "right", fillColor = "#FFF9DB", borderColor = "#FFE6BA", }) => {
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
7
|
+
const InformationTooltip = ({ children, content, className, align = "right", fillColor = "#FFF9DB", borderColor = "#FFE6BA", trigger = "hover", disabled = false, delay = 200, offset = 12, }) => {
|
|
8
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
9
|
+
const [position, setPosition] = useState({
|
|
10
|
+
top: 0,
|
|
11
|
+
left: 0,
|
|
12
|
+
finalAlign: align,
|
|
13
|
+
});
|
|
14
|
+
const triggerRef = useRef(null);
|
|
15
|
+
const tooltipRef = useRef(null);
|
|
16
|
+
const timeoutRef = useRef(null);
|
|
17
|
+
// Calculate optimal position based on viewport boundaries
|
|
18
|
+
const calculatePosition = useCallback(() => {
|
|
19
|
+
if (!triggerRef.current)
|
|
20
|
+
return { top: 0, left: 0, finalAlign: align };
|
|
21
|
+
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
22
|
+
const viewportWidth = window.innerWidth;
|
|
23
|
+
const viewportHeight = window.innerHeight;
|
|
24
|
+
const tooltipWidth = 224; // w-56 = 14rem = 224px
|
|
25
|
+
// Try to get actual tooltip height if available, otherwise use estimate
|
|
26
|
+
let tooltipHeight = 65; // default estimate
|
|
27
|
+
if (tooltipRef.current) {
|
|
28
|
+
const tooltipRect = tooltipRef.current.getBoundingClientRect();
|
|
29
|
+
if (tooltipRect.height > 0) {
|
|
30
|
+
tooltipHeight = tooltipRect.height;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
let finalAlign = align;
|
|
34
|
+
let top = 0;
|
|
35
|
+
let left = 0;
|
|
36
|
+
// Calculate position based on preferred alignment
|
|
37
|
+
switch (align) {
|
|
38
|
+
case "right":
|
|
39
|
+
left = triggerRect.right + offset;
|
|
40
|
+
top = triggerRect.top + triggerRect.height / 2 - tooltipHeight / 2;
|
|
41
|
+
// Check if tooltip would overflow viewport
|
|
42
|
+
if (left + tooltipWidth > viewportWidth) {
|
|
43
|
+
finalAlign = "left";
|
|
44
|
+
left = triggerRect.left - tooltipWidth - offset;
|
|
45
|
+
}
|
|
46
|
+
break;
|
|
47
|
+
case "left":
|
|
48
|
+
left = triggerRect.left - tooltipWidth - offset;
|
|
49
|
+
top = triggerRect.top + triggerRect.height / 2 - tooltipHeight / 2;
|
|
50
|
+
if (left < 0) {
|
|
51
|
+
finalAlign = "right";
|
|
52
|
+
left = triggerRect.right + offset;
|
|
53
|
+
}
|
|
54
|
+
break;
|
|
55
|
+
case "top":
|
|
56
|
+
left = triggerRect.left + triggerRect.width / 2 - tooltipWidth / 2;
|
|
57
|
+
top = triggerRect.top - tooltipHeight + offset / 2; // Reduce gap for closer positioning
|
|
58
|
+
if (top < 0) {
|
|
59
|
+
finalAlign = "bottom";
|
|
60
|
+
top = triggerRect.bottom + offset;
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
case "bottom":
|
|
64
|
+
left = triggerRect.left + triggerRect.width / 2 - tooltipWidth / 2;
|
|
65
|
+
top = triggerRect.bottom + offset;
|
|
66
|
+
if (top + tooltipHeight > viewportHeight) {
|
|
67
|
+
finalAlign = "top";
|
|
68
|
+
top = triggerRect.top - tooltipHeight - offset / 2; // Consistent closer positioning
|
|
69
|
+
}
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
// Ensure tooltip doesn't overflow horizontally
|
|
73
|
+
if (left < 0)
|
|
74
|
+
left = 8;
|
|
75
|
+
if (left + tooltipWidth > viewportWidth)
|
|
76
|
+
left = viewportWidth - tooltipWidth - 8;
|
|
77
|
+
// Ensure tooltip doesn't overflow vertically
|
|
78
|
+
if (top < 0)
|
|
79
|
+
top = 8;
|
|
80
|
+
if (top + tooltipHeight > viewportHeight)
|
|
81
|
+
top = viewportHeight - tooltipHeight - 8;
|
|
82
|
+
return { top, left, finalAlign };
|
|
83
|
+
}, [align, offset]);
|
|
84
|
+
const showTooltip = useCallback(() => {
|
|
85
|
+
if (disabled)
|
|
86
|
+
return;
|
|
87
|
+
if (timeoutRef.current) {
|
|
88
|
+
clearTimeout(timeoutRef.current);
|
|
89
|
+
}
|
|
90
|
+
timeoutRef.current = setTimeout(() => {
|
|
91
|
+
setPosition(calculatePosition());
|
|
92
|
+
setIsVisible(true);
|
|
93
|
+
}, trigger === "hover" ? delay : 0);
|
|
94
|
+
}, [disabled, calculatePosition, delay, trigger]);
|
|
95
|
+
const hideTooltip = useCallback(() => {
|
|
96
|
+
if (timeoutRef.current) {
|
|
97
|
+
clearTimeout(timeoutRef.current);
|
|
98
|
+
}
|
|
99
|
+
if (trigger === "hover") {
|
|
100
|
+
timeoutRef.current = setTimeout(() => {
|
|
101
|
+
setIsVisible(false);
|
|
102
|
+
}, 100);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
setIsVisible(false);
|
|
106
|
+
}
|
|
107
|
+
}, [trigger]);
|
|
108
|
+
const handleClick = useCallback(() => {
|
|
109
|
+
if (disabled)
|
|
110
|
+
return;
|
|
111
|
+
if (trigger === "click") {
|
|
112
|
+
if (isVisible) {
|
|
113
|
+
hideTooltip();
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
showTooltip();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}, [disabled, trigger, isVisible, showTooltip, hideTooltip]);
|
|
120
|
+
// Handle click outside
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
const handleClickOutside = (event) => {
|
|
123
|
+
if (trigger === "click" &&
|
|
124
|
+
isVisible &&
|
|
125
|
+
triggerRef.current &&
|
|
126
|
+
tooltipRef.current &&
|
|
127
|
+
!triggerRef.current.contains(event.target) &&
|
|
128
|
+
!tooltipRef.current.contains(event.target)) {
|
|
129
|
+
hideTooltip();
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
133
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
134
|
+
}, [trigger, isVisible, hideTooltip]);
|
|
135
|
+
// Handle escape key
|
|
136
|
+
useEffect(() => {
|
|
137
|
+
const handleEscape = (event) => {
|
|
138
|
+
if (event.key === "Escape" && isVisible) {
|
|
139
|
+
hideTooltip();
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
document.addEventListener("keydown", handleEscape);
|
|
143
|
+
return () => document.removeEventListener("keydown", handleEscape);
|
|
144
|
+
}, [isVisible, hideTooltip]);
|
|
145
|
+
// Recalculate position on scroll/resize
|
|
146
|
+
useEffect(() => {
|
|
147
|
+
const handleReposition = () => {
|
|
148
|
+
if (isVisible) {
|
|
149
|
+
setPosition(calculatePosition());
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
window.addEventListener("scroll", handleReposition, true);
|
|
153
|
+
window.addEventListener("resize", handleReposition);
|
|
154
|
+
return () => {
|
|
155
|
+
window.removeEventListener("scroll", handleReposition, true);
|
|
156
|
+
window.removeEventListener("resize", handleReposition);
|
|
157
|
+
};
|
|
158
|
+
}, [isVisible, calculatePosition]);
|
|
159
|
+
// Cleanup timeout on unmount
|
|
160
|
+
useEffect(() => {
|
|
161
|
+
return () => {
|
|
162
|
+
if (timeoutRef.current) {
|
|
163
|
+
clearTimeout(timeoutRef.current);
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
}, []);
|
|
167
|
+
const tooltipClass = cn(styles.tooltipPortal, className);
|
|
168
|
+
const arrowClass = cn(styles.arrowPortal, styles[`arrow${position.finalAlign.charAt(0).toUpperCase() +
|
|
169
|
+
position.finalAlign.slice(1)}`]);
|
|
170
|
+
const triggerProps = Object.assign(Object.assign({}, (trigger === "hover" && {
|
|
171
|
+
onMouseEnter: showTooltip,
|
|
172
|
+
onMouseLeave: hideTooltip,
|
|
173
|
+
onFocus: showTooltip,
|
|
174
|
+
onBlur: hideTooltip,
|
|
175
|
+
})), (trigger === "click" && {
|
|
176
|
+
onClick: handleClick,
|
|
177
|
+
}));
|
|
178
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", Object.assign({ ref: triggerRef, className: cn(styles.wrapper, disabled && styles.disabled) }, triggerProps, { tabIndex: trigger === "click" ? 0 : undefined, role: trigger === "click" ? "button" : undefined, "aria-describedby": isVisible ? "tooltip" : undefined, children: children ? children : _jsx(IconInfo, {}) })), isVisible &&
|
|
179
|
+
!disabled &&
|
|
180
|
+
createPortal(_jsxs("div", { ref: tooltipRef, id: "tooltip", role: "tooltip", className: tooltipClass, style: {
|
|
181
|
+
position: "fixed",
|
|
182
|
+
top: position.top,
|
|
183
|
+
left: position.left,
|
|
184
|
+
backgroundColor: fillColor,
|
|
185
|
+
borderColor: borderColor,
|
|
186
|
+
borderWidth: "1px",
|
|
187
|
+
color: "var(--color-primary)",
|
|
188
|
+
zIndex: 9999,
|
|
189
|
+
}, onMouseEnter: trigger === "hover" ? showTooltip : undefined, onMouseLeave: trigger === "hover" ? hideTooltip : undefined, children: [_jsx("span", { children: content }), _jsx("div", { className: arrowClass, children: _jsx(IconArrow, { fillColor: fillColor, borderColor: borderColor }) })] }), document.body)] }));
|
|
26
190
|
};
|
|
27
191
|
export default InformationTooltip;
|
|
@@ -4,6 +4,14 @@
|
|
|
4
4
|
@apply relative inline-flex items-center cursor-pointer;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
+
.wrapper:focus {
|
|
8
|
+
@apply outline-none;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.disabled {
|
|
12
|
+
@apply cursor-not-allowed opacity-50;
|
|
13
|
+
}
|
|
14
|
+
|
|
7
15
|
.tooltipContent {
|
|
8
16
|
@apply absolute rounded-[15px] text-sm w-56 px-4 py-3 shadow-md hidden z-10 transition-all duration-300 ease-in-out;
|
|
9
17
|
}
|
|
@@ -20,43 +28,29 @@
|
|
|
20
28
|
@apply block;
|
|
21
29
|
}
|
|
22
30
|
|
|
23
|
-
/*
|
|
24
|
-
.
|
|
25
|
-
|
|
26
|
-
@apply
|
|
31
|
+
/* Portal-based tooltip styles */
|
|
32
|
+
.tooltipPortal {
|
|
33
|
+
@apply rounded-[15px] text-sm w-56 px-4 py-3 shadow-lg border border-solid transition-all duration-200 ease-in-out;
|
|
34
|
+
@apply opacity-100 visible relative;
|
|
27
35
|
}
|
|
28
36
|
|
|
29
|
-
.
|
|
30
|
-
|
|
31
|
-
@apply top-1/2 transform -translate-y-1/2;
|
|
37
|
+
.arrowPortal {
|
|
38
|
+
@apply absolute w-6 h-3;
|
|
32
39
|
}
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
bottom: calc(100% + 19%);
|
|
36
|
-
@apply left-1/2 transform -translate-x-1/2;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.bottomAlign {
|
|
40
|
-
top: calc(100% + 20%);
|
|
41
|
-
@apply left-1/2 transform -translate-x-1/2;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/* Arrow positions */
|
|
41
|
+
/* Arrow positions for portal tooltips */
|
|
45
42
|
.arrowRight {
|
|
46
|
-
left
|
|
47
|
-
@apply top-1/2 transform rotate-90 -translate-x-[100%];
|
|
43
|
+
@apply left-[-18px] top-1/2 transform -translate-y-1/2 rotate-90;
|
|
48
44
|
}
|
|
49
45
|
|
|
50
46
|
.arrowLeft {
|
|
51
|
-
right
|
|
52
|
-
|
|
53
|
-
@apply top-1/2 transform rotate-90 translate-x-[100%];
|
|
47
|
+
@apply right-[-18px] top-1/2 transform -translate-y-1/2 rotate-[270deg];
|
|
54
48
|
}
|
|
55
49
|
|
|
56
50
|
.arrowTop {
|
|
57
|
-
@apply left-1/2 bottom-[
|
|
51
|
+
@apply left-1/2 bottom-[-12px] transform -translate-x-1/2 rotate-0;
|
|
58
52
|
}
|
|
59
53
|
|
|
60
54
|
.arrowBottom {
|
|
61
|
-
@apply left-
|
|
55
|
+
@apply left-1/2 top-[-12px] transform -translate-x-1/2 rotate-180;
|
|
62
56
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -30,10 +30,12 @@ export type { TInputChangeEvent, TTextAreaChangeEvent, TMouseEvent, TFormEvent,
|
|
|
30
30
|
export type { TDomainProperty, TDomainDuration, TDomainInfo, } from "./lib/types/domain";
|
|
31
31
|
export type { TApp } from "./lib/types/app";
|
|
32
32
|
export type { TUser } from "./lib/types/user";
|
|
33
|
+
export type { TAssets } from "./lib/types/assets";
|
|
33
34
|
export type { TApiResponse, TPagination } from "./lib/types/response";
|
|
34
35
|
export type { TInvoiceInfo, TAddressBilling, TAddressPayload, TAddressShipping, TInvoiceData, TInvoiceProduct, TPaymentIssue, TPaymentOption, } from "./lib/types/invoice";
|
|
35
36
|
export { default as countries } from "./lib/utils/country.json";
|
|
36
37
|
export { win, doc, storage } from "./lib/utils/dom";
|
|
38
|
+
export { ASSET_KEYS } from "./lib/constants/index";
|
|
37
39
|
export { setLocalStorage, getLocalStorage } from "./lib/utils/storage";
|
|
38
40
|
export { mkQueryString, mkToken, mkStrongPassword, } from "./lib/utils/StringOperation";
|
|
39
41
|
export { default as StatusColor } from "./lib/utils/statusColor";
|
package/dist/index.js
CHANGED
|
@@ -28,6 +28,7 @@ export { addOption, addOption2 } from "./lib/utils/option";
|
|
|
28
28
|
export { getBikiranUrl, getAccountUrl, getApiUrl, getApi2Url, getApi3Url, getBaseDomain, getSupportUrl, generateAnyUrl, getAdManageUrl, getAppoceanUrl, getDBConnectionString, getDocsUrl, getDomainUrl, getHostingUrl, getSiteUrl, SUB_DOMAIN_NAMES, isDev, getMode, } from "./lib/utils/Env";
|
|
29
29
|
export { default as countries } from "./lib/utils/country.json";
|
|
30
30
|
export { win, doc, storage } from "./lib/utils/dom";
|
|
31
|
+
export { ASSET_KEYS } from "./lib/constants/index";
|
|
31
32
|
export { setLocalStorage, getLocalStorage } from "./lib/utils/storage";
|
|
32
33
|
export { mkQueryString, mkToken, mkStrongPassword, } from "./lib/utils/StringOperation";
|
|
33
34
|
// UI utilities
|
package/dist/index.ts
CHANGED
|
@@ -73,7 +73,8 @@ export type {
|
|
|
73
73
|
export type { TApp } from "./lib/types/app";
|
|
74
74
|
// User types
|
|
75
75
|
export type { TUser } from "./lib/types/user";
|
|
76
|
-
|
|
76
|
+
// Asset keys
|
|
77
|
+
export type { TAssets } from "./lib/types/assets";
|
|
77
78
|
// Response types
|
|
78
79
|
export type { TApiResponse, TPagination } from "./lib/types/response";
|
|
79
80
|
|
|
@@ -90,6 +91,7 @@ export type {
|
|
|
90
91
|
} from "./lib/types/invoice";
|
|
91
92
|
export { default as countries } from "./lib/utils/country.json";
|
|
92
93
|
export { win, doc, storage } from "./lib/utils/dom";
|
|
94
|
+
export { ASSET_KEYS } from "./lib/constants/index";
|
|
93
95
|
export { setLocalStorage, getLocalStorage } from "./lib/utils/storage";
|
|
94
96
|
export {
|
|
95
97
|
mkQueryString,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { TAssets } from "../types/assets";
|
|
2
|
+
|
|
3
|
+
export const ASSET_KEYS: TAssets = {
|
|
4
|
+
domain: "DOMAIN",
|
|
5
|
+
hosting: "HOSTING",
|
|
6
|
+
appOcean: "APPOCEAN",
|
|
7
|
+
proBackup: "PROBACKUP",
|
|
8
|
+
eduSoft: "EDUSOFT",
|
|
9
|
+
push: "PUSH",
|
|
10
|
+
email: "EMAIL",
|
|
11
|
+
founder: "FOUNDER",
|
|
12
|
+
account: "ACCOUNT",
|
|
13
|
+
project: "PROJECT",
|
|
14
|
+
} as const;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|