UNPKG

@uifabric/utilities

Version:

Fluent UI React utilities for building components.

1 lines 10.2 kB
{"version":3,"file":"scroll.js","sourceRoot":"../src/","sources":["scroll.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,IAAI,eAAuB,CAAC;AAC5B,IAAI,wBAAwB,GAAG,CAAC,CAAC;AAEjC,IAAM,uBAAuB,GAAG,WAAW,CAAC;IAC1C,QAAQ,EAAE,mBAA+B;CAC1C,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,IAAM,4BAA4B,GAAG,oBAAoB,CAAC;AAEjE;;;GAGG;AACH,MAAM,CAAC,IAAM,oBAAoB,GAAG,UAAC,OAA2B,EAAE,MAAkB;IAClF,IAAI,CAAC,OAAO,EAAE;QACZ,OAAO;KACR;IAED,IAAI,gBAAgB,GAAG,CAAC,CAAC;IACzB,IAAI,QAAQ,GAAmB,IAAI,CAAC;IAEpC,iEAAiE;IACjE,IAAM,YAAY,GAAG,UAAC,KAAiB;QACrC,IAAI,KAAK,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE;YACpC,gBAAgB,GAAG,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;SACnD;IACH,CAAC,CAAC;IAEF,yDAAyD;IACzD,kDAAkD;IAClD,IAAM,qBAAqB,GAAG,UAAC,KAAiB;QAC9C,wCAAwC;QACxC,IAAI,KAAK,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE;YACpC,OAAO;SACR;QAED,iDAAiD;QACjD,kDAAkD;QAClD,KAAK,CAAC,eAAe,EAAE,CAAC;QAExB,IAAI,CAAC,QAAQ,EAAE;YACb,OAAO;SACR;QAED,IAAM,OAAO,GAAG,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,gBAAgB,CAAC;QAElE,IAAM,gBAAgB,GAAG,oBAAoB,CAAC,KAAK,CAAC,MAAqB,CAAgB,CAAC;QAC1F,IAAI,gBAAgB,EAAE;YACpB,QAAQ,GAAG,gBAAgB,CAAC;SAC7B;QAED,yCAAyC;QACzC,qCAAqC;QACrC,IAAI,QAAQ,CAAC,SAAS,KAAK,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE;YAC3C,KAAK,CAAC,cAAc,EAAE,CAAC;SACxB;QAED,4CAA4C;QAC5C,uCAAuC;QACvC,IAAI,QAAQ,CAAC,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,QAAQ,CAAC,YAAY,IAAI,OAAO,GAAG,CAAC,EAAE;YACjG,KAAK,CAAC,cAAc,EAAE,CAAC;SACxB;IACH,CAAC,CAAC;IAEF,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IACnE,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IAE3E,QAAQ,GAAG,OAAO,CAAC;AACrB,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,IAAM,wBAAwB,GAAG,UAAC,OAA2B,EAAE,MAAkB;IACtF,IAAI,CAAC,OAAO,EAAE;QACZ,OAAO;KACR;IACD,IAAM,mBAAmB,GAAG,UAAC,KAAiB;QAC5C,KAAK,CAAC,eAAe,EAAE,CAAC;IAC1B,CAAC,CAAC;IACF,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;AAC3E,CAAC,CAAC;AAEF,IAAM,qBAAqB,GAAG,UAAC,KAAiB;IAC9C,KAAK,CAAC,cAAc,EAAE,CAAC;AACzB,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,iBAAiB;IAC/B,IAAI,GAAG,GAAG,WAAW,EAAE,CAAC;IAExB,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,wBAAwB,EAAE;QAChD,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QAChD,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,WAAW,EAAE,qBAAqB,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;KACnG;IAED,wBAAwB,EAAE,CAAC;AAC7B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB;IAC9B,IAAI,wBAAwB,GAAG,CAAC,EAAE;QAChC,IAAI,GAAG,GAAG,WAAW,EAAE,CAAC;QAExB,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,IAAI,wBAAwB,KAAK,CAAC,EAAE;YACrD,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC;YACnD,GAAG,CAAC,IAAI,CAAC,mBAAmB,CAAC,WAAW,EAAE,qBAAqB,CAAC,CAAC;SAClE;QAED,wBAAwB,EAAE,CAAC;KAC5B;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB;IAC/B,IAAI,eAAe,KAAK,SAAS,EAAE;QACjC,IAAI,SAAS,GAAgB,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC3D,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC9C,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC/C,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAClD,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QACpD,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QAC9C,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QACrC,0BAA0B;QAC1B,eAAe,GAAG,SAAS,CAAC,WAAW,GAAG,SAAS,CAAC,WAAW,CAAC;QAEhE,iBAAiB;QACjB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;KACtC;IAED,OAAO,eAAe,CAAC;AACzB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,eAAmC;IACtE,IAAI,EAAE,GAA4C,eAAe,CAAC;IAClE,IAAM,GAAG,GAAG,WAAW,CAAC,eAAe,CAAE,CAAC;IAE1C,sDAAsD;IACtD,OAAO,EAAE,IAAI,EAAE,KAAK,GAAG,CAAC,IAAI,EAAE;QAC5B,IAAI,EAAE,CAAC,YAAY,CAAC,4BAA4B,CAAC,KAAK,MAAM,EAAE;YAC5D,OAAO,EAAE,CAAC;SACX;QACD,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC;KACvB;IAED,oGAAoG;IACpG,EAAE,GAAG,eAAe,CAAC;IAErB,OAAO,EAAE,IAAI,EAAE,KAAK,GAAG,CAAC,IAAI,EAAE;QAC5B,IAAI,EAAE,CAAC,YAAY,CAAC,4BAA4B,CAAC,KAAK,OAAO,EAAE;YAC7D,IAAM,cAAc,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAC;YAC5C,IAAI,SAAS,GAAG,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAEpF,IAAI,SAAS,IAAI,CAAC,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,MAAM,CAAC,EAAE;gBACjE,OAAO,EAAE,CAAC;aACX;SACF;QAED,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC;KACvB;IAED,8BAA8B;IAC9B,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,GAAG,CAAC,IAAI,EAAE;QAC1B,EAAE,GAAG,SAAS,CAAC,eAAe,CAAC,CAAC;KACjC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC","sourcesContent":["import { getDocument } from './dom/getDocument';\nimport { mergeStyles } from '@uifabric/merge-styles';\nimport { EventGroup } from './EventGroup';\nimport { getWindow } from './dom/getWindow';\n\nlet _scrollbarWidth: number;\nlet _bodyScrollDisabledCount = 0;\n\nconst DisabledScrollClassName = mergeStyles({\n overflow: 'hidden !important' as 'hidden',\n});\n\n/**\n * Placing this attribute on scrollable divs optimizes detection to know\n * if the div is scrollable or not (given we can avoid expensive operations\n * like getComputedStyle.)\n *\n * @public\n */\nexport const DATA_IS_SCROLLABLE_ATTRIBUTE = 'data-is-scrollable';\n\n/**\n * Allows the user to scroll within a element,\n * while preventing the user from scrolling the body\n */\nexport const allowScrollOnElement = (element: HTMLElement | null, events: EventGroup): void => {\n if (!element) {\n return;\n }\n\n let _previousClientY = 0;\n let _element: Element | null = null;\n\n // remember the clientY for future calls of _preventOverscrolling\n const _saveClientY = (event: TouchEvent): void => {\n if (event.targetTouches.length === 1) {\n _previousClientY = event.targetTouches[0].clientY;\n }\n };\n\n // prevent the body from scrolling when the user attempts\n // to scroll past the top or bottom of the element\n const _preventOverscrolling = (event: TouchEvent): void => {\n // only respond to a single-finger touch\n if (event.targetTouches.length !== 1) {\n return;\n }\n\n // prevent the body touchmove handler from firing\n // so that scrolling is allowed within the element\n event.stopPropagation();\n\n if (!_element) {\n return;\n }\n\n const clientY = event.targetTouches[0].clientY - _previousClientY;\n\n const scrollableParent = findScrollableParent(event.target as HTMLElement) as HTMLElement;\n if (scrollableParent) {\n _element = scrollableParent;\n }\n\n // if the element is scrolled to the top,\n // prevent the user from scrolling up\n if (_element.scrollTop === 0 && clientY > 0) {\n event.preventDefault();\n }\n\n // if the element is scrolled to the bottom,\n // prevent the user from scrolling down\n if (_element.scrollHeight - Math.ceil(_element.scrollTop) <= _element.clientHeight && clientY < 0) {\n event.preventDefault();\n }\n };\n\n events.on(element, 'touchstart', _saveClientY, { passive: false });\n events.on(element, 'touchmove', _preventOverscrolling, { passive: false });\n\n _element = element;\n};\n\n/**\n * Same as allowScrollOnElement but does not prevent overscrolling.\n */\nexport const allowOverscrollOnElement = (element: HTMLElement | null, events: EventGroup): void => {\n if (!element) {\n return;\n }\n const _allowElementScroll = (event: TouchEvent) => {\n event.stopPropagation();\n };\n events.on(element, 'touchmove', _allowElementScroll, { passive: false });\n};\n\nconst _disableIosBodyScroll = (event: TouchEvent) => {\n event.preventDefault();\n};\n\n/**\n * Disables the body scrolling.\n *\n * @public\n */\nexport function disableBodyScroll(): void {\n let doc = getDocument();\n\n if (doc && doc.body && !_bodyScrollDisabledCount) {\n doc.body.classList.add(DisabledScrollClassName);\n doc.body.addEventListener('touchmove', _disableIosBodyScroll, { passive: false, capture: false });\n }\n\n _bodyScrollDisabledCount++;\n}\n\n/**\n * Enables the body scrolling.\n *\n * @public\n */\nexport function enableBodyScroll(): void {\n if (_bodyScrollDisabledCount > 0) {\n let doc = getDocument();\n\n if (doc && doc.body && _bodyScrollDisabledCount === 1) {\n doc.body.classList.remove(DisabledScrollClassName);\n doc.body.removeEventListener('touchmove', _disableIosBodyScroll);\n }\n\n _bodyScrollDisabledCount--;\n }\n}\n\n/**\n * Calculates the width of a scrollbar for the browser/os.\n *\n * @public\n */\nexport function getScrollbarWidth(): number {\n if (_scrollbarWidth === undefined) {\n let scrollDiv: HTMLElement = document.createElement('div');\n scrollDiv.style.setProperty('width', '100px');\n scrollDiv.style.setProperty('height', '100px');\n scrollDiv.style.setProperty('overflow', 'scroll');\n scrollDiv.style.setProperty('position', 'absolute');\n scrollDiv.style.setProperty('top', '-9999px');\n document.body.appendChild(scrollDiv);\n // Get the scrollbar width\n _scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;\n\n // Delete the DIV\n document.body.removeChild(scrollDiv);\n }\n\n return _scrollbarWidth;\n}\n\n/**\n * Traverses up the DOM for the element with the data-is-scrollable=true attribute, or returns\n * document.body.\n *\n * @public\n */\nexport function findScrollableParent(startingElement: HTMLElement | null): HTMLElement | Window | undefined | null {\n let el: HTMLElement | Window | undefined | null = startingElement;\n const doc = getDocument(startingElement)!;\n\n // First do a quick scan for the scrollable attribute.\n while (el && el !== doc.body) {\n if (el.getAttribute(DATA_IS_SCROLLABLE_ATTRIBUTE) === 'true') {\n return el;\n }\n el = el.parentElement;\n }\n\n // If we haven't found it, the use the slower method: compute styles to evaluate if overflow is set.\n el = startingElement;\n\n while (el && el !== doc.body) {\n if (el.getAttribute(DATA_IS_SCROLLABLE_ATTRIBUTE) !== 'false') {\n const computedStyles = getComputedStyle(el);\n let overflowY = computedStyles ? computedStyles.getPropertyValue('overflow-y') : '';\n\n if (overflowY && (overflowY === 'scroll' || overflowY === 'auto')) {\n return el;\n }\n }\n\n el = el.parentElement;\n }\n\n // Fall back to window scroll.\n if (!el || el === doc.body) {\n el = getWindow(startingElement);\n }\n\n return el;\n}\n"]}