UNPKG

typeinit

Version:

An Intuitive Javascript Typing Animation Library

696 lines (693 loc) 26.5 kB
var __accessCheck = (obj, member, msg) => { if (!member.has(obj)) throw TypeError("Cannot " + msg); }; var __privateGet = (obj, member, getter) => { __accessCheck(obj, member, "read from private field"); return getter ? getter.call(obj) : member.get(obj); }; var __privateAdd = (obj, member, value) => { if (member.has(obj)) throw TypeError("Cannot add the same private member more than once"); member instanceof WeakSet ? member.add(obj) : member.set(obj, value); }; var __privateSet = (obj, member, value, setter) => { __accessCheck(obj, member, "write to private field"); setter ? setter.call(obj, value) : member.set(obj, value); return value; }; var __privateWrapper = (obj, member, setter, getter) => { return { set _(value) { __privateSet(obj, member, value, setter); }, get _() { return __privateGet(obj, member, getter); } }; }; var __privateMethod = (obj, member, method) => { __accessCheck(obj, member, "access private method"); return method; }; var _element, _options, _timeline, _intervalId, _controller, _playCalled, _isRepeating, _caretClass, _repeatCount, _numOfEntry, _restartCalled, _initialTextContent, __init, _init_fn, __confirmOptions, _confirmOptions_fn, __checkElementTextContent, _checkElementTextContent_fn, __getElement, _getElement_fn, __createCaret, _createCaret_fn, __removeCaretBlinking, _removeCaretBlinking_fn, __addCaretBlinking, _addCaretBlinking_fn, __addTimeline, _addTimeline_fn, _delay, delay_fn, _destroy, destroy_fn, __type, _type_fn, __del, _del_fn, __delAll, _delAll_fn, __newLine, _newLine_fn, __pause, _pause_fn, __restart, _restart_fn, __play, _play_fn; function createEl(type, textContent) { const el = document.createElement(type); if (type !== "br") el.textContent = textContent; return el; } function getLastChild(el, caret = false) { const lastChild = el.querySelector(":last-child"); if (!caret) { return lastChild; } return lastChild.previousElementSibling; } function waitUntilVisibleFunc(el, waitTill, controller) { const vPortHeight = window.innerHeight; return new Promise((res, rej) => { controller.signal.addEventListener("abort", () => { rej(); }); if (el.getBoundingClientRect().top + el.offsetHeight / 2 <= vPortHeight) { res(); } else { const handleScroll = () => { const elHeight = el.offsetHeight; const elTop = el.getBoundingClientRect().top; const elCenter = elTop + elHeight / 2; const elBottom = elTop + elHeight; const pageTop = 0; const pageBottom = vPortHeight; const pageCenter = pageBottom / 2; const optionsToValueForElement = { top: elTop, center: elCenter, bottom: elBottom }; const optionsToValueForPage = { top: pageTop, center: pageCenter, bottom: pageBottom }; const options = waitTill.split(" "); let elOption, pageOption; if (options.length === 1) { elOption = pageOption = options[0]; } else { elOption = options[0]; pageOption = options[1]; } const elementPos = optionsToValueForElement[elOption]; const pagePos = optionsToValueForPage[pageOption]; if (!elementPos || !pagePos) { document.removeEventListener("scroll", handleScroll); throw new Error(`unknown value for visiblity options - '${waitTill}'`); } if (elementPos <= pagePos) { document.removeEventListener("scroll", handleScroll); res(); } }; document.addEventListener("scroll", handleScroll); } }); } function getDefaultDisplay(el) { const cs = window.getComputedStyle(el); return cs.getPropertyValue("display"); } function isNumber(num) { return typeof num === "number"; } const defaultOptions = { startDelay: 0, typingSpeed: 100, deletingSpeed: 40, deleteDelay: 300, pause: 1e3, repeat: 0, repeatEase: false, repeatSpeed: 0, repeatDelay: 750, caret: true, caretColor: "currentcolor", caretWidth: 1, waitUntilVisible: false, visibleOptions: "center bottom", onStart: void 0, onEnd: void 0, onReset: void 0, onRestart: void 0, onCharTyped: void 0, onCharDeleted: void 0 }; class Typeinit { constructor(selector, optionsObj) { __privateAdd(this, __init); __privateAdd(this, __confirmOptions); __privateAdd(this, __checkElementTextContent); __privateAdd(this, __getElement); __privateAdd(this, __createCaret); __privateAdd(this, __removeCaretBlinking); __privateAdd(this, __addCaretBlinking); __privateAdd(this, __addTimeline); __privateAdd(this, _delay); __privateAdd(this, _destroy); __privateAdd(this, __type); __privateAdd(this, __del); __privateAdd(this, __delAll); __privateAdd(this, __newLine); __privateAdd(this, __pause); __privateAdd(this, __restart); __privateAdd(this, __play); __privateAdd(this, _element, void 0); __privateAdd(this, _options, void 0); __privateAdd(this, _timeline, []); __privateAdd(this, _intervalId, 0); __privateAdd(this, _controller, new AbortController()); __privateAdd(this, _playCalled, false); __privateAdd(this, _isRepeating, false); __privateAdd(this, _caretClass, "typeinit__caret"); __privateAdd(this, _repeatCount, 0); __privateAdd(this, _numOfEntry, 0); __privateAdd(this, _restartCalled, false); __privateAdd(this, _initialTextContent, ""); if (typeof selector === "string") { __privateSet(this, _element, __privateMethod(this, __getElement, _getElement_fn).call(this, selector)); } else { const tagName = selector.tagName.toLowerCase(); if (tagName === "input" || tagName === "textarea") { throw new Error(`Selector cannot be a '${tagName}' element`); } __privateSet(this, _element, selector); } __privateGet(this, _element).style.whiteSpace = "pre-wrap"; __privateMethod(this, __init, _init_fn).call(this); __privateMethod(this, __checkElementTextContent, _checkElementTextContent_fn).call(this); optionsObj = { ...defaultOptions, ...__privateMethod(this, __confirmOptions, _confirmOptions_fn).call(this, optionsObj) }; const { typingSpeed, deletingSpeed, pause, repeat, repeatEase, repeatSpeed, repeatDelay, caret, caretColor, caretWidth, waitUntilVisible, visibleOptions, deleteDelay, startDelay, onEnd, onStart, onCharTyped, onCharDeleted, onRestart, onReset } = optionsObj; __privateSet(this, _options, { typingSpeed, deletingSpeed, pause, repeat, repeatEase, repeatSpeed, repeatDelay, caret, caretColor, caretWidth, waitUntilVisible, visibleOptions, deleteDelay, startDelay, onEnd, onStart, onCharTyped, onCharDeleted, onRestart, onReset }); if (__privateGet(this, _options).caret) { this._addStyles(); __privateMethod(this, __createCaret, _createCaret_fn).call(this); } } _addStyles() { if (document.querySelector(`.${__privateGet(this, _caretClass)}`)) { return; } const style = createEl("style", ""); style.innerHTML = ` .${__privateGet(this, _caretClass)} { display: inline-block; height: 0.9em; transform: translateY(7%); border-radius: 100vmax; animation: blink-${__privateGet(this, _caretClass)} 1s infinite; } * + .${__privateGet(this, _caretClass)} { margin-inline-start: 0.25ch; } @keyframes blink-${__privateGet(this, _caretClass)} { 0% { opacity: 0; } 49% { opacity: 0; } 50% { opacity: 1; } } `; document.querySelector("head").appendChild(style); } type(message) { if (typeof message !== "string") { throw new Error(`'${message}' must be a string`); } if (!__privateGet(this, _playCalled)) __privateMethod(this, __addTimeline, _addTimeline_fn).call(this, __privateMethod(this, __type, _type_fn), message); return this; } delete(numToDel = 1, deleteOptions) { let mode = deleteOptions == null ? void 0 : deleteOptions.mode; const speed = deleteOptions == null ? void 0 : deleteOptions.speed; const deleteDelay = deleteOptions == null ? void 0 : deleteOptions.delay; if (!isNumber(numToDel)) { throw new Error(`'${numToDel}' must be a number`); } if (mode) { mode = mode.toLowerCase(); if (mode !== "char" && mode !== "c" && mode !== "word" && mode !== "w") { throw new Error("mode must be either 'word', 'w','char' or 'c'"); } } if (deleteDelay) { if (!isNumber(deleteDelay)) { throw new Error(`'${deleteDelay}' must be a number`); } } if (!__privateGet(this, _playCalled)) __privateMethod(this, __addTimeline, _addTimeline_fn).call(this, __privateMethod(this, __del, _del_fn), numToDel, { mode, speed, delay: deleteDelay }); return this; } deleteAll(ease = true, deleteAllOptions) { const speed = deleteAllOptions == null ? void 0 : deleteAllOptions.speed; const deleteDelay = deleteAllOptions == null ? void 0 : deleteAllOptions.delay; if (speed) { if (!isNumber(speed)) { throw new Error(`'${speed}' must be a number`); } } if (deleteDelay) { if (!isNumber(deleteDelay)) { throw new Error(`'${deleteDelay}' must be a number`); } } if (!__privateGet(this, _playCalled)) __privateMethod(this, __addTimeline, _addTimeline_fn).call(this, __privateMethod(this, __delAll, _delAll_fn), ease, { speed, delay: deleteDelay }); return this; } newLine(numOfLines = 1) { if (!isNumber(numOfLines)) { throw new Error(`'${numOfLines}' must be a number`); } if (!__privateGet(this, _playCalled)) __privateMethod(this, __addTimeline, _addTimeline_fn).call(this, __privateMethod(this, __newLine, _newLine_fn), numOfLines); return this; } pause(ms = __privateGet(this, _options).pause) { if (!isNumber(ms)) { throw new Error(`'${ms}' must be a number`); } if (!__privateGet(this, _playCalled)) __privateMethod(this, __addTimeline, _addTimeline_fn).call(this, __privateMethod(this, __pause, _pause_fn), ms); return this; } reset() { __privateMethod(this, _destroy, destroy_fn).call(this); if (__privateGet(this, _initialTextContent)) { if (!__privateGet(this, _element)) return; __privateGet(this, _element).innerHTML = __privateGet(this, _initialTextContent); } __privateSet(this, _element, void 0); __privateSet(this, _initialTextContent, ""); if (__privateGet(this, _options).onReset) { __privateGet(this, _options).onReset(); } __privateSet(this, _options, defaultOptions); } restart() { __privateMethod(this, __restart, _restart_fn).call(this); } play() { __privateMethod(this, __play, _play_fn).call(this); } } _element = new WeakMap(); _options = new WeakMap(); _timeline = new WeakMap(); _intervalId = new WeakMap(); _controller = new WeakMap(); _playCalled = new WeakMap(); _isRepeating = new WeakMap(); _caretClass = new WeakMap(); _repeatCount = new WeakMap(); _numOfEntry = new WeakMap(); _restartCalled = new WeakMap(); _initialTextContent = new WeakMap(); __init = new WeakSet(); _init_fn = function() { if (!__privateGet(this, _element)) return; const display = getDefaultDisplay(__privateGet(this, _element)); if (display === "inline") { __privateGet(this, _element).style.display = "inline-block"; } }; __confirmOptions = new WeakSet(); _confirmOptions_fn = function(opt) { const newOptionObj = {}; if (opt) { for (let option in opt) { const value = opt[option]; const dValue = defaultOptions[option]; if (typeof value !== typeof dValue) { if (option === "onStart" || option === "onEnd" || option === "onCharTyped" || option === "onCharDeleted" || option === "onRestart" || option === "onReset") { if (typeof value === "function") { newOptionObj[option] = value; } else { newOptionObj[option] = dValue; console.warn(`${value} is not of type 'function' or '${typeof dValue}'`); } } else if (option === "repeat") { if (value === "infinite") newOptionObj[option] = value; else { newOptionObj[option] = dValue; console.warn(`${value} is not of type 'infinite' or '${typeof dValue}'`); } } else { newOptionObj[option] = dValue; console.warn(`${value} is not of type '${typeof dValue}'`); } } else if (isNumber(value)) { if (value >= 0) { newOptionObj[option] = value; } else { newOptionObj[option] = 0; console.warn(`${option} expects a positive number, got ${value}`); } } else { newOptionObj[option] = value; } } } return newOptionObj; }; __checkElementTextContent = new WeakSet(); _checkElementTextContent_fn = function() { var _a; if (!__privateGet(this, _element)) return; const textContent = (_a = __privateGet(this, _element).textContent) == null ? void 0 : _a.trim(); if (textContent) { __privateGet(this, _element).innerHTML = ""; __privateSet(this, _initialTextContent, textContent); this.type(textContent); } }; __getElement = new WeakSet(); _getElement_fn = function(selector) { const el = document.querySelector(selector); if (el) { return el; } else { throw new Error(`Couldn't find an element with '${selector}'`); } }; __createCaret = new WeakSet(); _createCaret_fn = function() { if (!__privateGet(this, _element)) return; if (__privateGet(this, _element).querySelector(`.${__privateGet(this, _caretClass)}`)) return; const c = createEl("span", ""); c.classList.add(__privateGet(this, _caretClass)); c.setAttribute("aria-hidden", "true"); c.style.background = __privateGet(this, _options).caretColor; c.style.width = `${__privateGet(this, _options).caretWidth}px`; __privateGet(this, _element).appendChild(c); }; __removeCaretBlinking = new WeakSet(); _removeCaretBlinking_fn = function() { if (!__privateGet(this, _element)) return; if (__privateGet(this, _options).caret) { const caret = __privateGet(this, _element).querySelector(`.${__privateGet(this, _caretClass)}`); if ((caret == null ? void 0 : caret.style.animationDuration) !== "0s") caret.style.animationDuration = "0s"; } }; __addCaretBlinking = new WeakSet(); _addCaretBlinking_fn = function() { if (!__privateGet(this, _element)) return; if (__privateGet(this, _options).caret) { const caret = __privateGet(this, _element).querySelector(`.${__privateGet(this, _caretClass)}`); if (caret.style.animationDuration !== "1s") caret.style.animationDuration = "1s"; } }; __addTimeline = new WeakSet(); _addTimeline_fn = function(func, ...message) { __privateGet(this, _timeline).push([func, message]); }; _delay = new WeakSet(); delay_fn = function(ms) { return new Promise((res) => { const intId = setTimeout(() => { clearInterval(intId); res(); }, ms); __privateSet(this, _intervalId, intId); }); }; _destroy = new WeakSet(); destroy_fn = function() { clearInterval(__privateGet(this, _intervalId)); __privateSet(this, _intervalId, 0); __privateGet(this, _controller).abort(); __privateSet(this, _controller, new AbortController()); __privateSet(this, _timeline, []); __privateSet(this, _playCalled, false); __privateSet(this, _isRepeating, false); __privateSet(this, _repeatCount, 0); __privateSet(this, _numOfEntry, 0); __privateSet(this, _restartCalled, false); }; __type = new WeakSet(); _type_fn = async function(message) { if (!__privateGet(this, _element)) return; __privateMethod(this, __removeCaretBlinking, _removeCaretBlinking_fn).call(this); for (const ch of message) { if (!__privateGet(this, _element)) return; const chSpan = createEl("span", ch); __privateWrapper(this, _numOfEntry)._++; if (__privateGet(this, _options).caret) { __privateGet(this, _element).insertBefore(chSpan, __privateGet(this, _element).lastElementChild); } else { __privateGet(this, _element).appendChild(chSpan); } if (__privateGet(this, _options).onCharTyped) { __privateGet(this, _options).onCharTyped(); } await __privateMethod(this, _delay, delay_fn).call(this, __privateGet(this, _options).typingSpeed); } __privateMethod(this, __addCaretBlinking, _addCaretBlinking_fn).call(this); }; __del = new WeakSet(); _del_fn = async function(numToDel, deleteOptions) { var _a, _b, _c; if (!__privateGet(this, _element)) return; const mode = (_a = deleteOptions == null ? void 0 : deleteOptions.mode) != null ? _a : "char"; const speed = (_b = deleteOptions == null ? void 0 : deleteOptions.speed) != null ? _b : __privateGet(this, _options).deletingSpeed; const deleteDelay = (_c = deleteOptions == null ? void 0 : deleteOptions.delay) != null ? _c : __privateGet(this, _options).deleteDelay; const numOfChildrenToCheck = __privateGet(this, _options).caret ? 1 : 0; if (__privateGet(this, _element).childElementCount > numOfChildrenToCheck) { await __privateMethod(this, _delay, delay_fn).call(this, deleteDelay); if (mode === "char" || mode == "c") { numToDel = Math.min(numToDel, __privateGet(this, _element).childElementCount - numOfChildrenToCheck); for (let i = 0; i < numToDel; i++) { if (!__privateGet(this, _element)) return; __privateWrapper(this, _numOfEntry)._--; __privateGet(this, _element).removeChild(getLastChild(__privateGet(this, _element), __privateGet(this, _options).caret)); if (__privateGet(this, _options).onCharDeleted) { __privateGet(this, _options).onCharDeleted(); } await __privateMethod(this, _delay, delay_fn).call(this, speed); } } else { let numToDelCount = 0; while (__privateGet(this, _element).childElementCount > numOfChildrenToCheck && numToDelCount < numToDel) { if (!__privateGet(this, _element)) return; while (__privateGet(this, _element).childElementCount > numOfChildrenToCheck) { __privateWrapper(this, _numOfEntry)._--; const lastChild = getLastChild(__privateGet(this, _element), __privateGet(this, _options).caret); const content = lastChild.textContent; const previousSibling = lastChild.previousElementSibling; if (content) { if (content.trim()) { if (previousSibling) { const prevContent = previousSibling.textContent; if (prevContent) { if (!prevContent.trim()) { __privateGet(this, _element).removeChild(lastChild); await __privateMethod(this, _delay, delay_fn).call(this, speed); break; } __privateGet(this, _element).removeChild(lastChild); await __privateMethod(this, _delay, delay_fn).call(this, speed); } else { __privateGet(this, _element).removeChild(lastChild); await __privateMethod(this, _delay, delay_fn).call(this, speed); break; } } else { __privateGet(this, _element).removeChild(lastChild); await __privateMethod(this, _delay, delay_fn).call(this, speed); } } else { __privateGet(this, _element).removeChild(lastChild); await __privateMethod(this, _delay, delay_fn).call(this, speed); } } else { __privateGet(this, _element).removeChild(lastChild); await __privateMethod(this, _delay, delay_fn).call(this, speed); } } numToDelCount++; if (__privateGet(this, _options).onCharDeleted) { __privateGet(this, _options).onCharDeleted(); } } } } }; __delAll = new WeakSet(); _delAll_fn = async function(ease = true, deleteAllOptions) { var _a, _b; const speed = (_a = deleteAllOptions == null ? void 0 : deleteAllOptions.speed) != null ? _a : __privateGet(this, _options).deletingSpeed; const deleteDelay = (_b = deleteAllOptions == null ? void 0 : deleteAllOptions.delay) != null ? _b : __privateGet(this, _options).deleteDelay; const numOfChildrenToCheck = __privateGet(this, _options).caret ? 1 : 0; if (!__privateGet(this, _element)) return; if (__privateGet(this, _element).childElementCount > numOfChildrenToCheck) { await __privateMethod(this, _delay, delay_fn).call(this, deleteDelay); if (ease === false) { let numOfEntry = 0; while (numOfEntry < __privateGet(this, _numOfEntry)) { if (!__privateGet(this, _element)) return; getLastChild(__privateGet(this, _element), __privateGet(this, _options).caret).remove(); numOfEntry++; } __privateSet(this, _numOfEntry, 0); if (!__privateGet(this, _restartCalled)) { if (__privateGet(this, _options).onCharDeleted) { __privateGet(this, _options).onCharDeleted(); } } else { __privateSet(this, _restartCalled, false); } } else { let numOfEntry = 0; while (numOfEntry < __privateGet(this, _numOfEntry)) { if (!__privateGet(this, _element)) return; __privateGet(this, _element).removeChild(getLastChild(__privateGet(this, _element), __privateGet(this, _options).caret)); if (__privateGet(this, _options).onCharDeleted) { __privateGet(this, _options).onCharDeleted(); } await __privateMethod(this, _delay, delay_fn).call(this, speed); numOfEntry++; } __privateSet(this, _numOfEntry, 0); } } }; __newLine = new WeakSet(); _newLine_fn = async function(numOfLines) { if (!__privateGet(this, _element)) return; __privateMethod(this, __removeCaretBlinking, _removeCaretBlinking_fn).call(this); for (let i = 0; i < numOfLines; i++) { if (!__privateGet(this, _element)) return; __privateWrapper(this, _numOfEntry)._++; const line = createEl("br", ""); if (__privateGet(this, _options).caret) { __privateGet(this, _element).insertBefore(line, __privateGet(this, _element).lastElementChild); } else { __privateGet(this, _element).appendChild(line); } if (__privateGet(this, _options).onCharTyped) { __privateGet(this, _options).onCharTyped(); } await __privateMethod(this, _delay, delay_fn).call(this, __privateGet(this, _options).typingSpeed); } __privateMethod(this, __addCaretBlinking, _addCaretBlinking_fn).call(this); }; __pause = new WeakSet(); _pause_fn = async function(ms) { return __privateMethod(this, _delay, delay_fn).call(this, ms); }; __restart = new WeakSet(); _restart_fn = async function() { clearInterval(__privateGet(this, _intervalId)); if (__privateGet(this, _options).waitUntilVisible) { __privateGet(this, _controller).abort(); __privateSet(this, _controller, new AbortController()); } __privateSet(this, _restartCalled, true); await __privateMethod(this, __delAll, _delAll_fn).call(this, false, { delay: 0 }); if (__privateGet(this, _options).onRestart) { __privateGet(this, _options).onRestart(); } __privateSet(this, _intervalId, 0); __privateSet(this, _playCalled, false); __privateSet(this, _isRepeating, false); __privateSet(this, _repeatCount, 0); __privateSet(this, _numOfEntry, 0); __privateMethod(this, __play, _play_fn).call(this); }; __play = new WeakSet(); _play_fn = async function() { if (!__privateGet(this, _playCalled) || __privateGet(this, _isRepeating)) { if (!__privateGet(this, _element)) return; __privateSet(this, _playCalled, true); if (!__privateGet(this, _isRepeating)) { if (__privateGet(this, _options).waitUntilVisible) { try { await waitUntilVisibleFunc(__privateGet(this, _element), __privateGet(this, _options).visibleOptions, __privateGet(this, _controller)); } catch { return; } } await __privateMethod(this, _delay, delay_fn).call(this, __privateGet(this, _options).startDelay); } if (!__privateGet(this, _isRepeating) && __privateGet(this, _options).onStart) { __privateGet(this, _options).onStart(); } for (const action of __privateGet(this, _timeline)) { if (!__privateGet(this, _element)) return; const [func, args] = [action[0], action[1]]; await func.call(this, ...args); } if (isNumber(__privateGet(this, _options).repeat)) { if (__privateGet(this, _repeatCount) < __privateGet(this, _options).repeat) { __privateSet(this, _isRepeating, true); if (__privateGet(this, _options).repeatEase) { await __privateMethod(this, __delAll, _delAll_fn).call(this, true, { speed: __privateGet(this, _options).repeatSpeed }); } else { await __privateMethod(this, __delAll, _delAll_fn).call(this, false); } await __privateMethod(this, _delay, delay_fn).call(this, __privateGet(this, _options).repeatDelay); __privateMethod(this, __play, _play_fn).call(this); __privateWrapper(this, _repeatCount)._++; } else { __privateSet(this, _repeatCount, 0); __privateSet(this, _isRepeating, false); } } else if (__privateGet(this, _options).repeat === "infinite") { __privateSet(this, _isRepeating, true); if (__privateGet(this, _options).repeatEase) { await __privateMethod(this, __delAll, _delAll_fn).call(this, true, { speed: __privateGet(this, _options).repeatSpeed }); } else { await __privateMethod(this, __delAll, _delAll_fn).call(this, false); } await __privateMethod(this, _delay, delay_fn).call(this, __privateGet(this, _options).repeatDelay); __privateMethod(this, __play, _play_fn).call(this); } if (!__privateGet(this, _isRepeating) && __privateGet(this, _options).onEnd) { __privateGet(this, _options).onEnd(); } } }; export { Typeinit as default };