UNPKG

typecadence

Version:

Typing animation library that automatically mimics the flaws a human typist

725 lines 43 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; (function (global, factory) { if (typeof exports === 'object' && typeof module !== 'undefined') { module.exports = factory(); } else if (typeof define === 'function' && define.amd) { define(factory); } else { global.Typecadence = factory(); } }(this, function () { 'use strict'; var _Typecadence_instances, _a, _Typecadence_instance, _Typecadence_elements, _Typecadence_playbackState, _Typecadence_storedText, _Typecadence_defaultSettings, _Typecadence_adjacentMapping, _Typecadence_observer, _Typecadence_handleIntersect, _Typecadence_parseAnimationSettings, _Typecadence_parseSpeedAttribute, _Typecadence_parsePercent, _Typecadence_getTypingSpeed, _Typecadence_createCaret, _Typecadence_isMistake, _Typecadence_incorrectChar, _Typecadence_backspace, _Typecadence_waitIfPaused, _Typecadence_parseHtmlToTokens, _Typecadence_animateText; class Typecadence { constructor() { _Typecadence_instances.add(this); _Typecadence_elements.set(this, void 0); _Typecadence_playbackState.set(this, new Map()); _Typecadence_storedText.set(this, new Map()); _Typecadence_defaultSettings.set(this, { debug: false, delay: 0, minSpeed: 50, maxSpeed: 100, caret: true, caretChar: '|', caretColor: '', caretBold: true, caretBlink: true, caretBlinkSpeed: 500, caretTag: 'span', caretClass: '', caretId: '', caretRemain: false, caretRemainTimeout: null, spaceMinSpeed: null, spaceMaxSpeed: null, backspaceMinSpeed: null, backspaceMaxSpeed: null, mistakes: 5, mistakesPresent: 1, callback: '', keyboard: KeyboardLayout.QWERTY, }); _Typecadence_adjacentMapping.set(this, { qwerty: { '`': ['1', '2', 'q', 'w'], '1': ['2', 'q', '`'], '2': ['1', 'q', 'w', '3'], '3': ['2', 'w', 'e', '4'], '4': ['3', 'e', 'r', '5'], '5': ['4', 'r', 't', '6'], '6': ['5', 't', 'y', '7'], '7': ['6', 'y', 'u', '8'], '8': ['7', 'u', 'i', '9'], '9': ['8', 'i', 'o', '0'], '0': ['9', 'o', 'p', '-'], '-': ['0', 'p', '[', '='], '=': ['-', '[', ']'], 'q': ['1', '2', 'w', 'a', '`'], 'w': ['q', 'a', 's', 'e', '3', '2'], 'e': ['w', 's', 'd', 'r', '4', '3'], 'r': ['e', 'd', 'f', 't', '5', '4'], 't': ['r', 'f', 'g', 'y', '6', '5'], 'y': ['t', 'g', 'h', 'u', '7', '6'], 'u': ['y', 'h', 'j', 'i', '8', '7'], 'i': ['u', 'j', 'k', 'o', '9', '8'], 'o': ['i', 'k', 'l', 'p', '0', '9'], 'p': ['o', 'l', ';', '[', '-', '0'], '[': ['p', ';', '\'', ']', '=', '-'], ']': ['[', '\'', '\\', '='], 'a': ['q', 'w', 's', 'z'], 's': ['a', 'z', 'x', 'd', 'e', 'w'], 'd': ['s', 'x', 'c', 'f', 'r', 'e'], 'f': ['d', 'c', 'v', 'g', 't', 'r'], 'g': ['f', 'v', 'b', 'h', 'y', 't'], 'h': ['g', 'b', 'n', 'j', 'u', 'y'], 'j': ['h', 'n', 'm', 'k', 'i', 'u'], 'k': ['j', 'm', ',', 'l', 'o', 'i'], 'l': ['k', ',', '.', ';', 'p', 'o'], ';': ['l', '.', '/', '\'', '[', 'p'], '\'': [';', '/', ']', '['], 'z': ['a', 's', 'x'], 'x': ['z', 's', 'c', 'd'], 'c': ['x', 'd', 'f', 'v'], 'v': ['c', 'f', 'g', 'b'], 'b': ['v', 'g', 'h', 'n'], 'n': ['b', 'h', 'j', 'm'], 'm': ['n', 'j', 'k', ','], ',': ['m', 'k', 'l', '.'], '.': [',', 'l', ';', '/'], '/': ['.', ';', '\''], '\\': [']', '[', '\''], }, qwertz: { '1': ['2', 'q', 'a', 'y', '0'], '2': ['1', 'q', 'w', 's', 'e', '3'], '3': ['2', 'w', 'e', 'd', 'r', '4'], '4': ['3', 'e', 'r', 'f', 't', '5'], '5': ['4', 't', 'z', 'g', 'h', '6'], '6': ['5', 'z', 'u', 'h', 'j', '7'], '7': ['6', 'u', 'i', 'j', 'k', '8'], '8': ['7', 'i', 'o', 'k', 'l', '9'], '9': ['8', 'o', 'p', 'l', 'm', 'ß'], '0': ['9', 'p', 'ü', 'ß', '´'], 'ß': ['0', 'ü', '+', '´'], 'q': ['1', '2', 'w', 'a', 'y'], 'w': ['q', 'a', 's', 'e', 'd', '2', '3'], 'e': ['w', 's', 'd', 'f', 'r', '3', '4'], 'r': ['e', 'd', 'f', 'g', 't', '4', '5'], 't': ['r', 'f', 'g', 'h', 'z', '5', '6'], 'z': ['t', 'g', 'h', 'u', 'i', '6', '7'], 'u': ['z', 'h', 'j', 'k', 'o', '7', '8'], 'i': ['u', 'j', 'k', 'l', 'p', 'ö', 'ü', '8', '9'], 'o': ['i', 'k', 'l', 'ö', 'ä', 'p', '9', '0'], 'p': ['o', 'l', 'ö', 'ä', 'ü', '+', '0', 'ß'], 'a': ['q', 'w', 's', 'y'], 's': ['a', 'w', 'e', 'd', 'x', 'y'], 'd': ['s', 'e', 'r', 'f', 'c', 'x'], 'f': ['d', 'r', 't', 'g', 'v', 'c'], 'g': ['f', 't', 'z', 'h', 'b', 'v'], 'h': ['g', 'z', 'u', 'j', 'n', 'b'], 'j': ['h', 'u', 'i', 'k', 'm', 'n'], 'k': ['j', 'i', 'o', 'l', ',', 'm'], 'l': ['k', 'o', 'p', 'ö', 'ä', 'ü', 'm'], 'ö': ['l', 'p', 'ü', 'ä'], 'ä': ['ö', 'p', 'ü'], 'y': ['q', 'a', 's', 'x'], 'x': ['y', 's', 'd', 'c'], 'c': ['x', 'd', 'f', 'v'], 'v': ['c', 'f', 'g', 'b'], 'b': ['v', 'g', 'h', 'n'], 'n': ['b', 'h', 'j', 'm'], 'm': ['n', 'j', 'k', 'l', ','], ',': ['m', 'k', 'l', ';', '.', '-'], '.': [',', 'l', ';', ':', '/', '-'], '-': ['.', ';', ':', '_', '+'], '+': ['-', ':', 'ß', '´'], '´': ['+', 'ß'], }, azerty: { '1': ['2', '&', 'a', 'z'], '2': ['1', 'a', 'z', 'e', '3'], '3': ['2', 'e', 'r', 'z', 'u', '4'], '4': ['3', 'r', 't', 'u', 'i', 'f', '5'], '5': ['4', 't', 'y', 'i', 'o', 'g', '6'], '6': ['5', 'y', 'u', 'o', 'p', 'h', '7'], '7': ['6', 'u', 'i', 'p', '¨', 'j', '8'], '8': ['7', 'i', 'o', '¨', 'k', 'l', 'm', '9'], '9': ['8', 'o', 'p', 'l', 'm', 'ù', '0'], '0': ['9', 'p', 'm', 'ù', '²'], 'q': ['a', 'z', 'w', 's', '2'], 'w': ['q', 'z', 'e', 's', 'd', '3'], 'e': ['w', 's', 'd', 'f', 'r', '4'], 'r': ['e', 'd', 'f', 'g', 't', '5'], 't': ['r', 'f', 'g', 'h', 'y', '6'], 'y': ['t', 'g', 'h', 'j', 'u', '7'], 'u': ['y', 'h', 'j', 'k', 'i', 'z', '8'], 'i': ['u', 'j', 'k', 'l', 'o', 'è', '9'], 'o': ['i', 'k', 'l', 'm', 'p', 'à', '0'], 'p': ['o', 'l', 'm', 'ù', '0', '^', '$'], 'a': ['q', 'w', 'z', 'x'], 's': ['a', 'z', 'e', 'd', 'x', 'c'], 'd': ['s', 'e', 'r', 'f', 'c', 'v'], 'f': ['d', 'r', 't', 'g', 'v', 'b'], 'g': ['f', 't', 'y', 'h', 'b', 'n'], 'h': ['g', 'y', 'u', 'j', 'n', 'm'], 'j': ['h', 'u', 'i', 'k', 'm', ',', ';'], 'k': ['j', 'i', 'o', 'l', ',', 'm', '!'], 'l': ['k', 'o', 'p', 'm', 'ù', '²', ':'], 'm': ['l', 'p', 'ù', '²', '$', '*'], 'ù': ['m', 'p', '0', '²', '*', '%'], 'z': ['a', 'q', 's', 'e'], 'x': ['z', 's', 'd', 'c'], 'c': ['x', 'd', 'f', 'v'], 'v': ['c', 'f', 'g', 'b'], 'b': ['v', 'g', 'h', 'n'], 'n': ['b', 'h', 'j', 'm'], ',': ['m', 'j', 'k', ';', ':', '!'], ';': [',', 'k', 'l', 'm', ':', '*'], ':': [';', 'l', 'ù', '$', '*', '%'], '!': [':', 'k', 'm', 'ù', '$', '*'], '$': ['ù', 'm', ',', ';', ':', '!'], '^': ['p', 'ù', '*', '$'], '*': ['^', 'ù', 'm', ',', ';', ':', '!'], '%': ['^', 'ù', ':', '$', '*'], '²': ['&', 'é', '"', '(', '-', 'è', '_', 'ç', 'à', ')', '=', '0'], '&': ['1', 'a', 'z', 'é', '2', 'é', '²'], 'é': ['&', 'a', 'z', 'e', '"', '2', '²', '(', 'è', '3'], '"': ['é', 'z', 'e', 'r', "'", '(', '²', '-', 'è', '4'], '\'': ['"', 'e', 'r', 't', '(', 'è', '5', 'è'], '(': ['"', 'é', 'r', 't', 'y', 'u', 'è', '_', 'ç', '6'], '-': ['²', '(', 'è', 'y', 'u', 'i', 'è', 'ç', '8', '0', '=', ')'], 'è': ['-', 'y', 'u', 'i', 'o', 'p', '^', '$', '*', '(', '_', 'ç', 'à', ')', '=', '²'], '_': ['-', '(', 'è', 'u', 'i', 'o', 'p', '^', '$', '*', 'ç', 'à', ')', '=', '0'], 'ç': ['²', 'è', '_', 'a', 'q', 'w', 'x', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'ù', '²', '!', ':', '*', ')', '=', 'à'], 'à': ['ç', '²', '(', '-', '0', ')', '=', '_'], '=': ['-', '0', '²', ')', '_', 'ç', 'à'], } }); _Typecadence_observer.set(this, void 0); if (__classPrivateFieldGet(_a, _a, "f", _Typecadence_instance)) { return __classPrivateFieldGet(_a, _a, "f", _Typecadence_instance); } __classPrivateFieldSet(this, _Typecadence_elements, document.querySelectorAll(".typecadence"), "f"); __classPrivateFieldSet(this, _Typecadence_observer, new IntersectionObserver(__classPrivateFieldGet(this, _Typecadence_instances, "m", _Typecadence_handleIntersect).bind(this), { root: null, rootMargin: "0px", threshold: 0.1, }), "f"); __classPrivateFieldSet(_a, _a, this, "f", _Typecadence_instance); this.init(); } /** @internal Reset singleton for testing. */ static _resetInstance() { __classPrivateFieldSet(_a, _a, null, "f", _Typecadence_instance); } init() { var _b; for (const element of __classPrivateFieldGet(this, _Typecadence_elements, "f")) { // For manual trigger elements, hide text immediately and store it const triggerAttr = (_b = element.getAttribute("data-typecadence-trigger")) === null || _b === void 0 ? void 0 : _b.toLowerCase(); if (triggerAttr === TriggerMode.MANUAL) { __classPrivateFieldGet(this, _Typecadence_storedText, "f").set(element, element.innerHTML.trim()); element.innerHTML = ''; } __classPrivateFieldGet(this, _Typecadence_observer, "f").observe(element); } } static play(element) { const instance = __classPrivateFieldGet(_a, _a, "f", _Typecadence_instance); if (!instance) { console.warn('Typecadence: No instance available. Ensure Typecadence is initialized.'); return null; } const targetElement = typeof element === 'string' ? document.querySelector(element) : element; if (!targetElement) { console.warn('Typecadence: Element not found.'); return null; } // If animation is active, either resume (if paused) or ignore const state = __classPrivateFieldGet(instance, _Typecadence_playbackState, "f").get(targetElement); if (state) { if (state.paused && state.resumeResolve) { state.paused = false; state.resumeResolve(); state.resumeResolve = undefined; } return null; } // Otherwise start a new animation return __classPrivateFieldGet(instance, _Typecadence_instances, "m", _Typecadence_animateText).call(instance, targetElement); } static pause(element) { const instance = __classPrivateFieldGet(_a, _a, "f", _Typecadence_instance); if (!instance) { console.warn('Typecadence: No instance available. Ensure Typecadence is initialized.'); return false; } const targetElement = typeof element === 'string' ? document.querySelector(element) : element; if (!targetElement) { console.warn('Typecadence: Element not found.'); return false; } const state = __classPrivateFieldGet(instance, _Typecadence_playbackState, "f").get(targetElement); if (!state) { console.warn('Typecadence: No active animation for this element.'); return false; } state.paused = true; return true; } static restart(element) { const instance = __classPrivateFieldGet(_a, _a, "f", _Typecadence_instance); if (!instance) { console.warn('Typecadence: No instance available. Ensure Typecadence is initialized.'); return null; } const targetElement = typeof element === 'string' ? document.querySelector(element) : element; if (!targetElement) { console.warn('Typecadence: Element not found.'); return null; } const state = __classPrivateFieldGet(instance, _Typecadence_playbackState, "f").get(targetElement); if (state) { // Cancel current animation state.cancelled = true; if (state.caretInterval) { clearInterval(state.caretInterval); } if (state.paused && state.resumeResolve) { state.resumeResolve(); } // Store original text for the next animation to pick up if (state.originalText !== undefined) { __classPrivateFieldGet(instance, _Typecadence_storedText, "f").set(targetElement, state.originalText); targetElement.innerHTML = ''; } __classPrivateFieldGet(instance, _Typecadence_playbackState, "f").delete(targetElement); } return __classPrivateFieldGet(instance, _Typecadence_instances, "m", _Typecadence_animateText).call(instance, targetElement); } } _a = Typecadence, _Typecadence_elements = new WeakMap(), _Typecadence_playbackState = new WeakMap(), _Typecadence_storedText = new WeakMap(), _Typecadence_defaultSettings = new WeakMap(), _Typecadence_adjacentMapping = new WeakMap(), _Typecadence_observer = new WeakMap(), _Typecadence_instances = new WeakSet(), _Typecadence_handleIntersect = function _Typecadence_handleIntersect(entries) { var _b; for (const entry of entries) { if (entry.isIntersecting) { const element = entry.target; const triggerAttr = (_b = element.getAttribute("data-typecadence-trigger")) === null || _b === void 0 ? void 0 : _b.toLowerCase(); if (triggerAttr !== TriggerMode.MANUAL) { __classPrivateFieldGet(this, _Typecadence_instances, "m", _Typecadence_animateText).call(this, element); } __classPrivateFieldGet(this, _Typecadence_observer, "f").unobserve(entry.target); } } }, _Typecadence_parseAnimationSettings = function _Typecadence_parseAnimationSettings(element) { var _b, _c, _d, _e, _f, _g; const debugAttribute = (_b = element.getAttribute("data-typecadence-debug")) === null || _b === void 0 ? void 0 : _b.toLowerCase(); const debug = debugAttribute === "true" ? true : debugAttribute === "false" ? false : __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").debug; const delayAttribute = parseInt(element.getAttribute("data-typecadence-delay")); const delay = isNaN(delayAttribute) ? __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").delay : delayAttribute; const [minSpeed, maxSpeed] = __classPrivateFieldGet(this, _Typecadence_instances, "m", _Typecadence_parseSpeedAttribute).call(this, element.getAttribute("data-typecadence-speed")); const spaceSpeedAttr = element.getAttribute("data-typecadence-space-speed"); const [spaceMinSpeedParsed, spaceMaxSpeedParsed] = spaceSpeedAttr ? __classPrivateFieldGet(this, _Typecadence_instances, "m", _Typecadence_parseSpeedAttribute).call(this, spaceSpeedAttr) : [NaN, NaN]; const spaceMinSpeed = isNaN(spaceMinSpeedParsed) ? __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").spaceMinSpeed : spaceMinSpeedParsed; const spaceMaxSpeed = isNaN(spaceMaxSpeedParsed) ? __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").spaceMaxSpeed : spaceMaxSpeedParsed; const backspaceSpeedAttr = element.getAttribute("data-typecadence-backspace-speed"); const [backspaceMinSpeedParsed, backspaceMaxSpeedParsed] = backspaceSpeedAttr ? __classPrivateFieldGet(this, _Typecadence_instances, "m", _Typecadence_parseSpeedAttribute).call(this, backspaceSpeedAttr) : [NaN, NaN]; const backspaceMinSpeed = isNaN(backspaceMinSpeedParsed) ? __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").backspaceMinSpeed : backspaceMinSpeedParsed; const backspaceMaxSpeed = isNaN(backspaceMaxSpeedParsed) ? __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").backspaceMaxSpeed : backspaceMaxSpeedParsed; const displayCaretAttribute = (_c = element.getAttribute("data-typecadence-caret")) === null || _c === void 0 ? void 0 : _c.toLowerCase(); const caret = displayCaretAttribute === "true" ? true : displayCaretAttribute === "false" ? false : __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").caret; const caretChar = element.getAttribute("data-typecadence-caret-char") || __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").caretChar; const caretColor = element.getAttribute("data-typecadence-caret-color") || __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").caretColor; const caretTag = element.getAttribute("data-typecadence-caret-tag") || __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").caretTag; const caretClass = element.getAttribute("data-typecadence-caret-class") || __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").caretClass; const caretId = element.getAttribute("data-typecadence-caret-id") || __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").caretId; const caretBoldAttribute = (_d = element.getAttribute("data-typecadence-caret-bold")) === null || _d === void 0 ? void 0 : _d.toLowerCase(); const caretBold = caretBoldAttribute === "true" ? true : caretBoldAttribute === "false" ? false : __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").caretBold; const caretBlinkSpeedAttribute = parseInt(element.getAttribute("data-typecadence-caret-blink-speed")); const caretBlinkSpeed = isNaN(caretBlinkSpeedAttribute) ? __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").caretBlinkSpeed : caretBlinkSpeedAttribute; const caretBlinkAttribute = (_e = element.getAttribute("data-typecadence-caret-blink")) === null || _e === void 0 ? void 0 : _e.toLowerCase(); const caretBlink = caretBlinkAttribute === "true" ? true : caretBlinkAttribute === "false" ? false : __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").caretBlink; const caretRemainAttribute = (_f = element.getAttribute("data-typecadence-caret-remain")) === null || _f === void 0 ? void 0 : _f.toLowerCase(); const caretRemain = caretRemainAttribute === "true" ? true : caretRemainAttribute === "false" ? false : __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").caretRemain; const caretRemainTimeoutAttribute = parseInt(element.getAttribute("data-typecadence-caret-remain-timeout")); const caretRemainTimeout = isNaN(caretRemainTimeoutAttribute) ? __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").caretRemainTimeout : caretRemainTimeoutAttribute; const mistakesPercent = __classPrivateFieldGet(this, _Typecadence_instances, "m", _Typecadence_parsePercent).call(this, element.getAttribute("data-typecadence-mistakes")); const mistakes = (mistakesPercent !== null) ? mistakesPercent : __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").mistakes; const mistakesPresentAttribute = parseInt(element.getAttribute("data-typecadence-mistakes-present")); const mistakesPresent = mistakesPresentAttribute < 0 || isNaN(mistakesPresentAttribute) ? __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").mistakesPresent : Math.max(1, mistakesPresentAttribute); const callback = element.getAttribute("data-typecadence-callback") || __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").callback; const keyboardAttribute = (_g = element.getAttribute("data-typecadence-keyboard")) === null || _g === void 0 ? void 0 : _g.toLowerCase(); const keyboard = keyboardAttribute === KeyboardLayout.QWERTZ ? KeyboardLayout.QWERTZ : keyboardAttribute === KeyboardLayout.AZERTY ? KeyboardLayout.AZERTY : __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").keyboard; const animationSettings = { debug, delay, minSpeed, maxSpeed, spaceMinSpeed, spaceMaxSpeed, backspaceMinSpeed, backspaceMaxSpeed, caret, caretTag, caretClass, caretId, caretChar, caretColor, caretBold, caretBlinkSpeed, caretBlink, caretRemain, caretRemainTimeout, callback, mistakes, mistakesPresent, keyboard, }; if (debug) console.debug("Typecadence settings:", animationSettings); return animationSettings; }, _Typecadence_parseSpeedAttribute = function _Typecadence_parseSpeedAttribute(speedAttribute) { const regex = /^\d+(?:[,-]\d+)?$/; if (!speedAttribute || !regex.test(speedAttribute)) return [__classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").minSpeed, __classPrivateFieldGet(this, _Typecadence_defaultSettings, "f").maxSpeed]; const speedValues = speedAttribute.split(/[,-]/).map(Number); if (speedValues.length === 1) return [speedValues[0], speedValues[0]]; return [speedValues[0], speedValues[1]]; }, _Typecadence_parsePercent = function _Typecadence_parsePercent(percentAttribute) { const percent = parseInt(percentAttribute || '', 10); if (isNaN(percent)) { return null; } return percent < 0 ? 0 : (percent > 100 ? 100 : percent); }, _Typecadence_getTypingSpeed = function _Typecadence_getTypingSpeed(minSpeed, maxSpeed) { return Math.floor(Math.random() * (maxSpeed - minSpeed + 1)) + minSpeed; }, _Typecadence_createCaret = function _Typecadence_createCaret(animationSettings) { const caret = document.createElement(animationSettings.caretTag); caret.classList.add("typecadence-caret"); if (animationSettings.caretClass) { for (const cls of animationSettings.caretClass.split(/\s+/)) { if (cls) caret.classList.add(cls); } } if (animationSettings.caretId) { caret.id = animationSettings.caretId; } caret.textContent = animationSettings.caretChar; caret.style.color = animationSettings.caretColor; caret.style.fontWeight = animationSettings.caretBold ? "bold" : "normal"; caret.style.visibility = "visible"; return caret; }, _Typecadence_isMistake = function _Typecadence_isMistake(chance) { if (chance <= 0) return false; return Math.random() * 100 < chance; }, _Typecadence_incorrectChar = function _Typecadence_incorrectChar(desiredChar, keyboard = 'qwerty') { const desiredCharLower = desiredChar.toLowerCase(); const adjacentChars = __classPrivateFieldGet(this, _Typecadence_adjacentMapping, "f")[keyboard][desiredCharLower]; if (!adjacentChars) { return desiredChar; } const randomIndex = Math.floor(Math.random() * adjacentChars.length); const incorrectChar = adjacentChars[randomIndex]; return desiredChar === desiredChar.toUpperCase() ? incorrectChar.toUpperCase() : incorrectChar; }, _Typecadence_backspace = function _Typecadence_backspace(currentElement, caret, minSpeed, maxSpeed) { return __awaiter(this, void 0, void 0, function* () { if (caret) { const n = caret.previousSibling; if (n) currentElement.removeChild(n); } else { const n = currentElement.lastChild; if (n) currentElement.removeChild(n); } yield new Promise(resolve => setTimeout(resolve, __classPrivateFieldGet(this, _Typecadence_instances, "m", _Typecadence_getTypingSpeed).call(this, minSpeed, maxSpeed))); }); }, _Typecadence_waitIfPaused = function _Typecadence_waitIfPaused(element) { return __awaiter(this, void 0, void 0, function* () { const state = __classPrivateFieldGet(this, _Typecadence_playbackState, "f").get(element); if (state === null || state === void 0 ? void 0 : state.paused) { yield new Promise(resolve => { state.resumeResolve = resolve; }); } }); }, _Typecadence_parseHtmlToTokens = function _Typecadence_parseHtmlToTokens(html) { const scratch = document.createElement('div'); scratch.innerHTML = html; const tokens = []; const VOID_TAGS = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']); const walk = (node) => { var _b; if (node.nodeType === Node.TEXT_NODE) { for (const char of ((_b = node.textContent) !== null && _b !== void 0 ? _b : '')) { tokens.push({ type: 'char', char }); } } else if (node.nodeType === Node.ELEMENT_NODE) { const el = node; if (VOID_TAGS.has(el.tagName.toLowerCase())) { tokens.push({ type: 'insert', el: el.cloneNode(false) }); } else { tokens.push({ type: 'open', el: el.cloneNode(false) }); for (const child of Array.from(el.childNodes)) walk(child); tokens.push({ type: 'close' }); } } }; for (const child of Array.from(scratch.childNodes)) walk(child); return tokens; }, _Typecadence_animateText = function _Typecadence_animateText(element) { return __awaiter(this, void 0, void 0, function* () { var _b, _c, _d, _e, _f, _g; const animationSettings = __classPrivateFieldGet(this, _Typecadence_instances, "m", _Typecadence_parseAnimationSettings).call(this, element); // Define HTML content (use pre-stored content for manual trigger elements) const html = (__classPrivateFieldGet(this, _Typecadence_storedText, "f").get(element) || element.innerHTML).trim(); __classPrivateFieldGet(this, _Typecadence_storedText, "f").delete(element); // Initialize playback state with original HTML __classPrivateFieldGet(this, _Typecadence_playbackState, "f").set(element, { paused: false, originalText: html }); element.innerHTML = ''; let caret = null; let caretAnimationInterval = null; // Show caret if (animationSettings.caret) { caret = __classPrivateFieldGet(this, _Typecadence_instances, "m", _Typecadence_createCaret).call(this, animationSettings); if (!animationSettings.caretColor) { caret.style.color = getComputedStyle(element).color; } element.appendChild(caret); if (animationSettings.caretBlink) { // @ts-ignore - browser setInterval returns number caretAnimationInterval = setInterval(() => { if (caret.style.visibility === "visible") { caret.style.visibility = "hidden"; } else { caret.style.visibility = "visible"; } }, animationSettings.caretBlinkSpeed); const currentState = __classPrivateFieldGet(this, _Typecadence_playbackState, "f").get(element); if (currentState) { currentState.caretInterval = caretAnimationInterval; } } } // Delay before typing yield new Promise((resolve) => setTimeout(resolve, animationSettings.delay)); // Parse HTML into tokens and build charIndex→tokenIndex lookup const tokens = __classPrivateFieldGet(this, _Typecadence_instances, "m", _Typecadence_parseHtmlToTokens).call(this, html); const charTokenIndices = []; for (let i = 0; i < tokens.length; i++) { if (tokens[i].type === 'char') charTokenIndices.push(i); } let mistakeBuffer = []; let tokenIndex = 0; let charIndex = 0; let currentElement = element; const elementStack = []; let justCorrected = false; const backspaceMin = (_b = animationSettings.backspaceMinSpeed) !== null && _b !== void 0 ? _b : animationSettings.minSpeed; const backspaceMax = (_c = animationSettings.backspaceMaxSpeed) !== null && _c !== void 0 ? _c : animationSettings.maxSpeed; // Type animation const animationState = __classPrivateFieldGet(this, _Typecadence_playbackState, "f").get(element); while (tokenIndex < tokens.length || mistakeBuffer.length > 0) { // Check if cancelled (e.g., by restart) if (animationState === null || animationState === void 0 ? void 0 : animationState.cancelled) { if (caretAnimationInterval) clearInterval(caretAnimationInterval); return; } // Wait if paused yield __classPrivateFieldGet(this, _Typecadence_instances, "m", _Typecadence_waitIfPaused).call(this, element); // Check again after pause in case we were cancelled while paused if (animationState === null || animationState === void 0 ? void 0 : animationState.cancelled) { if (caretAnimationInterval) clearInterval(caretAnimationInterval); return; } // Correct mistakes (buffer full or end of content) if (mistakeBuffer.length >= animationSettings.mistakesPresent || (mistakeBuffer.length > 0 && tokenIndex >= tokens.length)) { const stepsToGoBack = charIndex - mistakeBuffer[0]; for (let i = 0; i < stepsToGoBack; i++) { yield __classPrivateFieldGet(this, _Typecadence_instances, "m", _Typecadence_backspace).call(this, currentElement, caret, backspaceMin, backspaceMax); charIndex--; } tokenIndex = charTokenIndices[charIndex]; mistakeBuffer = []; justCorrected = true; continue; } const token = tokens[tokenIndex]; // Pre-boundary flush: correct mistakes before any structural token if ((token.type === 'open' || token.type === 'close' || token.type === 'insert') && mistakeBuffer.length > 0) { const stepsToGoBack = charIndex - mistakeBuffer[0]; for (let i = 0; i < stepsToGoBack; i++) { yield __classPrivateFieldGet(this, _Typecadence_instances, "m", _Typecadence_backspace).call(this, currentElement, caret, backspaceMin, backspaceMax); charIndex--; } tokenIndex = charTokenIndices[charIndex]; mistakeBuffer = []; justCorrected = true; continue; } // Process structural tokens (no typing delay) if (token.type === 'open') { if (caret) { currentElement.removeChild(caret); token.el.appendChild(caret); } currentElement.appendChild(token.el); elementStack.push(currentElement); currentElement = token.el; tokenIndex++; continue; } if (token.type === 'close') { // Falls back to root element if stack is empty (shouldn't happen — // browser HTML parser guarantees balanced open/close tokens) const parent = (_d = elementStack.pop()) !== null && _d !== void 0 ? _d : element; if (caret) { currentElement.removeChild(caret); parent.appendChild(caret); } currentElement = parent; tokenIndex++; continue; } if (token.type === 'insert') { if (caret) currentElement.insertBefore(token.el, caret); else currentElement.appendChild(token.el); tokenIndex++; continue; } // Type next character const char = token.char; const isMistake = !justCorrected && __classPrivateFieldGet(this, _Typecadence_instances, "m", _Typecadence_isMistake).call(this, animationSettings.mistakes); justCorrected = false; const typedChar = isMistake ? __classPrivateFieldGet(this, _Typecadence_instances, "m", _Typecadence_incorrectChar).call(this, char, animationSettings.keyboard) : char; const charNode = document.createTextNode(typedChar); if (caret) currentElement.insertBefore(charNode, caret); else currentElement.appendChild(charNode); if (isMistake && char !== typedChar) mistakeBuffer.push(charIndex); const isSpace = char === ' '; const typingMinSpeed = isSpace ? ((_e = animationSettings.spaceMinSpeed) !== null && _e !== void 0 ? _e : animationSettings.minSpeed) : animationSettings.minSpeed; const typingMaxSpeed = isSpace ? ((_f = animationSettings.spaceMaxSpeed) !== null && _f !== void 0 ? _f : animationSettings.maxSpeed) : animationSettings.maxSpeed; const typingSpeed = __classPrivateFieldGet(this, _Typecadence_instances, "m", _Typecadence_getTypingSpeed).call(this, typingMinSpeed, typingMaxSpeed); yield new Promise((resolve) => setTimeout(resolve, typingSpeed)); charIndex++; tokenIndex++; } // Hide caret if (animationSettings.caret) { if (caretAnimationInterval && (animationSettings.caretRemain || animationSettings.caretRemainTimeout)) { if (animationSettings.caretRemainTimeout) { setTimeout(() => { clearInterval(caretAnimationInterval); if (caret) { caret.style.visibility = "hidden"; } }, animationSettings.caretRemainTimeout); } } else { clearInterval(caretAnimationInterval); if (caret) { caret.style.visibility = "hidden"; } } } // Preserve original text for potential restart, then clean up playback state const originalText = (_g = __classPrivateFieldGet(this, _Typecadence_playbackState, "f").get(element)) === null || _g === void 0 ? void 0 : _g.originalText; if (originalText !== undefined) { __classPrivateFieldGet(this, _Typecadence_storedText, "f").set(element, originalText); } __classPrivateFieldGet(this, _Typecadence_playbackState, "f").delete(element); // Dispatch completion event element.dispatchEvent(new CustomEvent('typecadence:complete', { bubbles: true, detail: { element } })); // Call named global callback if specified if (animationSettings.callback) { const fn = window[animationSettings.callback]; if (typeof fn === 'function') { fn(element); } } }); }; _Typecadence_instance = { value: null }; let TriggerMode; (function (TriggerMode) { TriggerMode["VISIBLE"] = "visible"; TriggerMode["MANUAL"] = "manual"; })(TriggerMode || (TriggerMode = {})); let KeyboardLayout; (function (KeyboardLayout) { KeyboardLayout["QWERTY"] = "qwerty"; KeyboardLayout["QWERTZ"] = "qwertz"; KeyboardLayout["AZERTY"] = "azerty"; })(KeyboardLayout || (KeyboardLayout = {})); if (typeof window !== 'undefined') { document.addEventListener("DOMContentLoaded", () => { new Typecadence(); }); } return Typecadence; })); //# sourceMappingURL=typecadence.js.map