@staticcanvas/typeflow 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +637 -0
- package/branding/dist/ico/typeflow-logo-16x16.ico +0 -0
- package/branding/dist/ico/typeflow-logo-256x256.ico +0 -0
- package/branding/dist/ico/typeflow-logo-32x32.ico +0 -0
- package/branding/dist/ico/typeflow-logo-48x48.ico +0 -0
- package/branding/dist/png/typeflow-logo-1024x1024.png +0 -0
- package/branding/dist/png/typeflow-logo-128x128.png +0 -0
- package/branding/dist/png/typeflow-logo-16x16.png +0 -0
- package/branding/dist/png/typeflow-logo-256x256.png +0 -0
- package/branding/dist/png/typeflow-logo-512x512.png +0 -0
- package/branding/dist/png/typeflow-logo-64x64.png +0 -0
- package/branding/dist/webp/typeflow-logo-1024x1024.webp +0 -0
- package/branding/dist/webp/typeflow-logo-128x128.webp +0 -0
- package/branding/dist/webp/typeflow-logo-16x16.webp +0 -0
- package/branding/dist/webp/typeflow-logo-256x256.webp +0 -0
- package/branding/dist/webp/typeflow-logo-32x32.webp +0 -0
- package/branding/dist/webp/typeflow-logo-48x48.webp +0 -0
- package/branding/dist/webp/typeflow-logo-512x512.webp +0 -0
- package/branding/dist/webp/typeflow-logo-64x64.webp +0 -0
- package/branding/gen-logo.ps1 +14 -0
- package/branding/typeflow-logo.svg +162 -0
- package/dist/typeflow/LICENSE +21 -0
- package/dist/typeflow/README.md +231 -0
- package/dist/typeflow/branding/dist/ico/typeflow-logo-16x16.ico +0 -0
- package/dist/typeflow/branding/dist/ico/typeflow-logo-256x256.ico +0 -0
- package/dist/typeflow/branding/dist/ico/typeflow-logo-32x32.ico +0 -0
- package/dist/typeflow/branding/dist/ico/typeflow-logo-48x48.ico +0 -0
- package/dist/typeflow/branding/dist/png/typeflow-logo-1024x1024.png +0 -0
- package/dist/typeflow/branding/dist/png/typeflow-logo-128x128.png +0 -0
- package/dist/typeflow/branding/dist/png/typeflow-logo-16x16.png +0 -0
- package/dist/typeflow/branding/dist/png/typeflow-logo-256x256.png +0 -0
- package/dist/typeflow/branding/dist/png/typeflow-logo-512x512.png +0 -0
- package/dist/typeflow/branding/dist/png/typeflow-logo-64x64.png +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-1024x1024.webp +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-128x128.webp +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-16x16.webp +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-256x256.webp +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-32x32.webp +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-48x48.webp +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-512x512.webp +0 -0
- package/dist/typeflow/branding/dist/webp/typeflow-logo-64x64.webp +0 -0
- package/dist/typeflow/branding/gen-logo.ps1 +14 -0
- package/dist/typeflow/branding/typeflow-logo.svg +162 -0
- package/dist/typeflow/dist/typeflow-caret.cjs +47 -0
- package/dist/typeflow/dist/typeflow-caret.cjs.map +1 -0
- package/dist/typeflow/dist/typeflow-caret.esm.js +47 -0
- package/dist/typeflow/dist/typeflow-caret.esm.js.map +1 -0
- package/dist/typeflow/dist/typeflow-caret.esm.min.js +2 -0
- package/dist/typeflow/dist/typeflow-caret.esm.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-caret.js +47 -0
- package/dist/typeflow/dist/typeflow-caret.js.map +1 -0
- package/dist/typeflow/dist/typeflow-caret.min.js +2 -0
- package/dist/typeflow/dist/typeflow-caret.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-caret.mjs +47 -0
- package/dist/typeflow/dist/typeflow-caret.mjs.map +1 -0
- package/dist/typeflow/dist/typeflow-debug.cjs +109 -0
- package/dist/typeflow/dist/typeflow-debug.cjs.map +1 -0
- package/dist/typeflow/dist/typeflow-debug.esm.js +109 -0
- package/dist/typeflow/dist/typeflow-debug.esm.js.map +1 -0
- package/dist/typeflow/dist/typeflow-debug.esm.min.js +2 -0
- package/dist/typeflow/dist/typeflow-debug.esm.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-debug.js +109 -0
- package/dist/typeflow/dist/typeflow-debug.js.map +1 -0
- package/dist/typeflow/dist/typeflow-debug.min.js +2 -0
- package/dist/typeflow/dist/typeflow-debug.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-debug.mjs +109 -0
- package/dist/typeflow/dist/typeflow-debug.mjs.map +1 -0
- package/dist/typeflow/dist/typeflow-extchars.cjs +66 -0
- package/dist/typeflow/dist/typeflow-extchars.cjs.map +1 -0
- package/dist/typeflow/dist/typeflow-extchars.esm.js +66 -0
- package/dist/typeflow/dist/typeflow-extchars.esm.js.map +1 -0
- package/dist/typeflow/dist/typeflow-extchars.esm.min.js +2 -0
- package/dist/typeflow/dist/typeflow-extchars.esm.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-extchars.js +66 -0
- package/dist/typeflow/dist/typeflow-extchars.js.map +1 -0
- package/dist/typeflow/dist/typeflow-extchars.min.js +2 -0
- package/dist/typeflow/dist/typeflow-extchars.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-extchars.mjs +66 -0
- package/dist/typeflow/dist/typeflow-extchars.mjs.map +1 -0
- package/dist/typeflow/dist/typeflow-keystroke.cjs +47 -0
- package/dist/typeflow/dist/typeflow-keystroke.cjs.map +1 -0
- package/dist/typeflow/dist/typeflow-keystroke.esm.js +47 -0
- package/dist/typeflow/dist/typeflow-keystroke.esm.js.map +1 -0
- package/dist/typeflow/dist/typeflow-keystroke.esm.min.js +2 -0
- package/dist/typeflow/dist/typeflow-keystroke.esm.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-keystroke.js +47 -0
- package/dist/typeflow/dist/typeflow-keystroke.js.map +1 -0
- package/dist/typeflow/dist/typeflow-keystroke.min.js +2 -0
- package/dist/typeflow/dist/typeflow-keystroke.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-keystroke.mjs +47 -0
- package/dist/typeflow/dist/typeflow-keystroke.mjs.map +1 -0
- package/dist/typeflow/dist/typeflow-metrics.cjs +76 -0
- package/dist/typeflow/dist/typeflow-metrics.cjs.map +1 -0
- package/dist/typeflow/dist/typeflow-metrics.esm.js +76 -0
- package/dist/typeflow/dist/typeflow-metrics.esm.js.map +1 -0
- package/dist/typeflow/dist/typeflow-metrics.esm.min.js +2 -0
- package/dist/typeflow/dist/typeflow-metrics.esm.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-metrics.js +76 -0
- package/dist/typeflow/dist/typeflow-metrics.js.map +1 -0
- package/dist/typeflow/dist/typeflow-metrics.min.js +2 -0
- package/dist/typeflow/dist/typeflow-metrics.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-metrics.mjs +76 -0
- package/dist/typeflow/dist/typeflow-metrics.mjs.map +1 -0
- package/dist/typeflow/dist/typeflow-parallel.cjs +3 -0
- package/dist/typeflow/dist/typeflow-parallel.cjs.map +1 -0
- package/dist/typeflow/dist/typeflow-parallel.esm.js +3 -0
- package/dist/typeflow/dist/typeflow-parallel.esm.js.map +1 -0
- package/dist/typeflow/dist/typeflow-parallel.esm.min.js +2 -0
- package/dist/typeflow/dist/typeflow-parallel.esm.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-parallel.js +3 -0
- package/dist/typeflow/dist/typeflow-parallel.js.map +1 -0
- package/dist/typeflow/dist/typeflow-parallel.min.js +2 -0
- package/dist/typeflow/dist/typeflow-parallel.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-parallel.mjs +3 -0
- package/dist/typeflow/dist/typeflow-parallel.mjs.map +1 -0
- package/dist/typeflow/dist/typeflow-webaudio.cjs +81 -0
- package/dist/typeflow/dist/typeflow-webaudio.cjs.map +1 -0
- package/dist/typeflow/dist/typeflow-webaudio.esm.js +81 -0
- package/dist/typeflow/dist/typeflow-webaudio.esm.js.map +1 -0
- package/dist/typeflow/dist/typeflow-webaudio.esm.min.js +2 -0
- package/dist/typeflow/dist/typeflow-webaudio.esm.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-webaudio.js +81 -0
- package/dist/typeflow/dist/typeflow-webaudio.js.map +1 -0
- package/dist/typeflow/dist/typeflow-webaudio.min.js +2 -0
- package/dist/typeflow/dist/typeflow-webaudio.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow-webaudio.mjs +81 -0
- package/dist/typeflow/dist/typeflow-webaudio.mjs.map +1 -0
- package/dist/typeflow/dist/typeflow.cjs +277 -0
- package/dist/typeflow/dist/typeflow.cjs.map +1 -0
- package/dist/typeflow/dist/typeflow.esm.js +277 -0
- package/dist/typeflow/dist/typeflow.esm.js.map +1 -0
- package/dist/typeflow/dist/typeflow.esm.min.js +2 -0
- package/dist/typeflow/dist/typeflow.esm.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow.js +277 -0
- package/dist/typeflow/dist/typeflow.js.map +1 -0
- package/dist/typeflow/dist/typeflow.min.js +2 -0
- package/dist/typeflow/dist/typeflow.min.js.map +1 -0
- package/dist/typeflow/dist/typeflow.mjs +277 -0
- package/dist/typeflow/dist/typeflow.mjs.map +1 -0
- package/dist/typeflow/jsr.jsonc +27 -0
- package/dist/typeflow/package.json +79 -0
- package/dist/typeflow/src/typeflow-audio-presets.js +137 -0
- package/dist/typeflow/src/typeflow-caret.d.ts +65 -0
- package/dist/typeflow/src/typeflow-caret.js +303 -0
- package/dist/typeflow/src/typeflow-debug.d.ts +34 -0
- package/dist/typeflow/src/typeflow-debug.js +223 -0
- package/dist/typeflow/src/typeflow-extchars.d.ts +28 -0
- package/dist/typeflow/src/typeflow-extchars.js +132 -0
- package/dist/typeflow/src/typeflow-keystroke.d.ts +28 -0
- package/dist/typeflow/src/typeflow-keystroke.js +220 -0
- package/dist/typeflow/src/typeflow-metrics.d.ts +38 -0
- package/dist/typeflow/src/typeflow-metrics.js +556 -0
- package/dist/typeflow/src/typeflow-parallel.d.ts +36 -0
- package/dist/typeflow/src/typeflow-parallel.js +157 -0
- package/dist/typeflow/src/typeflow-webaudio.d.ts +83 -0
- package/dist/typeflow/src/typeflow-webaudio.js +517 -0
- package/dist/typeflow/src/typeflow.d.ts +328 -0
- package/dist/typeflow/src/typeflow.js +2119 -0
- package/jsr.jsonc +27 -0
- package/package.json +133 -0
- package/src/typeflow-audio-presets.js +137 -0
- package/src/typeflow-caret.d.ts +65 -0
- package/src/typeflow-caret.js +303 -0
- package/src/typeflow-debug.d.ts +34 -0
- package/src/typeflow-debug.js +223 -0
- package/src/typeflow-extchars.d.ts +28 -0
- package/src/typeflow-extchars.js +132 -0
- package/src/typeflow-keystroke.d.ts +28 -0
- package/src/typeflow-keystroke.js +220 -0
- package/src/typeflow-metrics.d.ts +38 -0
- package/src/typeflow-metrics.js +556 -0
- package/src/typeflow-parallel.d.ts +36 -0
- package/src/typeflow-parallel.js +157 -0
- package/src/typeflow-webaudio.d.ts +83 -0
- package/src/typeflow-webaudio.js +517 -0
- package/src/typeflow.d.ts +328 -0
- package/src/typeflow.js +2119 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/*! typeflow v0.34.0 | https://staticcanvas.gitlab.io/typeflow | MIT */
|
|
2
|
+
var e=Object.defineProperty,t=Object.defineProperties,n=Object.getOwnPropertyDescriptors,r=Object.getOwnPropertySymbols,l=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable,a=e=>{throw TypeError(e)},i=(t,n,r)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[n]=r,s=(e,t)=>{for(var n in t||(t={}))l.call(t,n)&&i(e,n,t[n]);if(r)for(var n of r(t))o.call(t,n)&&i(e,n,t[n]);return e},c=(e,r)=>t(e,n(r)),u=(e,t,n)=>i(e,"symbol"!=typeof t?t+"":t,n),d=(e,t,n)=>t.has(e)||a("Cannot "+n),p=(e,t,n)=>(d(e,t,"read from private field"),n?n.call(e):t.get(e)),f=(e,t,n)=>t.has(e)?a("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,n),m=(e,t,n)=>(d(e,t,"access private method"),n),h=(e,t,n)=>new Promise((r,l)=>{var o=e=>{try{i(n.next(e))}catch(e){l(e)}},a=e=>{try{i(n.throw(e))}catch(e){l(e)}},i=e=>e.done?r(e.value):Promise.resolve(e.value).then(o,a);i((n=n.apply(e,t)).next())});
|
|
3
|
+
/**
|
|
4
|
+
* TypeFlow - A lightweight, interruptible, framework-agnostic typewriter library
|
|
5
|
+
* @version 2.3.0
|
|
6
|
+
* @license MIT
|
|
7
|
+
*
|
|
8
|
+
* Zero dependencies. Safe by default (no innerHTML string concatenation).
|
|
9
|
+
* Vanilla-first, with Intl.Segmenter support, multi-style reveals, and integrations for React, Vue, Svelte, Solid.js, Alpine.js, and Web Components.
|
|
10
|
+
*/
|
|
11
|
+
const y={matrix:"01X_#*~<>[]{}",ascii:"!@#$%^&*()_+-=[]{}|;:,.<>?","ascii-extended":"¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿",blocks:" ▂▃▄▅▆▇█░▒▓",binary:"01",hex:"0123456789ABCDEF",braille:"⠁⠃⠇⠏⠟⠿⡿⣿",runic:"ᚠᚡᚢᚣᚤᚥᚦᚧᚨᚩᚪᚫᚬᚭᚮᚯ",cyber:"!<>-_\\/[]{}—=+*^?#________"},g={cyberpunk:{typeStyle:"scramble",scrambleCharset:"matrix",scrambleRounds:2,speed:40,cursor:"|",cursorBlink:!0,audio:"synth"},terminal:{typeStyle:"char",speed:32,cursor:"█",cursorBlink:!0,audio:"mechanical"},writer:{naturalCadence:!0,speed:52,speedVariance:22,cursor:"|",cursorBlink:!0,audio:"mechanical"},matrix:{typeStyle:"scramble",scrambleCharset:"matrix",scrambleRounds:3,speed:30,cursor:"█",cursorBlink:!0,audio:"synth"},blocks:{typeStyle:"scramble",scrambleCharset:"blocks",scrambleRounds:2,speed:45,cursor:"█",cursorBlink:!0},subtle:{speed:45,cursor:"|",cursorBlink:!0,eraseStyle:"fade",respectReducedMotion:!0}},b={speed:50,delay:0,speedVariance:0,naturalCadence:!1,granularity:"grapheme",cursor:"|",cursorBlink:!0,html:!1,mode:"replace",direction:"left",typeStyle:"char",scrambleCharset:"cyber",scrambleGlyphs:"!<>-_\\/[]{}—=+*^?#________",scrambleRounds:2,audio:null,respectReducedMotion:!0},v=c(s({},b),{speed:25,cursorBlink:!1,eraseStyle:"end",preserveBaseline:!0}),w=new Set(["br","hr","img","input","wbr","area","base","col","embed","link","meta","source","track"]),x=new Set(["b","strong","i","em","mark","span","small","sub","sup","u","br","a","code"]),C={a:new Set(["href","title","target","rel"]),span:new Set(["class"]),mark:new Set(["class"]),"*":new Set(["class"])},S=new Set(["word-fade","float-in-top","float-in-bottom","float-in-left","float-in-right","zoom-in-space"]);let M=null;function T(e){if(!e)return;if("function"==typeof e){try{e()}catch(e){}return}const t="string"==typeof e?e:"mechanical";try{const e=function(){if("undefined"==typeof window)return null;const e=window.AudioContext||window.webkitAudioContext;if(!e)return null;if(!M)try{M=new e}catch(e){return null}return M&&"suspended"===M.state&&M.resume().catch(()=>{}),M}();if(!e)return;const n=e.currentTime,r=e.createOscillator(),l=e.createGain();"beep"===t?(r.type="sine",r.frequency.setValueAtTime(880,n),l.gain.setValueAtTime(.03,n),l.gain.exponentialRampToValueAtTime(.001,n+.035),r.connect(l),l.connect(e.destination),r.start(n),r.stop(n+.035)):"synth"===t?(r.type="sawtooth",r.frequency.setValueAtTime(340,n),r.frequency.exponentialRampToValueAtTime(140,n+.04),l.gain.setValueAtTime(.025,n),l.gain.exponentialRampToValueAtTime(.001,n+.04),r.connect(l),l.connect(e.destination),r.start(n),r.stop(n+.04)):(r.type="triangle",r.frequency.setValueAtTime(1100+300*Math.random(),n),l.gain.setValueAtTime(.035,n),l.gain.exponentialRampToValueAtTime(.001,n+.02),r.connect(l),l.connect(e.destination),r.start(n),r.stop(n+.02))}catch(e){}}function A(e){try{e.stop()}catch(e){}}const E=new WeakMap;function k(e,t="grapheme"){var n;const r=null!=(n=e.textContent)?n:"";let l=E.get(e);return l&&l.text===r||(l={text:r,values:new Map},E.set(e,l)),l.values.has(t)||l.values.set(t,function(e,t="grapheme"){if("undefined"!=typeof Intl&&Intl.Segmenter){const n=new Intl.Segmenter(void 0,{granularity:t});return Array.from(n.segment(e),e=>e.segment)}if("word"===t){return e.match(/\s+|\S+/g)||[e]}return Array.from(e)}(r,t)),l.values.get(t)}function N(e){const t=e.trim().toLowerCase();return!t.startsWith("javascript:")&&!t.startsWith("data:")&&!t.startsWith("vbscript:")}function F(e,t,n,r){const l=document.createDocumentFragment();if(t)return l.appendChild(document.createTextNode(e)),l;const o=document.createElement("template");o.innerHTML=e;const a=(e,t)=>{e.childNodes.forEach(e=>{var l;if(e.nodeType===Node.TEXT_NODE)t.appendChild(document.createTextNode(null!=(l=e.textContent)?l:""));else if(e.nodeType===Node.ELEMENT_NODE){const l=function(e,t,n){var r,l;const o=e.tagName.toLowerCase();if(!t.has(o))return null;const a=document.createElement(o),i=null!=(r=n[o])?r:new Set,s=null!=(l=n["*"])?l:new Set;for(const t of Array.from(e.attributes)){const e=t.name.toLowerCase();e.startsWith("on")||(i.has(e)||s.has(e))&&("href"!==e&&"src"!==e||N(t.value))&&a.setAttribute(e,t.value)}return"a"===o&&"_blank"===a.getAttribute("target")&&a.setAttribute("rel","noopener noreferrer"),a}(e,n,r);l?(t.appendChild(l),a(e,l)):a(e,t)}})};return a(o.content,l),l}function I(e,t="grapheme"){if(3===e.nodeType)return k(e,t).length;let n=0;return e.childNodes.forEach(e=>n+=I(e,t)),n}function O(e,t,n,r="grapheme",l={}){var o,a;if(3===e.nodeType){const i=k(e,r),s=i.length;if(n<=0||t>=s)return{clone:null,start:Math.max(0,t-s),end:Math.max(0,n-s)};const c=Math.max(0,t),u=Math.min(s,n),d=(null==e?void 0:e.ownerDocument)||("undefined"!=typeof document?document:null);if(!d)return{clone:null,start:t,end:n};if((null==l?void 0:l.scrambleActive)&&u>c&&(null==(o=i[u-1])?void 0:o.trim())){const e=d.createDocumentFragment();u-1>c&&e.appendChild(d.createTextNode(i.slice(c,u-1).join("")));const r=d.createElement("span");return r.className="tf-scramble",l.scrambleColor&&(r.style.color=l.scrambleColor),l.scrambleGradient&&(r.style.backgroundImage=l.scrambleGradient,r.style.webkitBackgroundImage=l.scrambleGradient,r.style.webkitBackgroundClip="text",r.style.backgroundClip="text",r.style.webkitTextFillColor="transparent",r.style.display="inline-block"),r.textContent=(a=l.scrambleGlyphs)[Math.floor(Math.random()*a.length)],e.appendChild(r),{clone:e,start:Math.max(0,t-s),end:Math.max(0,n-s)}}const p="number"==typeof l.trailFade?l.trailFade:"number"==typeof l.trailingFadeLength?l.trailingFadeLength:l.trailFade?4:0;if(p>0&&u-c>=1&&!l.isComplete){const e=d.createDocumentFragment(),r=Math.max(c,u-p);r>c&&e.appendChild(d.createTextNode(i.slice(c,r).join("")));const o=u-r,a="number"==typeof l.trailingFadeMinOpacity?l.trailingFadeMinOpacity:"number"==typeof l.trailMinOpacity?l.trailMinOpacity:.18;for(let t=0;t<o;t++){const n=r+t,l=d.createElement("span");l.className="tf-trail";const s=a+(1-a)*(o<=1?1:(t+1)/o);l.style.opacity=s.toFixed(3),l.textContent=i[n],e.appendChild(l)}return{clone:e,start:Math.max(0,t-s),end:Math.max(0,n-s)}}const f=i.slice(c,u).join("");return{clone:d.createTextNode(f),start:Math.max(0,t-s),end:Math.max(0,n-s)}}if(1===e.nodeType){const o=e,a=o.tagName.toLowerCase();if(w.has(a))return n<=0?{clone:null,start:t,end:n}:{clone:o.cloneNode(!1),start:t,end:n};const i=o.cloneNode(!1);let s=t,c=n,u=!1;return e.childNodes.forEach(e=>{const t=O(e,s,c,r,l);t.clone&&(i.appendChild(t.clone),u=!0),s=t.start,c=t.end}),{clone:u?i:null,start:s,end:c}}return{clone:null,start:t,end:n}}function L(e){const t=_(e);if(!t){const t=null===e?"null":void 0===e?"undefined":String(e);throw new Error(`TypeFlow: target element not found (${t})`)}return t}function _(e){return"string"==typeof e?document.querySelector(e):e}function P(e){const t=String(null!=e?e:"left-to-right").toLowerCase();return"right-to-left"===t||"reverse"===t||"rtl"===t?"right-to-left":"random"===t||"shuffle"===t?"random":"left-to-right"}function B(e,t,n){const r=Array.from({length:e},(e,t)=>t);if("right-to-left"===P(t))return r.reverse();if("random"!==P(t))return r;const l=function(e){if(null==e)return Math.random;const t=String(e);let n=2166136261;for(let e=0;e<t.length;e+=1)n^=t.charCodeAt(e),n=Math.imul(n,16777619);return()=>{n+=1831565813;let e=n;return e=Math.imul(e^e>>>15,1|e),e^=e+Math.imul(e^e>>>7,61|e),((e^e>>>14)>>>0)/4294967296}}(n);for(let e=r.length-1;e>0;e-=1){const t=Math.floor(l()*(e+1));[r[e],r[t]]=[r[t],r[e]]}return r}function D(e,t="opacity",n="word-fade"){const r=(null==e?void 0:e.ownerDocument)||("undefined"!=typeof document?document:null);if(!r)return{fragment:null,words:[]};const l=r.createDocumentFragment(),o=[],a="word-fade"!==n,i=(e,n)=>{e.childNodes.forEach(e=>{var l;if(e.nodeType===Node.TEXT_NODE)for(const i of function(e){var t;return"undefined"!=typeof Intl&&Intl.Segmenter?Array.from(new Intl.Segmenter(void 0,{granularity:"word"}).segment(e)):(null!=(t=e.match(/\s+|\S+/g))?t:[]).map(e=>({segment:e,isWordLike:!/^\s+$/u.test(e)}))}(null!=(l=e.textContent)?l:"")){if(/^\s+$/u.test(i.segment)){n.appendChild(r.createTextNode(i.segment));continue}if(!1===i.isWordLike&&o.length>0&&o.at(-1).parentNode===n){o.at(-1).appendChild(r.createTextNode(i.segment));continue}const e=r.createElement("span");e.className="tf-word-fade",e.dataset.tfWordIndex=String(o.length),e.textContent=i.segment,e.style.display=a?"inline-block":"inline",e.style.opacity="0",e.style.willChange=a?"opacity, transform":"opacity",e.setAttribute("aria-hidden","true"),"placeholder"===t&&(e.style.visibility="hidden"),o.push(e),n.appendChild(e)}else if(e.nodeType===Node.ELEMENT_NODE){const t=e.cloneNode(!1);n.appendChild(t),i(e,t)}})};return i(e,l),{fragment:l,words:o}}function q(){return"undefined"!=typeof window&&"function"==typeof window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches}function W(e,t=!1){const n=document.createElement("span");return n.className="tf-cursor",n.setAttribute("aria-hidden","true"),n.textContent=e,t&&(n.style.visibility="hidden"),n}const $=new class{constructor(){u(this,"active",new Map),u(this,"baselines",new WeakMap),u(this,"cursorIntervals",new Map)}clearCursorInterval(e){const t=this.cursorIntervals.get(e);t&&(clearInterval(t),this.cursorIntervals.delete(e))}animate(e,t,n,r,l,o,a,i={}){var s,c,u,d,p,f,m,h,g;this.clearCursorInterval(e),null==(s=this.active.get(e))||s.stop(),r.ariaLive&&e.setAttribute("aria-live",r.ariaLive);const v=null!=(c=i.prefix)?c:[],w=null!=(u=i.blinkOnFinish)&&u,x=o>=l?1:-1,C=Math.max(0,Number(null!=(d=r.speed)?d:b.speed)||0),S=null!=(p=r.granularity)?p:b.granularity,M="scramble"===r.typeStyle||"scramble"===r.eraseStyle,E=(N=r.scrambleGlyphs,(F=null!=(f=r.scrambleCharset)?f:r.scramblePreset)&&y[F]?y[F]:"string"==typeof N&&y[N]?y[N]:null!=N?N:y.cyber);var N,F;let I=!1,L=null,_=null;const P=!0===i.plainText&&1===x&&"left"===r.direction&&!M&&"fade-trail"!==r.typeStyle&&void 0===r.trailFade&&void 0===r.trailingFadeLength?k(t.firstChild,S):null,B=P?document.createTextNode(""):null;let D=null,$=0;const j=()=>{null!==L&&clearTimeout(L),this.clearCursorInterval(e),L=null},R=(l,a,s=!1,c=!1)=>{var u,d,p,f,m;if(B&&!s)return l===$+1?B.data+=null!=(u=P[$])?u:"":l!==$&&(B.data=P.slice(0,l).join("")),$=l,B.parentNode||e.replaceChildren(...v,B),void(a?(D||(D=W(a,c)),D.textContent=a,D.style.visibility=c?"hidden":"visible",D.parentNode||e.appendChild(D)):(null==D?void 0:D.parentNode)&&D.remove());const h=function(e,t,n,r,l){if(l){if("start"===r)return{start:t-e,end:t};if("center"===r){const n=Math.max(0,Math.floor((t-e)/2));return{start:n,end:Math.min(t,n+e)}}return{start:0,end:e}}if("right"===n)return{start:t-e,end:t};if("center"===n){const n=Math.max(0,Math.floor((t-e)/2));return{start:n,end:Math.min(t,n+e)}}return{start:0,end:e}}(l,n,null!=(d=r.direction)?d:"left",null!=(p=r.eraseStyle)?p:"end",null!=(f=i.isErasing)&&f),y=null!==r.trailFade&&void 0!==r.trailFade||null!==r.trailingFadeLength&&void 0!==r.trailingFadeLength||"fade-trail"===r.typeStyle||"fade-trail"===r.eraseStyle,g="number"==typeof r.trailFade?r.trailFade:"number"==typeof r.trailingFadeLength?r.trailingFadeLength:y?null!=(m=r.trailingFadeLength)?m:4:0,b="number"==typeof r.trailingFadeMinOpacity?r.trailingFadeMinOpacity:"number"==typeof r.trailMinOpacity?r.trailMinOpacity:.18;e.replaceChildren(...v,function(e,t,n,r="grapheme",l={}){const o=(null==e?void 0:e.ownerDocument)||("undefined"!=typeof document?document:null);if(!o)return null;const a=o.createDocumentFragment();let i=t,s=n;return e.childNodes.forEach(e=>{const t=O(e,i,s,r,l);t.clone&&a.appendChild(t.clone),i=t.start,s=t.end}),a}(t,h.start,h.end,S,{scrambleActive:s,scrambleGlyphs:E,scrambleColor:r.scrambleColor,scrambleGradient:r.scrambleGradient,trailFade:g,trailingFadeLength:g,trailingFadeMinOpacity:b,isComplete:l===o&&!s})),a&&e.appendChild(W(a,c))},z=t=>{var n,l,i;if(!I){if(I=!0,j(),this.active.delete(e),t){if(w&&r.cursor&&r.cursorBlink){let t=!0;R(o,r.cursor,!1,!1);const l=setInterval(()=>{t=!t,R(o,r.cursor,!1,!t)},530);null==(n=l.unref)||n.call(l),this.cursorIntervals.set(e,l)}else R(o,"",!1);null==(l=r.onComplete)||l.call(r,a)}else this.clearCursorInterval(e),A(r.audio),null==(i=r.onInterrupt)||i.call(r);null==_||_({completed:t,text:a})}},V={stop:()=>z(!1),promise:new Promise(e=>{_=e})};this.active.set(e,V);if(!0===r.respectReducedMotion&&q())return z(!0),V;let G=0;const X=null!=(m=r.scrambleRounds)?m:b.scrambleRounds,Y=e=>{var t,n;if(r.audio&&T(r.audio),M&&G<X&&e!==o)return R(e,null!=(t=r.cursor)?t:"",!0),G++,void(L=setTimeout(()=>Y(e),Math.max(10,C/2)));if(G=0,R(e,null!=(n=r.cursor)?n:"",!1),e===o)return void z(!0);const l=r.speedVariance?(2*Math.random()-1)*r.speedVariance:0,i=r.naturalCadence?function(e,t){if(t<=0||t>e.length)return 0;const n=e[t-1];return"."===n||"!"===n||"?"===n?220:","===n||";"===n||":"===n?110:" "===n?40:0}(a,e):0,s=Math.max(0,C+l+i);L=setTimeout(()=>Y(e+x),s)};return null==(h=r.onStart)||h.call(r),L=setTimeout(()=>Y(l),null!=(g=r.delay)?g:0),V}animateWordMotion(e,t,n,r={}){var l,o,a,i,s,c,u,d;this.clearCursorInterval(e),null==(l=this.active.get(e))||l.stop(),n.ariaLive&&e.setAttribute("aria-live",n.ariaLive);const p=null!=(o=r.prefix)?o:[],f=!0===r.isErasing,m=null!=(a=r.motionKind)?a:"word-fade",h="placeholder"===n.wordLayout?"placeholder":"opacity",y=Math.max(0,Number(null!=(i=n.wordFadeDuration)?i:280)||0),g=Math.max(0,Number(null!=(c=null!=(s=n.wordStagger)?s:n.speed)?c:70)||0),b=function(e,t){var n,r,l;const o=Math.max(0,Number(null!=(n=t.wordMotionDistance)?n:24)||0),a=Math.max(0,Number(null!=(r=t.wordMotionDepth)?r:160)||0),i=Math.min(1,Math.max(.01,Number(null!=(l=t.wordMotionScale)?l:.82)||.82));switch(e){case"float-in-top":return{hidden:`translateY(-${o}px)`,visible:"translateY(0)"};case"float-in-bottom":return{hidden:`translateY(${o}px)`,visible:"translateY(0)"};case"float-in-left":return{hidden:`translateX(-${o}px)`,visible:"translateX(0)"};case"float-in-right":return{hidden:`translateX(${o}px)`,visible:"translateX(0)"};case"zoom-in-space":return{hidden:`translateZ(-${a}px) scale(${i})`,visible:"translateZ(0) scale(1)"};default:return null}}(m,n),v="zoom-in-space"===m,{fragment:w,words:x}=D(t,h,m),C=B(x.length,n.wordOrder,n.wordSeed);C.forEach((e,t)=>{x[e].dataset.tfWordOrder=String(t)});const S=new Set;let M=null,E=!1,k=null;const N="string"==typeof n.wordMotionEasing&&n.wordMotionEasing.trim()?n.wordMotionEasing.trim():"ease";x.forEach(e=>{e.style.transition=b?`opacity ${y}ms ${N}, transform ${y}ms ${N}`:`opacity ${y}ms ${N}`,b&&(e.style.transform=b.hidden),f&&(e.style.opacity="1",e.style.visibility="visible",e.removeAttribute("aria-hidden"),b&&(e.style.transform=b.visible))}),v&&(e.style.perspective=`${Math.max(0,Number(null!=(u=n.wordMotionPerspective)?u:600)||0)}px`,e.style.transformStyle="preserve-3d"),e.replaceChildren(...p,w),e.setAttribute("aria-busy","true");const F=(e,t)=>{const n=setTimeout(()=>{S.delete(n),e()},t);S.add(n)},I=()=>{var t;if(!n.cursor)return;const r=W(n.cursor);if(e.appendChild(r),n.cursorBlink){let n=!0;const l=setInterval(()=>{n=!n,r.style.visibility=n?"visible":"hidden"},530);null==(t=l.unref)||t.call(l),this.cursorIntervals.set(e,l)}},O=l=>{var o,a,i,s,c;E||(E=!0,S.forEach(e=>clearTimeout(e)),S.clear(),null!==M&&"function"==typeof cancelAnimationFrame&&cancelAnimationFrame(M),M=null,this.active.delete(e),e.removeAttribute("aria-busy"),v&&(e.style.removeProperty("perspective"),e.style.removeProperty("transform-style")),l?f?(e.replaceChildren(...p),null==(o=n.onComplete)||o.call(n,"")):(e.replaceChildren(...p,t.cloneNode(!0)),I(),null==(i=n.onComplete)||i.call(n,null!=(a=r.resultText)?a:"")):(e.replaceChildren(...p,t.cloneNode(!0)),A(n.audio),null==(s=n.onInterrupt)||s.call(n)),null==k||k({completed:l,text:f?"":null!=(c=r.resultText)?c:""}))},L={stop:()=>O(!1),promise:new Promise(e=>{k=e})};if(this.active.set(e,L),!0===n.respectReducedMotion&&q())return O(!0),L;null==(d=n.onStart)||d.call(n);return F(()=>{M=requestAnimationFrame(()=>{if(M=null,0===x.length)return void O(!0);let e=0;const t=()=>{const r=x[C[e]];n.audio&&T(n.audio),f?(r.style.opacity="0",b&&(r.style.transform=b.hidden),r.setAttribute("aria-hidden","true")):(r.style.visibility="visible",r.removeAttribute("aria-hidden"),r.style.opacity="1",b&&(r.style.transform=b.visible)),e+=1,e<x.length?F(t,g):F(()=>O(!0),y)};t()})},Math.max(0,Number(n.delay)||0)),L}eraseFade(e,t,n,r){var l,o;this.clearCursorInterval(e),null==(l=this.active.get(e))||l.stop();const a=document.createElement("span");t.forEach(e=>a.appendChild(e)),e.replaceChildren(...n,a);const i=null!=(o=r.duration)?o:250;let s=!1,c=null,u=null;const d=t=>{var l,o;s||(s=!0,null!==c&&clearTimeout(c),this.clearCursorInterval(e),this.active.delete(e),t?(e.replaceChildren(...n),null==(l=r.onComplete)||l.call(r,"")):(A(r.audio),null==(o=r.onInterrupt)||o.call(r)),null==u||u({completed:t,text:""}))},p={stop:()=>d(!1),promise:new Promise(e=>{u=e})};return this.active.set(e,p),r.respectReducedMotion&&q()?(d(!0),p):(requestAnimationFrame(()=>{a.style.transition=`opacity ${i}ms ease`,a.style.opacity="0"}),c=setTimeout(()=>d(!0),i),p)}instantClear(e,t,n){var r,l;return this.clearCursorInterval(e),null==(r=this.active.get(e))||r.stop(),e.replaceChildren(...t),null==(l=n.onComplete)||l.call(n,""),{stop:()=>{},promise:Promise.resolve({completed:!0,text:""})}}
|
|
12
|
+
/**
|
|
13
|
+
* Types text or sanitized HTML into the target element character by character
|
|
14
|
+
* (or word by word when `typeStyle: 'word'`).
|
|
15
|
+
*
|
|
16
|
+
* Any animation currently running on `target` is stopped before the new one
|
|
17
|
+
* starts. If `prefers-reduced-motion: reduce` is active and
|
|
18
|
+
* `respectReducedMotion` is `true` (the default), the full text is rendered
|
|
19
|
+
* immediately without animation.
|
|
20
|
+
*
|
|
21
|
+
* @param {Element | string} target
|
|
22
|
+
* A DOM element or a CSS selector string resolved via `document.querySelector`.
|
|
23
|
+
* @param {string} text
|
|
24
|
+
* The text or HTML string to type. When `config.html` is `false` (default)
|
|
25
|
+
* the string is treated as plain text and no parsing is performed.
|
|
26
|
+
* @param {Partial<TypeFlowConfig>} [config={}]
|
|
27
|
+
* Optional configuration overrides. See {@link TypeFlowConfig} for the full
|
|
28
|
+
* option set. Merged with {@link TYPE_DEFAULTS}.
|
|
29
|
+
* @returns {TypeFlowController}
|
|
30
|
+
* A controller object with a `stop()` method and a `promise` that resolves
|
|
31
|
+
* to `{ completed: boolean, text: string }`.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* const controller = TypeFlow.type('#headline', 'Hello <strong>World</strong>', {
|
|
35
|
+
* html: true,
|
|
36
|
+
* speed: 45,
|
|
37
|
+
* cursor: '|',
|
|
38
|
+
* cursorBlink: true,
|
|
39
|
+
* onComplete: (text) => console.log('Done:', text),
|
|
40
|
+
* });
|
|
41
|
+
*
|
|
42
|
+
* // Abort mid-animation
|
|
43
|
+
* button.addEventListener('click', () => controller.stop());
|
|
44
|
+
*/type(e,t,n={}){var r,l;const o=L(e),a=s(s({},b),n);Object.prototype.hasOwnProperty.call(n,"scrambleGlyphs")&&(a.scrambleCharset=void 0),a.direction=function(e){if(!e)return"left";const t=String(e).toLowerCase();return"right"===t||"rtl"===t||"end"===t||"reverse"===t?"right":"center"===t||"middle"===t||"expand"===t||"both"===t?"center":"left"}(a.direction),a.typeStyle=function(e){if(!e)return"char";const t=String(e).toLowerCase();return"word"===t||"words"===t||"stream"===t?"word":"scramble"===t||"matrix"===t||"decrypt"===t||"cyber"===t||"random"===t?"scramble":"fade-trail"===t||"trail"===t||"trailing"===t||"soft"===t?"fade-trail":"word-fade"===t||"fade-words"===t||"wordfade"===t?"word-fade":"float-in-top"===t||"float-top"===t||"float-down"===t?"float-in-top":"float-in-bottom"===t||"float-bottom"===t||"float-up"===t?"float-in-bottom":"float-in-left"===t||"float-left"===t?"float-in-left":"float-in-right"===t||"float-right"===t?"float-in-right":"zoom-in-space"===t||"zoom-in"===t||"zoom-space"===t?"zoom-in-space":"char"}(a.typeStyle),"word"===a.typeStyle&&(a.granularity="word");const i=new Set([...x,...null!=(r=a.allowedTags)?r:[]]),c=s({},C);if(a.allowedAttributes)for(const[e,t]of Object.entries(a.allowedAttributes))c[e]=new Set([...null!=(l=c[e])?l:[],...t]);let u=null==t?"":String(t);a.html&&a.sanitizer&&(u=a.sanitizer(u));const d=F(u,!a.html,i,c),p=I(d,a.granularity),f="append"===a.mode?Array.from(o.childNodes):[];return"append"===a.mode?this.baselines.set(o,f):this.baselines.delete(o),S.has(a.typeStyle)?this.animateWordMotion(o,d,a,{prefix:f,resultText:u,isErasing:!1,motionKind:a.typeStyle}):this.animate(o,d,p,a,0,p,u,{prefix:f,blinkOnFinish:!0,isErasing:!1,plainText:!a.html})}erase(e,t={}){var n;const r=L(e),l=s(s({},v),t);Object.prototype.hasOwnProperty.call(t,"scrambleGlyphs")&&(l.scrambleCharset=void 0),l.eraseStyle=function(e){if(!e)return"end";const t=String(e).toLowerCase();return"start"===t||"erosion"===t||"left"===t||"forward"===t?"start":"center"===t||"middle"===t||"shrink"===t||"split"===t?"center":"scramble"===t||"matrix"===t||"decrypt"===t||"cyber"===t||"random"===t?"scramble":"fade-trail"===t||"trail"===t||"trailing"===t||"soft"===t?"fade-trail":"fade"===t||"dissolve"===t||"crossfade"===t?"fade":"word-fade"===t||"fade-words"===t||"wordfade"===t?"word-fade":"float-in-top"===t||"float-top"===t||"float-down"===t?"float-in-top":"float-in-bottom"===t||"float-bottom"===t||"float-up"===t?"float-in-bottom":"float-in-left"===t||"float-left"===t?"float-in-left":"float-in-right"===t||"float-right"===t?"float-in-right":"zoom-in-space"===t||"zoom-in"===t||"zoom-space"===t?"zoom-in-space":"instant"===t||"clear"===t||"reset"===t||"immediate"===t?"instant":"end"}(l.eraseStyle);const o=l.preserveBaseline&&null!=(n=this.baselines.get(r))?n:[],a=Array.from(r.childNodes),i=o.length?a.filter(e=>!o.includes(e)):a;if("instant"===l.eraseStyle)return this.instantClear(r,o,l);if("fade"===l.eraseStyle)return this.eraseFade(r,i,o,l);const c=document.createDocumentFragment();i.forEach(e=>c.appendChild(e.cloneNode(!0)));const u=I(c,l.granularity);return S.has(l.eraseStyle)?this.animateWordMotion(r,c,l,{prefix:o,isErasing:!0,motionKind:l.eraseStyle}):this.animate(r,c,u,l,u,0,"",{prefix:o,isErasing:!0})}
|
|
45
|
+
/**
|
|
46
|
+
* Smart Diff Morphing: compares the existing text content of `target` with `nextText`,
|
|
47
|
+
* erases only the mismatched trailing characters, and types the replacement text.
|
|
48
|
+
*
|
|
49
|
+
* @param {Element | string} target - Target element or CSS selector string.
|
|
50
|
+
* @param {string} nextText - Destination text.
|
|
51
|
+
* @param {Partial<TypeFlowConfig>} [options={}] - Animation options.
|
|
52
|
+
* @returns {Promise<{ completed: boolean, text: string }>}
|
|
53
|
+
*/morph(e,t,n={}){var r;const l=L(e),o=null!=(r=l.textContent)?r:"",a=null==t?"":String(t);let i=0;const u=Math.min(o.length,a.length);for(;i<u&&o[i]===a[i];)i++;const d=o.length-i,p=a.slice(i),f=[];return d>0&&f.push(j.call(()=>{var e,t;const r=document.createDocumentFragment();r.appendChild(document.createTextNode(o));const a=o.length;return this.animate(l,r,a,c(s(s({},v),n),{speed:null!=(t=null!=(e=n.eraseSpeed)?e:n.speed)?t:v.speed}),a,i,o.slice(0,i),{prefix:[],isErasing:!0}).promise})),p.length>0&&f.push(j.type(l,p,c(s({},n),{mode:"append"}))),this.sequence(f)}
|
|
54
|
+
/**
|
|
55
|
+
* Creates a streaming chunk consumer for real-time LLM token ingestion.
|
|
56
|
+
*
|
|
57
|
+
* @param {Element | string} target - Target element or CSS selector.
|
|
58
|
+
* @param {Partial<TypeFlowConfig> & { onChunk?: (chunk: string, fullText: string) => void }} [options={}]
|
|
59
|
+
* @returns {{ push: (chunk: string) => void, stop: () => void, clear: () => void }}
|
|
60
|
+
*/stream(e,t={}){const n=L(e);let r=[],l=!1;const o=()=>{if(0===r.length)return void(l=!1);l=!0;const e=r.shift();this.type(n,e,c(s({},t),{mode:"append",onComplete:n=>{var r;null==(r=t.onChunk)||r.call(t,e,n),o()}}))};return{push:e=>{null!=e&&String(e).length>0&&(r.push(String(e)),l||o())},stop:()=>{r=[],this.stop(n),l=!1},clear:()=>{r=[],this.stop(n),l=!1,n.replaceChildren()}}}
|
|
61
|
+
/**
|
|
62
|
+
* Returns a complete pre-configured options object for common typewriter profiles.
|
|
63
|
+
*
|
|
64
|
+
* @param {'cyberpunk' | 'terminal' | 'writer' | 'matrix' | 'blocks' | 'subtle'} name
|
|
65
|
+
* @param {Partial<TypeFlowConfig>} [overrides={}]
|
|
66
|
+
* @returns {TypeFlowConfig}
|
|
67
|
+
*/preset(e,t={}){var n;const r=null!=(n=g[e])?n:g.writer;return s(s({},r),t)}
|
|
68
|
+
/**
|
|
69
|
+
* Executes an ordered list of animation steps sequentially, waiting for each
|
|
70
|
+
* step to complete before advancing to the next one.
|
|
71
|
+
*
|
|
72
|
+
* Supported step kinds (created via the {@link seq} helper):
|
|
73
|
+
* - `seq.type(target, text, config)` — Types text into a target element.
|
|
74
|
+
* - `seq.erase(target, config)` — Erases content from a target element.
|
|
75
|
+
* - `seq.pause(duration)` — Waits `duration` milliseconds.
|
|
76
|
+
* - `seq.call(fn)` — Invokes an async or sync function.
|
|
77
|
+
* - `seq.visible(target, threshold)` — Waits until the target is visible.
|
|
78
|
+
*
|
|
79
|
+
* If any step's animation is interrupted (via `controller.stop()`), the
|
|
80
|
+
* entire sequence halts immediately.
|
|
81
|
+
*
|
|
82
|
+
* @param {Array<SequenceStep>} steps
|
|
83
|
+
* An ordered array of step descriptors. Use the {@link seq} helper to
|
|
84
|
+
* construct them.
|
|
85
|
+
* @param {{ repeat?: number, target?: Element | string }} [seqConfig={}]
|
|
86
|
+
* Optional sequence-level configuration.
|
|
87
|
+
* - `repeat` — Number of times to repeat the full sequence. Use `Infinity`
|
|
88
|
+
* for indefinite repetition. Defaults to `1`.
|
|
89
|
+
* - `target` — A default target element applied to steps that do not
|
|
90
|
+
* specify one individually.
|
|
91
|
+
* @returns {TypeFlowController}
|
|
92
|
+
* A controller with `stop()` and a `promise` resolving to
|
|
93
|
+
* `{ completed: boolean, text: '' }`.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* import { TypeFlow, seq } from '@staticcanvas/typeflow';
|
|
97
|
+
*
|
|
98
|
+
* TypeFlow.sequence([
|
|
99
|
+
* seq.type('#output', 'Step 1 complete.'),
|
|
100
|
+
* seq.pause(600),
|
|
101
|
+
* seq.call(() => triggerSoundEffect()),
|
|
102
|
+
* seq.erase('#output'),
|
|
103
|
+
* seq.type('#output', 'Step 2 starting...'),
|
|
104
|
+
* ], { repeat: 1 });
|
|
105
|
+
*/sequence(e,t={}){if(!Array.isArray(e)||0===e.length)return{stop:()=>{},promise:Promise.resolve({completed:!0,text:""})};let n=!1,r=null,l=null,o=null;const a=e=>{var n;const r=null!=(n=e.target)?n:t.target;if(!r)throw new Error("TypeFlow: a sequence step is missing a target, and no default `target` was set on the sequence config.");return r},i={stop:()=>{n||(n=!0,null==r||r.stop(),null==l||l(),null==o||o())},promise:null},s=()=>h(this,null,function*(){for(const t of e){if(n)return!1;if("type"===t.kind){if(r=this.type(a(t),t.text,t.config),!(yield r.promise).completed)return!1}else if("erase"===t.kind){if(r=this.erase(a(t),t.config),!(yield r.promise).completed)return!1}else if("pause"===t.kind){const e=yield new Promise(e=>{const n=setTimeout(()=>e(!0),t.duration);l=()=>{clearTimeout(n),e(!1)}});if(l=null,!e)return!1}else if("visible"===t.kind){const e=L(a(t)),n=yield new Promise(n=>{var r;if("undefined"==typeof IntersectionObserver)return void n(!0);const l=new IntersectionObserver(e=>{e.some(e=>e.isIntersecting)&&(l.disconnect(),n(!0))},{threshold:null!=(r=t.threshold)?r:.1});o=()=>{l.disconnect(),n(!1)},l.observe(e)});if(o=null,!n)return!1}else if("call"===t.kind)try{yield t.fn()}catch(e){console.error("TypeFlow: error in seq.call step:",e)}if(n)return!1}return!0});return i.promise=(()=>h(this,null,function*(){var e;const n=null!=(e=t.repeat)?e:1;for(let e=0;n===1/0||e<n;e++)if(!(yield s()))return{completed:!1,text:""};return{completed:!0,text:""}}))(),i}
|
|
106
|
+
/**
|
|
107
|
+
* Cyclically types and erases an array of strings in sequence.
|
|
108
|
+
*
|
|
109
|
+
* Internally delegates to {@link TypeFlowEngine#sequence}, constructing a
|
|
110
|
+
* step list of: `type → pause (holdDuration) → erase → pause (pauseBetween)`
|
|
111
|
+
* for each word.
|
|
112
|
+
*
|
|
113
|
+
* @param {Element | string} target
|
|
114
|
+
* A DOM element or a CSS selector string.
|
|
115
|
+
* @param {string[]} words
|
|
116
|
+
* An ordered array of strings to rotate through.
|
|
117
|
+
* @param {RotateConfig} [config={}]
|
|
118
|
+
* Optional rotation configuration.
|
|
119
|
+
* @param {Partial<TypeFlowConfig>} [config.typeConfig={}]
|
|
120
|
+
* Config options applied to every `type` step.
|
|
121
|
+
* @param {Partial<TypeFlowConfig>} [config.eraseConfig={}]
|
|
122
|
+
* Config options applied to every `erase` step.
|
|
123
|
+
* @param {number} [config.holdDuration=1200]
|
|
124
|
+
* Milliseconds to hold each fully-typed word before erasing.
|
|
125
|
+
* @param {number} [config.pauseBetween=200]
|
|
126
|
+
* Milliseconds to wait after erasing before typing the next word.
|
|
127
|
+
* @param {number | typeof Infinity} [config.repeat=Infinity]
|
|
128
|
+
* Number of full rotation cycles. Use `Infinity` for indefinite rotation.
|
|
129
|
+
* @returns {TypeFlowController}
|
|
130
|
+
* A controller with `stop()` and a resolving `promise`.
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* TypeFlow.rotate('#rotating', ['Fast', 'Lightweight', 'Reliable'], {
|
|
134
|
+
* holdDuration: 1200,
|
|
135
|
+
* pauseBetween: 200,
|
|
136
|
+
* repeat: Infinity,
|
|
137
|
+
* });
|
|
138
|
+
*/rotate(e,t,n={}){const{typeConfig:r={},eraseConfig:l={},holdDuration:o=1200,pauseBetween:a=200,repeat:i=1/0}=n,s=[];return t.forEach(t=>{s.push({kind:"type",target:e,text:t,config:r}),s.push({kind:"pause",duration:o}),s.push({kind:"erase",target:e,config:l}),s.push({kind:"pause",duration:a})}),this.sequence(s,{repeat:i})}
|
|
139
|
+
/**
|
|
140
|
+
* Staggers typing across multiple DOM elements with an offset delay between each item.
|
|
141
|
+
*
|
|
142
|
+
* @param {Element[] | NodeList | string} targets
|
|
143
|
+
* A CSS selector string matching multiple elements, or an array / NodeList of elements.
|
|
144
|
+
* @param {string | string[] | ((el: Element, index: number) => string)} [textOrTexts]
|
|
145
|
+
* A string, an array of strings (one per target), or a resolver callback.
|
|
146
|
+
* If omitted, reads each element's existing textContent.
|
|
147
|
+
* @param {Partial<TypeFlowConfig> & { stagger?: number }} [config={}]
|
|
148
|
+
* TypeFlow options merged with `stagger` offset delay in ms (default: `150`).
|
|
149
|
+
* @returns {TypeFlowController}
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* TypeFlow.stagger('.prompt-line', [
|
|
153
|
+
* 'npm install @staticcanvas/typeflow',
|
|
154
|
+
* 'npm run build',
|
|
155
|
+
* 'typeflow start --port=3000',
|
|
156
|
+
* 'Ready on http://localhost:3000'
|
|
157
|
+
* ], {
|
|
158
|
+
* speed: 30,
|
|
159
|
+
* stagger: 250,
|
|
160
|
+
* cursor: '|'
|
|
161
|
+
* });
|
|
162
|
+
*/stagger(e,t,n={}){var r;let l=[];if("string"==typeof e)l="undefined"!=typeof document?Array.from(document.querySelectorAll(e)):[];else if(Array.isArray(e))l=e.map(e=>{try{return L(e)}catch(e){return null}}).filter(Boolean);else if(e&&"function"==typeof e[Symbol.iterator])l=Array.from(e).map(e=>{try{return L(e)}catch(e){return null}}).filter(Boolean);else try{const t=L(e);t&&(l=[t])}catch(e){}if(0===l.length)return{stop:()=>{},promise:Promise.resolve({completed:!0,text:""})};const o=null!=(r=n.stagger)?r:150,a=[];let i=!1;const u=l.map((e,r)=>{var l;let i="";i="function"==typeof t?t(e,r):Array.isArray(t)?void 0!==t[r]?t[r]:"":"string"==typeof t?t:e.textContent||"";const u=(null!=(l=n.delay)?l:0)+r*o,d=c(s({},n),{delay:u}),p=this.type(e,i,d);return a.push(p),p.promise});return{stop:()=>{i=!0,a.forEach(e=>e.stop())},promise:Promise.all(u).then(e=>{const t=e.every(e=>e.completed);return{completed:!i&&t,text:e.map(e=>e.text).join("\n")}})}}
|
|
163
|
+
/**
|
|
164
|
+
* Observes a DOM subtree for mutations and invokes `callback` whenever
|
|
165
|
+
* elements matching `childSelector` are added to the tree. Also invokes the
|
|
166
|
+
* callback immediately for any pre-existing matching elements inside
|
|
167
|
+
* `container`.
|
|
168
|
+
*
|
|
169
|
+
* Useful for animating dynamically injected content (e.g. chat messages,
|
|
170
|
+
* feed items, server-streamed responses) without polling.
|
|
171
|
+
*
|
|
172
|
+
* @param {Element | string} container
|
|
173
|
+
* The root element whose subtree is observed.
|
|
174
|
+
* @param {string} childSelector
|
|
175
|
+
* A CSS selector string. Newly added elements matching this selector
|
|
176
|
+
* will trigger `callback`.
|
|
177
|
+
* @param {(el: Element) => void} callback
|
|
178
|
+
* Function invoked with each matching element. Runs synchronously for
|
|
179
|
+
* pre-existing matches and on the microtask after each mutation.
|
|
180
|
+
* @returns {{ disconnect: () => void }}
|
|
181
|
+
* An object with a `disconnect()` method that stops observation.
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* const watcher = TypeFlow.watch('#feed', '.item-title', (el) => {
|
|
185
|
+
* const text = el.textContent;
|
|
186
|
+
* el.textContent = '';
|
|
187
|
+
* TypeFlow.type(el, text, { speed: 20 });
|
|
188
|
+
* });
|
|
189
|
+
*
|
|
190
|
+
* // Stop observing when the container is destroyed
|
|
191
|
+
* watcher.disconnect();
|
|
192
|
+
*/watch(e,t,n){const r=L(e);r.querySelectorAll(t).forEach(n);const l=new MutationObserver(e=>{for(const r of e)r.addedNodes.forEach(e=>{if(e.nodeType!==Node.ELEMENT_NODE)return;const r=e;r.matches(t)&&n(r),r.querySelectorAll(t).forEach(n)})});return l.observe(r,{childList:!0,subtree:!0}),{disconnect:()=>l.disconnect()}}
|
|
193
|
+
/**
|
|
194
|
+
* Layout stabilization helper that measures a list of rotating candidate
|
|
195
|
+
* phrases and locks the target container's inline dimensions to prevent
|
|
196
|
+
* Cumulative Layout Shift (CLS).
|
|
197
|
+
*
|
|
198
|
+
* @param {Element | string} target
|
|
199
|
+
* A DOM element or a CSS selector string.
|
|
200
|
+
* @param {string[]} candidates
|
|
201
|
+
* An array of strings/phrases that will rotate inside this container.
|
|
202
|
+
* @returns {void}
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* TypeFlow.fit('#slogan', ['short', 'very long phrase that wraps']);
|
|
206
|
+
*/fit(e,t=[]){const n=L(e);if(!Array.isArray(t)||!t.length||"undefined"==typeof document)return;const r=document.createElement("span");r.style.cssText="position:absolute;visibility:hidden;opacity:0;pointer-events:none;white-space:nowrap;";const l="undefined"!=typeof window&&window.getComputedStyle?window.getComputedStyle(n):null;l&&(r.style.font=l.font,r.style.fontSize=l.fontSize,r.style.fontWeight=l.fontWeight,r.style.letterSpacing=l.letterSpacing,r.style.textTransform=l.textTransform),document.body.appendChild(r);let o=0;t.forEach(e=>{r.textContent=String(e).replace(/<[^>]*>/g,""),o=Math.max(o,r.getBoundingClientRect().width)}),r.remove(),o>0&&(n.style.display="inline-block",n.style.minWidth=`${Math.ceil(o)}px`)}
|
|
207
|
+
/**
|
|
208
|
+
* Stops any animation currently running on `target`. If no animation is
|
|
209
|
+
* active on the element this method is a no-op.
|
|
210
|
+
*
|
|
211
|
+
* Equivalent to calling `controller.stop()` on the controller returned by
|
|
212
|
+
* the originating `type()`, `erase()`, `sequence()`, or `rotate()` call.
|
|
213
|
+
*
|
|
214
|
+
* @param {Element | string} target - Target element or CSS selector string.
|
|
215
|
+
* @returns {void}
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* TypeFlow.type('#el', 'Long text...');
|
|
219
|
+
* // Stop from another handler without keeping a reference to the controller
|
|
220
|
+
* TypeFlow.stop('#el');
|
|
221
|
+
*/stop(e){var t;const n=L(e);n&&(this.clearCursorInterval(n),null==(t=this.active.get(n))||t.stop())}
|
|
222
|
+
/**
|
|
223
|
+
* Stops all animations currently managed by this engine instance.
|
|
224
|
+
*
|
|
225
|
+
* @returns {void}
|
|
226
|
+
*
|
|
227
|
+
* @example
|
|
228
|
+
* // Clean up all running animations on page unload
|
|
229
|
+
* window.addEventListener('pagehide', () => TypeFlow.stopAll());
|
|
230
|
+
*/stopAll(){this.cursorIntervals.forEach(e=>clearInterval(e)),this.cursorIntervals.clear(),Array.from(this.active.values()).forEach(e=>e.stop())}
|
|
231
|
+
/**
|
|
232
|
+
* Returns `true` when `target` has an active animation managed by this
|
|
233
|
+
* engine instance.
|
|
234
|
+
*
|
|
235
|
+
* @param {Element | string} target - Target element or CSS selector string.
|
|
236
|
+
* @returns {boolean}
|
|
237
|
+
*
|
|
238
|
+
* @example
|
|
239
|
+
* if (!TypeFlow.isTyping('#el')) {
|
|
240
|
+
* TypeFlow.type('#el', 'Now available.');
|
|
241
|
+
* }
|
|
242
|
+
*/isTyping(e){const t=_(e);return!!t&&this.active.has(t)}},j={
|
|
243
|
+
/**
|
|
244
|
+
* Creates a `type` step that types `text` into `target`.
|
|
245
|
+
* @param {Element | string} target
|
|
246
|
+
* @param {string} [text='']
|
|
247
|
+
* @param {Partial<TypeFlowConfig>} [config]
|
|
248
|
+
* @returns {SequenceStep}
|
|
249
|
+
*/
|
|
250
|
+
type:(e,t="",n)=>({kind:"type",target:e,text:t,config:n}),
|
|
251
|
+
/**
|
|
252
|
+
* Creates an `erase` step that erases content from `target`.
|
|
253
|
+
* @param {Element | string} target
|
|
254
|
+
* @param {Partial<TypeFlowConfig>} [config]
|
|
255
|
+
* @returns {SequenceStep}
|
|
256
|
+
*/
|
|
257
|
+
erase:(e,t)=>({kind:"erase",target:e,config:t}),
|
|
258
|
+
/**
|
|
259
|
+
* Creates a `pause` step that waits `duration` milliseconds.
|
|
260
|
+
* @param {number} duration - Wait time in milliseconds.
|
|
261
|
+
* @returns {SequenceStep}
|
|
262
|
+
*/
|
|
263
|
+
pause:e=>({kind:"pause",duration:e}),
|
|
264
|
+
/**
|
|
265
|
+
* Creates a `visible` step that waits until `target` enters the viewport.
|
|
266
|
+
* @param {Element | string} target
|
|
267
|
+
* @param {number} [threshold=0.1] - Intersection threshold (0–1).
|
|
268
|
+
* @returns {SequenceStep}
|
|
269
|
+
*/
|
|
270
|
+
visible:(e,t)=>({kind:"visible",target:e,threshold:t}),
|
|
271
|
+
/**
|
|
272
|
+
* Creates a `call` step that invokes `fn`. May be async.
|
|
273
|
+
* @param {() => void | Promise<void>} fn
|
|
274
|
+
* @returns {SequenceStep}
|
|
275
|
+
*/
|
|
276
|
+
call:e=>({kind:"call",fn:e})};function R(e){return function(t,n={}){const r=e.useRef(null);return e.useEffect(()=>{if(!r.current)return;const e=$.type(r.current,t,n);return()=>e.stop()},[t]),r}}function z(e){return function(t,n){e.useEffect(()=>{const e=$.sequence(t());return()=>e.stop()},n)}}function V(e){return function(t,n={}){const r=e.ref(null);let l=null;return e.watch(t,()=>{r.value&&(l=$.type(r.value,t(),n))},{immediate:!0}),e.onBeforeUnmount(()=>null==l?void 0:l.stop()),r}}function G(e){return function(t){let n=null;return e.onBeforeUnmount(()=>null==n?void 0:n.stop()),()=>{null==n||n.stop(),n=$.sequence(t())}}}function X(){return function(e,t){let n=null;const r=t=>{null==n||n.stop();const r="string"==typeof t?t:t.text,l="object"==typeof t?t.config:{};n=$.type(e,r,l)};return r(t),{update(e){r(e)},destroy(){null==n||n.stop()}}}}function Y(e){return function(t,n={}){let r,l=null;return e.createEffect(()=>{const e="function"==typeof t?t():t;r&&(null==l||l.stop(),l=$.type(r,e,n))}),e.onCleanup(()=>{null==l||l.stop()}),e=>{r=e}}}function K(e){if(!e||"function"!=typeof e.directive)throw new Error("[TypeFlow] createTypeFlowAlpine requires an Alpine instance with directive() support.");e.directive("typeflow",(e,{expression:t},{evaluateLater:n,effect:r,cleanup:l})=>{const o=n(t);let a=null;r(()=>{o(t=>{var n,r;if(null==a||a.stop(),null==t)return;const l="object"==typeof t&&null!==t?null!=(n=t.text)?n:"":String(t),o="object"==typeof t&&null!==t&&null!=(r=t.config)?r:{};a=$.type(e,l,o)})}),"function"==typeof l&&l(()=>null==a?void 0:a.stop())})}function H(e=("undefined"!=typeof customElements?customElements:null)){var t,n,r;if(e&&!e.get("type-flow")){class l extends HTMLElement{constructor(){super(...arguments),f(this,n),f(this,t,null)}static get observedAttributes(){return["text","speed","direction","cursor","type-style","erase-style","scramble-charset","audio"]}connectedCallback(){m(this,n,r).call(this)}disconnectedCallback(){var e;null==(e=p(this,t))||e.stop()}attributeChangedCallback(e,t,l){this.isConnected&&t!==l&&m(this,n,r).call(this)}stop(){var e;null==(e=p(this,t))||e.stop()}}t=new WeakMap,n=new WeakSet,r=function(){var e,n,r,l;null==(e=p(this,t))||e.stop();const o=null!=(r=null!=(n=this.getAttribute("text"))?n:this.textContent)?r:"",a=this.hasAttribute("speed")?Number(this.getAttribute("speed")):40,i=this.getAttribute("direction")||"left",s=null!=(l=this.getAttribute("cursor"))?l:"|",c=this.getAttribute("type-style")||"char",u=this.getAttribute("erase-style")||"end",f=this.getAttribute("scramble-charset")||"matrix",m=this.getAttribute("audio")||void 0;var h,y,g,b;h=this,y=t,g=$.type(this,o,{speed:a,direction:i,cursor:s,typeStyle:c,eraseStyle:u,scrambleCharset:f,audio:m}),d(h,y,"write to private field"),b?b.call(h,g):y.set(h,g)},e.define("type-flow",l)}}"undefined"!=typeof window&&(window.TypeFlow=$,window.TypeFlowSeq=j);export{$ as TypeFlow,K as createTypeFlowAlpine,R as createTypeFlowReact,z as createTypeFlowSequenceReact,G as createTypeFlowSequenceVue,Y as createTypeFlowSolid,X as createTypeFlowSvelte,V as createTypeFlowVue,$ as default,H as defineTypeFlowElement,j as seq};
|
|
277
|
+
//# sourceMappingURL=typeflow.esm.js.map
|