config redirect

This commit is contained in:
Nuno Coração
2023-01-29 22:30:24 +00:00
parent 17557c7d73
commit 5fb4bd8083
9905 changed files with 1258996 additions and 36355 deletions

0
node_modules/typeit/dist/Cursor.d.ts generated vendored Normal file
View File

13
node_modules/typeit/dist/Queue.d.ts generated vendored Normal file
View File

@@ -0,0 +1,13 @@
import { QueueItem } from "./types";
declare let Queue: (initialItems: QueueItem[]) => {
add: (steps: QueueItem[] | QueueItem) => typeof Queue;
set: (index: number, item: QueueItem) => void;
wipe: () => void;
reset: () => void;
destroy: (key: Symbol) => boolean;
done: (key: Symbol, shouldDestroy?: boolean) => boolean;
getItems: (all?: boolean) => QueueItem[];
getQueue: () => Map<any, any>;
getTypeable: () => QueueItem[];
};
export default Queue;

15
node_modules/typeit/dist/constants.d.ts generated vendored Normal file
View File

@@ -0,0 +1,15 @@
import { CursorOptions, Options } from "./types";
export declare const DATA_ATTRIBUTE = "data-typeit-id";
export declare const CURSOR_CLASS = "ti-cursor";
export declare const START = "START";
export declare const END = "END";
export declare const DEFAULT_STATUSES: {
started: boolean;
completed: boolean;
frozen: boolean;
destroyed: boolean;
};
export declare const DEFAULT_OPTIONS: Options & {
cursor: Required<CursorOptions>;
};
export declare const PLACEHOLDER_CSS: string;

View File

@@ -0,0 +1,2 @@
declare const _default: (styles: string, id?: string) => void;
export default _default;

5
node_modules/typeit/dist/helpers/asArray.d.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
/**
* Converts value as within array, unless the value itself already is one.
*/
declare const _default: <T>(value: any) => T[];
export default _default;

2
node_modules/typeit/dist/helpers/beforePaint.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
declare let beforePaint: (cb: any) => Promise<any>;
export default beforePaint;

9
node_modules/typeit/dist/helpers/calculateDelay.d.ts generated vendored Normal file
View File

@@ -0,0 +1,9 @@
/**
* Given a delay value, form it into the type of object
* that will be used by Instance().
*
* @param {integer | array}
* @return {array}
*/
declare const _default: (delayArg: number | number[]) => number[];
export default _default;

5
node_modules/typeit/dist/helpers/calculatePace.d.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
import { Options } from "../types";
/**
* [typePace, deletePace]
*/
export default function (options: Options): number[];

16
node_modules/typeit/dist/helpers/chunkStrings.d.ts generated vendored Normal file
View File

@@ -0,0 +1,16 @@
import { El } from "../types";
export declare function walkElementNodes(element: El | Node, shouldReverse?: boolean, shouldIncludeCursor?: boolean): El[];
/**
* Convert string to array of chunks that will be later
* used to construct a TypeIt queue.
*/
export declare function chunkStringAsHtml(string: string): El[];
/**
* Given a string, chunk it into array items to be later
* converted to queue items for typing.
*
* @param {string} str
* @param {boolean} asHtml
* @return {array}
*/
export declare function maybeChunkStringAsHtml(str: string, asHtml?: boolean): Partial<El>[];

View File

@@ -0,0 +1,9 @@
import { QueueItem, Sides } from "../types";
interface countStepsToSelectorArgs {
queueItems: QueueItem[];
selector: string | number;
cursorPosition: number;
to: Sides;
}
declare const countStepsToSelector: ({ queueItems, selector, cursorPosition, to, }: countStepsToSelectorArgs) => number;
export default countStepsToSelector;

3
node_modules/typeit/dist/helpers/createElement.d.ts generated vendored Normal file
View File

@@ -0,0 +1,3 @@
import { El } from "../types";
declare const _default: (el: any) => El;
export default _default;

2
node_modules/typeit/dist/helpers/createTextNode.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
declare const _default: (content: string) => Text;
export default _default;

View File

@@ -0,0 +1,2 @@
declare const _default: (timeouts: number[]) => [];
export default _default;

2
node_modules/typeit/dist/helpers/duplicate.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
declare const _default: <T>(value: T, times: number) => T[];
export default _default;

View File

@@ -0,0 +1,3 @@
import { El } from "../types";
declare let expandTextNodes: (element: El) => El;
export default expandTextNodes;

10
node_modules/typeit/dist/helpers/fireItem.d.ts generated vendored Normal file
View File

@@ -0,0 +1,10 @@
import { CursorOptions, El, QueueMapPair } from "../types";
interface FireItemArgs {
index: number;
queueItems: QueueMapPair[];
wait: (...args: any) => Promise<void>;
cursor: El | undefined;
cursorOptions: CursorOptions;
}
declare let fireItem: ({ index, queueItems, wait, cursor, cursorOptions, }: FireItemArgs) => Promise<number>;
export default fireItem;

View File

@@ -0,0 +1,2 @@
declare const _default: (element: HTMLElement, func: Function) => void;
export default _default;

2
node_modules/typeit/dist/helpers/generateHash.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
declare const _default: () => string;
export default _default;

7
node_modules/typeit/dist/helpers/getAllChars.d.ts generated vendored Normal file
View File

@@ -0,0 +1,7 @@
import { El } from "../types";
/**
* Get a flattened array of text nodes that have been typed.
* This excludes any cursor character that might exist.
*/
declare let getAllChars: (element: El) => any[];
export default getAllChars;

View File

@@ -0,0 +1,3 @@
import { El } from "../types";
declare let getAnimationFromElement: (element: El) => Animation | undefined;
export default getAnimationFromElement;

View File

@@ -0,0 +1,2 @@
declare const _default: (el: any) => CSSStyleDeclaration;
export default _default;

7
node_modules/typeit/dist/helpers/getParsedBody.d.ts generated vendored Normal file
View File

@@ -0,0 +1,7 @@
import { El } from "../types";
/**
* Parse a string as HTML and return the body
* of the parsed document, with all text nodes expanded.
*/
declare const _default: (content: any) => El;
export default _default;

View File

@@ -0,0 +1,2 @@
declare let handleFunctionalArg: <T>(arg: any) => T;
export default handleFunctionalArg;

View File

@@ -0,0 +1,6 @@
import { El } from "../types";
/**
* Inserts a set of content into the element. Intended for SINGLE characters.
*/
declare let insertIntoElement: (originalTarget: El, character: El) => void;
export default insertIntoElement;

2
node_modules/typeit/dist/helpers/isArray.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
declare const _default: (thing: any) => boolean;
export default _default;

3
node_modules/typeit/dist/helpers/isBodyElement.d.ts generated vendored Normal file
View File

@@ -0,0 +1,3 @@
import { El } from "../types";
declare let isBodyElement: (node: El) => boolean;
export default isBodyElement;

2
node_modules/typeit/dist/helpers/isInput.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
declare const _default: (el: HTMLElement) => boolean;
export default _default;

View File

@@ -0,0 +1,2 @@
declare const _default: (el: any) => boolean;
export default _default;

2
node_modules/typeit/dist/helpers/isNumber.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
declare const _default: (value: any) => boolean;
export default _default;

2
node_modules/typeit/dist/helpers/merge.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
declare const _default: (originalObj: any, newObj: any) => any;
export default _default;

View File

@@ -0,0 +1,3 @@
import { CursorOptions } from "../types";
declare let processCursorOptions: (cursorOptions: boolean | CursorOptions) => boolean | CursorOptions;
export default processCursorOptions;

2
node_modules/typeit/dist/helpers/randomInRange.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
declare const _default: (value: number, range: number) => number;
export default _default;

View File

@@ -0,0 +1,8 @@
import { El, CursorOptions } from "../types";
interface rebuildCursorAnimationArgs {
cursor: El | undefined;
cursorOptions: CursorOptions;
options: any;
}
declare let rebuildCursorAnimation: ({ cursor, options, cursorOptions, }: rebuildCursorAnimationArgs) => Animation;
export default rebuildCursorAnimation;

