Socket
Socket
Sign inDemoInstall

typeit

Package Overview
Dependencies
1
Maintainers
1
Versions
117
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 8.7.1 to 8.8.0

dist/helpers/splitOnBreak.d.ts

2

dist/constants.d.ts

@@ -15,2 +15,2 @@ import { CursorOptions, Options } from "./types";

};
export declare const PLACEHOLDER_CSS: string;
export declare const PLACEHOLDER_CSS = "[data-typeit-id]:before {content: '.'; display: inline-block; width: 0; visibility: hidden;}";
/**
* Literally just wraps toArray() to save a few bytes
* when it's repeatedly used.
*
* @param {any}
* @return {array}
*/
declare const _default: (val: any) => any[];
export default _default;
// TypeIt by Alex MacArthur - https://typeitjs.com
const isArray = (thing) => Array.isArray(thing);
const asArray = (value) => {
return isArray(value) ? value : [value];
};
const asArray = (value) => isArray(value) ? value : [value];
let Queue = function(initialItems) {

@@ -42,5 +42,5 @@ let add = function(steps) {

wipe,
done,
reset,
destroy,
done,
getItems,

@@ -51,22 +51,3 @@ getQueue,

};
const toArray = (val) => Array.from(val);
const createTextNode = (content) => document.createTextNode(content);
let expandTextNodes = (element) => {
[...element.childNodes].forEach((child) => {
if (child.nodeValue) {
[...child.nodeValue].forEach((c) => {
child.parentNode.insertBefore(createTextNode(c), child);
});
child.remove();
return;
}
expandTextNodes(child);
});
return element;
};
const getParsedBody = (content) => {
let doc = document.implementation.createHTMLDocument();
doc.body.innerHTML = content;
return expandTextNodes(doc.body);
};
const DATA_ATTRIBUTE = "data-typeit-id";

@@ -122,2 +103,59 @@ const CURSOR_CLASS = "ti-cursor";

const PLACEHOLDER_CSS = `[${DATA_ATTRIBUTE}]:before {content: '.'; display: inline-block; width: 0; visibility: hidden;}`;
const createElement = (el) => document.createElement(el);
const createTextNode = (content) => document.createTextNode(content);
const appendStyleBlock = (styles, id = "") => {
let styleBlock = createElement("style");
styleBlock.id = id;
styleBlock.appendChild(createTextNode(styles));
document.head.appendChild(styleBlock);
};
const calculateDelay = (delayArg) => {
if (!isArray(delayArg)) {
delayArg = [delayArg / 2, delayArg / 2];
}
return delayArg;
};
const randomInRange = (value, range) => {
return Math.abs(
Math.random() * (value + range - (value - range)) + (value - range)
);
};
let range = (val) => val / 2;
function calculatePace(options) {
let { speed, deleteSpeed, lifeLike } = options;
deleteSpeed = deleteSpeed !== null ? deleteSpeed : speed / 3;
return lifeLike ? [
randomInRange(speed, range(speed)),
randomInRange(deleteSpeed, range(deleteSpeed))
] : [speed, deleteSpeed];
}
const toArray = (val) => Array.from(val);
let expandTextNodes = (element) => {
[...element.childNodes].forEach((child) => {
if (child.nodeValue) {
[...child.nodeValue].forEach((c) => {
child.parentNode.insertBefore(createTextNode(c), child);
});
child.remove();
return;
}
expandTextNodes(child);
});
return element;
};
const getParsedBody = (content) => {
let doc = document.implementation.createHTMLDocument();
doc.body.innerHTML = content;
return expandTextNodes(doc.body);
};
function walkElementNodes(element, shouldReverse = false, shouldIncludeCursor = false) {

@@ -154,135 +192,5 @@ let cursor = element.querySelector(`.${CURSOR_CLASS}`);

}
const createElement = (el) => document.createElement(el);
const appendStyleBlock = (styles, id = "") => {
let styleBlock = createElement("style");
styleBlock.id = id;
styleBlock.appendChild(createTextNode(styles));
document.head.appendChild(styleBlock);
};
const calculateDelay = (delayArg) => {
if (!isArray(delayArg)) {
delayArg = [delayArg / 2, delayArg / 2];
}
return delayArg;
};
const randomInRange = (value, range2) => {
return Math.abs(
Math.random() * (value + range2 - (value - range2)) + (value - range2)
);
};
let range = (val) => val / 2;
function calculatePace(options) {
let { speed, deleteSpeed, lifeLike } = options;
deleteSpeed = deleteSpeed !== null ? deleteSpeed : speed / 3;
return lifeLike ? [
randomInRange(speed, range(speed)),
randomInRange(deleteSpeed, range(deleteSpeed))
] : [speed, deleteSpeed];
}
const destroyTimeouts = (timeouts) => {
timeouts.forEach(clearTimeout);
return [];
};
const generateHash = () => Math.random().toString().substring(2, 9);
const isInput = (el) => "value" in el;
let getAllChars = (element) => {
if (isInput(element)) {
return toArray(element.value);
}
return walkElementNodes(element, true).filter(
(c) => !(c.childNodes.length > 0)
);
};
const fireWhenVisible = (element, func) => {
let observer = new IntersectionObserver(
(entries, observer2) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
func();
observer2.unobserve(element);
}
});
},
{ threshold: 1 }
);
observer.observe(element);
};
let handleFunctionalArg = (arg) => {
return typeof arg === "function" ? arg() : arg;
};
const isNumber = (value) => Number.isInteger(value);
let select = (selector, element = document, all = false) => {
return element[`querySelector${all ? "All" : ""}`](selector);
};
let isBodyElement = (node) => /body/i.test(node?.tagName);
let insertIntoElement = (originalTarget, character) => {
if (isInput(originalTarget)) {
originalTarget.value = `${originalTarget.value}${character.textContent}`;
return;
}
character.innerHTML = "";
let target = isBodyElement(character.originalParent) ? originalTarget : character.originalParent || originalTarget;
target.insertBefore(
character,
select("." + CURSOR_CLASS, target) || null
);
};
let updateCursorPosition = (steps, cursorPosition, printedCharacters) => {
return Math.min(
Math.max(cursorPosition + steps, 0),
printedCharacters.length
);
};
const merge = (originalObj, newObj) => Object.assign({}, originalObj, newObj);
const removeNode = (node, rootElement) => {
if (!node)
return;
let nodeParent = node.parentNode;
let nodeToRemove = nodeParent.childNodes.length > 1 || nodeParent.isSameNode(rootElement) ? node : nodeParent;
nodeToRemove.remove();
};
const repositionCursor = (element, allChars, newCursorPosition) => {
let nodeToInsertBefore = allChars[newCursorPosition - 1];
let cursor = select(`.${CURSOR_CLASS}`, element);
element = nodeToInsertBefore?.parentNode || element;
element.insertBefore(cursor, nodeToInsertBefore || null);
};
function selectorToElement(thing) {
return typeof thing === "string" ? select(thing) : thing;
}
const isNonVoidElement = (el) => /<(.+)>(.*?)<\/(.+)>/.test(el.outerHTML);
let wait = (callback, delay, timeouts) => {
return new Promise((resolve) => {
let cb = async () => {
await callback();
resolve();
};
timeouts.push(setTimeout(cb, delay || 0));
});
};
let cursorFontStyles = {
"font-family": "",
"font-weight": "",
"font-size": "",
"font-style": "",
"line-height": "",
color: "",
transform: "translateX(-.125em)"
};
let setCursorStyles = (id, element) => {
let rootSelector = `[${DATA_ATTRIBUTE}='${id}']`;
let cursorSelector = `${rootSelector} .${CURSOR_CLASS}`;
let computedStyles = getComputedStyle(element);
let customProperties = Object.entries(cursorFontStyles).reduce(
(accumulator, [item, value]) => {
return `${accumulator} ${item}: var(--ti-cursor-${item}, ${value || computedStyles[item]});`;
},
""
);
appendStyleBlock(
`${cursorSelector} { display: inline-block; width: 0; ${customProperties} }`,
id
);
};
const duplicate = (value, times) => new Array(times).fill(value);
const countStepsToSelector = ({

@@ -312,2 +220,10 @@ queueItems,

};
const destroyTimeouts = (timeouts) => {
timeouts.forEach(clearTimeout);
return [];
};
const duplicate = (value, times) => new Array(times).fill(value);
let beforePaint = (cb) => {

@@ -320,2 +236,3 @@ return new Promise((resolve) => {

};
let getAnimationFromElement = (element) => {

@@ -326,2 +243,3 @@ return element?.getAnimations().find((animation) => {

};
let setCursorAnimation = ({

@@ -342,2 +260,3 @@ cursor,

};
let rebuildCursorAnimation = ({

@@ -367,2 +286,3 @@ cursor,

};
let execute = (queueItem) => queueItem.func?.call(null);

@@ -372,3 +292,3 @@ let fireItem = async ({

queueItems,
wait: wait2,
wait,
cursor,

@@ -404,3 +324,3 @@ cursorOptions

}
await wait2(async () => {
await wait(async () => {
if (animation && shouldPauseCursor) {

@@ -420,2 +340,62 @@ animation.cancel();

};
const fireWhenVisible = (element, func) => {
let observer = new IntersectionObserver(
(entries, observer2) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
func();
observer2.unobserve(element);
}
});
},
{ threshold: 1 }
);
observer.observe(element);
};
const generateHash = () => Math.random().toString().substring(2, 9);
const isInput = (el) => "value" in el;
let getAllChars = (element) => {
if (isInput(element)) {
return toArray(element.value);
}
return walkElementNodes(element, true).filter(
(c) => !(c.childNodes.length > 0)
);
};
let handleFunctionalArg = (arg) => {
return typeof arg === "function" ? arg() : arg;
};
let select = (selector, element = document, all = false) => {
return element[`querySelector${all ? "All" : ""}`](selector);
};
let isBodyElement = (node) => /body/i.test(node?.tagName);
let insertIntoElement = (originalTarget, character) => {
if (isInput(originalTarget)) {
originalTarget.value = `${originalTarget.value}${character.textContent}`;
return;
}
character.innerHTML = "";
let target = isBodyElement(character.originalParent) ? originalTarget : (
// If we add one-off fresh elements, there will be no
// "originalParent", so always fall back to the default target.
character.originalParent || originalTarget
);
target.insertBefore(
character,
select("." + CURSOR_CLASS, target) || null
);
};
const isNonVoidElement = (el) => /<(.+)>(.*?)<\/(.+)>/.test(el.outerHTML);
const merge = (originalObj, newObj) => Object.assign({}, originalObj, newObj);
let processCursorOptions = (cursorOptions) => {

@@ -440,210 +420,175 @@ if (typeof cursorOptions === "object") {

};
const TypeIt = function(element, options = {}) {
let _wait = async (callback, delay, silent = false) => {
if (_statuses.frozen) {
await new Promise((resolve) => {
this.unfreeze = () => {
_statuses.frozen = false;
resolve();
};
});
}
silent || await _opts.beforeStep(this);
await wait(callback, delay, _timeouts);
silent || await _opts.afterStep(this);
const removeNode = (node, rootElement) => {
if (!node)
return;
let nodeParent = node.parentNode;
let nodeToRemove = nodeParent.childNodes.length > 1 || nodeParent.isSameNode(rootElement) ? (
// This parent still needs to exist.
node
) : (
// There's nothing else in there, so just delete the entire thing.
// By doing this, we clean up markup as we go along.
nodeParent
);
nodeToRemove.remove();
};
const repositionCursor = (element, allChars, newCursorPosition) => {
let nodeToInsertBefore = allChars[newCursorPosition - 1];
let cursor = select(`.${CURSOR_CLASS}`, element);
element = nodeToInsertBefore?.parentNode || element;
element.insertBefore(cursor, nodeToInsertBefore || null);
};
function selectorToElement(thing) {
return typeof thing === "string" ? select(thing) : thing;
}
let cursorFontStyles = {
"font-family": "",
"font-weight": "",
"font-size": "",
"font-style": "",
"line-height": "",
color: "",
transform: "translateX(-.125em)"
};
let setCursorStyles = (id, element) => {
let rootSelector = `[${DATA_ATTRIBUTE}='${id}']`;
let cursorSelector = `${rootSelector} .${CURSOR_CLASS}`;
let computedStyles = getComputedStyle(element);
let customProperties = Object.entries(cursorFontStyles).reduce(
(accumulator, [item, value]) => {
return `${accumulator} ${item}: var(--ti-cursor-${item}, ${value || computedStyles[item]});`;
},
""
);
appendStyleBlock(
`${cursorSelector} { display: inline-block; width: 0; ${customProperties} }`,
id
);
};
function splitOnBreak(str) {
return str.replace(/<!--(.+?)-->/g, "").trim().split(/<br(?:\s*?)(?:\/)?>/);
}
let updateCursorPosition = (steps, cursorPosition, printedCharacters) => {
return Math.min(
Math.max(cursorPosition + steps, 0),
printedCharacters.length
);
};
let wait = (callback, delay, timeouts) => {
return new Promise((resolve) => {
let cb = async () => {
await callback();
resolve();
};
timeouts.push(setTimeout(cb, delay || 0));
});
};
class TypeIt {
element;
timeouts;
cursorPosition;
predictedCursorPosition;
statuses = {
started: false,
completed: false,
frozen: false,
destroyed: false
};
let _fireItemWithContext = (index, queueItems) => {
return fireItem({
index,
queueItems,
wait: _wait,
cursor: _cursor,
cursorOptions: _opts.cursor
});
opts;
id;
queue;
cursor;
unfreeze = () => {
};
let _removeNode = (node) => removeNode(node, _element);
let _elementIsInput = () => isInput(_element);
let _getPace = (index = 0) => calculatePace(_opts)[index];
let _getAllChars = () => getAllChars(_element);
let _maybeAppendPause = (opts = {}) => {
let delay = opts.delay;
delay && _queue.add({ delay });
};
let _queueAndReturn = (steps, opts) => {
_queue.add(steps);
_maybeAppendPause(opts);
return this;
};
let _getDerivedCursorPosition = () => _predictedCursorPosition ?? _cursorPosition;
let _generateTemporaryOptionQueueItems = (newOptions = {}) => {
return [
{ func: () => _options(newOptions) },
{ func: () => _options(_opts) }
];
};
let _addSplitPause = (items) => {
let delay = _opts.nextStringDelay;
_queue.add([{ delay: delay[0] }, ...items, { delay: delay[1] }]);
};
let _setUpCursor = () => {
if (_elementIsInput()) {
return;
constructor(element, options = {}) {
this.opts = merge(DEFAULT_OPTIONS, options);
this.element = selectorToElement(element);
this.timeouts = [];
this.cursorPosition = 0;
this.unfreeze = () => {
};
this.predictedCursorPosition = null;
this.statuses = merge({}, DEFAULT_STATUSES);
this.id = generateHash();
this.queue = Queue([{ delay: this.opts.startDelay }]);
this.#buildOptions(options);
this.cursor = this.#setUpCursor();
this.element.dataset.typeitId = this.id;
appendStyleBlock(PLACEHOLDER_CSS);
if (this.opts.strings.length) {
this.#generateQueue();
}
let cursor = createElement("span");
cursor.className = CURSOR_CLASS;
if (!_shouldRenderCursor) {
cursor.style.visibility = "hidden";
return cursor;
}
/**
* Can only be called once.
*/
go() {
if (this.statuses.started) {
return this;
}
cursor.innerHTML = getParsedBody(_opts.cursorChar).innerHTML;
return cursor;
};
let _attachCursor = async () => {
!_elementIsInput() && _cursor && _element.appendChild(_cursor);
if (_shouldRenderCursor) {
setCursorStyles(_id, _element);
_cursor.dataset.tiAnimationId = _id;
let { animation } = _opts.cursor;
let { frames, options: options2 } = animation;
setCursorAnimation({
frames,
cursor: _cursor,
options: {
duration: _opts.cursorSpeed,
...options2
}
});
this.#attachCursor();
if (!this.opts.waitUntilVisible) {
this.#fire();
return this;
}
};
let _generateQueue = () => {
let strings = _opts.strings.filter((string) => !!string);
strings.forEach((string, index) => {
this.type(string);
if (index + 1 === strings.length) {
return;
}
let splitItems = _opts.breakLines ? [{ func: () => _type(createElement("BR")), typeable: true }] : duplicate(
{
func: _delete,
delay: _getPace(1)
},
_queue.getTypeable().length
);
_addSplitPause(splitItems);
});
};
let _prepLoop = async (delay) => {
let derivedCursorPosition = _getDerivedCursorPosition();
derivedCursorPosition && await _move({ value: derivedCursorPosition });
let queueItems = _getAllChars().map((c) => {
return [
Symbol(),
{
func: _delete,
delay: _getPace(1),
deletable: true,
shouldPauseCursor: () => true
}
];
});
for (let index = 0; index < queueItems.length; index++) {
await _fireItemWithContext(index, queueItems);
fireWhenVisible(this.element, this.#fire.bind(this));
return this;
}
destroy(shouldRemoveCursor = true) {
this.timeouts = destroyTimeouts(this.timeouts);
handleFunctionalArg(shouldRemoveCursor) && this.cursor && this.#removeNode(this.cursor);
this.statuses.destroyed = true;
}
reset(rebuild) {
!this.is("destroyed") && this.destroy();
if (rebuild) {
this.queue.wipe();
rebuild(this);
} else {
this.queue.reset();
}
_queue.reset();
_queue.set(0, { delay });
};
let _maybePrependHardcodedStrings = (strings) => {
let existingMarkup = _element.innerHTML;
if (!existingMarkup) {
return strings;
this.cursorPosition = 0;
for (let property in this.statuses) {
this.statuses[property] = false;
}
_element.innerHTML = "";
if (_opts.startDelete) {
_element.innerHTML = existingMarkup;
expandTextNodes(_element);
_addSplitPause(
duplicate(
{
func: _delete,
delay: _getPace(1),
deletable: true
},
_getAllChars().length
)
);
return strings;
}
let hardCodedStrings = existingMarkup.replace(/<!--(.+?)-->/g, "").trim().split(/<br(?:\s*?)(?:\/)?>/);
return hardCodedStrings.concat(strings);
};
let _fire = async (remember = true) => {
_statuses.started = true;
let cleanUp = (qKey) => {
_queue.done(qKey, !remember);
};
try {
let queueItems = [..._queue.getQueue()];
for (let index = 0; index < queueItems.length; index++) {
let [queueKey, queueItem] = queueItems[index];
if (queueItem.done)
continue;
if (!queueItem.deletable || queueItem.deletable && _getAllChars().length) {
let newIndex = await _fireItemWithContext(index, queueItems);
Array(newIndex - index).fill(index + 1).map((x, y) => x + y).forEach((i) => {
let [key] = queueItems[i];
cleanUp(key);
});
index = newIndex;
}
cleanUp(queueKey);
}
if (!remember) {
return this;
}
_statuses.completed = true;
await _opts.afterComplete(this);
if (!_opts.loop) {
throw "";
}
let delay = _opts.loopDelay;
_wait(async () => {
await _prepLoop(delay[0]);
_fire();
}, delay[1]);
} catch (e) {
}
this.element[this.#elementIsInput() ? "value" : "innerHTML"] = "";
return this;
}
is = function(key) {
return this.statuses[key];
};
let _move = async (step) => {
_cursorPosition = updateCursorPosition(
step,
_cursorPosition,
_getAllChars()
);
repositionCursor(_element, _getAllChars(), _cursorPosition);
};
let _type = (char) => insertIntoElement(_element, char);
let _options = async (opts) => _opts = merge(_opts, opts);
let _empty = async () => {
if (_elementIsInput()) {
_element.value = "";
return;
}
_getAllChars().forEach(_removeNode);
return;
};
let _delete = () => {
let allChars = _getAllChars();
if (!allChars.length)
return;
if (_elementIsInput()) {
_element.value = _element.value.slice(0, -1);
} else {
_removeNode(allChars[_cursorPosition]);
}
};
this.break = function(actionOpts) {
return _queueAndReturn(
type(string, actionOpts = {}) {
string = handleFunctionalArg(string);
let { instant } = actionOpts;
let bookEndQueueItems = this.#generateTemporaryOptionQueueItems(actionOpts);
let chars = maybeChunkStringAsHtml(string, this.opts.html);
let charsAsQueueItems = chars.map((char) => {
return {
func: () => this.#type(char),
char,
delay: instant || isNonVoidElement(char) ? 0 : this.#getPace(),
typeable: char.nodeType === Node.TEXT_NODE
};
});
let itemsToQueue = [
bookEndQueueItems[0],
{ func: async () => await this.opts.beforeString(string, this) },
...charsAsQueueItems,
{ func: async () => await this.opts.afterString(string, this) },
bookEndQueueItems[1]
];
return this.#queueAndReturn(itemsToQueue, actionOpts);
}
break(actionOpts = {}) {
return this.#queueAndReturn(
{
func: () => _type(createElement("BR")),
func: () => this.#type(createElement("BR")),
typeable: true

@@ -653,9 +598,55 @@ },

);
};
this.delete = function(numCharacters = null, actionOpts = {}) {
}
move(movementArg, actionOpts = {}) {
movementArg = handleFunctionalArg(movementArg);
let bookEndQueueItems = this.#generateTemporaryOptionQueueItems(actionOpts);
let { instant, to } = actionOpts;
let numberOfSteps = countStepsToSelector({
queueItems: this.queue.getTypeable(),
selector: movementArg === null ? "" : movementArg,
to,
cursorPosition: this.#derivedCursorPosition
});
let directionalStep = numberOfSteps < 0 ? -1 : 1;
this.predictedCursorPosition = this.#derivedCursorPosition + numberOfSteps;
return this.#queueAndReturn(
[
bookEndQueueItems[0],
...duplicate(
{
func: () => this.#move(directionalStep),
delay: instant ? 0 : this.#getPace(),
cursorable: true
},
Math.abs(numberOfSteps)
),
bookEndQueueItems[1]
],
actionOpts
);
}
exec(func, actionOpts = {}) {
let bookEndQueueItems = this.#generateTemporaryOptionQueueItems(actionOpts);
return this.#queueAndReturn(
[bookEndQueueItems[0], { func: () => func(this) }, bookEndQueueItems[1]],
actionOpts
);
}
options(opts, actionOpts = {}) {
opts = handleFunctionalArg(opts);
this.#updateOptions(opts);
return this.#queueAndReturn({}, actionOpts);
}
pause(milliseconds, actionOpts = {}) {
return this.#queueAndReturn(
{ delay: handleFunctionalArg(milliseconds) },
actionOpts
);
}
delete(numCharacters = null, actionOpts = {}) {
numCharacters = handleFunctionalArg(numCharacters);
let bookEndQueueItems = _generateTemporaryOptionQueueItems(actionOpts);
let bookEndQueueItems = this.#generateTemporaryOptionQueueItems(actionOpts);
let num = numCharacters;
let { instant, to } = actionOpts;
let typeableQueueItems = _queue.getTypeable();
let typeableQueueItems = this.queue.getTypeable();
let rounds = (() => {

@@ -671,7 +662,7 @@ if (num === null) {

selector: num,
cursorPosition: _getDerivedCursorPosition(),
cursorPosition: this.#derivedCursorPosition,
to
});
})();
return _queueAndReturn(
return this.#queueAndReturn(
[

@@ -681,4 +672,4 @@ bookEndQueueItems[0],

{
func: _delete,
delay: instant ? 0 : _getPace(1),
func: this.#delete.bind(this),
delay: instant ? 0 : this.#getPace(1),
deletable: true

@@ -692,151 +683,293 @@ },

);
};
this.empty = function(actionOpts = {}) {
return _queueAndReturn({ func: _empty }, actionOpts);
};
this.exec = function(func, actionOpts = {}) {
let bookEndQueueItems = _generateTemporaryOptionQueueItems(actionOpts);
return _queueAndReturn(
[bookEndQueueItems[0], { func: () => func(this) }, bookEndQueueItems[1]],
actionOpts
}
freeze() {
this.statuses.frozen = true;
}
/**
* Like `.go()`, but more... "off the grid."
*
* - won't trigger `afterComplete` callback
* - items won't be replayed after `.reset()`
*
* When called, all non-done items will be "flushed" --
* that is, executed, but not remembered.
*/
flush(cb = () => {
}) {
this.#attachCursor();
this.#fire(false).then(cb);
return this;
}
getQueue() {
return this.queue;
}
getOptions() {
return this.opts;
}
updateOptions(options) {
return this.#updateOptions(options);
}
getElement() {
return this.element;
}
empty(actionOpts = {}) {
return this.#queueAndReturn({ func: this.#empty.bind(this) }, actionOpts);
}
async #empty() {
if (this.#elementIsInput()) {
this.element.value = "";
return;
}
this.#allChars.forEach(this.#removeNode.bind(this));
return;
}
/**
* Execute items in the queue.
*
* @param remember If false, each queue item will be destroyed once executed.
* @returns
*/
async #fire(remember = true) {
this.statuses.started = true;
let cleanUp = (qKey) => {
this.queue.done(qKey, !remember);
};
try {
let queueItems = [...this.queue.getQueue()];
for (let index = 0; index < queueItems.length; index++) {
let [queueKey, queueItem] = queueItems[index];
if (queueItem.done)
continue;
if (!queueItem.deletable || queueItem.deletable && this.#allChars.length) {
let newIndex = await this.#fireItemWithContext(index, queueItems);
Array(newIndex - index).fill(index + 1).map((x, y) => x + y).forEach((i) => {
let [key] = queueItems[i];
cleanUp(key);
});
index = newIndex;
}
cleanUp(queueKey);
}
if (!remember) {
return this;
}
this.statuses.completed = true;
await this.opts.afterComplete(this);
if (!this.opts.loop) {
throw "";
}
let delay = this.opts.loopDelay;
this.#wait(async () => {
await this.#prepLoop(delay[0]);
this.#fire();
}, delay[1]);
} catch (e) {
}
return this;
}
async #move(step) {
this.cursorPosition = updateCursorPosition(
step,
this.cursorPosition,
this.#allChars
);
};
this.move = function(movementArg, actionOpts = {}) {
movementArg = handleFunctionalArg(movementArg);
let bookEndQueueItems = _generateTemporaryOptionQueueItems(actionOpts);
let { instant, to } = actionOpts;
let numberOfSteps = countStepsToSelector({
queueItems: _queue.getTypeable(),
selector: movementArg === null ? "" : movementArg,
to,
cursorPosition: _getDerivedCursorPosition()
repositionCursor(this.element, this.#allChars, this.cursorPosition);
}
/**
* 1. Reset queue.
* 2. Reset initial pause.
*/
async #prepLoop(delay) {
let derivedCursorPosition = this.#derivedCursorPosition;
derivedCursorPosition && await this.#move({ value: derivedCursorPosition });
let queueItems = this.#allChars.map((c) => {
return [
Symbol(),
{
func: this.#delete.bind(this),
delay: this.#getPace(1),
deletable: true,
shouldPauseCursor: () => true
}
];
});
let directionalStep = numberOfSteps < 0 ? -1 : 1;
_predictedCursorPosition = _getDerivedCursorPosition() + numberOfSteps;
return _queueAndReturn(
[
bookEndQueueItems[0],
...duplicate(
{
func: () => _move(directionalStep),
delay: instant ? 0 : _getPace(),
cursorable: true
},
Math.abs(numberOfSteps)
),
bookEndQueueItems[1]
],
actionOpts
for (let index = 0; index < queueItems.length; index++) {
await this.#fireItemWithContext(index, queueItems);
}
this.queue.reset();
this.queue.set(0, { delay });
}
#fireItemWithContext(index, queueItems) {
return fireItem({
index,
queueItems,
wait: this.#wait.bind(this),
cursor: this.cursor,
cursorOptions: this.opts.cursor
});
}
async #wait(callback, delay, silent = false) {
if (this.statuses.frozen) {
await new Promise((resolve) => {
this.unfreeze = () => {
this.statuses.frozen = false;
resolve();
};
});
}
silent || await this.opts.beforeStep(this);
await wait(callback, delay, this.timeouts);
silent || await this.opts.afterStep(this);
}
/**
* Attach it to the DOM so, along with the required CSS transition.
*/
async #attachCursor() {
!this.#elementIsInput() && this.cursor && this.element.appendChild(this.cursor);
if (this.#shouldRenderCursor) {
setCursorStyles(this.id, this.element);
this.cursor.dataset.tiAnimationId = this.id;
let { animation } = this.opts.cursor;
let { frames, options } = animation;
setCursorAnimation({
frames,
cursor: this.cursor,
options: {
duration: this.opts.cursorSpeed,
...options
}
});
}
}
#elementIsInput() {
return isInput(this.element);
}
#queueAndReturn(steps, opts) {
this.queue.add(steps);
this.#maybeAppendPause(opts);
return this;
}
#maybeAppendPause(opts = {}) {
let delay = opts.delay;
delay && this.queue.add({ delay });
}
#generateTemporaryOptionQueueItems(newOptions = {}) {
return [
{ func: () => this.#updateOptions(newOptions) },
{ func: () => this.#updateOptions(this.opts) }
];
}
async #updateOptions(opts) {
this.opts = merge(this.opts, opts);
}
/**
* Based on provided strings, generate a TypeIt queue
* to be fired for each character in the string.
*/
#generateQueue() {
let strings = this.opts.strings.filter((string) => !!string);
strings.forEach((string, index) => {
this.type(string);
if (index + 1 === strings.length) {
return;
}
let splitItems = this.opts.breakLines ? [{ func: () => this.#type(createElement("BR")), typeable: true }] : duplicate(
{
func: this.#delete.bind(this),
delay: this.#getPace(1)
},
this.queue.getTypeable().length
);
this.#addSplitPause(splitItems);
});
}
#buildOptions = (options) => {
options.cursor = processCursorOptions(
options.cursor ?? DEFAULT_OPTIONS.cursor
);
};
this.options = function(opts, actionOpts = {}) {
opts = handleFunctionalArg(opts);
_options(opts);
return _queueAndReturn({}, actionOpts);
};
this.pause = function(milliseconds, actionOpts = {}) {
return _queueAndReturn(
{ delay: handleFunctionalArg(milliseconds) },
actionOpts
this.opts.strings = this.#prependHardcodedStrings(
asArray(this.opts.strings)
);
};
this.type = function(string, actionOpts = {}) {
string = handleFunctionalArg(string);
let { instant } = actionOpts;
let bookEndQueueItems = _generateTemporaryOptionQueueItems(actionOpts);
let chars = maybeChunkStringAsHtml(string, _opts.html);
let charsAsQueueItems = chars.map((char) => {
return {
func: () => _type(char),
char,
delay: instant || isNonVoidElement(char) ? 0 : _getPace(),
typeable: char.nodeType === Node.TEXT_NODE
};
this.opts = merge(this.opts, {
html: !this.#isInput && this.opts.html,
nextStringDelay: calculateDelay(this.opts.nextStringDelay),
loopDelay: calculateDelay(this.opts.loopDelay)
});
let itemsToQueue = [
bookEndQueueItems[0],
{ func: async () => await _opts.beforeString(string, this) },
...charsAsQueueItems,
{ func: async () => await _opts.afterString(string, this) },
bookEndQueueItems[1]
];
return _queueAndReturn(itemsToQueue, actionOpts);
};
this.is = function(key) {
return _statuses[key];
};
this.destroy = function(shouldRemoveCursor = true) {
_timeouts = destroyTimeouts(_timeouts);
handleFunctionalArg(shouldRemoveCursor) && _cursor && _removeNode(_cursor);
_statuses.destroyed = true;
};
this.freeze = function() {
_statuses.frozen = true;
};
this.unfreeze = () => {
};
this.reset = function(rebuild) {
!this.is("destroyed") && this.destroy();
if (rebuild) {
_queue.wipe();
rebuild(this);
} else {
_queue.reset();
#prependHardcodedStrings(strings) {
let existingMarkup = this.element.innerHTML;
if (!existingMarkup) {
return strings;
}
_cursorPosition = 0;
for (let property in _statuses) {
_statuses[property] = false;
this.element.innerHTML = "";
if (this.opts.startDelete) {
this.element.innerHTML = existingMarkup;
expandTextNodes(this.element);
this.#addSplitPause(
duplicate(
{
func: this.#delete.bind(this),
delay: this.#getPace(1),
deletable: true
},
this.#allChars.length
)
);
return strings;
}
_element[_elementIsInput() ? "value" : "innerHTML"] = "";
return this;
};
this.go = function() {
if (_statuses.started) {
return this;
return splitOnBreak(existingMarkup).concat(strings);
}
/**
* Provided it's a non-form element and the options is provided,
* set up the cursor element for the animation.
*/
#setUpCursor() {
if (this.#isInput) {
return null;
}
_attachCursor();
if (!_opts.waitUntilVisible) {
_fire();
return this;
let cursor = createElement("span");
cursor.className = CURSOR_CLASS;
if (!this.#shouldRenderCursor) {
cursor.style.visibility = "hidden";
return cursor;
}
fireWhenVisible(_element, _fire.bind(this));
return this;
};
this.flush = function(cb = () => {
}) {
_attachCursor();
_fire(false).then(cb);
return this;
};
this.getQueue = () => _queue;
this.getOptions = () => _opts;
this.updateOptions = (options2) => _options(options2);
this.getElement = () => _element;
let _element = selectorToElement(element);
let _timeouts = [];
let _cursorPosition = 0;
let _predictedCursorPosition = null;
let _statuses = merge({}, DEFAULT_STATUSES);
options.cursor = processCursorOptions(
options.cursor ?? DEFAULT_OPTIONS.cursor
);
let _opts = merge(DEFAULT_OPTIONS, options);
_opts = merge(_opts, {
html: !_elementIsInput() && _opts.html,
nextStringDelay: calculateDelay(_opts.nextStringDelay),
loopDelay: calculateDelay(_opts.loopDelay)
});
let _id = generateHash();
let _queue = Queue([{ delay: _opts.startDelay }]);
_element.dataset.typeitId = _id;
appendStyleBlock(PLACEHOLDER_CSS);
let _shouldRenderCursor = !!_opts.cursor && !_elementIsInput();
let _cursor = _setUpCursor();
_opts.strings = _maybePrependHardcodedStrings(asArray(_opts.strings));
if (_opts.strings.length) {
_generateQueue();
cursor.innerHTML = getParsedBody(this.opts.cursorChar).innerHTML;
return cursor;
}
};
export {
TypeIt as default
};
#addSplitPause(items) {
let delay = this.opts.nextStringDelay;
this.queue.add([{ delay: delay[0] }, ...items, { delay: delay[1] }]);
}
#type(char) {
insertIntoElement(this.element, char);
}
#delete() {
if (!this.#allChars.length)
return;
if (this.#isInput) {
this.element.value = this.element.value.slice(0, -1);
} else {
this.#removeNode(this.#allChars[this.cursorPosition]);
}
}
#removeNode(node) {
removeNode(node, this.element);
}
#getPace(index = 0) {
return calculatePace(this.opts)[index];
}
get #derivedCursorPosition() {
return this.predictedCursorPosition ?? this.cursorPosition;
}
get #isInput() {
return isInput(this.element);
}
get #shouldRenderCursor() {
return !!this.opts.cursor && !this.#isInput;
}
get #allChars() {
return getAllChars(this.element);
}
}
export { TypeIt as default };
// TypeIt by Alex MacArthur - https://typeitjs.com
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).TypeIt=t()}(this,(function(){"use strict";const e=e=>Array.isArray(e),t=t=>e(t)?t:[t];const n=e=>Array.from(e),r=e=>document.createTextNode(e);let i=e=>([...e.childNodes].forEach((e=>{if(e.nodeValue)return[...e.nodeValue].forEach((t=>{e.parentNode.insertBefore(r(t),e)})),void e.remove();i(e)})),e);const a=e=>{let t=document.implementation.createHTMLDocument();return t.body.innerHTML=e,i(t.body)},o="data-typeit-id",s="ti-cursor",l={started:!1,completed:!1,frozen:!1,destroyed:!1},u={breakLines:!0,cursor:{autoPause:!0,autoPauseDelay:500,animation:{frames:[0,0,1].map((e=>({opacity:e}))),options:{iterations:1/0,easing:"steps(2, start)",fill:"forwards"}}},cursorChar:"|",cursorSpeed:1e3,deleteSpeed:null,html:!0,lifeLike:!0,loop:!1,loopDelay:750,nextStringDelay:750,speed:100,startDelay:250,startDelete:!1,strings:[],waitUntilVisible:!1,beforeString:()=>{},afterString:()=>{},beforeStep:()=>{},afterStep:()=>{},afterComplete:()=>{}},c=`[${o}]:before {content: '.'; display: inline-block; width: 0; visibility: hidden;}`;function d(e,t=!1,n=!1){let r,i=e.querySelector(`.${s}`),a=document.createTreeWalker(e,NodeFilter.SHOW_ALL,{acceptNode:e=>{if(i&&n){if(e.classList?.contains(s))return NodeFilter.FILTER_ACCEPT;if(i.contains(e))return NodeFilter.FILTER_REJECT}return e.classList?.contains(s)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT}}),o=[];for(;r=a.nextNode();)r.originalParent||(r.originalParent=r.parentNode),o.push(r);return t?o.reverse():o}function f(e,t=!0){return t?d(a(e)):n(e).map(r)}const h=e=>document.createElement(e),y=(e,t="")=>{let n=h("style");n.id=t,n.appendChild(r(e)),document.head.appendChild(n)},p=t=>(e(t)||(t=[t/2,t/2]),t),m=(e,t)=>Math.abs(Math.random()*(e+t-(e-t))+(e-t));let g=e=>e/2;const b=e=>"value"in e;let w=e=>"function"==typeof e?e():e;const T=e=>Number.isInteger(e);let v=(e,t=document,n=!1)=>t["querySelector"+(n?"All":"")](e);const E=(e,t)=>Object.assign({},e,t);let P={"font-family":"","font-weight":"","font-size":"","font-style":"","line-height":"",color:"",transform:"translateX(-.125em)"};const S=(e,t)=>new Array(t).fill(e),N=({queueItems:e,selector:t,cursorPosition:n,to:r})=>{if(T(t))return-1*t;let i=new RegExp("END","i").test(r),a=t?[...e].reverse().findIndex((({char:e})=>{let n=e.parentElement,r=n.matches(t);return!(!i||!r)||r&&n.firstChild.isSameNode(e)})):-1;return a<0&&(a=i?0:e.length-1),a-n+(i?0:1)};let L=e=>new Promise((t=>{requestAnimationFrame((async()=>{t(await e())}))})),C=e=>e?.getAnimations().find((t=>t.id===e.dataset.tiAnimationId)),D=({cursor:e,frames:t,options:n})=>{let r=e.animate(t,n);return r.pause(),r.id=e.dataset.tiAnimationId,L((()=>{L((()=>{r.play()}))})),r},I=e=>e.func?.call(null),M=async({index:e,queueItems:t,wait:n,cursor:r,cursorOptions:i})=>{let a=t[e][1],o=[],s=e,l=a,u=()=>l&&!l.delay,c=a.shouldPauseCursor()&&i.autoPause;for(;u();)o.push(l),u()&&s++,l=t[s]?t[s][1]:null;if(o.length)return await L((async()=>{for(let e of o)await I(e)})),s-1;let d,f=C(r);return f&&(d={...f.effect.getComputedTiming(),delay:c?i.autoPauseDelay:0}),await n((async()=>{f&&c&&f.cancel(),await L((()=>{I(a)}))}),a.delay),await(({cursor:e,options:t,cursorOptions:n})=>{if(!e||!n)return;let r,i=C(e);i&&(t.delay=i.effect.getComputedTiming().delay,r=i.currentTime,i.cancel());let a=D({cursor:e,frames:n.animation.frames,options:t});return r&&(a.currentTime=r),a})({cursor:r,options:d,cursorOptions:i}),e};return function(e,r={}){let L=async(e,t,n=!1)=>{K.frozen&&await new Promise((e=>{this.unfreeze=()=>{K.frozen=!1,e()}})),n||await Y.beforeStep(this),await((e,t,n)=>new Promise((r=>{n.push(setTimeout((async()=>{await e(),r()}),t||0))})))(e,t,W),n||await Y.afterStep(this)},C=(e,t)=>M({index:e,queueItems:t,wait:L,cursor:ne,cursorOptions:Y.cursor}),I=e=>((e,t)=>{if(!e)return;let n=e.parentNode;(n.childNodes.length>1||n.isSameNode(t)?e:n).remove()})(e,J),x=()=>b(J),A=(e=0)=>function(e){let{speed:t,deleteSpeed:n,lifeLike:r}=e;return n=null!==n?n:t/3,r?[m(t,g(t)),m(n,g(n))]:[t,n]}(Y)[e],$=()=>(e=>b(e)?n(e.value):d(e,!0).filter((e=>!(e.childNodes.length>0))))(J),H=(e,t)=>(ee.add(e),((e={})=>{let t=e.delay;t&&ee.add({delay:t})})(t),this),O=()=>G??X,F=(e={})=>[{func:()=>j(e)},{func:()=>j(Y)}],k=e=>{let t=Y.nextStringDelay;ee.add([{delay:t[0]},...e,{delay:t[1]}])},R=async()=>{if(!x()&&ne&&J.appendChild(ne),te){((e,t)=>{let n=`[${o}='${e}'] .${s}`,r=getComputedStyle(t),i=Object.entries(P).reduce(((e,[t,n])=>`${e} ${t}: var(--ti-cursor-${t}, ${n||r[t]});`),"");y(`${n} { display: inline-block; width: 0; ${i} }`,e)})(Z,J),ne.dataset.tiAnimationId=Z;let{animation:e}=Y.cursor,{frames:t,options:n}=e;D({frames:t,cursor:ne,options:{duration:Y.cursorSpeed,...n}})}},q=()=>{let e=Y.strings.filter((e=>!!e));e.forEach(((t,n)=>{if(this.type(t),n+1===e.length)return;let r=Y.breakLines?[{func:()=>_(h("BR")),typeable:!0}]:S({func:Q,delay:A(1)},ee.getTypeable().length);k(r)}))},z=async(e=!0)=>{K.started=!0;let t=t=>{ee.done(t,!e)};try{let n=[...ee.getQueue()];for(let e=0;e<n.length;e++){let[r,i]=n[e];if(!i.done){if(!i.deletable||i.deletable&&$().length){let r=await C(e,n);Array(r-e).fill(e+1).map(((e,t)=>e+t)).forEach((e=>{let[r]=n[e];t(r)})),e=r}t(r)}}if(!e)return this;if(K.completed=!0,await Y.afterComplete(this),!Y.loop)throw"";let r=Y.loopDelay;L((async()=>{await(async e=>{let t=O();t&&await B({value:t});let n=$().map((e=>[Symbol(),{func:Q,delay:A(1),deletable:!0,shouldPauseCursor:()=>!0}]));for(let r=0;r<n.length;r++)await C(r,n);ee.reset(),ee.set(0,{delay:e})})(r[0]),z()}),r[1])}catch(n){}return this},B=async e=>{var t,n,r;t=e,n=X,r=$(),X=Math.min(Math.max(n+t,0),r.length),((e,t,n)=>{let r=t[n-1],i=v(`.${s}`,e);(e=r?.parentNode||e).insertBefore(i,r||null)})(J,$(),X)},_=e=>((e,t)=>{if(b(e))return void(e.value=`${e.value}${t.textContent}`);t.innerHTML="";let n=(r=t.originalParent,/body/i.test(r?.tagName)?e:t.originalParent||e);var r;n.insertBefore(t,v("."+s,n)||null)})(J,e),j=async e=>Y=E(Y,e),V=async()=>{x()?J.value="":$().forEach(I)},Q=()=>{let e=$();e.length&&(x()?J.value=J.value.slice(0,-1):I(e[X]))};this.break=function(e){return H({func:()=>_(h("BR")),typeable:!0},e)},this.delete=function(e=null,t={}){e=w(e);let n=F(t),r=e,{instant:i,to:a}=t,o=ee.getTypeable(),s=null===r?o.length:T(r)?r:N({queueItems:o,selector:r,cursorPosition:O(),to:a});return H([n[0],...S({func:Q,delay:i?0:A(1),deletable:!0},s),n[1]],t)},this.empty=function(e={}){return H({func:V},e)},this.exec=function(e,t={}){let n=F(t);return H([n[0],{func:()=>e(this)},n[1]],t)},this.move=function(e,t={}){e=w(e);let n=F(t),{instant:r,to:i}=t,a=N({queueItems:ee.getTypeable(),selector:null===e?"":e,to:i,cursorPosition:O()}),o=a<0?-1:1;return G=O()+a,H([n[0],...S({func:()=>B(o),delay:r?0:A(),cursorable:!0},Math.abs(a)),n[1]],t)},this.options=function(e,t={}){return e=w(e),j(e),H({},t)},this.pause=function(e,t={}){return H({delay:w(e)},t)},this.type=function(e,t={}){e=w(e);let{instant:n}=t,r=F(t),i=f(e,Y.html).map((e=>{return{func:()=>_(e),char:e,delay:n||(t=e,/<(.+)>(.*?)<\/(.+)>/.test(t.outerHTML))?0:A(),typeable:e.nodeType===Node.TEXT_NODE};var t})),a=[r[0],{func:async()=>await Y.beforeString(e,this)},...i,{func:async()=>await Y.afterString(e,this)},r[1]];return H(a,t)},this.is=function(e){return K[e]},this.destroy=function(e=!0){W.forEach(clearTimeout),W=[],w(e)&&ne&&I(ne),K.destroyed=!0},this.freeze=function(){K.frozen=!0},this.unfreeze=()=>{},this.reset=function(e){!this.is("destroyed")&&this.destroy(),e?(ee.wipe(),e(this)):ee.reset(),X=0;for(let t in K)K[t]=!1;return J[x()?"value":"innerHTML"]="",this},this.go=function(){return K.started?this:(R(),Y.waitUntilVisible?(((e,t)=>{new IntersectionObserver(((n,r)=>{n.forEach((n=>{n.isIntersecting&&(t(),r.unobserve(e))}))}),{threshold:1}).observe(e)})(J,z.bind(this)),this):(z(),this))},this.flush=function(e=(()=>{})){return R(),z(!1).then(e),this},this.getQueue=()=>ee,this.getOptions=()=>Y,this.updateOptions=e=>j(e),this.getElement=()=>J;let J="string"==typeof(U=e)?v(U):U;var U;let W=[],X=0,G=null,K=E({},l);r.cursor=(e=>{if("object"==typeof e){let t={},{frames:n,options:r}=u.cursor.animation;return t.animation=e.animation||{},t.animation.frames=e.animation?.frames||n,t.animation.options=E(r,e.animation?.options||{}),t.autoPause=e.autoPause??u.cursor.autoPause,t.autoPauseDelay=e.autoPauseDelay||u.cursor.autoPauseDelay,t}return!0===e?u.cursor:e})(r.cursor??u.cursor);let Y=E(u,r);Y=E(Y,{html:!x()&&Y.html,nextStringDelay:p(Y.nextStringDelay),loopDelay:p(Y.loopDelay)});let Z=Math.random().toString().substring(2,9),ee=function(e){let n=function(e){return t(e).forEach((e=>a.set(Symbol(e.char?.innerText),r({...e})))),this},r=e=>(e.shouldPauseCursor=function(){return Boolean(this.typeable||this.cursorable||this.deletable)},e),i=()=>Array.from(a.values()),a=new Map;return n(e),{add:n,set:function(e,t){let n=[...a.keys()];a.set(n[e],r(t))},wipe:function(){a=new Map,n(e)},reset:function(){a.forEach((e=>delete e.done))},destroy:e=>a.delete(e),done:(e,t=!1)=>t?a.delete(e):a.get(e).done=!0,getItems:(e=!1)=>e?i():i().filter((e=>!e.done)),getQueue:()=>a,getTypeable:()=>i().filter((e=>e.typeable))}}([{delay:Y.startDelay}]);J.dataset.typeitId=Z,y(c);let te=!!Y.cursor&&!x(),ne=(()=>{if(x())return;let e=h("span");return e.className=s,te?(e.innerHTML=a(Y.cursorChar).innerHTML,e):(e.style.visibility="hidden",e)})();Y.strings=(e=>{let t=J.innerHTML;return t?(J.innerHTML="",Y.startDelete?(J.innerHTML=t,i(J),k(S({func:Q,delay:A(1),deletable:!0},$().length)),e):t.replace(/<!--(.+?)-->/g,"").trim().split(/<br(?:\s*?)(?:\/)?>/).concat(e)):e})(t(Y.strings)),Y.strings.length&&q()}}));
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).TypeIt=t()}(this,(function(){"use strict";const e=e=>Array.isArray(e),t=t=>e(t)?t:[t];const s="data-typeit-id",i="ti-cursor",r={started:!1,completed:!1,frozen:!1,destroyed:!1},n={breakLines:!0,cursor:{autoPause:!0,autoPauseDelay:500,animation:{frames:[0,0,1].map((e=>({opacity:e}))),options:{iterations:1/0,easing:"steps(2, start)",fill:"forwards"}}},cursorChar:"|",cursorSpeed:1e3,deleteSpeed:null,html:!0,lifeLike:!0,loop:!1,loopDelay:750,nextStringDelay:750,speed:100,startDelay:250,startDelete:!1,strings:[],waitUntilVisible:!1,beforeString:()=>{},afterString:()=>{},beforeStep:()=>{},afterStep:()=>{},afterComplete:()=>{}},o=`[${s}]:before {content: '.'; display: inline-block; width: 0; visibility: hidden;}`,a=e=>document.createElement(e),u=e=>document.createTextNode(e),l=(e,t="")=>{let s=a("style");s.id=t,s.appendChild(u(e)),document.head.appendChild(s)},h=t=>(e(t)||(t=[t/2,t/2]),t),d=(e,t)=>Math.abs(Math.random()*(e+t-(e-t))+(e-t));let p=e=>e/2;const c=e=>Array.from(e);let m=e=>([...e.childNodes].forEach((e=>{if(e.nodeValue)return[...e.nodeValue].forEach((t=>{e.parentNode.insertBefore(u(t),e)})),void e.remove();m(e)})),e);const f=e=>{let t=document.implementation.createHTMLDocument();return t.body.innerHTML=e,m(t.body)};function y(e,t=!1,s=!1){let r,n=e.querySelector(`.${i}`),o=document.createTreeWalker(e,NodeFilter.SHOW_ALL,{acceptNode:e=>{if(n&&s){if(e.classList?.contains(i))return NodeFilter.FILTER_ACCEPT;if(n.contains(e))return NodeFilter.FILTER_REJECT}return e.classList?.contains(i)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT}}),a=[];for(;r=o.nextNode();)r.originalParent||(r.originalParent=r.parentNode),a.push(r);return t?a.reverse():a}function g(e,t=!0){return t?y(f(e)):c(e).map(u)}const b=e=>Number.isInteger(e),P=({queueItems:e,selector:t,cursorPosition:s,to:i})=>{if(b(t))return-1*t;let r=new RegExp("END","i").test(i),n=t?[...e].reverse().findIndex((({char:e})=>{let s=e.parentElement,i=s.matches(t);return!(!r||!i)||i&&s.firstChild.isSameNode(e)})):-1;return n<0&&(n=r?0:e.length-1),n-s+(r?0:1)},C=(e,t)=>new Array(t).fill(e);let v=e=>new Promise((t=>{requestAnimationFrame((async()=>{t(await e())}))})),T=e=>e?.getAnimations().find((t=>t.id===e.dataset.tiAnimationId)),w=({cursor:e,frames:t,options:s})=>{let i=e.animate(t,s);return i.pause(),i.id=e.dataset.tiAnimationId,v((()=>{v((()=>{i.play()}))})),i},I=e=>e.func?.call(null),q=async({index:e,queueItems:t,wait:s,cursor:i,cursorOptions:r})=>{let n=t[e][1],o=[],a=e,u=n,l=()=>u&&!u.delay,h=n.shouldPauseCursor()&&r.autoPause;for(;l();)o.push(u),l()&&a++,u=t[a]?t[a][1]:null;if(o.length)return await v((async()=>{for(let e of o)await I(e)})),a-1;let d,p=T(i);return p&&(d={...p.effect.getComputedTiming(),delay:h?r.autoPauseDelay:0}),await s((async()=>{p&&h&&p.cancel(),await v((()=>{I(n)}))}),n.delay),await(({cursor:e,options:t,cursorOptions:s})=>{if(!e||!s)return;let i,r=T(e);r&&(t.delay=r.effect.getComputedTiming().delay,i=r.currentTime,r.cancel());let n=w({cursor:e,frames:s.animation.frames,options:t});return i&&(n.currentTime=i),n})({cursor:i,options:d,cursorOptions:r}),e};const S=e=>"value"in e;let N=e=>"function"==typeof e?e():e,A=(e,t=document,s=!1)=>t["querySelector"+(s?"All":"")](e);const E=(e,t)=>Object.assign({},e,t);let L={"font-family":"","font-weight":"","font-size":"","font-style":"","line-height":"",color:"",transform:"translateX(-.125em)"};return class{element;timeouts;cursorPosition;predictedCursorPosition;statuses={started:!1,completed:!1,frozen:!1,destroyed:!1};opts;id;queue;cursor;unfreeze=()=>{};constructor(e,s={}){var i;this.opts=E(n,s),this.element="string"==typeof(i=e)?A(i):i,this.timeouts=[],this.cursorPosition=0,this.unfreeze=()=>{},this.predictedCursorPosition=null,this.statuses=E({},r),this.id=Math.random().toString().substring(2,9),this.queue=function(e){let s=function(e){return t(e).forEach((e=>n.set(Symbol(e.char?.innerText),i({...e})))),this},i=e=>(e.shouldPauseCursor=function(){return Boolean(this.typeable||this.cursorable||this.deletable)},e),r=()=>Array.from(n.values()),n=new Map;return s(e),{add:s,set:function(e,t){let s=[...n.keys()];n.set(s[e],i(t))},wipe:function(){n=new Map,s(e)},done:(e,t=!1)=>t?n.delete(e):n.get(e).done=!0,reset:function(){n.forEach((e=>delete e.done))},destroy:e=>n.delete(e),getItems:(e=!1)=>e?r():r().filter((e=>!e.done)),getQueue:()=>n,getTypeable:()=>r().filter((e=>e.typeable))}}([{delay:this.opts.startDelay}]),this.#e(s),this.cursor=this.#t(),this.element.dataset.typeitId=this.id,l(o),this.opts.strings.length&&this.#s()}go(){return this.statuses.started?this:(this.#i(),this.opts.waitUntilVisible?(e=this.element,t=this.#r.bind(this),new IntersectionObserver(((s,i)=>{s.forEach((s=>{s.isIntersecting&&(t(),i.unobserve(e))}))}),{threshold:1}).observe(e),this):(this.#r(),this));var e,t}destroy(e=!0){this.timeouts=(this.timeouts.forEach(clearTimeout),[]),N(e)&&this.cursor&&this.#n(this.cursor),this.statuses.destroyed=!0}reset(e){!this.is("destroyed")&&this.destroy(),e?(this.queue.wipe(),e(this)):this.queue.reset(),this.cursorPosition=0;for(let t in this.statuses)this.statuses[t]=!1;return this.element[this.#o()?"value":"innerHTML"]="",this}is=function(e){return this.statuses[e]};type(e,t={}){e=N(e);let{instant:s}=t,i=this.#a(t),r=g(e,this.opts.html).map((e=>{return{func:()=>this.#u(e),char:e,delay:s||(t=e,/<(.+)>(.*?)<\/(.+)>/.test(t.outerHTML))?0:this.#l(),typeable:e.nodeType===Node.TEXT_NODE};var t})),n=[i[0],{func:async()=>await this.opts.beforeString(e,this)},...r,{func:async()=>await this.opts.afterString(e,this)},i[1]];return this.#h(n,t)}break(e={}){return this.#h({func:()=>this.#u(a("BR")),typeable:!0},e)}move(e,t={}){e=N(e);let s=this.#a(t),{instant:i,to:r}=t,n=P({queueItems:this.queue.getTypeable(),selector:null===e?"":e,to:r,cursorPosition:this.#d}),o=n<0?-1:1;return this.predictedCursorPosition=this.#d+n,this.#h([s[0],...C({func:()=>this.#p(o),delay:i?0:this.#l(),cursorable:!0},Math.abs(n)),s[1]],t)}exec(e,t={}){let s=this.#a(t);return this.#h([s[0],{func:()=>e(this)},s[1]],t)}options(e,t={}){return e=N(e),this.#c(e),this.#h({},t)}pause(e,t={}){return this.#h({delay:N(e)},t)}delete(e=null,t={}){e=N(e);let s=this.#a(t),i=e,{instant:r,to:n}=t,o=this.queue.getTypeable(),a=(()=>null===i?o.length:b(i)?i:P({queueItems:o,selector:i,cursorPosition:this.#d,to:n}))();return this.#h([s[0],...C({func:this.#m.bind(this),delay:r?0:this.#l(1),deletable:!0},a),s[1]],t)}freeze(){this.statuses.frozen=!0}flush(e=(()=>{})){return this.#i(),this.#r(!1).then(e),this}getQueue(){return this.queue}getOptions(){return this.opts}updateOptions(e){return this.#c(e)}getElement(){return this.element}empty(e={}){return this.#h({func:this.#f.bind(this)},e)}async#f(){this.#o()?this.element.value="":this.#y.forEach(this.#n.bind(this))}async#r(e=!0){this.statuses.started=!0;let t=t=>{this.queue.done(t,!e)};try{let s=[...this.queue.getQueue()];for(let e=0;e<s.length;e++){let[i,r]=s[e];if(!r.done){if(!r.deletable||r.deletable&&this.#y.length){let i=await this.#g(e,s);Array(i-e).fill(e+1).map(((e,t)=>e+t)).forEach((e=>{let[i]=s[e];t(i)})),e=i}t(i)}}if(!e)return this;if(this.statuses.completed=!0,await this.opts.afterComplete(this),!this.opts.loop)throw"";let i=this.opts.loopDelay;this.#b((async()=>{await this.#P(i[0]),this.#r()}),i[1])}catch(s){}return this}async#p(e){var t,s,r;this.cursorPosition=(t=e,s=this.cursorPosition,r=this.#y,Math.min(Math.max(s+t,0),r.length)),((e,t,s)=>{let r=t[s-1],n=A(`.${i}`,e);(e=r?.parentNode||e).insertBefore(n,r||null)})(this.element,this.#y,this.cursorPosition)}async#P(e){let t=this.#d;t&&await this.#p({value:t});let s=this.#y.map((e=>[Symbol(),{func:this.#m.bind(this),delay:this.#l(1),deletable:!0,shouldPauseCursor:()=>!0}]));for(let i=0;i<s.length;i++)await this.#g(i,s);this.queue.reset(),this.queue.set(0,{delay:e})}#g(e,t){return q({index:e,queueItems:t,wait:this.#b.bind(this),cursor:this.cursor,cursorOptions:this.opts.cursor})}async#b(e,t,s=!1){this.statuses.frozen&&await new Promise((e=>{this.unfreeze=()=>{this.statuses.frozen=!1,e()}})),s||await this.opts.beforeStep(this),await((e,t,s)=>new Promise((i=>{s.push(setTimeout((async()=>{await e(),i()}),t||0))})))(e,t,this.timeouts),s||await this.opts.afterStep(this)}async#i(){if(!this.#o()&&this.cursor&&this.element.appendChild(this.cursor),this.#C){((e,t)=>{let r=`[${s}='${e}'] .${i}`,n=getComputedStyle(t),o=Object.entries(L).reduce(((e,[t,s])=>`${e} ${t}: var(--ti-cursor-${t}, ${s||n[t]});`),"");l(`${r} { display: inline-block; width: 0; ${o} }`,e)})(this.id,this.element),this.cursor.dataset.tiAnimationId=this.id;let{animation:e}=this.opts.cursor,{frames:t,options:r}=e;w({frames:t,cursor:this.cursor,options:{duration:this.opts.cursorSpeed,...r}})}}#o(){return S(this.element)}#h(e,t){return this.queue.add(e),this.#v(t),this}#v(e={}){let t=e.delay;t&&this.queue.add({delay:t})}#a(e={}){return[{func:()=>this.#c(e)},{func:()=>this.#c(this.opts)}]}async#c(e){this.opts=E(this.opts,e)}#s(){let e=this.opts.strings.filter((e=>!!e));e.forEach(((t,s)=>{if(this.type(t),s+1===e.length)return;let i=this.opts.breakLines?[{func:()=>this.#u(a("BR")),typeable:!0}]:C({func:this.#m.bind(this),delay:this.#l(1)},this.queue.getTypeable().length);this.#T(i)}))}#e=e=>{e.cursor=(e=>{if("object"==typeof e){let t={},{frames:s,options:i}=n.cursor.animation;return t.animation=e.animation||{},t.animation.frames=e.animation?.frames||s,t.animation.options=E(i,e.animation?.options||{}),t.autoPause=e.autoPause??n.cursor.autoPause,t.autoPauseDelay=e.autoPauseDelay||n.cursor.autoPauseDelay,t}return!0===e?n.cursor:e})(e.cursor??n.cursor),this.opts.strings=this.#w(t(this.opts.strings)),this.opts=E(this.opts,{html:!this.#I&&this.opts.html,nextStringDelay:h(this.opts.nextStringDelay),loopDelay:h(this.opts.loopDelay)})};#w(e){let t=this.element.innerHTML;return t?(this.element.innerHTML="",this.opts.startDelete?(this.element.innerHTML=t,m(this.element),this.#T(C({func:this.#m.bind(this),delay:this.#l(1),deletable:!0},this.#y.length)),e):(s=t,s.replace(/<!--(.+?)-->/g,"").trim().split(/<br(?:\s*?)(?:\/)?>/)).concat(e)):e;var s}#t(){if(this.#I)return null;let e=a("span");return e.className=i,this.#C?(e.innerHTML=f(this.opts.cursorChar).innerHTML,e):(e.style.visibility="hidden",e)}#T(e){let t=this.opts.nextStringDelay;this.queue.add([{delay:t[0]},...e,{delay:t[1]}])}#u(e){((e,t)=>{if(S(e))return void(e.value=`${e.value}${t.textContent}`);t.innerHTML="";let s=(r=t.originalParent,/body/i.test(r?.tagName)?e:t.originalParent||e);var r;s.insertBefore(t,A("."+i,s)||null)})(this.element,e)}#m(){this.#y.length&&(this.#I?this.element.value=this.element.value.slice(0,-1):this.#n(this.#y[this.cursorPosition]))}#n(e){((e,t)=>{if(!e)return;let s=e.parentNode;(s.childNodes.length>1||s.isSameNode(t)?e:s).remove()})(e,this.element)}#l(e=0){return function(e){let{speed:t,deleteSpeed:s,lifeLike:i}=e;return s=null!==s?s:t/3,i?[d(t,p(t)),d(s,p(s))]:[t,s]}(this.opts)[e]}get#d(){return this.predictedCursorPosition??this.cursorPosition}get#I(){return S(this.element)}get#C(){return!!this.opts.cursor&&!this.#I}get#y(){return e=this.element,S(e)?c(e.value):y(e,!0).filter((e=>!(e.childNodes.length>0)));var e}}}));
import { QueueItem } from "./types";
declare let Queue: (initialItems: QueueItem[]) => {
export interface QueueI {
add: (steps: QueueItem[] | QueueItem) => typeof Queue;
set: (index: number, item: QueueItem) => void;
wipe: () => void;
done: (key: Symbol, shouldDestroy?: boolean) => void;
reset: () => void;
destroy: (key: Symbol) => boolean;
done: (key: Symbol, shouldDestroy?: boolean) => boolean;
destroy: (key: Symbol) => void;
getItems: (all?: boolean) => QueueItem[];
getQueue: () => Map<any, any>;
getQueue: () => Map<Symbol, QueueItem>;
getTypeable: () => QueueItem[];
};
}
declare let Queue: (initialItems: QueueItem[]) => QueueI;
export default Queue;
/// <reference types="web-animations-js" />
export type TypeItInstance = (element: El | string, options: Options) => void;
export type Character = {

@@ -25,4 +24,4 @@ node: El | null;

loop?: boolean;
loopDelay?: number;
nextStringDelay?: number;
loopDelay?: number | number[];
nextStringDelay?: number | number[];
speed?: number;

@@ -39,2 +38,8 @@ startDelay?: number;

}
export interface Statuses {
started: boolean;
completed: boolean;
frozen: boolean;
destroyed: boolean;
}
export type ActionOpts = Options & {

@@ -41,0 +46,0 @@ to?: Sides;

{
"name": "typeit",
"version": "8.7.1",
"version": "8.8.0",
"description": "The most versatile animated typing utility on the planet.",

@@ -23,3 +23,3 @@ "author": "Alex MacArthur <alex@macarthur.me> (https://macarthur.me)",

"start": "vite serve examples --host 0.0.0.0",
"test": "jest",
"test": "vitest run",
"postinstall": "node ./scripts/notice.js",

@@ -43,22 +43,10 @@ "prepare": "npm run build"

"devDependencies": {
"@babel/preset-env": "^7.20.2",
"@babel/preset-typescript": "^7.18.6",
"@types/web-animations-js": "^2.2.12",
"jest": "^29.3.1",
"jest-cli": "^29.3.1",
"jest-environment-jsdom": "^29.3.1",
"terser": "^5.16.1",
"typescript": "^4.9.4",
"vite": "^4.0.1"
"terser": "^5.24.0",
"typescript": "^5.3.2",
"vite": "^5.0.2",
"vitest": "^0.34.6"
},
"jest": {
"clearMocks": true,
"testPathIgnorePatterns": [
"<rootDir>/__tests__/setup.js"
],
"setupFilesAfterEnv": [
"./__tests__/setup.js"
],
"testEnvironment": "jsdom"
"dependencies": {
"@types/web-animations-js": "^2.2.16"
}
}
import createElement from "./createElement";
import createTextNode from "./createTextNode";
export default (styles: string, id = ""): void => {
export default (styles: string, id: string = ""): void => {
let styleBlock: HTMLElement = createElement("style");

@@ -6,0 +6,0 @@ styleBlock.id = id;

@@ -6,4 +6,2 @@ import isArray from "./isArray";

*/
export default <T>(value): T[] => {
return isArray(value) ? value : [value];
};
export default <T>(value): T[] => (isArray(value) ? value : [value]);

@@ -1,1 +0,1 @@

export default (el) => /<(.+)>(.*?)<\/(.+)>/.test(el.outerHTML);
export default (el: any) => /<(.+)>(.*?)<\/(.+)>/.test(el.outerHTML);

@@ -19,3 +19,3 @@ import { El, CursorOptions } from "../types";

let animation = getAnimationFromElement(cursor);
let oldCurrentTime: number;
let oldCurrentTime: CSSNumberish;

@@ -22,0 +22,0 @@ // An existing animation is actively running...

/**
* Literally just wraps toArray() to save a few bytes
* when it's repeatedly used.
*
* @param {any}
* @return {array}
*/
export default (val): any[] => Array.from(val);
import asArray from "./helpers/asArray";
import { QueueItem } from "./types";
let Queue = function (initialItems: QueueItem[]) {
export interface QueueI {
add: (steps: QueueItem[] | QueueItem) => typeof Queue;
set: (index: number, item: QueueItem) => void;
wipe: () => void;
done: (key: Symbol, shouldDestroy?: boolean) => void;
reset: () => void;
destroy: (key: Symbol) => void;
getItems: (all?: boolean) => QueueItem[];
getQueue: () => Map<Symbol, QueueItem>;
getTypeable: () => QueueItem[];
}
let Queue = function (initialItems: QueueItem[]): QueueI {
/**

@@ -70,5 +82,5 @@ * Add a single or several steps onto the `waiting` queue.

wipe,
done,
reset,
destroy,
done,
getItems,

@@ -75,0 +87,0 @@ getQueue,

@@ -1,3 +0,1 @@

export type TypeItInstance = (element: El | string, options: Options) => void;
export type Character = {

@@ -30,4 +28,6 @@ node: El | null;

loop?: boolean;
loopDelay?: number;
nextStringDelay?: number;
loopDelay?: number | number[];
// @todo Rename to something like "betweenStringDelay"
nextStringDelay?: number | number[];
speed?: number;

@@ -45,2 +45,9 @@ startDelay?: number;

export interface Statuses {
started: boolean;
completed: boolean;
frozen: boolean;
destroyed: boolean;
}
export type ActionOpts = Options & {

@@ -47,0 +54,0 @@ to?: Sides;

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc