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

dynamic-marquee

Package Overview
Dependencies
Maintainers
1
Versions
44
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

dynamic-marquee - npm Package Compare versions

Comparing version 2.2.0 to 2.3.0

19

dist/dynamic-marquee.d.ts

@@ -11,6 +11,19 @@ export as namespace DynamicMarquee;

export class Marquee {
export type AppendItemConfig<TMetadata> = {
metadata?: TMetadata;
};
export type Touching<TMetadata> = {
$el: HTMLElement;
metadata: TMetadata;
};
export class Marquee<TMetadata = null> {
constructor($container: HTMLElement, options?: Options);
onItemRequired(
callback: (data: { immediatelyFollowsPrevious: boolean }) => Item | void
callback: (data: {
/** @deprecated use `touching !== null` instead */
immediatelyFollowsPrevious: boolean;
touching: Touching<TMetadata>;
}) => Item | void
): void;

@@ -24,3 +37,3 @@ onItemRemoved(callback: ($el: HTMLElement) => void): void;

isWaitingForItem(): boolean;
appendItem($el: Item): void;
appendItem($el: Item, config?: AppendItemConfig<TMetadata>): void;
}

@@ -27,0 +40,0 @@

1280

dist/dynamic-marquee.js
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined'
? factory(exports)
: typeof define === 'function' && define.amd
? define(['exports'], factory)
: ((global =
typeof globalThis !== 'undefined' ? globalThis : global || self),
factory((global.dynamicMarquee = {})));
})(this, function (exports) {
'use strict';
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.dynamicMarquee = {}));
})(this, (function (exports) { 'use strict';
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError('Cannot call a class as a function');
throw new TypeError("Cannot call a class as a function");
}

@@ -23,3 +18,3 @@ }

descriptor.configurable = true;
if ('value' in descriptor) descriptor.writable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);

@@ -32,4 +27,4 @@ }