3
node_modules/typeit/dist/helpers/removeNode.d.ts generated vendored Normal file
View File

@@ -0,0 +1,3 @@
import { El } from "../types";
declare const _default: (node: Node, rootElement: El) => void;
export default _default;

View File

@@ -0,0 +1,2 @@
declare const _default: (element: HTMLElement, allChars: any[], newCursorPosition: number) => void;
export default _default;

2
node_modules/typeit/dist/helpers/select.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
declare let select: (selector: string, element?: Node, all?: boolean) => Node | NodeList | null;
export default select;

View File

@@ -0,0 +1,2 @@
import { El } from "../types";
export default function (thing: string | El): El;

View File

@@ -0,0 +1,11 @@
/// <reference types="web-animations-js" />
import { El } from "../types";
/**
* Create and return an animation for the cursor.
*/
declare let setCursorAnimation: ({ cursor, frames, options, }: {
cursor: El;
frames: AnimationKeyFrame[];
options: Partial<AnimationEffectTiming>;
}) => Animation;
export default setCursorAnimation;

11
node_modules/typeit/dist/helpers/setCursorStyles.d.ts generated vendored Normal file
View File

@@ -0,0 +1,11 @@
import { El } from "../types";
export declare let cursorFontStyles: {
readonly "font-family": "";
readonly "font-weight": "";
readonly "font-size": "";
readonly "font-style": "";
readonly "line-height": "";
readonly color: "";
readonly transform: "translateX(-.125em)";
};
export declare let setCursorStyles: (id: string, element: El) => void;

9
node_modules/typeit/dist/helpers/toArray.d.ts generated vendored Normal file
View File

@@ -0,0 +1,9 @@
/**
* 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;

View File

@@ -0,0 +1,2 @@
declare let updateCursorPosition: (steps: number, cursorPosition: number, printedCharacters: Element[]) => number;
export default updateCursorPosition;

5
node_modules/typeit/dist/helpers/wait.d.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
/**
* Fire a callback after a delay, and add the timeout ID to a referenced array.
*/
declare let wait: (callback: Function, delay: number | undefined, timeouts: number[]) => Promise<void>;
export default wait;

4
node_modules/typeit/dist/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,4 @@
import { Options, TypeItInstance } from "./types";
export declare type TypeItOptions = Options;
declare const TypeIt: TypeItInstance;
export default TypeIt;

825
node_modules/typeit/dist/index.es.js generated vendored Normal file
View File

@@ -0,0 +1,825 @@
// TypeIt by Alex MacArthur - https://typeitjs.com
const isArray = (thing) => Array.isArray(thing);
const asArray = (value) => {
return isArray(value) ? value : [value];
};
let Queue = function(initialItems) {
let add = function(steps) {
asArray(steps).forEach((step) => {
return _q.set(Symbol(step.char?.innerText), buildQueueItem({ ...step }));
});
return this;
};
let getTypeable = () => rawValues().filter((value) => value.typeable);
let set = function(index, item) {
let keys = [..._q.keys()];
_q.set(keys[index], buildQueueItem(item));
};
let buildQueueItem = (queueItem) => {
queueItem.shouldPauseCursor = function() {
return Boolean(this.typeable || this.cursorable || this.deletable);
};
return queueItem;
};
let reset = function() {
_q.forEach((item) => delete item.done);
};
let wipe = function() {
_q = /* @__PURE__ */ new Map();
add(initialItems);
};
let getQueue = () => _q;
let rawValues = () => Array.from(_q.values());
let destroy = (key) => _q.delete(key);
let getItems = (all = false) => all ? rawValues() : rawValues().filter((i) => !i.done);
let done = (key, shouldDestroy = false) => shouldDestroy ? _q.delete(key) : _q.get(key).done = true;
let _q = /* @__PURE__ */ new Map();
add(initialItems);
return {
add,
set,
wipe,
reset,
destroy,
done,
getItems,
getQueue,
getTypeable
};
};
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";
const CURSOR_CLASS = "ti-cursor";
const END = "END";
const DEFAULT_STATUSES = {
started: false,
completed: false,
frozen: false,
destroyed: false
};
const DEFAULT_OPTIONS = {
breakLines: true,
cursor: {
autoPause: true,
autoPauseDelay: 500,
animation: {
frames: [0, 0, 1].map((n) => {
return { opacity: n };
}),
options: {
iterations: Infinity,
easing: "steps(2, start)",
fill: "forwards"
}
}
},
cursorChar: "|",
cursorSpeed: 1e3,
deleteSpeed: null,
html: true,
lifeLike: true,
loop: false,
loopDelay: 750,
nextStringDelay: 750,
speed: 100,
startDelay: 250,
startDelete: false,
strings: [],
waitUntilVisible: false,
beforeString: () => {
},
afterString: () => {
},
beforeStep: () => {
},
afterStep: () => {
},
afterComplete: () => {
}
};
const PLACEHOLDER_CSS = `[${DATA_ATTRIBUTE}]:before {content: '.'; display: inline-block; width: 0; visibility: hidden;}`;
function walkElementNodes(element, shouldReverse = false, shouldIncludeCursor = false) {
let cursor = element.querySelector(`.${CURSOR_CLASS}`);
let walker = document.createTreeWalker(element, NodeFilter.SHOW_ALL, {
acceptNode: (node) => {
if (cursor && shouldIncludeCursor) {
if (node.classList?.contains(CURSOR_CLASS)) {
return NodeFilter.FILTER_ACCEPT;
}
if (cursor.contains(node)) {
return NodeFilter.FILTER_REJECT;
}
}
return node.classList?.contains(CURSOR_CLASS) ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT;
}
});
let nextNode;
let nodes = [];
while (nextNode = walker.nextNode()) {
if (!nextNode.originalParent) {
nextNode.originalParent = nextNode.parentNode;
}
nodes.push(nextNode);
}
return shouldReverse ? nodes.reverse() : nodes;
}
function chunkStringAsHtml(string) {
return walkElementNodes(getParsedBody(string));
}
function maybeChunkStringAsHtml(str, asHtml = true) {
return asHtml ? chunkStringAsHtml(str) : toArray(str).map(createTextNode);
}
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 = ({
queueItems,
selector,
cursorPosition,
to
}) => {
if (isNumber(selector)) {
return selector * -1;
}
let isMovingToEnd = new RegExp(END, "i").test(to);
let selectorIndex = selector ? [...queueItems].reverse().findIndex(({ char }) => {
let parentElement = char.parentElement;
let parentMatches = parentElement.matches(selector);
if (isMovingToEnd && parentMatches) {
return true;
}
return parentMatches && parentElement.firstChild.isSameNode(char);
}) : -1;
if (selectorIndex < 0) {
selectorIndex = isMovingToEnd ? 0 : queueItems.length - 1;
}
let offset = isMovingToEnd ? 0 : 1;
return selectorIndex - cursorPosition + offset;
};
let beforePaint = (cb) => {
return new Promise((resolve) => {
requestAnimationFrame(async () => {
resolve(await cb());
});
});
};
let getAnimationFromElement = (element) => {
return element?.getAnimations().find((animation) => {
return animation.id === element.dataset.tiAnimationId;
});
};
let setCursorAnimation = ({
cursor,
frames,
options
}) => {
let animation = cursor.animate(frames, options);
animation.pause();
animation.id = cursor.dataset.tiAnimationId;
beforePaint(() => {
beforePaint(() => {
animation.play();
});
});
return animation;
};
let rebuildCursorAnimation = ({
cursor,
options,
cursorOptions
}) => {
if (!cursor || !cursorOptions)
return;
let animation = getAnimationFromElement(cursor);
let oldCurrentTime;
if (animation) {
options.delay = animation.effect.getComputedTiming().delay;
oldCurrentTime = animation.currentTime;
animation.cancel();
}
let newAnimation = setCursorAnimation({
cursor,
frames: cursorOptions.animation.frames,
options
});
if (oldCurrentTime) {
newAnimation.currentTime = oldCurrentTime;
}
return newAnimation;
};
let execute = (queueItem) => queueItem.func?.call(null);
let fireItem = async ({
index,
queueItems,
wait: wait2,
cursor,
cursorOptions
}) => {
let queueItem = queueItems[index][1];
let instantQueue = [];
let tempIndex = index;
let futureItem = queueItem;
let shouldBeGrouped = () => futureItem && !futureItem.delay;
let shouldPauseCursor = queueItem.shouldPauseCursor() && cursorOptions.autoPause;
while (shouldBeGrouped()) {
instantQueue.push(futureItem);
shouldBeGrouped() && tempIndex++;
futureItem = queueItems[tempIndex] ? queueItems[tempIndex][1] : null;
}
if (instantQueue.length) {
await beforePaint(async () => {
for (let q of instantQueue) {
await execute(q);
}
});
return tempIndex - 1;
}
let animation = getAnimationFromElement(cursor);
let options;
if (animation) {
options = {
...animation.effect.getComputedTiming(),
delay: shouldPauseCursor ? cursorOptions.autoPauseDelay : 0
};
}
await wait2(async () => {
if (animation && shouldPauseCursor) {
animation.cancel();
}
await beforePaint(() => {
execute(queueItem);
});
}, queueItem.delay);
await rebuildCursorAnimation({
cursor,
options,
cursorOptions
});
return index;
};
let processCursorOptions = (cursorOptions) => {
if (typeof cursorOptions === "object") {
let newOptions = {};
let { frames: defaultFrames, options: defaultOptions } = DEFAULT_OPTIONS.cursor.animation;
newOptions.animation = cursorOptions.animation || {};
newOptions.animation.frames = cursorOptions.animation?.frames || defaultFrames;
newOptions.animation.options = merge(
defaultOptions,
cursorOptions.animation?.options || {}
);
newOptions.autoPause = cursorOptions.autoPause ?? DEFAULT_OPTIONS.cursor.autoPause;
newOptions.autoPauseDelay = cursorOptions.autoPauseDelay || DEFAULT_OPTIONS.cursor.autoPauseDelay;
return newOptions;
}
if (cursorOptions === true) {
return DEFAULT_OPTIONS.cursor;
}
return cursorOptions;
};
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);
};
let _fireItemWithContext = (index, queueItems) => {
return fireItem({
index,
queueItems,
wait: _wait,
cursor: _cursor,
cursorOptions: _opts.cursor
});
};
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;
}
let cursor = createElement("span");
cursor.className = CURSOR_CLASS;
if (!_shouldRenderCursor) {
cursor.style.visibility = "hidden";
return cursor;
}
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
}
});
}
};
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);
}
_queue.reset();
_queue.set(0, { delay });
};
let _maybePrependHardcodedStrings = (strings) => {
let existingMarkup = _element.innerHTML;
if (!existingMarkup) {
return strings;
}
_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) {
}
return this;
};
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(
{
func: () => _type(createElement("BR")),
typeable: true
},
actionOpts
);
};
this.delete = function(numCharacters = null, actionOpts = {}) {
numCharacters = handleFunctionalArg(numCharacters);
let bookEndQueueItems = _generateTemporaryOptionQueueItems(actionOpts);
let num = numCharacters;
let { instant, to } = actionOpts;
let typeableQueueItems = _queue.getTypeable();
let rounds = (() => {
if (num === null) {
return typeableQueueItems.length;
}
if (isNumber(num)) {
return num;
}
return countStepsToSelector({
queueItems: typeableQueueItems,
selector: num,
cursorPosition: _getDerivedCursorPosition(),
to
});
})();
return _queueAndReturn(
[
bookEndQueueItems[0],
...duplicate(
{
func: _delete,
delay: instant ? 0 : _getPace(1),
deletable: true
},
rounds
),
bookEndQueueItems[1]
],
actionOpts
);
};
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
);
};
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()
});
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
);
};
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.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
};
});
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();
}
_cursorPosition = 0;
for (let property in _statuses) {
_statuses[property] = false;
}
_element[_elementIsInput() ? "value" : "innerHTML"] = "";
return this;
};
this.go = function() {
if (_statuses.started) {
return this;
}
_attachCursor();
if (!_opts.waitUntilVisible) {
_fire();
return this;
}
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();
}
};
export {
TypeIt as default
};

