UNPKG

react-sequencer

Version:

Step based sequencer to give your components reliable states for transitions and animations.

206 lines 7.75 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var types_1 = require("./types"); var ticker_1 = __importDefault(require("./ticker")); var ticker = new ticker_1.default(); var Sequencer = /** @class */ (function () { function Sequencer(props) { var _this = this; this.onLoop = function (now) { if (_this.status !== types_1.PlayStatus.PLAYING) { return; } _this.currentTimeIn = now - _this.startedAt; var currentStep = _this.getCurrentStep(); var completesAt = currentStep.endPos; if (_this.currentTimeIn >= completesAt) { if (_this.currentStepIndex === _this.steps.length - 1) { if (_this.endMode === 'start') { _this.stop(); return; } if (_this.endMode === 'end') { _this.complete(); return; } if (_this.endMode === 'loop') { _this.startedAt = now; _this.goToStepByIndex(0); _this.notifyChange(); } } else { _this.currentStepIndex++; _this.notifyChange(); } } }; this.onChange = function (fn) { _this.subscriptions.push(fn); return function () { var index = _this.subscriptions.findIndex(function (f) { return f === fn; }); if (index !== -1) { _this.subscriptions.splice(index, 1); } }; }; this.play = function () { if (_this.status === types_1.PlayStatus.PLAYING) { return; } if (_this.isComplete()) { _this.goToStepByIndex(0); } _this.status = types_1.PlayStatus.PLAYING; ticker.onTick(_this.onLoop); _this.startedAt = ticker.currentTimeStamp - _this.currentTimeIn; _this.notifyChange(); }; this.pause = function () { if (_this.status === types_1.PlayStatus.PLAYING) { _this.status = types_1.PlayStatus.IDLE; ticker.offTick(_this.onLoop); _this.notifyChange(); } }; this.stop = function () { _this.goToStepByIndex(0); _this.status = types_1.PlayStatus.IDLE; ticker.offTick(_this.onLoop); _this.notifyChange(); }; this.complete = function () { _this.currentStepIndex = _this.steps.length - 1; _this.currentTimeIn = _this.totalDuration; _this.status = types_1.PlayStatus.IDLE; ticker.offTick(_this.onLoop); _this.notifyChange(); }; this.isStopped = function () { return _this.currentTimeIn === 0 && _this.status === types_1.PlayStatus.IDLE; }; this.isComplete = function () { return _this.currentTimeIn >= _this.totalDuration; }; this.isPlaying = function () { return _this.status === types_1.PlayStatus.PLAYING; }; this.isBefore = function (stepName) { var stepIndex = _this.steps.findIndex(function (step) { return step.name === stepName; }); if (stepIndex === -1) { throw new Error("Sequencer step " + stepName + " not found."); } return _this.currentStepIndex < stepIndex; }; this.isAfter = function (stepName) { var stepIndex = _this.steps.findIndex(function (step) { return step.name === stepName; }); if (stepIndex === -1) { throw new Error("Sequencer step " + stepName + " not found."); } return _this.currentStepIndex > stepIndex; }; this.getState = function () { var state = { current: _this.steps[_this.currentStepIndex].name, index: _this.currentStepIndex, isPlaying: _this.isPlaying(), isComplete: _this.isComplete(), isStopped: _this.isStopped(), }; return state; }; this.getApi = function () { var _a = _this, play = _a.play, pause = _a.pause, stop = _a.stop, complete = _a.complete, isBefore = _a.isBefore, isAfter = _a.isAfter; var api = { play: play, pause: pause, stop: stop, complete: complete, isBefore: isBefore, isAfter: isAfter, }; return api; }; var defaults = { steps: [], loop: false, complete: false, endMode: 'end', autoplay: false, }; var options = __assign(__assign({}, defaults), props); if (options.steps.length === 0) { throw new Error('React Sequencer: At least one step required in options'); } this.steps = this.generateSteps(options.steps); this.totalDuration = this.steps[this.steps.length - 1].endPos; this.currentStepIndex = 0; this.currentTimeIn = 0; this.startedAt = 0; this.endMode = options.loop ? 'loop' : options.endMode; this.status = types_1.PlayStatus.IDLE; this.subscriptions = []; if (options.complete === true) { this.goToStepByIndex(this.steps.length - 1); } if (options.autoplay === true) { this.play(); } this.prevState = this.getState(); } Sequencer.prototype.generateSteps = function (stepsInput) { if (!stepsInput) { throw new Error('Invalid format.'); } var prev = 0; var steps = stepsInput.map(function (step) { if (!Array.isArray(step) || step.length !== 2) { throw new Error('Invalid format. See docs for correct structure.'); } var startPos = prev; var endPos = step[1] + prev; prev = endPos; return { startPos: startPos, endPos: endPos, name: step[0], }; }); return steps; }; Sequencer.prototype.notifyChange = function () { var state = this.getState(); if (!this.prevState || state.index !== this.prevState.index || state.isPlaying !== this.prevState.isPlaying) { this.subscriptions.forEach(function (fn) { fn(state); }); } this.prevState = state; }; Sequencer.prototype.goToStepByIndex = function (index) { this.currentStepIndex = index; this.currentTimeIn = this.steps[index].startPos; }; Sequencer.prototype.getCurrentStep = function () { return this.steps[this.currentStepIndex]; }; return Sequencer; }()); exports.default = Sequencer; //# sourceMappingURL=sequencer.js.map