@foxford/ui 2.107.1-beta-270ec35-20260428 → 2.108.0
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/dts/index.d.ts +5 -1
- package/hooks/useScrollLock.js +1 -1
- package/hooks/useScrollLock.js.map +1 -1
- package/hooks/useScrollLock.mjs +1 -1
- package/hooks/useScrollLock.mjs.map +1 -1
- package/icon-pack/src/collection.json.js +1 -1
- package/icon-pack/src/collection.json.mjs +1 -1
- package/package.json +2 -2
package/dts/index.d.ts
CHANGED
|
@@ -1523,7 +1523,8 @@ type IconName$1 =
|
|
|
1523
1523
|
| 'youtubeSocial'
|
|
1524
1524
|
| 'facebookSocial'
|
|
1525
1525
|
| 'vkSocial'
|
|
1526
|
-
| '
|
|
1526
|
+
| 'sbPrimeFill'
|
|
1527
|
+
| 'sbSpasiboFill'
|
|
1527
1528
|
| 'giftAltFill'
|
|
1528
1529
|
| 'giftFill'
|
|
1529
1530
|
| 'messageCircleChatFill'
|
|
@@ -1621,9 +1622,12 @@ type IconName$1 =
|
|
|
1621
1622
|
| 'rotateFill'
|
|
1622
1623
|
| 'chevronDownRightFill'
|
|
1623
1624
|
| 'cornerDownRightFill'
|
|
1625
|
+
| 'algoritmikaLogo'
|
|
1624
1626
|
| 'foxCoin'
|
|
1625
1627
|
| 'maxSocialColor'
|
|
1626
1628
|
| 'sbSpasiboGradientColor'
|
|
1629
|
+
| 'sbPrimeGradientColor'
|
|
1630
|
+
| 'sbPrimeColor'
|
|
1627
1631
|
| 'sbSpasiboColor'
|
|
1628
1632
|
| 'youtubeAltSocialColor'
|
|
1629
1633
|
| 'whatsappSocialColor'
|
package/hooks/useScrollLock.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var React=require('react');var getDomTargets=require('../shared/utils/getDomTargets.js');const TOUCH_EVENT_OPTIONS={capture:!0,passive:!1};const supportsScrollbarGutter=typeof CSS!='undefined'&&typeof CSS.supports=='function'&&CSS.supports('scrollbar-gutter: stable');const isIosDevice=typeof window!='undefined'&&window.navigator?.userAgent&&(/iP(ad|hone|od)/.test(window.navigator.userAgent)||window.navigator.userAgent.includes('Macintosh')&&window.navigator.maxTouchPoints>1);const iosScrollableBlocks=[];let iosActiveScrollElement=null;let iosTouchStartY=null;let touchStartHandler=null;let touchMoveHandler=null;function getScrollLockCount(){return Number(document.documentElement.dataset.scrollLockCount||0)}function setScrollLockCount(t){document.documentElement.dataset.scrollLockCount=t.toString()}function applyScrollLockStyles(){const t=document.documentElement;if(t.dataset.prevOverflow=t.style.overflow||'',supportsScrollbarGutter&&!isIosDevice)t.style.scrollbarGutter='stable';else{const e=window.innerWidth-document.documentElement.clientWidth;if(t.dataset.prevPaddingRight=t.style.paddingRight||'',e>0){const o=parseFloat(getComputedStyle(t).paddingRight)||0;t.style.paddingRight=`${o+e}px`}}t.style.overflow='hidden'}function resetScrollLockStyles(){const t=document.documentElement;t.style.overflow=t.dataset.prevOverflow||'',t.style.paddingRight=t.dataset.prevPaddingRight||'',delete t.dataset.prevOverflow,delete t.dataset.prevPaddingRight}function isScrollable(t){const e=getComputedStyle(t);return(e.overflowY==='auto'||e.overflowY==='scroll')&&t.scrollHeight>t.clientHeight}function findScrollableParent(t,e){let o=t;for(;o&&o!==e.parentElement;){if(isScrollable(o))return o;o=o.parentElement}return isScrollable(e)?e:null}function unlockTargetScroll(t){t.dataset.prevOverflow!==void 0&&(t.style.overflow=t.dataset.prevOverflow),t.dataset.prevPaddingRight!==void 0&&(t.style.paddingRight=t.dataset.prevPaddingRight),delete t.dataset.prevOverflow,delete t.dataset.prevPaddingRight,supportsScrollbarGutter&&(t.style.scrollbarGutter='')}exports.useScrollLock=t=>{const{locked:e,iosAllowedScrollContainer:o=document.documentElement,target:l}=t;const r=l===void 0||l===document.documentElement||l===document.body;React.useEffect(()=>{if(!l||r)return;const t=getDomTargets.getDomTargets(l)[0];return
|
|
1
|
+
'use strict';var React=require('react');var getDomTargets=require('../shared/utils/getDomTargets.js');const TOUCH_EVENT_OPTIONS={capture:!0,passive:!1};const supportsScrollbarGutter=typeof CSS!='undefined'&&typeof CSS.supports=='function'&&CSS.supports('scrollbar-gutter: stable');const isIosDevice=typeof window!='undefined'&&window.navigator?.userAgent&&(/iP(ad|hone|od)/.test(window.navigator.userAgent)||window.navigator.userAgent.includes('Macintosh')&&window.navigator.maxTouchPoints>1);const iosScrollableBlocks=[];let iosActiveScrollElement=null;let iosTouchStartY=null;let touchStartHandler=null;let touchMoveHandler=null;function getScrollLockCount(){return Number(document.documentElement.dataset.scrollLockCount||0)}function setScrollLockCount(t){document.documentElement.dataset.scrollLockCount=t.toString()}function applyScrollLockStyles(){const t=document.documentElement;if(t.dataset.prevOverflow=t.style.overflow||'',supportsScrollbarGutter&&!isIosDevice)t.style.scrollbarGutter='stable';else{const e=window.innerWidth-document.documentElement.clientWidth;if(t.dataset.prevPaddingRight=t.style.paddingRight||'',e>0){const o=parseFloat(getComputedStyle(t).paddingRight)||0;t.style.paddingRight=`${o+e}px`}}t.style.overflow='hidden'}function resetScrollLockStyles(){const t=document.documentElement;t.style.overflow=t.dataset.prevOverflow||'',t.style.paddingRight=t.dataset.prevPaddingRight||'',delete t.dataset.prevOverflow,delete t.dataset.prevPaddingRight}function isScrollable(t){const e=getComputedStyle(t);return(e.overflowY==='auto'||e.overflowY==='scroll')&&t.scrollHeight>t.clientHeight}function findScrollableParent(t,e){let o=t;for(;o&&o!==e.parentElement;){if(isScrollable(o))return o;o=o.parentElement}return isScrollable(e)?e:null}function unlockTargetScroll(t){t.dataset.prevOverflow!==void 0&&(t.style.overflow=t.dataset.prevOverflow),t.dataset.prevPaddingRight!==void 0&&(t.style.paddingRight=t.dataset.prevPaddingRight),delete t.dataset.prevOverflow,delete t.dataset.prevPaddingRight,supportsScrollbarGutter&&(t.style.scrollbarGutter='')}exports.useScrollLock=t=>{const{locked:e,iosAllowedScrollContainer:o=document.documentElement,target:l}=t;const r=l===void 0||l===document.documentElement||l===document.body;React.useEffect(()=>{if(!l||r)return;const t=getDomTargets.getDomTargets(l)[0];return e?(t=>{const e=getComputedStyle(t);t.dataset.prevOverflow===void 0&&(t.dataset.prevOverflow=e.overflow||''),t.dataset.prevPaddingRight===void 0&&(t.dataset.prevPaddingRight=e.paddingRight||'');const o=(parseFloat(e.borderLeftWidth)||0)+(parseFloat(e.borderRightWidth)||0);const l=e.overflow;t.style.overflow='scroll';const r=t.offsetWidth-t.clientWidth-o;if(t.style.overflow=l,supportsScrollbarGutter)t.style.scrollbarGutter='stable';else if(r>0){const e=parseFloat(t.dataset.prevPaddingRight)||0;t.style.paddingRight=`${e+r}px`}t.style.overflow='hidden'})(t):t.dataset.prevOverflow!==void 0&&unlockTargetScroll(t),()=>{unlockTargetScroll(t)}},[l,e,r]),React.useEffect(()=>{if(e&&r)return isIosDevice?((t=>{iosScrollableBlocks.push(t);const e=getScrollLockCount();e===0&&(applyScrollLockStyles(),touchMoveHandler||touchStartHandler||(touchStartHandler=t=>{const e=t.target;if(!(e instanceof HTMLElement))return iosActiveScrollElement=null,void(iosTouchStartY=null);iosTouchStartY=t.touches[0]?.clientY??null,iosActiveScrollElement=null;for(const t of iosScrollableBlocks)if(t.contains(e)){const o=findScrollableParent(e,t);if(o){iosActiveScrollElement=o;break}}},touchMoveHandler=t=>{const e=t.touches[0];if(!e||t.touches.length===2||(t=>{if(!(t&&t instanceof HTMLElement))return!1;const e=t.ownerDocument?.defaultView?.getSelection();return!(!e||e.isCollapsed||!e.containsNode(t,!0))||'selectionStart'in t&&'selectionEnd'in t&&Number(t.selectionStart)<Number(t.selectionEnd)&&t.ownerDocument?.activeElement===t})(t.target))return;if(!t.cancelable)return;if(!iosActiveScrollElement||iosTouchStartY===null)return void t.preventDefault();const o=e.clientY-Number(iosTouchStartY);(iosActiveScrollElement.scrollTop<=0&&o>0||iosActiveScrollElement.scrollTop+iosActiveScrollElement.clientHeight>=iosActiveScrollElement.scrollHeight&&o<0)&&t.preventDefault()},document.addEventListener('touchstart',touchStartHandler,TOUCH_EVENT_OPTIONS),document.addEventListener('touchmove',touchMoveHandler,TOUCH_EVENT_OPTIONS))),setScrollLockCount(e+1)})(getDomTargets.getDomTargets(o)[0]),()=>{(()=>{iosScrollableBlocks.pop();const t=getScrollLockCount();const e=Math.max(0,t-1);setScrollLockCount(e),e===0&&(resetScrollLockStyles(),touchStartHandler&&(document.removeEventListener('touchstart',touchStartHandler,TOUCH_EVENT_OPTIONS),touchStartHandler=null),touchMoveHandler&&(document.removeEventListener('touchmove',touchMoveHandler,TOUCH_EVENT_OPTIONS),touchMoveHandler=null),iosActiveScrollElement=null,iosTouchStartY=null)})()}):((()=>{const t=getScrollLockCount();t===0&&applyScrollLockStyles(),setScrollLockCount(t+1)})(),()=>{(()=>{const t=getScrollLockCount();if(t<=0)return;const e=t-1;setScrollLockCount(e),e===0&&resetScrollLockStyles()})()})},[o,r,e])};
|
|
2
2
|
//# sourceMappingURL=useScrollLock.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useScrollLock.js","sources":["../../../src/hooks/useScrollLock.ts"],"sourcesContent":["import { useEffect } from 'react'\nimport type { DomTarget, Nullable } from 'shared/types'\nimport { getDomTargets } from 'shared/utils/getDomTargets'\n\ntype ScrollLockParams = {\n /**\n * Блокировать скролл.\n */\n locked: boolean\n /**\n * Контейнер, в котором разрешена прокрутка на iOS при заблокированном скролле страницы.\n */\n iosAllowedScrollContainer?: DomTarget\n /**\n * Элемент, на котором блокируется скролл.\n *\n * @default 'document.documentElement'\n */\n target?: DomTarget\n}\n\nconst TOUCH_EVENT_OPTIONS = { capture: true, passive: false }\nconst DATA_SCROLL_LOCK_COUNT = 'scrollLockCount'\nconst DATA_PREV_OVERFLOW = 'prevOverflow'\nconst DATA_PREV_PADDING_RIGHT = 'prevPaddingRight'\n\nconst supportsScrollbarGutter =\n typeof CSS !== 'undefined' && typeof CSS.supports === 'function' && CSS.supports('scrollbar-gutter: stable')\nconst isIosDevice =\n typeof window !== 'undefined' &&\n window.navigator?.userAgent &&\n (/iP(ad|hone|od)/.test(window.navigator.userAgent) ||\n (window.navigator.userAgent.includes('Macintosh') && window.navigator.maxTouchPoints > 1))\n\nconst iosScrollableBlocks: HTMLElement[] = []\nlet iosActiveScrollElement: Nullable<HTMLElement> = null\nlet iosTouchStartY: Nullable<number> = null\nlet touchStartHandler: Nullable<(event: TouchEvent) => void> = null\nlet touchMoveHandler: Nullable<(event: TouchEvent) => void> = null\n\nfunction getScrollLockCount(): number {\n return Number(document.documentElement.dataset[DATA_SCROLL_LOCK_COUNT] || 0)\n}\n\nfunction setScrollLockCount(count: number) {\n document.documentElement.dataset[DATA_SCROLL_LOCK_COUNT] = count.toString()\n}\n\nfunction applyScrollLockStyles() {\n const root = document.documentElement\n root.dataset[DATA_PREV_OVERFLOW] = root.style.overflow || ''\n\n if (supportsScrollbarGutter && !isIosDevice) {\n root.style.scrollbarGutter = 'stable'\n } else {\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth\n root.dataset[DATA_PREV_PADDING_RIGHT] = root.style.paddingRight || ''\n if (scrollbarWidth > 0) {\n const currentPaddingRight = parseFloat(getComputedStyle(root).paddingRight) || 0\n root.style.paddingRight = `${currentPaddingRight + scrollbarWidth}px`\n }\n }\n root.style.overflow = 'hidden'\n}\n\nfunction resetScrollLockStyles() {\n const root = document.documentElement\n root.style.overflow = root.dataset[DATA_PREV_OVERFLOW] || ''\n root.style.paddingRight = root.dataset[DATA_PREV_PADDING_RIGHT] || ''\n delete root.dataset[DATA_PREV_OVERFLOW]\n delete root.dataset[DATA_PREV_PADDING_RIGHT]\n}\n\nfunction lockScroll() {\n const count = getScrollLockCount()\n if (count === 0) {\n applyScrollLockStyles()\n }\n setScrollLockCount(count + 1)\n}\n\nfunction unlockScroll() {\n const currentCount = getScrollLockCount()\n if (currentCount <= 0) {\n return\n }\n\n const nextCount = currentCount - 1\n setScrollLockCount(nextCount)\n if (nextCount === 0) {\n resetScrollLockStyles()\n }\n}\n\nfunction isScrollable(element: HTMLElement): boolean {\n const style = getComputedStyle(element)\n const overflowY = style.overflowY === 'auto' || style.overflowY === 'scroll'\n\n return overflowY && element.scrollHeight > element.clientHeight\n}\n\nfunction findScrollableParent(startElement: HTMLElement, root: HTMLElement): Nullable<HTMLElement> {\n let element: Nullable<HTMLElement> = startElement\n\n while (element && element !== root.parentElement) {\n if (isScrollable(element)) {\n return element\n }\n\n element = element.parentElement\n }\n\n if (isScrollable(root)) {\n return root\n }\n\n return null\n}\n\nfunction isTouchMoveAllowed(target: Nullable<EventTarget>): boolean {\n if (!target || !(target instanceof HTMLElement)) {\n return false\n }\n\n const selection = target.ownerDocument?.defaultView?.getSelection()\n if (selection && !selection.isCollapsed && selection.containsNode(target, true)) {\n return true\n }\n\n if (\n 'selectionStart' in target &&\n 'selectionEnd' in target &&\n Number(target.selectionStart) < Number(target.selectionEnd) &&\n target.ownerDocument?.activeElement === target\n ) {\n return true\n }\n\n return false\n}\n\nfunction addIOSEvents() {\n if (touchMoveHandler || touchStartHandler) {\n return\n }\n\n touchStartHandler = (event: TouchEvent) => {\n const target = event.target\n if (!(target instanceof HTMLElement)) {\n iosActiveScrollElement = null\n iosTouchStartY = null\n\n return\n }\n\n iosTouchStartY = event.touches[0]?.clientY ?? null\n iosActiveScrollElement = null\n for (const block of iosScrollableBlocks) {\n if (block.contains(target)) {\n const scrollElement = findScrollableParent(target, block)\n if (scrollElement) {\n iosActiveScrollElement = scrollElement\n break\n }\n }\n }\n }\n\n touchMoveHandler = (event: TouchEvent) => {\n const touch = event.touches[0]\n if (!touch || event.touches.length === 2 || isTouchMoveAllowed(event.target)) {\n return\n }\n\n if (!event.cancelable) {\n return\n }\n\n if (!iosActiveScrollElement || iosTouchStartY === null) {\n event.preventDefault()\n\n return\n }\n\n const currentY = touch.clientY\n const deltaY = currentY - Number(iosTouchStartY)\n const atTop = iosActiveScrollElement.scrollTop <= 0\n const atBottom =\n iosActiveScrollElement.scrollTop + iosActiveScrollElement.clientHeight >= iosActiveScrollElement.scrollHeight\n if ((atTop && deltaY > 0) || (atBottom && deltaY < 0)) {\n event.preventDefault()\n }\n }\n\n document.addEventListener('touchstart', touchStartHandler, TOUCH_EVENT_OPTIONS)\n document.addEventListener('touchmove', touchMoveHandler, TOUCH_EVENT_OPTIONS)\n}\n\nfunction removeIOSEvents() {\n if (touchStartHandler) {\n document.removeEventListener('touchstart', touchStartHandler, TOUCH_EVENT_OPTIONS)\n touchStartHandler = null\n }\n if (touchMoveHandler) {\n document.removeEventListener('touchmove', touchMoveHandler, TOUCH_EVENT_OPTIONS)\n touchMoveHandler = null\n }\n iosActiveScrollElement = null\n iosTouchStartY = null\n}\n\nfunction lockScrollIOS(scrollableContainer?: HTMLElement) {\n if (scrollableContainer) {\n iosScrollableBlocks.push(scrollableContainer)\n }\n const count = getScrollLockCount()\n if (count === 0) {\n applyScrollLockStyles()\n addIOSEvents()\n }\n setScrollLockCount(count + 1)\n}\n\nfunction unlockScrollIOS() {\n iosScrollableBlocks.pop()\n const count = getScrollLockCount()\n const nexCount = Math.max(0, count - 1)\n setScrollLockCount(nexCount)\n if (nexCount === 0) {\n resetScrollLockStyles()\n removeIOSEvents()\n }\n}\n\nfunction lockTargetScroll(element: HTMLElement) {\n const style = getComputedStyle(element)\n if (element.dataset[DATA_PREV_OVERFLOW] === undefined) {\n element.dataset[DATA_PREV_OVERFLOW] = style.overflow || ''\n }\n if (element.dataset[DATA_PREV_PADDING_RIGHT] === undefined) {\n element.dataset[DATA_PREV_PADDING_RIGHT] = style.paddingRight || ''\n }\n\n const borderLeft = parseFloat(style.borderLeftWidth) || 0\n const borderRight = parseFloat(style.borderRightWidth) || 0\n const borderWidth = borderLeft + borderRight\n const originalOverflow = style.overflow\n element.style.overflow = 'scroll'\n const scrollbarWidth = element.offsetWidth - element.clientWidth - borderWidth\n element.style.overflow = originalOverflow\n if (supportsScrollbarGutter) {\n element.style.scrollbarGutter = 'stable'\n } else if (scrollbarWidth > 0) {\n const currentPaddingRight = parseFloat(element.dataset[DATA_PREV_PADDING_RIGHT]) || 0\n element.style.paddingRight = `${currentPaddingRight + scrollbarWidth}px`\n }\n element.style.overflow = 'hidden'\n}\n\nfunction unlockTargetScroll(element: HTMLElement) {\n if (element.dataset[DATA_PREV_OVERFLOW] !== undefined) {\n element.style.overflow = element.dataset[DATA_PREV_OVERFLOW]\n }\n if (element.dataset[DATA_PREV_PADDING_RIGHT] !== undefined) {\n element.style.paddingRight = element.dataset[DATA_PREV_PADDING_RIGHT]\n }\n delete element.dataset[DATA_PREV_OVERFLOW]\n delete element.dataset[DATA_PREV_PADDING_RIGHT]\n if (supportsScrollbarGutter) {\n element.style.scrollbarGutter = ''\n }\n}\n\nfunction useScrollLock(params: ScrollLockParams) {\n const { locked, iosAllowedScrollContainer = document.documentElement, target } = params\n\n const isRootTarget = target === undefined || target === document.documentElement || target === document.body\n\n useEffect(() => {\n if (!target || isRootTarget) {\n return\n }\n\n const domTarget = getDomTargets(target)[0]\n if (!domTarget) {\n return\n }\n\n if (locked) {\n lockTargetScroll(domTarget)\n } else {\n if (domTarget.dataset[DATA_PREV_OVERFLOW] !== undefined) {\n unlockTargetScroll(domTarget)\n }\n }\n\n return () => {\n unlockTargetScroll(domTarget)\n }\n }, [target, locked, isRootTarget])\n\n useEffect(() => {\n if (!locked || !isRootTarget) {\n return\n }\n\n if (isIosDevice) {\n const domContainer = getDomTargets(iosAllowedScrollContainer)[0]\n lockScrollIOS(domContainer)\n\n return () => {\n unlockScrollIOS()\n }\n }\n\n lockScroll()\n\n return () => {\n unlockScroll()\n }\n }, [iosAllowedScrollContainer, isRootTarget, locked])\n}\n\nexport { useScrollLock }\n"],"names":["TOUCH_EVENT_OPTIONS","capture","passive","supportsScrollbarGutter","CSS","supports","isIosDevice","window","navigator","userAgent","test","includes","maxTouchPoints","iosScrollableBlocks","iosActiveScrollElement","iosTouchStartY","touchStartHandler","touchMoveHandler","getScrollLockCount","Number","document","documentElement","dataset","setScrollLockCount","count","toString","applyScrollLockStyles","root","style","overflow","scrollbarGutter","scrollbarWidth","innerWidth","clientWidth","paddingRight","currentPaddingRight","parseFloat","getComputedStyle","resetScrollLockStyles","isScrollable","element","overflowY","scrollHeight","clientHeight","findScrollableParent","startElement","parentElement","unlockTargetScroll","undefined","params","locked","iosAllowedScrollContainer","target","isRootTarget","body","useEffect","domTarget","getDomTargets","borderWidth","borderLeftWidth","borderRightWidth","originalOverflow","offsetWidth","lockTargetScroll","scrollableContainer","push","event","HTMLElement","touches","clientY","block","contains","scrollElement","touch","length","selection","ownerDocument","defaultView","getSelection","isCollapsed","containsNode","selectionStart","selectionEnd","activeElement","isTouchMoveAllowed","cancelable","preventDefault","deltaY","scrollTop","addEventListener","lockScrollIOS","pop","nexCount","Math","max","removeEventListener","unlockScrollIOS","lockScroll","currentCount","nextCount","unlockScroll"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useScrollLock.js","sources":["../../../src/hooks/useScrollLock.ts"],"sourcesContent":["import { useEffect } from 'react'\nimport type { DomTarget, Nullable } from 'shared/types'\nimport { getDomTargets } from 'shared/utils/getDomTargets'\n\ntype ScrollLockParams = {\n /**\n * Блокировать скролл.\n */\n locked: boolean\n /**\n * Контейнер, в котором разрешена прокрутка на iOS при заблокированном скролле страницы.\n */\n iosAllowedScrollContainer?: DomTarget\n /**\n * Элемент, на котором блокируется скролл.\n *\n * @default 'document.documentElement'\n */\n target?: DomTarget\n}\n\nconst TOUCH_EVENT_OPTIONS = { capture: true, passive: false }\nconst DATA_SCROLL_LOCK_COUNT = 'scrollLockCount'\nconst DATA_PREV_OVERFLOW = 'prevOverflow'\nconst DATA_PREV_PADDING_RIGHT = 'prevPaddingRight'\n\nconst supportsScrollbarGutter =\n typeof CSS !== 'undefined' && typeof CSS.supports === 'function' && CSS.supports('scrollbar-gutter: stable')\nconst isIosDevice =\n typeof window !== 'undefined' &&\n window.navigator?.userAgent &&\n (/iP(ad|hone|od)/.test(window.navigator.userAgent) ||\n (window.navigator.userAgent.includes('Macintosh') && window.navigator.maxTouchPoints > 1))\n\nconst iosScrollableBlocks: HTMLElement[] = []\nlet iosActiveScrollElement: Nullable<HTMLElement> = null\nlet iosTouchStartY: Nullable<number> = null\nlet touchStartHandler: Nullable<(event: TouchEvent) => void> = null\nlet touchMoveHandler: Nullable<(event: TouchEvent) => void> = null\n\nfunction getScrollLockCount(): number {\n return Number(document.documentElement.dataset[DATA_SCROLL_LOCK_COUNT] || 0)\n}\n\nfunction setScrollLockCount(count: number) {\n document.documentElement.dataset[DATA_SCROLL_LOCK_COUNT] = count.toString()\n}\n\nfunction applyScrollLockStyles() {\n const root = document.documentElement\n root.dataset[DATA_PREV_OVERFLOW] = root.style.overflow || ''\n\n if (supportsScrollbarGutter && !isIosDevice) {\n root.style.scrollbarGutter = 'stable'\n } else {\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth\n root.dataset[DATA_PREV_PADDING_RIGHT] = root.style.paddingRight || ''\n if (scrollbarWidth > 0) {\n const currentPaddingRight = parseFloat(getComputedStyle(root).paddingRight) || 0\n root.style.paddingRight = `${currentPaddingRight + scrollbarWidth}px`\n }\n }\n root.style.overflow = 'hidden'\n}\n\nfunction resetScrollLockStyles() {\n const root = document.documentElement\n root.style.overflow = root.dataset[DATA_PREV_OVERFLOW] || ''\n root.style.paddingRight = root.dataset[DATA_PREV_PADDING_RIGHT] || ''\n delete root.dataset[DATA_PREV_OVERFLOW]\n delete root.dataset[DATA_PREV_PADDING_RIGHT]\n}\n\nfunction lockScroll() {\n const count = getScrollLockCount()\n if (count === 0) {\n applyScrollLockStyles()\n }\n setScrollLockCount(count + 1)\n}\n\nfunction unlockScroll() {\n const currentCount = getScrollLockCount()\n if (currentCount <= 0) {\n return\n }\n\n const nextCount = currentCount - 1\n setScrollLockCount(nextCount)\n if (nextCount === 0) {\n resetScrollLockStyles()\n }\n}\n\nfunction isScrollable(element: HTMLElement): boolean {\n const style = getComputedStyle(element)\n const overflowY = style.overflowY === 'auto' || style.overflowY === 'scroll'\n\n return overflowY && element.scrollHeight > element.clientHeight\n}\n\nfunction findScrollableParent(startElement: HTMLElement, root: HTMLElement): Nullable<HTMLElement> {\n let element: Nullable<HTMLElement> = startElement\n\n while (element && element !== root.parentElement) {\n if (isScrollable(element)) {\n return element\n }\n\n element = element.parentElement\n }\n\n if (isScrollable(root)) {\n return root\n }\n\n return null\n}\n\nfunction isTouchMoveAllowed(target: Nullable<EventTarget>): boolean {\n if (!target || !(target instanceof HTMLElement)) {\n return false\n }\n\n const selection = target.ownerDocument?.defaultView?.getSelection()\n if (selection && !selection.isCollapsed && selection.containsNode(target, true)) {\n return true\n }\n\n if (\n 'selectionStart' in target &&\n 'selectionEnd' in target &&\n Number(target.selectionStart) < Number(target.selectionEnd) &&\n target.ownerDocument?.activeElement === target\n ) {\n return true\n }\n\n return false\n}\n\nfunction addIOSEvents() {\n if (touchMoveHandler || touchStartHandler) {\n return\n }\n\n touchStartHandler = (event: TouchEvent) => {\n const target = event.target\n if (!(target instanceof HTMLElement)) {\n iosActiveScrollElement = null\n iosTouchStartY = null\n\n return\n }\n\n iosTouchStartY = event.touches[0]?.clientY ?? null\n iosActiveScrollElement = null\n for (const block of iosScrollableBlocks) {\n if (block.contains(target)) {\n const scrollElement = findScrollableParent(target, block)\n if (scrollElement) {\n iosActiveScrollElement = scrollElement\n break\n }\n }\n }\n }\n\n touchMoveHandler = (event: TouchEvent) => {\n const touch = event.touches[0]\n if (!touch || event.touches.length === 2 || isTouchMoveAllowed(event.target)) {\n return\n }\n\n if (!event.cancelable) {\n return\n }\n\n if (!iosActiveScrollElement || iosTouchStartY === null) {\n event.preventDefault()\n\n return\n }\n\n const currentY = touch.clientY\n const deltaY = currentY - Number(iosTouchStartY)\n const atTop = iosActiveScrollElement.scrollTop <= 0\n const atBottom =\n iosActiveScrollElement.scrollTop + iosActiveScrollElement.clientHeight >= iosActiveScrollElement.scrollHeight\n if ((atTop && deltaY > 0) || (atBottom && deltaY < 0)) {\n event.preventDefault()\n }\n }\n\n document.addEventListener('touchstart', touchStartHandler, TOUCH_EVENT_OPTIONS)\n document.addEventListener('touchmove', touchMoveHandler, TOUCH_EVENT_OPTIONS)\n}\n\nfunction removeIOSEvents() {\n if (touchStartHandler) {\n document.removeEventListener('touchstart', touchStartHandler, TOUCH_EVENT_OPTIONS)\n touchStartHandler = null\n }\n if (touchMoveHandler) {\n document.removeEventListener('touchmove', touchMoveHandler, TOUCH_EVENT_OPTIONS)\n touchMoveHandler = null\n }\n iosActiveScrollElement = null\n iosTouchStartY = null\n}\n\nfunction lockScrollIOS(scrollableContainer: HTMLElement) {\n iosScrollableBlocks.push(scrollableContainer)\n const count = getScrollLockCount()\n if (count === 0) {\n applyScrollLockStyles()\n addIOSEvents()\n }\n setScrollLockCount(count + 1)\n}\n\nfunction unlockScrollIOS() {\n iosScrollableBlocks.pop()\n const count = getScrollLockCount()\n const nexCount = Math.max(0, count - 1)\n setScrollLockCount(nexCount)\n if (nexCount === 0) {\n resetScrollLockStyles()\n removeIOSEvents()\n }\n}\n\nfunction lockTargetScroll(element: HTMLElement) {\n const style = getComputedStyle(element)\n if (element.dataset[DATA_PREV_OVERFLOW] === undefined) {\n element.dataset[DATA_PREV_OVERFLOW] = style.overflow || ''\n }\n if (element.dataset[DATA_PREV_PADDING_RIGHT] === undefined) {\n element.dataset[DATA_PREV_PADDING_RIGHT] = style.paddingRight || ''\n }\n\n const borderLeft = parseFloat(style.borderLeftWidth) || 0\n const borderRight = parseFloat(style.borderRightWidth) || 0\n const borderWidth = borderLeft + borderRight\n const originalOverflow = style.overflow\n element.style.overflow = 'scroll'\n const scrollbarWidth = element.offsetWidth - element.clientWidth - borderWidth\n element.style.overflow = originalOverflow\n if (supportsScrollbarGutter) {\n element.style.scrollbarGutter = 'stable'\n } else if (scrollbarWidth > 0) {\n const currentPaddingRight = parseFloat(element.dataset[DATA_PREV_PADDING_RIGHT]) || 0\n element.style.paddingRight = `${currentPaddingRight + scrollbarWidth}px`\n }\n element.style.overflow = 'hidden'\n}\n\nfunction unlockTargetScroll(element: HTMLElement) {\n if (element.dataset[DATA_PREV_OVERFLOW] !== undefined) {\n element.style.overflow = element.dataset[DATA_PREV_OVERFLOW]\n }\n if (element.dataset[DATA_PREV_PADDING_RIGHT] !== undefined) {\n element.style.paddingRight = element.dataset[DATA_PREV_PADDING_RIGHT]\n }\n delete element.dataset[DATA_PREV_OVERFLOW]\n delete element.dataset[DATA_PREV_PADDING_RIGHT]\n if (supportsScrollbarGutter) {\n element.style.scrollbarGutter = ''\n }\n}\n\nfunction useScrollLock(params: ScrollLockParams) {\n const { locked, iosAllowedScrollContainer = document.documentElement, target } = params\n\n const isRootTarget = target === undefined || target === document.documentElement || target === document.body\n\n useEffect(() => {\n if (!target || isRootTarget) {\n return\n }\n\n const domTarget = getDomTargets(target)[0]\n\n if (locked) {\n lockTargetScroll(domTarget)\n } else {\n if (domTarget.dataset[DATA_PREV_OVERFLOW] !== undefined) {\n unlockTargetScroll(domTarget)\n }\n }\n\n return () => {\n unlockTargetScroll(domTarget)\n }\n }, [target, locked, isRootTarget])\n\n useEffect(() => {\n if (!locked || !isRootTarget) {\n return\n }\n\n if (isIosDevice) {\n const domContainer = getDomTargets(iosAllowedScrollContainer)[0]\n lockScrollIOS(domContainer)\n\n return () => {\n unlockScrollIOS()\n }\n }\n\n lockScroll()\n\n return () => {\n unlockScroll()\n }\n }, [iosAllowedScrollContainer, isRootTarget, locked])\n}\n\nexport { useScrollLock }\n"],"names":["TOUCH_EVENT_OPTIONS","capture","passive","supportsScrollbarGutter","CSS","supports","isIosDevice","window","navigator","userAgent","test","includes","maxTouchPoints","iosScrollableBlocks","iosActiveScrollElement","iosTouchStartY","touchStartHandler","touchMoveHandler","getScrollLockCount","Number","document","documentElement","dataset","setScrollLockCount","count","toString","applyScrollLockStyles","root","style","overflow","scrollbarGutter","scrollbarWidth","innerWidth","clientWidth","paddingRight","currentPaddingRight","parseFloat","getComputedStyle","resetScrollLockStyles","isScrollable","element","overflowY","scrollHeight","clientHeight","findScrollableParent","startElement","parentElement","unlockTargetScroll","undefined","params","locked","iosAllowedScrollContainer","target","isRootTarget","body","useEffect","domTarget","getDomTargets","borderWidth","borderLeftWidth","borderRightWidth","originalOverflow","offsetWidth","lockTargetScroll","scrollableContainer","push","event","HTMLElement","touches","clientY","block","contains","scrollElement","touch","length","selection","ownerDocument","defaultView","getSelection","isCollapsed","containsNode","selectionStart","selectionEnd","activeElement","isTouchMoveAllowed","cancelable","preventDefault","deltaY","scrollTop","addEventListener","lockScrollIOS","pop","nexCount","Math","max","removeEventListener","unlockScrollIOS","lockScroll","currentCount","nextCount","unlockScroll"],"mappings":"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"}
|
package/hooks/useScrollLock.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{useEffect}from'react';import{getDomTargets}from'../shared/utils/getDomTargets.mjs';const TOUCH_EVENT_OPTIONS={capture:!0,passive:!1};const supportsScrollbarGutter=typeof CSS!='undefined'&&typeof CSS.supports=='function'&&CSS.supports('scrollbar-gutter: stable');const isIosDevice=typeof window!='undefined'&&window.navigator?.userAgent&&(/iP(ad|hone|od)/.test(window.navigator.userAgent)||window.navigator.userAgent.includes('Macintosh')&&window.navigator.maxTouchPoints>1);const iosScrollableBlocks=[];let iosActiveScrollElement=null;let iosTouchStartY=null;let touchStartHandler=null;let touchMoveHandler=null;function getScrollLockCount(){return Number(document.documentElement.dataset.scrollLockCount||0)}function setScrollLockCount(t){document.documentElement.dataset.scrollLockCount=t.toString()}function applyScrollLockStyles(){const t=document.documentElement;if(t.dataset.prevOverflow=t.style.overflow||'',supportsScrollbarGutter&&!isIosDevice)t.style.scrollbarGutter='stable';else{const e=window.innerWidth-document.documentElement.clientWidth;if(t.dataset.prevPaddingRight=t.style.paddingRight||'',e>0){const o=parseFloat(getComputedStyle(t).paddingRight)||0;t.style.paddingRight=`${o+e}px`}}t.style.overflow='hidden'}function resetScrollLockStyles(){const t=document.documentElement;t.style.overflow=t.dataset.prevOverflow||'',t.style.paddingRight=t.dataset.prevPaddingRight||'',delete t.dataset.prevOverflow,delete t.dataset.prevPaddingRight}function isScrollable(t){const e=getComputedStyle(t);return(e.overflowY==='auto'||e.overflowY==='scroll')&&t.scrollHeight>t.clientHeight}function findScrollableParent(t,e){let o=t;for(;o&&o!==e.parentElement;){if(isScrollable(o))return o;o=o.parentElement}return isScrollable(e)?e:null}function unlockTargetScroll(t){t.dataset.prevOverflow!==void 0&&(t.style.overflow=t.dataset.prevOverflow),t.dataset.prevPaddingRight!==void 0&&(t.style.paddingRight=t.dataset.prevPaddingRight),delete t.dataset.prevOverflow,delete t.dataset.prevPaddingRight,supportsScrollbarGutter&&(t.style.scrollbarGutter='')}function useScrollLock(t){const{locked:e,iosAllowedScrollContainer:o=document.documentElement,target:l}=t;const r=l===void 0||l===document.documentElement||l===document.body;useEffect(()=>{if(!l||r)return;const t=getDomTargets(l)[0];return
|
|
1
|
+
import{useEffect}from'react';import{getDomTargets}from'../shared/utils/getDomTargets.mjs';const TOUCH_EVENT_OPTIONS={capture:!0,passive:!1};const supportsScrollbarGutter=typeof CSS!='undefined'&&typeof CSS.supports=='function'&&CSS.supports('scrollbar-gutter: stable');const isIosDevice=typeof window!='undefined'&&window.navigator?.userAgent&&(/iP(ad|hone|od)/.test(window.navigator.userAgent)||window.navigator.userAgent.includes('Macintosh')&&window.navigator.maxTouchPoints>1);const iosScrollableBlocks=[];let iosActiveScrollElement=null;let iosTouchStartY=null;let touchStartHandler=null;let touchMoveHandler=null;function getScrollLockCount(){return Number(document.documentElement.dataset.scrollLockCount||0)}function setScrollLockCount(t){document.documentElement.dataset.scrollLockCount=t.toString()}function applyScrollLockStyles(){const t=document.documentElement;if(t.dataset.prevOverflow=t.style.overflow||'',supportsScrollbarGutter&&!isIosDevice)t.style.scrollbarGutter='stable';else{const e=window.innerWidth-document.documentElement.clientWidth;if(t.dataset.prevPaddingRight=t.style.paddingRight||'',e>0){const o=parseFloat(getComputedStyle(t).paddingRight)||0;t.style.paddingRight=`${o+e}px`}}t.style.overflow='hidden'}function resetScrollLockStyles(){const t=document.documentElement;t.style.overflow=t.dataset.prevOverflow||'',t.style.paddingRight=t.dataset.prevPaddingRight||'',delete t.dataset.prevOverflow,delete t.dataset.prevPaddingRight}function isScrollable(t){const e=getComputedStyle(t);return(e.overflowY==='auto'||e.overflowY==='scroll')&&t.scrollHeight>t.clientHeight}function findScrollableParent(t,e){let o=t;for(;o&&o!==e.parentElement;){if(isScrollable(o))return o;o=o.parentElement}return isScrollable(e)?e:null}function unlockTargetScroll(t){t.dataset.prevOverflow!==void 0&&(t.style.overflow=t.dataset.prevOverflow),t.dataset.prevPaddingRight!==void 0&&(t.style.paddingRight=t.dataset.prevPaddingRight),delete t.dataset.prevOverflow,delete t.dataset.prevPaddingRight,supportsScrollbarGutter&&(t.style.scrollbarGutter='')}function useScrollLock(t){const{locked:e,iosAllowedScrollContainer:o=document.documentElement,target:l}=t;const r=l===void 0||l===document.documentElement||l===document.body;useEffect(()=>{if(!l||r)return;const t=getDomTargets(l)[0];return e?(t=>{const e=getComputedStyle(t);t.dataset.prevOverflow===void 0&&(t.dataset.prevOverflow=e.overflow||''),t.dataset.prevPaddingRight===void 0&&(t.dataset.prevPaddingRight=e.paddingRight||'');const o=(parseFloat(e.borderLeftWidth)||0)+(parseFloat(e.borderRightWidth)||0);const l=e.overflow;t.style.overflow='scroll';const r=t.offsetWidth-t.clientWidth-o;if(t.style.overflow=l,supportsScrollbarGutter)t.style.scrollbarGutter='stable';else if(r>0){const e=parseFloat(t.dataset.prevPaddingRight)||0;t.style.paddingRight=`${e+r}px`}t.style.overflow='hidden'})(t):t.dataset.prevOverflow!==void 0&&unlockTargetScroll(t),()=>{unlockTargetScroll(t)}},[l,e,r]),useEffect(()=>{if(e&&r)return isIosDevice?((t=>{iosScrollableBlocks.push(t);const e=getScrollLockCount();e===0&&(applyScrollLockStyles(),touchMoveHandler||touchStartHandler||(touchStartHandler=t=>{const e=t.target;if(!(e instanceof HTMLElement))return iosActiveScrollElement=null,void(iosTouchStartY=null);iosTouchStartY=t.touches[0]?.clientY??null,iosActiveScrollElement=null;for(const t of iosScrollableBlocks)if(t.contains(e)){const o=findScrollableParent(e,t);if(o){iosActiveScrollElement=o;break}}},touchMoveHandler=t=>{const e=t.touches[0];if(!e||t.touches.length===2||(t=>{if(!(t&&t instanceof HTMLElement))return!1;const e=t.ownerDocument?.defaultView?.getSelection();return!(!e||e.isCollapsed||!e.containsNode(t,!0))||'selectionStart'in t&&'selectionEnd'in t&&Number(t.selectionStart)<Number(t.selectionEnd)&&t.ownerDocument?.activeElement===t})(t.target))return;if(!t.cancelable)return;if(!iosActiveScrollElement||iosTouchStartY===null)return void t.preventDefault();const o=e.clientY-Number(iosTouchStartY);(iosActiveScrollElement.scrollTop<=0&&o>0||iosActiveScrollElement.scrollTop+iosActiveScrollElement.clientHeight>=iosActiveScrollElement.scrollHeight&&o<0)&&t.preventDefault()},document.addEventListener('touchstart',touchStartHandler,TOUCH_EVENT_OPTIONS),document.addEventListener('touchmove',touchMoveHandler,TOUCH_EVENT_OPTIONS))),setScrollLockCount(e+1)})(getDomTargets(o)[0]),()=>{(()=>{iosScrollableBlocks.pop();const t=getScrollLockCount();const e=Math.max(0,t-1);setScrollLockCount(e),e===0&&(resetScrollLockStyles(),touchStartHandler&&(document.removeEventListener('touchstart',touchStartHandler,TOUCH_EVENT_OPTIONS),touchStartHandler=null),touchMoveHandler&&(document.removeEventListener('touchmove',touchMoveHandler,TOUCH_EVENT_OPTIONS),touchMoveHandler=null),iosActiveScrollElement=null,iosTouchStartY=null)})()}):((()=>{const t=getScrollLockCount();t===0&&applyScrollLockStyles(),setScrollLockCount(t+1)})(),()=>{(()=>{const t=getScrollLockCount();if(t<=0)return;const e=t-1;setScrollLockCount(e),e===0&&resetScrollLockStyles()})()})},[o,r,e])}export{useScrollLock};
|
|
2
2
|
//# sourceMappingURL=useScrollLock.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useScrollLock.mjs","sources":["../../../src/hooks/useScrollLock.ts"],"sourcesContent":["import { useEffect } from 'react'\nimport type { DomTarget, Nullable } from 'shared/types'\nimport { getDomTargets } from 'shared/utils/getDomTargets'\n\ntype ScrollLockParams = {\n /**\n * Блокировать скролл.\n */\n locked: boolean\n /**\n * Контейнер, в котором разрешена прокрутка на iOS при заблокированном скролле страницы.\n */\n iosAllowedScrollContainer?: DomTarget\n /**\n * Элемент, на котором блокируется скролл.\n *\n * @default 'document.documentElement'\n */\n target?: DomTarget\n}\n\nconst TOUCH_EVENT_OPTIONS = { capture: true, passive: false }\nconst DATA_SCROLL_LOCK_COUNT = 'scrollLockCount'\nconst DATA_PREV_OVERFLOW = 'prevOverflow'\nconst DATA_PREV_PADDING_RIGHT = 'prevPaddingRight'\n\nconst supportsScrollbarGutter =\n typeof CSS !== 'undefined' && typeof CSS.supports === 'function' && CSS.supports('scrollbar-gutter: stable')\nconst isIosDevice =\n typeof window !== 'undefined' &&\n window.navigator?.userAgent &&\n (/iP(ad|hone|od)/.test(window.navigator.userAgent) ||\n (window.navigator.userAgent.includes('Macintosh') && window.navigator.maxTouchPoints > 1))\n\nconst iosScrollableBlocks: HTMLElement[] = []\nlet iosActiveScrollElement: Nullable<HTMLElement> = null\nlet iosTouchStartY: Nullable<number> = null\nlet touchStartHandler: Nullable<(event: TouchEvent) => void> = null\nlet touchMoveHandler: Nullable<(event: TouchEvent) => void> = null\n\nfunction getScrollLockCount(): number {\n return Number(document.documentElement.dataset[DATA_SCROLL_LOCK_COUNT] || 0)\n}\n\nfunction setScrollLockCount(count: number) {\n document.documentElement.dataset[DATA_SCROLL_LOCK_COUNT] = count.toString()\n}\n\nfunction applyScrollLockStyles() {\n const root = document.documentElement\n root.dataset[DATA_PREV_OVERFLOW] = root.style.overflow || ''\n\n if (supportsScrollbarGutter && !isIosDevice) {\n root.style.scrollbarGutter = 'stable'\n } else {\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth\n root.dataset[DATA_PREV_PADDING_RIGHT] = root.style.paddingRight || ''\n if (scrollbarWidth > 0) {\n const currentPaddingRight = parseFloat(getComputedStyle(root).paddingRight) || 0\n root.style.paddingRight = `${currentPaddingRight + scrollbarWidth}px`\n }\n }\n root.style.overflow = 'hidden'\n}\n\nfunction resetScrollLockStyles() {\n const root = document.documentElement\n root.style.overflow = root.dataset[DATA_PREV_OVERFLOW] || ''\n root.style.paddingRight = root.dataset[DATA_PREV_PADDING_RIGHT] || ''\n delete root.dataset[DATA_PREV_OVERFLOW]\n delete root.dataset[DATA_PREV_PADDING_RIGHT]\n}\n\nfunction lockScroll() {\n const count = getScrollLockCount()\n if (count === 0) {\n applyScrollLockStyles()\n }\n setScrollLockCount(count + 1)\n}\n\nfunction unlockScroll() {\n const currentCount = getScrollLockCount()\n if (currentCount <= 0) {\n return\n }\n\n const nextCount = currentCount - 1\n setScrollLockCount(nextCount)\n if (nextCount === 0) {\n resetScrollLockStyles()\n }\n}\n\nfunction isScrollable(element: HTMLElement): boolean {\n const style = getComputedStyle(element)\n const overflowY = style.overflowY === 'auto' || style.overflowY === 'scroll'\n\n return overflowY && element.scrollHeight > element.clientHeight\n}\n\nfunction findScrollableParent(startElement: HTMLElement, root: HTMLElement): Nullable<HTMLElement> {\n let element: Nullable<HTMLElement> = startElement\n\n while (element && element !== root.parentElement) {\n if (isScrollable(element)) {\n return element\n }\n\n element = element.parentElement\n }\n\n if (isScrollable(root)) {\n return root\n }\n\n return null\n}\n\nfunction isTouchMoveAllowed(target: Nullable<EventTarget>): boolean {\n if (!target || !(target instanceof HTMLElement)) {\n return false\n }\n\n const selection = target.ownerDocument?.defaultView?.getSelection()\n if (selection && !selection.isCollapsed && selection.containsNode(target, true)) {\n return true\n }\n\n if (\n 'selectionStart' in target &&\n 'selectionEnd' in target &&\n Number(target.selectionStart) < Number(target.selectionEnd) &&\n target.ownerDocument?.activeElement === target\n ) {\n return true\n }\n\n return false\n}\n\nfunction addIOSEvents() {\n if (touchMoveHandler || touchStartHandler) {\n return\n }\n\n touchStartHandler = (event: TouchEvent) => {\n const target = event.target\n if (!(target instanceof HTMLElement)) {\n iosActiveScrollElement = null\n iosTouchStartY = null\n\n return\n }\n\n iosTouchStartY = event.touches[0]?.clientY ?? null\n iosActiveScrollElement = null\n for (const block of iosScrollableBlocks) {\n if (block.contains(target)) {\n const scrollElement = findScrollableParent(target, block)\n if (scrollElement) {\n iosActiveScrollElement = scrollElement\n break\n }\n }\n }\n }\n\n touchMoveHandler = (event: TouchEvent) => {\n const touch = event.touches[0]\n if (!touch || event.touches.length === 2 || isTouchMoveAllowed(event.target)) {\n return\n }\n\n if (!event.cancelable) {\n return\n }\n\n if (!iosActiveScrollElement || iosTouchStartY === null) {\n event.preventDefault()\n\n return\n }\n\n const currentY = touch.clientY\n const deltaY = currentY - Number(iosTouchStartY)\n const atTop = iosActiveScrollElement.scrollTop <= 0\n const atBottom =\n iosActiveScrollElement.scrollTop + iosActiveScrollElement.clientHeight >= iosActiveScrollElement.scrollHeight\n if ((atTop && deltaY > 0) || (atBottom && deltaY < 0)) {\n event.preventDefault()\n }\n }\n\n document.addEventListener('touchstart', touchStartHandler, TOUCH_EVENT_OPTIONS)\n document.addEventListener('touchmove', touchMoveHandler, TOUCH_EVENT_OPTIONS)\n}\n\nfunction removeIOSEvents() {\n if (touchStartHandler) {\n document.removeEventListener('touchstart', touchStartHandler, TOUCH_EVENT_OPTIONS)\n touchStartHandler = null\n }\n if (touchMoveHandler) {\n document.removeEventListener('touchmove', touchMoveHandler, TOUCH_EVENT_OPTIONS)\n touchMoveHandler = null\n }\n iosActiveScrollElement = null\n iosTouchStartY = null\n}\n\nfunction lockScrollIOS(scrollableContainer?: HTMLElement) {\n if (scrollableContainer) {\n iosScrollableBlocks.push(scrollableContainer)\n }\n const count = getScrollLockCount()\n if (count === 0) {\n applyScrollLockStyles()\n addIOSEvents()\n }\n setScrollLockCount(count + 1)\n}\n\nfunction unlockScrollIOS() {\n iosScrollableBlocks.pop()\n const count = getScrollLockCount()\n const nexCount = Math.max(0, count - 1)\n setScrollLockCount(nexCount)\n if (nexCount === 0) {\n resetScrollLockStyles()\n removeIOSEvents()\n }\n}\n\nfunction lockTargetScroll(element: HTMLElement) {\n const style = getComputedStyle(element)\n if (element.dataset[DATA_PREV_OVERFLOW] === undefined) {\n element.dataset[DATA_PREV_OVERFLOW] = style.overflow || ''\n }\n if (element.dataset[DATA_PREV_PADDING_RIGHT] === undefined) {\n element.dataset[DATA_PREV_PADDING_RIGHT] = style.paddingRight || ''\n }\n\n const borderLeft = parseFloat(style.borderLeftWidth) || 0\n const borderRight = parseFloat(style.borderRightWidth) || 0\n const borderWidth = borderLeft + borderRight\n const originalOverflow = style.overflow\n element.style.overflow = 'scroll'\n const scrollbarWidth = element.offsetWidth - element.clientWidth - borderWidth\n element.style.overflow = originalOverflow\n if (supportsScrollbarGutter) {\n element.style.scrollbarGutter = 'stable'\n } else if (scrollbarWidth > 0) {\n const currentPaddingRight = parseFloat(element.dataset[DATA_PREV_PADDING_RIGHT]) || 0\n element.style.paddingRight = `${currentPaddingRight + scrollbarWidth}px`\n }\n element.style.overflow = 'hidden'\n}\n\nfunction unlockTargetScroll(element: HTMLElement) {\n if (element.dataset[DATA_PREV_OVERFLOW] !== undefined) {\n element.style.overflow = element.dataset[DATA_PREV_OVERFLOW]\n }\n if (element.dataset[DATA_PREV_PADDING_RIGHT] !== undefined) {\n element.style.paddingRight = element.dataset[DATA_PREV_PADDING_RIGHT]\n }\n delete element.dataset[DATA_PREV_OVERFLOW]\n delete element.dataset[DATA_PREV_PADDING_RIGHT]\n if (supportsScrollbarGutter) {\n element.style.scrollbarGutter = ''\n }\n}\n\nfunction useScrollLock(params: ScrollLockParams) {\n const { locked, iosAllowedScrollContainer = document.documentElement, target } = params\n\n const isRootTarget = target === undefined || target === document.documentElement || target === document.body\n\n useEffect(() => {\n if (!target || isRootTarget) {\n return\n }\n\n const domTarget = getDomTargets(target)[0]\n if (!domTarget) {\n return\n }\n\n if (locked) {\n lockTargetScroll(domTarget)\n } else {\n if (domTarget.dataset[DATA_PREV_OVERFLOW] !== undefined) {\n unlockTargetScroll(domTarget)\n }\n }\n\n return () => {\n unlockTargetScroll(domTarget)\n }\n }, [target, locked, isRootTarget])\n\n useEffect(() => {\n if (!locked || !isRootTarget) {\n return\n }\n\n if (isIosDevice) {\n const domContainer = getDomTargets(iosAllowedScrollContainer)[0]\n lockScrollIOS(domContainer)\n\n return () => {\n unlockScrollIOS()\n }\n }\n\n lockScroll()\n\n return () => {\n unlockScroll()\n }\n }, [iosAllowedScrollContainer, isRootTarget, locked])\n}\n\nexport { useScrollLock }\n"],"names":["TOUCH_EVENT_OPTIONS","capture","passive","supportsScrollbarGutter","CSS","supports","isIosDevice","window","navigator","userAgent","test","includes","maxTouchPoints","iosScrollableBlocks","iosActiveScrollElement","iosTouchStartY","touchStartHandler","touchMoveHandler","getScrollLockCount","Number","document","documentElement","dataset","setScrollLockCount","count","toString","applyScrollLockStyles","root","style","overflow","scrollbarGutter","scrollbarWidth","innerWidth","clientWidth","paddingRight","currentPaddingRight","parseFloat","getComputedStyle","resetScrollLockStyles","isScrollable","element","overflowY","scrollHeight","clientHeight","findScrollableParent","startElement","parentElement","unlockTargetScroll","undefined","useScrollLock","params","locked","iosAllowedScrollContainer","target","isRootTarget","body","useEffect","domTarget","getDomTargets","borderWidth","borderLeftWidth","borderRightWidth","originalOverflow","offsetWidth","lockTargetScroll","scrollableContainer","push","event","HTMLElement","touches","clientY","block","contains","scrollElement","touch","length","selection","ownerDocument","defaultView","getSelection","isCollapsed","containsNode","selectionStart","selectionEnd","activeElement","isTouchMoveAllowed","cancelable","preventDefault","deltaY","scrollTop","addEventListener","lockScrollIOS","pop","nexCount","Math","max","removeEventListener","unlockScrollIOS","lockScroll","currentCount","nextCount","unlockScroll"],"mappings":"0FAqBA,MAAMA,oBAAsB,CAAEC,SAAS,EAAMC,SAAS,GAKtD,MAAMC,+BACGC,KAAQ,oBAAsBA,IAAIC,UAAa,YAAcD,IAAIC,SAAS,4BACnF,MAAMC,mBACGC,QAAW,aAClBA,OAAOC,WAAWC,YACjB,iBAAiBC,KAAKH,OAAOC,UAAUC,YACrCF,OAAOC,UAAUC,UAAUE,SAAS,cAAgBJ,OAAOC,UAAUI,eAAiB,GAE3F,MAAMC,oBAAqC,GAC3C,IAAIC,uBAAgD,KACpD,IAAIC,eAAmC,KACvC,IAAIC,kBAA2D,KAC/D,IAAIC,iBAA0D,KAE9D,SAASC,qBACP,OAAOC,OAAOC,SAASC,gBAAgBC,QAA8B,iBAAK,EAC5E,CAEA,SAASC,mBAAmBC,GAC1BJ,SAASC,gBAAgBC,QAA8B,gBAAIE,EAAMC,UACnE,CAEA,SAASC,wBACP,MAAMC,EAAOP,SAASC,gBAGtB,GAFAM,EAAKL,QAA0B,aAAIK,EAAKC,MAAMC,UAAY,GAEtD1B,0BAA4BG,YAC9BqB,EAAKC,MAAME,gBAAkB,aACxB,CACL,MAAMC,EAAiBxB,OAAOyB,WAAaZ,SAASC,gBAAgBY,YAEpE,GADAN,EAAKL,QAA+B,iBAAIK,EAAKC,MAAMM,cAAgB,GAC/DH,EAAiB,EAAG,CACtB,MAAMI,EAAsBC,WAAWC,iBAAiBV,GAAMO,eAAiB,EAC/EP,EAAKC,MAAMM,aAAe,GAAGC,EAAsBJ,KACrD,CACF,CACAJ,EAAKC,MAAMC,SAAW,QACxB,CAEA,SAASS,wBACP,MAAMX,EAAOP,SAASC,gBACtBM,EAAKC,MAAMC,SAAWF,EAAKL,QAA0B,cAAK,GAC1DK,EAAKC,MAAMM,aAAeP,EAAKL,QAA+B,kBAAK,UAC5DK,EAAKL,QAA0B,oBAC/BK,EAAKL,QAA+B,gBAC7C,CAuBA,SAASiB,aAAaC,GACpB,MAAMZ,EAAQS,iBAAiBG,GAG/B,OAFkBZ,EAAMa,YAAc,QAAUb,EAAMa,YAAc,WAEhDD,EAAQE,aAAeF,EAAQG,YACrD,CAEA,SAASC,qBAAqBC,EAA2BlB,GACvD,IAAIa,EAAiCK,EAErC,KAAOL,GAAWA,IAAYb,EAAKmB,eAAe,CAChD,GAAIP,aAAaC,GACf,OAAOA,EAGTA,EAAUA,EAAQM,aACpB,CAEA,OAAIP,aAAaZ,GACRA,EAGF,IACT,CA8IA,SAASoB,mBAAmBP,GACtBA,EAAQlB,QAA0B,oBAAM0B,IAC1CR,EAAQZ,MAAMC,SAAWW,EAAQlB,QAA0B,cAEzDkB,EAAQlB,QAA+B,wBAAM0B,IAC/CR,EAAQZ,MAAMM,aAAeM,EAAQlB,QAA+B,yBAE/DkB,EAAQlB,QAA0B,oBAClCkB,EAAQlB,QAA+B,iBAC1CnB,0BACFqC,EAAQZ,MAAME,gBAAkB,GAEpC,CAEA,SAASmB,cAAcC,GACrB,MAAMC,OAAEA,EAAMC,0BAAEA,EAA4BhC,SAASC,gBAAegC,OAAEA,GAAWH,EAEjF,MAAMI,EAAeD,SAAWL,GAAaK,IAAWjC,SAASC,iBAAmBgC,IAAWjC,SAASmC,KAExGC,UAAU,KACR,IAAKH,GAAUC,EACb,OAGF,MAAMG,EAAYC,cAAcL,GAAQ,GACxC,OAAKI,GAIDN,EAtDR,CAA0BX,IACxB,MAAMZ,EAAQS,iBAAiBG,GAC3BA,EAAQlB,QAA0B,oBAAM0B,IAC1CR,EAAQlB,QAA0B,aAAIM,EAAMC,UAAY,IAEtDW,EAAQlB,QAA+B,wBAAM0B,IAC/CR,EAAQlB,QAA+B,iBAAIM,EAAMM,cAAgB,IAKnE,MAAMyB,GAFavB,WAAWR,EAAMgC,kBAAoB,IACpCxB,WAAWR,EAAMiC,mBAAqB,GAE1D,MAAMC,EAAmBlC,EAAMC,SAC/BW,EAAQZ,MAAMC,SAAW,SACzB,MAAME,EAAiBS,EAAQuB,YAAcvB,EAAQP,YAAc0B,EAEnE,GADAnB,EAAQZ,MAAMC,SAAWiC,EACrB3D,wBACFqC,EAAQZ,MAAME,gBAAkB,cAC3B,GAAIC,EAAiB,EAAG,CAC7B,MAAMI,EAAsBC,WAAWI,EAAQlB,QAA+B,mBAAM,EACpFkB,EAAQZ,MAAMM,aAAe,GAAGC,EAAsBJ,KACxD,CACAS,EAAQZ,MAAMC,SAAW,QAC3B,EAgCMmC,CAAiBP,GAEbA,EAAUnC,QAA0B,oBAAM0B,GAC5CD,mBAAmBU,GAIhB,KACLV,mBAAmBU,UAbrB,GAeC,CAACJ,EAAQF,EAAQG,IAEpBE,UAAU,KACR,GAAKL,GAAWG,EAIhB,OAAIhD,aA/FR,CAAuB2D,IACjBA,GACFpD,oBAAoBqD,KAAKD,GAE3B,MAAMzC,EAAQN,qBACVM,IAAU,IACZE,wBA3EET,kBAAoBD,oBAIxBA,kBAAqBmD,IACnB,MAAMd,EAASc,EAAMd,OACrB,KAAMA,aAAkBe,aAItB,OAHAtD,uBAAyB,UACzBC,eAAiB,MAKnBA,eAAiBoD,EAAME,QAAQ,IAAIC,SAAW,KAC9CxD,uBAAyB,KACzB,IAAK,MAAMyD,KAAS1D,oBAClB,GAAI0D,EAAMC,SAASnB,GAAS,CAC1B,MAAMoB,EAAgB7B,qBAAqBS,EAAQkB,GACnD,GAAIE,EAAe,CACjB3D,uBAAyB2D,EACzB,KACF,CACF,GAIJxD,iBAAoBkD,IAClB,MAAMO,EAAQP,EAAME,QAAQ,GAC5B,IAAKK,GAASP,EAAME,QAAQM,SAAW,GAnD3C,CAA4BtB,IAC1B,KAAKA,GAAYA,aAAkBe,aACjC,OAAO,EAGT,MAAMQ,EAAYvB,EAAOwB,eAAeC,aAAaC,eACrD,SAAIH,GAAcA,EAAUI,cAAeJ,EAAUK,aAAa5B,GAAQ,KAKxE,mBAAoBA,GACpB,iBAAkBA,GAClBlC,OAAOkC,EAAO6B,gBAAkB/D,OAAOkC,EAAO8B,eAC9C9B,EAAOwB,eAAeO,gBAAkB/B,CAM5C,EA+BgDgC,CAAmBlB,EAAMd,QACnE,OAGF,IAAKc,EAAMmB,WACT,OAGF,IAAKxE,wBAA0BC,iBAAmB,KAGhD,YAFAoD,EAAMoB,iBAMR,MAAMC,EADWd,EAAMJ,QACGnD,OAAOJ,iBACnBD,uBAAuB2E,WAAa,GAGpCD,EAAS,GADrB1E,uBAAuB2E,UAAY3E,uBAAuB6B,cAAgB7B,uBAAuB4B,cACzD8C,EAAS,IACjDrB,EAAMoB,kBAIVnE,SAASsE,iBAAiB,aAAc1E,kBAAmBhB,qBAC3DoB,SAASsE,iBAAiB,YAAazE,iBAAkBjB,uBAyBzDuB,mBAAmBC,EAAQ,EAC7B,EAuFMmE,CADqBjC,cAAcN,GAA2B,IAGvD,KAvFb,MACEvC,oBAAoB+E,MACpB,MAAMpE,EAAQN,qBACd,MAAM2E,EAAWC,KAAKC,IAAI,EAAGvE,EAAQ,GACrCD,mBAAmBsE,GACfA,IAAa,IACfvD,wBA9BEtB,oBACFI,SAAS4E,oBAAoB,aAAchF,kBAAmBhB,qBAC9DgB,kBAAoB,MAElBC,mBACFG,SAAS4E,oBAAoB,YAAa/E,iBAAkBjB,qBAC5DiB,iBAAmB,MAErBH,uBAAyB,KACzBC,eAAiB,KAwBnB,EA+EQkF,MA9OR,MACE,MAAMzE,EAAQN,qBACVM,IAAU,GACZE,wBAEFH,mBAAmBC,EAAQ,EAC7B,EA4OI0E,GAEO,KA5OX,MACE,MAAMC,EAAejF,qBACrB,GAAIiF,GAAgB,EAClB,OAGF,MAAMC,EAAYD,EAAe,EACjC5E,mBAAmB6E,GACfA,IAAc,GAChB9D,uBAEJ,EAkOM+D,MAED,CAACjD,EAA2BE,EAAcH,GAC/C"}
|
|
1
|
+
{"version":3,"file":"useScrollLock.mjs","sources":["../../../src/hooks/useScrollLock.ts"],"sourcesContent":["import { useEffect } from 'react'\nimport type { DomTarget, Nullable } from 'shared/types'\nimport { getDomTargets } from 'shared/utils/getDomTargets'\n\ntype ScrollLockParams = {\n /**\n * Блокировать скролл.\n */\n locked: boolean\n /**\n * Контейнер, в котором разрешена прокрутка на iOS при заблокированном скролле страницы.\n */\n iosAllowedScrollContainer?: DomTarget\n /**\n * Элемент, на котором блокируется скролл.\n *\n * @default 'document.documentElement'\n */\n target?: DomTarget\n}\n\nconst TOUCH_EVENT_OPTIONS = { capture: true, passive: false }\nconst DATA_SCROLL_LOCK_COUNT = 'scrollLockCount'\nconst DATA_PREV_OVERFLOW = 'prevOverflow'\nconst DATA_PREV_PADDING_RIGHT = 'prevPaddingRight'\n\nconst supportsScrollbarGutter =\n typeof CSS !== 'undefined' && typeof CSS.supports === 'function' && CSS.supports('scrollbar-gutter: stable')\nconst isIosDevice =\n typeof window !== 'undefined' &&\n window.navigator?.userAgent &&\n (/iP(ad|hone|od)/.test(window.navigator.userAgent) ||\n (window.navigator.userAgent.includes('Macintosh') && window.navigator.maxTouchPoints > 1))\n\nconst iosScrollableBlocks: HTMLElement[] = []\nlet iosActiveScrollElement: Nullable<HTMLElement> = null\nlet iosTouchStartY: Nullable<number> = null\nlet touchStartHandler: Nullable<(event: TouchEvent) => void> = null\nlet touchMoveHandler: Nullable<(event: TouchEvent) => void> = null\n\nfunction getScrollLockCount(): number {\n return Number(document.documentElement.dataset[DATA_SCROLL_LOCK_COUNT] || 0)\n}\n\nfunction setScrollLockCount(count: number) {\n document.documentElement.dataset[DATA_SCROLL_LOCK_COUNT] = count.toString()\n}\n\nfunction applyScrollLockStyles() {\n const root = document.documentElement\n root.dataset[DATA_PREV_OVERFLOW] = root.style.overflow || ''\n\n if (supportsScrollbarGutter && !isIosDevice) {\n root.style.scrollbarGutter = 'stable'\n } else {\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth\n root.dataset[DATA_PREV_PADDING_RIGHT] = root.style.paddingRight || ''\n if (scrollbarWidth > 0) {\n const currentPaddingRight = parseFloat(getComputedStyle(root).paddingRight) || 0\n root.style.paddingRight = `${currentPaddingRight + scrollbarWidth}px`\n }\n }\n root.style.overflow = 'hidden'\n}\n\nfunction resetScrollLockStyles() {\n const root = document.documentElement\n root.style.overflow = root.dataset[DATA_PREV_OVERFLOW] || ''\n root.style.paddingRight = root.dataset[DATA_PREV_PADDING_RIGHT] || ''\n delete root.dataset[DATA_PREV_OVERFLOW]\n delete root.dataset[DATA_PREV_PADDING_RIGHT]\n}\n\nfunction lockScroll() {\n const count = getScrollLockCount()\n if (count === 0) {\n applyScrollLockStyles()\n }\n setScrollLockCount(count + 1)\n}\n\nfunction unlockScroll() {\n const currentCount = getScrollLockCount()\n if (currentCount <= 0) {\n return\n }\n\n const nextCount = currentCount - 1\n setScrollLockCount(nextCount)\n if (nextCount === 0) {\n resetScrollLockStyles()\n }\n}\n\nfunction isScrollable(element: HTMLElement): boolean {\n const style = getComputedStyle(element)\n const overflowY = style.overflowY === 'auto' || style.overflowY === 'scroll'\n\n return overflowY && element.scrollHeight > element.clientHeight\n}\n\nfunction findScrollableParent(startElement: HTMLElement, root: HTMLElement): Nullable<HTMLElement> {\n let element: Nullable<HTMLElement> = startElement\n\n while (element && element !== root.parentElement) {\n if (isScrollable(element)) {\n return element\n }\n\n element = element.parentElement\n }\n\n if (isScrollable(root)) {\n return root\n }\n\n return null\n}\n\nfunction isTouchMoveAllowed(target: Nullable<EventTarget>): boolean {\n if (!target || !(target instanceof HTMLElement)) {\n return false\n }\n\n const selection = target.ownerDocument?.defaultView?.getSelection()\n if (selection && !selection.isCollapsed && selection.containsNode(target, true)) {\n return true\n }\n\n if (\n 'selectionStart' in target &&\n 'selectionEnd' in target &&\n Number(target.selectionStart) < Number(target.selectionEnd) &&\n target.ownerDocument?.activeElement === target\n ) {\n return true\n }\n\n return false\n}\n\nfunction addIOSEvents() {\n if (touchMoveHandler || touchStartHandler) {\n return\n }\n\n touchStartHandler = (event: TouchEvent) => {\n const target = event.target\n if (!(target instanceof HTMLElement)) {\n iosActiveScrollElement = null\n iosTouchStartY = null\n\n return\n }\n\n iosTouchStartY = event.touches[0]?.clientY ?? null\n iosActiveScrollElement = null\n for (const block of iosScrollableBlocks) {\n if (block.contains(target)) {\n const scrollElement = findScrollableParent(target, block)\n if (scrollElement) {\n iosActiveScrollElement = scrollElement\n break\n }\n }\n }\n }\n\n touchMoveHandler = (event: TouchEvent) => {\n const touch = event.touches[0]\n if (!touch || event.touches.length === 2 || isTouchMoveAllowed(event.target)) {\n return\n }\n\n if (!event.cancelable) {\n return\n }\n\n if (!iosActiveScrollElement || iosTouchStartY === null) {\n event.preventDefault()\n\n return\n }\n\n const currentY = touch.clientY\n const deltaY = currentY - Number(iosTouchStartY)\n const atTop = iosActiveScrollElement.scrollTop <= 0\n const atBottom =\n iosActiveScrollElement.scrollTop + iosActiveScrollElement.clientHeight >= iosActiveScrollElement.scrollHeight\n if ((atTop && deltaY > 0) || (atBottom && deltaY < 0)) {\n event.preventDefault()\n }\n }\n\n document.addEventListener('touchstart', touchStartHandler, TOUCH_EVENT_OPTIONS)\n document.addEventListener('touchmove', touchMoveHandler, TOUCH_EVENT_OPTIONS)\n}\n\nfunction removeIOSEvents() {\n if (touchStartHandler) {\n document.removeEventListener('touchstart', touchStartHandler, TOUCH_EVENT_OPTIONS)\n touchStartHandler = null\n }\n if (touchMoveHandler) {\n document.removeEventListener('touchmove', touchMoveHandler, TOUCH_EVENT_OPTIONS)\n touchMoveHandler = null\n }\n iosActiveScrollElement = null\n iosTouchStartY = null\n}\n\nfunction lockScrollIOS(scrollableContainer: HTMLElement) {\n iosScrollableBlocks.push(scrollableContainer)\n const count = getScrollLockCount()\n if (count === 0) {\n applyScrollLockStyles()\n addIOSEvents()\n }\n setScrollLockCount(count + 1)\n}\n\nfunction unlockScrollIOS() {\n iosScrollableBlocks.pop()\n const count = getScrollLockCount()\n const nexCount = Math.max(0, count - 1)\n setScrollLockCount(nexCount)\n if (nexCount === 0) {\n resetScrollLockStyles()\n removeIOSEvents()\n }\n}\n\nfunction lockTargetScroll(element: HTMLElement) {\n const style = getComputedStyle(element)\n if (element.dataset[DATA_PREV_OVERFLOW] === undefined) {\n element.dataset[DATA_PREV_OVERFLOW] = style.overflow || ''\n }\n if (element.dataset[DATA_PREV_PADDING_RIGHT] === undefined) {\n element.dataset[DATA_PREV_PADDING_RIGHT] = style.paddingRight || ''\n }\n\n const borderLeft = parseFloat(style.borderLeftWidth) || 0\n const borderRight = parseFloat(style.borderRightWidth) || 0\n const borderWidth = borderLeft + borderRight\n const originalOverflow = style.overflow\n element.style.overflow = 'scroll'\n const scrollbarWidth = element.offsetWidth - element.clientWidth - borderWidth\n element.style.overflow = originalOverflow\n if (supportsScrollbarGutter) {\n element.style.scrollbarGutter = 'stable'\n } else if (scrollbarWidth > 0) {\n const currentPaddingRight = parseFloat(element.dataset[DATA_PREV_PADDING_RIGHT]) || 0\n element.style.paddingRight = `${currentPaddingRight + scrollbarWidth}px`\n }\n element.style.overflow = 'hidden'\n}\n\nfunction unlockTargetScroll(element: HTMLElement) {\n if (element.dataset[DATA_PREV_OVERFLOW] !== undefined) {\n element.style.overflow = element.dataset[DATA_PREV_OVERFLOW]\n }\n if (element.dataset[DATA_PREV_PADDING_RIGHT] !== undefined) {\n element.style.paddingRight = element.dataset[DATA_PREV_PADDING_RIGHT]\n }\n delete element.dataset[DATA_PREV_OVERFLOW]\n delete element.dataset[DATA_PREV_PADDING_RIGHT]\n if (supportsScrollbarGutter) {\n element.style.scrollbarGutter = ''\n }\n}\n\nfunction useScrollLock(params: ScrollLockParams) {\n const { locked, iosAllowedScrollContainer = document.documentElement, target } = params\n\n const isRootTarget = target === undefined || target === document.documentElement || target === document.body\n\n useEffect(() => {\n if (!target || isRootTarget) {\n return\n }\n\n const domTarget = getDomTargets(target)[0]\n\n if (locked) {\n lockTargetScroll(domTarget)\n } else {\n if (domTarget.dataset[DATA_PREV_OVERFLOW] !== undefined) {\n unlockTargetScroll(domTarget)\n }\n }\n\n return () => {\n unlockTargetScroll(domTarget)\n }\n }, [target, locked, isRootTarget])\n\n useEffect(() => {\n if (!locked || !isRootTarget) {\n return\n }\n\n if (isIosDevice) {\n const domContainer = getDomTargets(iosAllowedScrollContainer)[0]\n lockScrollIOS(domContainer)\n\n return () => {\n unlockScrollIOS()\n }\n }\n\n lockScroll()\n\n return () => {\n unlockScroll()\n }\n }, [iosAllowedScrollContainer, isRootTarget, locked])\n}\n\nexport { useScrollLock }\n"],"names":["TOUCH_EVENT_OPTIONS","capture","passive","supportsScrollbarGutter","CSS","supports","isIosDevice","window","navigator","userAgent","test","includes","maxTouchPoints","iosScrollableBlocks","iosActiveScrollElement","iosTouchStartY","touchStartHandler","touchMoveHandler","getScrollLockCount","Number","document","documentElement","dataset","setScrollLockCount","count","toString","applyScrollLockStyles","root","style","overflow","scrollbarGutter","scrollbarWidth","innerWidth","clientWidth","paddingRight","currentPaddingRight","parseFloat","getComputedStyle","resetScrollLockStyles","isScrollable","element","overflowY","scrollHeight","clientHeight","findScrollableParent","startElement","parentElement","unlockTargetScroll","undefined","useScrollLock","params","locked","iosAllowedScrollContainer","target","isRootTarget","body","useEffect","domTarget","getDomTargets","borderWidth","borderLeftWidth","borderRightWidth","originalOverflow","offsetWidth","lockTargetScroll","scrollableContainer","push","event","HTMLElement","touches","clientY","block","contains","scrollElement","touch","length","selection","ownerDocument","defaultView","getSelection","isCollapsed","containsNode","selectionStart","selectionEnd","activeElement","isTouchMoveAllowed","cancelable","preventDefault","deltaY","scrollTop","addEventListener","lockScrollIOS","pop","nexCount","Math","max","removeEventListener","unlockScrollIOS","lockScroll","currentCount","nextCount","unlockScroll"],"mappings":"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"}
|