2
node_modules/typeit/dist/index.umd.js generated vendored Normal file

File diff suppressed because one or more lines are too long

58
node_modules/typeit/dist/types.d.ts generated vendored Normal file
View File

@@ -0,0 +1,58 @@
/// <reference types="web-animations-js" />
export type TypeItInstance = (element: El | string, options: Options) => void;
export type Character = {
node: El | null;
content: string | Node;
};
export interface CursorAnimationOptions {
frames?: AnimationKeyFrame[];
options?: Partial<AnimationEffectTiming>;
}
export interface CursorOptions {
autoPause?: boolean;
autoPauseDelay?: number;
animation?: CursorAnimationOptions;
}
export interface Options {
breakLines?: boolean;
cursorChar?: string;
cursor?: CursorOptions | boolean;
cursorSpeed?: number;
deleteSpeed?: null | number;
html?: boolean;
lifeLike?: boolean;
loop?: boolean;
loopDelay?: number;
nextStringDelay?: number;
speed?: number;
startDelay?: number;
startDelete?: boolean;
strings?: string[] | string;
waitUntilVisible?: boolean;
beforeString?: Function;
afterString?: Function;
beforeStep?: Function;
afterStep?: Function;
afterComplete?: Function;
}
export type ActionOpts = Options & {
to?: Sides;
instant?: boolean;
delay?: number;
};
export type QueueItem = {
done?: boolean;
func?: () => any;
delay?: number;
char?: any;
typeable?: boolean;
deletable?: boolean;
cursorable?: boolean;
shouldPauseCursor?: () => boolean;
};
export type QueueMapPair = [Symbol, QueueItem];
export interface El extends HTMLElement {
value: string | number;
originalParent?: HTMLElement;
}
export type Sides = "START" | "END";

62
node_modules/typeit/package.json generated vendored Normal file
View File

@@ -0,0 +1,62 @@
{
"name": "typeit",
"version": "8.7.1",
"description": "The most versatile animated typing utility on the planet.",
"author": "Alex MacArthur <alex@macarthur.me> (https://macarthur.me)",
"license": "GPL-3.0",
"bugs": {
"url": "https://github.com/alexmacarthur/typeit/issues"
},
"homepage": "https://typeitjs.com",
"main": "dist/index.umd.js",
"module": "dist/index.es.js",
"types": "dist/index.d.ts",
"files": [
"dist/",
"src/",
"scripts/"
],
"scripts": {
"build": "vite build && scripts/banner && tsc",
"tsc": "tsc",
"start": "vite serve examples --host 0.0.0.0",
"test": "jest",
"postinstall": "node ./scripts/notice.js",
"prepare": "npm run build"
},
"keywords": [
"javascript",
"animated",
"typing",
"typing effect",
"typewriter",
"typewriter effect",
"type effect",
"text effects"
],
"repository": {
"type": "git",
"url": "git+https://github.com/alexmacarthur/typeit.git"
},
"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"
},
"jest": {
"clearMocks": true,
"testPathIgnorePatterns": [
"<rootDir>/__tests__/setup.js"
],
"setupFilesAfterEnv": [
"./__tests__/setup.js"
],
"testEnvironment": "jsdom"
}
}

9
node_modules/typeit/scripts/banner generated vendored Executable file
View File

@@ -0,0 +1,9 @@
#!/bin/bash
DIST_PATH="$(pwd)/dist"
DIST_FILES=("index.umd.js" "index.es.js")
for f in "${DIST_FILES[@]}"
do
echo -e "// TypeIt by Alex MacArthur - https://typeitjs.com\n$(cat $DIST_PATH/$f)" > $DIST_PATH/$f
done

