phase 0.0.6 → 0.0.8
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 +201 -15
- package/dist/{pointer-D5F7_Jjs.js → debounce-D5ugkrXN.js} +411 -2
- package/dist/debounce-D5ugkrXN.js.map +1 -0
- package/dist/{index-tRHsbTE2.d.ts → index-C10bmjm1.d.ts} +99 -2
- package/dist/index-C10bmjm1.d.ts.map +1 -0
- package/dist/index.d.ts +34 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/react.d.ts +109 -4
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +191 -52
- package/dist/react.js.map +1 -1
- package/package.json +4 -4
- package/dist/index-tRHsbTE2.d.ts.map +0 -1
- package/dist/pointer-D5F7_Jjs.js.map +0 -1
|
@@ -1207,6 +1207,415 @@ function createPointer(options) {
|
|
|
1207
1207
|
};
|
|
1208
1208
|
}
|
|
1209
1209
|
//#endregion
|
|
1210
|
-
|
|
1210
|
+
//#region src/core/_internal/pool/ro-pool.ts
|
|
1211
|
+
let observer = null;
|
|
1212
|
+
const callbacks = /* @__PURE__ */ new Map();
|
|
1213
|
+
/**
|
|
1214
|
+
* Observe an element via a singleton ResizeObserver.
|
|
1215
|
+
* One RO instance for the entire page. Per-element `box` options are
|
|
1216
|
+
* forwarded to `ResizeObserver.observe()`.
|
|
1217
|
+
*
|
|
1218
|
+
* @returns Cleanup function that unobserves the element.
|
|
1219
|
+
*/
|
|
1220
|
+
function observeResize(element, callback, box) {
|
|
1221
|
+
callbacks.set(element, callback);
|
|
1222
|
+
getObserver().observe(element, box ? { box } : void 0);
|
|
1223
|
+
let disposed = false;
|
|
1224
|
+
return () => {
|
|
1225
|
+
if (disposed) return;
|
|
1226
|
+
disposed = true;
|
|
1227
|
+
if (callbacks.get(element) === callback) {
|
|
1228
|
+
callbacks.delete(element);
|
|
1229
|
+
observer?.unobserve(element);
|
|
1230
|
+
}
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1233
|
+
/** Lazy-created singleton. RO takes zero constructor options, so one instance can observe everything. */
|
|
1234
|
+
function getObserver() {
|
|
1235
|
+
if (!observer) observer = new ResizeObserver((entries) => {
|
|
1236
|
+
for (const entry of entries) {
|
|
1237
|
+
const cb = callbacks.get(entry.target);
|
|
1238
|
+
if (cb) cb(entry);
|
|
1239
|
+
}
|
|
1240
|
+
});
|
|
1241
|
+
return observer;
|
|
1242
|
+
}
|
|
1243
|
+
//#endregion
|
|
1244
|
+
//#region src/core/scroll/index.ts
|
|
1245
|
+
/**
|
|
1246
|
+
* Lifecycle-aware scroll tracker. Reads `scrollLeft`/`scrollTop` once per rAF
|
|
1247
|
+
* frame and reads the reflow-heavy geometry (`scrollWidth`/`clientWidth`) only
|
|
1248
|
+
* on resize or explicit `measure()`, never on the scroll path. Auto-pauses when
|
|
1249
|
+
* the element is off-screen.
|
|
1250
|
+
*
|
|
1251
|
+
* This is to `scroll` + `scrollWidth` what `createPointer` is to `pointermove`
|
|
1252
|
+
* + `getBoundingClientRect`: the layout read is batched off the hot path so the
|
|
1253
|
+
* per-scroll work is a single cheap position read plus math on cached geometry.
|
|
1254
|
+
*/
|
|
1255
|
+
function createScroll(options) {
|
|
1256
|
+
if (typeof document === "undefined") serverContextError("createScroll");
|
|
1257
|
+
const { element, onScroll, onPhaseChange, visibility = "pause", intersectionOptions, signal } = options;
|
|
1258
|
+
if (!element) noElementError("createScroll");
|
|
1259
|
+
let _phase = "paused";
|
|
1260
|
+
let _reason = "initial";
|
|
1261
|
+
let stopped = false;
|
|
1262
|
+
const _state = {
|
|
1263
|
+
x: 0,
|
|
1264
|
+
y: 0,
|
|
1265
|
+
maxX: 0,
|
|
1266
|
+
maxY: 0,
|
|
1267
|
+
progressX: 0,
|
|
1268
|
+
progressY: 0,
|
|
1269
|
+
visibleX: 1,
|
|
1270
|
+
visibleY: 1
|
|
1271
|
+
};
|
|
1272
|
+
let rafId = 0;
|
|
1273
|
+
let dirty = false;
|
|
1274
|
+
let listenersAttached = false;
|
|
1275
|
+
let unobserveRO;
|
|
1276
|
+
function setPhase(phase, reason) {
|
|
1277
|
+
const prev = _phase;
|
|
1278
|
+
_phase = phase;
|
|
1279
|
+
_reason = reason;
|
|
1280
|
+
if (prev !== phase) onPhaseChange?.(phase, reason);
|
|
1281
|
+
}
|
|
1282
|
+
function computePosition() {
|
|
1283
|
+
const { maxX, maxY } = _state;
|
|
1284
|
+
const x = element.scrollLeft;
|
|
1285
|
+
const y = element.scrollTop;
|
|
1286
|
+
_state.x = x < 0 ? 0 : x > maxX ? maxX : x;
|
|
1287
|
+
_state.y = y < 0 ? 0 : y > maxY ? maxY : y;
|
|
1288
|
+
_state.progressX = maxX > 0 ? _state.x / maxX : 0;
|
|
1289
|
+
_state.progressY = maxY > 0 ? _state.y / maxY : 0;
|
|
1290
|
+
}
|
|
1291
|
+
function measure() {
|
|
1292
|
+
if (stopped || !listenersAttached) return;
|
|
1293
|
+
const scrollWidth = element.scrollWidth;
|
|
1294
|
+
const clientWidth = element.clientWidth;
|
|
1295
|
+
const scrollHeight = element.scrollHeight;
|
|
1296
|
+
const clientHeight = element.clientHeight;
|
|
1297
|
+
const maxX = scrollWidth - clientWidth;
|
|
1298
|
+
const maxY = scrollHeight - clientHeight;
|
|
1299
|
+
_state.maxX = maxX > 0 ? maxX : 0;
|
|
1300
|
+
_state.maxY = maxY > 0 ? maxY : 0;
|
|
1301
|
+
_state.visibleX = maxX > 0 ? clientWidth / scrollWidth : 1;
|
|
1302
|
+
_state.visibleY = maxY > 0 ? clientHeight / scrollHeight : 1;
|
|
1303
|
+
computePosition();
|
|
1304
|
+
onScroll(_state);
|
|
1305
|
+
}
|
|
1306
|
+
function flush() {
|
|
1307
|
+
rafId = 0;
|
|
1308
|
+
if (!dirty || stopped) return;
|
|
1309
|
+
dirty = false;
|
|
1310
|
+
computePosition();
|
|
1311
|
+
onScroll(_state);
|
|
1312
|
+
}
|
|
1313
|
+
function scheduleFlush() {
|
|
1314
|
+
if (rafId !== 0) return;
|
|
1315
|
+
rafId = requestAnimationFrame(flush);
|
|
1316
|
+
}
|
|
1317
|
+
function cancelFlush() {
|
|
1318
|
+
if (rafId !== 0) {
|
|
1319
|
+
cancelAnimationFrame(rafId);
|
|
1320
|
+
rafId = 0;
|
|
1321
|
+
}
|
|
1322
|
+
dirty = false;
|
|
1323
|
+
}
|
|
1324
|
+
function onScrollEvent() {
|
|
1325
|
+
if (stopped) return;
|
|
1326
|
+
dirty = true;
|
|
1327
|
+
scheduleFlush();
|
|
1328
|
+
}
|
|
1329
|
+
function onROResize() {
|
|
1330
|
+
if (stopped) return;
|
|
1331
|
+
measure();
|
|
1332
|
+
}
|
|
1333
|
+
function attachListeners() {
|
|
1334
|
+
if (listenersAttached) return;
|
|
1335
|
+
listenersAttached = true;
|
|
1336
|
+
element.addEventListener("scroll", onScrollEvent, { passive: true });
|
|
1337
|
+
unobserveRO = observeResize(element, onROResize);
|
|
1338
|
+
measure();
|
|
1339
|
+
}
|
|
1340
|
+
function detachListeners() {
|
|
1341
|
+
if (!listenersAttached) return;
|
|
1342
|
+
listenersAttached = false;
|
|
1343
|
+
element.removeEventListener("scroll", onScrollEvent);
|
|
1344
|
+
unobserveRO?.();
|
|
1345
|
+
unobserveRO = void 0;
|
|
1346
|
+
cancelFlush();
|
|
1347
|
+
}
|
|
1348
|
+
let cleanupVisibility;
|
|
1349
|
+
if (visibility === "pause") {
|
|
1350
|
+
let elementInView = false;
|
|
1351
|
+
let documentVisible = !document.hidden;
|
|
1352
|
+
function recompute() {
|
|
1353
|
+
if (stopped) return;
|
|
1354
|
+
const shouldTrack = documentVisible && elementInView;
|
|
1355
|
+
if (shouldTrack && !listenersAttached) {
|
|
1356
|
+
setPhase("tracking", "started");
|
|
1357
|
+
attachListeners();
|
|
1358
|
+
} else if (!shouldTrack && listenersAttached) {
|
|
1359
|
+
detachListeners();
|
|
1360
|
+
setPhase("paused", "sight");
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
function onVisChange() {
|
|
1364
|
+
documentVisible = !document.hidden;
|
|
1365
|
+
recompute();
|
|
1366
|
+
}
|
|
1367
|
+
function onPageShow(event) {
|
|
1368
|
+
if (!event.persisted) return;
|
|
1369
|
+
documentVisible = true;
|
|
1370
|
+
recompute();
|
|
1371
|
+
}
|
|
1372
|
+
document.addEventListener("visibilitychange", onVisChange);
|
|
1373
|
+
window.addEventListener("pageshow", onPageShow);
|
|
1374
|
+
const unobserveIO = observeIntersection({
|
|
1375
|
+
element,
|
|
1376
|
+
onIntersect: (entry) => {
|
|
1377
|
+
elementInView = entry.isIntersecting;
|
|
1378
|
+
recompute();
|
|
1379
|
+
},
|
|
1380
|
+
...intersectionOptions
|
|
1381
|
+
});
|
|
1382
|
+
cleanupVisibility = () => {
|
|
1383
|
+
document.removeEventListener("visibilitychange", onVisChange);
|
|
1384
|
+
window.removeEventListener("pageshow", onPageShow);
|
|
1385
|
+
unobserveIO();
|
|
1386
|
+
};
|
|
1387
|
+
} else {
|
|
1388
|
+
setPhase("tracking", "started");
|
|
1389
|
+
attachListeners();
|
|
1390
|
+
}
|
|
1391
|
+
let unlinkAbort;
|
|
1392
|
+
function stop() {
|
|
1393
|
+
if (stopped) return;
|
|
1394
|
+
stopped = true;
|
|
1395
|
+
unlinkAbort?.();
|
|
1396
|
+
cleanupVisibility?.();
|
|
1397
|
+
detachListeners();
|
|
1398
|
+
cancelFlush();
|
|
1399
|
+
setPhase("stopped", "disposed");
|
|
1400
|
+
}
|
|
1401
|
+
unlinkAbort = linkAbortSignal(signal, stop);
|
|
1402
|
+
return {
|
|
1403
|
+
get phase() {
|
|
1404
|
+
return _phase;
|
|
1405
|
+
},
|
|
1406
|
+
get phaseReason() {
|
|
1407
|
+
return _reason;
|
|
1408
|
+
},
|
|
1409
|
+
get state() {
|
|
1410
|
+
return _state;
|
|
1411
|
+
},
|
|
1412
|
+
measure,
|
|
1413
|
+
stop
|
|
1414
|
+
};
|
|
1415
|
+
}
|
|
1416
|
+
//#endregion
|
|
1417
|
+
//#region src/core/throttle/index.ts
|
|
1418
|
+
/**
|
|
1419
|
+
* Frame-aligned, visibility-aware throttle. Leading calls fire synchronously;
|
|
1420
|
+
* a pending trailing call rides a one-shot rAF chain and fires with the latest
|
|
1421
|
+
* value on the first frame at or past `interval`. While the document is hidden
|
|
1422
|
+
* nothing is scheduled: a pending call is flushed or dropped per `hidden`, and
|
|
1423
|
+
* new calls are recorded but deferred until the document is visible again.
|
|
1424
|
+
*
|
|
1425
|
+
* @remarks
|
|
1426
|
+
* `call` takes exactly one value and stores it by reference, so the hot path
|
|
1427
|
+
* never allocates. Trailing calls read the value at fire time.
|
|
1428
|
+
*/
|
|
1429
|
+
function createThrottle(options) {
|
|
1430
|
+
if (typeof document === "undefined") serverContextError("createThrottle");
|
|
1431
|
+
const { callback, interval, edge = "both", hidden = "flush", signal } = options;
|
|
1432
|
+
const leading = edge !== "trailing";
|
|
1433
|
+
const trailing = edge !== "leading";
|
|
1434
|
+
let stopped = false;
|
|
1435
|
+
let pending = false;
|
|
1436
|
+
let lastFire = 0;
|
|
1437
|
+
let rafId = 0;
|
|
1438
|
+
let documentVisible = !document.hidden;
|
|
1439
|
+
let latest = void 0;
|
|
1440
|
+
function fire(now) {
|
|
1441
|
+
lastFire = now;
|
|
1442
|
+
pending = false;
|
|
1443
|
+
callback(latest);
|
|
1444
|
+
}
|
|
1445
|
+
function cancelRaf() {
|
|
1446
|
+
if (rafId !== 0) {
|
|
1447
|
+
cancelAnimationFrame(rafId);
|
|
1448
|
+
rafId = 0;
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
function tick() {
|
|
1452
|
+
rafId = 0;
|
|
1453
|
+
if (stopped || !pending) return;
|
|
1454
|
+
const now = performance.now();
|
|
1455
|
+
if (now - lastFire >= interval) fire(now);
|
|
1456
|
+
else rafId = requestAnimationFrame(tick);
|
|
1457
|
+
}
|
|
1458
|
+
function scheduleRaf() {
|
|
1459
|
+
if (rafId === 0) rafId = requestAnimationFrame(tick);
|
|
1460
|
+
}
|
|
1461
|
+
function call(value) {
|
|
1462
|
+
if (stopped) return;
|
|
1463
|
+
latest = value;
|
|
1464
|
+
if (!documentVisible) {
|
|
1465
|
+
pending = true;
|
|
1466
|
+
return;
|
|
1467
|
+
}
|
|
1468
|
+
const now = performance.now();
|
|
1469
|
+
if (now - lastFire >= interval) {
|
|
1470
|
+
if (leading) {
|
|
1471
|
+
fire(now);
|
|
1472
|
+
return;
|
|
1473
|
+
}
|
|
1474
|
+
lastFire = now;
|
|
1475
|
+
}
|
|
1476
|
+
if (trailing) {
|
|
1477
|
+
pending = true;
|
|
1478
|
+
scheduleRaf();
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
function flush() {
|
|
1482
|
+
if (stopped || !pending) return;
|
|
1483
|
+
cancelRaf();
|
|
1484
|
+
fire(performance.now());
|
|
1485
|
+
}
|
|
1486
|
+
function cancel() {
|
|
1487
|
+
if (stopped) return;
|
|
1488
|
+
cancelRaf();
|
|
1489
|
+
pending = false;
|
|
1490
|
+
lastFire = 0;
|
|
1491
|
+
}
|
|
1492
|
+
function onVisibilityChange() {
|
|
1493
|
+
documentVisible = !document.hidden;
|
|
1494
|
+
if (stopped) return;
|
|
1495
|
+
if (!documentVisible) {
|
|
1496
|
+
cancelRaf();
|
|
1497
|
+
if (pending) if (hidden === "flush") fire(performance.now());
|
|
1498
|
+
else pending = false;
|
|
1499
|
+
} else if (pending) scheduleRaf();
|
|
1500
|
+
}
|
|
1501
|
+
function onPageShow(event) {
|
|
1502
|
+
if (!event.persisted) return;
|
|
1503
|
+
documentVisible = true;
|
|
1504
|
+
if (!stopped && pending) scheduleRaf();
|
|
1505
|
+
}
|
|
1506
|
+
document.addEventListener("visibilitychange", onVisibilityChange);
|
|
1507
|
+
window.addEventListener("pageshow", onPageShow);
|
|
1508
|
+
let unlinkAbort;
|
|
1509
|
+
function stop() {
|
|
1510
|
+
if (stopped) return;
|
|
1511
|
+
stopped = true;
|
|
1512
|
+
unlinkAbort?.();
|
|
1513
|
+
document.removeEventListener("visibilitychange", onVisibilityChange);
|
|
1514
|
+
window.removeEventListener("pageshow", onPageShow);
|
|
1515
|
+
cancelRaf();
|
|
1516
|
+
pending = false;
|
|
1517
|
+
}
|
|
1518
|
+
unlinkAbort = linkAbortSignal(signal, stop);
|
|
1519
|
+
return {
|
|
1520
|
+
call,
|
|
1521
|
+
flush,
|
|
1522
|
+
cancel,
|
|
1523
|
+
get pending() {
|
|
1524
|
+
return pending;
|
|
1525
|
+
},
|
|
1526
|
+
stop
|
|
1527
|
+
};
|
|
1528
|
+
}
|
|
1529
|
+
//#endregion
|
|
1530
|
+
//#region src/core/debounce/index.ts
|
|
1531
|
+
/**
|
|
1532
|
+
* Visibility-aware trailing debounce. Fires the callback with the latest
|
|
1533
|
+
* value once `wait` milliseconds pass without a new call. While the document
|
|
1534
|
+
* is hidden no timer runs: a pending call is flushed or dropped per `hidden`,
|
|
1535
|
+
* and new calls are recorded but wait until the document is visible again,
|
|
1536
|
+
* when the quiet timer restarts.
|
|
1537
|
+
*/
|
|
1538
|
+
function createDebounce(options) {
|
|
1539
|
+
if (typeof document === "undefined") serverContextError("createDebounce");
|
|
1540
|
+
const { callback, wait, hidden = "flush", signal } = options;
|
|
1541
|
+
let stopped = false;
|
|
1542
|
+
let pending = false;
|
|
1543
|
+
let timer;
|
|
1544
|
+
let documentVisible = !document.hidden;
|
|
1545
|
+
let latest = void 0;
|
|
1546
|
+
function fire() {
|
|
1547
|
+
pending = false;
|
|
1548
|
+
callback(latest);
|
|
1549
|
+
}
|
|
1550
|
+
function clearTimer() {
|
|
1551
|
+
if (timer !== void 0) {
|
|
1552
|
+
clearTimeout(timer);
|
|
1553
|
+
timer = void 0;
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
function onTimer() {
|
|
1557
|
+
timer = void 0;
|
|
1558
|
+
if (stopped || !pending) return;
|
|
1559
|
+
fire();
|
|
1560
|
+
}
|
|
1561
|
+
function startTimer() {
|
|
1562
|
+
clearTimer();
|
|
1563
|
+
timer = setTimeout(onTimer, wait);
|
|
1564
|
+
}
|
|
1565
|
+
function call(value) {
|
|
1566
|
+
if (stopped) return;
|
|
1567
|
+
latest = value;
|
|
1568
|
+
pending = true;
|
|
1569
|
+
if (documentVisible) startTimer();
|
|
1570
|
+
}
|
|
1571
|
+
function flush() {
|
|
1572
|
+
if (stopped || !pending) return;
|
|
1573
|
+
clearTimer();
|
|
1574
|
+
fire();
|
|
1575
|
+
}
|
|
1576
|
+
function cancel() {
|
|
1577
|
+
if (stopped) return;
|
|
1578
|
+
clearTimer();
|
|
1579
|
+
pending = false;
|
|
1580
|
+
}
|
|
1581
|
+
function onVisibilityChange() {
|
|
1582
|
+
documentVisible = !document.hidden;
|
|
1583
|
+
if (stopped) return;
|
|
1584
|
+
if (!documentVisible) {
|
|
1585
|
+
clearTimer();
|
|
1586
|
+
if (pending) if (hidden === "flush") fire();
|
|
1587
|
+
else pending = false;
|
|
1588
|
+
} else if (pending) startTimer();
|
|
1589
|
+
}
|
|
1590
|
+
function onPageShow(event) {
|
|
1591
|
+
if (!event.persisted) return;
|
|
1592
|
+
documentVisible = true;
|
|
1593
|
+
if (!stopped && pending) startTimer();
|
|
1594
|
+
}
|
|
1595
|
+
document.addEventListener("visibilitychange", onVisibilityChange);
|
|
1596
|
+
window.addEventListener("pageshow", onPageShow);
|
|
1597
|
+
let unlinkAbort;
|
|
1598
|
+
function stop() {
|
|
1599
|
+
if (stopped) return;
|
|
1600
|
+
stopped = true;
|
|
1601
|
+
unlinkAbort?.();
|
|
1602
|
+
document.removeEventListener("visibilitychange", onVisibilityChange);
|
|
1603
|
+
window.removeEventListener("pageshow", onPageShow);
|
|
1604
|
+
clearTimer();
|
|
1605
|
+
pending = false;
|
|
1606
|
+
}
|
|
1607
|
+
unlinkAbort = linkAbortSignal(signal, stop);
|
|
1608
|
+
return {
|
|
1609
|
+
call,
|
|
1610
|
+
flush,
|
|
1611
|
+
cancel,
|
|
1612
|
+
get pending() {
|
|
1613
|
+
return pending;
|
|
1614
|
+
},
|
|
1615
|
+
stop
|
|
1616
|
+
};
|
|
1617
|
+
}
|
|
1618
|
+
//#endregion
|
|
1619
|
+
export { missingContextError as C, isPhaseError as S, linkAbortSignal as T, subscribeMediaQuery as _, createPointer as a, PhaseError as b, prefersReducedMotion as c, subscribeDpr as d, createRenderState as f, readMediaQuery as g, createLifecycle as h, observeResize as i, whenIdle as l, createLoop as m, createThrottle as n, createMutation as o, createScrollProgress as p, createScroll as r, REDUCED_MOTION_QUERY as s, createDebounce as t, readDpr as u, createSight as v, serverContextError as w, invalidDurationError as x, createTicker as y };
|
|
1211
1620
|
|
|
1212
|
-
//# sourceMappingURL=
|
|
1621
|
+
//# sourceMappingURL=debounce-D5ugkrXN.js.map
|