@ringcentral/spring-base 1.9.0 → 1.9.1
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/hooks.js +354 -17
- package/index.js +0 -1
- package/package.json +1 -2
- package/src/hooks/useBodyScrollLock/bodyScrollLock.d.ts +31 -0
- package/src/hooks/useBodyScrollLock/internal.d.ts +6 -0
- package/src/hooks/useBodyScrollLock/useBodyScrollLock.d.ts +3 -1
- package/src/typings/ComponentTypes.d.ts +1 -0
package/hooks.js
CHANGED
|
@@ -13,7 +13,6 @@ import 'lodash/isPlainObject';
|
|
|
13
13
|
import debounce from 'lodash/debounce';
|
|
14
14
|
import noop from 'lodash/noop';
|
|
15
15
|
import throttle from 'lodash/throttle';
|
|
16
|
-
import { disableBodyScroll, enableBodyScroll } from 'body-scroll-lock';
|
|
17
16
|
import 'tailwind-merge';
|
|
18
17
|
|
|
19
18
|
const useEventCallback = (func) => {
|
|
@@ -1479,31 +1478,369 @@ const useFontLoaded = (enabled = true) => {
|
|
|
1479
1478
|
return loaded;
|
|
1480
1479
|
};
|
|
1481
1480
|
|
|
1481
|
+
function createInitialState() {
|
|
1482
|
+
return {
|
|
1483
|
+
entries: [],
|
|
1484
|
+
savedBodyOverflow: '',
|
|
1485
|
+
savedBodyPaddingRight: null,
|
|
1486
|
+
docTouchStartHandler: null,
|
|
1487
|
+
docTouchMoveHandler: null,
|
|
1488
|
+
touchStartY: 0,
|
|
1489
|
+
touchStartX: 0,
|
|
1490
|
+
nonIOSLocked: false,
|
|
1491
|
+
nonIOSReservedScrollBarGap: false,
|
|
1492
|
+
};
|
|
1493
|
+
}
|
|
1494
|
+
function isIOS(win) {
|
|
1495
|
+
const { platform, maxTouchPoints, userAgent } = win.navigator;
|
|
1496
|
+
return (/iP(ad|hone|od)/.test(platform) ||
|
|
1497
|
+
(platform === 'MacIntel' && maxTouchPoints > 1) ||
|
|
1498
|
+
/iPad|iPhone|iPod/.test(userAgent));
|
|
1499
|
+
}
|
|
1500
|
+
function isScrollableElement(el, win) {
|
|
1501
|
+
const { overflow, overflowX, overflowY } = win.getComputedStyle(el);
|
|
1502
|
+
if (!/(auto|scroll|overlay)/.test(overflow + overflowX + overflowY))
|
|
1503
|
+
return false;
|
|
1504
|
+
return (el.scrollHeight > el.clientHeight + 1 || el.scrollWidth > el.clientWidth + 1);
|
|
1505
|
+
}
|
|
1506
|
+
function isScrollBoundaryHit(scrollable, dx, dy) {
|
|
1507
|
+
if (Math.abs(dy) >= Math.abs(dx)) {
|
|
1508
|
+
if (dy > 0 && scrollable.scrollTop <= 0)
|
|
1509
|
+
return true;
|
|
1510
|
+
return (dy < 0 &&
|
|
1511
|
+
scrollable.scrollTop + scrollable.clientHeight >=
|
|
1512
|
+
scrollable.scrollHeight - 1);
|
|
1513
|
+
}
|
|
1514
|
+
if (dx > 0 && scrollable.scrollLeft <= 0)
|
|
1515
|
+
return true;
|
|
1516
|
+
return (dx < 0 &&
|
|
1517
|
+
scrollable.scrollLeft + scrollable.clientWidth >= scrollable.scrollWidth - 1);
|
|
1518
|
+
}
|
|
1519
|
+
function findNearestScrollableAncestorWithinBoundary(el, win, boundary) {
|
|
1520
|
+
const { body, documentElement } = win.document;
|
|
1521
|
+
let cur = el;
|
|
1522
|
+
while (cur && cur !== body && cur !== documentElement) {
|
|
1523
|
+
if (isScrollableElement(cur, win))
|
|
1524
|
+
return cur;
|
|
1525
|
+
if (cur === boundary)
|
|
1526
|
+
break;
|
|
1527
|
+
cur = cur.parentElement;
|
|
1528
|
+
}
|
|
1529
|
+
return null;
|
|
1530
|
+
}
|
|
1531
|
+
function getActiveEntries(state) {
|
|
1532
|
+
return state.entries.filter((entry) => entry.active);
|
|
1533
|
+
}
|
|
1534
|
+
function getBoundaryForEntry(topEntry) {
|
|
1535
|
+
return topEntry.kind === 'element' ? topEntry.element : null;
|
|
1536
|
+
}
|
|
1537
|
+
function getScrollableWithinBoundary(target, win, boundary) {
|
|
1538
|
+
if (boundary && !boundary.contains(target)) {
|
|
1539
|
+
return null;
|
|
1540
|
+
}
|
|
1541
|
+
return findNearestScrollableAncestorWithinBoundary(target, win, boundary);
|
|
1542
|
+
}
|
|
1543
|
+
function getEntryScopedScrollable(topEntry, target, win, { allowAnonymous = false } = {}) {
|
|
1544
|
+
const boundary = getBoundaryForEntry(topEntry);
|
|
1545
|
+
if (!boundary && !allowAnonymous) {
|
|
1546
|
+
return null;
|
|
1547
|
+
}
|
|
1548
|
+
return getScrollableWithinBoundary(target, win, boundary);
|
|
1549
|
+
}
|
|
1550
|
+
function getAllowTouchMoveScrollable(entry, target, win) {
|
|
1551
|
+
if (entry.allowTouchMove?.(target) !== true)
|
|
1552
|
+
return null;
|
|
1553
|
+
return getEntryScopedScrollable(entry, target, win, {
|
|
1554
|
+
allowAnonymous: true,
|
|
1555
|
+
});
|
|
1556
|
+
}
|
|
1557
|
+
function canEntryAllowInnerScroll(entry, target, win, dx, dy) {
|
|
1558
|
+
const allowTouchMoveScrollable = getAllowTouchMoveScrollable(entry, target, win);
|
|
1559
|
+
if (allowTouchMoveScrollable) {
|
|
1560
|
+
return !isScrollBoundaryHit(allowTouchMoveScrollable, dx, dy);
|
|
1561
|
+
}
|
|
1562
|
+
const boundaryScrollable = getEntryScopedScrollable(entry, target, win);
|
|
1563
|
+
if (boundaryScrollable) {
|
|
1564
|
+
return !isScrollBoundaryHit(boundaryScrollable, dx, dy);
|
|
1565
|
+
}
|
|
1566
|
+
return false;
|
|
1567
|
+
}
|
|
1568
|
+
function findEntryIndex(state, targetElement, entryKey) {
|
|
1569
|
+
if (entryKey) {
|
|
1570
|
+
return state.entries.findIndex((entry) => entry.key === entryKey);
|
|
1571
|
+
}
|
|
1572
|
+
if (targetElement) {
|
|
1573
|
+
for (let i = state.entries.length - 1; i >= 0; i--) {
|
|
1574
|
+
const entry = state.entries[i];
|
|
1575
|
+
if (entry.kind === 'element' && entry.element === targetElement) {
|
|
1576
|
+
return i;
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
return -1;
|
|
1580
|
+
}
|
|
1581
|
+
for (let i = state.entries.length - 1; i >= 0; i--) {
|
|
1582
|
+
if (state.entries[i].kind === 'anonymous') {
|
|
1583
|
+
return i;
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
return -1;
|
|
1587
|
+
}
|
|
1588
|
+
function ensureEntry(state, targetElement, options = {}) {
|
|
1589
|
+
const index = findEntryIndex(state, targetElement, options.entryKey);
|
|
1590
|
+
const kind = targetElement ? 'element' : 'anonymous';
|
|
1591
|
+
if (index >= 0) {
|
|
1592
|
+
const entry = state.entries[index];
|
|
1593
|
+
entry.kind = kind;
|
|
1594
|
+
entry.element = targetElement ?? null;
|
|
1595
|
+
entry.reserveScrollBarGap = Boolean(options.reserveScrollBarGap);
|
|
1596
|
+
entry.allowTouchMove = options.allowTouchMove;
|
|
1597
|
+
return entry;
|
|
1598
|
+
}
|
|
1599
|
+
const entry = {
|
|
1600
|
+
key: options.entryKey ?? Symbol('scroll-lock-entry'),
|
|
1601
|
+
kind,
|
|
1602
|
+
element: targetElement ?? null,
|
|
1603
|
+
active: true,
|
|
1604
|
+
reserveScrollBarGap: Boolean(options.reserveScrollBarGap),
|
|
1605
|
+
allowTouchMove: options.allowTouchMove,
|
|
1606
|
+
};
|
|
1607
|
+
state.entries.push(entry);
|
|
1608
|
+
return entry;
|
|
1609
|
+
}
|
|
1610
|
+
function shouldPreventTouchMove(e, state, win) {
|
|
1611
|
+
if (e.touches.length > 1)
|
|
1612
|
+
return false;
|
|
1613
|
+
if (e.ctrlKey)
|
|
1614
|
+
return false;
|
|
1615
|
+
if (!e.cancelable)
|
|
1616
|
+
return false;
|
|
1617
|
+
const touch = e.touches[0];
|
|
1618
|
+
if (!touch)
|
|
1619
|
+
return false;
|
|
1620
|
+
const dy = touch.clientY - state.touchStartY;
|
|
1621
|
+
const dx = touch.clientX - state.touchStartX;
|
|
1622
|
+
if (dy === 0 && dx === 0)
|
|
1623
|
+
return false;
|
|
1624
|
+
if (getActiveEntries(state).length === 0)
|
|
1625
|
+
return false;
|
|
1626
|
+
const target = e.target;
|
|
1627
|
+
if (!(target instanceof win.Element)) {
|
|
1628
|
+
return true;
|
|
1629
|
+
}
|
|
1630
|
+
for (let i = state.entries.length - 1; i >= 0; i--) {
|
|
1631
|
+
if (canEntryAllowInnerScroll(state.entries[i], target, win, dx, dy)) {
|
|
1632
|
+
return false;
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
return true;
|
|
1636
|
+
}
|
|
1637
|
+
function lockIOS(state, win) {
|
|
1638
|
+
const doc = win.document;
|
|
1639
|
+
state.docTouchStartHandler = (e) => {
|
|
1640
|
+
if (e.touches.length > 0) {
|
|
1641
|
+
state.touchStartY = e.touches[0].clientY;
|
|
1642
|
+
state.touchStartX = e.touches[0].clientX;
|
|
1643
|
+
}
|
|
1644
|
+
};
|
|
1645
|
+
state.docTouchMoveHandler = (e) => {
|
|
1646
|
+
if (shouldPreventTouchMove(e, state, win)) {
|
|
1647
|
+
e.preventDefault();
|
|
1648
|
+
}
|
|
1649
|
+
};
|
|
1650
|
+
doc.addEventListener('touchstart', state.docTouchStartHandler, {
|
|
1651
|
+
passive: true,
|
|
1652
|
+
});
|
|
1653
|
+
doc.addEventListener('touchmove', state.docTouchMoveHandler, {
|
|
1654
|
+
passive: false,
|
|
1655
|
+
});
|
|
1656
|
+
}
|
|
1657
|
+
function unlockIOS(state, win) {
|
|
1658
|
+
const doc = win.document;
|
|
1659
|
+
if (state.docTouchStartHandler) {
|
|
1660
|
+
doc.removeEventListener('touchstart', state.docTouchStartHandler);
|
|
1661
|
+
state.docTouchStartHandler = null;
|
|
1662
|
+
}
|
|
1663
|
+
if (state.docTouchMoveHandler) {
|
|
1664
|
+
doc.removeEventListener('touchmove', state.docTouchMoveHandler);
|
|
1665
|
+
state.docTouchMoveHandler = null;
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
function lockNonIOS(state, win, { reserveScrollBarGap = false }) {
|
|
1669
|
+
const body = win.document.body;
|
|
1670
|
+
const gap = win.innerWidth - win.document.documentElement.clientWidth;
|
|
1671
|
+
state.savedBodyOverflow = body.style.overflow;
|
|
1672
|
+
if (reserveScrollBarGap && gap > 0) {
|
|
1673
|
+
const computedPaddingRight = parseInt(win.getComputedStyle(body).paddingRight, 10) || 0;
|
|
1674
|
+
state.savedBodyPaddingRight = body.style.paddingRight;
|
|
1675
|
+
body.style.paddingRight = `${computedPaddingRight + gap}px`;
|
|
1676
|
+
}
|
|
1677
|
+
body.style.overflow = 'hidden';
|
|
1678
|
+
}
|
|
1679
|
+
function unlockNonIOS(state, win) {
|
|
1680
|
+
const body = win.document.body;
|
|
1681
|
+
body.style.overflow = state.savedBodyOverflow;
|
|
1682
|
+
if (state.savedBodyPaddingRight !== null) {
|
|
1683
|
+
if (state.savedBodyPaddingRight === '') {
|
|
1684
|
+
body.style.removeProperty('padding-right');
|
|
1685
|
+
}
|
|
1686
|
+
else {
|
|
1687
|
+
body.style.paddingRight = state.savedBodyPaddingRight;
|
|
1688
|
+
}
|
|
1689
|
+
state.savedBodyPaddingRight = null;
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
function bodyLockDesired(state) {
|
|
1693
|
+
return getActiveEntries(state).length > 0;
|
|
1694
|
+
}
|
|
1695
|
+
function shouldReserveScrollBarGap(state) {
|
|
1696
|
+
return state.entries.some((entry) => entry.active && entry.reserveScrollBarGap);
|
|
1697
|
+
}
|
|
1698
|
+
function syncIOS(state, win) {
|
|
1699
|
+
const desired = state.entries.length > 0;
|
|
1700
|
+
const attached = state.docTouchMoveHandler !== null;
|
|
1701
|
+
if (desired === attached)
|
|
1702
|
+
return;
|
|
1703
|
+
if (desired) {
|
|
1704
|
+
lockIOS(state, win);
|
|
1705
|
+
}
|
|
1706
|
+
else {
|
|
1707
|
+
unlockIOS(state, win);
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
function syncNonIOS(state, win) {
|
|
1711
|
+
const desired = bodyLockDesired(state);
|
|
1712
|
+
const reserveScrollBarGap = shouldReserveScrollBarGap(state);
|
|
1713
|
+
if (!desired) {
|
|
1714
|
+
if (!state.nonIOSLocked)
|
|
1715
|
+
return;
|
|
1716
|
+
unlockNonIOS(state, win);
|
|
1717
|
+
state.nonIOSLocked = false;
|
|
1718
|
+
state.nonIOSReservedScrollBarGap = false;
|
|
1719
|
+
return;
|
|
1720
|
+
}
|
|
1721
|
+
if (!state.nonIOSLocked) {
|
|
1722
|
+
lockNonIOS(state, win, {
|
|
1723
|
+
reserveScrollBarGap,
|
|
1724
|
+
});
|
|
1725
|
+
state.nonIOSLocked = true;
|
|
1726
|
+
state.nonIOSReservedScrollBarGap = reserveScrollBarGap;
|
|
1727
|
+
return;
|
|
1728
|
+
}
|
|
1729
|
+
if (reserveScrollBarGap === state.nonIOSReservedScrollBarGap)
|
|
1730
|
+
return;
|
|
1731
|
+
unlockNonIOS(state, win);
|
|
1732
|
+
lockNonIOS(state, win, { reserveScrollBarGap });
|
|
1733
|
+
state.nonIOSReservedScrollBarGap = reserveScrollBarGap;
|
|
1734
|
+
}
|
|
1735
|
+
function syncScrollLock(state, win) {
|
|
1736
|
+
if (isIOS(win)) {
|
|
1737
|
+
syncIOS(state, win);
|
|
1738
|
+
}
|
|
1739
|
+
else {
|
|
1740
|
+
syncNonIOS(state, win);
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
function activateEntry(state, win, targetElement, options = {}) {
|
|
1744
|
+
const entry = ensureEntry(state, targetElement, options);
|
|
1745
|
+
entry.active = true;
|
|
1746
|
+
syncScrollLock(state, win);
|
|
1747
|
+
}
|
|
1748
|
+
function lock(state, win, targetElement, options = {}) {
|
|
1749
|
+
activateEntry(state, win, targetElement, options);
|
|
1750
|
+
}
|
|
1751
|
+
function unlock(state, win, targetElement, options = {}) {
|
|
1752
|
+
const index = findEntryIndex(state, targetElement, options.entryKey);
|
|
1753
|
+
if (index < 0)
|
|
1754
|
+
return;
|
|
1755
|
+
state.entries.splice(index, 1);
|
|
1756
|
+
syncScrollLock(state, win);
|
|
1757
|
+
}
|
|
1758
|
+
function pause(state, win, targetElement, options = {}) {
|
|
1759
|
+
const index = findEntryIndex(state, targetElement, options.entryKey);
|
|
1760
|
+
if (index < 0 || state.entries[index].active === false)
|
|
1761
|
+
return;
|
|
1762
|
+
state.entries[index].active = false;
|
|
1763
|
+
syncScrollLock(state, win);
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1766
|
+
const SCROLL_LOCK_KEY = '__SUI_SCROLL_LOCK__';
|
|
1767
|
+
function getStoredScrollLockState(win) {
|
|
1768
|
+
return win[SCROLL_LOCK_KEY];
|
|
1769
|
+
}
|
|
1770
|
+
function setStoredScrollLockState(win, state) {
|
|
1771
|
+
const global = win;
|
|
1772
|
+
global[SCROLL_LOCK_KEY] = state;
|
|
1773
|
+
return state;
|
|
1774
|
+
}
|
|
1775
|
+
function getOrCreateScrollLockState(win) {
|
|
1776
|
+
const state = getStoredScrollLockState(win);
|
|
1777
|
+
if (!state) {
|
|
1778
|
+
return setStoredScrollLockState(win, createInitialState());
|
|
1779
|
+
}
|
|
1780
|
+
return state;
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
function applyLockState(state, win, targetElement, options, disabled) {
|
|
1784
|
+
lock(state, win, targetElement, options);
|
|
1785
|
+
if (disabled) {
|
|
1786
|
+
pause(state, win, targetElement, options);
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
function useResolvedElement(target) {
|
|
1790
|
+
const [resolvedElement, setResolvedElement] = useState(() => (getRefElement(target) ?? null));
|
|
1791
|
+
const targetRef = useRef(target);
|
|
1792
|
+
targetRef.current = target;
|
|
1793
|
+
useEffect(() => {
|
|
1794
|
+
const nextResolvedElement = (getRefElement(targetRef.current) ??
|
|
1795
|
+
null);
|
|
1796
|
+
setResolvedElement((current) => current === nextResolvedElement ? current : nextResolvedElement);
|
|
1797
|
+
});
|
|
1798
|
+
return resolvedElement;
|
|
1799
|
+
}
|
|
1482
1800
|
const useBodyScrollLock = (isLocked, targetElement, options = {}) => {
|
|
1483
|
-
const { disabled = false, reserveScrollBarGap = true
|
|
1484
|
-
const {
|
|
1801
|
+
const { disabled = false, reserveScrollBarGap = true } = options;
|
|
1802
|
+
const { allowTouchMove } = options;
|
|
1803
|
+
const entryKeyRef = useRef(Symbol('use-body-scroll-lock-entry'));
|
|
1804
|
+
const resolvedElement = useResolvedElement(targetElement);
|
|
1805
|
+
const { globalThis: global } = useWindowContext();
|
|
1485
1806
|
useEffect(() => {
|
|
1486
|
-
if (
|
|
1807
|
+
if (!isLocked)
|
|
1487
1808
|
return;
|
|
1488
|
-
const
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1809
|
+
const win = global;
|
|
1810
|
+
const state = getOrCreateScrollLockState(global);
|
|
1811
|
+
const entryKey = entryKeyRef.current;
|
|
1812
|
+
const syncOptions = {
|
|
1813
|
+
reserveScrollBarGap,
|
|
1814
|
+
allowTouchMove,
|
|
1815
|
+
entryKey,
|
|
1816
|
+
};
|
|
1817
|
+
applyLockState(state, win, resolvedElement, syncOptions, disabled);
|
|
1495
1818
|
return () => {
|
|
1496
|
-
|
|
1497
|
-
|
|
1819
|
+
const currentState = getStoredScrollLockState(global);
|
|
1820
|
+
if (currentState) {
|
|
1821
|
+
unlock(currentState, win, resolvedElement, { entryKey });
|
|
1498
1822
|
}
|
|
1499
1823
|
};
|
|
1824
|
+
}, [isLocked, global]);
|
|
1825
|
+
useEffect(() => {
|
|
1826
|
+
if (!isLocked)
|
|
1827
|
+
return;
|
|
1828
|
+
const win = global;
|
|
1829
|
+
const state = getOrCreateScrollLockState(global);
|
|
1830
|
+
const entryKey = entryKeyRef.current;
|
|
1831
|
+
const syncOptions = {
|
|
1832
|
+
reserveScrollBarGap,
|
|
1833
|
+
allowTouchMove,
|
|
1834
|
+
entryKey,
|
|
1835
|
+
};
|
|
1836
|
+
applyLockState(state, win, resolvedElement, syncOptions, disabled);
|
|
1500
1837
|
}, [
|
|
1501
|
-
|
|
1502
|
-
targetElement,
|
|
1838
|
+
allowTouchMove,
|
|
1503
1839
|
disabled,
|
|
1840
|
+
isLocked,
|
|
1841
|
+
global,
|
|
1842
|
+
resolvedElement,
|
|
1504
1843
|
reserveScrollBarGap,
|
|
1505
|
-
allowTouchMove,
|
|
1506
|
-
document,
|
|
1507
1844
|
]);
|
|
1508
1845
|
};
|
|
1509
1846
|
|
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ringcentral/spring-base",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.1",
|
|
4
4
|
"author": "RingCentral",
|
|
5
5
|
"description": "Core utilities, hooks, and foundational functionality for Spring UI components, providing essential building blocks for React applications",
|
|
6
6
|
"main": "./index.js",
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"@mui/utils": "^6.0.2",
|
|
11
11
|
"@types/lodash": "^4.14.182",
|
|
12
|
-
"body-scroll-lock": "4.0.0-beta.0",
|
|
13
12
|
"clsx": "^1.2.1",
|
|
14
13
|
"framer-motion": "^6.5.1",
|
|
15
14
|
"lodash": "^4.17.21",
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
declare type Win = Window & typeof globalThis;
|
|
2
|
+
export interface ScrollLockOptions {
|
|
3
|
+
reserveScrollBarGap?: boolean;
|
|
4
|
+
allowTouchMove?: (el: Element) => boolean;
|
|
5
|
+
entryKey?: symbol;
|
|
6
|
+
}
|
|
7
|
+
interface LockEntry {
|
|
8
|
+
key: symbol;
|
|
9
|
+
kind: 'anonymous' | 'element';
|
|
10
|
+
element: HTMLElement | null;
|
|
11
|
+
active: boolean;
|
|
12
|
+
reserveScrollBarGap: boolean;
|
|
13
|
+
allowTouchMove?: (el: Element) => boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface WindowState {
|
|
16
|
+
entries: LockEntry[];
|
|
17
|
+
savedBodyOverflow: string;
|
|
18
|
+
savedBodyPaddingRight: string | null;
|
|
19
|
+
docTouchStartHandler: ((e: TouchEvent) => void) | null;
|
|
20
|
+
docTouchMoveHandler: ((e: TouchEvent) => void) | null;
|
|
21
|
+
touchStartY: number;
|
|
22
|
+
touchStartX: number;
|
|
23
|
+
nonIOSLocked: boolean;
|
|
24
|
+
nonIOSReservedScrollBarGap: boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare function createInitialState(): WindowState;
|
|
27
|
+
export declare function lock(state: WindowState, win: Win, targetElement?: HTMLElement | null, options?: ScrollLockOptions): void;
|
|
28
|
+
export declare function unlock(state: WindowState, win: Win, targetElement?: HTMLElement | null, options?: ScrollLockOptions): void;
|
|
29
|
+
export declare function pause(state: WindowState, win: Win, targetElement?: HTMLElement | null, options?: ScrollLockOptions): void;
|
|
30
|
+
export declare function clearAllLocks(state: WindowState, win: Win): void;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { WindowState } from './bodyScrollLock';
|
|
2
|
+
export declare const SCROLL_LOCK_KEY = "__SUI_SCROLL_LOCK__";
|
|
3
|
+
export declare function getStoredScrollLockState(win: typeof globalThis): WindowState | undefined;
|
|
4
|
+
export declare function setStoredScrollLockState(win: typeof globalThis, state: WindowState): WindowState;
|
|
5
|
+
export declare function getOrCreateScrollLockState(win: typeof globalThis): WindowState;
|
|
6
|
+
export declare function deleteStoredScrollLockState(win: typeof globalThis): void;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
export declare type UseBodyScrollLockTarget = HTMLElement | RefObject<HTMLElement | null> | null | undefined;
|
|
1
3
|
export interface UseBodyScrollLockOptions {
|
|
2
4
|
disabled?: boolean;
|
|
3
5
|
reserveScrollBarGap?: boolean;
|
|
4
6
|
allowTouchMove?: (el: Element) => boolean;
|
|
5
7
|
}
|
|
6
|
-
export declare const useBodyScrollLock: (isLocked: boolean, targetElement?:
|
|
8
|
+
export declare const useBodyScrollLock: (isLocked: boolean, targetElement?: UseBodyScrollLockTarget, options?: UseBodyScrollLockOptions) => void;
|
|
@@ -8,6 +8,7 @@ export declare type ClassesProp<K extends string> = {
|
|
|
8
8
|
classes?: Partial<Record<K | 'root' | GlobalStateClassesKey, string>>;
|
|
9
9
|
};
|
|
10
10
|
export declare type PropsWithRoot<P, R extends ElementType, O extends string = '', E = HTMLDataAttribute> = P & Omit<ComponentPropsWithRef<R>, keyof P | O> & E;
|
|
11
|
+
export declare type SlotProps<R extends ElementType, O extends keyof ComponentPropsWithRef<R> = never, E = HTMLDataAttribute> = Omit<ComponentPropsWithRef<R>, O | 'className'> & E;
|
|
11
12
|
export declare type StandardProps<P, C extends string, R extends ElementType | void = void, O extends string = '', ExtendAttributes = HTMLDataAttribute> = ClassesProp<C> & (R extends ElementType ? PropsWithRoot<P, R, 'classes' | O, ExtendAttributes> : P & {
|
|
12
13
|
className?: string;
|
|
13
14
|
}) & ExtendAttributes;
|