5
node_modules/typeit/scripts/notice.js generated vendored Normal file
View File

@@ -0,0 +1,5 @@
const message = `Thanks for using TypeIt! If you're using this library commercially, please purchase a license:
https://typeitjs.com/licenses/purchase`;
console.log("\x1b[35m%s\x1b[0m", message);

0
node_modules/typeit/src/Cursor.ts generated vendored Normal file
View File

79
node_modules/typeit/src/Queue.ts generated vendored Normal file
View File

@@ -0,0 +1,79 @@
import asArray from "./helpers/asArray";
import { QueueItem } from "./types";
let Queue = function (initialItems: QueueItem[]) {
/**
* Add a single or several steps onto the `waiting` queue.
*/
let add = function (steps: QueueItem[] | QueueItem): typeof Queue {
asArray<QueueItem>(steps).forEach((step) => {
return _q.set(Symbol(step.char?.innerText), buildQueueItem({ ...step }));
});
return this;
};
let getTypeable = (): QueueItem[] =>
rawValues().filter((value) => value.typeable);
/**
* Given an index, set an item in the queue.
*/
let set = function (index: number, item: QueueItem): void {
let keys = [..._q.keys()];
_q.set(keys[index], buildQueueItem(item));
};
let buildQueueItem = (queueItem: QueueItem): QueueItem => {
queueItem.shouldPauseCursor = function () {
return Boolean(this.typeable || this.cursorable || this.deletable);
};
return queueItem;
};
/**
* Move all `executed` queue items to `waiting`.
*/
let reset = function (): void {
_q.forEach((item) => delete item.done);
};
let wipe = function (): void {
_q = new Map();
add(initialItems);
};
let getQueue = () => _q;
let rawValues = (): QueueItem[] => Array.from(_q.values());
let destroy = (key: Symbol) => _q.delete(key);
/**
* Retrieve all items that are still eligible to be executed. By default, only the
* completed items will be retrieved.
*/
let getItems = (all: boolean = false): QueueItem[] =>
all ? rawValues() : rawValues().filter((i) => !i.done);
let done = (key: Symbol, shouldDestroy: boolean = false) =>
shouldDestroy ? _q.delete(key) : (_q.get(key).done = true);
let _q = new Map();
add(initialItems);
return {
add,
set,
wipe,
reset,
destroy,
done,
getItems,
getQueue,
getTypeable,
};
};
export default Queue;

51
node_modules/typeit/src/constants.ts generated vendored Normal file
View File

@@ -0,0 +1,51 @@
import { CursorOptions, Options } from "./types";
export const DATA_ATTRIBUTE = "data-typeit-id";
export const CURSOR_CLASS = "ti-cursor";
export const START = "START";
export const END = "END";
export const DEFAULT_STATUSES = {
started: false,
completed: false,
frozen: false,
destroyed: false,
};
export const DEFAULT_OPTIONS: Options & {
cursor: Required<CursorOptions>;
} = {
breakLines: true,
cursor: {
autoPause: true,
autoPauseDelay: 500,
animation: {
frames: [0, 0, 1].map((n) => {
return { opacity: n };
}),
options: {
iterations: Infinity,
easing: "steps(2, start)",
fill: "forwards",
},
},
},
cursorChar: "|",
cursorSpeed: 1000,
deleteSpeed: null,
html: true,
lifeLike: true,
loop: false,
loopDelay: 750,
nextStringDelay: 750,
speed: 100,
startDelay: 250,
startDelete: false,
strings: [],
waitUntilVisible: false,
beforeString: () => {},
afterString: () => {},
beforeStep: () => {},
afterStep: () => {},
afterComplete: () => {},
};
export const PLACEHOLDER_CSS = `[${DATA_ATTRIBUTE}]:before {content: '.'; display: inline-block; width: 0; visibility: hidden;}`;

9
node_modules/typeit/src/helpers/appendStyleBlock.ts generated vendored Normal file
View File

@@ -0,0 +1,9 @@
import createElement from "./createElement";
import createTextNode from "./createTextNode";
export default (styles: string, id = ""): void => {
let styleBlock: HTMLElement = createElement("style");
styleBlock.id = id;
styleBlock.appendChild(createTextNode(styles));
document.head.appendChild(styleBlock);
};

8
node_modules/typeit/src/helpers/asArray.ts generated vendored Normal file
View File

@@ -0,0 +1,8 @@
import isArray from "./isArray";
/**
* Converts value as within array, unless the value itself already is one.
*/
export default <T>(value): T[] => {
return isArray(value) ? value : [value];
};

9
node_modules/typeit/src/helpers/beforePaint.ts generated vendored Normal file
View File

@@ -0,0 +1,9 @@
let beforePaint = (cb): Promise<any> => {
return new Promise((resolve) => {
requestAnimationFrame(async () => {
resolve(await cb());
});
});
};
export default beforePaint;

16
node_modules/typeit/src/helpers/calculateDelay.ts generated vendored Normal file
View File

@@ -0,0 +1,16 @@
import isArray from "./isArray";
/**
* Given a delay value, form it into the type of object
* that will be used by Instance().
*
* @param {integer | array}
* @return {array}
*/
export default (delayArg: number | number[]): number[] => {
if (!isArray(delayArg)) {
delayArg = [(delayArg as number) / 2, (delayArg as number) / 2];
}
return delayArg as number[];
};

20
node_modules/typeit/src/helpers/calculatePace.ts generated vendored Normal file
View File

@@ -0,0 +1,20 @@
import { Options } from "../types";
import randomInRange from "./randomInRange";
let range = (val: number): number => val / 2;
/**
* [typePace, deletePace]
*/
export default function (options: Options): number[] {
let { speed, deleteSpeed, lifeLike } = options;
deleteSpeed = deleteSpeed !== null ? deleteSpeed : speed / 3;
return lifeLike
? [
randomInRange(speed, range(speed)),
randomInRange(deleteSpeed, range(deleteSpeed)),
]
: [speed, deleteSpeed];
}

73
node_modules/typeit/src/helpers/chunkStrings.ts generated vendored Normal file
View File

@@ -0,0 +1,73 @@
import { El } from "../types";
import toArray from "./toArray";
import getParsedBody from "./getParsedBody";
import createTextNode from "./createTextNode";
import { CURSOR_CLASS } from "../constants";
export function walkElementNodes(
element: El | Node,
shouldReverse: boolean = false,
shouldIncludeCursor: boolean = false
): El[] {
let cursor = (element as HTMLElement).querySelector(`.${CURSOR_CLASS}`);
let walker = document.createTreeWalker(element, NodeFilter.SHOW_ALL, {
acceptNode: (node: El) => {
// Include the cursor node, but none of it's children.
if (cursor && shouldIncludeCursor) {
if (node.classList?.contains(CURSOR_CLASS)) {
return NodeFilter.FILTER_ACCEPT;
}
// Do not include any of the cursor's child nodes.
if (cursor.contains(node)) {
return NodeFilter.FILTER_REJECT;
}
}
// Maybe exclude the cursor and its children.
return node.classList?.contains(CURSOR_CLASS)
? NodeFilter.FILTER_REJECT
: NodeFilter.FILTER_ACCEPT;
},
});
let nextNode;
let nodes = [];
while ((nextNode = walker.nextNode())) {
// Necessary for preserving reference to parent nodes
// as we empty elements during typing.
// If this has already been set, don't do it again.
if (!nextNode.originalParent) {
nextNode.originalParent = nextNode.parentNode;
}
nodes.push(nextNode);
}
return shouldReverse ? nodes.reverse() : nodes;
}
/**
* Convert string to array of chunks that will be later
* used to construct a TypeIt queue.
*/
export function chunkStringAsHtml(string: string): El[] {
return walkElementNodes(getParsedBody(string));
}
/**
* Given a string, chunk it into array items to be later
* converted to queue items for typing.
*
* @param {string} str
* @param {boolean} asHtml
* @return {array}
*/
export function maybeChunkStringAsHtml(
str: string,
asHtml = true
): Partial<El>[] {
return asHtml ? chunkStringAsHtml(str) : toArray(str).map(createTextNode);
}

