@ssaprt/tooltip 1.0.3 → 1.0.4
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/index.js +164 -50
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +164 -50
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -963,6 +963,63 @@ var INTERACTIVE_RECHECK_INTERVAL = 50;
|
|
|
963
963
|
var TOUCH_MOVE_THRESHOLD = 10;
|
|
964
964
|
var TOUCH_MAX_TAP_DURATION = 600;
|
|
965
965
|
var TOUCH_FOCUS_SUPPRESSION = 700;
|
|
966
|
+
var activeTooltipSession = null;
|
|
967
|
+
var inputModality = "pointer";
|
|
968
|
+
var inputModalitySubscribers = 0;
|
|
969
|
+
var handleGlobalPointerDown = () => {
|
|
970
|
+
inputModality = "pointer";
|
|
971
|
+
};
|
|
972
|
+
var keyboardFocusKeys = /* @__PURE__ */ new Set([
|
|
973
|
+
"Tab",
|
|
974
|
+
"Enter",
|
|
975
|
+
" ",
|
|
976
|
+
"ArrowUp",
|
|
977
|
+
"ArrowDown",
|
|
978
|
+
"ArrowLeft",
|
|
979
|
+
"ArrowRight",
|
|
980
|
+
"Home",
|
|
981
|
+
"End",
|
|
982
|
+
"PageUp",
|
|
983
|
+
"PageDown"
|
|
984
|
+
]);
|
|
985
|
+
var handleGlobalKeyDown = (event) => {
|
|
986
|
+
if (event.metaKey || event.ctrlKey || event.altKey || !keyboardFocusKeys.has(event.key)) {
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
inputModality = "keyboard";
|
|
990
|
+
};
|
|
991
|
+
var subscribeInputModality = () => {
|
|
992
|
+
inputModalitySubscribers += 1;
|
|
993
|
+
if (inputModalitySubscribers !== 1) {
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
996
|
+
document.addEventListener("pointerdown", handleGlobalPointerDown, true);
|
|
997
|
+
document.addEventListener("keydown", handleGlobalKeyDown, true);
|
|
998
|
+
};
|
|
999
|
+
var unsubscribeInputModality = () => {
|
|
1000
|
+
inputModalitySubscribers = Math.max(0, inputModalitySubscribers - 1);
|
|
1001
|
+
if (inputModalitySubscribers !== 0) {
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
document.removeEventListener("pointerdown", handleGlobalPointerDown, true);
|
|
1005
|
+
document.removeEventListener("keydown", handleGlobalKeyDown, true);
|
|
1006
|
+
};
|
|
1007
|
+
var requestTooltipActivation = (session, point) => {
|
|
1008
|
+
const currentSession = activeTooltipSession;
|
|
1009
|
+
if (currentSession && currentSession.owner !== session.owner) {
|
|
1010
|
+
if (point && currentSession.interactive && currentSession.protectsPoint(point)) {
|
|
1011
|
+
return false;
|
|
1012
|
+
}
|
|
1013
|
+
currentSession.close();
|
|
1014
|
+
}
|
|
1015
|
+
activeTooltipSession = session;
|
|
1016
|
+
return true;
|
|
1017
|
+
};
|
|
1018
|
+
var clearTooltipActivation = (owner) => {
|
|
1019
|
+
if (activeTooltipSession?.owner === owner) {
|
|
1020
|
+
activeTooltipSession = null;
|
|
1021
|
+
}
|
|
1022
|
+
};
|
|
966
1023
|
var oppositePlacement = {
|
|
967
1024
|
top: "bottom",
|
|
968
1025
|
bottom: "top",
|
|
@@ -1088,6 +1145,7 @@ var useTooltip = ({
|
|
|
1088
1145
|
}) => {
|
|
1089
1146
|
const tooltipRef = (0, import_react.useRef)(null);
|
|
1090
1147
|
const bodyRef = (0, import_react.useRef)(null);
|
|
1148
|
+
const ownerRef = (0, import_react.useRef)(/* @__PURE__ */ Symbol("tooltip"));
|
|
1091
1149
|
const hideTimerRef = (0, import_react.useRef)(null);
|
|
1092
1150
|
const firstFrameRef = (0, import_react.useRef)(null);
|
|
1093
1151
|
const secondFrameRef = (0, import_react.useRef)(null);
|
|
@@ -1100,6 +1158,7 @@ var useTooltip = ({
|
|
|
1100
1158
|
y: Number.NaN,
|
|
1101
1159
|
pointerType: ""
|
|
1102
1160
|
});
|
|
1161
|
+
const interactiveAreaAtPointRef = (0, import_react.useRef)(() => "outside");
|
|
1103
1162
|
const touchGestureRef = (0, import_react.useRef)(null);
|
|
1104
1163
|
const suppressFocusUntilRef = (0, import_react.useRef)(0);
|
|
1105
1164
|
const [mounted, setMounted] = (0, import_react.useState)(false);
|
|
@@ -1238,7 +1297,7 @@ var useTooltip = ({
|
|
|
1238
1297
|
});
|
|
1239
1298
|
}, [anchor, getAvailableSpace, preferredPlacement]);
|
|
1240
1299
|
const isFocusInsideTooltipRegion = (0, import_react.useCallback)(() => {
|
|
1241
|
-
if (!anchor || typeof document === "undefined") {
|
|
1300
|
+
if (!anchor || typeof document === "undefined" || inputModality !== "keyboard") {
|
|
1242
1301
|
return false;
|
|
1243
1302
|
}
|
|
1244
1303
|
const activeElement = document.activeElement;
|
|
@@ -1246,50 +1305,60 @@ var useTooltip = ({
|
|
|
1246
1305
|
if (!(activeElement instanceof Node)) {
|
|
1247
1306
|
return false;
|
|
1248
1307
|
}
|
|
1249
|
-
|
|
1250
|
-
return true;
|
|
1251
|
-
}
|
|
1252
|
-
return anchor.contains(activeElement) && activeElement instanceof Element && activeElement.matches(":focus-visible");
|
|
1308
|
+
return anchor.contains(activeElement) || Boolean(interactive && tooltip?.contains(activeElement));
|
|
1253
1309
|
}, [anchor, interactive]);
|
|
1310
|
+
const getInteractivePointerAreaAtPoint = (0, import_react.useCallback)(
|
|
1311
|
+
(point) => {
|
|
1312
|
+
if (!interactive || !anchor) {
|
|
1313
|
+
return "outside";
|
|
1314
|
+
}
|
|
1315
|
+
const tooltip = tooltipRef.current;
|
|
1316
|
+
if (!tooltip || !Number.isFinite(point.x) || !Number.isFinite(point.y)) {
|
|
1317
|
+
return "outside";
|
|
1318
|
+
}
|
|
1319
|
+
const anchorRect = anchor.getBoundingClientRect();
|
|
1320
|
+
const tooltipRect = tooltip.getBoundingClientRect();
|
|
1321
|
+
if (isPointInsideRect(
|
|
1322
|
+
point,
|
|
1323
|
+
anchorRect,
|
|
1324
|
+
INTERACTIVE_DIRECT_PADDING
|
|
1325
|
+
) || isPointInsideRect(
|
|
1326
|
+
point,
|
|
1327
|
+
tooltipRect,
|
|
1328
|
+
INTERACTIVE_DIRECT_PADDING
|
|
1329
|
+
)) {
|
|
1330
|
+
return "direct";
|
|
1331
|
+
}
|
|
1332
|
+
const bridge = createInteractiveBridge(
|
|
1333
|
+
anchorRect,
|
|
1334
|
+
tooltipRect,
|
|
1335
|
+
placement
|
|
1336
|
+
);
|
|
1337
|
+
return isPointInsidePolygon(point, bridge) ? "bridge" : "outside";
|
|
1338
|
+
},
|
|
1339
|
+
[anchor, interactive, placement]
|
|
1340
|
+
);
|
|
1341
|
+
(0, import_react.useLayoutEffect)(() => {
|
|
1342
|
+
interactiveAreaAtPointRef.current = getInteractivePointerAreaAtPoint;
|
|
1343
|
+
}, [getInteractivePointerAreaAtPoint]);
|
|
1254
1344
|
const getInteractivePointerArea = (0, import_react.useCallback)(() => {
|
|
1255
|
-
if (!interactive || !anchor) {
|
|
1256
|
-
return "outside";
|
|
1257
|
-
}
|
|
1258
1345
|
const pointer = pointerRef.current;
|
|
1259
|
-
|
|
1260
|
-
if (!tooltip || pointer.pointerType !== "mouse" && pointer.pointerType !== "pen" || !Number.isFinite(pointer.x) || !Number.isFinite(pointer.y)) {
|
|
1346
|
+
if (pointer.pointerType !== "mouse" && pointer.pointerType !== "pen" || !Number.isFinite(pointer.x) || !Number.isFinite(pointer.y)) {
|
|
1261
1347
|
return "outside";
|
|
1262
1348
|
}
|
|
1263
|
-
|
|
1349
|
+
return getInteractivePointerAreaAtPoint({
|
|
1264
1350
|
x: pointer.x,
|
|
1265
1351
|
y: pointer.y
|
|
1266
|
-
};
|
|
1267
|
-
|
|
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]);
|
|
1352
|
+
});
|
|
1353
|
+
}, [getInteractivePointerAreaAtPoint]);
|
|
1287
1354
|
const removeTooltip = (0, import_react.useCallback)(() => {
|
|
1288
1355
|
clearHideTimer();
|
|
1289
1356
|
clearEnterFrames();
|
|
1290
1357
|
clearInteractiveFrame();
|
|
1291
1358
|
pendingHideRef.current = false;
|
|
1292
1359
|
interactiveBridgeDeadlineRef.current = 0;
|
|
1360
|
+
clearTooltipActivation(ownerRef.current);
|
|
1361
|
+
setMounted(false);
|
|
1293
1362
|
updatePhase("hidden");
|
|
1294
1363
|
}, [clearEnterFrames, clearHideTimer, clearInteractiveFrame, updatePhase]);
|
|
1295
1364
|
const runHide = (0, import_react.useCallback)(() => {
|
|
@@ -1365,21 +1434,51 @@ var useTooltip = ({
|
|
|
1365
1434
|
runHide
|
|
1366
1435
|
]
|
|
1367
1436
|
);
|
|
1368
|
-
const showTooltip = (0, import_react.useCallback)(
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1437
|
+
const showTooltip = (0, import_react.useCallback)(
|
|
1438
|
+
(activationPoint) => {
|
|
1439
|
+
if (!anchor || disabled) {
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1442
|
+
const activated = requestTooltipActivation(
|
|
1443
|
+
{
|
|
1444
|
+
owner: ownerRef.current,
|
|
1445
|
+
interactive,
|
|
1446
|
+
protectsPoint: (point) => {
|
|
1447
|
+
if (phaseRef.current === "hidden") {
|
|
1448
|
+
return false;
|
|
1449
|
+
}
|
|
1450
|
+
return interactiveAreaAtPointRef.current(point) !== "outside";
|
|
1451
|
+
},
|
|
1452
|
+
close: () => {
|
|
1453
|
+
hideTooltip(true);
|
|
1454
|
+
}
|
|
1455
|
+
},
|
|
1456
|
+
activationPoint
|
|
1457
|
+
);
|
|
1458
|
+
if (!activated) {
|
|
1459
|
+
return;
|
|
1460
|
+
}
|
|
1461
|
+
clearHideTimer();
|
|
1462
|
+
clearEnterFrames();
|
|
1463
|
+
interactiveBridgeDeadlineRef.current = 0;
|
|
1464
|
+
pendingHideRef.current = false;
|
|
1465
|
+
setMounted(true);
|
|
1466
|
+
if (phaseRef.current === "entering" || phaseRef.current === "visible") {
|
|
1467
|
+
return;
|
|
1468
|
+
}
|
|
1469
|
+
updatePhase("preparing");
|
|
1470
|
+
setShowVersion((value) => value + 1);
|
|
1471
|
+
},
|
|
1472
|
+
[
|
|
1473
|
+
anchor,
|
|
1474
|
+
clearEnterFrames,
|
|
1475
|
+
clearHideTimer,
|
|
1476
|
+
disabled,
|
|
1477
|
+
hideTooltip,
|
|
1478
|
+
interactive,
|
|
1479
|
+
updatePhase
|
|
1480
|
+
]
|
|
1481
|
+
);
|
|
1383
1482
|
const keepTooltipOpen = (0, import_react.useCallback)(() => {
|
|
1384
1483
|
if (!interactive || disabled) {
|
|
1385
1484
|
return;
|
|
@@ -1469,6 +1568,13 @@ var useTooltip = ({
|
|
|
1469
1568
|
showVersion,
|
|
1470
1569
|
updatePhase
|
|
1471
1570
|
]);
|
|
1571
|
+
(0, import_react.useEffect)(() => {
|
|
1572
|
+
subscribeInputModality();
|
|
1573
|
+
return () => {
|
|
1574
|
+
unsubscribeInputModality();
|
|
1575
|
+
clearTooltipActivation(ownerRef.current);
|
|
1576
|
+
};
|
|
1577
|
+
}, []);
|
|
1472
1578
|
(0, import_react.useEffect)(() => {
|
|
1473
1579
|
if (!anchor) {
|
|
1474
1580
|
removeTooltip();
|
|
@@ -1486,7 +1592,10 @@ var useTooltip = ({
|
|
|
1486
1592
|
if (event.pointerType === "touch") {
|
|
1487
1593
|
return;
|
|
1488
1594
|
}
|
|
1489
|
-
showTooltip(
|
|
1595
|
+
showTooltip({
|
|
1596
|
+
x: event.clientX,
|
|
1597
|
+
y: event.clientY
|
|
1598
|
+
});
|
|
1490
1599
|
};
|
|
1491
1600
|
const onPointerLeave = (event) => {
|
|
1492
1601
|
updatePointer(event);
|
|
@@ -1558,7 +1667,10 @@ var useTooltip = ({
|
|
|
1558
1667
|
return;
|
|
1559
1668
|
}
|
|
1560
1669
|
if (phaseRef.current === "hidden" || phaseRef.current === "leaving") {
|
|
1561
|
-
showTooltip(
|
|
1670
|
+
showTooltip({
|
|
1671
|
+
x: event.clientX,
|
|
1672
|
+
y: event.clientY
|
|
1673
|
+
});
|
|
1562
1674
|
} else {
|
|
1563
1675
|
hideTooltip(true);
|
|
1564
1676
|
}
|
|
@@ -1655,7 +1767,9 @@ var useTooltip = ({
|
|
|
1655
1767
|
scheduleInteractivePointerProcessing();
|
|
1656
1768
|
};
|
|
1657
1769
|
const onFocusIn = () => {
|
|
1658
|
-
|
|
1770
|
+
if (inputModality === "keyboard") {
|
|
1771
|
+
keepTooltipOpen();
|
|
1772
|
+
}
|
|
1659
1773
|
};
|
|
1660
1774
|
const onFocusOut = (event) => {
|
|
1661
1775
|
const relatedTarget = event.relatedTarget;
|