if (staticProps) _defineProperties(Constructor, staticProps);
Object.defineProperty(Constructor, 'prototype', {
writable: false,
Object.defineProperty(Constructor, "prototype", {
writable: false
});

@@ -39,11 +34,161 @@ return Constructor;

function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) return _arrayLikeToArray(arr);
}
function _iterableToArray(iter) {
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
/**
* A boundary represents everything below a given point in the call stack.
*
* It can have an `onEnter` function which is called on entry and an `onExit`
* function which is called on exit.
*
* To enter the boundry call `enter` with the function you want to run inside
* it. On the first call to `enter` in the current stack `onEnter` will be
* called before the provided function and `onExit` will be called after it.
*
* Nested `enter` calls will be called immediately.
*
* The function provided to `enter` will receive the return value from `onEnter`
* as the first argument. This will be `undefined` if the `onEnter` function is still
* executing.
*
* `onExit` will receive the the return value from `onEnter` and also the exception
* if one is thrown from an `enter` call. It can choose to handle it, or leave it
* to be rethrown.
*/
var Boundary = /** @class */ (function () {
/**
* Takes an object with the following properties:
* - onEnter (optional): A function that is called immediately before the boundary
* is entered. It must not call `enter` on the boundary.
* - onExit (optional): A function that is called immediately after leaving the
* boundary. It receives an object that contains the following
* properties:
* - onEnterResult: The return value from `onEnter`. This will be
* `undefined` if `onEnter` threw an exception.
* - exceptionOccurred: `true` if an exception occured inside
* the boundary.
* - retrieveException: A function that returns the exception
* that occurred. Calling this will prevent
* the exception being thrown from `enter()`.
* Rethrow it if you don't want to handle it
* yourself.
* If an exception occurs inside the boundary this will still
* be called, and the exception will be rethrown, unless you call
* `retrieveException`.
*/
function Boundary(_a) {
var onEnter = _a.onEnter, onExit = _a.onExit;
this._execution = null;
this.inBoundary = this.inBoundary.bind(this);
this.enter = this.enter.bind(this);
this._onEnter = onEnter || null;
this._onExit = onExit || null;
}
/**
* Returns `true` if called from within the boundary. This includes the `onEnter`
* callback.
*/
Boundary.prototype.inBoundary = function () {
return !!this._execution;
};
Boundary.prototype.enter = function (fn) {
if (this._execution) {
return fn ? fn(this._execution.onEnterResult) : undefined;
}
var execution = (this._execution = {
onEnterResult: undefined,
});
var returnVal = undefined;
var exceptionOccurred = false;
var exception = undefined;
try {
if (this._onEnter) {
execution.onEnterResult = this._onEnter();
}
if (fn) {
returnVal = fn(execution.onEnterResult);
}
}
catch (e) {
exceptionOccurred = true;
exception = e;
}
this._execution = null;
var exceptionHandled = !exceptionOccurred;
if (this._onExit) {
try {
this._onExit({
onEnterResult: execution.onEnterResult,
exceptionOccurred: exceptionOccurred,
retrieveException: function () {
exceptionHandled = true;
return exception;
},
});
}
catch (e) {
if (exceptionHandled) {
// if an error occured before onExit prioritise that one
// (similar to how `finally` works)
throw e;
}
}
}
if (!exceptionHandled) {
throw exception;
}
return returnVal;
};
return Boundary;
}());
var DIRECTION = {
RIGHT: 'right',
DOWN: 'down',
DOWN: 'down'
};
var SizeWatcher = /*#__PURE__*/ (function () {
var PX_REGEX = /px$/;
function pxStringToValue(input) {
if (!PX_REGEX.test(input)) {
throw new Error('String missing `px` suffix');
}
return parseFloat(input.slice(0, -2));
}
var SizeWatcher = /*#__PURE__*/function () {
function SizeWatcher($el) {
var _this = this,
_this$_observer;
_this$_observer;

@@ -55,58 +200,44 @@ _classCallCheck(this, SizeWatcher);

this._height = null;
this._observer =
'ResizeObserver' in window
? new ResizeObserver(function (entries) {
var entry = entries[entries.length - 1];
var size = entry.borderBoxSize[0] || entry.borderBoxSize;
_this._width = size.inlineSize;
_this._height = size.blockSize;
})
: null;
(_this$_observer = this._observer) === null || _this$_observer === void 0
? void 0
: _this$_observer.observe($el);
this._observer = 'ResizeObserver' in window ? new ResizeObserver(function (entries) {
var entry = entries[entries.length - 1];
var size = entry.borderBoxSize[0] || entry.borderBoxSize;
_this._width = size.inlineSize;
_this._height = size.blockSize;
}) : null;
(_this$_observer = this._observer) === null || _this$_observer === void 0 ? void 0 : _this$_observer.observe($el);
}
_createClass(SizeWatcher, [
{
key: 'getWidth',
value: function getWidth() {
var _this$_width;
_createClass(SizeWatcher, [{
key: "getWidth",
value: function getWidth() {
if (this._width !== null) return this._width; // maps to `inlineSize`
return (_this$_width = this._width) !== null &&
_this$_width !== void 0
? _this$_width
: this._$el.offsetWidth;
},
},
{
key: 'getHeight',
value: function getHeight() {
var _this$_height;
var width = pxStringToValue(window.getComputedStyle(this._$el).width);
if (this._observer) this._width = width;
return width;
}
}, {
key: "getHeight",
value: function getHeight() {
if (this._height !== null) return this._height; // maps to `blockSize`
return (_this$_height = this._height) !== null &&
_this$_height !== void 0
? _this$_height
: this._$el.offsetHeight;
},
},
{
key: 'tearDown',
value: function tearDown() {
var _this$_observer2;
var height = pxStringToValue(window.getComputedStyle(this._$el).height);
if (this._observer) this._height = height;
return height;
}
}, {
key: "tearDown",
value: function tearDown() {
var _this$_observer2;
(_this$_observer2 = this._observer) === null ||
_this$_observer2 === void 0
? void 0
: _this$_observer2.disconnect();
},
},
]);
(_this$_observer2 = this._observer) === null || _this$_observer2 === void 0 ? void 0 : _this$_observer2.disconnect();
this._observer = null;
}
}]);
return SizeWatcher;
})();
}();
var transitionDuration = 60000;
var Item = /*#__PURE__*/ (function () {
function Item($el, direction) {
var Item = /*#__PURE__*/function () {
function Item($el, direction, metadata) {
_classCallCheck(this, Item);

@@ -116,2 +247,3 @@

$container.style.display = 'block';
$container.style.opacity = '0';
$container.style.position = 'absolute';

@@ -125,3 +257,2 @@ $container.style.margin = '0';

$container.style.willChange = 'auto';
this._sizeWatcher = new SizeWatcher($container);

@@ -132,156 +263,119 @@ $container.appendChild($el);

this._direction = direction;
this._transitionState = null;
this._metadata = metadata;
this._offset = null;
}
_createClass(Item, [
{
key: 'getSize',
value: function getSize() {
var _ref =
arguments.length > 0 && arguments[0] !== undefined
? arguments[0]
: {},
_createClass(Item, [{
key: "getSize",
value: function getSize() {
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
_ref$inverse = _ref.inverse,
inverse = _ref$inverse === void 0 ? false : _ref$inverse;
var dir = this._direction;
var dir = this._direction;
if (inverse) {
dir = dir === DIRECTION.RIGHT ? DIRECTION.DOWN : DIRECTION.RIGHT;
}
if (inverse) {
dir = dir === DIRECTION.RIGHT ? DIRECTION.DOWN : DIRECTION.RIGHT;
}
return dir === DIRECTION.RIGHT
? this._sizeWatcher.getWidth()
: this._sizeWatcher.getHeight();
},
},
{
key: 'setOffset',
value: function setOffset(offset, rate, force) {
var transitionState = this._transitionState;
var rateChanged = !transitionState || transitionState.rate !== rate;
return dir === DIRECTION.RIGHT ? this._sizeWatcher.getWidth() : this._sizeWatcher.getHeight();
}
}, {
key: "setOffset",
value: function setOffset(offset) {
if (this._offset === offset) return;
this._offset = offset;
this._$container.style.opacity = '1';
if (transitionState && !force) {
var timePassed = performance.now() - transitionState.time;
if (this._direction === DIRECTION.RIGHT) {
this._$container.style.left = "".concat(offset, "px");
} else {
this._$container.style.top = "".concat(offset, "px");
}
}
}, {
key: "remove",
value: function remove() {
this._sizeWatcher.tearDown();
if (timePassed < transitionDuration - 10000 && !rateChanged) {
return;
}
}
this._$container.parentNode.removeChild(this._$container);
}
}, {
key: "getContainer",
value: function getContainer() {
return this._$container;
}
}, {
key: "getOriginalEl",
value: function getOriginalEl() {
return this._$el;
}
}, {
key: "getMetadata",
value: function getMetadata() {
return this._metadata;
}
}]);
if (force || rateChanged) {
if (this._direction === DIRECTION.RIGHT) {
this._$container.style.transform = 'translateX('.concat(
offset,
'px)'
);
} else {
this._$container.style.transform = 'translateY('.concat(
offset,
'px)'
);
}
return Item;
}();
this._$container.style.transition = '';
this._$container.offsetLeft;
var transitionDuration = 30000;
var Slider = /*#__PURE__*/function () {
function Slider($el, direction) {
_classCallCheck(this, Slider);
this._$el = $el;
this._direction = direction;
this._transitionState = null;
}
_createClass(Slider, [{
key: "setOffset",
value: function setOffset(offset, rate, force) {
var transitionState = this._transitionState;
var rateChanged = !transitionState || transitionState.rate !== rate;
if (transitionState && !force) {
var timePassed = performance.now() - transitionState.time;
if (timePassed < transitionDuration - 10000 && !rateChanged) {
return;
}
}
var futureOffset = offset + (rate / 1000) * transitionDuration;
if (force || rateChanged) {
if (this._direction === DIRECTION.RIGHT) {
this._$container.style.transform = 'translateX('.concat(
futureOffset,
'px)'
);
this._$el.style.transform = "translateX(".concat(offset, "px)");
} else {
this._$container.style.transform = 'translateY('.concat(
futureOffset,
'px)'
);
this._$el.style.transform = "translateY(".concat(offset, "px)");
}
if (rate) {
this._$container.style.transition = 'transform '.concat(
transitionDuration,
'ms linear'
);
}
this._$el.style.transition = 'none';
this._$el.offsetLeft;
}
this._transitionState = {
time: performance.now(),
rate: rate,
};
},
},
{
key: 'enableAnimationHint',
value: function enableAnimationHint(enable) {
this._$container.style.willChange = enable ? 'transform' : 'auto';
},
},
{
key: 'remove',
value: function remove() {
this._sizeWatcher.tearDown();
if (rate && (force || rateChanged)) {
this._$el.style.transition = "transform ".concat(transitionDuration, "ms linear");
}
this._$container.parentNode.removeChild(this._$container);
},
},
{
key: 'getContainer',
value: function getContainer() {
return this._$container;
},
},
{
key: 'getOriginalEl',
value: function getOriginalEl() {
return this._$el;
},
},
]);
if (rate) {
var futureOffset = offset + rate / 1000 * transitionDuration;
return Item;
})();
var VirtualItem = /*#__PURE__*/ (function () {
function VirtualItem(size) {
_classCallCheck(this, VirtualItem);
this._size = size;
}
_createClass(VirtualItem, [
{
key: 'getSize',
value: function getSize() {
var _ref2 =
arguments.length > 0 && arguments[0] !== undefined
? arguments[0]
: {},
_ref2$inverse = _ref2.inverse,
inverse = _ref2$inverse === void 0 ? false : _ref2$inverse;
if (inverse) {
throw new Error('Inverse not supported on virtual item.');
if (this._direction === DIRECTION.RIGHT) {
this._$el.style.transform = "translateX(".concat(futureOffset, "px)");
} else {
this._$el.style.transform = "translateY(".concat(futureOffset, "px)");
}
}
return this._size;
},
},
{
key: 'setOffset',
value: function setOffset() {},
},
{
key: 'enableAnimationHint',
value: function enableAnimationHint() {},
},
{
key: 'remove',
value: function remove() {},
},
]);
this._transitionState = {
time: performance.now(),
rate: rate
};
}
}]);
return VirtualItem;
})();
return Slider;
}();

@@ -312,27 +406,56 @@ function defer(fn) {

}
function last(input) {
return input.length ? input[input.length - 1] : null;
}
function first(input) {
return input.length ? input[0] : null;
}
var Marquee = /*#__PURE__*/ (function () {
var maxTranslateDistance = 500000;
var renderInterval = 100;
var Marquee = /*#__PURE__*/function () {
function Marquee($container) {
var _ref =
arguments.length > 1 && arguments[1] !== undefined
? arguments[1]
: {},
_ref$rate = _ref.rate,
rate = _ref$rate === void 0 ? -25 : _ref$rate,
_ref$upDown = _ref.upDown,
upDown = _ref$upDown === void 0 ? false : _ref$upDown,
_ref$startOnScreen = _ref.startOnScreen,
startOnScreen =
_ref$startOnScreen === void 0 ? false : _ref$startOnScreen;
var _this = this;
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
_ref$rate = _ref.rate,
rate = _ref$rate === void 0 ? -25 : _ref$rate,
_ref$upDown = _ref.upDown,
upDown = _ref$upDown === void 0 ? false : _ref$upDown,
_ref$startOnScreen = _ref.startOnScreen,
startOnScreen = _ref$startOnScreen === void 0 ? false : _ref$startOnScreen;
_classCallCheck(this, Marquee);
this._rendering = false;
this._boundary = new Boundary({
onEnter: function onEnter() {
return {
allItemsRemoved: false,
callbacks: []
};
},
onExit: function onExit(_ref2) {
var _ref2$onEnterResult = _ref2.onEnterResult,
callbacks = _ref2$onEnterResult.callbacks,
allItemsRemoved = _ref2$onEnterResult.allItemsRemoved;
if (allItemsRemoved) {
_this._onAllItemsRemoved.forEach(function (cb) {
return callbacks.push(cb);
});
}
callbacks.forEach(function (cb) {
return defer(function () {
return cb();
});
});
}
});
this._waitingForItem = true;
this._nextItemImmediatelyFollowsPrevious = startOnScreen;
this._nextItemWouldBeTouching = startOnScreen;
this._rate = rate;
this._lastRate = 0;
this._lastEffectiveRate = rate;
this._justReversedRate = false;
this._lastUpdateTime = null;
this._correlation = null;
this._direction = upDown ? DIRECTION.DOWN : DIRECTION.RIGHT;

@@ -342,133 +465,130 @@ this._onItemRequired = [];

this._onAllItemsRemoved = [];
this._leftItemOffset = 0;
this._windowOffset = 0;
this._containerSize = 0;
this._previousContainerSize = null;
this._containerSizeWatcher = null;
this._items = [];
this._pendingItem = null;
var $innerContainer = document.createElement('div');
$innerContainer.style.position = 'relative';
$innerContainer.style.display = 'inline-block';
this._$container = $innerContainer;
this._containerInverseSize = null;
$innerContainer.style.width = '100%';
var $window = document.createElement('div');
$window.style.display = 'block';
$window.style.overflow = 'hidden';
if (this._direction === DIRECTION.DOWN) {
$innerContainer.style.height = '100%';
$window.style.height = '100%';
}
this._updateContainerInverseSize();
this._$window = $window;
this.windowInverseSize = null;
$container.appendChild($innerContainer);
this._updateWindowInverseSize();
var $moving = document.createElement('div');
this._$moving = $moving;
$moving.style.display = 'block';
$moving.style.position = 'absolute';
$moving.style.left = '0';
$moving.style.right = '0';
this._slider = new Slider($moving, this._direction);
$window.appendChild($moving);
$container.appendChild($window);
} // called when there's room for a new item.
// You can return the item to append next
_createClass(Marquee, [
{
key: 'onItemRequired',
value: function onItemRequired(cb) {
this._onItemRequired.push(cb);
}, // Called when an item is removed
},
{
key: 'onItemRemoved',
value: function onItemRemoved(cb) {
this._onItemRemoved.push(cb);
}, // Called when the last item is removed
},
{
key: 'onAllItemsRemoved',
value: function onAllItemsRemoved(cb) {
this._onAllItemsRemoved.push(cb);
},
},
{
key: 'getNumItems',
value: function getNumItems() {
return this._items.filter(function (_ref2) {
var item = _ref2.item;
return item instanceof Item;
}).length;
},
},
{
key: 'setRate',
value: function setRate(rate) {
if (rate === this._rate) {
return;
}
if (!rate !== !this._rate) {
this._enableAnimationHint(!!rate);
_createClass(Marquee, [{
key: "onItemRequired",
value: function onItemRequired(cb) {
this._onItemRequired.push(cb);
} // Called when an item is removed
if (rate) {
this._scheduleRender(true);
}
}
}, {
key: "onItemRemoved",
value: function onItemRemoved(cb) {
this._onItemRemoved.push(cb);
} // Called when the last item is removed
if (rate * this._lastEffectiveRate < 0) {
this._justReversedRate = !this._justReversedRate;
}, {
key: "onAllItemsRemoved",
value: function onAllItemsRemoved(cb) {
this._onAllItemsRemoved.push(cb);
}
}, {
key: "getNumItems",
value: function getNumItems() {
return this._items.length;
}
}, {
key: "setRate",
value: function setRate(rate) {
if (rate === this._rate) {
return;
}
if (rate <= 0) {
var containerSize = this._containerSize;
var nextOffset = this._leftItemOffset;
if (rate * this._lastEffectiveRate < 0) {
this._justReversedRate = !this._justReversedRate;
}
this._items.forEach(function (_ref3) {
var item = _ref3.item;
nextOffset += item.getSize();
});
this._rate = rate;
this._waitingForItem = nextOffset <= containerSize;
} else {
this._waitingForItem = this._leftItemOffset >= 0;
}
if (rate) {
this._lastEffectiveRate = rate;
if (!this._items.length) {
this._waitingForItem = true;
}
} else {
this._waitingForItem = false;
}
this._rate = rate;
this._tick();
}
}, {
key: "getRate",
value: function getRate() {
return this._rate;
}
}, {
key: "clear",
value: function clear() {
var _this2 = this;
if (rate) {
this._lastEffectiveRate = rate;
}
},
},
{
key: 'getRate',
value: function getRate() {
return this._rate;
},
},
{
key: 'clear',
value: function clear() {
var _this = this;
this._items.forEach(function (_ref4) {
var item = _ref4.item;
return _this._removeItem(item);
this._boundary.enter(function () {
_this2._items.forEach(function (_ref3) {
var item = _ref3.item;
return _this2._removeItem(item);
});
this._items = [];
this._waitingForItem = true;
_this2._items = [];
_this2._waitingForItem = true;
_this2._nextItemWouldBeTouching = false;
this._updateContainerInverseSize();
},
},
{
key: 'isWaitingForItem',
value: function isWaitingForItem() {
return this._waitingForItem;
},
},
{
key: 'appendItem',
value: function appendItem($el) {
if (!this._waitingForItem) {
_this2._updateWindowInverseSize();
_this2._cleanup();
});
}
}, {
key: "isWaitingForItem",
value: function isWaitingForItem() {
return this._waitingForItem;
}
}, {
key: "appendItem",
value: function appendItem($el) {
var _this3 = this;
var _ref4 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
_ref4$metadata = _ref4.metadata,
metadata = _ref4$metadata === void 0 ? null : _ref4$metadata;
this._boundary.enter(function () {
if (!_this3._waitingForItem) {
throw new Error('No room for item.');
} // convert to div if $el is a string
$el = toDomEl($el);
var itemAlreadyExists = this._items.some(function (_ref5) {
var itemAlreadyExists = _this3._items.some(function (_ref5) {
var item = _ref5.item;
return item instanceof Item && item.getOriginalEl() === $el;
return item.getOriginalEl() === $el;
});

@@ -480,117 +600,86 @@

this._waitingForItem = false;
this._pendingItem = new Item($el, this._direction);
_this3._waitingForItem = false;
_this3._pendingItem = new Item($el, _this3._direction, metadata);
this._pendingItem.enableAnimationHint(!!this._rate);
_this3._tick();
});
}
}, {
key: "_removeItem",
value: function _removeItem(item) {
var _this4 = this;
if (this._rendering) {
this._render(0);
} else {
this._scheduleRender(true);
}
},
},
{
key: '_removeItem',
value: function _removeItem(item) {
var _this2 = this;
this._boundary.enter(function (_ref6) {
var callbacks = _ref6.callbacks;
item.remove();
defer(function () {
item.remove();
_this4._items.splice(_this4._items.indexOf(item), 1);
if (item instanceof Item) {
_this2._onItemRemoved.forEach(function (cb) {
deferException(function () {
return cb(item.getOriginalEl());
});
});
}
_this4._onItemRemoved.forEach(function (cb) {
callbacks.push(function () {
return cb(item.getOriginalEl());
});
});
}, // update size of container so that the marquee items fit inside it.
// This is needed because the items are posisitioned absolutely, so not in normal flow.
// Without this, for DIRECTION.RIGHT, the height of the container would always be 0px, which is not useful
},
{
key: '_updateContainerInverseSize',
value: function _updateContainerInverseSize() {
if (this._direction === DIRECTION.DOWN) {
return;
}
});
} // update size of container so that the marquee items fit inside it.
// This is needed because the items are posisitioned absolutely, so not in normal flow.
// Without this, for DIRECTION.RIGHT, the height of the container would always be 0px, which is not useful
var maxSize = this._items.reduce(function (size, _ref6) {
var item = _ref6.item;
}, {
key: "_updateWindowInverseSize",
value: function _updateWindowInverseSize() {
if (this._direction === DIRECTION.DOWN) {
return;
}
if (item instanceof VirtualItem) {
return size;
}
var a = item.getSize({
inverse: true,
});
if (a > size) {
return a;
}
return size;
}, 0);
if (this._containerInverseSize !== maxSize) {
this._containerInverseSize = maxSize;
this._$container.style.height = ''.concat(maxSize, 'px');
}
},
},
{
key: '_enableAnimationHint',
value: function _enableAnimationHint(enable) {
this._items.forEach(function (_ref7) {
var item = _ref7.item;
return item.enableAnimationHint(enable);
var maxSize = Math.max.apply(Math, _toConsumableArray(this._items.map(function (_ref7) {
var item = _ref7.item;
return item.getSize({
inverse: true
});
},
},
{
key: '_scheduleRender',
value: function _scheduleRender(immediate) {
var _this3 = this;
})));
if (immediate) {
if (this._renderTimer) window.clearTimeout(this._renderTimer);
this._renderTimer = null;
}
if (this.windowInverseSize !== maxSize) {
this.windowInverseSize = maxSize;
this._$window.style.height = "".concat(maxSize, "px");
}
}
}, {
key: "_scheduleRender",
value: function _scheduleRender() {
var _this5 = this;
if (!this._renderTimer) {
// ideally we'd use requestAnimationFrame here but there's a bug in
// chrome which means when the callback is called it triggers a style
// recalculation even when nothing changes, which is not efficient
// see https://bugs.chromium.org/p/chromium/issues/detail?id=1252311
// and https://stackoverflow.com/q/69293778/1048589
this._renderTimer = window.setTimeout(
function () {
return _this3._tick();
},
immediate ? 0 : 100
);
}
},
},
{
key: '_cleanup',
value: function _cleanup() {
this._containerSizeWatcher.tearDown();
if (!this._renderTimer) {
// ideally we'd use requestAnimationFrame here but there's a bug in
// chrome which means when the callback is called it triggers a style
// recalculation even when nothing changes, which is not efficient
// see https://bugs.chromium.org/p/chromium/issues/detail?id=1252311
// and https://stackoverflow.com/q/69293778/1048589
this._renderTimer = window.setTimeout(function () {
return _this5._tick();
}, renderInterval);
}
}
}, {
key: "_cleanup",
value: function _cleanup() {
var _this$_containerSizeW;
this._containerSizeWatcher = null;
this._lastUpdateTime = null;
},
},
{
key: '_tick',
value: function _tick() {
var _this4 = this;
(_this$_containerSizeW = this._containerSizeWatcher) === null || _this$_containerSizeW === void 0 ? void 0 : _this$_containerSizeW.tearDown();
this._containerSizeWatcher = null;
this._correlation = null;
this._windowOffset = 0;
}
}, {
key: "_tick",
value: function _tick() {
var _this6 = this;
this._renderTimer = null;
this._boundary.enter(function (_ref8) {
var callbacks = _ref8.callbacks;
_this6._renderTimer && clearTimeout(_this6._renderTimer);
_this6._renderTimer = null;
if (!this._items.length && !this._pendingItem) {
this._cleanup();
if (!_this6._items.length && !_this6._pendingItem) {
_this6._cleanup();

@@ -600,206 +689,138 @@ return;

if (!this._containerSizeWatcher) {
this._containerSizeWatcher = new SizeWatcher(this._$container);
_this6._scheduleRender();
if (!_this6._containerSizeWatcher) {
_this6._containerSizeWatcher = new SizeWatcher(_this6._$window);
}
var now = performance.now();
var timePassed = this._lastUpdateTime
? now - this._lastUpdateTime
: 0;
this._lastUpdateTime = now;
this._rendering = true;
var shiftAmount = this._lastRate * (timePassed / 1000);
this._lastRate = this._rate;
this._containerSize =
this._direction === DIRECTION.RIGHT
? this._containerSizeWatcher.getWidth()
: this._containerSizeWatcher.getHeight();
deferException(function () {
return _this4._render(shiftAmount);
});
this._rendering = false;
var resynced = false;
if (this._rate) {
this._scheduleRender();
if (_this6._correlation) {
var timePassed = now - _this6._correlation.time;
_this6._windowOffset = _this6._correlation.offset + _this6._correlation.rate * -1 * (timePassed / 1000);
} else {
this._cleanup();
resynced = true;
}
},
},
{
key: '_render',
value: function _render(shiftAmount) {
var _this5 = this;
this._leftItemOffset += shiftAmount;
var containerSize = this._containerSize;
if (Math.abs(_this6._windowOffset) > maxTranslateDistance) {
// resync so that the number of pixels we are translating doesn't get too big
resynced = true;
var shiftAmount = _this6._windowOffset;
if (this._rate < 0) {
while (this._items.length) {
var item = this._items[0].item;
var size = item.getSize();
_this6._items.forEach(function (item) {
return item.offset -= shiftAmount;
});
if (this._leftItemOffset + size > 0) {
break;
}
this._removeItem(item);
this._items.shift();
this._leftItemOffset += size;
}
_this6._correlation = null;
_this6._windowOffset = 0;
}
var offsets = [];
var nextOffset = this._leftItemOffset;
_this6._slider.setOffset(_this6._windowOffset * -1, _this6._rate, resynced);
this._items.some(function (_ref8, i) {
var item = _ref8.item;
if (nextOffset >= containerSize) {
if (_this5._rate > 0) {
_this5._items.splice(i).forEach(function (a) {
return _this5._removeItem(a.item);
});
return true;
}
}
offsets.push(nextOffset);
nextOffset += item.getSize();
return false;
});
var justReversedRate = this._justReversedRate;
this._justReversedRate = false;
if (justReversedRate) {
this._nextItemImmediatelyFollowsPrevious = false;
if (!_this6._correlation || _this6._correlation.rate !== _this6._rate) {
_this6._correlation = {
time: now,
offset: _this6._windowOffset,
rate: _this6._rate
};
}
if (this._pendingItem) {
this._$container.appendChild(this._pendingItem.getContainer());
_this6._containerSize = _this6._direction === DIRECTION.RIGHT ? _this6._containerSizeWatcher.getWidth() : _this6._containerSizeWatcher.getHeight(); // if container has size 0 pretend it is 1 to prevent infinite loop
// of adding items that are instantly removed
if (this._rate <= 0) {
if (!this._nextItemImmediatelyFollowsPrevious) {
// insert virtual item so that it starts off screen
this._items.push({
item: new VirtualItem(
Math.max(0, containerSize - nextOffset)
),
offset: nextOffset,
});
var containerSize = Math.max(_this6._containerSize, 1);
var justReversedRate = _this6._justReversedRate;
_this6._justReversedRate = false;
var newItemWouldBeTouching = _this6._nextItemWouldBeTouching;
_this6._nextItemWouldBeTouching = null;
var nextItemTouching = null;
offsets.push(nextOffset);
nextOffset = containerSize;
}
if (_this6._pendingItem) {
_this6._$moving.appendChild(_this6._pendingItem.getContainer());
this._items.push({
item: this._pendingItem,
offset: nextOffset,
});
var touching = _this6._rate <= 0 ? last(_this6._items) : first(_this6._items);
offsets.push(nextOffset);
nextOffset += this._pendingItem.getSize();
if (_this6._rate <= 0) {
_this6._items = [].concat(_toConsumableArray(_this6._items), [{
item: _this6._pendingItem,
appendRate: _this6._rate,
offset: newItemWouldBeTouching ? touching ? touching.offset + touching.item.getSize() : _this6._windowOffset : _this6._windowOffset + containerSize
}]);
} else {
if (
this._nextItemImmediatelyFollowsPrevious &&
!this._items.length
) {
this._leftItemOffset = containerSize;
} else if (
!this._nextItemImmediatelyFollowsPrevious &&
this._items.length &&
this._leftItemOffset > 0
) {
this._items.unshift({
item: new VirtualItem(this._leftItemOffset),
offset: 0,
});
_this6._items = [{
item: _this6._pendingItem,
appendRate: _this6._rate,
offset: newItemWouldBeTouching ? touching ? touching.offset - _this6._pendingItem.getSize() : _this6._windowOffset + containerSize - _this6._pendingItem.getSize() : _this6._windowOffset - _this6._pendingItem.getSize()
}].concat(_toConsumableArray(_this6._items));
}
offsets.unshift(0);
this._leftItemOffset = 0;
}
_this6._pendingItem = null;
} // add a buffer on the side to make sure that new elements are added before they would actually be on screen
this._leftItemOffset -= this._pendingItem.getSize();
offsets.unshift(this._leftItemOffset);
this._items.unshift({
item: this._pendingItem,
offset: this._leftItemOffset,
});
}
var buffer = renderInterval / 1000 * Math.abs(_this6._rate);
var requireNewItem = false;
this._pendingItem = null;
} // trim virtual items
while (
this._items.length &&
this._items[0].item instanceof VirtualItem
if (!_this6._waitingForItem && _this6._items.length
/* there should always be items at this point */
) {
offsets.shift();
var firstItem = first(_this6._items);
var lastItem = last(_this6._items);
this._items.shift();
var _touching = _this6._rate <= 0 ? lastItem : firstItem;
this._leftItemOffset = offsets[0] || 0;
if (_this6._rate <= 0 && lastItem.offset + _touching.item.getSize() - _this6._windowOffset <= containerSize + buffer || _this6._rate > 0 && _touching.offset - _this6._windowOffset > -1 * buffer) {
_this6._waitingForItem = requireNewItem = true; // if an item is appended immediately below, it would be considered touching
// the previous if we haven't just changed direction.
// This is useful when deciding whether to add a separator on the side that enters the
// screen first or not
nextItemTouching = justReversedRate ? null : {
$el: _touching.item.getOriginalEl(),
metadata: _touching.item.getMetadata()
};
}
}
while (
this._items.length &&
this._items[this._items.length - 1].item instanceof VirtualItem
) {
offsets.pop();
this._items.pop();
if (nextItemTouching) {
_this6._nextItemWouldBeTouching = true;
}
var containerSizeChanged =
this._containerSize !== this._previousContainerSize;
this._previousContainerSize = this._containerSize;
offsets.forEach(function (offset, i) {
var item = _this5._items[i];
var hasJumped = Math.abs(item.offset + shiftAmount - offset) >= 1;
item.item.setOffset(
offset,
_this5._rate,
containerSizeChanged || hasJumped
);
item.offset = offset;
_this6._items = _toConsumableArray(_this6._items).filter(function (_ref9) {
var item = _ref9.item,
offset = _ref9.offset;
var keep = _this6._rate < 0 ? offset + item.getSize() > _this6._windowOffset : offset < _this6._windowOffset + containerSize;
if (!keep) _this6._removeItem(item);
return keep;
});
this._updateContainerInverseSize();
if (!this._items.length) {
this._leftItemOffset = 0;
defer(function () {
_this5._onAllItemsRemoved.forEach(function (cb) {
deferException(function () {
return cb();
});
});
if (!_this6._items.length) {
_this6._onAllItemsRemoved.forEach(function (cb) {
return callbacks.push(cb);
});
}
this._nextItemImmediatelyFollowsPrevious = false;
_this6._items.reduce(function (newOffset, item) {
if (newOffset !== null && item.offset < newOffset) {
// the size of the item before has increased and would now be overlapping
// this one, so shuffle this one along
item.offset = newOffset;
}
if (
!this._waitingForItem &&
((this._rate <= 0 && nextOffset <= containerSize) ||
(this._rate > 0 && this._leftItemOffset >= 0))
) {
this._waitingForItem = true; // if an item is appended immediately below, it would be considered immediately following
// the previous if we haven't just changed direction.
// This is useful when deciding whether to add a separator on the side that enters the
// screen first or not
item.item.setOffset(item.offset);
return item.offset + item.item.getSize();
}, null);
this._nextItemImmediatelyFollowsPrevious = !justReversedRate;
_this6._updateWindowInverseSize();
if (requireNewItem) {
var nextItem;
this._onItemRequired.some(function (cb) {
_this6._onItemRequired.some(function (cb) {
return deferException(function () {
nextItem = cb({
immediatelyFollowsPrevious:
_this5._nextItemImmediatelyFollowsPrevious,
/** @deprecated */
immediatelyFollowsPrevious: !!nextItemTouching,
touching: nextItemTouching
});

@@ -811,35 +832,34 @@ return !!nextItem;

if (nextItem) {
// Note appendItem() will call _render() synchronously again
this.appendItem(nextItem);
// Note appendItem() will call _tick() synchronously again
_this6.appendItem(nextItem);
}
this._nextItemImmediatelyFollowsPrevious = false;
_this6._nextItemWouldBeTouching = false;
}
},
},
]);
});
}
}]);
return Marquee;
})();
}();
var indexMap = function (list) {
var indexMap = function(list) {
var map = {};
list.forEach(function (each, i) {
list.forEach(function(each, i) {
map[each] = map[each] || [];
map[each].push(i);
});
return map;
return map
};
var longestCommonSubstring = function (seq1, seq2) {
var result = { startString1: 0, startString2: 0, length: 0 };
var longestCommonSubstring = function(seq1, seq2) {
var result = {startString1:0, startString2:0, length:0};
var indexMapBefore = indexMap(seq1);
var previousOverlap = [];
seq2.forEach(function (eachAfter, indexAfter) {
seq2.forEach(function(eachAfter, indexAfter) {
var overlapLength;
var overlap = [];
var indexesBefore = indexMapBefore[eachAfter] || [];
indexesBefore.forEach(function (indexBefore) {
overlapLength =
((indexBefore && previousOverlap[indexBefore - 1]) || 0) + 1;
indexesBefore.forEach(function(indexBefore) {
overlapLength = ((indexBefore && previousOverlap[indexBefore-1]) || 0) + 1;
if (overlapLength > result.length) {

@@ -854,3 +874,3 @@ result.length = overlapLength;

});
return result;
return result
};

@@ -861,6 +881,4 @@

function loop(marquee) {
var buildersIn =
arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
var seperatorBuilder =
arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
var buildersIn = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
var seperatorBuilder = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
var lastIndex = -1;

@@ -870,12 +888,13 @@ var builders = buildersIn.slice();

var getNextBuilder = function getNextBuilder() {
var offset =
arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
var offset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
var nextIndex = (lastIndex + offset) % builders.length;
return {
builder: builders[nextIndex],
index: nextIndex,
index: nextIndex
};
};
var appendItem = function appendItem(immediatelyFollowsPrevious) {
var appendItem = function appendItem(touching) {
var _touching$metadata;
if (!builders.length || !marquee.isWaitingForItem()) {

@@ -885,32 +904,23 @@ return;

if (seperatorBuilder && touching && ((_touching$metadata = touching.metadata) === null || _touching$metadata === void 0 ? void 0 : _touching$metadata.isSeperator) !== true) {
var $el = toDomEl(seperatorBuilder());
marquee.appendItem($el, {
metadata: {
isSeperator: true
}
});
return;
}
var _getNextBuilder = getNextBuilder(),
builder = _getNextBuilder.builder,
index = _getNextBuilder.index;
builder = _getNextBuilder.builder,
index = _getNextBuilder.index;
lastIndex = index;
var $item = toDomEl(builder());
if (immediatelyFollowsPrevious && seperatorBuilder) {
var $seperator = toDomEl(seperatorBuilder());
var $container = document.createElement('div');
$seperator.style.display = 'inline';
$item.style.display = 'inline';
if (marquee.getRate() <= 0) {
$container.appendChild($seperator);
$container.appendChild($item);
} else {
$container.appendChild($item);
$container.appendChild($seperator);
}
$item = $container;
}
marquee.appendItem($item);
marquee.appendItem(toDomEl(builder()));
};
marquee.onItemRequired(function (_ref) {
var immediatelyFollowsPrevious = _ref.immediatelyFollowsPrevious;
return appendItem(immediatelyFollowsPrevious);
var touching = _ref.touching;
return appendItem(touching);
});

@@ -933,9 +943,6 @@ appendItem();

var _longestSubstring = longestCommonSubstring_1(
buildersStructure,
newBuildersStructure
),
startString1 = _longestSubstring.startString1,
startString2 = _longestSubstring.startString2,
length = _longestSubstring.length;
var _longestSubstring = longestCommonSubstring_1(buildersStructure, newBuildersStructure),
startString1 = _longestSubstring.startString1,
startString2 = _longestSubstring.startString2,
length = _longestSubstring.length;

@@ -953,3 +960,3 @@ if (lastIndex >= startString1 && lastIndex < startString1 + length) {

appendItem(false);
},
}
};

@@ -962,2 +969,3 @@ }

Object.defineProperty(exports, '__esModule', { value: true });
});
}));
{
"name": "dynamic-marquee",
"version": "2.2.0",
"version": "2.3.0",
"description": "A small library for creating marquees.",

@@ -40,2 +40,3 @@ "main": "./dist/dynamic-marquee.js",

"@rollup/plugin-node-resolve": "^13.2.1",
"@tjenkinson/boundary": "^2.0.0",
"husky": "^7.0.0",

@@ -42,0 +43,0 @@ "longest-common-substring": "0.0.1",

@@ -40,2 +40,3 @@ [![npm version](https://badge.fury.io/js/dynamic-marquee.svg)](https://badge.fury.io/js/dynamic-marquee)

></script>
<script type="text/javascript">

@@ -88,12 +89,16 @@ const Marquee = dynamicMarquee.Marquee;

`appendItem` also takes an optional second param `config` object, which should contain a `metadata` property. The value of this will be provided back to you in `onItemRequired`.
You can be notified when an item is required with
```js
marquee.onItemRequired(({ immediatelyFollowsPrevious }) => {
// for convenience if you have an item ready to go you can just return it
marquee.onItemRequired(({ touching }) => {
// For convenience if you have an item ready to go you can just return it
// in place of `marquee.appendItem($item);`
// if `immediatelyFollowsPrevious` is `true`, this would be a good time to add
// a seperator on the side that is entering the screen first. See loop.js
// for an example.
// If the new item would be touching another then `touching`
// will be set to an object that contains `$el` and `metadata` of
// the item it will be touching.
// This can be used to determine if a separate should be added.
// See loop.js for an example.
return $item;

@@ -125,2 +130,4 @@ });

You should also call this before removing the marquee from the DOM if you no longer need it to ensure that all timers are cleaned up and garbage collection can occur.
## When has an item been removed?

@@ -127,0 +134,0 @@

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