View File

@@ -0,0 +1,49 @@
import { END } from "../constants";
import { QueueItem, Sides } from "../types";
import isNumber from "./isNumber";
interface countStepsToSelectorArgs {
queueItems: QueueItem[];
selector: string | number;
cursorPosition: number;
to: Sides;
}
const countStepsToSelector = ({
queueItems,
selector,
cursorPosition,
to,
}: countStepsToSelectorArgs): number => {
if (isNumber(selector)) {
return (selector as number) * -1;
}
let isMovingToEnd = new RegExp(END, "i").test(to);
let selectorIndex = selector
? [...queueItems].reverse().findIndex(({ char }) => {
let parentElement = char.parentElement;
let parentMatches = parentElement.matches(selector);
// We found the butt end of the selected element.
if (isMovingToEnd && parentMatches) {
return true;
}
// We found the very beginning of the selected element.
return parentMatches && parentElement.firstChild.isSameNode(char);
})
: -1;
// Couldn't find it the selector, so determine if we
// need to move either to the beginning or the end.
if (selectorIndex < 0) {
selectorIndex = isMovingToEnd ? 0 : queueItems.length - 1;
}
let offset = isMovingToEnd ? 0 : 1;
return selectorIndex - cursorPosition + offset;
};
export default countStepsToSelector;

3
node_modules/typeit/src/helpers/createElement.ts generated vendored Normal file
View File

@@ -0,0 +1,3 @@
import { El } from "../types";
export default (el): El => document.createElement(el);

1
node_modules/typeit/src/helpers/createTextNode.ts generated vendored Normal file
View File

@@ -0,0 +1 @@
export default (content: string): Text => document.createTextNode(content);

5
node_modules/typeit/src/helpers/destroyTimeouts.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
export default (timeouts: number[]): [] => {
timeouts.forEach(clearTimeout);
return [];
};

2
node_modules/typeit/src/helpers/duplicate.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
export default <T>(value: T, times: number): T[] =>
new Array(times).fill(value);

21
node_modules/typeit/src/helpers/expandTextNodes.ts generated vendored Normal file
View File

@@ -0,0 +1,21 @@
import createTextNode from "./createTextNode";
import { El } from "../types";
let expandTextNodes = (element: El): El => {
[...element.childNodes].forEach((child) => {
if (child.nodeValue) {
[...child.nodeValue].forEach((c) => {
child.parentNode.insertBefore(createTextNode(c), child);
});
child.remove();
return;
}
expandTextNodes(child as El);
});
return element;
};
export default expandTextNodes;

87
node_modules/typeit/src/helpers/fireItem.ts generated vendored Normal file
View File

@@ -0,0 +1,87 @@
import { CursorOptions, El, QueueItem, QueueMapPair } from "../types";
import beforePaint from "./beforePaint";
import getAnimationFromElement from "./getAnimationFromElement";
import rebuildCursorAnimation from "./rebuildCursorAnimation";
let execute = (queueItem: QueueItem) => queueItem.func?.call(null);
interface FireItemArgs {
index: number;
queueItems: QueueMapPair[];
wait: (...args: any) => Promise<void>;
cursor: El | undefined;
cursorOptions: CursorOptions;
}
let fireItem = async ({
index,
queueItems,
wait,
cursor,
cursorOptions,
}: FireItemArgs): Promise<number> => {
let queueItem = queueItems[index][1];
let instantQueue = [];
let tempIndex = index;
let futureItem = queueItem;
let shouldBeGrouped = () => futureItem && !futureItem.delay;
let shouldPauseCursor =
queueItem.shouldPauseCursor() && cursorOptions.autoPause;
// Crawl through the queue and group together all items that
// do not have have a delay and can be executed instantly.
while (shouldBeGrouped()) {
instantQueue.push(futureItem);
shouldBeGrouped() && tempIndex++;
futureItem = queueItems[tempIndex] ? queueItems[tempIndex][1] : null;
}
if (instantQueue.length) {
// All are executed together before the browser has a chance to repaint.
await beforePaint(async () => {
for (let q of instantQueue) {
await execute(q);
}
});
// Important! Because we moved into the future, the index
// needs to be modified and returned for accurate remaining execution.
return tempIndex - 1;
}
// An animation is only registered on the cursor when it's made visible.
// If the cursor has been disabled, there won't be one here.
let animation = getAnimationFromElement(cursor);
let options;
if (animation) {
options = {
...animation.effect.getComputedTiming(),
delay: shouldPauseCursor ? cursorOptions.autoPauseDelay : 0,
};
}
await wait(async () => {
// If it's a qualified queue item, pause the cursor at the
// beginning of the item's execution by destroying the aniatmion.
// Immediately after completing, the animation will be recreated (with a delay).
if (animation && shouldPauseCursor) {
animation.cancel();
}
await beforePaint(() => {
execute(queueItem);
});
}, queueItem.delay);
await rebuildCursorAnimation({
cursor,
options,
cursorOptions,
});
return index;
};
export default fireItem;

15
node_modules/typeit/src/helpers/fireWhenVisible.ts generated vendored Normal file
View File

@@ -0,0 +1,15 @@
export default (element: HTMLElement, func: Function): void => {
let observer = new IntersectionObserver(
(entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
func();
observer.unobserve(element);
}
});
},
{ threshold: 1.0 }
);
observer.observe(element);
};

1
node_modules/typeit/src/helpers/generateHash.ts generated vendored Normal file
View File

@@ -0,0 +1 @@
export default (): string => Math.random().toString().substring(2, 9);

20
node_modules/typeit/src/helpers/getAllChars.ts generated vendored Normal file
View File

@@ -0,0 +1,20 @@
import isInput from "./isInput";
import { El } from "../types";
import toArray from "./toArray";
import { walkElementNodes } from "./chunkStrings";
/**
* Get a flattened array of text nodes that have been typed.
* This excludes any cursor character that might exist.
*/
let getAllChars = (element: El) => {
if (isInput(element)) {
return toArray(element.value);
}
return walkElementNodes(element, true).filter(
(c) => !(c.childNodes.length > 0)
);
};
export default getAllChars;

View File

@@ -0,0 +1,9 @@
import { El } from "../types";
let getAnimationFromElement = (element: El): Animation | undefined => {
return element?.getAnimations().find((animation) => {
return animation.id === element.dataset.tiAnimationId;
});
};
export default getAnimationFromElement;

1
node_modules/typeit/src/helpers/getComputedStyle.ts generated vendored Normal file
View File

@@ -0,0 +1 @@
export default (el): CSSStyleDeclaration => window.getComputedStyle(el, null);

13
node_modules/typeit/src/helpers/getParsedBody.ts generated vendored Normal file
View File

@@ -0,0 +1,13 @@
import { El } from "../types";
import expandTextNodes from "./expandTextNodes";
/**
* Parse a string as HTML and return the body
* of the parsed document, with all text nodes expanded.
*/
export default (content): El => {
let doc = document.implementation.createHTMLDocument();
doc.body.innerHTML = content;
return expandTextNodes(doc.body as El);
};

View File

@@ -0,0 +1,5 @@
let handleFunctionalArg = <T>(arg: any | (() => T)): T => {
return typeof arg === "function" ? arg() : arg;
};
export default handleFunctionalArg;

32
node_modules/typeit/src/helpers/insertIntoElement.ts generated vendored Normal file
View File

@@ -0,0 +1,32 @@
import isInput from "./isInput";
import select from "./select";
import { CURSOR_CLASS } from "../constants";
import { El } from "../types";
import isBodyElement from "./isBodyElement";
/**
* Inserts a set of content into the element. Intended for SINGLE characters.
*/
let insertIntoElement = (originalTarget: El, character: El) => {
if (isInput(originalTarget)) {
originalTarget.value = `${originalTarget.value}${character.textContent}`;
return;
}
// Necessary for creating *empty* elements that will
// later be filled with actual characters.
character.innerHTML = "";
let target = isBodyElement(character.originalParent as El)
? 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 as El,
(select("." + CURSOR_CLASS, target) as Node) || null
);
};
export default insertIntoElement;

