Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

scroll-behavior-polyfill

Package Overview
Dependencies
Maintainers
1
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

scroll-behavior-polyfill - npm Package Compare versions

Comparing version 2.0.1 to 2.0.3

13

CHANGELOG.md

@@ -0,1 +1,14 @@

## [2.0.2](https://github.com/wessberg/scroll-behavior-polyfill/compare/v2.0.1...v2.0.2) (2019-01-11)
### Features
* **improvements:** Bug fixes, support for scrolling via the scrollTop and scrollLeft setters, and more ([4989d15](https://github.com/wessberg/scroll-behavior-polyfill/commit/4989d15))
## [2.0.1](https://github.com/wessberg/scroll-behavior-polyfill/compare/v2.0.0...v2.0.1) (2019-01-09)
# [2.0.0](https://github.com/wessberg/scroll-behavior-polyfill/compare/v1.0.2...v2.0.0) (2019-01-09)

@@ -2,0 +15,0 @@

341

dist/index.js

@@ -53,8 +53,2 @@ (function () {

var ELEMENT_ORIGINAL_SCROLL = Element.prototype.scroll;
var ELEMENT_ORIGINAL_SCROLL_BY = Element.prototype.scrollBy;
var ELEMENT_ORIGINAL_SCROLL_TO = Element.prototype.scrollTo;
var styleDeclarationPropertyName = "scrollBehavior";

@@ -162,5 +156,92 @@ var styleAttributePropertyName = "scroll-behavior";

var ELEMENT_ORIGINAL_SCROLL = Element.prototype.scroll;
var WINDOW_ORIGINAL_SCROLL = window.scroll;
var ELEMENT_ORIGINAL_SCROLL_BY = Element.prototype.scrollBy;
var WINDOW_ORIGINAL_SCROLL_BY = window.scrollBy;
var ELEMENT_ORIGINAL_SCROLL_TO = Element.prototype.scrollTo;
var WINDOW_ORIGINAL_SCROLL_TO = window.scrollTo;
/**
* A fallback if Element.prototype.scroll is not defined
* @param {number} x
* @param {number} y
*/
function elementPrototypeScrollFallback(x, y) {
this.__adjustingScrollPosition = true;
this.scrollLeft = x;
this.scrollTop = y;
delete this.__adjustingScrollPosition;
}
/**
* A fallback if Element.prototype.scrollTo is not defined
* @param {number} x
* @param {number} y
*/
function elementPrototypeScrollToFallback(x, y) {
return elementPrototypeScrollFallback.call(this, x, y);
}
/**
* A fallback if Element.prototype.scrollBy is not defined
* @param {number} x
* @param {number} y
*/
function elementPrototypeScrollByFallback(x, y) {
this.__adjustingScrollPosition = true;
this.scrollLeft += x;
this.scrollTop += y;
delete this.__adjustingScrollPosition;
}
/**
* Gets the original non-patched prototype method for the given kind
* @param {ScrollMethodName} kind
* @param {Element|Window} element
* @return {Function}
*/
function getOriginalScrollMethodForKind(kind, element) {
switch (kind) {
case "scroll":
if (element instanceof Element) {
if (ELEMENT_ORIGINAL_SCROLL != null) {
return ELEMENT_ORIGINAL_SCROLL;
}
else {
return elementPrototypeScrollFallback;
}
}
else {
return WINDOW_ORIGINAL_SCROLL;
}
case "scrollBy":
if (element instanceof Element) {
if (ELEMENT_ORIGINAL_SCROLL_BY != null) {
return ELEMENT_ORIGINAL_SCROLL_BY;
}
else {
return elementPrototypeScrollByFallback;
}
}
else {
return WINDOW_ORIGINAL_SCROLL_BY;
}
case "scrollTo":
if (element instanceof Element) {
if (ELEMENT_ORIGINAL_SCROLL_TO != null) {
return ELEMENT_ORIGINAL_SCROLL_TO;
}
else {
return elementPrototypeScrollToFallback;
}
}
else {
return WINDOW_ORIGINAL_SCROLL_TO;
}
}
}
/**
* Gets the Smooth Scroll Options to use for the step function

@@ -190,3 +271,3 @@ * @param {Element|Window} element

: y),
method: WINDOW_ORIGINAL_SCROLL_TO.bind(window)
method: getOriginalScrollMethodForKind("scrollTo", window).bind(window)
};

@@ -202,9 +283,9 @@ }

startY: startY,
endX: kind === "scrollBy"
endX: Math.floor(kind === "scrollBy"
? startX + x
: x,
endY: kind === "scrollBy"
: x),
endY: Math.floor(kind === "scrollBy"
? startY + y
: y,
method: ELEMENT_ORIGINAL_SCROLL_TO.bind(element)
: y),
method: getOriginalScrollMethodForKind("scrollTo", element).bind(element)
};

@@ -215,13 +296,2 @@ }

/**
* Gets the scrollLeft version of an element. If a window is provided, the 'pageXOffset' is used.
* @param {Element | Window} element
* @returns {number}
*/
function getScrollLeft(element) {
if (element instanceof Element)
return element.scrollLeft;
return element.pageXOffset;
}
/**
* Ensures that the given value is numeric

@@ -246,13 +316,2 @@ * @param {number} value

/**
* Gets the scrollTop version of an element. If a window is provided, the 'pageYOffset' is used.
* @param {Element | Window} element
* @returns {number}
*/
function getScrollTop(element) {
if (element instanceof Element)
return element.scrollTop;
return element.pageYOffset;
}
/**
* Returns true if the given value is some ScrollToOptions

@@ -266,6 +325,2 @@ * @param {number | ScrollToOptions} value

var WINDOW_ORIGINAL_SCROLL = window.scroll;
var WINDOW_ORIGINAL_SCROLL_BY = window.scrollBy;
/**

@@ -279,33 +334,5 @@ * Handles a scroll method

function handleScrollMethod(element, kind, optionsOrX, y) {
// If only one argument is given, and it isn't an options object, throw a TypeError
if (y === undefined && !isScrollToOptions(optionsOrX)) {
throw new TypeError("Failed to execute 'scroll' on 'Element': parameter 1 ('options') is not an object.");
}
// Scroll based on the primitive values given as arguments
if (!isScrollToOptions(optionsOrX)) {
var _a = normalizeScrollCoordinates(optionsOrX, y, element, kind), left = _a.left, top_1 = _a.top;
onScrollPrimitive(left, top_1, element, kind);
}
// Scroll based on the received options object
else {
onScrollWithOptions(__assign({}, normalizeScrollCoordinates(optionsOrX.left, optionsOrX.top, element, kind), { behavior: optionsOrX.behavior == null ? "auto" : optionsOrX.behavior }), element, kind);
}
onScrollWithOptions(getScrollToOptionsWithValidation(optionsOrX, y), element, kind);
}
/**
* Gets the original non-patched prototype method for the given kind
* @param {ScrollMethodName} kind
* @param {Element|Window} element
* @return {Function}
*/
function getOriginalPrototypeMethodForKind(kind, element) {
switch (kind) {
case "scroll":
return element instanceof Element ? ELEMENT_ORIGINAL_SCROLL : WINDOW_ORIGINAL_SCROLL;
case "scrollBy":
return element instanceof Element ? ELEMENT_ORIGINAL_SCROLL_BY : WINDOW_ORIGINAL_SCROLL_BY;
case "scrollTo":
return element instanceof Element ? ELEMENT_ORIGINAL_SCROLL_TO : WINDOW_ORIGINAL_SCROLL_TO;
}
}
/**
* Invoked when a 'ScrollToOptions' dict is provided to 'scroll()' as the first argument

@@ -320,3 +347,3 @@ * @param {ScrollToOptions} options

if (behavior == null || behavior === "auto") {
getOriginalPrototypeMethodForKind(kind, element).call(element, options.left, options.top);
getOriginalScrollMethodForKind(kind, element).call(element, options.left, options.top);
}

@@ -328,37 +355,32 @@ else {

/**
* Invoked when 'scroll()' is invoked with primitive x or y values
* @param {number} x
* @param {number} y
* @param {ScrollMethodName} kind
* @param {Element|Window} element
*/
function onScrollPrimitive(x, y, element, kind) {
// noinspection SuspiciousTypeOfGuard
return onScrollWithOptions({
left: x,
top: y,
behavior: "auto"
}, element, kind);
}
/**
* Normalizes the given scroll coordinates
* @param {number?} x
* @param {number?} y
* @param {Element|Window} element
* @param {ScrollMethodName} kind
* @return {Required<Pick<ScrollToOptions, "top" | "left">>}
*/
function normalizeScrollCoordinates(x, y, element, kind) {
switch (kind) {
case "scrollBy":
return {
left: getScrollLeft(element) + ensureNumeric(x),
top: getScrollTop(element) + ensureNumeric(y)
};
default:
return {
left: ensureNumeric(x),
top: ensureNumeric(y)
};
function normalizeScrollCoordinates(x, y) {
return {
left: ensureNumeric(x),
top: ensureNumeric(y)
};
}
/**
* Gets ScrollToOptions based on the given arguments. Will throw if validation fails
* @param {number | ScrollToOptions} optionsOrX
* @param {number} y
* @return {Required<ScrollToOptions>}
*/
function getScrollToOptionsWithValidation(optionsOrX, y) {
// If only one argument is given, and it isn't an options object, throw a TypeError
if (y === undefined && !isScrollToOptions(optionsOrX)) {
throw new TypeError("Failed to execute 'scroll' on 'Element': parameter 1 ('options') is not an object.");
}
// Scroll based on the primitive values given as arguments
if (!isScrollToOptions(optionsOrX)) {
return __assign({}, normalizeScrollCoordinates(optionsOrX, y), { behavior: "auto" });
}
// Scroll based on the received options object
else {
return __assign({}, normalizeScrollCoordinates(optionsOrX.left, optionsOrX.top), { behavior: optionsOrX.behavior == null ? "auto" : optionsOrX.behavior });
}
}

@@ -441,3 +463,25 @@

var scrollingElement = document.scrollingElement != null ? document.scrollingElement : document.documentElement;
/**
* Returns true if the given overflow property represents a scrollable overflow value
* @param {string | null} overflow
* @return {boolean}
*/
function canOverflow(overflow) {
return overflow !== "visible" && overflow !== "clip";
}
/**
* Returns true if the given element is scrollable
* @param {Element} element
* @return {boolean}
*/
function isScrollable(element) {
if (element.clientHeight < element.scrollHeight || element.clientWidth < element.scrollWidth) {
var style = getComputedStyle(element, null);
return (canOverflow(style.overflowY) ||
canOverflow(style.overflowX));
}
return false;
}
/**
* Finds the nearest ancestor of an element that can scroll

@@ -451,11 +495,19 @@ * @param {Element} target

var behavior = getScrollBehavior(currentElement);
if (behavior != null)
if (behavior != null && (currentElement === scrollingElement || isScrollable(currentElement))) {
return [currentElement, behavior];
}
var parent_1 = getParent(currentElement);
// If the last Node is equal to the latest parentNode, break immediately
if (parent_1 === currentElement)
break;
currentElement = parent_1;
}
return undefined;
// No such element could be found. Start over, but this time find the nearest ancestor that can simply scroll
currentElement = target;
while (currentElement != null) {
if (currentElement === scrollingElement || isScrollable(currentElement)) {
return [currentElement, "auto"];
}
var parent_2 = getParent(currentElement);
currentElement = parent_2;
}
// Default to the scrolling element
return [scrollingElement, "auto"];
}

@@ -504,12 +556,2 @@

return;
// Find the nearest ancestor that can be scrolled
var ancestorWithScrollBehaviorResult = findNearestAncestorsWithScrollBehavior(e.target);
// If there is none, don't proceed
if (ancestorWithScrollBehaviorResult == null)
return;
// Take the scroll behavior for that ancestor
var _a = __read(ancestorWithScrollBehaviorResult, 2), ancestorWithScrollBehavior = _a[0], behavior = _a[1];
// If the behavior isn't smooth, don't proceed
if (behavior !== "smooth")
return;
// Find the nearest root, whether it be a ShadowRoot or the document itself

@@ -524,2 +566,7 @@ var root = findNearestRoot(e.target);

return;
// Find the nearest ancestor that can be scrolled
var _a = __read(findNearestAncestorsWithScrollBehavior(elementMatch), 2), ancestorWithScrollBehavior = _a[0], behavior = _a[1];
// If the behavior isn't smooth, don't proceed
if (behavior !== "smooth")
return;
// Otherwise, first prevent the default action.

@@ -805,13 +852,17 @@ e.preventDefault();

// Find the nearest ancestor that can be scrolled
var ancestorWithScrollBehaviorResult = findNearestAncestorsWithScrollBehavior(this);
// If there is none, opt-out by calling the original implementation
if (ancestorWithScrollBehaviorResult == null) {
ELEMENT_ORIGINAL_SCROLL_INTO_VIEW.call(this, normalizedOptions);
return;
}
var _a = __read(ancestorWithScrollBehaviorResult, 2), ancestorWithScroll = _a[0], ancestorWithScrollBehavior = _a[1];
var behavior = normalizedOptions.behavior != null ? normalizedOptions.behavior : ancestorWithScrollBehavior;
var _a = __read(findNearestAncestorsWithScrollBehavior(this), 2), ancestorWithScroll = _a[0], ancestorWithScrollBehavior = _a[1];
var behavior = normalizedOptions.behavior != null
? normalizedOptions.behavior
: ancestorWithScrollBehavior;
// If the behavior isn't smooth, simply invoke the original implementation and do no more
if (behavior !== "smooth") {
ELEMENT_ORIGINAL_SCROLL_INTO_VIEW.call(this, normalizedOptions);
// Assert that 'scrollIntoView' is actually defined
if (ELEMENT_ORIGINAL_SCROLL_INTO_VIEW != null) {
ELEMENT_ORIGINAL_SCROLL_INTO_VIEW.call(this, normalizedOptions);
}
// Otherwise, invoke 'scrollTo' instead and provide the scroll coordinates
else {
var _b = computeScrollIntoView(this, ancestorWithScroll, normalizedOptions), top_1 = _b.top, left = _b.left;
getOriginalScrollMethodForKind("scrollTo", this).call(this, left, top_1);
}
return;

@@ -823,6 +874,41 @@ }

var ELEMENT_ORIGINAL_SCROLL_TOP_SET_DESCRIPTOR = Object.getOwnPropertyDescriptor(Element.prototype, "scrollTop").set;
/**
* Patches the 'scrollTop' property descriptor on the Element prototype
*/
function patchElementScrollTop() {
Object.defineProperty(Element.prototype, "scrollTop", {
set: function (scrollTop) {
if (this.__adjustingScrollPosition) {
return ELEMENT_ORIGINAL_SCROLL_TOP_SET_DESCRIPTOR.call(this, scrollTop);
}
handleScrollMethod(this, "scrollTo", this.scrollLeft, scrollTop);
return scrollTop;
}
});
}
var ELEMENT_ORIGINAL_SCROLL_LEFT_SET_DESCRIPTOR = Object.getOwnPropertyDescriptor(Element.prototype, "scrollLeft").set;
/**
* Patches the 'scrollLeft' property descriptor on the Element prototype
*/
function patchElementScrollLeft() {
Object.defineProperty(Element.prototype, "scrollLeft", {
set: function (scrollLeft) {
if (this.__adjustingScrollPosition) {
return ELEMENT_ORIGINAL_SCROLL_LEFT_SET_DESCRIPTOR.call(this, scrollLeft);
}
handleScrollMethod(this, "scrollTo", scrollLeft, this.scrollTop);
return scrollLeft;
}
});
}
/**
* Applies the polyfill
*/
function patch() {
// Element.prototype methods
patchElementScroll();

@@ -832,9 +918,20 @@ patchElementScrollBy();

patchElementScrollIntoView();
// Element.prototype descriptors
patchElementScrollLeft();
patchElementScrollTop();
// window methods
patchWindowScroll();
patchWindowScrollBy();
patchWindowScrollTo();
// Navigation
catchNavigation();
}
if (!SUPPORTS_SCROLL_BEHAVIOR) {
/**
* Is true if the browser natively supports the Element.prototype.[scroll|scrollTo|scrollBy|scrollIntoView] methods
* @type {boolean}
*/
var SUPPORTS_ELEMENT_PROTOTYPE_SCROLL_METHODS = "scroll" in Element.prototype && "scrollTo" in Element.prototype && "scrollBy" in Element.prototype && "scrollIntoView" in Element.prototype;
if (!SUPPORTS_SCROLL_BEHAVIOR || !SUPPORTS_ELEMENT_PROTOTYPE_SCROLL_METHODS) {
patch();

@@ -841,0 +938,0 @@ }

{
"name": "scroll-behavior-polyfill",
"version": "2.0.1",
"version": "2.0.3",
"description": "A polyfill for the 'scroll-behavior' CSS-property",

@@ -24,3 +24,3 @@ "repository": {

"prepare": "npm run rollup",
"publish:before": "NODE_ENV=production npm run lint && NODE_ENV=production npm run prepare && npm run generate:all && git add . && git commit -am \"Bumped version\" || true",
"publish:before": "NODE_ENV=production npm run lint && NODE_ENV=production npm run prepare && npm run generate:all && git add . && (git commit -am \"Bumped version\" && git push) || true",
"publish:after": "git push && npm publish",

@@ -27,0 +27,0 @@ "publish:patch": "npm run publish:before && npm version patch && npm run publish:after",

@@ -10,8 +10,13 @@ <a href="https://npmcharts.com/compare/scroll-behavior-polyfill?minimal=true"><img alt="Downloads per month" src="https://img.shields.io/npm/dm/scroll-behavior-polyfill.svg" height="20"></img></a>

> A polyfill for the [`scroll-behavior`](https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-behavior) CSS-property
> A polyfill for the [`scroll-behavior`](https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-behavior) CSS-property as well as the extensions to the Element interface in the [CSSOM View Module](https://drafts.csswg.org/cssom-view/#dom-element-scrollto-options-options)
## Description
The scroll-behavior CSS property sets the behavior for a scrolling box when scrolling is triggered by the navigation or CSSOM scrolling APIs.
The `scroll-behavior` CSS property sets the behavior for a scrolling box when scrolling is triggered by the navigation or CSSOM scrolling APIs.
This polyfill brings this new feature to all browsers.
It is very efficient, tiny, and works with the latest browser technologies such as Shadow DOM.
This polyfill also implements the extensions to the Element interface in the [CSSOM View Module](https://drafts.csswg.org/cssom-view/#dom-element-scrollto-options-options) such as `Element.prototype.scroll`, `Element.prototype.scrollTo`, `Element.protype.scrollBy`, and `Element.prototype.scrollIntoView`.
## Install

@@ -68,7 +73,7 @@

<div scroll-behavior="smooth"></div>
```
```typescript
// Works jut fine when given as a style property
element.style.scrollBehavior = "smooth";
<script>
// Works jut fine when given as a style property
element.style.scrollBehavior = "smooth";
</script>
```

@@ -102,2 +107,9 @@

You can also use the `scrollTop` and `scrollLeft` setters, both of which works with the polyfill too:
```typescript
element.scrollTop += 100;
element.scrollLeft += 50;
```
## Dependencies & Browser support

@@ -108,3 +120,2 @@

- `requestAnimationFrame`
- `Element.prototype.scrollIntoView`

@@ -126,3 +137,2 @@ For by far the most browsers, these features will already be natively available.

- You cannot set `scrollLeft` or `scrollTop`. There is no way to overwrite the property descriptors for those operations. Instead, use `scroll()`, `scrollTo` or `scrollBy` which does the exact same thing.
- `scroll-behavior` properties declared only in stylesheets won't be discovered. This is because [polyfilling CSS is hard and really bad for performance](https://philipwalton.com/articles/the-dark-side-of-polyfilling-css/).

@@ -129,0 +139,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc