Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ✨ add types as JSDoc #15

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
47 changes: 47 additions & 0 deletions typical.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* Asynchronously types a given node with a series of arguments.
* @param {HTMLElement} node - The HTML element to type into.
* @param {...(string|number|Function|Promise)} args - A list of arguments. A string is typed, a number is a delay in milliseconds, a function is called with the node as first argument, and a promise is awaited
*/
export async function type(node, ...args) {
for (const arg of args) {
switch (typeof arg) {
Expand All @@ -16,40 +21,82 @@ export async function type(node, ...args) {
}
}

/**
* Asynchronously edits the text content of a node to match the provided text.
* @param {HTMLElement} node - The HTML element to edit.
* @param {string} text - The text to set as the new content of the node.
* @returns {Promise<void>} - A promise that resolves when the editing is done.
*/
async function edit(node, text) {
const overlap = getOverlap(node.textContent, text);
await perform(node, [...deleter(node.textContent, overlap), ...writer(text, overlap)]);
}

/**
* Asynchronously waits for a specified number of milliseconds.
* @param {number} ms - The number of milliseconds to wait.
* @returns {Promise<void>} - A promise that resolves when the waiting is done.
*/
async function wait(ms) {
await new Promise(resolve => setTimeout(resolve, ms));
}

/**
* Performs a sequence of text editing operations on a node with a specified speed.
* @param {HTMLElement} node - The HTML element to edit.
* @param {string[]} edits - An array of text edits to perform.
* @param {number} speed - The typing speed in milliseconds.
*/
async function perform(node, edits, speed = 60) {
for (const op of editor(edits)) {
op(node);
await wait(speed + speed * (Math.random() - 0.5));
}
}

/**
* Generates an iterator for text editing operations.
* @param {string[]} edits - An array of text edits to perform.
* @returns {Generator<function(HTMLElement), void, void>} - The text editing operations.
*/
export function* editor(edits) {
for (const edit of edits) {
yield (node) => requestAnimationFrame(() => node.textContent = edit);
}
}

/**
* Generates an iterator for writing text progressively.
* @param {string[]} text - The text to write progressively.
* @param {number} startIndex - The starting index for writing.
* @param {number} endIndex - The ending index for writing.
* @returns {Generator<string, void, void>} - The text written progressively.
*/
export function* writer([...text], startIndex = 0, endIndex = text.length) {
while (startIndex < endIndex) {
yield text.slice(0, ++startIndex).join('');
}
}

/**
* Generates an iterator for deleting text progressively.
* @param {string[]} text - The text to delete progressively.
* @param {number} startIndex - The starting index for deleting.
* @param {number} endIndex - The ending index for deleting.
* @returns {Generator<string, void, void>} - The text deleted progressively.
*/
export function* deleter([...text], startIndex = 0, endIndex = text.length) {
while (endIndex > startIndex) {
yield text.slice(0, --endIndex).join('');
}
}

/**
* Gets the index of the first character where two strings differ.
* @param {string} start - The starting string.
* @param {string[]} end - The ending string as an array of characters.
* @returns {number} - The index of the first differing character.
*/
export function getOverlap(start, [...end]) {
return [...start, NaN].findIndex((char, i) => end[i] !== char);
}