1
node_modules/typeit/src/helpers/isArray.ts generated vendored Normal file
View File

@@ -0,0 +1 @@
export default (thing: any): boolean => Array.isArray(thing);

5
node_modules/typeit/src/helpers/isBodyElement.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
import { El } from "../types";
let isBodyElement = (node: El): boolean => /body/i.test(node?.tagName);
export default isBodyElement;

1
node_modules/typeit/src/helpers/isInput.ts generated vendored Normal file
View File

@@ -0,0 +1 @@
export default (el: HTMLElement): boolean => "value" in el;

1
node_modules/typeit/src/helpers/isNonVoidElement.ts generated vendored Normal file
View File

@@ -0,0 +1 @@
export default (el) => /<(.+)>(.*?)<\/(.+)>/.test(el.outerHTML);

1
node_modules/typeit/src/helpers/isNumber.ts generated vendored Normal file
View File

@@ -0,0 +1 @@
export default (value: any): boolean => Number.isInteger(value);

1
node_modules/typeit/src/helpers/merge.ts generated vendored Normal file
View File

@@ -0,0 +1 @@
export default (originalObj, newObj) => Object.assign({}, originalObj, newObj);

View File

@@ -0,0 +1,35 @@
import { DEFAULT_OPTIONS } from "../constants";
import { CursorOptions } from "../types";
import merge from "./merge";
let processCursorOptions = (
cursorOptions: boolean | CursorOptions
): boolean | CursorOptions => {
if (typeof cursorOptions === "object") {
let newOptions: CursorOptions = {};
let { frames: defaultFrames, options: defaultOptions } =
DEFAULT_OPTIONS.cursor.animation;
newOptions.animation = cursorOptions.animation || {};
newOptions.animation.frames =
cursorOptions.animation?.frames || defaultFrames;
newOptions.animation.options = merge(
defaultOptions,
cursorOptions.animation?.options || {}
);
newOptions.autoPause =
cursorOptions.autoPause ?? DEFAULT_OPTIONS.cursor.autoPause;
newOptions.autoPauseDelay =
cursorOptions.autoPauseDelay || DEFAULT_OPTIONS.cursor.autoPauseDelay;
return newOptions;
}
if (cursorOptions === true) {
return DEFAULT_OPTIONS.cursor;
}
return cursorOptions;
};
export default processCursorOptions;

5
node_modules/typeit/src/helpers/randomInRange.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
export default (value: number, range: number): number => {
return Math.abs(
Math.random() * (value + range - (value - range)) + (value - range)
);
};

View File

@@ -0,0 +1,49 @@
import { El, CursorOptions } from "../types";
import getAnimationFromElement from "./getAnimationFromElement";
import setCursorAnimation from "./setCursorAnimation";
interface rebuildCursorAnimationArgs {
cursor: El | undefined;
cursorOptions: CursorOptions;
options: any;
}
let rebuildCursorAnimation = ({
cursor,
options,
cursorOptions,
}: rebuildCursorAnimationArgs): Animation => {
if (!cursor || !cursorOptions) return;
let animation = getAnimationFromElement(cursor);
let oldCurrentTime: number;
// An existing animation is actively running...
// so carry over the timing properties we care about.
if (animation) {
options.delay = animation.effect.getComputedTiming().delay;
// This needs to be set later, since there's no way to pass
// the current time into the constructor.
oldCurrentTime = animation.currentTime;
animation.cancel();
}
// Create a new animation using the same
// configuration as the previous one.
let newAnimation = setCursorAnimation({
cursor,
frames: cursorOptions.animation.frames,
options,
});
// By setting the currentTime, the animation will
// be in sync with the previous one.
if (oldCurrentTime) {
newAnimation.currentTime = oldCurrentTime;
}
return newAnimation;
};
export default rebuildCursorAnimation;

16
node_modules/typeit/src/helpers/removeNode.ts generated vendored Normal file
View File

@@ -0,0 +1,16 @@
import { El } from "../types";
export default (node: Node, rootElement: El): void => {
if (!node) return;
let nodeParent = node.parentNode as HTMLElement;
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 as Element).remove();
};

15
node_modules/typeit/src/helpers/repositionCursor.ts generated vendored Normal file
View File

@@ -0,0 +1,15 @@
import { CURSOR_CLASS } from "../constants";
import select from "./select";
import { El } from "../types";
export default (
element: HTMLElement,
allChars: any[],
newCursorPosition: number
): void => {
let nodeToInsertBefore = allChars[newCursorPosition - 1];
let cursor = select(`.${CURSOR_CLASS}`, element) as El;
element = nodeToInsertBefore?.parentNode || element;
element.insertBefore(cursor as any, nodeToInsertBefore || null);
};

9
node_modules/typeit/src/helpers/select.ts generated vendored Normal file
View File

@@ -0,0 +1,9 @@
let select = (
selector: string,
element: Node = document,
all: boolean = false
): Node | NodeList | null => {
return element[`querySelector${all ? "All" : ""}`](selector);
};
export default select;

6
node_modules/typeit/src/helpers/selectorToElement.ts generated vendored Normal file
View File

@@ -0,0 +1,6 @@
import { El } from "../types";
import select from "./select";
export default function (thing: string | El): El {
return typeof thing === "string" ? (select(thing as string) as El) : thing;
}

34
node_modules/typeit/src/helpers/setCursorAnimation.ts generated vendored Normal file
View File

@@ -0,0 +1,34 @@
import { El } from "../types";
import beforePaint from "./beforePaint";
/**
* Create and return an animation for the cursor.
*/
let setCursorAnimation = ({
cursor,
frames,
options,
}: {
cursor: El;
frames: AnimationKeyFrame[];
options: Partial<AnimationEffectTiming>;
}): Animation => {
let animation = cursor.animate(frames, options);
animation.pause();
animation.id = cursor.dataset.tiAnimationId;
// Kicking back the animation until after the next repaint
// prevents odd freezing issues when a new animation is
// generated in place of an older one.
beforePaint(() => {
beforePaint(() => {
animation.play();
});
});
return animation;
};
export default setCursorAnimation;

33
node_modules/typeit/src/helpers/setCursorStyles.ts generated vendored Normal file
View File

@@ -0,0 +1,33 @@
import { CURSOR_CLASS, DATA_ATTRIBUTE } from "../constants";
import { El } from "../types";
import appendStyleBlock from "./appendStyleBlock";
export let cursorFontStyles = {
"font-family": "",
"font-weight": "",
"font-size": "",
"font-style": "",
"line-height": "",
color: "",
transform: "translateX(-.125em)",
} as const;
export let setCursorStyles = (id: string, element: El) => {
let rootSelector = `[${DATA_ATTRIBUTE}='${id}']`;
let cursorSelector = `${rootSelector} .${CURSOR_CLASS}`;
let computedStyles = getComputedStyle(element);
let customProperties: string = Object.entries(cursorFontStyles).reduce(
(accumulator, [item, value]) => {
return `${accumulator} ${item}: var(--ti-cursor-${item}, ${
value || computedStyles[item]
});`;
},
""
);
// Set animation styles & custom properties.
appendStyleBlock(
`${cursorSelector} { display: inline-block; width: 0; ${customProperties} }`,
id
);
};

8
node_modules/typeit/src/helpers/toArray.ts generated vendored Normal file
View File

@@ -0,0 +1,8 @@
/**
* 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);

View File

@@ -0,0 +1,12 @@
let updateCursorPosition = (
steps: number,
cursorPosition: number,
printedCharacters: Element[]
) => {
return Math.min(
Math.max(cursorPosition + steps, 0),
printedCharacters.length
);
};
export default updateCursorPosition;

20
node_modules/typeit/src/helpers/wait.ts generated vendored Normal file
View File

@@ -0,0 +1,20 @@
/**
* Fire a callback after a delay, and add the timeout ID to a referenced array.
*/
let wait = (
callback: Function,
delay: number | undefined,
timeouts: number[]
) => {
return new Promise<void>((resolve) => {
let cb = async () => {
await callback();
resolve();
};
timeouts.push(setTimeout(cb, delay || 0) as unknown as number);
});
};
export default wait;

