UNPKG

react-typist-updated

Version:
121 lines (102 loc) 3.22 kB
import React from 'react'; export const sleep = (val) => new Promise((resolve) => ( val != null ? setTimeout(resolve, val) : resolve() )); export function gaussianRnd(mean, std) { const times = 12; let sum = 0; for (let idx = 0; idx < times; idx++) { sum += Math.random(); } sum -= (times / 2); return Math.round((sum) * std) + mean; } export function eachPromise(arr, iterator, ...extraArgs) { const promiseReducer = (prev, current, idx) => ( prev.then(() => iterator(current, idx, ...extraArgs)) ); return Array.from(arr).reduce(promiseReducer, Promise.resolve()); } export function exclude(obj, keys) { const res = {}; for (const key in obj) { if (keys.indexOf(key) === -1) { res[key] = obj[key]; } } return res; } export function isBackspaceElement(element) { return element && element.type && element.type.componentName === 'Backspace'; } export function isDelayElement(element) { return element && element.type && element.type.componentName === 'Delay'; } export function extractTextFromElement(element) { const stack = element ? [element] : []; const lines = []; while (stack.length > 0) { const current = stack.pop(); if (React.isValidElement(current)) { if (isBackspaceElement(current) || isDelayElement(current)) { // If it is a `Backspace` or `Delay` element, we want to keep it in our // `textLines` state. These will serve as markers when updating the // state of the text lines.unshift(current); } else { React.Children.forEach(current.props.children, (child) => { stack.push(child); }); } } else if (Array.isArray(current)) { for (const el of current) { stack.push(el); } } else { lines.unshift(current); } } return lines; } export function cloneElement(element, children) { const tag = element.type; const props = exclude(element.props, ['children']); // eslint-disable-next-line props.key = `Typist-element-${tag}-${Date.now() + Math.random() + Math.random()}`; return React.createElement(tag, props, ...children); } function cloneElementWithSpecifiedTextAtIndex(element, textLines, textIdx) { if (textIdx >= textLines.length) { return [null, textIdx]; } let idx = textIdx; const recurse = (el) => { const [child, advIdx] = cloneElementWithSpecifiedTextAtIndex( el, textLines, idx ); idx = advIdx; return child; }; const isNonTypistElement = ( React.isValidElement(element) && !(isBackspaceElement(element) || isDelayElement(element)) ); if (isNonTypistElement) { const clonedChildren = React.Children.map(element.props.children, recurse) || []; return [cloneElement(element, clonedChildren), idx]; } if (Array.isArray(element)) { const children = element.map(recurse); return [children, idx]; } // Anything that isn't a React element or an Array is interpreted as text return [textLines[idx], idx + 1]; } export function cloneElementWithSpecifiedText({ element, textLines }) { if (!element) { return undefined; } return cloneElementWithSpecifiedTextAtIndex(element, textLines, 0)[0]; }