From 58d0464a5169d4c035ce69ff8c723acd1116b2d3 Mon Sep 17 00:00:00 2001 From: Alex MacArthur Date: Sun, 10 Dec 2017 20:38:04 -0600 Subject: [PATCH] Add ability to freeze/unfreeze instances and manipulate after instantiation. --- README.md | 135 ++++++---- package.json | 2 +- src/instance.js | 339 ++++++++++++++----------- src/typeit.js | 67 ++++- tests/{typeit.test.js => base.test.js} | 6 +- tests/typing.test.js | 159 ++++++++++++ 6 files changed, 490 insertions(+), 218 deletions(-) rename tests/{typeit.test.js => base.test.js} (90%) create mode 100644 tests/typing.test.js diff --git a/README.md b/README.md index 3c0f0870..8cbcd3f5 100644 --- a/README.md +++ b/README.md @@ -3,18 +3,17 @@ The Most Versatile JavaScript Animated Typing Utility on the Planet [![Build Status](https://travis-ci.org/alexmacarthur/typeit.svg?branch=master)](https://travis-ci.org/alexmacarthur/typeit) +[![npm downloads](https://img.shields.io/npm/dm/typeit.svg?style=flat-square)](http://npm-stat.com/charts.html?package=typeit) ## Table of Contents * [Overview](#overview) * [Choose a License](#choose-a-license) * [Usage](#usage) * [API](#api) - * [Options](#options) - * [Companion Functions](#companion-functions) - * [Other Handy Functions](#other-handy-functions) +* [Options](#options) +* [CodePen Examples](#codepen-examples) * [Contribute](#contribute) * [License](#license) -* [Full Documentation (offsite)](https://typeitjs.com/docs) ## Overview @@ -33,10 +32,7 @@ For more advanced, controlled typing effects, TypeIt comes with companion functi * No dependencies! ### Demos -Checkout several demos and a sandbox where you can try it out at typeitjs.com. - -### Full Documentation -View the full documentation for using TypeIt here: typeitjs.com/docs. +See some more examples and try out the sandbox (here)[https://typeitjs.com]. ## Choose a License Using TypeIt for an open source or personal project is completely free. To use it in a commercial project, purchase a single license, or an unlimited license that'll never expire, no matter how many times you use it. @@ -48,7 +44,10 @@ Using TypeIt for an open source or personal project is completely free. To use i ### Get the Code -* CDN: Include `https://cdn.jsdelivr.net/npm/typeit@VERSION_NUMBER/dist/typeit.min.js` on your page. +* CDN: Include this on your page: +``` +https://cdn.jsdelivr.net/npm/typeit@VERSION_NUMBER/dist/typeit.min.js +``` * npm / yarn: Install with `npm install typeit` or `yarn install typeit` and import into your project with `import TypeIt from 'typeit'`. * Build It Yourself: If, for some weird reason, you want to clone the repository and build the code yourself, first run `yarn install` and then `yarn run build`. The compiled source files will be in the `/dist` directory. @@ -72,7 +71,7 @@ Using TypeIt for an open source or personal project is completely free. To use i You're ready to start typing! -### Simple Usage +### Create an Instance At its simplest use, just create a new TypeIt instance, pass an empty element, and define your [options](#options). @@ -84,10 +83,25 @@ Example: }); ``` -### Advanced Usage -To control a typewriter effect to the smallest character, pause, speed, or more, there are six companion functions available. Simply chain them together on an instance of TypeIt, and your chain will execute. You'll be able to create a dynamic, realistic narrative with just a few lines of code. +## API + +#### Companion Functions +To control a typewriter effect to the smallest character, pause, speed, or more, there companion functions available. Simply chain them together on an instance of TypeIt, and your chain will execute. You'll be able to create a dynamic, realistic narrative with just a few lines of code. + +| Function | Arguments | Description +| ------------- | ------------- | ------------- | +| type() | (string) Characters (including those wrapped in HTML) to be typed. | Will type the characters. If instance has already begun, will add the typing action to the end of the queue. | +| delete() | (number) Number of characters to be deleted from what's already been typed. | Will delete the specified number of characters. If left empty, will delete all of what's been typed. | +| empty() | (none) | Will instantly delete everything that has already been typed. +| pause() | (number) Number of milliseconds to pause before continuing. | Will pause the specified number of milliseconds.| +| break() | (none) | Will break the typing to a new line.| +| options() | (JSON) Options you'd like to update | Will redefine your options on the fly. This will only work for updating the `speed`, `lifeLike`, and `html` options.| +| destroy() | (bool) Whether you want to remove the cursor after destroying. Default is `true`.| Destroys the instance on whatever elements to which it's attached. +| freeze() | none | Will pause/freeze an instance. +| unfreeze() | none | Will resume an instance. -For example: +#### Chaining on Initializing +You may use these functions to generate a queue of typing events immediately upon creating the instance. ```js new TypeIt('.type-it', { @@ -102,16 +116,62 @@ For example: .type('t!'); ``` -To view these functions and how they work, see the [API](#api) section. +#### Pausing/Resuming Typing +Additionally, you may use these functions to manipulate an instance after it's been created. A common use case for this is pausing and resuming an instance. -## API +```js +var instance = new TypeIt('#element', { + strings: "This is what I'm choosing to type right now." +}); + +//-- Pause after one second. +setTimeout(() => { + instance.freeze(); +}, 1000); + +//-- Resume after three seconds. +setTimeout(() => { + instance.unfreeze(); +}, 3000); + +``` + +#### Respond to User Action +This is also helpful if you want your typing to respond to user action of any sort. + +```js +var instance = new TypeIt('#element'); + +document.querySelector('button').addEventListener('click', (event) => { + instance.type('You just clicked a button!'); +}); + +``` -### Options +### Tack on Strings Later +You can also use the `type()` function to add more strings onto the queue at a later time. If the instance has already finished, the string will be added to the queue and typed when it's time. -#### Defining Your Options -You can modify the options for the plugin by passing in JSON. +```js +var instance = new TypeIt('#element', { + strings: "What I'm first going to type." +}); + +instance.type("I just decided to add this on too, but it won't be typed until the active queue has finished."); +``` + +### Check If Instance Is Complete +At any moment, you may check if the instance is complete. Access the 'isComplete' property to do so. If `loop` is set to `true`, the instance will never be marked complete. + +```js +var instance = new TypeIt('#element', { /* options... */ }); -There are a number of options you may use to customize TypeIt. For more details on these options, view the full documentation. +if(instance.isComplete) { + //-- Do something. +} +``` + +## Options +You can modify the options for the plugin by passing in JSON upon instantiation. | Option | Description | Default Value | ------------- | ------------- | ------------- | @@ -143,40 +203,17 @@ If you're creating several instances of TypeIt on a page, and don't wish to repe }); ``` -### Companion Functions +## CodePen Examples +I have a few CodePen examples that illustrate to do a few interesting implementations of TypeIt. -Use these functions to chain typing commands together upon initialization. - -| Function | Arguments | Description -| ------------- | ------------- | ------------- | -| type() | (string) Characters (including those wrapped in HTML) to be typed. | Will type the characters. | -| delete() | (number) Number of characters to be deleted from what's already been typed. | Will delete the specified number of characters. | -| empty() | (none) | Will instantly delete everything that has already been typed. -| pause() | (number) Number of milliseconds to pause before continuing. | Will pause the specified number of milliseconds.| -| break() | (none) | Will break the typing to a new line.| -| options() | (JSON) Options you'd like to update | Will redefine your options on the fly. This will only work for updating the `speed`, `lifeLike`, and `html` options.| - -### Other Handy Functions - -#### Destroy an Instance - -| Function | Arguments | Description -| ------------- | ------------- | ------------- | -| destroy() | (bool) Whether you want to remove the cursor after destroying. Default is `true`.| Destroys the instance on whatever elements to which it's attached. - -```js -var instance = new TypeIt('#id', { - strings: 'This is my string' -}); - -//-- Will preserve the cursor. If you want to destory that too, pass 'false'. -instance.destroy(); -``` +* [TypeIt as a React Component](https://codepen.io/alexmacarthur/pen/gXNyBJ) +* [Chained Typing Animations](https://codepen.io/alexmacarthur/pen/MOPQvp) +* ['Fill in the Blank' Effect](https://codepen.io/alexmacarthur/pen/pdXLRG) ## Contribute -Please do! The code is available on Github. Check out the [CONTRIBUTING.md](CONTRIBUTING.md) file to see how to get started. +Please do! The code is available on Github. Check out the [CONTRIBUTING.md](https://github.com/alexmacarthur/typeit/blob/master/CONTRIBUTING.md) file to see how to get started. ## License -[GPL-2.0](LICENSE) © Alex MacArthur +[GPL-2.0](https://github.com/alexmacarthur/typeit/blob/master/LICENSE) © Alex MacArthur diff --git a/package.json b/package.json index ceee38ce..2012d77e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "typeit", - "version": "5.2.0", + "version": "5.3.0", "description": "The most versatile animated typing utility on the planet.", "author": "Alex MacArthur (https://macarthur.me)", "license": "GPL-2.0", diff --git a/src/instance.js b/src/instance.js index f6fc75ea..4dd2dcdc 100644 --- a/src/instance.js +++ b/src/instance.js @@ -5,12 +5,12 @@ export default class Instance { this.timeouts = []; this.id = id; this.queue = []; - this.queueIndex = 0; this.hasStarted = false; - this.inTag = false; + this.isFrozen = false; + this.isComplete = false; + this.isInTag = false; this.stringsToDelete = ""; - this.style = - 'style="display:inline;position:relative;font:inherit;color:inherit;"'; + this.style = "display:inline;position:relative;font:inherit;color:inherit;"; this.element = element; this.setOptions(options, window.TypeItDefaults, false); @@ -28,10 +28,9 @@ export default class Instance { return; } - this.element.innerHTML = - '.'; + this.element.innerHTML = ` + + `; this.element.setAttribute("data-typeitid", this.id); this.elementContainer = this.element.querySelector("span"); @@ -39,9 +38,10 @@ export default class Instance { if (this.options.startDelete) { this.insert(this.stringsToDelete); this.queue.push([this.delete]); - this.insertPauseIntoQueue(1); + this.insertSplitPause(1); } + this.cursor(); this.generateQueue(); this.kickoff(); } @@ -52,50 +52,124 @@ export default class Instance { }); } - generateQueue() { - for (let i = 0; i < this.options.strings.length; i++) { - this.queue.push([this.type, this.options.strings[i]]); + generateQueue(initialStep = null) { + initialStep = + initialStep === null + ? [this.pause, this.options.startDelay] + : initialStep; + + this.queue.push(initialStep); + + this.options.strings.forEach((string, index) => { + this.queueUpString(string); - if (i < this.options.strings.length - 1) { - this.queue.push([this.options.breakLines ? this.break : this.delete]); - this.insertPauseIntoQueue(this.queue.length); + //-- This is not the last string,so insert a pause for between strings. + if (index + 1 < this.options.strings.length) { + if (this.options.breakLines) { + this.queue.push([this.break]); + this.insertSplitPause(this.queue.length); + } else { + this.queueUpDeletions(string); + this.insertSplitPause(this.queue.length, string.length); + } } + }); + } + + /** + * Delete each character from a string. + */ + queueUpDeletions(stringOrNumber = null) { + let number = + typeof stringOrNumber === "string" + ? stringOrNumber.length + : stringOrNumber; + + for (let i = 0; i < number; i++) { + this.queue.push([this.delete, 1]); } } - insertPauseIntoQueue(position) { + /** + * Add steps to the queue for each character in a given string. + */ + queueUpString(string, rake = true) { + if (!string) return; + + string = this.toArray(string); + + var doc = document.implementation.createHTMLDocument(); + doc.body.innerHTML = string; + + //-- If it's designated, rake that bad boy for HTML tags and stuff. + if (rake) { + string = this.rake(string); + string = string[0]; + } + + //-- If an opening HTML tag is found and we're not already printing inside a tag + if ( + this.options.html && + (string[0].startsWith("<") && !string[0].startsWith("/); + let doc = document.implementation.createHTMLDocument(); + doc.body.innerHTML = "<" + matches[1] + ">"; + + //-- Add to the queue. + this.queue.push([this.type, doc.body.children[0]]); + } else { + this.queue.push([this.type, string[0]]); + } + + //-- Shorten it by one character. + string.splice(0, 1); + + //-- If there's more to it, run again until fully printed. + if (string.length) { + this.queueUpString(string, false); + } + } + + /** + * Insert a split pause around a range of queue items. + * + * @param {Number} startPosition The position at which to start wrapping. + * @param {Number} numberOfActionsToWrap The number of actions in the queue to wrap. + * @return {void} + */ + insertSplitPause(startPosition, numberOfActionsToWrap = 1) { let halfDelay = this.options.nextStringDelay / 2; - this.queue.splice(position - 1, 0, [this.pause, halfDelay]); - this.queue.splice(position + 2, 0, [this.pause, halfDelay]); + this.queue.splice(startPosition, 0, [this.pause, halfDelay]); + this.queue.splice(startPosition - numberOfActionsToWrap, 0, [ + this.pause, + halfDelay + ]); } kickoff() { - this.cursor(); - if (this.options.autoStart) { - this.startQueue(); - } else { - if (this.isVisible()) { - this.hasStarted = true; - this.startQueue(); - } else { - let that = this; - - window.addEventListener("scroll", function checkForStart(event) { - if (that.isVisible() && !that.hasStarted) { - that.hasStarted = true; - that.startQueue(); - event.currentTarget.removeEventListener(event.type, checkForStart); - } - }); - } + this.hasStarted = true; + this.next(); + return; } - } - startQueue() { - setTimeout(() => { - this.executeQueue(); - }, this.options.startDelay); + if (this.isVisible()) { + this.hasStarted = true; + this.next(); + return; + } + + let that = this; + + window.addEventListener("scroll", function checkForStart(event) { + if (that.isVisible() && !that.hasStarted) { + that.hasStarted = true; + that.next(); + event.currentTarget.removeEventListener(event.type, checkForStart); + } + }); } isVisible() { @@ -129,37 +203,41 @@ export default class Instance { } cursor() { - if (!this.options.cursor) return; + let visibilityStyle = "visibility: hidden;"; - let styleBlock = document.createElement("style"); + if (this.options.cursor) { + let styleBlock = document.createElement("style"); - styleBlock.id = this.id; + styleBlock.id = this.id; - let styles = ` - @keyframes blink-${this.id} { - 0% {opacity: 0} - 49%{opacity: 0} - 50% {opacity: 1} - } + let styles = ` + @keyframes blink-${this.id} { + 0% {opacity: 0} + 49% {opacity: 0} + 50% {opacity: 1} + } - [data-typeitid='${this.id}'] .ti-cursor { - animation: blink-${this.id} ${this.options.cursorSpeed / - 1000}s infinite; - } - `; + [data-typeitid='${this.id}'] .ti-cursor { + animation: blink-${this.id} ${this.options.cursorSpeed / + 1000}s infinite; + } + `; + + styleBlock.appendChild(document.createTextNode(styles)); - styleBlock.appendChild(document.createTextNode(styles)); + document.head.appendChild(styleBlock); - document.head.appendChild(styleBlock); + visibilityStyle = ""; + } this.element.insertAdjacentHTML( "beforeend", - "|' + `|` ); } /** - * Appends string to element container. + * Inserts string to element container. */ insert(content, toChildNode = false) { if (toChildNode) { @@ -199,15 +277,13 @@ export default class Instance { break() { this.insert("
"); - this.executeQueue(); + this.next(); } pause(time) { - time = time === undefined ? this.options.nextStringDelay : time; - setTimeout(() => { - this.executeQueue(); - }, time); + this.next(); + }, time === undefined ? this.options.nextStringDelay : time); } /* @@ -246,72 +322,29 @@ export default class Instance { }); } - print(character) { - if (this.inTag) { - this.insert(character, true); - - if (this.tagCount < this.tagDuration) { - this.tagCount++; - } else { - this.inTag = false; - } - } else { - this.insert(character); - } - } - - /** - * Pass in a string, and loop over that string until empty. Then return true. - */ - type(string, rake = true) { - string = this.toArray(string); - - //-- If it's designated, rake that bad boy for HTML tags and stuff. - if (rake) { - string = this.rake(string); - string = string[0]; - } + type(character) { + this.setPace(); this.timeouts[0] = setTimeout(() => { - //-- Randomize the timeout each time, if that's your thing. - this.setPace(this); - - //-- If an opening HTML tag is found and we're not already printing inside a tag - if ( - this.options.html && - (string[0].indexOf("<") !== -1 && string[0].indexOf("= 0; i--) { - if (string[i].indexOf("/); - let doc = document.implementation.createHTMLDocument(); - doc.body.innerHTML = "<" + matches[1] + ">"; + //-- We must have an HTML tag! + if (typeof character !== "string") { + character.innerHTML = ""; + this.elementContainer.appendChild(character); + this.isInTag = true; + this.next(); + return; + } - //-- Add that new node to the element. - this.elementContainer.appendChild(doc.body.children[0]); - } else { - this.print(string[0]); + //-- When we hit the end of the tag, turn it off! + if (character.startsWith(" { this.element.removeChild(helperElement); }); } - setOptions(settings, defaults = null, autoExecuteQueue = true) { + setOptions(settings, defaults = null, autonext = true) { let mergedSettings = {}; if (defaults === null) { @@ -344,8 +378,8 @@ export default class Instance { this.options = mergedSettings; - if (autoExecuteQueue) { - this.executeQueue(); + if (autonext) { + this.next(); } } @@ -378,7 +412,7 @@ export default class Instance { let textArray = this.elementContainer.innerHTML.split(""); - let amount = chars === null ? textArray.length - 1 : chars + 1; + let amount = chars + 1; //-- Cut the array by a character. for (let n = textArray.length - 1; n > -1; n--) { @@ -436,12 +470,16 @@ export default class Instance { this.elementContainer.innerHTML = textArray.join(""); - //-- Characters still in the string. - if (amount > (chars === null ? 0 : 2)) { - this.delete(chars === null ? null : chars - 1); - } else { - this.executeQueue(); + //-- Delete again! Don't call directly, to respect possible pauses. + if (chars === null) { + this.queue.unshift([this.delete, textArray.length]); } + + if (chars > 1) { + this.queue.unshift([this.delete, chars - 1]); + } + + this.next(); }, this.deletePace); } @@ -450,34 +488,33 @@ export default class Instance { */ empty() { this.elementContainer.innerHTML = ""; - this.executeQueue(); + this.next(); } - executeQueue() { - if (this.queueIndex < this.queue.length) { - let thisFunc = this.queue[this.queueIndex]; - this.queueIndex++; - - //-- Delay execution if looping back to the beginning of the queue. - if (this.isLooping && this.queueIndex === 1) { - setTimeout(() => { - thisFunc[0].call(this, thisFunc[1]); - }, this.options.loopDelay / 2); - } else { - thisFunc[0].call(this, thisFunc[1]); - } + next() { + if (this.isFrozen) { + return; + } + //-- We haven't reached the end of the queue, go again. + if (this.queue.length > 0) { + let thisStep = this.queue[0]; + this.queue.shift(); + thisStep[0].call(this, thisStep[1]); return; } this.options.callback(); if (this.options.loop) { - this.queueIndex = 0; - this.isLooping = true; + this.queueUpDeletions(this.elementContainer.innerHTML); + this.generateQueue([this.pause, this.options.loopDelay / 2]); + setTimeout(() => { - this.delete(); + this.next(); }, this.options.loopDelay / 2); + } else { + this.isComplete = true; } } } diff --git a/src/typeit.js b/src/typeit.js index 4313b56d..b4c26b65 100644 --- a/src/typeit.js +++ b/src/typeit.js @@ -25,6 +25,10 @@ export default class TypeIt { this.createInstances(); } + get isComplete() { + return this.instances[0].isComplete; + } + generateHash() { return ( Math.random() @@ -45,11 +49,60 @@ export default class TypeIt { pushAction(func, argument = null) { this.instances.forEach(instance => { instance.queue.push([instance[func], argument]); + + if (instance.isComplete === true) { + instance.next(); + } + }); + } + + /** + * If used after typing has started, will append strings to the end of the existing queue. If used when typing is paused, will restart it. + * + * @param {string} string The string to be typed. + * @return {object} TypeIt instance + */ + type(string = "") { + this.instances.forEach(instance => { + //-- Queue up a string right off the bat. + instance.queueUpString(string); + + if (instance.isComplete === true) { + instance.next(); + } + }); + + return this; + } + + /** + * If null is passed, will delete whatever's currently in the element. + * + * @param { number } numCharacters Number of characters to delete. + * @return { TypeIt } + */ + delete(numCharacters = null) { + this.pushAction("delete", numCharacters); + return this; + } + + freeze() { + this.instances.forEach(instance => { + instance.isFrozen = true; }); } - type(string) { - this.pushAction("type", string); + unfreeze() { + this.instances.forEach(instance => { + if (!instance.isFrozen) return; + + instance.isFrozen = false; + instance.next(); + }); + } + + pause(ms = null) { + this.pushAction("pause", ms); return this; } @@ -69,21 +122,11 @@ export default class TypeIt { this.instances = []; } - delete(numCharacters) { - this.pushAction("delete", numCharacters); - return this; - } - empty() { this.pushAction("empty"); return this; } - pause(ms) { - this.pushAction("pause", ms); - return this; - } - break() { this.pushAction("break"); return this; diff --git a/tests/typeit.test.js b/tests/base.test.js similarity index 90% rename from tests/typeit.test.js rename to tests/base.test.js index 4f5ee05f..1fb5ff9e 100644 --- a/tests/typeit.test.js +++ b/tests/base.test.js @@ -10,8 +10,6 @@ test('Returns an object with base properties.', () => { const instance = new TypeIt('#element', {}); expect(Object.keys(instance).sort()).toEqual(['elements', 'id', 'instances', 'args'].sort()); - - document.body.innerHTML = ''; }); test('Destroys instances successfully.', () => { @@ -33,11 +31,9 @@ test('Destroys instances successfully.', () => { expect(instance.instances).toHaveLength(0); expect(document.body.querySelector('.ti-cursor')).toEqual(null); - - document.body.innerHTML = ''; }); -test('Redefines defaults correct.', () => { +test('Redefines defaults correctly.', () => { document.body.innerHTML = `
' diff --git a/tests/typing.test.js b/tests/typing.test.js new file mode 100644 index 00000000..561e8606 --- /dev/null +++ b/tests/typing.test.js @@ -0,0 +1,159 @@ +import TypeIt from '../src/typeit'; + +test('Generates a queue correctly.', () => { + + document.body.innerHTML = + `
' + +
`; + + const instance = new TypeIt('#element', { + strings: ["Taxation is...", "theft."] + }); + + instance.instances.forEach((instance) => { + expect(instance.queue).toHaveLength(23); + }); + +}); + +test('Generates a queue correctly when chaining upon instantiation.', () => { + document.body.innerHTML = + `
' + +
`; + + const instance = new TypeIt('#element', {}) + .type('First string.') + .delete() + .type('Second string.'); + + instance.instances.forEach((instance) => { + expect(instance.queue).toHaveLength(28); + }); +}); + +test('Pauses and resumes typing.', () => { + + jest.useFakeTimers(); + + document.body.innerHTML = + `
' + +
`; + + const instance = new TypeIt('#element', { + strings: "Chicken nuggets." + }); + + //-- Pause typing. + instance.freeze(); + + instance.instances.forEach((instance) => { + expect(instance.isFrozen).toBe(true); + }); + + //-- Resume typing. + setTimeout(() => { + instance.unfreeze(); + }, 1000); + + jest.runAllTimers(); + + const typedString = document.querySelector('#element .ti-container').innerHTML; + + expect(typedString).toEqual('Chicken nuggets.'); + +}); + +test('Instance is marked complete successfully.', () => { + + jest.useFakeTimers(); + + document.body.innerHTML = + `
' + +
`; + + const instance = new TypeIt('#element', { + strings: ["Ham over turkey.", "Obviously."] + }); + + jest.runAllTimers(); + + const typedString = document.querySelector('#element .ti-container').innerHTML; + + //-- Typing should be complete with the correct string. + expect(instance.isComplete).toBe(true); + expect(typedString).toEqual('Ham over turkey.
Obviously.'); +}); + +test('Can type new string after completion.', () => { + + jest.useFakeTimers(); + + document.body.innerHTML = + `
' + +
`; + + const instance = new TypeIt('#element', { + strings: "Ham over turkey." + }); + + jest.runAllTimers(); + + let typedString = document.querySelector('#element .ti-container').innerHTML; + + expect(typedString).toEqual('Ham over turkey.'); + + instance.type(' Obviously.'); + + jest.runAllTimers(); + + typedString = document.querySelector('#element .ti-container').innerHTML; + + expect(typedString).toEqual('Ham over turkey. Obviously.'); +}); + +test('Wraps pauses correctly when replacing lines.', () => { + + document.body.innerHTML = + `
' + +
`; + + const instance = new TypeIt('#element', { + strings: ["Free markets...", "win."], + breakLines: false + }); + const firstInstance = instance.instances[0]; + const pause = firstInstance.options.nextStringDelay / 2; + + expect(firstInstance.queue[15][0].name).toBe('pause'); + expect(firstInstance.queue[15][1]).toBe(pause); + + expect(firstInstance.queue[31][0].name).toBe('pause'); + expect(firstInstance.queue[31][1]).toBe(pause); +}); + +test('Wraps pauses correctly when breaking lines.', () => { + + document.body.innerHTML = + `
' + +
`; + + const instance = new TypeIt('#element', { + nextStringDelay: 500, + strings: ["Free markets...", "win."] + }); + + const firstInstance = instance.instances[0]; + + expect(firstInstance.queue[15][0].name).toBe('pause'); + expect(firstInstance.queue[15][1]).toBe(250); + + expect(firstInstance.queue[17][0].name).toBe('pause'); + expect(firstInstance.queue[17][1]).toBe(250); +});