@foxford/ui 2.108.0 → 2.108.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/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 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])};
|
|
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 t?(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)}):void 0},[l,e,r]),React.useEffect(()=>{if(e&&r)return isIosDevice?((t=>{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 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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"}
|
|
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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"}
|
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 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};
|
|
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 t?(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)}):void 0},[l,e,r]),useEffect(()=>{if(e&&r)return isIosDevice?((t=>{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 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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"}
|
|
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":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@foxford/ui",
|
|
3
|
-
"version": "2.108.
|
|
3
|
+
"version": "2.108.1",
|
|
4
4
|
"description": "UI components and utilities",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/foxford/ui/issues"
|
|
@@ -63,6 +63,6 @@
|
|
|
63
63
|
"shared",
|
|
64
64
|
"theme"
|
|
65
65
|
],
|
|
66
|
-
"sha": "
|
|
66
|
+
"sha": "4ad497a",
|
|
67
67
|
"scripts": {}
|
|
68
68
|
}
|