682
node_modules/typeit/src/index.ts generated vendored Normal file
View File

@@ -0,0 +1,682 @@
import Queue from "./Queue";
import { maybeChunkStringAsHtml } from "./helpers/chunkStrings";
import expandTextNodes from "./helpers/expandTextNodes";
import appendStyleBlock from "./helpers/appendStyleBlock";
import asArray from "./helpers/asArray";
import calculateDelay from "./helpers/calculateDelay";
import calculatePace from "./helpers/calculatePace";
import createElement from "./helpers/createElement";
import destroyTimeouts from "./helpers/destroyTimeouts";
import generateHash from "./helpers/generateHash";
import getAllChars from "./helpers/getAllChars";
import fireWhenVisible from "./helpers/fireWhenVisible";
import getParsedBody from "./helpers/getParsedBody";
import handleFunctionalArg from "./helpers/handleFunctionalArg";
import isNumber from "./helpers/isNumber";
import insertIntoElement from "./helpers/insertIntoElement";
import isInput from "./helpers/isInput";
import updateCursorPosition from "./helpers/updateCursorPosition";
import merge from "./helpers/merge";
import removeNode from "./helpers/removeNode";
import repositionCursor from "./helpers/repositionCursor";
import selectorToElement from "./helpers/selectorToElement";
import isNonVoidElement from "./helpers/isNonVoidElement";
import wait from "./helpers/wait";
import { setCursorStyles } from "./helpers/setCursorStyles";
import {
El,
Options,
QueueItem,
ActionOpts,
TypeItInstance,
QueueMapPair,
CursorOptions,
} from "./types";
import {
CURSOR_CLASS,
DEFAULT_STATUSES,
DEFAULT_OPTIONS,
PLACEHOLDER_CSS,
} from "./constants";
import duplicate from "./helpers/duplicate";
import countStepsToSelector from "./helpers/countStepsToSelector";
import fireItem from "./helpers/fireItem";
import setCursorAnimation from "./helpers/setCursorAnimation";
import processCursorOptions from "./helpers/processCursorOptions";
// Necessary for publicly exposing types.
export declare type TypeItOptions = Options;
const TypeIt: TypeItInstance = function (element, options = {}) {
let _wait = async (
callback: Function,
delay: number | undefined,
silent: boolean = false
): Promise<void> => {
if (_statuses.frozen) {
await new Promise<void>((resolve) => {
this.unfreeze = () => {
_statuses.frozen = false;
resolve();
};
});
}
silent || (await _opts.beforeStep(this));
await wait(callback, delay, _timeouts);
silent || (await _opts.afterStep(this));
};
let _fireItemWithContext = (
index: number,
queueItems: QueueMapPair[]
): Promise<number> => {
return fireItem({
index,
queueItems,
wait: _wait,
cursor: _cursor as El,
cursorOptions: _opts.cursor as CursorOptions,
});
};
let _removeNode = (node) => removeNode(node, _element);
let _elementIsInput = () => isInput(_element);
let _getPace = (index: number = 0): number => calculatePace(_opts)[index];
let _getAllChars = (): El[] => getAllChars(_element);
let _maybeAppendPause = (opts: ActionOpts = {}) => {
let delay = opts.delay;
delay && _queue.add({ delay });
};
let _queueAndReturn = (steps: QueueItem[] | QueueItem, opts: ActionOpts) => {
_queue.add(steps);
_maybeAppendPause(opts);
return this;
};
let _getDerivedCursorPosition = () =>
_predictedCursorPosition ?? _cursorPosition;
let _generateTemporaryOptionQueueItems = (
newOptions: Options = {}
): QueueItem[] => {
return [
{ func: () => _options(newOptions) },
{ func: () => _options(_opts) },
];
};
/**
* Add items to the queue with a split pause
* wrapped around them.
*/
let _addSplitPause = (items: QueueItem[]) => {
let delay = _opts.nextStringDelay;
_queue.add([{ delay: delay[0] }, ...items, { delay: delay[1] }]);
};
/**
* Provided it's a non-form element and the options is provided,
* set up the cursor element for the
*/
let _setUpCursor = (): void | El => {
if (_elementIsInput()) {
return;
}
// If we have a cursor node from a previous instance (prior to a reset()),
// there's no need to recreate one now.
let cursor = createElement("span");
cursor.className = CURSOR_CLASS;
// Don't bother touching up the cursor if we don't want it to visibly render anyway.
if (!_shouldRenderCursor) {
cursor.style.visibility = "hidden";
return cursor as El;
}
cursor.innerHTML = getParsedBody(_opts.cursorChar).innerHTML;
return cursor as El;
};
/**
* Attach it to the DOM so, along with the required CSS transition.
*/
let _attachCursor = async () => {
!_elementIsInput() && _cursor && _element.appendChild(_cursor);
if (_shouldRenderCursor) {
setCursorStyles(_id, _element);
(_cursor as El).dataset.tiAnimationId = _id;
let { animation } = _opts.cursor as CursorOptions;
let { frames, options } = animation;
setCursorAnimation({
frames,
cursor: _cursor as El,
options: {
duration: _opts.cursorSpeed,
...options,
},
});
}
};
/**
* Based on provided strings, generate a TypeIt queue
* to be fired for each character in the string.
*/
let _generateQueue = () => {
let strings = (_opts.strings as string[]).filter((string) => !!string);
strings.forEach((string, index) => {
this.type(string);
// This is the last string. Get outta here.
if (index + 1 === strings.length) {
return;
}
let splitItems: QueueItem[] = _opts.breakLines
? [{ func: () => _type(createElement("BR")), typeable: true }]
: duplicate(
{
func: _delete,
delay: _getPace(1),
},
_queue.getTypeable().length
);
_addSplitPause(splitItems);
});
};
/**
* 1. Reset queue.
* 2. Reset initial pause.
*/
let _prepLoop = async (delay: number) => {
let derivedCursorPosition = _getDerivedCursorPosition();
derivedCursorPosition && (await _move({ value: derivedCursorPosition }));
// Grab all characters currently mounted to the DOM,
// in order to wipe the slate clean before restarting.
//
// It's important to first convert each deletion to a
// queue item, so that we can take advantage of the same
// cursor-pausing logic (and anything else that might be
// introduced in the future).
let queueItems: QueueMapPair[] = _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);
}
_queue.reset();
_queue.set(0, { delay });
};
let _maybePrependHardcodedStrings = (strings): string[] => {
let existingMarkup = _element.innerHTML;
if (!existingMarkup) {
return strings;
}
// Once we've saved the existing markup to a variable,
// wipe the element clean to prepare for typing.
_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);
};
/**
* Execute items in the queue.
*
* @param remember If false, each queue item will be destroyed once executed.
* @returns
*/
let _fire = async (remember = true): Promise<TypeItInstance> => {
_statuses.started = true;
// @todo remove this eventually..
// console.log(
// "Total time:",
// queueItems.reduce((total, step) => {
// total = total + step.delay;
// return total;
// }, 0)
// );
let cleanUp = (qKey) => {
_queue.done(qKey, !remember);
};
try {
let queueItems = [..._queue.getQueue()] as QueueMapPair[];
for (let index = 0; index < queueItems.length; index++) {
let [queueKey, queueItem] = queueItems[index];
// Only execute items that aren't done yet.
if (queueItem.done) continue;
// Because calling .delete() with no parameters will attempt to
// delete all "typeable" characters, we may overfetch, since some characters
// in the queue may already be deleted. This ensures that we do not attempt to
// delete a character that isn't actually mounted to the DOM.
if (
!queueItem.deletable ||
(queueItem.deletable && _getAllChars().length)
) {
let newIndex = await _fireItemWithContext(index, queueItems);
// Ensure each skipped item goes through the cleanup process,
// so that methods like .flush() don't get messed up.
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) {}
return this;
};
/**
* Move type cursor by a given number.
*/
let _move = async (step): Promise<void> => {
_cursorPosition = updateCursorPosition(
step,
_cursorPosition,
_getAllChars()
);
repositionCursor(_element, _getAllChars(), _cursorPosition);
};
/**
* Insert a single or many characters into the target element.
*/
let _type = (char): void => 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 = (): void => {
let allChars = _getAllChars();
if (!allChars.length) return;
if (_elementIsInput()) {
_element.value = (_element.value as string).slice(0, -1);
} else {
_removeNode(allChars[_cursorPosition]);
}
};
this.break = function (actionOpts: ActionOpts) {
return _queueAndReturn(
{
func: () => _type(createElement("BR")),
typeable: true,
},
actionOpts
);
};
this.delete = function (
numCharacters: number | string | (() => number | null) = null,
actionOpts: ActionOpts = {}
) {
numCharacters = handleFunctionalArg<number>(numCharacters);
let bookEndQueueItems = _generateTemporaryOptionQueueItems(actionOpts);
let num = numCharacters;
let { instant, to } = actionOpts;
let typeableQueueItems = _queue.getTypeable();
let rounds = (() => {
if (num === null) {
return typeableQueueItems.length;
}
if (isNumber(num)) {
return num;
}
return countStepsToSelector({
queueItems: typeableQueueItems,
selector: num,
cursorPosition: _getDerivedCursorPosition(),
to,
});
})();
return _queueAndReturn(
[
bookEndQueueItems[0],
...duplicate(
{
func: _delete,
delay: instant ? 0 : _getPace(1),
deletable: true,
},
rounds
),
bookEndQueueItems[1],
],
actionOpts
);
};
this.empty = function (actionOpts: ActionOpts = {}) {
return _queueAndReturn({ func: _empty }, actionOpts);
};
this.exec = function (
func: (instance: TypeItInstance) => any,
actionOpts: ActionOpts = {}
) {
let bookEndQueueItems = _generateTemporaryOptionQueueItems(actionOpts);
return _queueAndReturn(
[bookEndQueueItems[0], { func: () => func(this) }, bookEndQueueItems[1]],
actionOpts
);
};
this.move = function (
movementArg: string | number | (() => string | number),
actionOpts: ActionOpts = {}
) {
movementArg = handleFunctionalArg<string | number>(movementArg);
let bookEndQueueItems = _generateTemporaryOptionQueueItems(actionOpts);
let { instant, to } = actionOpts;
let numberOfSteps = countStepsToSelector({
queueItems: _queue.getTypeable(),
selector: movementArg === null ? "" : movementArg,
to,
cursorPosition: _getDerivedCursorPosition(),
});
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
);
};
this.options = function (
opts: Options | (() => Options),
actionOpts: ActionOpts = {}
) {
opts = handleFunctionalArg<Options>(opts);
_options(opts);
return _queueAndReturn({}, actionOpts);
};
this.pause = function (
milliseconds: number | (() => number),
actionOpts: ActionOpts = {}
) {
return _queueAndReturn(
{ delay: handleFunctionalArg<number>(milliseconds) },
actionOpts
);
};
this.type = function (
string: string | (() => string),
actionOpts: ActionOpts = {}
) {
string = handleFunctionalArg<string>(string);
let { instant } = actionOpts;
let bookEndQueueItems = _generateTemporaryOptionQueueItems(actionOpts);
let chars = maybeChunkStringAsHtml(string, _opts.html);
let charsAsQueueItems = chars.map((char): QueueItem => {
return {
func: () => _type(char),
char,
delay: instant || isNonVoidElement(char) ? 0 : _getPace(),
typeable: char.nodeType === Node.TEXT_NODE,
};
});
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): boolean {
return _statuses[key];
};
this.destroy = function (shouldRemoveCursor = true) {
_timeouts = destroyTimeouts(_timeouts);
handleFunctionalArg<boolean>(shouldRemoveCursor) &&
_cursor &&
_removeNode(_cursor);
_statuses.destroyed = true;
};
this.freeze = function () {
_statuses.frozen = true;
};
this.unfreeze = () => {};
this.reset = function (rebuild: ((TypeIt) => typeof TypeIt) | undefined) {
!this.is("destroyed") && this.destroy();
// If provided, the queue can be totally regenerated.
if (rebuild) {
_queue.wipe();
rebuild(this);
} else {
_queue.reset();
}
_cursorPosition = 0;
for (let property in _statuses) {
_statuses[property] = false;
}
_element[_elementIsInput() ? "value" : "innerHTML"] = "";
return this;
};
/**
* Can only be called once.
*/
this.go = function () {
if (_statuses.started) {
return this;
}
_attachCursor();
if (!_opts.waitUntilVisible) {
_fire();
return this;
}
fireWhenVisible(_element, _fire.bind(this));
return this;
};
/**
* 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.
*/
this.flush = function (cb: () => any = () => {}) {
_attachCursor();
_fire(false).then(cb);
return this;
};
this.getQueue = () => _queue;
this.getOptions = () => _opts;
this.updateOptions = (options: Options) => _options(options);
this.getElement = () => _element;
let _element = selectorToElement(element);
let _timeouts: number[] = [];
let _cursorPosition = 0;
let _predictedCursorPosition = null;
let _statuses = merge({}, DEFAULT_STATUSES);
options.cursor = processCursorOptions(
options.cursor ?? DEFAULT_OPTIONS.cursor
);
let _opts: Options = 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;
// Used to set a "placeholder" space in the element, so that it holds vertical sizing before anything's typed.
appendStyleBlock(PLACEHOLDER_CSS);
let _shouldRenderCursor = !!_opts.cursor && !_elementIsInput();
let _cursor = _setUpCursor();
_opts.strings = _maybePrependHardcodedStrings(asArray<string>(_opts.strings));
// Only generate a queue if we have strings
// and this isn't a reset of a previous instance,
// in which case we'd have a pre-defined queue.
if (_opts.strings.length) {
_generateQueue();
}
};
export default TypeIt;

