@ssaprt/tooltip 1.0.0 → 1.0.3
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/README.md +318 -403
- package/dist/index.d.mts +4 -7
- package/dist/index.d.ts +4 -7
- package/dist/index.js +430 -48
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +430 -48
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -372,7 +372,7 @@ var presets = {
|
|
|
372
372
|
animation: animations.bounce
|
|
373
373
|
}),
|
|
374
374
|
hologram: createTheme({
|
|
375
|
-
background: "linear-gradient(115deg, rgba(34, 211, 238, 0.42), rgba(168, 85, 247, 0.35), rgba(236, 72, 153, 0.35), rgba(34, 211, 238, 0.42)),
|
|
375
|
+
background: "linear-gradient(115deg, rgba(34, 211, 238, 0.42), rgba(168, 85, 247, 0.35), rgba(236, 72, 153, 0.35), rgba(34, 211, 238, 0.42)), linear-gradient(135deg, #082f49, #312e81)",
|
|
376
376
|
color: "#ecfeff",
|
|
377
377
|
fontFamily: "Segoe UI, Arial, sans-serif",
|
|
378
378
|
fontSize: "12px",
|
|
@@ -382,25 +382,23 @@ var presets = {
|
|
|
382
382
|
filter: "drop-shadow(0 0 7px rgba(34, 211, 238, 0.75)) drop-shadow(0 0 16px rgba(168, 85, 247, 0.4))",
|
|
383
383
|
padding: "9px 15px",
|
|
384
384
|
letterSpacing: "0.06em",
|
|
385
|
-
backdropFilter: "blur(8px)",
|
|
386
385
|
arrowSize: "8px",
|
|
387
386
|
arrowWidth: "18px",
|
|
388
387
|
animation: animations.blur
|
|
389
388
|
}),
|
|
390
389
|
glass: createTheme({
|
|
391
|
-
background: "linear-gradient(135deg, rgba(255, 255, 255, 0.22), rgba(255, 255, 255, 0.07)),
|
|
390
|
+
background: "linear-gradient(135deg, rgba(255, 255, 255, 0.22), rgba(255, 255, 255, 0.07)), linear-gradient(135deg, #1e293b, #0f172a)",
|
|
392
391
|
color: "#f8fafc",
|
|
393
392
|
border: "1px solid rgba(255, 255, 255, 0.34)",
|
|
394
393
|
borderRadius: "16px",
|
|
395
394
|
filter: "drop-shadow(0 12px 20px rgba(15, 23, 42, 0.38))",
|
|
396
395
|
padding: "9px 15px",
|
|
397
|
-
backdropFilter: "blur(16px)",
|
|
398
396
|
arrowSize: "8px",
|
|
399
397
|
arrowWidth: "18px",
|
|
400
398
|
animation: animations.blur
|
|
401
399
|
}),
|
|
402
400
|
frost: createTheme({
|
|
403
|
-
background: "radial-gradient(circle at 15% 20%, rgba(255, 255, 255, 0.85), transparent 35%), linear-gradient(135deg,
|
|
401
|
+
background: "radial-gradient(circle at 15% 20%, rgba(255, 255, 255, 0.85), transparent 35%), linear-gradient(135deg, #e0f2fe, #bae6fd)",
|
|
404
402
|
color: "#075985",
|
|
405
403
|
fontWeight: 600,
|
|
406
404
|
border: "1px solid rgba(125, 211, 252, 0.9)",
|
|
@@ -408,7 +406,6 @@ var presets = {
|
|
|
408
406
|
filter: "drop-shadow(0 8px 15px rgba(14, 116, 144, 0.24))",
|
|
409
407
|
padding: "9px 15px",
|
|
410
408
|
textShadow: "0 1px 0 rgba(255, 255, 255, 0.8)",
|
|
411
|
-
backdropFilter: "blur(14px)",
|
|
412
409
|
arrowSize: "8px",
|
|
413
410
|
arrowWidth: "19px",
|
|
414
411
|
animation: animations.blur
|
|
@@ -773,7 +770,6 @@ var presets = {
|
|
|
773
770
|
borderRadius: "20px 8px 20px 8px",
|
|
774
771
|
filter: "drop-shadow(0 10px 17px rgba(49, 46, 129, 0.48))",
|
|
775
772
|
padding: "10px 16px",
|
|
776
|
-
backdropFilter: "blur(8px)",
|
|
777
773
|
arrowSize: "9px",
|
|
778
774
|
arrowWidth: "21px",
|
|
779
775
|
animation: animations.blur
|
|
@@ -960,6 +956,13 @@ var VIEWPORT_PADDING = 8;
|
|
|
960
956
|
var DEFAULT_ARROW_SIZE = 6;
|
|
961
957
|
var DEFAULT_TOOLTIP_GAP = 10;
|
|
962
958
|
var ARROW_EDGE_OFFSET = 10;
|
|
959
|
+
var INTERACTIVE_DIRECT_PADDING = 4;
|
|
960
|
+
var INTERACTIVE_BRIDGE_PADDING = 8;
|
|
961
|
+
var INTERACTIVE_BRIDGE_TIMEOUT = 700;
|
|
962
|
+
var INTERACTIVE_RECHECK_INTERVAL = 50;
|
|
963
|
+
var TOUCH_MOVE_THRESHOLD = 10;
|
|
964
|
+
var TOUCH_MAX_TAP_DURATION = 600;
|
|
965
|
+
var TOUCH_FOCUS_SUPPRESSION = 700;
|
|
963
966
|
var oppositePlacement = {
|
|
964
967
|
top: "bottom",
|
|
965
968
|
bottom: "top",
|
|
@@ -970,6 +973,112 @@ var clamp = (value, min, max) => {
|
|
|
970
973
|
const resolvedMax = Math.max(min, max);
|
|
971
974
|
return Math.min(Math.max(value, min), resolvedMax);
|
|
972
975
|
};
|
|
976
|
+
var isPointInsideRect = (point, rect, padding = 0) => {
|
|
977
|
+
return point.x >= rect.left - padding && point.x <= rect.right + padding && point.y >= rect.top - padding && point.y <= rect.bottom + padding;
|
|
978
|
+
};
|
|
979
|
+
var isPointOnSegment = (point, start, end) => {
|
|
980
|
+
const cross = (point.y - start.y) * (end.x - start.x) - (point.x - start.x) * (end.y - start.y);
|
|
981
|
+
if (Math.abs(cross) > 1e-3) {
|
|
982
|
+
return false;
|
|
983
|
+
}
|
|
984
|
+
return point.x >= Math.min(start.x, end.x) && point.x <= Math.max(start.x, end.x) && point.y >= Math.min(start.y, end.y) && point.y <= Math.max(start.y, end.y);
|
|
985
|
+
};
|
|
986
|
+
var isPointInsidePolygon = (point, polygon) => {
|
|
987
|
+
let inside = false;
|
|
988
|
+
for (let currentIndex = 0, previousIndex = polygon.length - 1; currentIndex < polygon.length; previousIndex = currentIndex, currentIndex += 1) {
|
|
989
|
+
const current = polygon[currentIndex];
|
|
990
|
+
const previous = polygon[previousIndex];
|
|
991
|
+
if (isPointOnSegment(point, previous, current)) {
|
|
992
|
+
return true;
|
|
993
|
+
}
|
|
994
|
+
const crosses = current.y > point.y !== previous.y > point.y && point.x < (previous.x - current.x) * (point.y - current.y) / (previous.y - current.y) + current.x;
|
|
995
|
+
if (crosses) {
|
|
996
|
+
inside = !inside;
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
return inside;
|
|
1000
|
+
};
|
|
1001
|
+
var createInteractiveBridge = (anchorRect, tooltipRect, placement) => {
|
|
1002
|
+
const padding = INTERACTIVE_BRIDGE_PADDING;
|
|
1003
|
+
if (placement === "top") {
|
|
1004
|
+
return [
|
|
1005
|
+
{
|
|
1006
|
+
x: tooltipRect.left - padding,
|
|
1007
|
+
y: tooltipRect.bottom - padding
|
|
1008
|
+
},
|
|
1009
|
+
{
|
|
1010
|
+
x: tooltipRect.right + padding,
|
|
1011
|
+
y: tooltipRect.bottom - padding
|
|
1012
|
+
},
|
|
1013
|
+
{
|
|
1014
|
+
x: anchorRect.right + padding,
|
|
1015
|
+
y: anchorRect.top + padding
|
|
1016
|
+
},
|
|
1017
|
+
{
|
|
1018
|
+
x: anchorRect.left - padding,
|
|
1019
|
+
y: anchorRect.top + padding
|
|
1020
|
+
}
|
|
1021
|
+
];
|
|
1022
|
+
}
|
|
1023
|
+
if (placement === "bottom") {
|
|
1024
|
+
return [
|
|
1025
|
+
{
|
|
1026
|
+
x: anchorRect.left - padding,
|
|
1027
|
+
y: anchorRect.bottom - padding
|
|
1028
|
+
},
|
|
1029
|
+
{
|
|
1030
|
+
x: anchorRect.right + padding,
|
|
1031
|
+
y: anchorRect.bottom - padding
|
|
1032
|
+
},
|
|
1033
|
+
{
|
|
1034
|
+
x: tooltipRect.right + padding,
|
|
1035
|
+
y: tooltipRect.top + padding
|
|
1036
|
+
},
|
|
1037
|
+
{
|
|
1038
|
+
x: tooltipRect.left - padding,
|
|
1039
|
+
y: tooltipRect.top + padding
|
|
1040
|
+
}
|
|
1041
|
+
];
|
|
1042
|
+
}
|
|
1043
|
+
if (placement === "left") {
|
|
1044
|
+
return [
|
|
1045
|
+
{
|
|
1046
|
+
x: tooltipRect.right - padding,
|
|
1047
|
+
y: tooltipRect.top - padding
|
|
1048
|
+
},
|
|
1049
|
+
{
|
|
1050
|
+
x: anchorRect.left + padding,
|
|
1051
|
+
y: anchorRect.top - padding
|
|
1052
|
+
},
|
|
1053
|
+
{
|
|
1054
|
+
x: anchorRect.left + padding,
|
|
1055
|
+
y: anchorRect.bottom + padding
|
|
1056
|
+
},
|
|
1057
|
+
{
|
|
1058
|
+
x: tooltipRect.right - padding,
|
|
1059
|
+
y: tooltipRect.bottom + padding
|
|
1060
|
+
}
|
|
1061
|
+
];
|
|
1062
|
+
}
|
|
1063
|
+
return [
|
|
1064
|
+
{
|
|
1065
|
+
x: anchorRect.right - padding,
|
|
1066
|
+
y: anchorRect.top - padding
|
|
1067
|
+
},
|
|
1068
|
+
{
|
|
1069
|
+
x: tooltipRect.left + padding,
|
|
1070
|
+
y: tooltipRect.top - padding
|
|
1071
|
+
},
|
|
1072
|
+
{
|
|
1073
|
+
x: tooltipRect.left + padding,
|
|
1074
|
+
y: tooltipRect.bottom + padding
|
|
1075
|
+
},
|
|
1076
|
+
{
|
|
1077
|
+
x: anchorRect.right - padding,
|
|
1078
|
+
y: anchorRect.bottom + padding
|
|
1079
|
+
}
|
|
1080
|
+
];
|
|
1081
|
+
};
|
|
973
1082
|
var useTooltip = ({
|
|
974
1083
|
anchor,
|
|
975
1084
|
preferredPlacement,
|
|
@@ -982,8 +1091,17 @@ var useTooltip = ({
|
|
|
982
1091
|
const hideTimerRef = (0, import_react.useRef)(null);
|
|
983
1092
|
const firstFrameRef = (0, import_react.useRef)(null);
|
|
984
1093
|
const secondFrameRef = (0, import_react.useRef)(null);
|
|
1094
|
+
const interactiveFrameRef = (0, import_react.useRef)(null);
|
|
985
1095
|
const phaseRef = (0, import_react.useRef)("hidden");
|
|
986
1096
|
const pendingHideRef = (0, import_react.useRef)(false);
|
|
1097
|
+
const interactiveBridgeDeadlineRef = (0, import_react.useRef)(0);
|
|
1098
|
+
const pointerRef = (0, import_react.useRef)({
|
|
1099
|
+
x: Number.NaN,
|
|
1100
|
+
y: Number.NaN,
|
|
1101
|
+
pointerType: ""
|
|
1102
|
+
});
|
|
1103
|
+
const touchGestureRef = (0, import_react.useRef)(null);
|
|
1104
|
+
const suppressFocusUntilRef = (0, import_react.useRef)(0);
|
|
987
1105
|
const [mounted, setMounted] = (0, import_react.useState)(false);
|
|
988
1106
|
const [phase, setPhase] = (0, import_react.useState)("hidden");
|
|
989
1107
|
const [placement, setPlacement] = (0, import_react.useState)(preferredPlacement);
|
|
@@ -1015,6 +1133,13 @@ var useTooltip = ({
|
|
|
1015
1133
|
secondFrameRef.current = null;
|
|
1016
1134
|
}
|
|
1017
1135
|
}, []);
|
|
1136
|
+
const clearInteractiveFrame = (0, import_react.useCallback)(() => {
|
|
1137
|
+
if (interactiveFrameRef.current === null) {
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1140
|
+
window.cancelAnimationFrame(interactiveFrameRef.current);
|
|
1141
|
+
interactiveFrameRef.current = null;
|
|
1142
|
+
}, []);
|
|
1018
1143
|
const getAvailableSpace = (0, import_react.useCallback)(
|
|
1019
1144
|
(currentPlacement, rect) => {
|
|
1020
1145
|
switch (currentPlacement) {
|
|
@@ -1054,10 +1179,7 @@ var useTooltip = ({
|
|
|
1054
1179
|
}
|
|
1055
1180
|
return bodyWidth + distance;
|
|
1056
1181
|
};
|
|
1057
|
-
const preferredAvailable = getAvailableSpace(
|
|
1058
|
-
preferredPlacement,
|
|
1059
|
-
rect
|
|
1060
|
-
);
|
|
1182
|
+
const preferredAvailable = getAvailableSpace(preferredPlacement, rect);
|
|
1061
1183
|
const preferredRequired = getRequiredSpace(preferredPlacement);
|
|
1062
1184
|
let nextPlacement = preferredPlacement;
|
|
1063
1185
|
if (preferredAvailable < preferredRequired) {
|
|
@@ -1115,12 +1237,61 @@ var useTooltip = ({
|
|
|
1115
1237
|
"--tooltip-arrow-offset": arrowOffset
|
|
1116
1238
|
});
|
|
1117
1239
|
}, [anchor, getAvailableSpace, preferredPlacement]);
|
|
1240
|
+
const isFocusInsideTooltipRegion = (0, import_react.useCallback)(() => {
|
|
1241
|
+
if (!anchor || typeof document === "undefined") {
|
|
1242
|
+
return false;
|
|
1243
|
+
}
|
|
1244
|
+
const activeElement = document.activeElement;
|
|
1245
|
+
const tooltip = tooltipRef.current;
|
|
1246
|
+
if (!(activeElement instanceof Node)) {
|
|
1247
|
+
return false;
|
|
1248
|
+
}
|
|
1249
|
+
if (interactive && tooltip?.contains(activeElement)) {
|
|
1250
|
+
return true;
|
|
1251
|
+
}
|
|
1252
|
+
return anchor.contains(activeElement) && activeElement instanceof Element && activeElement.matches(":focus-visible");
|
|
1253
|
+
}, [anchor, interactive]);
|
|
1254
|
+
const getInteractivePointerArea = (0, import_react.useCallback)(() => {
|
|
1255
|
+
if (!interactive || !anchor) {
|
|
1256
|
+
return "outside";
|
|
1257
|
+
}
|
|
1258
|
+
const pointer = pointerRef.current;
|
|
1259
|
+
const tooltip = tooltipRef.current;
|
|
1260
|
+
if (!tooltip || pointer.pointerType !== "mouse" && pointer.pointerType !== "pen" || !Number.isFinite(pointer.x) || !Number.isFinite(pointer.y)) {
|
|
1261
|
+
return "outside";
|
|
1262
|
+
}
|
|
1263
|
+
const point = {
|
|
1264
|
+
x: pointer.x,
|
|
1265
|
+
y: pointer.y
|
|
1266
|
+
};
|
|
1267
|
+
const anchorRect = anchor.getBoundingClientRect();
|
|
1268
|
+
const tooltipRect = tooltip.getBoundingClientRect();
|
|
1269
|
+
if (isPointInsideRect(
|
|
1270
|
+
point,
|
|
1271
|
+
anchorRect,
|
|
1272
|
+
INTERACTIVE_DIRECT_PADDING
|
|
1273
|
+
) || isPointInsideRect(
|
|
1274
|
+
point,
|
|
1275
|
+
tooltipRect,
|
|
1276
|
+
INTERACTIVE_DIRECT_PADDING
|
|
1277
|
+
)) {
|
|
1278
|
+
return "direct";
|
|
1279
|
+
}
|
|
1280
|
+
const bridge = createInteractiveBridge(
|
|
1281
|
+
anchorRect,
|
|
1282
|
+
tooltipRect,
|
|
1283
|
+
placement
|
|
1284
|
+
);
|
|
1285
|
+
return isPointInsidePolygon(point, bridge) ? "bridge" : "outside";
|
|
1286
|
+
}, [anchor, interactive, placement]);
|
|
1118
1287
|
const removeTooltip = (0, import_react.useCallback)(() => {
|
|
1119
1288
|
clearHideTimer();
|
|
1120
1289
|
clearEnterFrames();
|
|
1290
|
+
clearInteractiveFrame();
|
|
1121
1291
|
pendingHideRef.current = false;
|
|
1292
|
+
interactiveBridgeDeadlineRef.current = 0;
|
|
1122
1293
|
updatePhase("hidden");
|
|
1123
|
-
}, [clearEnterFrames, clearHideTimer, updatePhase]);
|
|
1294
|
+
}, [clearEnterFrames, clearHideTimer, clearInteractiveFrame, updatePhase]);
|
|
1124
1295
|
const runHide = (0, import_react.useCallback)(() => {
|
|
1125
1296
|
const currentPhase = phaseRef.current;
|
|
1126
1297
|
if (currentPhase === "hidden" || currentPhase === "leaving") {
|
|
@@ -1138,17 +1309,61 @@ var useTooltip = ({
|
|
|
1138
1309
|
}, [removeTooltip, updatePhase]);
|
|
1139
1310
|
const hideTooltip = (0, import_react.useCallback)(
|
|
1140
1311
|
(immediate = false) => {
|
|
1141
|
-
clearHideTimer();
|
|
1142
1312
|
if (immediate) {
|
|
1313
|
+
clearHideTimer();
|
|
1314
|
+
interactiveBridgeDeadlineRef.current = 0;
|
|
1143
1315
|
runHide();
|
|
1144
1316
|
return;
|
|
1145
1317
|
}
|
|
1146
|
-
hideTimerRef.current
|
|
1318
|
+
if (hideTimerRef.current !== null) {
|
|
1319
|
+
return;
|
|
1320
|
+
}
|
|
1321
|
+
const attemptHide = () => {
|
|
1147
1322
|
hideTimerRef.current = null;
|
|
1323
|
+
if (isFocusInsideTooltipRegion()) {
|
|
1324
|
+
interactiveBridgeDeadlineRef.current = 0;
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
if (interactive) {
|
|
1328
|
+
const pointerArea = getInteractivePointerArea();
|
|
1329
|
+
if (pointerArea === "direct") {
|
|
1330
|
+
interactiveBridgeDeadlineRef.current = 0;
|
|
1331
|
+
return;
|
|
1332
|
+
}
|
|
1333
|
+
if (pointerArea === "bridge") {
|
|
1334
|
+
const now = window.performance.now();
|
|
1335
|
+
if (interactiveBridgeDeadlineRef.current === 0) {
|
|
1336
|
+
interactiveBridgeDeadlineRef.current = now + INTERACTIVE_BRIDGE_TIMEOUT;
|
|
1337
|
+
}
|
|
1338
|
+
const remaining = interactiveBridgeDeadlineRef.current - now;
|
|
1339
|
+
if (remaining > 0) {
|
|
1340
|
+
hideTimerRef.current = window.setTimeout(
|
|
1341
|
+
attemptHide,
|
|
1342
|
+
Math.min(
|
|
1343
|
+
INTERACTIVE_RECHECK_INTERVAL,
|
|
1344
|
+
remaining
|
|
1345
|
+
)
|
|
1346
|
+
);
|
|
1347
|
+
return;
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
interactiveBridgeDeadlineRef.current = 0;
|
|
1148
1352
|
runHide();
|
|
1149
|
-
}
|
|
1353
|
+
};
|
|
1354
|
+
hideTimerRef.current = window.setTimeout(
|
|
1355
|
+
attemptHide,
|
|
1356
|
+
resolvedHideDelay
|
|
1357
|
+
);
|
|
1150
1358
|
},
|
|
1151
|
-
[
|
|
1359
|
+
[
|
|
1360
|
+
clearHideTimer,
|
|
1361
|
+
getInteractivePointerArea,
|
|
1362
|
+
interactive,
|
|
1363
|
+
isFocusInsideTooltipRegion,
|
|
1364
|
+
resolvedHideDelay,
|
|
1365
|
+
runHide
|
|
1366
|
+
]
|
|
1152
1367
|
);
|
|
1153
1368
|
const showTooltip = (0, import_react.useCallback)(() => {
|
|
1154
1369
|
if (!anchor || disabled) {
|
|
@@ -1156,6 +1371,7 @@ var useTooltip = ({
|
|
|
1156
1371
|
}
|
|
1157
1372
|
clearHideTimer();
|
|
1158
1373
|
clearEnterFrames();
|
|
1374
|
+
interactiveBridgeDeadlineRef.current = 0;
|
|
1159
1375
|
pendingHideRef.current = false;
|
|
1160
1376
|
setMounted(true);
|
|
1161
1377
|
if (phaseRef.current === "entering" || phaseRef.current === "visible") {
|
|
@@ -1169,11 +1385,51 @@ var useTooltip = ({
|
|
|
1169
1385
|
return;
|
|
1170
1386
|
}
|
|
1171
1387
|
clearHideTimer();
|
|
1388
|
+
interactiveBridgeDeadlineRef.current = 0;
|
|
1172
1389
|
pendingHideRef.current = false;
|
|
1173
1390
|
if (phaseRef.current === "leaving") {
|
|
1174
1391
|
updatePhase("visible");
|
|
1175
1392
|
}
|
|
1176
1393
|
}, [clearHideTimer, disabled, interactive, updatePhase]);
|
|
1394
|
+
const processInteractivePointer = (0, import_react.useCallback)(() => {
|
|
1395
|
+
if (!interactive || disabled || phaseRef.current === "hidden") {
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
if (isFocusInsideTooltipRegion()) {
|
|
1399
|
+
keepTooltipOpen();
|
|
1400
|
+
return;
|
|
1401
|
+
}
|
|
1402
|
+
const pointerArea = getInteractivePointerArea();
|
|
1403
|
+
if (pointerArea === "direct") {
|
|
1404
|
+
keepTooltipOpen();
|
|
1405
|
+
return;
|
|
1406
|
+
}
|
|
1407
|
+
if (pointerArea === "bridge") {
|
|
1408
|
+
if (interactiveBridgeDeadlineRef.current === 0) {
|
|
1409
|
+
interactiveBridgeDeadlineRef.current = window.performance.now() + INTERACTIVE_BRIDGE_TIMEOUT;
|
|
1410
|
+
}
|
|
1411
|
+
hideTooltip(false);
|
|
1412
|
+
return;
|
|
1413
|
+
}
|
|
1414
|
+
interactiveBridgeDeadlineRef.current = 0;
|
|
1415
|
+
hideTooltip(false);
|
|
1416
|
+
}, [
|
|
1417
|
+
disabled,
|
|
1418
|
+
getInteractivePointerArea,
|
|
1419
|
+
hideTooltip,
|
|
1420
|
+
interactive,
|
|
1421
|
+
isFocusInsideTooltipRegion,
|
|
1422
|
+
keepTooltipOpen
|
|
1423
|
+
]);
|
|
1424
|
+
const scheduleInteractivePointerProcessing = (0, import_react.useCallback)(() => {
|
|
1425
|
+
if (interactiveFrameRef.current !== null) {
|
|
1426
|
+
return;
|
|
1427
|
+
}
|
|
1428
|
+
interactiveFrameRef.current = window.requestAnimationFrame(() => {
|
|
1429
|
+
interactiveFrameRef.current = null;
|
|
1430
|
+
processInteractivePointer();
|
|
1431
|
+
});
|
|
1432
|
+
}, [processInteractivePointer]);
|
|
1177
1433
|
const onAnimationEnd = (0, import_react.useCallback)(() => {
|
|
1178
1434
|
const currentPhase = phaseRef.current;
|
|
1179
1435
|
if (currentPhase === "entering") {
|
|
@@ -1218,35 +1474,112 @@ var useTooltip = ({
|
|
|
1218
1474
|
removeTooltip();
|
|
1219
1475
|
return;
|
|
1220
1476
|
}
|
|
1477
|
+
const updatePointer = (event) => {
|
|
1478
|
+
pointerRef.current = {
|
|
1479
|
+
x: event.clientX,
|
|
1480
|
+
y: event.clientY,
|
|
1481
|
+
pointerType: event.pointerType
|
|
1482
|
+
};
|
|
1483
|
+
};
|
|
1221
1484
|
const onPointerEnter = (event) => {
|
|
1485
|
+
updatePointer(event);
|
|
1222
1486
|
if (event.pointerType === "touch") {
|
|
1223
1487
|
return;
|
|
1224
1488
|
}
|
|
1225
1489
|
showTooltip();
|
|
1226
1490
|
};
|
|
1227
1491
|
const onPointerLeave = (event) => {
|
|
1492
|
+
updatePointer(event);
|
|
1228
1493
|
if (event.pointerType === "touch") {
|
|
1229
1494
|
return;
|
|
1230
1495
|
}
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1496
|
+
if (interactive) {
|
|
1497
|
+
interactiveBridgeDeadlineRef.current = window.performance.now() + INTERACTIVE_BRIDGE_TIMEOUT;
|
|
1498
|
+
hideTooltip(false);
|
|
1499
|
+
scheduleInteractivePointerProcessing();
|
|
1235
1500
|
return;
|
|
1236
1501
|
}
|
|
1237
1502
|
hideTooltip(false);
|
|
1238
1503
|
};
|
|
1239
1504
|
const onPointerDown = (event) => {
|
|
1505
|
+
updatePointer(event);
|
|
1506
|
+
if (event.pointerType !== "touch") {
|
|
1507
|
+
return;
|
|
1508
|
+
}
|
|
1509
|
+
const now = window.performance.now();
|
|
1510
|
+
touchGestureRef.current = {
|
|
1511
|
+
pointerId: event.pointerId,
|
|
1512
|
+
startX: event.clientX,
|
|
1513
|
+
startY: event.clientY,
|
|
1514
|
+
startedAt: now,
|
|
1515
|
+
moved: false,
|
|
1516
|
+
cancelled: false
|
|
1517
|
+
};
|
|
1518
|
+
suppressFocusUntilRef.current = now + TOUCH_FOCUS_SUPPRESSION;
|
|
1519
|
+
};
|
|
1520
|
+
const onPointerMove = (event) => {
|
|
1521
|
+
updatePointer(event);
|
|
1522
|
+
if (event.pointerType !== "touch") {
|
|
1523
|
+
return;
|
|
1524
|
+
}
|
|
1525
|
+
const gesture = touchGestureRef.current;
|
|
1526
|
+
if (!gesture || gesture.pointerId !== event.pointerId) {
|
|
1527
|
+
return;
|
|
1528
|
+
}
|
|
1529
|
+
const distance = Math.hypot(
|
|
1530
|
+
event.clientX - gesture.startX,
|
|
1531
|
+
event.clientY - gesture.startY
|
|
1532
|
+
);
|
|
1533
|
+
if (distance <= TOUCH_MOVE_THRESHOLD) {
|
|
1534
|
+
return;
|
|
1535
|
+
}
|
|
1536
|
+
gesture.moved = true;
|
|
1537
|
+
suppressFocusUntilRef.current = window.performance.now() + TOUCH_FOCUS_SUPPRESSION;
|
|
1538
|
+
hideTooltip(true);
|
|
1539
|
+
};
|
|
1540
|
+
const onPointerUp = (event) => {
|
|
1541
|
+
updatePointer(event);
|
|
1240
1542
|
if (event.pointerType !== "touch") {
|
|
1241
1543
|
return;
|
|
1242
1544
|
}
|
|
1545
|
+
const gesture = touchGestureRef.current;
|
|
1546
|
+
touchGestureRef.current = null;
|
|
1547
|
+
if (!gesture || gesture.pointerId !== event.pointerId) {
|
|
1548
|
+
return;
|
|
1549
|
+
}
|
|
1550
|
+
const now = window.performance.now();
|
|
1551
|
+
const distance = Math.hypot(
|
|
1552
|
+
event.clientX - gesture.startX,
|
|
1553
|
+
event.clientY - gesture.startY
|
|
1554
|
+
);
|
|
1555
|
+
const duration = now - gesture.startedAt;
|
|
1556
|
+
suppressFocusUntilRef.current = now + TOUCH_FOCUS_SUPPRESSION;
|
|
1557
|
+
if (gesture.cancelled || gesture.moved || distance > TOUCH_MOVE_THRESHOLD || duration > TOUCH_MAX_TAP_DURATION) {
|
|
1558
|
+
return;
|
|
1559
|
+
}
|
|
1243
1560
|
if (phaseRef.current === "hidden" || phaseRef.current === "leaving") {
|
|
1244
1561
|
showTooltip();
|
|
1245
1562
|
} else {
|
|
1246
1563
|
hideTooltip(true);
|
|
1247
1564
|
}
|
|
1248
1565
|
};
|
|
1566
|
+
const onPointerCancel = (event) => {
|
|
1567
|
+
if (event.pointerType !== "touch") {
|
|
1568
|
+
return;
|
|
1569
|
+
}
|
|
1570
|
+
const gesture = touchGestureRef.current;
|
|
1571
|
+
if (!gesture || gesture.pointerId !== event.pointerId) {
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1574
|
+
gesture.cancelled = true;
|
|
1575
|
+
touchGestureRef.current = null;
|
|
1576
|
+
suppressFocusUntilRef.current = window.performance.now() + TOUCH_FOCUS_SUPPRESSION;
|
|
1577
|
+
hideTooltip(true);
|
|
1578
|
+
};
|
|
1249
1579
|
const onFocusIn = () => {
|
|
1580
|
+
if (window.performance.now() < suppressFocusUntilRef.current) {
|
|
1581
|
+
return;
|
|
1582
|
+
}
|
|
1250
1583
|
showTooltip();
|
|
1251
1584
|
};
|
|
1252
1585
|
const onFocusOut = (event) => {
|
|
@@ -1260,51 +1593,66 @@ var useTooltip = ({
|
|
|
1260
1593
|
anchor.addEventListener("pointerenter", onPointerEnter);
|
|
1261
1594
|
anchor.addEventListener("pointerleave", onPointerLeave);
|
|
1262
1595
|
anchor.addEventListener("pointerdown", onPointerDown);
|
|
1596
|
+
anchor.addEventListener("pointermove", onPointerMove);
|
|
1597
|
+
anchor.addEventListener("pointerup", onPointerUp);
|
|
1598
|
+
anchor.addEventListener("pointercancel", onPointerCancel);
|
|
1263
1599
|
anchor.addEventListener("focusin", onFocusIn);
|
|
1264
1600
|
anchor.addEventListener("focusout", onFocusOut);
|
|
1265
1601
|
return () => {
|
|
1266
1602
|
anchor.removeEventListener("pointerenter", onPointerEnter);
|
|
1267
1603
|
anchor.removeEventListener("pointerleave", onPointerLeave);
|
|
1268
1604
|
anchor.removeEventListener("pointerdown", onPointerDown);
|
|
1605
|
+
anchor.removeEventListener("pointermove", onPointerMove);
|
|
1606
|
+
anchor.removeEventListener("pointerup", onPointerUp);
|
|
1607
|
+
anchor.removeEventListener("pointercancel", onPointerCancel);
|
|
1269
1608
|
anchor.removeEventListener("focusin", onFocusIn);
|
|
1270
1609
|
anchor.removeEventListener("focusout", onFocusOut);
|
|
1610
|
+
touchGestureRef.current = null;
|
|
1271
1611
|
clearHideTimer();
|
|
1272
1612
|
clearEnterFrames();
|
|
1613
|
+
clearInteractiveFrame();
|
|
1273
1614
|
};
|
|
1274
1615
|
}, [
|
|
1275
1616
|
anchor,
|
|
1276
1617
|
clearEnterFrames,
|
|
1277
1618
|
clearHideTimer,
|
|
1619
|
+
clearInteractiveFrame,
|
|
1278
1620
|
hideTooltip,
|
|
1279
1621
|
interactive,
|
|
1280
|
-
keepTooltipOpen,
|
|
1281
1622
|
removeTooltip,
|
|
1623
|
+
scheduleInteractivePointerProcessing,
|
|
1282
1624
|
showTooltip
|
|
1283
1625
|
]);
|
|
1284
1626
|
(0, import_react.useEffect)(() => {
|
|
1285
|
-
if (!interactive ||
|
|
1627
|
+
if (!interactive || phase === "hidden") {
|
|
1286
1628
|
return;
|
|
1287
1629
|
}
|
|
1288
1630
|
const tooltip = tooltipRef.current;
|
|
1289
1631
|
if (!tooltip) {
|
|
1290
1632
|
return;
|
|
1291
1633
|
}
|
|
1634
|
+
const updatePointer = (event) => {
|
|
1635
|
+
pointerRef.current = {
|
|
1636
|
+
x: event.clientX,
|
|
1637
|
+
y: event.clientY,
|
|
1638
|
+
pointerType: event.pointerType
|
|
1639
|
+
};
|
|
1640
|
+
};
|
|
1292
1641
|
const onPointerEnter = (event) => {
|
|
1642
|
+
updatePointer(event);
|
|
1293
1643
|
if (event.pointerType === "touch") {
|
|
1294
1644
|
return;
|
|
1295
1645
|
}
|
|
1296
1646
|
keepTooltipOpen();
|
|
1297
1647
|
};
|
|
1298
1648
|
const onPointerLeave = (event) => {
|
|
1649
|
+
updatePointer(event);
|
|
1299
1650
|
if (event.pointerType === "touch") {
|
|
1300
1651
|
return;
|
|
1301
1652
|
}
|
|
1302
|
-
|
|
1303
|
-
if (relatedTarget instanceof Node && anchor?.contains(relatedTarget)) {
|
|
1304
|
-
keepTooltipOpen();
|
|
1305
|
-
return;
|
|
1306
|
-
}
|
|
1653
|
+
interactiveBridgeDeadlineRef.current = window.performance.now() + INTERACTIVE_BRIDGE_TIMEOUT;
|
|
1307
1654
|
hideTooltip(false);
|
|
1655
|
+
scheduleInteractivePointerProcessing();
|
|
1308
1656
|
};
|
|
1309
1657
|
const onFocusIn = () => {
|
|
1310
1658
|
keepTooltipOpen();
|
|
@@ -1331,7 +1679,36 @@ var useTooltip = ({
|
|
|
1331
1679
|
hideTooltip,
|
|
1332
1680
|
interactive,
|
|
1333
1681
|
keepTooltipOpen,
|
|
1334
|
-
|
|
1682
|
+
phase,
|
|
1683
|
+
scheduleInteractivePointerProcessing
|
|
1684
|
+
]);
|
|
1685
|
+
(0, import_react.useEffect)(() => {
|
|
1686
|
+
if (!interactive || phase === "hidden") {
|
|
1687
|
+
return;
|
|
1688
|
+
}
|
|
1689
|
+
const onDocumentPointerMove = (event) => {
|
|
1690
|
+
if (event.pointerType === "touch") {
|
|
1691
|
+
return;
|
|
1692
|
+
}
|
|
1693
|
+
pointerRef.current = {
|
|
1694
|
+
x: event.clientX,
|
|
1695
|
+
y: event.clientY,
|
|
1696
|
+
pointerType: event.pointerType
|
|
1697
|
+
};
|
|
1698
|
+
scheduleInteractivePointerProcessing();
|
|
1699
|
+
};
|
|
1700
|
+
document.addEventListener("pointermove", onDocumentPointerMove, {
|
|
1701
|
+
passive: true
|
|
1702
|
+
});
|
|
1703
|
+
return () => {
|
|
1704
|
+
document.removeEventListener("pointermove", onDocumentPointerMove);
|
|
1705
|
+
clearInteractiveFrame();
|
|
1706
|
+
};
|
|
1707
|
+
}, [
|
|
1708
|
+
clearInteractiveFrame,
|
|
1709
|
+
interactive,
|
|
1710
|
+
phase,
|
|
1711
|
+
scheduleInteractivePointerProcessing
|
|
1335
1712
|
]);
|
|
1336
1713
|
(0, import_react.useEffect)(() => {
|
|
1337
1714
|
if (!anchor || phase === "hidden") {
|
|
@@ -1343,6 +1720,7 @@ var useTooltip = ({
|
|
|
1343
1720
|
if (target instanceof Node && (anchor.contains(target) || interactive && tooltip?.contains(target))) {
|
|
1344
1721
|
return;
|
|
1345
1722
|
}
|
|
1723
|
+
touchGestureRef.current = null;
|
|
1346
1724
|
hideTooltip(true);
|
|
1347
1725
|
};
|
|
1348
1726
|
const onKeyDown = (event) => {
|
|
@@ -1350,11 +1728,7 @@ var useTooltip = ({
|
|
|
1350
1728
|
hideTooltip(true);
|
|
1351
1729
|
}
|
|
1352
1730
|
};
|
|
1353
|
-
document.addEventListener(
|
|
1354
|
-
"pointerdown",
|
|
1355
|
-
onDocumentPointerDown,
|
|
1356
|
-
true
|
|
1357
|
-
);
|
|
1731
|
+
document.addEventListener("pointerdown", onDocumentPointerDown, true);
|
|
1358
1732
|
document.addEventListener("keydown", onKeyDown);
|
|
1359
1733
|
window.addEventListener("resize", calculatePosition);
|
|
1360
1734
|
window.addEventListener("scroll", calculatePosition, true);
|
|
@@ -1368,13 +1742,7 @@ var useTooltip = ({
|
|
|
1368
1742
|
window.removeEventListener("resize", calculatePosition);
|
|
1369
1743
|
window.removeEventListener("scroll", calculatePosition, true);
|
|
1370
1744
|
};
|
|
1371
|
-
}, [
|
|
1372
|
-
anchor,
|
|
1373
|
-
calculatePosition,
|
|
1374
|
-
hideTooltip,
|
|
1375
|
-
interactive,
|
|
1376
|
-
phase
|
|
1377
|
-
]);
|
|
1745
|
+
}, [anchor, calculatePosition, hideTooltip, interactive, phase]);
|
|
1378
1746
|
(0, import_react.useLayoutEffect)(() => {
|
|
1379
1747
|
if (phase === "hidden") {
|
|
1380
1748
|
return;
|
|
@@ -1741,7 +2109,8 @@ var import_react2 = require("react");
|
|
|
1741
2109
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
1742
2110
|
var DEFAULT_TOOLTIP_VALUES = {
|
|
1743
2111
|
defaultRenderPosition: "top",
|
|
1744
|
-
selectTheme: "primary"
|
|
2112
|
+
selectTheme: "primary",
|
|
2113
|
+
interactive: false
|
|
1745
2114
|
};
|
|
1746
2115
|
var TooltipContext = (0, import_react2.createContext)(DEFAULT_TOOLTIP_VALUES);
|
|
1747
2116
|
var TooltipProvider = ({
|
|
@@ -1749,16 +2118,27 @@ var TooltipProvider = ({
|
|
|
1749
2118
|
defaultRenderPosition = DEFAULT_TOOLTIP_VALUES.defaultRenderPosition,
|
|
1750
2119
|
selectTheme = DEFAULT_TOOLTIP_VALUES.selectTheme,
|
|
1751
2120
|
customTheme,
|
|
1752
|
-
animation
|
|
2121
|
+
animation,
|
|
2122
|
+
interactive = DEFAULT_TOOLTIP_VALUES.interactive,
|
|
2123
|
+
hideDelay
|
|
1753
2124
|
}) => {
|
|
1754
2125
|
const value = (0, import_react2.useMemo)(() => {
|
|
1755
2126
|
return {
|
|
1756
2127
|
defaultRenderPosition,
|
|
1757
2128
|
selectTheme,
|
|
1758
2129
|
customTheme,
|
|
1759
|
-
animation
|
|
2130
|
+
animation,
|
|
2131
|
+
interactive,
|
|
2132
|
+
hideDelay
|
|
1760
2133
|
};
|
|
1761
|
-
}, [
|
|
2134
|
+
}, [
|
|
2135
|
+
animation,
|
|
2136
|
+
customTheme,
|
|
2137
|
+
defaultRenderPosition,
|
|
2138
|
+
hideDelay,
|
|
2139
|
+
interactive,
|
|
2140
|
+
selectTheme
|
|
2141
|
+
]);
|
|
1762
2142
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TooltipContext.Provider, { value, children });
|
|
1763
2143
|
};
|
|
1764
2144
|
var useTooltipDefaults = () => {
|
|
@@ -2219,7 +2599,7 @@ var Tooltip = ({
|
|
|
2219
2599
|
customTheme,
|
|
2220
2600
|
animation,
|
|
2221
2601
|
disabled = false,
|
|
2222
|
-
interactive
|
|
2602
|
+
interactive,
|
|
2223
2603
|
hideDelay
|
|
2224
2604
|
}) => {
|
|
2225
2605
|
const defaults = useTooltipDefaults();
|
|
@@ -2263,6 +2643,8 @@ var Tooltip = ({
|
|
|
2263
2643
|
const animationSpeed = animation?.speed ?? localThemeAnimation?.speed ?? defaults.animation?.speed ?? inheritedTheme.animation?.speed ?? "120ms";
|
|
2264
2644
|
const animationEasing = animation?.easing ?? localThemeAnimation?.easing ?? defaults.animation?.easing ?? inheritedTheme.animation?.easing ?? "ease-in-out";
|
|
2265
2645
|
const preferredPlacement = position ?? defaults.defaultRenderPosition;
|
|
2646
|
+
const resolvedInteractive = interactive ?? defaults.interactive;
|
|
2647
|
+
const resolvedHideDelay = hideDelay ?? defaults.hideDelay;
|
|
2266
2648
|
const {
|
|
2267
2649
|
shouldRender,
|
|
2268
2650
|
phase,
|
|
@@ -2275,8 +2657,8 @@ var Tooltip = ({
|
|
|
2275
2657
|
anchor,
|
|
2276
2658
|
preferredPlacement,
|
|
2277
2659
|
disabled: disabled || content === null || content === void 0,
|
|
2278
|
-
interactive,
|
|
2279
|
-
hideDelay
|
|
2660
|
+
interactive: resolvedInteractive,
|
|
2661
|
+
hideDelay: resolvedHideDelay
|
|
2280
2662
|
});
|
|
2281
2663
|
const arrowSize = theme.arrow?.size ?? "6px";
|
|
2282
2664
|
const arrowWidth = theme.arrow?.width ?? `calc(${arrowSize} * 2)`;
|
|
@@ -2312,7 +2694,7 @@ var Tooltip = ({
|
|
|
2312
2694
|
`tooltip-container--phase-${phase}`,
|
|
2313
2695
|
`tooltip-container--show-${showAnimation}`,
|
|
2314
2696
|
`tooltip-container--hide-${hideAnimation}`,
|
|
2315
|
-
|
|
2697
|
+
resolvedInteractive ? "tooltip-container--interactive" : null
|
|
2316
2698
|
].filter(Boolean).join(" "),
|
|
2317
2699
|
style: containerStyle,
|
|
2318
2700
|
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|