{"ast":null,"code":"import { __assign, __decorate } from \"tslib\";\nimport clamp from 'lodash-es/clamp';\nimport { Options } from './options';\nimport { setStyle, clearEventsOn } from './utils/';\nimport { debounce } from './decorators/';\nimport { TrackController } from './track/';\nimport { getSize, update, isVisible } from './geometry/';\nimport { scrollTo, setPosition, scrollIntoView } from './scrolling/';\nimport { initPlugins } from './plugin';\nimport * as eventHandlers from './events/'; // DO NOT use WeakMap here\n// .getAll() methods requires `scrollbarMap.values()`\n\nexport var scrollbarMap = new Map();\n\nvar Scrollbar =\n/** @class */\nfunction () {\n function Scrollbar(containerEl, options) {\n var _this = this;\n /**\n * Current scrolling offsets\n */\n\n\n this.offset = {\n x: 0,\n y: 0\n };\n /**\n * Max-allowed scrolling offsets\n */\n\n this.limit = {\n x: Infinity,\n y: Infinity\n };\n /**\n * Container bounding rect\n */\n\n this.bounding = {\n top: 0,\n right: 0,\n bottom: 0,\n left: 0\n };\n this._plugins = [];\n this._momentum = {\n x: 0,\n y: 0\n };\n this._listeners = new Set();\n this.containerEl = containerEl;\n var contentEl = this.contentEl = document.createElement('div');\n this.options = new Options(options); // mark as a scroll element\n\n containerEl.setAttribute('data-scrollbar', 'true'); // make container focusable\n\n containerEl.setAttribute('tabindex', '-1');\n setStyle(containerEl, {\n overflow: 'hidden',\n outline: 'none'\n }); // enable touch event capturing in IE, see:\n // https://github.com/idiotWu/smooth-scrollbar/issues/39\n\n if (window.navigator.msPointerEnabled) {\n containerEl.style.msTouchAction = 'none';\n } // mount content\n\n\n contentEl.className = 'scroll-content';\n Array.from(containerEl.childNodes).forEach(function (node) {\n contentEl.appendChild(node);\n });\n containerEl.appendChild(contentEl); // attach track\n\n this.track = new TrackController(this); // initial measuring\n\n this.size = this.getSize(); // init plugins\n\n this._plugins = initPlugins(this, this.options.plugins); // preserve scroll offset\n\n var scrollLeft = containerEl.scrollLeft,\n scrollTop = containerEl.scrollTop;\n containerEl.scrollLeft = containerEl.scrollTop = 0;\n this.setPosition(scrollLeft, scrollTop, {\n withoutCallbacks: true\n });\n var global = window;\n var MutationObserver = global.MutationObserver || global.WebKitMutationObserver || global.MozMutationObserver; // observe\n\n if (typeof MutationObserver === 'function') {\n this._observer = new MutationObserver(function () {\n _this.update();\n });\n\n this._observer.observe(contentEl, {\n subtree: true,\n childList: true\n });\n }\n\n scrollbarMap.set(containerEl, this); // wait for DOM ready\n\n requestAnimationFrame(function () {\n _this._init();\n });\n }\n\n Object.defineProperty(Scrollbar.prototype, \"parent\", {\n /**\n * Parent scrollbar\n */\n get: function get() {\n var elem = this.containerEl.parentElement;\n\n while (elem) {\n var parentScrollbar = scrollbarMap.get(elem);\n\n if (parentScrollbar) {\n return parentScrollbar;\n }\n\n elem = elem.parentElement;\n }\n\n return null;\n },\n enumerable: true,\n configurable: true\n });\n Object.defineProperty(Scrollbar.prototype, \"scrollTop\", {\n /**\n * Gets or sets `scrollbar.offset.y`\n */\n get: function get() {\n return this.offset.y;\n },\n set: function set(y) {\n this.setPosition(this.scrollLeft, y);\n },\n enumerable: true,\n configurable: true\n });\n Object.defineProperty(Scrollbar.prototype, \"scrollLeft\", {\n /**\n * Gets or sets `scrollbar.offset.x`\n */\n get: function get() {\n return this.offset.x;\n },\n set: function set(x) {\n this.setPosition(x, this.scrollTop);\n },\n enumerable: true,\n configurable: true\n });\n /**\n * Returns the size of the scrollbar container element\n * and the content wrapper element\n */\n\n Scrollbar.prototype.getSize = function () {\n return getSize(this);\n };\n /**\n * Forces scrollbar to update geometry infomation.\n *\n * By default, scrollbars are automatically updated with `100ms` debounce (or `MutationObserver` fires).\n * You can call this method to force an update when you modified contents\n */\n\n\n Scrollbar.prototype.update = function () {\n update(this);\n\n this._plugins.forEach(function (plugin) {\n plugin.onUpdate();\n });\n };\n /**\n * Checks if an element is visible in the current view area\n */\n\n\n Scrollbar.prototype.isVisible = function (elem) {\n return isVisible(this, elem);\n };\n /**\n * Sets the scrollbar to the given offset without easing\n */\n\n\n Scrollbar.prototype.setPosition = function (x, y, options) {\n var _this = this;\n\n if (x === void 0) {\n x = this.offset.x;\n }\n\n if (y === void 0) {\n y = this.offset.y;\n }\n\n if (options === void 0) {\n options = {};\n }\n\n var status = setPosition(this, x, y);\n\n if (!status || options.withoutCallbacks) {\n return;\n }\n\n this._listeners.forEach(function (fn) {\n fn.call(_this, status);\n });\n };\n /**\n * Scrolls to given position with easing function\n */\n\n\n Scrollbar.prototype.scrollTo = function (x, y, duration, options) {\n if (x === void 0) {\n x = this.offset.x;\n }\n\n if (y === void 0) {\n y = this.offset.y;\n }\n\n if (duration === void 0) {\n duration = 0;\n }\n\n if (options === void 0) {\n options = {};\n }\n\n scrollTo(this, x, y, duration, options);\n };\n /**\n * Scrolls the target element into visible area of scrollbar,\n * likes the DOM method `element.scrollIntoView().\n */\n\n\n Scrollbar.prototype.scrollIntoView = function (elem, options) {\n if (options === void 0) {\n options = {};\n }\n\n scrollIntoView(this, elem, options);\n };\n /**\n * Adds scrolling listener\n */\n\n\n Scrollbar.prototype.addListener = function (fn) {\n if (typeof fn !== 'function') {\n throw new TypeError('[smooth-scrollbar] scrolling listener should be a function');\n }\n\n this._listeners.add(fn);\n };\n /**\n * Removes listener previously registered with `scrollbar.addListener()`\n */\n\n\n Scrollbar.prototype.removeListener = function (fn) {\n this._listeners.delete(fn);\n };\n /**\n * Adds momentum and applys delta transformers.\n */\n\n\n Scrollbar.prototype.addTransformableMomentum = function (x, y, fromEvent, callback) {\n this._updateDebounced();\n\n var finalDelta = this._plugins.reduce(function (delta, plugin) {\n return plugin.transformDelta(delta, fromEvent) || delta;\n }, {\n x: x,\n y: y\n });\n\n var willScroll = !this._shouldPropagateMomentum(finalDelta.x, finalDelta.y);\n\n if (willScroll) {\n this.addMomentum(finalDelta.x, finalDelta.y);\n }\n\n if (callback) {\n callback.call(this, willScroll);\n }\n };\n /**\n * Increases scrollbar's momentum\n */\n\n\n Scrollbar.prototype.addMomentum = function (x, y) {\n this.setMomentum(this._momentum.x + x, this._momentum.y + y);\n };\n /**\n * Sets scrollbar's momentum to given value\n */\n\n\n Scrollbar.prototype.setMomentum = function (x, y) {\n if (this.limit.x === 0) {\n x = 0;\n }\n\n if (this.limit.y === 0) {\n y = 0;\n }\n\n if (this.options.renderByPixels) {\n x = Math.round(x);\n y = Math.round(y);\n }\n\n this._momentum.x = x;\n this._momentum.y = y;\n };\n /**\n * Update options for specific plugin\n *\n * @param pluginName Name of the plugin\n * @param [options] An object includes the properties that you want to update\n */\n\n\n Scrollbar.prototype.updatePluginOptions = function (pluginName, options) {\n this._plugins.forEach(function (plugin) {\n if (plugin.name === pluginName) {\n Object.assign(plugin.options, options);\n }\n });\n };\n\n Scrollbar.prototype.destroy = function () {\n var _a = this,\n containerEl = _a.containerEl,\n contentEl = _a.contentEl;\n\n clearEventsOn(this);\n\n this._listeners.clear();\n\n this.setMomentum(0, 0);\n cancelAnimationFrame(this._renderID);\n\n if (this._observer) {\n this._observer.disconnect();\n }\n\n scrollbarMap.delete(this.containerEl); // restore contents\n\n var childNodes = Array.from(contentEl.childNodes);\n\n while (containerEl.firstChild) {\n containerEl.removeChild(containerEl.firstChild);\n }\n\n childNodes.forEach(function (el) {\n containerEl.appendChild(el);\n }); // reset scroll position\n\n setStyle(containerEl, {\n overflow: ''\n });\n containerEl.scrollTop = this.scrollTop;\n containerEl.scrollLeft = this.scrollLeft; // invoke plugin.onDestroy\n\n this._plugins.forEach(function (plugin) {\n plugin.onDestroy();\n });\n\n this._plugins.length = 0;\n };\n\n Scrollbar.prototype._init = function () {\n var _this = this;\n\n this.update(); // init evet handlers\n\n Object.keys(eventHandlers).forEach(function (prop) {\n eventHandlers[prop](_this);\n }); // invoke `plugin.onInit`\n\n this._plugins.forEach(function (plugin) {\n plugin.onInit();\n });\n\n this._render();\n };\n\n Scrollbar.prototype._updateDebounced = function () {\n this.update();\n }; // check whether to propagate monmentum to parent scrollbar\n // the following situations are considered as `true`:\n // 1. continuous scrolling is enabled (automatically disabled when overscroll is enabled)\n // 2. scrollbar reaches one side and is not about to scroll on the other direction\n\n\n Scrollbar.prototype._shouldPropagateMomentum = function (deltaX, deltaY) {\n if (deltaX === void 0) {\n deltaX = 0;\n }\n\n if (deltaY === void 0) {\n deltaY = 0;\n }\n\n var _a = this,\n options = _a.options,\n offset = _a.offset,\n limit = _a.limit;\n\n if (!options.continuousScrolling) return false; // force an update when scrollbar is \"unscrollable\", see #106\n\n if (limit.x === 0 && limit.y === 0) {\n this._updateDebounced();\n }\n\n var destX = clamp(deltaX + offset.x, 0, limit.x);\n var destY = clamp(deltaY + offset.y, 0, limit.y);\n var res = true; // offsets are not about to change\n // `&=` operator is not allowed for boolean types\n\n res = res && destX === offset.x;\n res = res && destY === offset.y; // current offsets are on the edge\n\n res = res && (offset.x === limit.x || offset.x === 0 || offset.y === limit.y || offset.y === 0);\n return res;\n };\n\n Scrollbar.prototype._render = function () {\n var _momentum = this._momentum;\n\n if (_momentum.x || _momentum.y) {\n var nextX = this._nextTick('x');\n\n var nextY = this._nextTick('y');\n\n _momentum.x = nextX.momentum;\n _momentum.y = nextY.momentum;\n this.setPosition(nextX.position, nextY.position);\n }\n\n var remain = __assign({}, this._momentum);\n\n this._plugins.forEach(function (plugin) {\n plugin.onRender(remain);\n });\n\n this._renderID = requestAnimationFrame(this._render.bind(this));\n };\n\n Scrollbar.prototype._nextTick = function (direction) {\n var _a = this,\n options = _a.options,\n offset = _a.offset,\n _momentum = _a._momentum;\n\n var current = offset[direction];\n var remain = _momentum[direction];\n\n if (Math.abs(remain) <= 0.1) {\n return {\n momentum: 0,\n position: current + remain\n };\n }\n\n var nextMomentum = remain * (1 - options.damping);\n\n if (options.renderByPixels) {\n nextMomentum |= 0;\n }\n\n return {\n momentum: nextMomentum,\n position: current + remain - nextMomentum\n };\n };\n\n __decorate([debounce(100, {\n leading: true\n })], Scrollbar.prototype, \"_updateDebounced\", null);\n\n return Scrollbar;\n}();\n\nexport { Scrollbar };","map":null,"metadata":{},"sourceType":"module"}