// @ts-check
///
///
///
///
///
///
"use strict";
/**
* @name Celestra
* @version 6.8.0 browser
* @author Ferenc Czigler
* @see https://github.com/Serrin/Celestra/
* @license MIT https://opensource.org/licenses/MIT
*/
const VERSION = "Celestra v6.8.0 browser";
/** TS browser and NodeJS common types **/
/**
* @description False like values.
* @see https://developer.mozilla.org/en-US/docs/Glossary/Falsy
* @note Missing values: NaN and document.all
* @private
*/
type Falsy = null | undefined | false | 0 | -0 | 0n | "";
/** * @description Truthy like values. * @private */
/* @ts-ignore */
type Truthy = Exclude;
/** * @description Object key type. Built-in type. * @private */
/* type PropertyKey = string | number | symbol; */
/** * @description Object with string, number or symbol keys. * @private */
type ObjectLike = Record;
/** * @description String-like object. * @private */
type BooleanLike = boolean | Boolean;
/** * @description Number-like object. * @private */
type NumberLike = number | Number;
/** * @description BigInt-like object. * @private */
type BigIntLike = bigint | BigInt;
/** * @description Number-like object. * @private */
type Numeric = number | bigint;
/** * @description Number and BigInt-like object. * @private */
type NumericLike = NumberLike | BigIntLike;
/** * @description String-like object. * @private */
type StringLike = string | String;
/** * @description String-like object. * @private */
type SymbolLike = symbol | Symbol;
/** * @description Any iterable or iterator. * @private */
type IterableLike = Iterable | Iterator | IterableIterator;
/** * @description Any iterable, iterator or array-like objects. * @private */
type IterableLikeAndArrayLike =
Iterable | Iterator | IterableIterator | ArrayLike;
/** * @description Iterable and Iterator and Generator types. * @private */
type GeneratorLike =
Iterable | Iterator | Generator;
/** * @description Type for undefined and null values. * @private */
type Nullish = undefined | null;
/** * @description Not null or undefined. Built-in type. * @private */
/* type NonNullable = number | boolean | string | symbol | object | Function; */
/** * @description Not null or undefined or object or function. * @private */
type NonNullablePrimitive = boolean | number | bigint | string | symbol;
/** * @description NonNullablePrimitiveLike object. * @private */
type NonNullablePrimitiveLike =
BooleanLike | NumericLike | StringLike | SymbolLike;
/** * @description Not object or function. * @private */
type Primitive = Nullish | NonNullablePrimitive;
/** * @description Primitive-like object. * @private */
/* @ts-ignore */
type PrimitiveLike = Nullish | NonNullablePrimitiveLike;
/** * @description Object or function. * @private */
/* @ts-ignore */
type NonPrimitive = object | Function;
/** * @description Generic comparable types. * @private */
type Comparable = number | bigint | string | boolean | Date;
/** * @description AsyncFunction. * @private */
type AsyncFunction = (...args: ReadonlyArray) => Promise;
/** * @description ArrowFunction. * @private */
type ArrowFunction =
(this: void, ...args: Args) => R;
/** * @description TypedArray types. * @private */
type TypedArray = Exclude;
/** TS browser only types **/
/** * @description ClearCookiesOptions object type. * @private */
type ClearCookiesOptions = {
path?: string | undefined;
domain?: string | undefined;
secure?: boolean | undefined;
SameSite?: string | undefined;
HttpOnly?: boolean | undefined;
};
/** polyfills **/
/* globalThis; */
(function (global) {
if (!global.globalThis) {
if (Object.defineProperty) {
Object.defineProperty(global, "globalThis", {
configurable: true, enumerable: false, value: global, writable: true
});
} else {
global.globalThis = global;
}
}
})(typeof this === "object" ? this : Function("return this")());
/* Math.sumPrecise(); */
if (!("sumPrecise" in Math)) {
(Math as ObjectLike).sumPrecise = function sumPrecise ([...array]): number {
if (array.length === 0) { return -0; }
/* iterator with items */
if (array.every((value: unknown): boolean => typeof value === "number")) {
/* return NaN + Infinity + -Infinity */
let inf = array.indexOf(Infinity) >- 1;
let negInf = array.indexOf(-Infinity) > -1;
if (array.some((value: unknown): boolean => value !== value)
|| (inf && negInf)) { return NaN; }
if (inf) { return Infinity; }
if (negInf) { return -Infinity; }
/* sum hi */
let hi = array.filter((value: unknown): boolean =>
(value === 1e20 || value === -1e20))
.reduce((acc, value): number => acc + value, 0);
/* sum lo - Kahan sum */
let lo: number = 0.0;
let c: number = 0.0;
for (let item of array.filter((value: unknown): boolean =>
(value !== 1e20 && value !== -1e20))) {
let y = item - c; let t = lo + y; c = (t - lo) - y; lo = t;
}
/* return sum values */
if (lo === 0 && hi !== 0) { return hi; }
if (lo > 0 && hi > 0) { return hi; }
if (lo < 0 && hi < 0) { return hi; }
if (lo > 0 && hi < 0) { return lo + hi; }
if (lo < 0 && hi > 0) { return lo + hi; }
if (lo === 0 && hi === 0) { return lo; }
if (lo !== 0 && hi === 0) { return lo; }
}
/* not number items -> TypeError */
throw new TypeError("values passed to Math.sumPrecise must be numbers");
};
}
/* Error.isError(); */
if (!("isError" in Error)) {
(Error as ObjectLike).isError = function isError (value: unknown) {
let className =
Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
return (className === "error" || className === "domexception");
};
}
/* crypto.randomUUID(); */
if ("crypto" in globalThis && !("randomUUID" in globalThis.crypto)) {
(globalThis.crypto as ObjectLike).randomUUID = function randomUUID () {
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g,
(c: any): any =>
(c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> c/4)))
.toString(16)
);
};
}
/* globalThis.GeneratorFunction; */
if (!(globalThis as ObjectLike).GeneratorFunction) {
(globalThis as ObjectLike).GeneratorFunction =
Object.getPrototypeOf(function*(){}).constructor;
}
/* globalThis.AsyncFunction; */
if (!(globalThis as ObjectLike).AsyncFunction) {
(globalThis as ObjectLike).AsyncFunction =
Object.getPrototypeOf(async function(){}).constructor;
}
/* globalThis.AsyncGeneratorFunction; */
if (!(globalThis as ObjectLike).AsyncGeneratorFunction) {
(globalThis as ObjectLike).AsyncGeneratorFunction =
Object.getPrototypeOf(async function* () {}).constructor;
}
/** Core API **/
/* Alphabet constans */
const BASE16 = "0123456789ABCDEF";
const BASE32 = "234567ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const BASE36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const BASE58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
const BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
const WORDSAFEALPHABET = "23456789CFGHJMPQRVWXcfghjmpqvwx"; /* 31 characters */
/**
* @description Ensures that `condition` is truthy. Throws an `Error` if falsy.
* @param {unknown} condition The value to check.
* @param {unknown} [message] - Optional message or Error to throw.
* @throws {Error} If assertion is failed.
*/
function assert (condition: unknown, message?: unknown): asserts condition {
if (!condition) {
if (Error.isError(message)) { throw message; }
let errorMessage =
`[assert] Assertion failed: ${condition} should be truly${message ? ` - ${message}` : ""}`;
throw new Error(errorMessage, {cause: errorMessage});
}
}
/**
* @description SameValueZero equality (like `Object.is`, but +0 === -0).
* @param {unknown} value1
* @param {unknown} value2
* @returns {boolean}
*/
const eq = (value1: unknown, value2: unknown): boolean =>
value1 === value2 || (value1 !== value1 && value2 !== value2);
/**
* @description Greater than.
* @param {any} value1
* @param {any} value2
* @returns {boolean}
*/
const gt = (value1: Comparable, value2: Comparable): boolean =>
typeOf(value1) === typeOf(value2) && value1 > value2;
/**
* @description Greater than or equal (SameValueZero).
* @param {any} value1
* @param {any} value2
* @returns {boolean}
*/
const gte = (value1: Comparable, value2: Comparable): boolean =>
gt(value1, value2) || eq(value1, value2);
/**
* @description Less than.
* @param {any} value1
* @param {any} value2
* @returns {boolean}
*/
const lt = (value1: Comparable, value2: Comparable): boolean =>
typeOf(value1) === typeOf(value2) && value1 < value2;
/**
* @description Less than or equal (SameValueZero).
* @param {any} value1
* @param {any} value2
* @returns {boolean}
*/
const lte = (value1: Comparable, value2: Comparable): boolean =>
lt(value1, value2) || eq(value1, value2);
/**
* @description Calls `callback` with the given `value` and then returns `value`.
* @param {Function} callback
* @returns {Function}
*/
const tap = (callback: Function): any =>
function (value: unknown): any { callback(value); return value; };
/**
* @description Creates a function that is restricted to invoking `callback` once.
* @param {Function} callback
* @returns {Function}
*/
function once (callback: Function): Function {
let called: boolean = false;
let result: any;
return function (...args: any[]): any {
if (!called) {
called = true;
result = callback(...args);
}
return result;
};
}
/**
* @description Transforms a function of N arguments into N functions of one argument.
* @param {Function} callback
* @returns {Function}
*/
function curry (callback: Function): Function {
const curried = (...args: any[]): any => args.length >= callback.length
? callback(...args)
: (...rest: any[]): any => curried(...args, ...rest);
return curried;
}
/**
* @description Creates a function that is the composition of the provided functions.
* @param {Function} functions
* @returns {Function}
*/
const pipe = (...functions: Function[]): Function =>
(first: any): any =>
functions.reduce((value: unknown, callback: Function): any =>
callback(value), first);
/**
* @description Creates a function that is the composition of the provided functions.
* @param {Function} functions
* @returns {Function}
*/
const compose = (...functions: Function[]): Function =>
(first: any): any => functions.reduceRight(
(value, callback): any => callback(value),
first
);
/**
* @description Creates a new object composed of the picked `object` properties.
* @param {object} obj
* @param {string[]} keys
*/
const pick = (obj: ObjectLike, keys: string[]): ObjectLike =>
keys.reduce(function (acc: ObjectLike, key: string) {
if (key in obj) { acc[key] = obj[key]; }
return acc;
}, {});
/**
* @description Creates a new object composed of the `object` properties except for those omitted.
* @param {object} obj
* @param {string[]} keys
* @returns {object}
*/
const omit = (obj: ObjectLike, keys: string[]): ObjectLike =>
Object.keys(obj).reduce(function (acc: ObjectLike, key: string) {
if (!keys.includes(key)) { acc[key] = obj[key]; }
return acc;
}, {});
/**
* @description Returns a new object with the specified key-value pair added or updated.
* @param {object} obj
* @param {string} key
* @param {object} value
*/
const assoc = (obj: ObjectLike, key: string, value: unknown): ObjectLike =>
({...obj, [key]: value});
/**
* @description An asynchronous no-operation function that returns a resolved Promise.
* @returns {Promise}
*/
async function asyncNoop (): Promise {
return new Promise(function (resolve: Function) { resolve(); });
}
/**
* @description Asynchronous function that returns a resolved Promise with `true`.
* @returns {Promise}
*/
async function asyncT (): Promise { return true; }
/**
* @description Asynchronous function that returns a resolved Promise with `false`.
* @returns {Promise}
*/
async function asyncF (): Promise { return false; }
/**
* @description Creates an asynchronous function that returns a resolved Promise with the specified value.
* @param {unknown} value
* @returns {Function}
*/
function asyncConstant (value: T): AsyncFunction {
return async function () { return value; };
}
/**
* @description Asynchronous identity function that returns a resolved Promise with the given value.
* @param {unknown} value
* @returns {Promise}
*/
async function asyncIdentity (value: unknown): Promise { return value; }
/**
* @description Generates a random UUID version 7 or UUID version 7 with version 4 ID.
* @param {boolean} [v4=false] - If true, generates a UUID version 4; otherwise, generates version 7.
* @returns {string} A randomly generated UUID string.
*/
function randomUUIDv7(v4: boolean = false): string {
let version = v4 ? "4" : "7";
/* 12 hex timestamp digits + 1 version char = 13, but UUID positions 0-7, 9-12 = 12 slots */
/* So keep ts as 12 chars and write version explicitly into position 14 */
let timestamp = Date.now().toString(16).padStart(12, "0");
let uuid: string[] = Array.from(
"10000000-1000-4000-8000-100000000000"
.replace(/[018]/g, (c: string): string => {
let n = parseInt(c, 10);
return (n ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (n / 4))))
.toString(16);
}
)
);
/* Write 12 timestamp chars into positions 0-7, 9-12 (skipping dash at 8) */
let timestampIndex = 0;
for (let pos = 0; timestampIndex < 12; pos++) {
if (pos === 8) continue; // skip dash
uuid[pos] = timestamp[timestampIndex++];
}
/* Write version into position 14 (after second dash) */
uuid[14] = version;
return uuid.join("");
}
/**
* @description Returns a Promise that resolves after a specified delay in milliseconds.
* @param {number} milisec - The delay duration in milliseconds.
* @returns {Promise} A Promise that resolves after the specified delay.
*/
const delay = (milisec: number): Promise =>
new Promise(resolve => setTimeout(resolve, milisec));
/**
* @description Generates a random boolean value.
* @returns {boolean} A randomly generated boolean value.
*/
const randomBoolean = (): boolean => !Math.round(Math.random());
/**
* @description Deep assign of an object (Object, Array, etc.)
* @returns {any}
*/
function deepAssign (target: T, source: U): T & U;
function deepAssign (target: T, s1: U, s2: V): T & U & V;
function deepAssign (target: T, ...sources: any[]): T;
function deepAssign (target: T, ...sources: any[]): T;
function deepAssign (target: object, ...sources: any[]): object;
function deepAssign (target: any, ...sources: any): any {
function _deepClone(value: any) {
try { return structuredClone(value); } catch { return value; }
}
if (!sources.length) { return target == null ? target : _deepClone(target); }
for (let source of sources) { Object.assign(target, _deepClone(source)); }
return target;
}
/**
* @description Returns the number of own properties (including symbols) of an object.
* @param {object} object
* @returns {number}
*/
const sizeIn = (object: object): number =>
Object.getOwnPropertyNames(object).length
+ Object.getOwnPropertySymbols(object).length;
/**
* @description Creates a function that invokes `callback` with its `this` binding removed.
* @param {Function} callback
* @returns {Function}
*/
const unBind = (callback: Function): Function =>
Function.prototype.call.bind(callback);
/**
* @description Creates a function that invokes `callback` with its `this` binding set to the provided context.
* @param {Function} callback
* @param {Function} context
*/
const bind = Function.prototype.call.bind(Function.prototype.bind);
/**
* @description Returns a function that always returns the same value.
* @param {unknown} value
* @returns {unknown}
*/
const constant = (value: T): (() => T) => () => value;
/**
* @description Returns value unchanged.
* @param {unknown} value
* @returns {unknown}
*/
const identity = (value: T): T => value;
/**
* @description A function that does nothing.
* @returns {void}
*/
function noop (): void {}
/**
* @description Always returns true.
* @returns {true}
*/
const T = (): true => true;
/**
* @description Always returns false.
* @returns {false}
*/
const F = (): false => false;
/**
* @description Generates a random string ID of specified size using the provided alphabet.
* @param {number} [size=21] - The length of the generated ID.
* @param {string} [alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-"] - The set of characters to use for generating the ID.
*/
function nanoid(
size: number = 21,
alphabet: string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-"
): string {
if (!Number.isSafeInteger(size) || size < 1 || size > 255) {
throw new RangeError(
"[nanoid] Size should be an integer between 1 and 255."
);
}
if (typeof alphabet !== "string"
|| !alphabet.length
|| alphabet.length > 255) {
throw new TypeError(
"[nanoid] Alphabet should be a non-empty string with maximum length 255."
);
}
let mask = (2 << (31 - Math.clz32(alphabet.length - 1))) - 1;
let result = "";
let index = size;
while (index--) {
let pos: number;
do {
pos = crypto.getRandomValues(new Uint8Array(1))[0] & mask;
} while (pos >= alphabet.length);
result += alphabet[pos];
}
return result;
}
/**
* @description Generates a timestamp-based string ID of specified size using the provided alphabet.
* @param {number} [size=21] - The total length of the generated ID, including the timestamp.
* @param {string} [alphabet="23456789CFGHJMPQRVWXcfghjmpqvwx"] - The set of characters to use for generating the ID.
* @returns {string} The generated timestamp-based ID.
*/
function timestampID (
size: number = 21,
alphabet: string = "23456789CFGHJMPQRVWXcfghjmpqvwx"
): string {
if (!Number.isSafeInteger(size)
|| size < 11
|| alphabet.length > 255) {
throw new RangeError(
"[timestampID] Size should be an integer in between 11 and 255."
);
}
if (typeof alphabet !== "string"
|| !alphabet.length
|| alphabet.length > 255) {
throw new TypeError(
"[timestampID] Alphabet should be a non-empty string with maximum length 255."
);
}
return Date.now().toString(36).padStart(10, "0")
+ (size > 11 ? "-" + nanoid(size - 11, alphabet) : "-")
}
/** String API **/
/**
* @description Encodes a string to Base64 format.
* @param {any} str - The string to encode.
* @returns {string} The Base64 encoded string.
*/
function b64Encode (str: any): string {
return btoa(encodeURIComponent(String(str)).replace(/%([0-9A-F]{2})/g,
function toSolidBytes (_match, p1): string {
return String.fromCharCode(parseInt(p1, 16));
}
));
}
/**
* @description Decodes a Base64 encoded string.
* @param {string} str - The Base64 encoded string to decode.
* @returns {string} The decoded string.
*/
function b64Decode (str: any): string {
return decodeURIComponent(atob(String(str)).split("").map(function (c) {
return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
}).join(""));
}
/**
* @description Counts the occurrences of a substring in a string.
* @param {unknown} str - The string to search in.
* @param {unknown} substr - The substring to search for.
* @returns {number} The number of occurrences of the substring.
*/
function strCount (str: unknown, substr: unknown): number {
let count = (String(str)?.split(String(substr)) ?? []).length - 1;
return count < 0 ? 0 : count;
}
/**
* @description Truncates a string to a specified length, optionally adding an omission string.
* @param {string} str - The string to truncate.
* @param {number} newLength - The maximum length of the truncated string.
* @param {string} [omission=""] - The string to append to the truncated string.
* @returns {string} The truncated string.
*/
function strTruncate (
str: any,
newLength: number,
omission: string = ""): string {
str = String(str);
omission = String(omission);
let strUC = Array.from(str);
if (newLength >= strUC.length) { return str; }
return strUC.slice(0, newLength - Array.from(omission).length).join("")
+ omission;
}
/**
* @description Converts the first character of each word in a string to uppercase and the rest to lowercase.
* @param {any} str - The string to convert.
* @returns {string} The converted string.
*/
const strPropercase = (str: any): string =>
String(str).trim().split(" ").map(function (value: string) {
let chars = Array.from(value).map( (c: string): string => c.toLowerCase() );
if (chars.length) { chars[0] = chars[0].toUpperCase(); }
return chars.join("");
}).join(" ");
/**
* @description Converts the first character of each word in a string to uppercase and the rest to lowercase.
* @param {any} str - The string to convert.
* @returns {string} The converted string.
*/
const strTitlecase = (str: any): string =>
String(str).trim().split(" ").map(function (value: string) {
let chars = Array.from(value).map( (c: string): string => c.toLowerCase() );
if (chars.length) { chars[0] = chars[0].toUpperCase(); }
return chars.join("");
}).join(" ");
/**
* @description Capitalizes the first character of a string and converts the rest to lowercase.
* @param {any} str - The string to capitalize.
* @returns {string} The capitalized string.
*/
function strCapitalize (str: any): string {
let chars = [...String(str).trim().toLowerCase()];
if (chars.length) { chars[0] = chars[0].toUpperCase(); }
return chars.join("");
}
/**
* @description Converts the first character of a string to uppercase.
* @param {any} str - The string to modify.
* @returns {string} The modified string.
*/
function strUpFirst (str: any): string {
let chars = [...String(str).trim()];
if (chars.length) { chars[0] = chars[0].toUpperCase(); }
return chars.join("");
}
/**
* @description Converts the first character of a string to lowercase.
* @param {any} str - The string to modify.
* @returns {string} The modified string.
*/
function strDownFirst (str: any): string {
let chars = [...String(str).trim()];
if (chars.length) { chars[0] = chars[0].toLowerCase(); }
return chars.join("");
}
/**
* @description Reverses the characters in a string.
* @param {any} str - The string to reverse.
* @returns {string} The reversed string.
*/
const strReverse = (str: unknown): string =>
Array.from(String(str)).reverse().join("");
/**
* @description Returns an array of Unicode code points for each character in a string.
* @param {any} str - The string to process.
* @returns {number[]} An array of Unicode code points.
*/
const strCodePoints = (str: any): any[] =>
Array.from(String(str), (value: string): number | undefined =>
value.codePointAt(0));
/**
* @description Creates a string from an array or iterable of Unicode code points.
* @param {Iterable} iterator - An array or iterable of Unicode code points.
* @returns {string} The constructed string.
*/
const strFromCodePoints = ([...array]: Iterable): string =>
String.fromCodePoint(...array);
/**
* @description Gets or sets a unicode character at a specified index in a string.
* @param {string} str - The string to modify.
* @param {number} index - The index of the character to get or set.
*/
function strAt (str: string, index: number, newChar?: string): string {
let chars: string[] = Array.from(String(str));
if (newChar == null) { return chars.at(index) || ""; }
index = index < 0 ? chars.length + index : index;
if (index > chars.length) { return chars.join(""); }
chars[index] = newChar;
return chars.join("");
}
/**
* @description Splices a string by removing a specified number of characters at a given index and optionally adding new characters.
* @param {string} str - The string to splice.
* @param {number} index - The index at which to start splicing.
* @param {number} count - The number of characters to remove.
* @param {string} [add] - The string to add at the splice index.
* @returns {string} The spliced string.
*/
const strSplice = (
str: string,
index: number,
count: number,
...add: any[]): string =>
Array.from(str).toSpliced(index, count, add.join("")).join("");
/**
* @description Removes HTML tags from a string.
* @param {any} str - The string from which to remove HTML tags.
* @returns {string} The string without HTML tags.
*/
const strHTMLRemoveTags = (str: any): string =>
String(str).trim().replace(/<[^>]*>/g, " ").replace(/\s{2,}/g, " ").trim();
/**
* @description Escapes special HTML characters in a string.
* @param {any} str - The string to escape.
* @returns {string} The escaped string.
*/
const strHTMLEscape = (str: any): string => String(str).trim()
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
/**
* @description Unescapes special HTML characters in a string.
* @param {any} str - The string to unescape.
* @returns {string} The unescaped string.
*/
const strHTMLUnEscape = (str: string): string => String(str).trim()
.replace(/&/g, "&").replace(/&/g, "&")
.replace(/</g, "<").replace(/</g, "<")
.replace(/>/g, ">").replace(/>/g, ">")
.replace(/"/g, '"').replace(/"/g, '"')
.replace(/'/g, "'").replace(/'/g, "'");
/** DOM API **/
/**
* @description Selects all elements matching the specified CSS selector within the given context.
* @param {string} str - The CSS selector to match.
* @param {Document | HTMLElement} [context=document] - The context in which to search for elements.
* @returns {any[]} An array of matching elements.
*/
const qsa = (str: string, context: Document | HTMLElement = document): any[] =>
Array.from(context.querySelectorAll(str));
/**
* @description Selects the first element matching the specified CSS selector within the given context.
* @param {string} str - The CSS selector to match.
* @param {Document | HTMLElement} [context=document] - The context in which to search for the element.
* @returns {HTMLElement | null} The first matching element, or null if no match is found.
*/
const qs = (
str: string,
context: Document | HTMLElement = document): HTMLElement | null =>
context.querySelector(str);
/**
* @description Executes a callback function when the DOM is fully loaded.
* @param {Function} callback - The callback function to execute.
* @returns {void}
*/
function domReady (callback: Function): void {
if (document.readyState !== "loading") {
callback();
} else {
document.addEventListener(
"DOMContentLoaded",
function (_event) { callback(); }
);
}
}
/* domCreate(type: string[, properties: object[, innerHTML: string]]):
element */
/* domCreate(element descriptive object): HTMLelement */
/**
* @description Creates a new DOM element with specified properties and inner HTML.
* @param {string | object} elementType - The type of element to create or an object describing the element.
* @param {object} [properties] - An object containing properties to set on the element.
* @param {string} [innerHTML] - The inner HTML content to set for the element.
* @returns {HTMLElement} The newly created DOM element.
*/
function domCreate (
elementType: string | ObjectLike,
properties: object,
innerHTML: string): HTMLElement {
if (arguments.length === 1 && typeof elementType === "object") {
let obj = elementType;
elementType = obj.elementType;
properties = {};
for (const [key, value] of Object.entries(obj)) {
if (key !== "elementType") {(globalThis as ObjectLike)[key] = value; }
}
}
let element: HTMLElement = document.createElement(elementType as string);
if (properties) {
for (let [key, value] of Object.entries(properties)) {
if (key !== "style" || typeof value === "string") {
(element as ObjectLike)[key] = value;
} else {
Object.assign(element.style, value);
}
}
}
if (innerHTML) { element.innerHTML = innerHTML; }
return element;
}
/**
* @description Converts an HTML string to a DOM element.
* @param {string} str - The HTML string to convert.
* @returns {Element | null} The resulting DOM element, or null if conversion fails.
*/
function domToElement (str: string): Element | null {
let element: HTMLElement = document.createElement("div");
element.innerHTML = str;
return element.firstElementChild;
}
/**
* @description Gets the computed CSS property value of a DOM element.
* @param {HTMLElement} element - The DOM element to retrieve the CSS property from.
* @param {string | number} [property] - The CSS property name to retrieve. If omitted, returns the full CSSStyleDeclaration.
* @returns {string | CSSStyleDeclaration} The computed CSS property value or the full CSSStyleDeclaration.
*/
const domGetCSS = (
element: HTMLElement,
property: string | number): string | CSSStyleDeclaration =>
(property
? (globalThis.getComputedStyle(element, null) as ObjectLike)[property]
: globalThis.getComputedStyle(element, null)
);
/* domSetCSS(element, property: string, value: string): undefined */
/* domSetCSS(element, properties: object): undefined */
/**
* @description Sets CSS property values on a DOM element.
* @param {HTMLElement} element - The DOM element to set the CSS properties on.
* @param {string | object} property - The CSS property name to set or an object containing multiple properties and their values.
* @param {string} [value] - The value to set for the specified CSS property (if `property` is a string).
* @returns {void}
*/
function domSetCSS (
element: HTMLElement,
property: string | object,
value: string): void {
if (typeof property === "string") {
/* @ts-ignore */
element.style[property] = value;
} else if (typeof property === "object") {
Object.keys(property).forEach((key: string): void =>
/* @ts-ignore */
element.style[key] = property[key]
);
}
}
/**
* @description Fades in a DOM element over a specified duration.
* @param {HTMLElement} element - The DOM element to fade in.
* @param {number} [duration=500] - The duration of the fade-in effect in milliseconds.
* @param {string} [display=""] - The CSS display value to set when the element is shown.
* @returns {void}
*/
function domFadeIn (
element: HTMLElement,
duration: number,
display: string): void {
let style = element.style;
let step: number = 25/(duration || 500);
style.opacity = (style.opacity ?? 0);
style.display = (display || "");
(function fade () {
/* @ts-ignore */
(style.opacity = parseFloat(style.opacity) + step) > 1
/* @ts-ignore */
? style.opacity = 1
: setTimeout(fade,25);
})();
}
/**
* @description Fades out a DOM element over a specified duration.
* @param {HTMLElement} element - The DOM element to fade out.
* @param {number} [duration=500] - The duration of the fade-out effect in milliseconds.
* @returns {void}
*/
function domFadeOut (
element: HTMLElement, duration: number): void {
let style = element.style;
let step: number = 25/(duration || 500);
/* @ts-ignore */
style.opacity = (style.opacity || 1);
(function fade () {
/* @ts-ignore */
(style.opacity -= step) < 0 ? style.display = "none" : setTimeout(fade, 25);
})();
}
/**
* @description Toggles the fade in/out effect of a DOM element over a specified duration.
* @param {HTMLElement} element - The DOM element to toggle fade effect on.
* @param {number} [duration=500] - The duration of the fade effect in milliseconds.
* @param {string} [display=""] - The CSS display value to set when the element is shown.
* @returns {void}
*/
function domFadeToggle (
element: HTMLElement, duration: number, display: string = ""): void {
if (getComputedStyle(element, null).display === "none") {
domFadeIn(element, duration, display);
} else {
domFadeOut(element, duration);
}
}
/**
* @description Hides a DOM element by setting its display style to "none".
* @param {element} element - The DOM element to hide.
* @returns {void}
*/
const domHide = (element: HTMLElement): any => element.style.display = "none";
/**
* @description Shows a DOM element by setting its display style.
* @param {HTMLElement} element - The DOM element to show.
* @param {string} [display=""] - The CSS display value to set when showing the element.
* @returns {void}
*/
const domShow = (element: HTMLElement, display: string = ""): any =>
element.style.display = display;
/**
* @description Toggles the visibility of a DOM element by changing its display style.
* @param {HTMLElement} element
* @param {string} [display] - The CSS display value to set when showing the element.
* @returns {void}
*/
function domToggle (element: HTMLElement, display: string = ""): void {
if (globalThis.getComputedStyle(element, null).display === "none") {
element.style.display = display;
} else {
element.style.display = "none";
}
}
/**
* @description Checks if a DOM element is hidden (i.e., has display style set to "none").
* @param {HTMLElement} element - The DOM element to check.
* @returns {boolean} True if the element is hidden, false otherwise.
*/
const domIsHidden = (element: HTMLElement): boolean =>
globalThis.getComputedStyle(element, null).display === "none";
/**
* @description Retrieves all sibling elements of a given DOM element.
* @param {Element} element - The DOM element whose siblings are to be retrieved.
* @returns {Element[]} An array of sibling elements.
*/
function domSiblings (element: Element): Element[] {
let parent = element.parentNode;
if (!parent) { return []; }
return Array.prototype.filter.call(parent.children,
(item: HTMLElement): boolean => (item !== element)
);
}
/**
* @description Retrieves all sibling elements before a given DOM element.
* @param {Element} element - The DOM element whose previous siblings are to be retrieved.
* @returns {Element[]} An array of previous sibling elements.
*/
function domSiblingsPrev (element: Element): Element[] {
let parent = element.parentNode;
if (!parent) { return []; }
let siblings = Array.from((parent as Element).children);
return siblings.slice(0, siblings.indexOf(element));
}
/**
* @description Retrieves all sibling elements to the left of a given DOM element.
* @param {Element} element - The DOM element whose left siblings are to be retrieved.
* @returns {Element[]} An array of left sibling elements.
*/
function domSiblingsLeft (element: Element): Element[] {
let parent = element.parentNode;
if (!parent) { return []; }
let siblings = Array.from((parent as Element).children);
return siblings.slice(0, siblings.indexOf(element));
}
/**
* @description Retrieves all sibling elements after a given DOM element.
* @param {Element} element - The DOM element whose next siblings are to be retrieved.
* @returns {Element[]} An array of next sibling elements.
*/
function domSiblingsNext (element: Element): Element[] {
let parent = element.parentNode;
if (!parent) { return []; }
let siblings = Array.from((parent as Element).children);
return siblings.slice(siblings.indexOf(element) + 1, parent.children.length);
}
/**
* @description Retrieves all sibling elements to the right of a given DOM element.
* @param {Element} element - The DOM element whose right siblings are to be retrieved.
* @returns {Element[]} An array of right sibling elements.
*/
function domSiblingsRight (element: Element): Element[] {
let parent = element.parentNode;
if (!parent) { return []; }
let siblings = Array.from((parent as Element).children);
return siblings.slice(siblings.indexOf(element) + 1, parent.children.length);
}
/**
* @description Dynamically imports one or more JavaScript files into the document.
* @param {string[]} scripts - The URLs of the JavaScript files to import.
* @returns {void}
*/
function importScript (...scripts: string[]): void {
for (let item of scripts) {
let element: HTMLScriptElement = document.createElement("script");
element.type = "text\/javascript";
element.src = item;
element.onerror = function (error: Event | string): void {
let source = "";
if (typeOf(error) === "object") {
source = ((error as ObjectLike).target as ObjectLike).src || "";
}
throw new URIError(
`[importScript] Loading failed${source ? ` for the script with source ${source}` : ""}`
);
};
(document.head||document.getElementsByTagName("head")[0])
.appendChild(element);
}
}
/**
* @description Dynamically imports one or more CSS stylesheets into the document.
* @param {string[]} styles - The URLs of the CSS stylesheets to import.
* @returns {void}
*/
function importStyle (...styles: string[]): void {
for (let item of styles) {
let element: HTMLLinkElement = document.createElement("link");
element.rel = "stylesheet";
element.type = "text\/css";
element.href = item;
element.onerror = function (error) {
throw new URIError(
/* @ts-ignore */
`[importStyle] Loading failed for the style with source ${error.target.href}`
);
};
(document.head||document.getElementsByTagName("head")[0])
.appendChild(element);
}
}
/**
* @description Converts a form element into an array of key-value pairs.
* @param {HTMLFormElement} form - The form element to convert.
* @returns {object[]} An array of objects representing the form data.
*/
function form2array (form: HTMLFormElement): object[] {
let field: any;
let result = Array