UNPKG

scroll-into-view-if-needed

Version:

Element.scrollIntoViewIfNeeded ponyfill that can animate the scrolling

71 lines (70 loc) 3.07 kB
import animate from 'amator'; export default function scrollIntoViewIfNeeded(elem, centerIfNeeded, options, finalElement, config) { if (config === void 0) { config = {}; } if (!elem || !(elem instanceof HTMLElement)) throw new Error('Element is required in scrollIntoViewIfNeeded'); function withinBounds(value, min, max, extent) { if (false === centerIfNeeded || (max <= value + extent && value <= min + extent)) { return Math.min(max, Math.max(min, value)); } else { return (min + max) / 2; } } var offsetTop = config.offsetTop || 0; var offsetLeft = config.offsetLeft || 0; var offsetBottom = config.offsetBottom || 0; var offsetRight = config.offsetRight || 0; function makeArea(left, top, width, height) { return { left: left + offsetLeft, top: top + offsetTop, width: width, height: height, right: left + offsetLeft + width + offsetRight, bottom: top + offsetTop + height + offsetBottom, translate: function (x, y) { return makeArea(x + left + offsetLeft, y + top + offsetTop, width, height); }, relativeFromTo: function (lhs, rhs) { var newLeft = left + offsetLeft, newTop = top + offsetTop; lhs = lhs.offsetParent; rhs = rhs.offsetParent; if (lhs === rhs) { return area; } for (; lhs; lhs = lhs.offsetParent) { newLeft += lhs.offsetLeft + lhs.clientLeft; newTop += lhs.offsetTop + lhs.clientTop; } for (; rhs; rhs = rhs.offsetParent) { newLeft -= rhs.offsetLeft + rhs.clientLeft; newTop -= rhs.offsetTop + rhs.clientTop; } return makeArea(newLeft, newTop, width, height); }, }; } var parent, area = makeArea(elem.offsetLeft, elem.offsetTop, elem.offsetWidth, elem.offsetHeight); while ((parent = elem.parentNode) instanceof HTMLElement && elem !== finalElement) { var clientLeft = parent.offsetLeft + parent.clientLeft; var clientTop = parent.offsetTop + parent.clientTop; area = area.relativeFromTo(elem, parent).translate(-clientLeft, -clientTop); var scrollLeft = withinBounds(parent.scrollLeft, area.right - parent.clientWidth, area.left, parent.clientWidth); var scrollTop = withinBounds(parent.scrollTop, area.bottom - parent.clientHeight, area.top, parent.clientHeight); if (options) { animate(parent, { scrollLeft: scrollLeft, scrollTop: scrollTop, }, options); } else { parent.scrollLeft = scrollLeft; parent.scrollTop = scrollTop; } area = area.translate(clientLeft - parent.scrollLeft, clientTop - parent.scrollTop); elem = parent; } }