78
node_modules/typeit/src/types.ts generated vendored Normal file
View File

@@ -0,0 +1,78 @@
export type TypeItInstance = (element: El | string, options: Options) => void;
export type Character = {
node: El | null;
content: string | Node;
};
export interface CursorAnimationOptions {
frames?: AnimationKeyFrame[];
options?: Partial<AnimationEffectTiming>;
}
export interface CursorOptions {
autoPause?: boolean;
autoPauseDelay?: number;
animation?: CursorAnimationOptions;
}
export interface Options {
breakLines?: boolean;
cursorChar?: string;
cursor?: CursorOptions | boolean;
// @todo: Remove in next major release.
cursorSpeed?: number;
deleteSpeed?: null | number;
html?: boolean;
lifeLike?: boolean;
loop?: boolean;
loopDelay?: number;
nextStringDelay?: number;
speed?: number;
startDelay?: number;
startDelete?: boolean;
strings?: string[] | string;
waitUntilVisible?: boolean;
beforeString?: Function;
afterString?: Function;
beforeStep?: Function;
afterStep?: Function;
afterComplete?: Function;
}
export type ActionOpts = Options & {
to?: Sides;
instant?: boolean;
delay?: number;
};
export type QueueItem = {
done?: boolean;
func?: () => any;
delay?: number;
char?: any;
// A queue item that can be visibly 'typed' to the
// screen, including those queued with ".type()" and ".break()"
typeable?: boolean;
deletable?: boolean;
// An explicit indicator that a queue item should pause
// the cursor animation during execution.
cursorable?: boolean;
// An item should pause the cursor of it's
// EITHER "typeable," "cusorable," or "deleteable."
shouldPauseCursor?: () => boolean;
};
export type QueueMapPair = [Symbol, QueueItem];
export interface El extends HTMLElement {
value: string | number;
originalParent?: HTMLElement;
}
export type Sides = "START" | "END";