compute-scroll-into-view 2.0.4 → 3.0.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/README.md CHANGED
@@ -31,15 +31,13 @@ npm i compute-scroll-into-view
31
31
  You can also use it from a CDN:
32
32
 
33
33
  ```js
34
- const { default: compute } = await import(
35
- 'https://esm.sh/compute-scroll-into-view'
36
- )
34
+ const { compute } = await import('https://esm.sh/compute-scroll-into-view')
37
35
  ```
38
36
 
39
37
  # Usage
40
38
 
41
39
  ```js
42
- import compute from 'compute-scroll-into-view'
40
+ import { compute } from 'compute-scroll-into-view'
43
41
 
44
42
  const node = document.getElementById('hero')
45
43
 
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  /** @public */
2
- declare const _default: (target: Element, options: Options) => ScrollAction[]
3
- export default _default
2
+ export declare let compute: (
3
+ target: Element,
4
+ options: Options
5
+ ) => ScrollAction[]
4
6
 
5
7
  /** @public */
6
8
  export declare interface Options {
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- let e=e=>"object"==typeof e&&null!=e&&1===e.nodeType,t=(e,t)=>(!t||"hidden"!==e)&&("visible"!==e&&"clip"!==e),n=(e,n)=>{if(e.clientHeight<e.scrollHeight||e.clientWidth<e.scrollWidth){let l=getComputedStyle(e,null);return t(l.overflowY,n)||t(l.overflowX,n)||(e=>{let t=(e=>{if(!e.ownerDocument||!e.ownerDocument.defaultView)return null;try{return e.ownerDocument.defaultView.frameElement}catch(e){return null}})(e);return!!t&&(t.clientHeight<e.scrollHeight||t.clientWidth<e.scrollWidth)})(e)}return!1},l=(e,t,n,l,i,o,r,d)=>o<e&&r>t||o>e&&r<t?0:o<=e&&d<=n||r>=t&&d>=n?o-e-l:r>t&&d<n||o<e&&d>n?r-t+i:0,i=e=>{let t=e.parentElement;return null==t?e.getRootNode().host||null:t};var o=(t,o)=>{var r,d,h,f,u,s;if("undefined"==typeof document)return[];let{scrollMode:a,block:c,inline:g,boundary:m,skipOverflowHiddenElements:p}=o,w="function"==typeof m?m:e=>e!==m;if(!e(t))throw new TypeError("Invalid target");let W=document.scrollingElement||document.documentElement,H=[],b=t;for(;e(b)&&w(b);){if(b=i(b),b===W){H.push(b);break}null!=b&&b===document.body&&n(b)&&!n(document.documentElement)||null!=b&&n(b,p)&&H.push(b)}let v=null!=(d=null==(r=window.visualViewport)?void 0:r.width)?d:innerWidth,y=null!=(f=null==(h=window.visualViewport)?void 0:h.height)?f:innerHeight,E=null!=(u=window.scrollX)?u:pageXOffset,M=null!=(s=window.scrollY)?s:pageYOffset,{height:x,width:I,top:C,right:R,bottom:T,left:V}=t.getBoundingClientRect(),k="start"===c||"nearest"===c?C:"end"===c?T:C+x/2,B="center"===g?V+I/2:"end"===g?R:V,D=[];for(let e=0;e<H.length;e++){let t=H[e],{height:n,width:i,top:o,right:r,bottom:d,left:h}=t.getBoundingClientRect();if("if-needed"===a&&C>=0&&V>=0&&T<=y&&R<=v&&C>=o&&T<=d&&V>=h&&R<=r)return D;let f=getComputedStyle(t),u=parseInt(f.borderLeftWidth,10),s=parseInt(f.borderTopWidth,10),m=parseInt(f.borderRightWidth,10),p=parseInt(f.borderBottomWidth,10),w=0,b=0,O="offsetWidth"in t?t.offsetWidth-t.clientWidth-u-m:0,X="offsetHeight"in t?t.offsetHeight-t.clientHeight-s-p:0,Y="offsetWidth"in t?0===t.offsetWidth?0:i/t.offsetWidth:0,L="offsetHeight"in t?0===t.offsetHeight?0:n/t.offsetHeight:0;if(W===t)w="start"===c?k:"end"===c?k-y:"nearest"===c?l(M,M+y,y,s,p,M+k,M+k+x,x):k-y/2,b="start"===g?B:"center"===g?B-v/2:"end"===g?B-v:l(E,E+v,v,u,m,E+B,E+B+I,I),w=Math.max(0,w+M),b=Math.max(0,b+E);else{w="start"===c?k-o-s:"end"===c?k-d+p+X:"nearest"===c?l(o,d,n,s,p+X,k,k+x,x):k-(o+n/2)+X/2,b="start"===g?B-h-u:"center"===g?B-(h+i/2)+O/2:"end"===g?B-r+m+O:l(h,r,i,u,m+O,B,B+I,I);let{scrollLeft:e,scrollTop:f}=t;w=Math.max(0,Math.min(f+w/L,t.scrollHeight-n/L+X)),b=Math.max(0,Math.min(e+b/Y,t.scrollWidth-i/Y+O)),k+=f-w,B+=e-b}D.push({el:t,top:w,left:b})}return D};export{o as default};//# sourceMappingURL=index.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});let e=e=>"object"==typeof e&&null!=e&&1===e.nodeType,t=(e,t)=>(!t||"hidden"!==e)&&("visible"!==e&&"clip"!==e),n=(e,n)=>{if(e.clientHeight<e.scrollHeight||e.clientWidth<e.scrollWidth){let l=getComputedStyle(e,null);return t(l.overflowY,n)||t(l.overflowX,n)||(e=>{let t=(e=>{if(!e.ownerDocument||!e.ownerDocument.defaultView)return null;try{return e.ownerDocument.defaultView.frameElement}catch(e){return null}})(e);return!!t&&(t.clientHeight<e.scrollHeight||t.clientWidth<e.scrollWidth)})(e)}return!1},l=(e,t,n,l,o,i,r,d)=>i<e&&r>t||i>e&&r<t?0:i<=e&&d<=n||r>=t&&d>=n?i-e-l:r>t&&d<n||i<e&&d>n?r-t+o:0,o=e=>{let t=e.parentElement;return null==t?e.getRootNode().host||null:t};exports.compute=(t,i)=>{var r,d,h,u;if("undefined"==typeof document)return[];let{scrollMode:s,block:f,inline:c,boundary:a,skipOverflowHiddenElements:m}=i,g="function"==typeof a?a:e=>e!==a;if(!e(t))throw new TypeError("Invalid target");let p=document.scrollingElement||document.documentElement,w=[],W=t;for(;e(W)&&g(W);){if(W=o(W),W===p){w.push(W);break}null!=W&&W===document.body&&n(W)&&!n(document.documentElement)||null!=W&&n(W,m)&&w.push(W)}let b=null!=(d=null==(r=window.visualViewport)?void 0:r.width)?d:innerWidth,H=null!=(u=null==(h=window.visualViewport)?void 0:h.height)?u:innerHeight,{scrollX:v,scrollY:y}=window,{height:M,width:E,top:x,right:I,bottom:C,left:R}=t.getBoundingClientRect(),T="start"===f||"nearest"===f?x:"end"===f?C:x+M/2,V="center"===c?R+E/2:"end"===c?I:R,k=[];for(let e=0;e<w.length;e++){let t=w[e],{height:n,width:o,top:i,right:r,bottom:d,left:h}=t.getBoundingClientRect();if("if-needed"===s&&x>=0&&R>=0&&C<=H&&I<=b&&x>=i&&C<=d&&R>=h&&I<=r)return k;let u=getComputedStyle(t),a=parseInt(u.borderLeftWidth,10),m=parseInt(u.borderTopWidth,10),g=parseInt(u.borderRightWidth,10),W=parseInt(u.borderBottomWidth,10),B=0,D=0,j="offsetWidth"in t?t.offsetWidth-t.clientWidth-a-g:0,L="offsetHeight"in t?t.offsetHeight-t.clientHeight-m-W:0,O="offsetWidth"in t?0===t.offsetWidth?0:o/t.offsetWidth:0,S="offsetHeight"in t?0===t.offsetHeight?0:n/t.offsetHeight:0;if(p===t)B="start"===f?T:"end"===f?T-H:"nearest"===f?l(y,y+H,H,m,W,y+T,y+T+M,M):T-H/2,D="start"===c?V:"center"===c?V-b/2:"end"===c?V-b:l(v,v+b,b,a,g,v+V,v+V+E,E),B=Math.max(0,B+y),D=Math.max(0,D+v);else{B="start"===f?T-i-m:"end"===f?T-d+W+L:"nearest"===f?l(i,d,n,m,W+L,T,T+M,M):T-(i+n/2)+L/2,D="start"===c?V-h-a:"center"===c?V-(h+o/2)+j/2:"end"===c?V-r+g+j:l(h,r,o,a,g+j,V,V+E,E);let{scrollLeft:e,scrollTop:u}=t;B=Math.max(0,Math.min(u+B/S,t.scrollHeight-n/S+L)),D=Math.max(0,Math.min(e+D/O,t.scrollWidth-o/O+j)),T+=u-B,V+=e-D}k.push({el:t,top:B,left:D})}return k};//# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["// Compute what scrolling needs to be done on required scrolling boxes for target to be in view\n\n// The type names here are named after the spec to make it easier to find more information around what they mean:\n// To reduce churn and reduce things that need be maintained things from the official TS DOM library is used here\n// https://drafts.csswg.org/cssom-view/\n\n// For a definition on what is \"block flow direction\" exactly, check this: https://drafts.csswg.org/css-writing-modes-4/#block-flow-direction\n\n/**\n * This new option is tracked in this PR, which is the most likely candidate at the time: https://github.com/w3c/csswg-drafts/pull/1805\n * @public\n */\nexport type ScrollMode = 'always' | 'if-needed'\n\n/** @public */\nexport interface Options {\n /**\n * Control the logical scroll position on the y-axis. The spec states that the `block` direction is related to the [writing-mode](https://developer.mozilla.org/en-US/docs/Web/CSS/writing-mode), but this is not implemented yet in this library.\n * This means that `block: 'start'` aligns to the top edge and `block: 'end'` to the bottom.\n * @defaultValue 'center'\n */\n block?: ScrollLogicalPosition\n /**\n * Like `block` this is affected by the [writing-mode](https://developer.mozilla.org/en-US/docs/Web/CSS/writing-mode). In left-to-right pages `inline: 'start'` will align to the left edge. In right-to-left it should be flipped. This will be supported in a future release.\n * @defaultValue 'nearest'\n */\n inline?: ScrollLogicalPosition\n /**\n * This is a proposed addition to the spec that you can track here: https://github.com/w3c/csswg-drafts/pull/5677\n *\n * This library will be updated to reflect any changes to the spec and will provide a migration path.\n * To be backwards compatible with `Element.scrollIntoViewIfNeeded` if something is not 100% visible it will count as \"needs scrolling\". If you need a different visibility ratio your best option would be to implement an [Intersection Observer](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API).\n * @defaultValue 'always'\n */\n scrollMode?: ScrollMode\n /**\n * By default there is no boundary. All the parent elements of your target is checked until it reaches the viewport ([`document.scrollingElement`](https://developer.mozilla.org/en-US/docs/Web/API/document/scrollingElement)) when calculating layout and what to scroll.\n * By passing a boundary you can short-circuit this loop depending on your needs:\n * \n * - Prevent the browser window from scrolling.\n * - Scroll elements into view in a list, without scrolling container elements.\n * \n * You can also pass a function to do more dynamic checks to override the scroll scoping:\n * \n * ```js\n * let actions = compute(target, {\n * boundary: (parent) => {\n * // By default `overflow: hidden` elements are allowed, only `overflow: visible | clip` is skipped as\n * // this is required by the CSSOM spec\n * if (getComputedStyle(parent)['overflow'] === 'hidden') {\n * return false\n * }\n\n * return true\n * },\n * })\n * ```\n * @defaultValue null\n */\n boundary?: Element | ((parent: Element) => boolean) | null\n /**\n * New option that skips auto-scrolling all nodes with overflow: hidden set\n * See FF implementation: https://hg.mozilla.org/integration/fx-team/rev/c48c3ec05012#l7.18\n * @defaultValue false\n * @public\n */\n skipOverflowHiddenElements?: boolean\n}\n\n/** @public */\nexport interface ScrollAction {\n el: Element\n top: number\n left: number\n}\n\n// @TODO better shadowdom test, 11 = document fragment\nlet isElement = (el: any): el is Element =>\n typeof el === 'object' && el != null && el.nodeType === 1\n\nlet canOverflow = (\n overflow: string | null,\n skipOverflowHiddenElements?: boolean\n) => {\n if (skipOverflowHiddenElements && overflow === 'hidden') {\n return false\n }\n\n return overflow !== 'visible' && overflow !== 'clip'\n}\n\nlet getFrameElement = (el: Element) => {\n if (!el.ownerDocument || !el.ownerDocument.defaultView) {\n return null\n }\n\n try {\n return el.ownerDocument.defaultView.frameElement\n } catch (e) {\n return null\n }\n}\n\nlet isHiddenByFrame = (el: Element): boolean => {\n let frame = getFrameElement(el)\n if (!frame) {\n return false\n }\n\n return (\n frame.clientHeight < el.scrollHeight || frame.clientWidth < el.scrollWidth\n )\n}\n\nlet isScrollable = (el: Element, skipOverflowHiddenElements?: boolean) => {\n if (el.clientHeight < el.scrollHeight || el.clientWidth < el.scrollWidth) {\n let style = getComputedStyle(el, null)\n return (\n canOverflow(style.overflowY, skipOverflowHiddenElements) ||\n canOverflow(style.overflowX, skipOverflowHiddenElements) ||\n isHiddenByFrame(el)\n )\n }\n\n return false\n}\n/**\n * Find out which edge to align against when logical scroll position is \"nearest\"\n * Interesting fact: \"nearest\" works similarily to \"if-needed\", if the element is fully visible it will not scroll it\n *\n * Legends:\n * ┌────────┐ ┏ ━ ━ ━ ┓\n * │ target │ frame\n * └────────┘ ┗ ━ ━ ━ ┛\n */\nlet alignNearest = (\n scrollingEdgeStart: number,\n scrollingEdgeEnd: number,\n scrollingSize: number,\n scrollingBorderStart: number,\n scrollingBorderEnd: number,\n elementEdgeStart: number,\n elementEdgeEnd: number,\n elementSize: number\n) => {\n /**\n * If element edge A and element edge B are both outside scrolling box edge A and scrolling box edge B\n *\n * ┌──┐\n * ┏━│━━│━┓\n * │ │\n * ┃ │ │ ┃ do nothing\n * │ │\n * ┗━│━━│━┛\n * └──┘\n *\n * If element edge C and element edge D are both outside scrolling box edge C and scrolling box edge D\n *\n * ┏ ━ ━ ━ ━ ┓\n * ┌───────────┐\n * │┃ ┃│ do nothing\n * └───────────┘\n * ┗ ━ ━ ━ ━ ┛\n */\n if (\n (elementEdgeStart < scrollingEdgeStart &&\n elementEdgeEnd > scrollingEdgeEnd) ||\n (elementEdgeStart > scrollingEdgeStart && elementEdgeEnd < scrollingEdgeEnd)\n ) {\n return 0\n }\n\n /**\n * If element edge A is outside scrolling box edge A and element height is less than scrolling box height\n *\n * ┌──┐\n * ┏━│━━│━┓ ┏━┌━━┐━┓\n * └──┘ │ │\n * from ┃ ┃ to ┃ └──┘ ┃\n *\n * ┗━ ━━ ━┛ ┗━ ━━ ━┛\n *\n * If element edge B is outside scrolling box edge B and element height is greater than scrolling box height\n *\n * ┏━ ━━ ━┓ ┏━┌━━┐━┓\n * │ │\n * from ┃ ┌──┐ ┃ to ┃ │ │ ┃\n * │ │ │ │\n * ┗━│━━│━┛ ┗━│━━│━┛\n * │ │ └──┘\n * │ │\n * └──┘\n *\n * If element edge C is outside scrolling box edge C and element width is less than scrolling box width\n *\n * from to\n * ┏ ━ ━ ━ ━ ┓ ┏ ━ ━ ━ ━ ┓\n * ┌───┐ ┌───┐\n * │ ┃ │ ┃ ┃ │ ┃\n * └───┘ └───┘\n * ┗ ━ ━ ━ ━ ┛ ┗ ━ ━ ━ ━ ┛\n *\n * If element edge D is outside scrolling box edge D and element width is greater than scrolling box width\n *\n * from to\n * ┏ ━ ━ ━ ━ ┓ ┏ ━ ━ ━ ━ ┓\n * ┌───────────┐ ┌───────────┐\n * ┃ │ ┃ │ ┃ ┃ │\n * └───────────┘ └───────────┘\n * ┗ ━ ━ ━ ━ ┛ ┗ ━ ━ ━ ━ ┛\n */\n if (\n (elementEdgeStart <= scrollingEdgeStart && elementSize <= scrollingSize) ||\n (elementEdgeEnd >= scrollingEdgeEnd && elementSize >= scrollingSize)\n ) {\n return elementEdgeStart - scrollingEdgeStart - scrollingBorderStart\n }\n\n /**\n * If element edge B is outside scrolling box edge B and element height is less than scrolling box height\n *\n * ┏━ ━━ ━┓ ┏━ ━━ ━┓\n *\n * from ┃ ┃ to ┃ ┌──┐ ┃\n * ┌──┐ │ │\n * ┗━│━━│━┛ ┗━└━━┘━┛\n * └──┘\n *\n * If element edge A is outside scrolling box edge A and element height is greater than scrolling box height\n *\n * ┌──┐\n * │ │\n * │ │ ┌──┐\n * ┏━│━━│━┓ ┏━│━━│━┓\n * │ │ │ │\n * from ┃ └──┘ ┃ to ┃ │ │ ┃\n * │ │\n * ┗━ ━━ ━┛ ┗━└━━┘━┛\n *\n * If element edge C is outside scrolling box edge C and element width is greater than scrolling box width\n *\n * from to\n * ┏ ━ ━ ━ ━ ┓ ┏ ━ ━ ━ ━ ┓\n * ┌───────────┐ ┌───────────┐\n * │ ┃ │ ┃ │ ┃ ┃\n * └───────────┘ └───────────┘\n * ┗ ━ ━ ━ ━ ┛ ┗ ━ ━ ━ ━ ┛\n *\n * If element edge D is outside scrolling box edge D and element width is less than scrolling box width\n *\n * from to\n * ┏ ━ ━ ━ ━ ┓ ┏ ━ ━ ━ ━ ┓\n * ┌───┐ ┌───┐\n * ┃ │ ┃ │ ┃ │ ┃\n * └───┘ └───┘\n * ┗ ━ ━ ━ ━ ┛ ┗ ━ ━ ━ ━ ┛\n *\n */\n if (\n (elementEdgeEnd > scrollingEdgeEnd && elementSize < scrollingSize) ||\n (elementEdgeStart < scrollingEdgeStart && elementSize > scrollingSize)\n ) {\n return elementEdgeEnd - scrollingEdgeEnd + scrollingBorderEnd\n }\n\n return 0\n}\n\nlet getParentElement = (element: Node): Element | null => {\n let parent = element.parentElement\n if (parent == null) {\n return (element.getRootNode() as ShadowRoot).host || null\n }\n return parent\n}\n\n/** @public */\nexport let compute = (target: Element, options: Options): ScrollAction[] => {\n if (typeof document === 'undefined') {\n // If there's no DOM we assume it's not in a browser environment\n return []\n }\n\n let { scrollMode, block, inline, boundary, skipOverflowHiddenElements } =\n options\n // Allow using a callback to check the boundary\n // The default behavior is to check if the current target matches the boundary element or not\n // If undefined it'll check that target is never undefined (can happen as we recurse up the tree)\n let checkBoundary =\n typeof boundary === 'function' ? boundary : (node: any) => node !== boundary\n\n if (!isElement(target)) {\n throw new TypeError('Invalid target')\n }\n\n // Used to handle the top most element that can be scrolled\n let scrollingElement = document.scrollingElement || document.documentElement\n\n // Collect all the scrolling boxes, as defined in the spec: https://drafts.csswg.org/cssom-view/#scrolling-box\n let frames: Element[] = []\n let cursor: Element | null = target\n while (isElement(cursor) && checkBoundary(cursor)) {\n // Move cursor to parent\n cursor = getParentElement(cursor)\n\n // Stop when we reach the viewport\n if (cursor === scrollingElement) {\n frames.push(cursor)\n break\n }\n\n // Skip document.body if it's not the scrollingElement and documentElement isn't independently scrollable\n if (\n cursor != null &&\n cursor === document.body &&\n isScrollable(cursor) &&\n !isScrollable(document.documentElement)\n ) {\n continue\n }\n\n // Now we check if the element is scrollable, this code only runs if the loop haven't already hit the viewport or a custom boundary\n if (cursor != null && isScrollable(cursor, skipOverflowHiddenElements)) {\n frames.push(cursor)\n }\n }\n\n // Support pinch-zooming properly, making sure elements scroll into the visual viewport\n // Browsers that don't support visualViewport will report the layout viewport dimensions on document.documentElement.clientWidth/Height\n // and viewport dimensions on window.innerWidth/Height\n // https://www.quirksmode.org/mobile/viewports2.html\n // https://bokand.github.io/viewport/index.html\n let viewportWidth = window.visualViewport?.width ?? innerWidth\n let viewportHeight = window.visualViewport?.height ?? innerHeight\n let { scrollX, scrollY } = window\n\n let {\n height: targetHeight,\n width: targetWidth,\n top: targetTop,\n right: targetRight,\n bottom: targetBottom,\n left: targetLeft,\n } = target.getBoundingClientRect()\n\n // These values mutate as we loop through and generate scroll coordinates\n let targetBlock: number =\n block === 'start' || block === 'nearest'\n ? targetTop\n : block === 'end'\n ? targetBottom\n : targetTop + targetHeight / 2 // block === 'center\n let targetInline: number =\n inline === 'center'\n ? targetLeft + targetWidth / 2\n : inline === 'end'\n ? targetRight\n : targetLeft // inline === 'start || inline === 'nearest\n\n // Collect new scroll positions\n let computations: ScrollAction[] = []\n // In chrome there's no longer a difference between caching the `frames.length` to a var or not, so we don't in this case (size > speed anyways)\n for (let index = 0; index < frames.length; index++) {\n let frame = frames[index]\n\n // @TODO add a shouldScroll hook here that allows userland code to take control\n\n let { height, width, top, right, bottom, left } =\n frame.getBoundingClientRect()\n\n // If the element is already visible we can end it here\n // @TODO targetBlock and targetInline should be taken into account to be compliant with https://github.com/w3c/csswg-drafts/pull/1805/files#diff-3c17f0e43c20f8ecf89419d49e7ef5e0R1333\n if (\n scrollMode === 'if-needed' &&\n targetTop >= 0 &&\n targetLeft >= 0 &&\n targetBottom <= viewportHeight &&\n targetRight <= viewportWidth &&\n targetTop >= top &&\n targetBottom <= bottom &&\n targetLeft >= left &&\n targetRight <= right\n ) {\n // Break the loop and return the computations for things that are not fully visible\n return computations\n }\n\n let frameStyle = getComputedStyle(frame)\n let borderLeft = parseInt(frameStyle.borderLeftWidth as string, 10)\n let borderTop = parseInt(frameStyle.borderTopWidth as string, 10)\n let borderRight = parseInt(frameStyle.borderRightWidth as string, 10)\n let borderBottom = parseInt(frameStyle.borderBottomWidth as string, 10)\n\n let blockScroll: number = 0\n let inlineScroll: number = 0\n\n // The property existance checks for offfset[Width|Height] is because only HTMLElement objects have them, but any Element might pass by here\n // @TODO find out if the \"as HTMLElement\" overrides can be dropped\n let scrollbarWidth =\n 'offsetWidth' in frame\n ? (frame as HTMLElement).offsetWidth -\n (frame as HTMLElement).clientWidth -\n borderLeft -\n borderRight\n : 0\n let scrollbarHeight =\n 'offsetHeight' in frame\n ? (frame as HTMLElement).offsetHeight -\n (frame as HTMLElement).clientHeight -\n borderTop -\n borderBottom\n : 0\n\n let scaleX =\n 'offsetWidth' in frame\n ? (frame as HTMLElement).offsetWidth === 0\n ? 0\n : width / (frame as HTMLElement).offsetWidth\n : 0\n let scaleY =\n 'offsetHeight' in frame\n ? (frame as HTMLElement).offsetHeight === 0\n ? 0\n : height / (frame as HTMLElement).offsetHeight\n : 0\n\n if (scrollingElement === frame) {\n // Handle viewport logic (document.documentElement or document.body)\n\n if (block === 'start') {\n blockScroll = targetBlock\n } else if (block === 'end') {\n blockScroll = targetBlock - viewportHeight\n } else if (block === 'nearest') {\n blockScroll = alignNearest(\n scrollY,\n scrollY + viewportHeight,\n viewportHeight,\n borderTop,\n borderBottom,\n scrollY + targetBlock,\n scrollY + targetBlock + targetHeight,\n targetHeight\n )\n } else {\n // block === 'center' is the default\n blockScroll = targetBlock - viewportHeight / 2\n }\n\n if (inline === 'start') {\n inlineScroll = targetInline\n } else if (inline === 'center') {\n inlineScroll = targetInline - viewportWidth / 2\n } else if (inline === 'end') {\n inlineScroll = targetInline - viewportWidth\n } else {\n // inline === 'nearest' is the default\n inlineScroll = alignNearest(\n scrollX,\n scrollX + viewportWidth,\n viewportWidth,\n borderLeft,\n borderRight,\n scrollX + targetInline,\n scrollX + targetInline + targetWidth,\n targetWidth\n )\n }\n\n // Apply scroll position offsets and ensure they are within bounds\n // @TODO add more test cases to cover this 100%\n blockScroll = Math.max(0, blockScroll + scrollY)\n inlineScroll = Math.max(0, inlineScroll + scrollX)\n } else {\n // Handle each scrolling frame that might exist between the target and the viewport\n if (block === 'start') {\n blockScroll = targetBlock - top - borderTop\n } else if (block === 'end') {\n blockScroll = targetBlock - bottom + borderBottom + scrollbarHeight\n } else if (block === 'nearest') {\n blockScroll = alignNearest(\n top,\n bottom,\n height,\n borderTop,\n borderBottom + scrollbarHeight,\n targetBlock,\n targetBlock + targetHeight,\n targetHeight\n )\n } else {\n // block === 'center' is the default\n blockScroll = targetBlock - (top + height / 2) + scrollbarHeight / 2\n }\n\n if (inline === 'start') {\n inlineScroll = targetInline - left - borderLeft\n } else if (inline === 'center') {\n inlineScroll = targetInline - (left + width / 2) + scrollbarWidth / 2\n } else if (inline === 'end') {\n inlineScroll = targetInline - right + borderRight + scrollbarWidth\n } else {\n // inline === 'nearest' is the default\n inlineScroll = alignNearest(\n left,\n right,\n width,\n borderLeft,\n borderRight + scrollbarWidth,\n targetInline,\n targetInline + targetWidth,\n targetWidth\n )\n }\n\n let { scrollLeft, scrollTop } = frame\n // Ensure scroll coordinates are not out of bounds while applying scroll offsets\n blockScroll = Math.max(\n 0,\n Math.min(\n scrollTop + blockScroll / scaleY,\n frame.scrollHeight - height / scaleY + scrollbarHeight\n )\n )\n inlineScroll = Math.max(\n 0,\n Math.min(\n scrollLeft + inlineScroll / scaleX,\n frame.scrollWidth - width / scaleX + scrollbarWidth\n )\n )\n\n // Cache the offset so that parent frames can scroll this into view correctly\n targetBlock += scrollTop - blockScroll\n targetInline += scrollLeft - inlineScroll\n }\n\n computations.push({ el: frame, top: blockScroll, left: inlineScroll })\n }\n\n return computations\n}\n"],"names":["Object","defineProperty","exports","value","isElement","el","nodeType","canOverflow","overflow","skipOverflowHiddenElements","isScrollable","clientHeight","scrollHeight","clientWidth","scrollWidth","style","getComputedStyle","overflowY","overflowX","frame","ownerDocument","defaultView","frameElement","e","getFrameElement","isHiddenByFrame","alignNearest","scrollingEdgeStart","scrollingEdgeEnd","scrollingSize","scrollingBorderStart","scrollingBorderEnd","elementEdgeStart","elementEdgeEnd","elementSize","getParentElement","element","parent","parentElement","getRootNode","host","compute","target","options","_a","_b","_c","_d","document","scrollMode","block","inline","boundary","checkBoundary","node","TypeError","scrollingElement","documentElement","frames","cursor","push","body","viewportWidth","window","visualViewport","width","innerWidth","viewportHeight","height","innerHeight","scrollX","scrollY","targetHeight","targetWidth","top","targetTop","right","targetRight","bottom","targetBottom","left","targetLeft","getBoundingClientRect","targetBlock","targetInline","computations","index","length","frameStyle","borderLeft","parseInt","borderLeftWidth","borderTop","borderTopWidth","borderRight","borderRightWidth","borderBottom","borderBottomWidth","blockScroll","inlineScroll","scrollbarWidth","offsetWidth","scrollbarHeight","offsetHeight","scaleX","scaleY","Math","max","scrollLeft","scrollTop","min"],"mappings":"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"}
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ let t=t=>"object"==typeof t&&null!=t&&1===t.nodeType,e=(t,e)=>(!e||"hidden"!==t)&&("visible"!==t&&"clip"!==t),n=(t,n)=>{if(t.clientHeight<t.scrollHeight||t.clientWidth<t.scrollWidth){let l=getComputedStyle(t,null);return e(l.overflowY,n)||e(l.overflowX,n)||(t=>{let e=(t=>{if(!t.ownerDocument||!t.ownerDocument.defaultView)return null;try{return t.ownerDocument.defaultView.frameElement}catch(t){return null}})(t);return!!e&&(e.clientHeight<t.scrollHeight||e.clientWidth<t.scrollWidth)})(t)}return!1},l=(t,e,n,l,i,o,r,d)=>o<t&&r>e||o>t&&r<e?0:o<=t&&d<=n||r>=e&&d>=n?o-t-l:r>e&&d<n||o<t&&d>n?r-e+i:0,i=t=>{let e=t.parentElement;return null==e?t.getRootNode().host||null:e},o=(e,o)=>{var r,d,h,f;if("undefined"==typeof document)return[];let{scrollMode:u,block:s,inline:c,boundary:a,skipOverflowHiddenElements:g}=o,m="function"==typeof a?a:t=>t!==a;if(!t(e))throw new TypeError("Invalid target");let p=document.scrollingElement||document.documentElement,w=[],W=e;for(;t(W)&&m(W);){if(W=i(W),W===p){w.push(W);break}null!=W&&W===document.body&&n(W)&&!n(document.documentElement)||null!=W&&n(W,g)&&w.push(W)}let H=null!=(d=null==(r=window.visualViewport)?void 0:r.width)?d:innerWidth,b=null!=(f=null==(h=window.visualViewport)?void 0:h.height)?f:innerHeight,{scrollX:v,scrollY:y}=window,{height:E,width:M,top:x,right:I,bottom:C,left:R}=e.getBoundingClientRect(),T="start"===s||"nearest"===s?x:"end"===s?C:x+E/2,V="center"===c?R+M/2:"end"===c?I:R,k=[];for(let t=0;t<w.length;t++){let e=w[t],{height:n,width:i,top:o,right:r,bottom:d,left:h}=e.getBoundingClientRect();if("if-needed"===u&&x>=0&&R>=0&&C<=b&&I<=H&&x>=o&&C<=d&&R>=h&&I<=r)return k;let f=getComputedStyle(e),a=parseInt(f.borderLeftWidth,10),g=parseInt(f.borderTopWidth,10),m=parseInt(f.borderRightWidth,10),W=parseInt(f.borderBottomWidth,10),B=0,D=0,L="offsetWidth"in e?e.offsetWidth-e.clientWidth-a-m:0,S="offsetHeight"in e?e.offsetHeight-e.clientHeight-g-W:0,X="offsetWidth"in e?0===e.offsetWidth?0:i/e.offsetWidth:0,Y="offsetHeight"in e?0===e.offsetHeight?0:n/e.offsetHeight:0;if(p===e)B="start"===s?T:"end"===s?T-b:"nearest"===s?l(y,y+b,b,g,W,y+T,y+T+E,E):T-b/2,D="start"===c?V:"center"===c?V-H/2:"end"===c?V-H:l(v,v+H,H,a,m,v+V,v+V+M,M),B=Math.max(0,B+y),D=Math.max(0,D+v);else{B="start"===s?T-o-g:"end"===s?T-d+W+S:"nearest"===s?l(o,d,n,g,W+S,T,T+E,E):T-(o+n/2)+S/2,D="start"===c?V-h-a:"center"===c?V-(h+i/2)+L/2:"end"===c?V-r+m+L:l(h,r,i,a,m+L,V,V+M,M);let{scrollLeft:t,scrollTop:f}=e;B=Math.max(0,Math.min(f+B/Y,e.scrollHeight-n/Y+S)),D=Math.max(0,Math.min(t+D/X,e.scrollWidth-i/X+L)),T+=f-B,V+=t-D}k.push({el:e,top:B,left:D})}return k};export{o as compute};//# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["// Compute what scrolling needs to be done on required scrolling boxes for target to be in view\n\n// The type names here are named after the spec to make it easier to find more information around what they mean:\n// To reduce churn and reduce things that need be maintained things from the official TS DOM library is used here\n// https://drafts.csswg.org/cssom-view/\n\n// For a definition on what is \"block flow direction\" exactly, check this: https://drafts.csswg.org/css-writing-modes-4/#block-flow-direction\n\n/**\n * This new option is tracked in this PR, which is the most likely candidate at the time: https://github.com/w3c/csswg-drafts/pull/1805\n * @public\n */\nexport type ScrollMode = 'always' | 'if-needed'\n\n/** @public */\nexport interface Options {\n /**\n * Control the logical scroll position on the y-axis. The spec states that the `block` direction is related to the [writing-mode](https://developer.mozilla.org/en-US/docs/Web/CSS/writing-mode), but this is not implemented yet in this library.\n * This means that `block: 'start'` aligns to the top edge and `block: 'end'` to the bottom.\n * @defaultValue 'center'\n */\n block?: ScrollLogicalPosition\n /**\n * Like `block` this is affected by the [writing-mode](https://developer.mozilla.org/en-US/docs/Web/CSS/writing-mode). In left-to-right pages `inline: 'start'` will align to the left edge. In right-to-left it should be flipped. This will be supported in a future release.\n * @defaultValue 'nearest'\n */\n inline?: ScrollLogicalPosition\n /**\n * This is a proposed addition to the spec that you can track here: https://github.com/w3c/csswg-drafts/pull/5677\n *\n * This library will be updated to reflect any changes to the spec and will provide a migration path.\n * To be backwards compatible with `Element.scrollIntoViewIfNeeded` if something is not 100% visible it will count as \"needs scrolling\". If you need a different visibility ratio your best option would be to implement an [Intersection Observer](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API).\n * @defaultValue 'always'\n */\n scrollMode?: ScrollMode\n /**\n * By default there is no boundary. All the parent elements of your target is checked until it reaches the viewport ([`document.scrollingElement`](https://developer.mozilla.org/en-US/docs/Web/API/document/scrollingElement)) when calculating layout and what to scroll.\n * By passing a boundary you can short-circuit this loop depending on your needs:\n * \n * - Prevent the browser window from scrolling.\n * - Scroll elements into view in a list, without scrolling container elements.\n * \n * You can also pass a function to do more dynamic checks to override the scroll scoping:\n * \n * ```js\n * let actions = compute(target, {\n * boundary: (parent) => {\n * // By default `overflow: hidden` elements are allowed, only `overflow: visible | clip` is skipped as\n * // this is required by the CSSOM spec\n * if (getComputedStyle(parent)['overflow'] === 'hidden') {\n * return false\n * }\n\n * return true\n * },\n * })\n * ```\n * @defaultValue null\n */\n boundary?: Element | ((parent: Element) => boolean) | null\n /**\n * New option that skips auto-scrolling all nodes with overflow: hidden set\n * See FF implementation: https://hg.mozilla.org/integration/fx-team/rev/c48c3ec05012#l7.18\n * @defaultValue false\n * @public\n */\n skipOverflowHiddenElements?: boolean\n}\n\n/** @public */\nexport interface ScrollAction {\n el: Element\n top: number\n left: number\n}\n\n// @TODO better shadowdom test, 11 = document fragment\nlet isElement = (el: any): el is Element =>\n typeof el === 'object' && el != null && el.nodeType === 1\n\nlet canOverflow = (\n overflow: string | null,\n skipOverflowHiddenElements?: boolean\n) => {\n if (skipOverflowHiddenElements && overflow === 'hidden') {\n return false\n }\n\n return overflow !== 'visible' && overflow !== 'clip'\n}\n\nlet getFrameElement = (el: Element) => {\n if (!el.ownerDocument || !el.ownerDocument.defaultView) {\n return null\n }\n\n try {\n return el.ownerDocument.defaultView.frameElement\n } catch (e) {\n return null\n }\n}\n\nlet isHiddenByFrame = (el: Element): boolean => {\n let frame = getFrameElement(el)\n if (!frame) {\n return false\n }\n\n return (\n frame.clientHeight < el.scrollHeight || frame.clientWidth < el.scrollWidth\n )\n}\n\nlet isScrollable = (el: Element, skipOverflowHiddenElements?: boolean) => {\n if (el.clientHeight < el.scrollHeight || el.clientWidth < el.scrollWidth) {\n let style = getComputedStyle(el, null)\n return (\n canOverflow(style.overflowY, skipOverflowHiddenElements) ||\n canOverflow(style.overflowX, skipOverflowHiddenElements) ||\n isHiddenByFrame(el)\n )\n }\n\n return false\n}\n/**\n * Find out which edge to align against when logical scroll position is \"nearest\"\n * Interesting fact: \"nearest\" works similarily to \"if-needed\", if the element is fully visible it will not scroll it\n *\n * Legends:\n * ┌────────┐ ┏ ━ ━ ━ ┓\n * │ target │ frame\n * └────────┘ ┗ ━ ━ ━ ┛\n */\nlet alignNearest = (\n scrollingEdgeStart: number,\n scrollingEdgeEnd: number,\n scrollingSize: number,\n scrollingBorderStart: number,\n scrollingBorderEnd: number,\n elementEdgeStart: number,\n elementEdgeEnd: number,\n elementSize: number\n) => {\n /**\n * If element edge A and element edge B are both outside scrolling box edge A and scrolling box edge B\n *\n * ┌──┐\n * ┏━│━━│━┓\n * │ │\n * ┃ │ │ ┃ do nothing\n * │ │\n * ┗━│━━│━┛\n * └──┘\n *\n * If element edge C and element edge D are both outside scrolling box edge C and scrolling box edge D\n *\n * ┏ ━ ━ ━ ━ ┓\n * ┌───────────┐\n * │┃ ┃│ do nothing\n * └───────────┘\n * ┗ ━ ━ ━ ━ ┛\n */\n if (\n (elementEdgeStart < scrollingEdgeStart &&\n elementEdgeEnd > scrollingEdgeEnd) ||\n (elementEdgeStart > scrollingEdgeStart && elementEdgeEnd < scrollingEdgeEnd)\n ) {\n return 0\n }\n\n /**\n * If element edge A is outside scrolling box edge A and element height is less than scrolling box height\n *\n * ┌──┐\n * ┏━│━━│━┓ ┏━┌━━┐━┓\n * └──┘ │ │\n * from ┃ ┃ to ┃ └──┘ ┃\n *\n * ┗━ ━━ ━┛ ┗━ ━━ ━┛\n *\n * If element edge B is outside scrolling box edge B and element height is greater than scrolling box height\n *\n * ┏━ ━━ ━┓ ┏━┌━━┐━┓\n * │ │\n * from ┃ ┌──┐ ┃ to ┃ │ │ ┃\n * │ │ │ │\n * ┗━│━━│━┛ ┗━│━━│━┛\n * │ │ └──┘\n * │ │\n * └──┘\n *\n * If element edge C is outside scrolling box edge C and element width is less than scrolling box width\n *\n * from to\n * ┏ ━ ━ ━ ━ ┓ ┏ ━ ━ ━ ━ ┓\n * ┌───┐ ┌───┐\n * │ ┃ │ ┃ ┃ │ ┃\n * └───┘ └───┘\n * ┗ ━ ━ ━ ━ ┛ ┗ ━ ━ ━ ━ ┛\n *\n * If element edge D is outside scrolling box edge D and element width is greater than scrolling box width\n *\n * from to\n * ┏ ━ ━ ━ ━ ┓ ┏ ━ ━ ━ ━ ┓\n * ┌───────────┐ ┌───────────┐\n * ┃ │ ┃ │ ┃ ┃ │\n * └───────────┘ └───────────┘\n * ┗ ━ ━ ━ ━ ┛ ┗ ━ ━ ━ ━ ┛\n */\n if (\n (elementEdgeStart <= scrollingEdgeStart && elementSize <= scrollingSize) ||\n (elementEdgeEnd >= scrollingEdgeEnd && elementSize >= scrollingSize)\n ) {\n return elementEdgeStart - scrollingEdgeStart - scrollingBorderStart\n }\n\n /**\n * If element edge B is outside scrolling box edge B and element height is less than scrolling box height\n *\n * ┏━ ━━ ━┓ ┏━ ━━ ━┓\n *\n * from ┃ ┃ to ┃ ┌──┐ ┃\n * ┌──┐ │ │\n * ┗━│━━│━┛ ┗━└━━┘━┛\n * └──┘\n *\n * If element edge A is outside scrolling box edge A and element height is greater than scrolling box height\n *\n * ┌──┐\n * │ │\n * │ │ ┌──┐\n * ┏━│━━│━┓ ┏━│━━│━┓\n * │ │ │ │\n * from ┃ └──┘ ┃ to ┃ │ │ ┃\n * │ │\n * ┗━ ━━ ━┛ ┗━└━━┘━┛\n *\n * If element edge C is outside scrolling box edge C and element width is greater than scrolling box width\n *\n * from to\n * ┏ ━ ━ ━ ━ ┓ ┏ ━ ━ ━ ━ ┓\n * ┌───────────┐ ┌───────────┐\n * │ ┃ │ ┃ │ ┃ ┃\n * └───────────┘ └───────────┘\n * ┗ ━ ━ ━ ━ ┛ ┗ ━ ━ ━ ━ ┛\n *\n * If element edge D is outside scrolling box edge D and element width is less than scrolling box width\n *\n * from to\n * ┏ ━ ━ ━ ━ ┓ ┏ ━ ━ ━ ━ ┓\n * ┌───┐ ┌───┐\n * ┃ │ ┃ │ ┃ │ ┃\n * └───┘ └───┘\n * ┗ ━ ━ ━ ━ ┛ ┗ ━ ━ ━ ━ ┛\n *\n */\n if (\n (elementEdgeEnd > scrollingEdgeEnd && elementSize < scrollingSize) ||\n (elementEdgeStart < scrollingEdgeStart && elementSize > scrollingSize)\n ) {\n return elementEdgeEnd - scrollingEdgeEnd + scrollingBorderEnd\n }\n\n return 0\n}\n\nlet getParentElement = (element: Node): Element | null => {\n let parent = element.parentElement\n if (parent == null) {\n return (element.getRootNode() as ShadowRoot).host || null\n }\n return parent\n}\n\n/** @public */\nexport let compute = (target: Element, options: Options): ScrollAction[] => {\n if (typeof document === 'undefined') {\n // If there's no DOM we assume it's not in a browser environment\n return []\n }\n\n let { scrollMode, block, inline, boundary, skipOverflowHiddenElements } =\n options\n // Allow using a callback to check the boundary\n // The default behavior is to check if the current target matches the boundary element or not\n // If undefined it'll check that target is never undefined (can happen as we recurse up the tree)\n let checkBoundary =\n typeof boundary === 'function' ? boundary : (node: any) => node !== boundary\n\n if (!isElement(target)) {\n throw new TypeError('Invalid target')\n }\n\n // Used to handle the top most element that can be scrolled\n let scrollingElement = document.scrollingElement || document.documentElement\n\n // Collect all the scrolling boxes, as defined in the spec: https://drafts.csswg.org/cssom-view/#scrolling-box\n let frames: Element[] = []\n let cursor: Element | null = target\n while (isElement(cursor) && checkBoundary(cursor)) {\n // Move cursor to parent\n cursor = getParentElement(cursor)\n\n // Stop when we reach the viewport\n if (cursor === scrollingElement) {\n frames.push(cursor)\n break\n }\n\n // Skip document.body if it's not the scrollingElement and documentElement isn't independently scrollable\n if (\n cursor != null &&\n cursor === document.body &&\n isScrollable(cursor) &&\n !isScrollable(document.documentElement)\n ) {\n continue\n }\n\n // Now we check if the element is scrollable, this code only runs if the loop haven't already hit the viewport or a custom boundary\n if (cursor != null && isScrollable(cursor, skipOverflowHiddenElements)) {\n frames.push(cursor)\n }\n }\n\n // Support pinch-zooming properly, making sure elements scroll into the visual viewport\n // Browsers that don't support visualViewport will report the layout viewport dimensions on document.documentElement.clientWidth/Height\n // and viewport dimensions on window.innerWidth/Height\n // https://www.quirksmode.org/mobile/viewports2.html\n // https://bokand.github.io/viewport/index.html\n let viewportWidth = window.visualViewport?.width ?? innerWidth\n let viewportHeight = window.visualViewport?.height ?? innerHeight\n let { scrollX, scrollY } = window\n\n let {\n height: targetHeight,\n width: targetWidth,\n top: targetTop,\n right: targetRight,\n bottom: targetBottom,\n left: targetLeft,\n } = target.getBoundingClientRect()\n\n // These values mutate as we loop through and generate scroll coordinates\n let targetBlock: number =\n block === 'start' || block === 'nearest'\n ? targetTop\n : block === 'end'\n ? targetBottom\n : targetTop + targetHeight / 2 // block === 'center\n let targetInline: number =\n inline === 'center'\n ? targetLeft + targetWidth / 2\n : inline === 'end'\n ? targetRight\n : targetLeft // inline === 'start || inline === 'nearest\n\n // Collect new scroll positions\n let computations: ScrollAction[] = []\n // In chrome there's no longer a difference between caching the `frames.length` to a var or not, so we don't in this case (size > speed anyways)\n for (let index = 0; index < frames.length; index++) {\n let frame = frames[index]\n\n // @TODO add a shouldScroll hook here that allows userland code to take control\n\n let { height, width, top, right, bottom, left } =\n frame.getBoundingClientRect()\n\n // If the element is already visible we can end it here\n // @TODO targetBlock and targetInline should be taken into account to be compliant with https://github.com/w3c/csswg-drafts/pull/1805/files#diff-3c17f0e43c20f8ecf89419d49e7ef5e0R1333\n if (\n scrollMode === 'if-needed' &&\n targetTop >= 0 &&\n targetLeft >= 0 &&\n targetBottom <= viewportHeight &&\n targetRight <= viewportWidth &&\n targetTop >= top &&\n targetBottom <= bottom &&\n targetLeft >= left &&\n targetRight <= right\n ) {\n // Break the loop and return the computations for things that are not fully visible\n return computations\n }\n\n let frameStyle = getComputedStyle(frame)\n let borderLeft = parseInt(frameStyle.borderLeftWidth as string, 10)\n let borderTop = parseInt(frameStyle.borderTopWidth as string, 10)\n let borderRight = parseInt(frameStyle.borderRightWidth as string, 10)\n let borderBottom = parseInt(frameStyle.borderBottomWidth as string, 10)\n\n let blockScroll: number = 0\n let inlineScroll: number = 0\n\n // The property existance checks for offfset[Width|Height] is because only HTMLElement objects have them, but any Element might pass by here\n // @TODO find out if the \"as HTMLElement\" overrides can be dropped\n let scrollbarWidth =\n 'offsetWidth' in frame\n ? (frame as HTMLElement).offsetWidth -\n (frame as HTMLElement).clientWidth -\n borderLeft -\n borderRight\n : 0\n let scrollbarHeight =\n 'offsetHeight' in frame\n ? (frame as HTMLElement).offsetHeight -\n (frame as HTMLElement).clientHeight -\n borderTop -\n borderBottom\n : 0\n\n let scaleX =\n 'offsetWidth' in frame\n ? (frame as HTMLElement).offsetWidth === 0\n ? 0\n : width / (frame as HTMLElement).offsetWidth\n : 0\n let scaleY =\n 'offsetHeight' in frame\n ? (frame as HTMLElement).offsetHeight === 0\n ? 0\n : height / (frame as HTMLElement).offsetHeight\n : 0\n\n if (scrollingElement === frame) {\n // Handle viewport logic (document.documentElement or document.body)\n\n if (block === 'start') {\n blockScroll = targetBlock\n } else if (block === 'end') {\n blockScroll = targetBlock - viewportHeight\n } else if (block === 'nearest') {\n blockScroll = alignNearest(\n scrollY,\n scrollY + viewportHeight,\n viewportHeight,\n borderTop,\n borderBottom,\n scrollY + targetBlock,\n scrollY + targetBlock + targetHeight,\n targetHeight\n )\n } else {\n // block === 'center' is the default\n blockScroll = targetBlock - viewportHeight / 2\n }\n\n if (inline === 'start') {\n inlineScroll = targetInline\n } else if (inline === 'center') {\n inlineScroll = targetInline - viewportWidth / 2\n } else if (inline === 'end') {\n inlineScroll = targetInline - viewportWidth\n } else {\n // inline === 'nearest' is the default\n inlineScroll = alignNearest(\n scrollX,\n scrollX + viewportWidth,\n viewportWidth,\n borderLeft,\n borderRight,\n scrollX + targetInline,\n scrollX + targetInline + targetWidth,\n targetWidth\n )\n }\n\n // Apply scroll position offsets and ensure they are within bounds\n // @TODO add more test cases to cover this 100%\n blockScroll = Math.max(0, blockScroll + scrollY)\n inlineScroll = Math.max(0, inlineScroll + scrollX)\n } else {\n // Handle each scrolling frame that might exist between the target and the viewport\n if (block === 'start') {\n blockScroll = targetBlock - top - borderTop\n } else if (block === 'end') {\n blockScroll = targetBlock - bottom + borderBottom + scrollbarHeight\n } else if (block === 'nearest') {\n blockScroll = alignNearest(\n top,\n bottom,\n height,\n borderTop,\n borderBottom + scrollbarHeight,\n targetBlock,\n targetBlock + targetHeight,\n targetHeight\n )\n } else {\n // block === 'center' is the default\n blockScroll = targetBlock - (top + height / 2) + scrollbarHeight / 2\n }\n\n if (inline === 'start') {\n inlineScroll = targetInline - left - borderLeft\n } else if (inline === 'center') {\n inlineScroll = targetInline - (left + width / 2) + scrollbarWidth / 2\n } else if (inline === 'end') {\n inlineScroll = targetInline - right + borderRight + scrollbarWidth\n } else {\n // inline === 'nearest' is the default\n inlineScroll = alignNearest(\n left,\n right,\n width,\n borderLeft,\n borderRight + scrollbarWidth,\n targetInline,\n targetInline + targetWidth,\n targetWidth\n )\n }\n\n let { scrollLeft, scrollTop } = frame\n // Ensure scroll coordinates are not out of bounds while applying scroll offsets\n blockScroll = Math.max(\n 0,\n Math.min(\n scrollTop + blockScroll / scaleY,\n frame.scrollHeight - height / scaleY + scrollbarHeight\n )\n )\n inlineScroll = Math.max(\n 0,\n Math.min(\n scrollLeft + inlineScroll / scaleX,\n frame.scrollWidth - width / scaleX + scrollbarWidth\n )\n )\n\n // Cache the offset so that parent frames can scroll this into view correctly\n targetBlock += scrollTop - blockScroll\n targetInline += scrollLeft - inlineScroll\n }\n\n computations.push({ el: frame, top: blockScroll, left: inlineScroll })\n }\n\n return computations\n}\n"],"names":["isElement","el","nodeType","canOverflow","overflow","skipOverflowHiddenElements","isScrollable","clientHeight","scrollHeight","clientWidth","scrollWidth","style","getComputedStyle","overflowY","overflowX","frame","ownerDocument","defaultView","frameElement","e","getFrameElement","isHiddenByFrame","alignNearest","scrollingEdgeStart","scrollingEdgeEnd","scrollingSize","scrollingBorderStart","scrollingBorderEnd","elementEdgeStart","elementEdgeEnd","elementSize","getParentElement","element","parent","parentElement","getRootNode","host","compute","target","options","_a","_b","_c","_d","document","scrollMode","block","inline","boundary","checkBoundary","node","TypeError","scrollingElement","documentElement","frames","cursor","push","body","viewportWidth","window","visualViewport","width","innerWidth","viewportHeight","height","innerHeight","scrollX","scrollY","targetHeight","targetWidth","top","targetTop","right","targetRight","bottom","targetBottom","left","targetLeft","getBoundingClientRect","targetBlock","targetInline","computations","index","length","frameStyle","borderLeft","parseInt","borderLeftWidth","borderTop","borderTopWidth","borderRight","borderRightWidth","borderBottom","borderBottomWidth","blockScroll","inlineScroll","scrollbarWidth","offsetWidth","scrollbarHeight","offsetHeight","scaleX","scaleY","Math","max","scrollLeft","scrollTop","min"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "compute-scroll-into-view",
3
- "version": "2.0.4",
3
+ "version": "3.0.1",
4
4
  "description": "The engine that powers scroll-into-view-if-needed",
5
5
  "keywords": [
6
6
  "if-needed",
@@ -20,19 +20,20 @@
20
20
  "license": "MIT",
21
21
  "author": "Cody Olsen",
22
22
  "sideEffects": false,
23
- "type": "module",
23
+ "type": "commonjs",
24
24
  "exports": {
25
25
  ".": {
26
26
  "types": "./dist/index.d.ts",
27
27
  "source": "./src/index.ts",
28
- "import": "./dist/index.js",
29
- "require": "./dist/index.cjs",
28
+ "require": "./dist/index.js",
29
+ "import": "./dist/index.mjs",
30
30
  "default": "./dist/index.js"
31
31
  },
32
32
  "./package.json": "./package.json"
33
33
  },
34
- "main": "./dist/index.cjs",
35
- "module": "./dist/index.js",
34
+ "main": "./dist/index.js",
35
+ "module": "./dist/index.mjs",
36
+ "source": "./src/index.ts",
36
37
  "typings": "./dist/index.d.ts",
37
38
  "files": [
38
39
  "dist",
@@ -46,7 +47,7 @@
46
47
  "typecheck": "tsc"
47
48
  },
48
49
  "browserslist": [
49
- "> 0.2% and supports es6-module and supports es6-module-dynamic-import and not dead and not IE 11",
50
+ "> 0.2% and supports es6-module and supports es6-module-dynamic-import and not dead",
50
51
  "maintained node versions"
51
52
  ],
52
53
  "prettier": {
@@ -54,22 +55,22 @@
54
55
  "singleQuote": true
55
56
  },
56
57
  "devDependencies": {
57
- "@sanity/pkg-utils": "^2.1.1",
58
- "@sanity/semantic-release-preset": "^3.0.0",
58
+ "@sanity/pkg-utils": "^2.2.5",
59
+ "@sanity/semantic-release-preset": "^4.0.0",
59
60
  "@types/expect-puppeteer": "^5.0.2",
60
- "@types/jest": "^29.2.5",
61
+ "@types/jest": "^29.4.0",
61
62
  "@types/jest-environment-puppeteer": "^5.0.3",
62
63
  "@types/puppeteer": "^7.0.4",
63
64
  "cross-env": "^7.0.3",
64
- "jest": "^29.3.1",
65
+ "jest": "^29.5.0",
65
66
  "jest-junit": "^15.0.0",
66
- "jest-puppeteer": "^6.2.0",
67
- "prettier": "^2.8.2",
68
- "prettier-plugin-packagejson": "^2.3.0",
69
- "puppeteer": "^19.4.1",
70
- "rimraf": "^3.0.2",
71
- "serve": "^14.1.2",
72
- "typescript": "^4.9.4"
67
+ "jest-puppeteer": "^8.0.0",
68
+ "prettier": "^2.8.4",
69
+ "prettier-plugin-packagejson": "^2.4.3",
70
+ "puppeteer": "^19.7.0",
71
+ "rimraf": "^4.1.2",
72
+ "serve": "^14.2.0",
73
+ "typescript": "^5.0.0"
73
74
  },
74
75
  "bundlesize": [
75
76
  {
package/src/index.ts CHANGED
@@ -275,7 +275,7 @@ let getParentElement = (element: Node): Element | null => {
275
275
  }
276
276
 
277
277
  /** @public */
278
- export default (target: Element, options: Options): ScrollAction[] => {
278
+ export let compute = (target: Element, options: Options): ScrollAction[] => {
279
279
  if (typeof document === 'undefined') {
280
280
  // If there's no DOM we assume it's not in a browser environment
281
281
  return []
@@ -332,10 +332,7 @@ export default (target: Element, options: Options): ScrollAction[] => {
332
332
  // https://bokand.github.io/viewport/index.html
333
333
  let viewportWidth = window.visualViewport?.width ?? innerWidth
334
334
  let viewportHeight = window.visualViewport?.height ?? innerHeight
335
-
336
- // Newer browsers supports scroll[X|Y], page[X|Y]Offset is
337
- let viewportX = window.scrollX ?? pageXOffset
338
- let viewportY = window.scrollY ?? pageYOffset
335
+ let { scrollX, scrollY } = window
339
336
 
340
337
  let {
341
338
  height: targetHeight,
@@ -436,13 +433,13 @@ export default (target: Element, options: Options): ScrollAction[] => {
436
433
  blockScroll = targetBlock - viewportHeight
437
434
  } else if (block === 'nearest') {
438
435
  blockScroll = alignNearest(
439
- viewportY,
440
- viewportY + viewportHeight,
436
+ scrollY,
437
+ scrollY + viewportHeight,
441
438
  viewportHeight,
442
439
  borderTop,
443
440
  borderBottom,
444
- viewportY + targetBlock,
445
- viewportY + targetBlock + targetHeight,
441
+ scrollY + targetBlock,
442
+ scrollY + targetBlock + targetHeight,
446
443
  targetHeight
447
444
  )
448
445
  } else {
@@ -459,24 +456,23 @@ export default (target: Element, options: Options): ScrollAction[] => {
459
456
  } else {
460
457
  // inline === 'nearest' is the default
461
458
  inlineScroll = alignNearest(
462
- viewportX,
463
- viewportX + viewportWidth,
459
+ scrollX,
460
+ scrollX + viewportWidth,
464
461
  viewportWidth,
465
462
  borderLeft,
466
463
  borderRight,
467
- viewportX + targetInline,
468
- viewportX + targetInline + targetWidth,
464
+ scrollX + targetInline,
465
+ scrollX + targetInline + targetWidth,
469
466
  targetWidth
470
467
  )
471
468
  }
472
469
 
473
470
  // Apply scroll position offsets and ensure they are within bounds
474
471
  // @TODO add more test cases to cover this 100%
475
- blockScroll = Math.max(0, blockScroll + viewportY)
476
- inlineScroll = Math.max(0, inlineScroll + viewportX)
472
+ blockScroll = Math.max(0, blockScroll + scrollY)
473
+ inlineScroll = Math.max(0, inlineScroll + scrollX)
477
474
  } else {
478
475
  // Handle each scrolling frame that might exist between the target and the viewport
479
-
480
476
  if (block === 'start') {
481
477
  blockScroll = targetBlock - top - borderTop
482
478
  } else if (block === 'end') {
package/dist/index.cjs DELETED
@@ -1 +0,0 @@
1
- "use strict";let e=e=>"object"==typeof e&&null!=e&&1===e.nodeType,t=(e,t)=>(!t||"hidden"!==e)&&("visible"!==e&&"clip"!==e),n=(e,n)=>{if(e.clientHeight<e.scrollHeight||e.clientWidth<e.scrollWidth){let l=getComputedStyle(e,null);return t(l.overflowY,n)||t(l.overflowX,n)||(e=>{let t=(e=>{if(!e.ownerDocument||!e.ownerDocument.defaultView)return null;try{return e.ownerDocument.defaultView.frameElement}catch(e){return null}})(e);return!!t&&(t.clientHeight<e.scrollHeight||t.clientWidth<e.scrollWidth)})(e)}return!1},l=(e,t,n,l,i,o,r,d)=>o<e&&r>t||o>e&&r<t?0:o<=e&&d<=n||r>=t&&d>=n?o-e-l:r>t&&d<n||o<e&&d>n?r-t+i:0,i=e=>{let t=e.parentElement;return null==t?e.getRootNode().host||null:t};module.exports=(t,o)=>{var r,d,h,f,u,s;if("undefined"==typeof document)return[];let{scrollMode:c,block:a,inline:g,boundary:m,skipOverflowHiddenElements:p}=o,w="function"==typeof m?m:e=>e!==m;if(!e(t))throw new TypeError("Invalid target");let W=document.scrollingElement||document.documentElement,H=[],b=t;for(;e(b)&&w(b);){if(b=i(b),b===W){H.push(b);break}null!=b&&b===document.body&&n(b)&&!n(document.documentElement)||null!=b&&n(b,p)&&H.push(b)}let v=null!=(d=null==(r=window.visualViewport)?void 0:r.width)?d:innerWidth,y=null!=(f=null==(h=window.visualViewport)?void 0:h.height)?f:innerHeight,E=null!=(u=window.scrollX)?u:pageXOffset,M=null!=(s=window.scrollY)?s:pageYOffset,{height:x,width:I,top:C,right:R,bottom:T,left:V}=t.getBoundingClientRect(),k="start"===a||"nearest"===a?C:"end"===a?T:C+x/2,B="center"===g?V+I/2:"end"===g?R:V,D=[];for(let e=0;e<H.length;e++){let t=H[e],{height:n,width:i,top:o,right:r,bottom:d,left:h}=t.getBoundingClientRect();if("if-needed"===c&&C>=0&&V>=0&&T<=y&&R<=v&&C>=o&&T<=d&&V>=h&&R<=r)return D;let f=getComputedStyle(t),u=parseInt(f.borderLeftWidth,10),s=parseInt(f.borderTopWidth,10),m=parseInt(f.borderRightWidth,10),p=parseInt(f.borderBottomWidth,10),w=0,b=0,O="offsetWidth"in t?t.offsetWidth-t.clientWidth-u-m:0,X="offsetHeight"in t?t.offsetHeight-t.clientHeight-s-p:0,Y="offsetWidth"in t?0===t.offsetWidth?0:i/t.offsetWidth:0,L="offsetHeight"in t?0===t.offsetHeight?0:n/t.offsetHeight:0;if(W===t)w="start"===a?k:"end"===a?k-y:"nearest"===a?l(M,M+y,y,s,p,M+k,M+k+x,x):k-y/2,b="start"===g?B:"center"===g?B-v/2:"end"===g?B-v:l(E,E+v,v,u,m,E+B,E+B+I,I),w=Math.max(0,w+M),b=Math.max(0,b+E);else{w="start"===a?k-o-s:"end"===a?k-d+p+X:"nearest"===a?l(o,d,n,s,p+X,k,k+x,x):k-(o+n/2)+X/2,b="start"===g?B-h-u:"center"===g?B-(h+i/2)+O/2:"end"===g?B-r+m+O:l(h,r,i,u,m+O,B,B+I,I);let{scrollLeft:e,scrollTop:f}=t;w=Math.max(0,Math.min(f+w/L,t.scrollHeight-n/L+X)),b=Math.max(0,Math.min(e+b/Y,t.scrollWidth-i/Y+O)),k+=f-w,B+=e-b}D.push({el:t,top:w,left:b})}return D};//# sourceMappingURL=index.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}