ziko
Version:
A versatile JavaScript library offering a rich set of Hyperscript Based UI components, advanced mathematical utilities, interactivity ,animations, client side routing and more ...
5,614 lines • 176 kB
JavaScript
/*
Project: ziko.js
Author: Zakaria Elalaoui
Date : Thu Dec 25 2025 01:19:21 GMT+0100 (UTC+01:00)
Git-Repo : https://github.com/zakarialaoui10/ziko.js
Git-Wiki : https://github.com/zakarialaoui10/ziko.js/wiki
Released under MIT License
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Ziko = {}));
})(this, (function (exports) { 'use strict';
const { PI: PI$1, E } = Math;
const EPSILON=Number.EPSILON;
const is_primitive = value => typeof value !== 'object' && typeof value !== 'function' || value === null;
const mapfun=(fun,...X)=>{
const Y=X.map(x=>{
if(is_primitive(x) || x?.__mapfun__) return fun(x)
if(x instanceof Array) return x.map(n=>mapfun(fun,n));
if(ArrayBuffer.isView(x)) return x.map(n=>fun(n));
if(x instanceof Set) return new Set(mapfun(fun,...[...x]));
if(x instanceof Map) return new Map([...x].map(n=>[n[0],mapfun(fun,n[1])]));
if(x.isMatrix?.()) return new x.constructor(x.rows, x.cols, mapfun(x.arr.flat(1)))
else if(x instanceof Object){
return Object.fromEntries(
Object.entries(x).map(
n=>n=[n[0],mapfun(fun,n[1])]
)
)
}
});
return Y.length==1? Y[0]: Y;
};
const apply_fun = (x, fn) => {
if (x.isComplex?.()) return new x.constructor(
fn(x.a),
fn(x.b)
)
if (x.isMatrix?.()) return new x.constructor(
x.rows,
x.cols,
x.arr.flat(1).map(fn)
)
if (x instanceof Array) mapfun(fn, ...x);
return fn(x)
};
const base2base = (value, fromBase, toBase) => {
const dec = parseInt(value, fromBase);
if (Number.isNaN(dec)) throw new TypeError('Invalid value for the given base');
return dec.toString(toBase);
};
const arithmetic_helper=(op, x, y)=>{
if(typeof x === 'number'){
if(typeof y === 'number'){
switch(op){
case 'add' : return x + y;
case 'sub' : return x - y;
case 'mul' : return x * y;
case 'div' : return x / y;
case 'modulo' : return x % y;
}
}
if(y?.isComplex?.()) x = new y.constructor(x, 0);
if(y?.isMatrix?.()) x = y.constructor.nums(y.rows, y.cols, x);
return x[op](y)
}
if(x?.isComplex?.()){
if(typeof y === 'number' || y?.isComplex?.()) return x.clone()[op](y);
if(y?.isMatrix?.()){
x = y.constructor.nums(y.rows, y.cols, x);
return x.clone()[op](y)
}
}
if(x?.isMatrix?.()){
return x.clone()[op](y)
}
};
const add=(a,...b)=>{
let res = a;
for(let i=0; i<b.length; i++)
res = arithmetic_helper('add', res, b[i]);
return res;
};
const sub=(a,...b)=>{
let res = a;
for(let i=0; i<b.length; i++)
res = arithmetic_helper('sub', res, b[i]);
return res;
};
const mul=(a,...b)=>{
let res = a;
for(let i=0; i<b.length; i++)
res = arithmetic_helper('mul', res, b[i]);
return res;
};
const div=(a,...b)=>{
let res = a;
for(let i=0; i<b.length; i++)
res = arithmetic_helper('div', res, b[i]);
return res;
};
const modulo=(a,...b)=>{
let res = a;
for(let i=0; i<b.length; i++)
res = arithmetic_helper('modulo', res, b[i]);
return res;
};
const min = (...x) => Math.min(...x);
const max = (...x) => Math.max(...x);
const binomial = (n, k) =>{
if(n !== Math.floor(n)) return TypeError('n must be an integer');
if(k !== Math.floor(k)) return TypeError('k must be an integer');
if (n < 0) return TypeError('n must be non-negative');
if (k < 0 || n < 0 || k > n) return 0;
if (k > n - k) k = n - k;
let c = 1, i;
for (i = 0; i < k; i++)
c = c * (n - i) / (i + 1);
return c;
};
const mean = (...x) => x.reduce((a, b) => a + b) / x.length;
const variance = (...x) => {
const n = x.length;
if (n === 0) return NaN;
const x_mean = mean(...x);
return x.reduce((sum, xi) => sum + (xi - x_mean) ** 2, 0) / n;
};
const std = (...x) => Math.sqrt(variance(...x));
const accum_sum = (...x) => {
let result = [];
let total = 0, i, n = x.length;
for(i = 0; i < n ; i++){
total = add(total, x[i]);
result.push(total);
}
return result;
};
const accum_prod = (...x) => {
let result = [];
let prod = 1, i, n = x.length;
for(i = 0; i < n ; i++){
prod = mul(prod, x[i]);
result.push(prod);
}
return result;
};
const percentile = (X, p) => {
if (X.length === 0)
return NaN;
let a = [...X].sort((x, y) => x - y);
let index = (p / 100) * (a.length - 1);
let i = Math.floor(index);
let f = index - i;
if (i === a.length - 1)
return a[i];
return a[i] * (1 - f) + a[i + 1] * f;
};
const median = X => percentile(X, 50);
class Random {
static int(a, b){
return Math.floor(this.float(a, b));
}
static float(a, b){
return b !== undefined
? Math.random() * (b - a) + a
: Math.random() * a;
}
static bin(){
return this.int(2);
}
static oct(){
return this.int(8);
}
static dec(){
return this.int(10);
}
static hex(){
return base2base(this.int(16), 10, 16);
}
static char(upperCase = false){
const i = upperCase
? this.int(65, 91)
: this.int(97, 123);
return String.fromCharCode(i);
}
static bool(){
return Boolean(this.int(2));
}
static get color(){
return {
hex : () =>
`#${this.int(0xffffff).toString(16).padStart(6, '0')}`,
hexa : () => {
const [r,g,b,a] = Array.from(
{length:4},
() => this.int(0xff).toString(16).padStart(2,'0')
);
return `#${r}${g}${b}${a}`;
},
rgb : () => {
const [r,g,b] = Array.from({length:3}, () => this.int(0xff));
return `rgb(${r}, ${g}, ${b})`;
},
rgba : () => {
const [r,g,b] = Array.from({length:3}, () => this.int(0xff));
const a = Math.random().toFixed(2);
return `rgba(${r}, ${g}, ${b}, ${a})`;
},
hsl : () => {
const h = this.int(360);
const s = this.int(100);
const l = this.int(100);
return `hsl(${h}, ${s}%, ${l}%)`;
},
hsla : () => {
const h = this.int(360);
const s = this.int(100);
const l = this.int(100);
const a = Math.random().toFixed(2);
return `hsla(${h}, ${s}%, ${l}%, ${a})`;
},
gray : () => {
const g = this.int(0xff);
return `rgb(${g}, ${g}, ${g})`;
}
};
}
static get sample(){
const R = this;
return {
int : (n,a,b) => Array.from({length:n}, () => R.int(a,b)),
float : (n,a,b) => Array.from({length:n}, () => R.float(a,b)),
char : (n,upper=false) => Array.from({length:n}, () => R.char(upper)),
bool : n => Array.from({length:n}, () => R.bool()),
bin : n => Array.from({length:n}, () => R.bin()),
oct : n => Array.from({length:n}, () => R.oct()),
dec : n => Array.from({length:n}, () => R.dec()),
hex : n => Array.from({length:n}, () => R.hex()),
get color(){
return {
hex : n => Array.from({length:n}, () => R.color.hex()),
hexa : n => Array.from({length:n}, () => R.color.hexa()),
rgb : n => Array.from({length:n}, () => R.color.rgb()),
rgba : n => Array.from({length:n}, () => R.color.rgba()),
hsl : n => Array.from({length:n}, () => R.color.hsl()),
hsla : n => Array.from({length:n}, () => R.color.hsla()),
gray : n => Array.from({length:n}, () => R.color.gray())
};
},
choice : (n, choices, p) =>
Array.from({length:n}, () => R.choice(choices, p))
};
}
static shuffle(arr){
return [...arr].sort(() => 0.5 - Math.random());
}
static choice(choices = [1,2,3], p = new Array(choices.length).fill(1 / choices.length)){
const acc = accum_sum(...p).map(v => v * 100);
const pool = new Array(100);
pool.fill(choices[0], 0, acc[0]);
for(let i=1;i<choices.length;i++)
pool.fill(choices[i], acc[i-1], acc[i]);
return pool[this.int(pool.length)];
}
}
globalThis.Random = Random;
// // (upperCase) => upperCase ? : String.fromCharCode(rand_int(97,120))
// class Random {
// static string(length,upperCase){
// return length instanceof Array?
// new Array(this.int(...length)).fill(0).map(() => this.char(upperCase)).join(""):
// new Array(length).fill(0).map(() => this.char(upperCase)).join("");
// }
// }
// export{Random}
const complex_constructor = (Complex, a, b) => {
let _a, _b;
if (a instanceof Complex) {
_a = a.a;
_b = a.b;
}
else if (typeof a === "object") {
if ("a" in a && "b" in a) {
_a = a.a;
_b = a.b;
}
else if ("a" in a && "z" in a) {
_a = a.a;
_b = Math.sqrt(a.z ** 2 - a.a ** 2);
}
else if ("a" in a && "phi" in a) {
_a = a.a;
_b = a.a * Math.tan(a.phi);
}
else if ("b" in a && "z" in a) {
_b = a.b;
_a = Math.sqrt(a.z ** 2 - a.b ** 2);
}
else if ("b" in a && "phi" in a) {
_b = b;
_a = a.b / Math.tan(a.phi);
}
else if ("z" in a && "phi" in a) {
_a = +a.z * Math.cos(a.phi).toFixed(15);
_b = +a.z * Math.sin(a.phi).toFixed(15);
}
}
else if (typeof a === "number" && typeof b === "number") {
_a = +a.toFixed(32);
_b = +b.toFixed(32);
}
return [_a, _b]
};
class Complex{
constructor(a = 0, b = 0) {
[
this.a,
this.b
] = complex_constructor(Complex, a, b);
}
get __mapfun__(){
return true
}
isComplex(){
return true
}
toString(){
let str = "";
if (this.a !== 0)
this.b >= 0
? (str = `${this.a}+${this.b}*i`)
: (str = `${this.a}-${Math.abs(this.b)}*i`);
else
this.b >= 0
? (str = `${this.b}*i`)
: (str = `-${Math.abs(this.b)}*i`);
return str;
}
serialize() {
return JSON.stringify({
type : 'complex',
data : this
});
}
static deserialize(json){
if(typeof json === 'string') json = JSON.parse(json);
let {data, type} = json;
return (type === 'complex' && ('a' in data) && ('b' in data))
? new Complex(data.a, data.b)
: TypeError('Not a valid complex')
}
toFixed(n){
this.a = + this.a.toFixed(n);
this.b = + this.b.toFixed(n);
return this;
}
toPrecision(n){
this.a = + this.a.toPrecision(n);
this.b = + this.b.toPrecision(n);
return this;
}
clone() {
return new Complex(this.a, this.b);
}
get z(){
return Math.hypot(this.a,this.b);
}
get phi(){
return Math.atan2(this.b , this.a);
}
static zero() {
return new Complex(0, 0);
}
static fromPolar(z, phi) {
return new Complex(
+(z * cos(phi)).toFixed(13),
+(z * sin(phi)).toFixed(13)
);
}
static get random(){
return {
int : (a, b)=> new Complex(...Random.sample.int(2, a, b) ),
float : (a, b)=> new Complex(...Random.sample.float(2, a, b) ),
}
}
static twiddle(K, N){
const phi = -2 * Math.PI * K / N;
return new Complex(
Math.cos(phi),
Math.sin(phi)
);
}
get conj() {
return new Complex(this.a, -this.b);
}
get inv() {
return new Complex(
this.a / Math.hypot(this.a, this.b),
-this.b / Math.hypot(this.a, this.b)
);
}
add(...c) {
for (let i = 0; i < c.length; i++) {
if (typeof c[i] === "number") c[i] = new Complex(c[i], 0);
this.a += c[i].a;
this.b += c[i].b;
}
return this;
}
sub(...c) {
for (let i = 0; i < c.length; i++) {
if (typeof c[i] === "number") c[i] = new Complex(c[i], 0);
this.a -= c[i].a;
this.b -= c[i].b;
}
return this;
}
mul(...c){
let {z, phi} = this;
for (let i = 0; i < c.length; i++) {
if (typeof c[i] === "number") c[i] = new Complex(c[i], 0);
z *= c[i].z;
phi += c[i].phi;
}
this.a = z * Math.cos(phi);
this.b = z * Math.sin(phi);
return this.toFixed(8);
}
div(...c){
let {z, phi} = this;
for (let i = 0; i < c.length; i++) {
if (typeof c[i] === "number") c[i] = new Complex(c[i], 0);
z /= c[i].z;
phi -= c[i].phi;
}
this.a = z * Math.cos(phi);
this.b = z * Math.sin(phi);
return this.toFixed(8); }
modulo(...c) {
for (let i = 0; i < c.length; i++) {
if (typeof c[i] === "number") c[i] = new Complex(c[i], 0);
this.a %= c[i].a;
this.b %= c[i].b;
}
return this;
}
pow(...c){
let {z, phi} = this;
for (let i = 0; i < c.length; i++) {
if (typeof c[i] === "number") c[i] = new Complex(c[i], 0);
z *= Math.exp(c[i].a * Math.log(z) - c[i].b * phi);
phi += c[i].b * Math.log(z) + c[i].a * phi;
}
this.a = z * Math.cos(phi);
this.b = z * Math.sin(phi);
return this;
}
get expo() {
return [this.z, this.phi];
}
nthr(n=2){
return complex({z: this.z ** (1/n), phi: this.phi / n});
}
get sqrt(){
return this.nthr(2);
}
get cbrt(){
return this.nthr(3);
}
get log(){
return complex(this.z, this.phi);
}
get cos(){
return complex(
Math.cos(this.a) * Math.cosh(this.b),
Math.sin(this.a) * Math.sinh(this.b)
)
}
get sin(){
return complex(
Math.sin(this.a) * Math.cosh(this.b),
Math.cos(this.a) * Math.sinh(this.b)
)
}
get tan(){
const D=cos(this.a*2)+cosh(this.b*2);
return complex(
Math.sin(2 * this.a) / D,
Math.sinh(2 * this.b) / D
);
}
}
const complex=(a,b)=>{
if((a instanceof Array||ArrayBuffer.isView(a)) && (b instanceof Array||ArrayBuffer.isView(a)))return a.map((n,i)=>complex(a[i],b[i]));
if(a.isMatrix?.() && b.isMatrix?.()){
if((a.shape[0]!==b.shape[0])||(a.shape[1]!==b.shape[1]))return Error(0)
const arr=a.arr.map((n,i)=>complex(a.arr[i],b.arr[i]));
return new a.constructor(a.rows,a.cols,...arr)
}
return new Complex(a,b)
};
const PRECESION = 8;
const abs = (...x) => mapfun(
x =>{
if(x.isComplex?.()) return x.z;
return Math.abs(x)
},
...x
);
const pow$1 = (...x) => {
const n = x.pop();
return mapfun(
x => {
if(x.isComplex?.()) {
if(n.isComplex?.()) return new x.constructor({
z: Math.exp(n.a * Math.log(x.z) - n.b * x.phi),
phi: n.b * Math.log(x.z) + n.a * x.phi
})
return new x.constructor({z: x.z ** n, phi: x.phi * n});
}
if(n.isComplex?.()) return new x.constructor({
z: Math.exp(n.a * Math.log(x)),
phi: n.b * Math.log(x)
})
return Math.pow(x, n)
},
...x
)
};
const sqrt$2 = (...x) => mapfun(
x=>{
if(x.isComplex?.())
return new x.constructor({z: x.z**(1/2), phi: x.phi/2});
if(x < 0) return complex(0, Math.sqrt(-x)).toFixed(PRECESION)
return + Math.sqrt(x).toFixed(PRECESION);
},
...x
);
const cbrt = (...x) => mapfun(
x=>{
if(x.isComplex?.())
return new x.constructor({z: x.z**(1/3), phi: x.phi/3}).toFixed(PRECESION)
return + Math.cbrt(x).toFixed(PRECESION);
},
...x
);
const nthr = (...x) => {
const n = x.pop();
if(typeof n !== 'number') throw Error('nthr expects a real number n');
return mapfun(
x => {
if(x.isComplex?.()) return new x.constructor({z: x.z ** (1/n), phi: x.phi / n});
if(x<0) return n %2 ===2
? complex(0, (-x)**(1/n)).toFixed(PRECESION)
: + (-1 * (-x)**(1/n)).toFixed(PRECESION)
return + (x**(1/n)).toFixed(PRECESION)
},
...x
)
};
const croot = (...x) =>{
const c = x.pop();
if(!c.isComplex?.()) throw Error('croot expect Complex number as root')
return mapfun(
x => {
if(typeof x === 'number') x = new c.constructor(x, 0);
const {a : c_a, b : c_b} = c;
const {z, phi} = x;
const D = Math.hypot(c_a, c_b);
const A = Math.exp((Math.log(z)*c_a + phi*c_b)/D);
const B = (phi*c_a - Math.log(z)*c_b)/D;
return new c.constructor(
A * Math.cos(B),
A * Math.sin(B)
).toFixed(PRECESION)
},
...x
)
};
const exp$1 = (...x) => mapfun(
x => {
if(x.isComplex?.()) return new x.constructor(
Math.exp(x.a) * Math.cos(x.b),
Math.exp(x.a) * Math.sin(x.b)
).toFixed(PRECESION);
return + Math.exp(x).toFixed(PRECESION)
}
,...x
);
const ln = (...x) => mapfun(
x => {
if(x.isComplex?.()) return new x.constructor(
Math.log(x.z),
x.phi
).toFixed(PRECESION);
return + Math.log(x).toFixed(PRECESION)
}
,...x
);
const sign = (...x) => mapfun(
x => {
if(x.isComplex?.()){
const {z, phi} = x;
if(z===0) return new x.constructor(0, 0);
return new x.constructor({z:1, phi})
}
return Math.sign(x)
}
,...x
);
const floor = (...x) => mapfun(
x => {
if(x.isComplex?.()) return new x.constructor(
Math.floor(x.a),
Math.floor(x.b)
)
return Math.floor(x)
},
...x
);
const ceil = (...x) => mapfun(
x => {
if(x.isComplex?.()) return new x.constructor(
Math.ceil(x.a),
Math.ceil(x.b)
)
return Math.ceil(x)
},
...x
);
const round = (...x) => mapfun(
x => {
if(x.isComplex?.()) return new x.constructor(
Math.round(x.a),
Math.round(x.b)
)
return Math.round(x)
},
...x
);
const trunc = (...x) => mapfun(
x => {
if(x.isComplex?.()) return new x.constructor(
Math.trunc(x.a),
Math.trunc(x.b)
)
return Math.trunc(x)
},
...x
);
const fract = (...x) => mapfun(
x => {
if(x.isComplex?.()) return new x.constructor(
x.a - Math.trunc(x.a),
x.b - Math.trunc(x.b)
)
return x - Math.trunc(x)
},
...x
);
const cos$3 = (...x) => mapfun(
x => {
if(x.isComplex?.()) return new x.constructor(
Math.cos(x.a) * Math.cosh(x.b),
-Math.sin(x.a) * Math.sinh(x.b)
).toFixed(PRECESION);
return + Math.cos(x).toFixed(PRECESION)
}
,...x
);
const sin$3 = (...x) => mapfun(
x =>{
if(x?.isComplex) return new x.constructor(
Math.sin(x.a) * Math.cosh(x.b),
Math.cos(x.a) * Math.sinh(x.b)
).toFixed(PRECESION);
return + Math.sin(x).toFixed(PRECESION)
}
, ...x
);
const tan = (...x) => mapfun(
x =>{
if(x?.isComplex){
const D = Math.cos(2*x.a) + Math.cosh(2*x.b);
return new x.constructor(
Math.sin(2*x.a) / D,
Math.sinh(2*x.b) / D
).toFixed(PRECESION);
}
return + Math.tan(x).toFixed(PRECESION)
},
...x
);
const sec = (...x) => mapfun(
x => {
if(x.isComplex?.()) ;
return + (1 / Math.cos(x)).toFixed(PRECESION)
}
,...x
);
const acos$1 = (...x) => mapfun(
x =>{
if(x?.isComplex){
const { a, b } = x;
const Rp = Math.hypot(a + 1, b);
const Rm = Math.hypot(a - 1, b);
globalThis.Rp = Rp;
globalThis.Rm = Rm;
return new x.constructor(
Math.acos((Rp - Rm) / 2),
-Math.acosh((Rp + Rm) / 2),
).toFixed(PRECESION)
}
return + Math.acos(x).toFixed(PRECESION)
},
...x
);
const asin = (...x) => mapfun(
x => {
if(x?.isComplex){
const { a, b } = x;
const Rp = Math.hypot(a + 1, b);
const Rm = Math.hypot(a - 1, b);
return new x.constructor(
Math.asin((Rp - Rm) / 2),
Math.acosh((Rp + Rm) / 2)
).toFixed(PRECESION);
}
return + Math.asin(x).toFixed(PRECESION);
},
...x
);
const atan = (...x) => mapfun(
x => {
if(x?.isComplex){
const { a, b } = x;
return new x.constructor(
Math.atan((a*2/(1-a**2-b**2)))/2,
Math.log((a**2 + (1+b)**2)/(a**2 + (1-b)**2))/4
).toFixed(PRECESION)
}
return + Math.atan(x).toFixed(PRECESION);
},
...x
);
const acot = (...x) => mapfun(
x => {
if(x?.isComplex){
const { a, b } = x;
return new x.constructor(
Math.atan(2*a/(a**2+(b-1)*(b+1)))/2,
Math.log((a**2 + (b-1)**2)/(a**2 + (b+1)**2))/4
).toFixed(PRECESION)
}
return + (Math.PI/2 - Math.atan(x)).toFixed(PRECESION);
},
...x
);
const cosh$2 = (...x) => mapfun(
x =>{
if(x?.isComplex) return new x.constructor(
Math.cosh(x.a) * Math.cos(x.b),
Math.sinh(x.a) * Math.sin(x.b)
).toFixed(PRECESION);
return + Math.cosh(x).toFixed(PRECESION)
},
...x
);
const sinh$1 = (...x) => mapfun(
x =>{
if(x?.isComplex) return new x.constructor(
Math.sinh(x.a) * Math.cos(x.b),
Math.cosh(x.a) * Math.sin(x.b)
).toFixed(PRECESION);
return + Math.sinh(x).toFixed(PRECESION)
},
...x
);
const tanh = (...x) => mapfun(
x =>{
if(x?.isComplex){
const D = Math.cosh(2*a) + Math.cos(2*b);
return new x.constructor(
Math.sinh(2*a) / D,
Math.sin(2*b) / D
).toFixed(PRECESION)
}
return + Math.tanh(x).toFixed(PRECESION)
},
...x
);
const coth = (...x) => mapfun(
x =>{
if(x?.isComplex){
const {a, b} = x;
const D = (Math.sinh(a)**2)*(Math.cos(b)**2) + (Math.cosh(a)**2)*(Math.sin(b)**2);
return new x.constructor(
Math.cosh(a) * Math.sinh(a) / D,
- Math.sin(b) * Math.cos(b) / D
).toFixed(PRECESION)
}
return + (1 / Math.tanh(x)).toFixed(PRECESION)
},
...x
);
const acosh = (...x) => mapfun(
x =>{
if(x?.isComplex){
return ln(x.clone().add(sqrt$2(x.clone().mul(x.clone()).sub(1))))
}
return + Math.acosh(x).toFixed(PRECESION)
},
...x
);
const asinh = (...x) => mapfun(
x =>{
if(x?.isComplex){
return ln(x.clone().add(sqrt$2(x.clone().mul(x.clone()).add(1))))
}
return + Math.asinh(x).toFixed(PRECESION)
},
...x
);
const atanh = (...x) => mapfun(
x =>{
if(x?.isComplex);
return + Math.atanh(x).toFixed(PRECESION)
},
...x
);
const sig = (...x) => mapfun(
x =>{
if(x?.isComplex);
return 1/(1 + Math.exp(-x)).toFixed(PRECESION)
},
...x
);
const deg2rad = (...deg) => mapfun(x => x * Math.PI / 180, ...deg);
const rad2deg = (...rad) => mapfun(x => x / Math.PI * 180, ...rad);
const norm = (x, min, max) => apply_fun(
x,
v => min !== max ? (v - min) / (max - min) : 0
);
const lerp = (x, min, max) => apply_fun(
x,
v => (max - min) * v + min
);
const clamp = (x, min, max) => apply_fun(
x,
v => Math.min(Math.max(v, min), max)
);
const map$1 = (x, a, b, c, d) => apply_fun(
x,
v => lerp(norm(v, a, b), c, d)
);
const hypot = (...x) => {
const c0 = x.find(a => a.isComplex?.());
if (c0) {
const W = x.map(n => n.isComplex?.() ? n : new c0.constructor(n, 0));
return Math.hypot(...W.map(c => c.z));
}
return Math.hypot(...x);
};
const atan2 = (y, x, rad = true) => {
if (y instanceof Array && !(x instanceof Array))
return mapfun(n => atan2(n, x, rad), ...y);
if (x instanceof Array && !(y instanceof Array))
return mapfun(n => atan2(y, n, rad), ...x);
if (y instanceof Array && x instanceof Array)
return y.map((v, i) => atan2(v, x[i], rad));
const phi = Math.atan2(y, x);
return rad ? phi : phi * 180 / Math.PI;
};
const not = x => {
if(x.isComplex?.()) return new x.constructor(not(x.a), not(x.b))
if(x.isMatrix?.()) return new x.constructor(x.rows, x.cols, x.arr.flat(1).map(not))
return + !x;
};
const handle_complex_and_matrix = (x, operation) => {
if (x.every(n => n.isComplex?.())) {
const Re = x.map(n => n.a);
const Im = x.map(n => n.b);
return new x[0].constructor(
operation(...Re),
operation(...Im)
);
}
if (x.every(n => n.isMatrix?.())) {
if (!x.every(mat => mat.rows === x[0].rows && mat.cols === x[0].cols)) {
return TypeError('All matrices must have the same shape');
}
const { rows, cols } = x[0];
const Y = Array.from({ length: rows }, (_, i) =>
Array.from({ length: cols }, (_, j) =>
operation(...x.map(mat => mat.arr[i][j]))
)
);
return new x[0].constructor(Y);
}
return null; // Return null if no Complex or Matrix found
};
const and = (...x) => {
const result = handle_complex_and_matrix(x, and);
if (result !== null) return result;
return x.reduce((n, m) => (n &= m), 1);
};
const or = (...x) => {
const result = handle_complex_and_matrix(x, or);
if (result !== null) return result;
return x.reduce((n, m) => (n |= m), 0);
};
const xor = (...x) => {
const result = handle_complex_and_matrix(x, xor);
if (result !== null) return result;
return x.reduce((n, m) => (n ^= m), 0);
};
const nand = (...x) => not(and(...x));
const nor = (...x) => not(or(...x));
const xnor = (...x) => not(xor(...x));
const matrix_constructor = (Matrix, rows, cols, element) => {
if (rows instanceof Matrix) {
arr = rows.arr;
rows = rows.rows;
cols = rows.cols;
}
else {
let arr = [], i, j;
if (rows instanceof Array) {
arr = rows;
rows = arr.length;
cols = arr[0].length;
}
else {
for (i = 0; i < rows; i++) {
arr.push([]);
arr[i].push(new Array(cols));
for (j = 0; j < cols; j++) {
arr[i][j] = element[i * cols + j];
if (element[i * cols + j] == undefined) arr[i][j] = 0;
}
}
}
return [
rows,
cols,
arr
]
}
};
const maintain_indexes = (Matrix, oldRows) =>{
for (let i = 0; i < Matrix.arr.length; i++) {
Object.defineProperty(Matrix, i, {
value: Matrix.arr[i],
writable: true,
configurable: true,
enumerable: false
});
}
for (let i = Matrix.arr.length; i < oldRows; i++) {
delete Matrix[i];
}
};
function matrix_inverse(M) {
if(M.row !== M.cols) throw Error('is not a square matrix"')
if (M.det === 0) throw Error("determinant should not equal 0");
const { arr } = M;
if (arr.length !== arr[0].length) return;
var i = 0, ii = 0, j = 0, dim = arr.length, e = 0;
var I = [], C = [];
for (i = 0; i < dim; i += 1) {
I[I.length] = [];
C[C.length] = [];
for (j = 0; j < dim; j += 1) {
if (i == j) I[i][j] = 1;
else I[i][j] = 0;
C[i][j] = arr[i][j];
}
}
for (i = 0; i < dim; i += 1) {
e = C[i][i];
if (e == 0) {
for (ii = i + 1; ii < dim; ii += 1) {
if (C[ii][i] != 0) {
for (j = 0; j < dim; j++) {
e = C[i][j];
C[i][j] = C[ii][j];
C[ii][j] = e;
e = I[i][j];
I[i][j] = I[ii][j];
I[ii][j] = e;
}
break;
}
}
e = C[i][i];
if (e == 0) return;
}
for (j = 0; j < dim; j++) {
C[i][j] = C[i][j] / e;
I[i][j] = I[i][j] / e;
}
for (ii = 0; ii < dim; ii++) {
if (ii == i) {
continue;
}
e = C[ii][i];
for (j = 0; j < dim; j++) {
C[ii][j] -= e * C[i][j];
I[ii][j] -= e * I[i][j];
}
}
}
return new M.constructor(I);
}
function matrix_det(M) {
if (!M.isSquare) return new Error("is not square matrix");
if (M.rows == 1) return M.arr[0][0];
function determinat(M) {
if (M.length == 2) {
if (M.flat(1).some((n) => n?.isMatrix?.())) {
console.warn("Tensors are not completely supported yet ...");
return;
}
return sub(mul(M[0][0],M[1][1]),mul(M[0][1],M[1][0]))
}
var answer = 0;
for (var i = 0; i < M.length; i++) {
//console.log(M[0][i]);
/*answer = answer.add(
pow(-1, i)
.mul(M[0][i])
.mul(determinat(deleteRowAndColumn(M, i)))
);*/
//const to_be_added=add(mul(pow(-1, i),mul(M[0][i],determinat(deleteRowAndColumn(M, i)))));
const to_be_added=add(mul(pow$1(-1, i),mul(M[0][i],determinat(deleteRowAndColumn(M, i)))));
answer=add(answer,to_be_added);
}
return answer;
}
return determinat(M.arr);
}
function deleteRowAndColumn(M, index) {
var temp = [];
for (let i = 0; i < M.length; i++) temp.push(M[i].slice(0));
temp.splice(0, 1);
for (let i = 0; i < temp.length; i++) temp[i].splice(index, 1);
return temp;
}
function hstack(M1, M2){
M1 = M1.clone();
M2 = M2.clone();
if (M1.rows !== M2.rows) return;
let newArr = M1.arr;
for (let i = 0; i < M1.rows; i++)
for (let j = M1.cols; j < M1.cols + M2.cols; j++)
newArr[i][j] = M2.arr[i][j - M1.cols];
M1.cols += M2.cols;
return new M1.constructor(M1.rows, M1.cols, newArr.flat(1));
}
function vstack(M1, M2){
M1 = M1.clone();
M2 = M2.clone();
if (M1.cols !== M2.cols) return;
let newArr = M1.arr;
for (let i = M1.rows; i < M1.rows + M2.rows; i++) {
newArr[i] = [];
for (let j = 0; j < M1.cols; j++) newArr[i][j] = M2.arr[i - M1.rows][j];
}
M1.rows += M2.rows;
return new M1.constructor(M1.rows, M1.cols, newArr.flat(1));
}
class Matrix{
constructor(rows, cols, element = [] ) {
[
this.rows,
this.cols,
this.arr
] = matrix_constructor(Matrix, rows, cols, element);
maintain_indexes(this);
}
isMatrix(){
return true
}
clone() {
return new Matrix(this.rows, this.cols, this.arr.flat(1));
}
toComplex(){
this.arr = mapfun(
x => x?.isComplex?.() ? x : new Complex(x, 0),
...this.arr
);
maintain_indexes(this);
return this;
}
[Symbol.iterator]() {
return this.arr[Symbol.iterator]();
}
get size() {
return this.rows * this.cols;
}
get shape() {
return [this.rows, this.cols];
}
// toString(){
// return arr2str(this.arr,false);
// }
at(i = 0, j = undefined) {
if(i < 0) i += this.rows;
if(i < 0 || i >= this.rows) throw new Error('Row index out of bounds');
if(j === undefined) return this.arr[i];
if(j < 0) j += this.cols;
if(j < 0 || j >= this.cols) throw new Error('Column index out of bounds');
return this.arr[i][j];
}
slice(r0=0, c0=0, r1 = this.rows-1, c1 = this.cols-1) {
if(r1 < 0) r1 = this.rows + r1;
if(c1 < 0 ) c1 = this.cols + c1;
let newRow = r1 - r0,
newCol = c1 - c0;
let newArr = new Array(newCol);
for (let i = 0; i < newRow; i++) {
newArr[i] = [];
for (let j = 0; j < newCol; j++)
newArr[i][j] = this.arr[i + r0][j + c0];
}
this.arr = newArr;
maintain_indexes(this.rows);
this.rows = newRow;
this.cols = newCol;
return this;
}
reshape(newRows, newCols) {
if(!(newRows * newCols === this.rows * this.cols)) throw Error('size not matched');
const oldRows = this.rows;
Object.assign(this, new Matrix(newRows, newCols, this.arr.flat(1)));
maintain_indexes(oldRows);
return this;
}
get T() {
let transpose = [];
for (let i = 0; i < this.arr[0].length; i++) {
transpose[i] = [];
for (let j = 0; j < this.arr.length; j++)
transpose[i][j] = this.arr[j][i];
}
return new Matrix(this.cols, this.rows, transpose.flat(1));
}
get det() {
return matrix_det(this)
}
get inv() {
return matrix_inverse(this)
}
// normalize names
static eye(size) {
let result = new Matrix(size, size);
for (let i = 0; i < size; i++)
for (let j = 0; j < size; j++) i === j ? (result.arr[i][j] = 1) : (result.arr[i][j] = 0);
return result;
}
static zeros(rows, cols) {
let result = new Matrix(rows, cols);
for (let i = 0; i < rows; i++)
for (var j = 0; j < cols; j++) result.arr[i][j] = 0;
return result;
}
static ones(rows, cols) {
let result = new Matrix(rows, cols);
for (let i = 0; i < rows; i++)
for (let j = 0; j < cols; j++) result.arr[i][j] = 1;
return result;
}
static nums(rows, cols, number) {
let result = new Matrix(rows, cols);
for (let i = 0; i < rows; i++)
for (let j = 0; j < cols; j++) result.arr[i][j] = number;
return result;
}
static get random(){
return {
int : (r, c, a, b)=> new Matrix(
r,
c,
Random.sample.int(r*c, a, b)
),
float : (r, c, a,)=> new Matrix(
r,
c,
Random.sample.float(r*c, a, b)
),
}
}
get range(){
return {
map : (xmin, xmax, ymin, ymax) => {
this.arr = map$1(this.arr, xmin, xmax, ymin, ymax);
return this;
},
norm : (min, max) => {
this.arr = norm(this.arr, min, max);
return this;
},
lerp : (min, max) => {
this.arr = lerp(this.arr, min, max);
return this;
},
clamp : (min, max) => {
this.arr = clamp(this.arr, min, max);
return this;
},
}
}
hstack(...matrices) {
const M=[this, ...matrices].reduce((a,b)=>hstack(a, b));
Object.assign(this, M);
maintain_indexes(this);
return this;
}
vstack(...matrices){
const M=[this, ...matrices].reduce((a,b)=>vstack(a, b));
Object.assign(this, M);
maintain_indexes(this);
return this;
}
hqueue(...matrices){
const M=[this, ...matrices].reverse().reduce((a,b)=>hstack(a, b));
Object.assign(this, M);
maintain_indexes(this);
return this;
}
vqueue(...matrices){
const M=[this,...matrices].reverse().reduce((a, b)=>vstack(a, b));
Object.assign(this, M);
maintain_indexes(this);
return this;
}
forEach(fn){
this.arr.flat(1).forEach(fn);
return this;
}
forEachRow(fn){
this.arr.forEach(fn);
return this;
}
forEachCol(fn){
this.clone().T.forEachRow(fn);
return this
}
map(fn){
const arr = this.arr.flat(1).map(fn);
return new Matrix(
this.rows,
this.cols,
arr
)
}
mapRows(fn = ()=>{}){
this.arr = this.arr.map(fn);
return this;
}
mapCols(fn){
return this.clone().T.mapRows(fn).T;
}
sort(fn = ()=>{}){
const arr = this.arr.flat(1).sort(fn);
return new Matrix(
this.rows,
this.cols,
arr
)
}
shuffle(){
return this.sort(() => 0.5-Math.random())
}
sortRows(fn = ()=>{}){
this.arr = this.arr.map(row => row.sort(fn));
return this;
}
shuffleRows(){
return this.sortRows(() => 0.5-Math.random())
}
sortCols(fn){
return this.clone().T.sortRows(fn).T;
}
shuffleCols(){
return this.sortCols(() => 0.5-Math.random())
}
reduce(fn, initialValue){
const value = initialValue
? this.arr.flat(1).reduce(fn, initialValue)
: this.arr.flat(1).reduce(fn);
return new Matrix([[value]])
}
reduceRows(fn, initialValue){
const values = initialValue
? this.arr.map(row => row.reduce(fn, initialValue))
: this.arr.map(row => row.reduce(fn));
return new Matrix(1, this.cols, values)
}
reduceCols(fn, initialValue){
return this.T.reduceRows(fn, initialValue).T
}
filterRows(fn){
const mask = this.arr.map(n => n.some(m => fn(m)));
const arr = [];
let i;
for(i = 0; i < mask.length; i++)
if(mask[i]) arr.push(this.arr[i]);
return new Matrix(arr)
}
filterCols(fn){
const arr = this.T.filterRows(fn);
return new Matrix(arr).T
}
every(fn){
return this.arr.flat(1).every(fn)
}
everyRow(fn){
return this.arr.map(n => n.every(fn))
}
everyCol(fn){
return this.T.arr.map(n => n.every(fn))
}
some(fn){
return this.arr.flat(1).some(fn)
}
someRow(fn){
return this.arr.map(n => n.some(fn))
}
someCol(fn){
return this.T.arr.map(n => n.some(fn))
}
// Checkers
get isSquare() {
return this.rows === this.cols;
}
get isSym() {
if (!this.isSquare) return false;
for (let i = 0; i < this.rows; i++) {
for (let j = i + 1; j < this.cols; j++) {
if (this.arr[i][j] !== this.arr[j][i]) return false;
}
}
return true;
}
get isAntiSym() {
if (!this.isSquare) return false;
const n = this.rows;
for (let i = 0; i < n; i++) {
if (this.arr[i][i] !== 0) return false;
for (let j = i + 1; j < n; j++) {
if (this.arr[i][j] !== -this.arr[j][i]) return false;
}
}
return true;
}
get isDiag() {
if (!this.isSquare) return false;
const n = this.rows;
for (let i = 0; i < n; i++) {
for (let j = i + 1; j < n; j++) {
if (this.arr[i][j] !== 0 || this.arr[j][i] !== 0) return false;
}
}
return true;
}
get isOrtho() {
if (!this.isSquare) return false;
return this.isDiag && (this.det == 1 || this.det == -1);
}
get isIdemp() {
if (!this.isSquare) return false;
const n = this.rows;
const A = this.arr;
// Compute A * A
const MM = [];
for (let i = 0; i < n; i++) {
MM[i] = [];
for (let j = 0; j < n; j++) {
let sum = 0;
for (let k = 0; k < n; k++) {
sum += A[i][k] * A[k][j];
}
MM[i][j] = sum;
}
}
// Check if A * A == A
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
if (MM[i][j] !== A[i][j]) return false;
}
}
return true;
}
get isUpperTri() {
if (!this.isSquare) return false;
const n = this.rows;
for (let i = 1; i < n; i++) {
for (let j = 0; j < i; j++) {
if (this.arr[i][j] !== 0) return false;
}
}
return true;
}
get isLowerTri() {
if (!this.isSquare) return false;
const n = this.rows;
for (let i = 0; i < n - 1; i++) {
for (let j = i + 1; j < n; j++) {
if (this.arr[i][j] !== 0) return false;
}
}
return true;
}
toPrecision(p) {
for (let i = 0; i < this.cols; i++)
for (let j = 0; j < this.rows; j++)
this.arr[i][j] = +this.arr[i][j].toPrecision(p);
return this;
}
toFixed(p) {
for (let i = 0; i < this.cols; i++)
for (let j = 0; j < this.rows; j++)
this.arr[i][j] = +this.arr[i][j].toFixed(p);
return this;
}
// max2min() {
// let newArr = this.arr.flat(1).max2min;
// return new Matrix(this.rows, this.cols, newArr);
// }
// min2max() {
// let newArr = this.arr.flat(1).min2max;
// return new Matrix(this.rows, this.cols, newArr);
// }
// count(n) {
// return this.arr.flat(1).count(n);
// }
splice(r0,c0,deleteCount,...items){
}
getRows(ri, rf = ri + 1) {
return this.slice(ri, 0, rf, this.cols);
}
getCols(ci, cf = ci + 1) {
return this.slice(0, ci, this.rows, cf);
}
#arithmetic(fn, ...matr){
for (let k = 0; k < matr.length; k++) {
if (typeof matr[k] == "number" || matr[k]?.isComplex?.()) matr[k] = Matrix.nums(this.rows, this.cols, matr[k]);
for (let i = 0; i < this.rows; i++)
for (var j = 0; j < this.cols; j++)
this.arr[i][j] = fn(this.arr[i][j], matr[k].arr[i][j]);
}
return new Matrix(this.rows, this.cols, this.arr.flat(1));
}
add(...matr) {
return this.#arithmetic(add, ...matr)
}
sub(...matr) {
return this.#arithmetic(sub, ...matr)
}
mul(...matr) {
return this.#arithmetic(mul, ...matr)
}
div(...matr) {
return this.#arithmetic(div, ...matr)
}
modulo(...matr) {
return this.#arithmetic(modulo, ...matr)
}
dot(matrix) {
var res = [];
for (var i = 0; i < this.arr.length; i++) {
res[i] = [];
for (var j = 0; j < matrix.arr[0].length; j++) {
res[i][j] = 0;
for (var k = 0; k < this.arr[0].length; k++) {
res[i][j] = add(
res[i][j],
mul(this.arr[i][k],matrix.arr[k][j])
);
}
}
}
return new Matrix(this.arr.length, matrix.arr[0].length, res.flat(1));
}
pow(n) {
let a = this.clone(),
p = this.clone();
for (let i = 0; i < n - 1; i++) p = p.dot(a);
return p;
}
sum(){
let S = 0;
for (let i = 0; i < this.rows; i++)
for (let j = 0; j < this.cols; j++)
S = add(S, this.arr[i][j]);
return S;
}
prod(){
let S = 1;
for (let i = 0; i < this.rows; i++)
for (let j = 0; j < this.cols; j++)
S = mul(S, this.arr[i][j]);
return S;
}
hasComplex(){
return this.arr.flat(Infinity).some((n) => n instanceof Complex);
}
get min() {
if (this.hasComplex()) console.error("Complex numbers are not comparable");
let minRow = [];
for (let i = 0; i < this.rows; i++)
minRow.push(Math.min(...this.arr[i]));
return Math.min(...minRow);
}
get max() {
if (this.hasComplex()) console.error("Complex numbers are not comparable");
let maxRow = [];
for (let i = 0; i < this.rows; i++)
maxRow.push(Math.max(...this.arr[i]));
return Math.max(...maxRow);
}
get minRows() {
if (this.hasComplex()) console.error("Complex numbers are not comparable");
let minRow = [];
for (let i = 0; i < this.rows; i++)
minRow.push(Math.min(...this.arr[i]));
return minRow;
}
get maxRows() {
if (this.hasComplex()) console.error("Complex numbers are not comparable");
let maxRow = [];
for (let i = 0; i < this.rows; i++)
maxRow.push(Math.max(...this.arr[i]));
return maxRow;
}
get minCols() {
if (this.hasComplex()) console.error("Complex numbers are not comparable");
return this.T.minRows;
}
get maxCols() {
if (this.hasComplex()) console.error("Complex numbers are not comparable");
return this.T.maxRows;
}
static fromVector(v) {
return new Matrix(v.length, 1, v);
}
serialize() {
const arr = mapfun(x => x.serialize?.() || x, ...this.arr);
return JSON.stringify({
type : 'matrix',
data : {
rows : this.rows,
cols : this.cols,
arr,
}
});
}
static deserialize(json) {
if (typeof json == "string") json = JSON.parse(json);
const {type, data} = json;
if(type !== 'matrix') return TypeError('Not a valid Matrix')
let {arr} = data;
arr = mapfun(x => {
if(typeof x === 'string') {
const x_obj = JSON.parse(x);
const {type} = x_obj;
if(type === 'complex') return Complex.deserialize(x_obj)
}
return x
}, ...arr);
return new Matrix(arr)
}
flip(){
return this.flipeH().flipeV()
}
flipeH(){
this.arr = this.arr.map(row => [...row].reverse());
maintain_indexes(this);
return this;
}
flipeV(){
this.arr = this.arr.reverse();
maintain_indexes(this);
return this;
}
}
const matrix=(r, c, element)=>new Matrix(r, c, element);
const matrix2=(...element)=>new Matrix(2, 2, element);
const matrix3=(...element)=>new Matrix(3, 3, element);
const matrix4=(...element)=>new Matrix(4, 4, element);
const zeros=(n)=>new Array(n).fill(0);
const ones=(n)=>new Array(n).fill(1);
const nums=(num,n)=>new Array(n).fill(num);
const arange=(a, b, step , include = false)=>{
let tab = [];
if(a<b){
for (let i = a; include?i<=b:i<b; i += step) tab.push((i * 10) / 10);
}
else {
for(let i = a; include?i>=b:i>b; i -= step) tab.push((i * 10) / 10);
}
return tab;
};
const linspace=(a,b,n=abs(b-a)+1,endpoint=true)=>{
if(Math.floor(n)!==n)return;
if([a,b].every(n=>typeof n==="number")){
const [max,min]=[a,b].sort((a,b)=>b-a);
var Y = [];
let step ;
endpoint ? step = (max - min) / (n - 1) : step = (max - min) / n;
for (var i = 0; i < n; i++) {
a<b?Y.push(min+step*i):Y.push(max-step*i);
}
return Y
}
if([a,b].some(n=>n.isComplex?.())){
const z1 = new n.constructor(a);
const z2 = new n.constructor(b);
n=n||Math.abs(z1.a-z2.a)+1;
const X=linspace(z1.a,z2.a,n,endpoint);
const Y=linspace(z1.b,z2.b,n,endpoint);
let Z=new Array(n).fill(null);
Z=Z.map((n,i)=> new n.constructor(X[i],Y[i]));
return Z;
}
};
const logspace=(a,b,n=b-a+1,base=E,endpoint=true)=>{
return linspace(a,b,n,endpoint).map(n=>pow$1(base,n))
};
const geomspace=(a,b,n=abs(b-a)+1,endpoint=true)=>{
if(Math.floor(n)!==n)return;
if([a,b].every(n=>typeof n==="number")){
const [max,min]=[a,b].sort((a,b)=>b-a);
let base;
endpoint ? base = nthr(max/min,n-1) : base = nthr(max/min,n) ;
const Y = [min];
for (let i = 1; i < n; i++) {
Y.push(Y[i-1]*base);
}
return a<b?Y:Y.reverse()
}
if([a,b].some(n=>n.isComplex?.())){
const z1 = new n.constructor(a);
const z2 = new n.constructor(b);
n=n||Math.abs(z1.a-z2.a)+1;
let base;
endpoint ? base = nthr(z2.div(z1),n-1) : base = nthr(z2.div(z1),n) ;
const Y = [z1];
for (let i = 1; i < n; i++) {
Y.push(mul(Y[i-1],base));
}
return Y;
}
};
/** @module Math */
/**
* Checks if a value is within the specified range.
* @function
* @param {number} x - The value to check.
* @param {number} a - The start of the range.
* @param {number} b - The end of the range.
* @returns {boolean} Returns true if the value is within the range [a, b], otherwise false.
*/
const inRange = (x, a, b) => {
const [min, max] = [Math.min(a, b), Math.max(a, b)];
return x >= min && x <= max;
};
/**
* Checks if two numbers are approximately equal within a given error margin.
* @param {number} a - The first number.
* @param {number} b - The second number.
* @param {number} [Err=0.0001] - The maximum acceptable difference between the two numbers.
* @returns {boolean} Returns true if the two numbers are approximately equal within the specified error margin, otherwise false.
*/
const isApproximatlyEqual = (a, b, Err = 0.0001) => {
return Math.abs(a - b) <= Err;
};
/** @module Math */
/**
* Computes the cartesian product of two arrays.
* @param {Array} a - The first array.
* @param {Array} b - The second array.
* @returns {Array} Returns an array representing the cartesian product of the input arrays.
*/
const cartesianProduct = (a, b) => a.reduce((p, x) => [...p, ...b.map((y) => [x, y])], []);
/**
* Computes the greatest common divisor (GCD) of two numbers.
* @param {number} n1 - The first number.
* @param {number} n2 - The second number.
* @returns {number} Returns the greatest common divisor of the two input numbers.
*/
const pgcd = (n1, n2) => {
let i,
pgcd = 1;
if (n1 == floor(n1) && n2 == floor(n2)) {
for (i = 2; i <= n1 && i <= n2; ++i) {
if (n1 % i == 0 && n2 % i == 0) pgcd = i;
}
return pgcd;
} else console.log("error");
};
/**
* Computes the least common multiple (LCM) of two numbers.
* @param {number} n1 - The first number.
* @param {number} n2 - The second number.
* @returns {number} Returns the least common multiple of the two input numbers.
*/
const ppcm = (n1, n2) => {
let ppcm;
if (n1 == floor(n1) && n2 == floor(n2)) {
ppcm = n1 > n2 ? n1 : n2;
while (true) {
if (ppcm % n1 == 0 && ppcm % n2 == 0) break;
++ppcm;
}
return ppcm;
} else console.log("error");
};
// import { mapfun } from "../mapfun/index.js";
// import {
// add,
// sub,
// mul,
// div,
// modulo
// } from "./arithmetic.js";
const Utils={
// add,
// sub,
// mul,
// div,
// modulo,
zeros,
ones,
nums,
// norm,
// lerp,
// map,
// clamp,
arange,
linspace,
logspace,
geomspace,
// sum,
// prod,
// accum,
cartesianProduct,
ppcm,
pgcd,
// deg2rad,
// rad2deg,
inRange,
isApproximatlyEqual
};
class UINode {
constructor(node){
this.cache = {
node
};
}
isZikoUINode(){
return true
}
get node(){
return this.cache.node;
}
}
// globalThis.node = (node) => new UINode(node);
function parseQueryParams$1(queryString) {
const params = {};
queryString.replace(/[A-Z0-9]+?=([\w|:|\/\.]*)/gi, (match) => {
const [key, value] = match.split('=');
params[key] = value;
});
return params;
}
function defineParamsGetter$1(target ){
Object.defineProperties(target, {
'QueryParams': {
get: function() {
return parseQueryParams$1(globalThis.location.search.substring(1));
},
configurable: false,
enumerable: true
},
'HashParams': {
get: function() {
const hash = globalThis.location.hash.substring(1);
return hash.split("#");
},
configurable: false,
enumerable: true
}
});
}
class UIStore extends Array {
constructor(...args) {
super(...args);
}
clear(){
this.length = 0;
return this;
}
getItemById(id) {
return this.find(n => n.element.id === id);
}
getItemsByTagName(tag) {
return this.filter(n => n.element.tagName.toLowerCase() === tag.toLowerCase());
}
getElementsByClassName(className) {
return this.filter(n => n.element.classList?.contains(className));
}
querySelector(selector) {
const el = globalThis?.document?.querySelector(selector);
if (!el) return null;
return this.find(ui => ui.element === el) || null;
}
querySelectorAll(selector) {
const els = globalThis?.document?.querySelectorAll(selector);
return Array.from(els)
.map(el => this.find(ui => ui.element === el))
.filter(Boolean);
}
}
// create the singleton
const __UI__ = new UIStore();
const __Config__ = {
default:{
target:null,
render:true,
math:{
mode:"deg"
}
},
setDefault:function(pairs){
const keys=Object.keys(pairs);
const values=Object.values(pairs);
for(let i=0; i<keys.length; i++) this.default[keys[i]]=values[i];
},
init:()=>{
// document.documentElement.setAttribute("data-engine","zikojs")
},
renderingMode :"spa",
isSSC : false,
};
const __HYDRATION__ = {
store : new Map(),
index : 0,
register: function(component){
this.store.set(this.index++ , component);
},
reset(){
this.index = 0;
this.store.clear();
}
};
const __CACHE__ = {
ui_index : 0,
get_ui_index:function(){
return this.ui_index ++
},
register_ui: function(UIElement){
}
};
class UseIPC {
#channel;
#eventData;
#handlers;
#uuid;
#subscribers;
#currentRooms;
constructor(name = "") {
this.#channel = new BroadcastChannel(name);
this.#eventData = new Map();
this.#handlers = new Map(); // Map<event, Array<{fn, rooms}>>
this.#uuid = "ziko-channel:" + (Math.random()*10e16); // To Be Replaced by UUID
this.#subscribers = new Set([this.#uuid]);
this.#currentRooms = new Set();
this.#channel.addEventListener("message", (e) => {
const { last_sent_event, userId, eventData, rooms } = e.data;
if (userId === this.#uuid) return; // ignore own messages
// broadcast if no rooms, else check intersection
if (rooms && rooms.length && !rooms.some(r => this.#currentRooms.has(r))) return;
this.#subscribers.add(userId);
this.#eventData = new Map(eventData);
const handlersList = this.#handlers.get(last_sent_event);
if (!handlersList) return;
handlersList.forEach(({ fn, rooms: handlerRooms }) => {
// trigger if listener has no room filter, or intersects subscriber rooms
if (!handlerRooms || handlerRooms.length === 0 ||
!rooms || rooms.some(r => handlerRooms.includes(r))) {
fn(this.#eventData.get(last_sent_event));
}
});
});
}
emit(event, data, rooms) {
this.#eventData.set(event, data);
if(typeof rooms === 'string') rooms = [rooms];
this.#channel.postMessage({
eventData: Array.from(this.#eventData.entries()),
last_sent_event: event,
userId: this.#uuid,
rooms: rooms && rooms.length ? rooms : undefined
});
return this;
}
on(event, handler = console.log, rooms) {
if (!this.#handlers.has(event)) this.#handlers.set(event, []);
if(typeof rooms === 'string') rooms = [rooms];
this.#handlers.get(event).push({ fn: handler, rooms });
return this;
}
off(event, handler) {
if (!this.#handlers.has(event)) return this;
this.#handlers.set(
event,
this.#handlers.get(event).filter(h => h.fn !== handler)
);
return this;
}
once(event, handler, rooms) {
const wrapper = (data) => {
handler(data);
this.off(event, wrapper);
};
this.on(event, wrapper, rooms);
return this;
}
join(...rooms) {
rooms.forEach(r => this.#currentRooms.add(r));
return this;
}
leave(...rooms) {
if (!rooms.length) this.#currentRooms.clear();
else rooms.forEach(r => this.#currentRooms.delete(r));
return this;
}
close() {
this.#channel.close();
return this;
}
}
const useIPC = (name) => new UseIPC(name);
class UseStorage {
constructor(storage, globalKey, initialValue, use_channel = true) {
this.cache = {
storage,
globalKey,
channel: use_channel ? useIPC(`Ziko:useStorage-${globalKey}`) : null,
oldItemKeys: new Set()
};
this.#init(initialValue, use_channel);
}
get items() {
const raw = this.cache.storage.getItem(this.cache.globalKey);
if (!raw) return {};
try {
return JSON.parse(raw);
} catch {
return {};
}
}
#maintain() {
const items = this.items;
this.cache.oldItemKeys.forEach(k => delete this[k]);
for (const key in items) {
this[key] = items[key];
this.cache.oldItemKeys.add(key);
}
}
#init(initialValue, use_channel) {
if (use_channel && this.cache.channel) this.cache.channel.on("Ziko-Storage-Updated", () => this.#maintain());
if (!initialValue) {
this.#maintain();
return;
}
if (this.cache.storage.getItem(this.cache.globalKey)) {
const existing = this.items;
Object.keys(existing).forEach(k => this.cache.oldItemKeys.add(k));
this.#maintain();
}
else this.set(initialValue);
}
set(data) {
this.cache.storage.setItem(this.cache.globalKey, JSON.stringify(data));
if (this.cache.channel) this.cache.channel.emit("Ziko-Storage-Updated", data);
this.#maintain();
return this;
}
add(data) {
this.set({
...this.items,
...data
});
return this;
}
remove(...keys) {
const items = { ...this.items };
keys.forEach(key => {
delete items[key];
delete this[key];
this.cache.oldItemKeys.delete(key);
});
this.set(items);
return this;
}
get(key) {
return this.items[key];
}
clear() {
this.cache.storage.removeItem(this.cache.globalKey);
this.cache.oldItemKeys.forEach(k => delete this[k]);
this.cache.oldItemKeys.clear();
this.#maintain();
return this;
}
onStorageUpdated(callback) {
if (this.cache.channel) {
this.cache.channel.on("Ziko-Storage-Updated", callback);
}
return this;
}
}
// factory functions
const useLocaleStorage = (key, initialValue, use_channel = true) =>
new UseStorage(localStorage, key, initialValue, use_channel);
const useSessionStorage = (key, initialValue, use_channel = true) =>
new UseStorage(sessionStorage, key, initialValue, use_channel);
var __State__ = {
store : new Map(),
index : 0,
session_storage : null,
register: function(state){
if(!undefined.SSR && undefined.DEV){
if(!this.session) this.session_storage = useSessionStorage('ziko-state', {});
const savedValue = this.session_storage.get(this.index);
if(!savedValue) this.session_storage.add({[this.index] : state.value});
else state.value = savedValue;
}
this.store.set(this.index++, state);
},
update: function(index, value){
if(!undefined.SSR && undefined.DEV){
this.session_storage.add({[index] : value});
}
},
};
function __init__global__(){
if ( !globalThis?.__Ziko__ ){
globalThis.__Ziko__ = {
__UI__,
__HYDRATION__,
__State__,
__Config__,
__CACHE__,
};
defineParamsGetter$1(__Ziko__);
}
}
__init__global__();
class UIElementCore extends UINode{
constructor(){
super();
}
init(element, name, type, render){
this.target = globalThis.__Ziko__.__Config__.default.target||globalThis?.document?.body;
if(typeof element === "string") {
switch(type){
case "html" : {
element = globalThis?.document?.createElement(element);
// console.log('1')
} break;
case "svg" : {
element = globalThis?.document?.createElementNS("http://www.w3.org/2000/svg", element);
// console.log('2')
} break;
default : throw Error("Not supported")
}
}
else this.target = element?.parentElement;
Object.assign(this.cache, {
name,
isInteractive : false,
parent:null,
isBody:false,
isRoot:false,
isHidden: false,
isFrozzen:false,
legacyParent : null,
attributes: {},
filters: {},
temp:{}
});
this.events = {
ptr:null,
mouse:null,
wheel:null,
key:null,
drag:null,
drop:null,
click:null,
clipboard:null,
focus:null,
swipe:null,
custom:null,
};
this.observer={
resize:null,
intersection:null
};
if(element) Object.assign(this.cache,{element});
// useDefaultStyle && this.style({
// position: "relative",
// boxSizing:"border-box",
// margin:0,
// padding:0,
// width : "auto",
// height : "auto"
// });
this.items = new UIStore();
globalThis.__Ziko__.__UI__[this.cache.name]?globalThis.__Ziko__.__UI__[this.cache.name]?.push(this):globalThis.__Ziko__.__UI__[this.cache.name]=[this];
element && render && this?.render?.();
globalThis.__Ziko__.__UI__.push(this);
}
get element(){
return this.cache.element;
}
[Symbol.iterator]() {
return this.items[Symbol.iterator]();
}
maintain() {
for (let i = 0; i < this.items.length; i++) {
Object.defineProperty(this, i, {
value: this.items[i],
writable: true,
configurable: true,
enumerable: false
});
}
}
isInteractive(){
return this.cache.isInteractive;
}
isUIElement(){
return true;
}
}
function register_to_class(target, ...mixins){
mixins.forEach(n => _register_to_class_(target, n));
}
function _register_to_class_(target, mixin) {
const descriptors = Object.getOwnPropertyDescriptors(mixin);
for (const key of Reflect.ownKeys(descriptors)) {
const desc = descriptors[key];
if ('get' in desc || 'set' in desc || typeof desc.value !== 'function') {
Object.defineProperty(Object.getPrototypeOf(target), key, desc);
} else if (typeof desc.value === 'function') {
if (!Object.getPrototypeOf(target).hasOwnProperty(key)) {
Object.defineProperty(Object.getPrototypeOf(target), key, desc);
}
}
}
}
// export function mount(target = this.target) {
// if(this.isBody) return ;
// if(target?.isUIElement)target=target.element;
// this.target=target;
// this.target?.appendChild(this.element);
// return this;
// }
// export function unmount(){
// if(this.cache.parent)this.cache.parent.remove(this);
// else if(this.target?.children?.length && [...this.target?.children].includes(this.element)) this.target.removeChild(this.element);
// return this;
// }
// export function mountAfter(target = this.target, t = 1) {
// setTimeout(() => this.mount(), t);
// return this;
// }
// export function unmountAfter(t = 1) {
// setTimeout(() => this.unmount(), t);
// return this;
// }
function mount(target = this.target, delay = 0) {
if (delay > 0) {
setTimeout(() => this.mount(target, 0), delay);
return this;
}
if (this.isBody) return this;
if (target?.isUIElement) target = target.element;
this.target = target;
this.target?.appendChild(this.element);
return this;
}
function unmount(delay = 0) {
if (delay > 0) {
setTimeout(() => this.unmount(0), delay);
return this;
}
if (this.cache.parent) {
this.cache.parent.remove(this);
} else if (
this.target?.children?.length &&
[...this.target.children].includes(this.element)
) {
this.target.removeChild(this.element);
}
return this;
}
var LifecycleMethods = /*#__PURE__*/Object.freeze({
__proto__: null,
mount: mount,
unmount: unmount
});
if(!globalThis.__Ziko__) __init__global__();
function useState(initialValue) {
const {store, index} = __Ziko__.__State__;
__Ziko__.__State__.register({
value : initialValue,
subscribers : new Set(),
paused : false
});
let current = store.get(index);
function getValue() {
return {
value: current.value,
isStateGetter: () => true,
_subscribe: (fn) => current.subscribers.add(fn),
};
}
function setValue(newValue) {
if (current.paused) return;
if (typeof newValue === "function") {
newValue = newValue(current.value);
}
if (newValue !== current.value) {
current.value = newValue;
current.subscribers.forEach(fn => fn(current.value));
__Ziko__.__State__.update(index, newValue);
}
}
const controller = {
pause: () => { current.paused = true; },
resume: () => { current.paused = false; },
clear: () => { current.subscribers.clear(); },
force: (newValue) => {
if (typeof newValue === "function") newValue = newValue(current.value);
current.value = newValue;
current.subscribers.forEach(fn => fn(current.value));
},
getSubscribers: () => new Set(current.subscribers),
};
return [getValue, setValue, controller];
}
const isStateGetter = (arg) => {
return typeof arg === 'function' && arg?.()?.isStateGetter?.();
};
const camel2hyphencase$1 = (text = '') => text.replace(/[A-Z]/g, match => '-' + match.toLowerCase());
const is_camelcase$1 = (text = '') =>{
if (text.length === 0) return false;
const camelCasePattern = /^[a-z][a-zA-Z0-9]*$/;
return camelCasePattern.test(text);
};
class ZikoUIText extends UINode {
constructor(...value) {
super("span", "text", false, ...value);
this.element = globalThis?.document?.createTextNode(...value);
}
isText(){
return true
}
}
const text = (...str) => new ZikoUIText(...str);
async function __addItem__(adder, pusher, ...ele) {
if (this.cache.isFrozzen) {
console.warn("You can't append new item to frozzen element");
return this;
}
for (let i = 0; i < ele.length; i++) {
if (["number", "string"].includes(typeof ele[i])) ele[i] = text(ele[i]);
// Fix Items Latter
if (ele[i] instanceof Function) {
const getter = ele[i]();
if (getter.isStateGetter) {
ele[i] = text(getter.value);
getter._subscribe(
(newValue) => (ele[i].element.textContent = newValue),
ele[i]
);
// this.element.appendChild(textNode);
}
}
if (typeof globalThis?.Node === "function" && ele[i] instanceof globalThis?.Node) ele[i] = new this.constructor(ele[i]);
if (ele[i]?.isZikoUINode) {
ele[i].cache.parent = this;
this.element?.[adder](ele[i].element);
ele[i].target = this.element;
this.items[pusher](ele[i]);
}
else if(ele[i] instanceof Promise){
const UIEle = await ele[i];
UIEle.cache.parent = this;
this.element?.[adder](UIEle.element);
UIEle.target = this.element;
this.items[pusher](UIEle);
}
else if (ele[i] instanceof Object) {
if (ele[i]?.style) this.style(ele[i]?.style);
if (ele[i]?.attr) {
Object.entries(ele[i].attr).forEach((n) =>
this.setAttr("" + n[0], n[1]),
);
}
}
}
this.maintain();
return this;
}
function _set_attrs_(name, value){
if(globalThis.SVGAElement && this.element instanceof globalThis.SVGAElement) name = is_camelcase$1(name) ? camel2hyphencase$1(name) : name;
if(this?.attr[name] && this?.attr[name]===value) return;
if(isStateGetter(value)){
const getter = value();
getter._subscribe(
(newValue) => this.element?.setAttribute(name, newValue),
this
);
}
else this.element?.setAttribute(name, value);
Object.assign(this.cache.attributes, {[name]:value});
}
// import {
// is_camelcase,
// camel2hyphencase
// } from '../../data/string/index.js'
function setAttr(name, value) {
if(name instanceof Object){
const [names,values]=[Object.keys(name),Object.values(name)];
for(let i=0;i<names.length;i++){
if(values[i] instanceof Array)value[i] = values[i].join(" ");
_set_attrs_.call(this, names[i], values[i]);
}
}
else {
if(value instanceof Array) value = value.join(" ");
_set_attrs_.call(this, name, value);
}
return this;
}
function removeAttr(...names) {
for(let i=0;i<names.length;i++)this.element?.removeAttribute(names[i]);
return this;
}
function getAttr(name){
name = is_camelcase(name) ? camel2hyphencase(name) : name;
return this.element.attributes[name].value;
}
function setContentEditable(bool = true) {
this.setAttr("contenteditable", bool);
return this;
}
var AttrsMethods = /*#__PURE__*/Object.freeze({
__proto__: null,
getAttr: getAttr,
removeAttr: removeAttr,
setAttr: setAttr,
setContentEditable: setContentEditable
});
function append(...ele) {
__addItem__.call(this, "append", "push", ...ele);
return this;
}
function prepend(...ele) {
this.__addItem__.call(this, "prepend", "unshift", ...ele);
return this;
}
function insertAt(index, ...ele) {
if (index >= this.element.children.length) this.append(...ele);
else
for (let i = 0; i < ele.length; i++) {
if (["number", "string"].includes(typeof ele[i])) ele[i] = text(ele[i]);
this.element?.insertBefore(ele[i].element, this.items[index].element);
this.items.splice(index, 0, ele[i]);
}
return this;
}
function remove(...ele) {
const remove = (ele) => {
if (typeof ele === "number") ele = this.items[ele];
if (ele?.isUIElement) this.element?.removeChild(ele.element);
this.items = this.items.filter((n) => n !== ele);
};
for (let i = 0; i < ele.length; i++) remove(ele[i]);
for (let i = 0; i < this.items.length; i++)
Object.assign(this, { [[i]]: this.items[i] });
// Remove from item
return this;
}
function clear(){
this?.items?.forEach(n=>n.unmount());
this.element.innerHTML = "";
return this;
}
function replaceElementWith(new_element){
this.cache.element.replaceWith(new_element);
this.cache.element = new_element;
// To do : Dispose Events and States
return this
}
function after(ui){
if(ui?.isUIElement) ui=ui.element;
this.element?.after(ui);
return this;
}
function before(ui){
if(ui?.isUIElement) ui=ui.element;
this.element?.before(ui);
return this;
}
var DomMethods = /*#__PURE__*/Object.freeze({
__proto__: null,
after: after,
append: append,
before: before,
clear: clear,
insertAt: insertAt,
prepend: prepend,
remove: remove,
replaceElementWith: replaceElementWith
});
const EventsMap = {
'Click' : [
'Click',
'DblClick',
'ClickAway'
],
'Ptr' : [
'PtrMove',
'PtrDown',
'PtrUp',
'PtrLeave',
'PtrEnter',
'PtrOut',
'PtrCancel'
],
'Mouse' : [
'MouseMove',
'MouseDown',
'MouseUp',
'MouseEnter',
'MouseLeave',
'MouseOut'
],
// 'Touch' : [],
'Key' : [
'KeyDown',
'KeyPress',
'KeyUp'
],
'Clipboard':[
'Copy',
'Cut',
'Paste'
],
'Focus':[
'focus',
'blur'
],
'Drag':[
"Drag",
"DragStart",
"DragEnd",
"Drop"
],
'Wheel': [
'Wheel'
],
// 'Media':[
// ],
// 'Hash':[
// "HashChange"
// ]
'View':[
'EnterView',
'ExitView',
'ResizeView'
],
'Swipe':[
'SwipeLeft',
'SwipeUp',
'SwipeRight',
'SwipeDown'
]
};
function event_controller(e, event_name, details_setter, customizer) {
this.cache.currentEvent = event_name;
this.cache.event = e;
details_setter?.call(this);
if (customizer?.hasOwnProperty('prototype')) customizer?.call(this);
else customizer?.call(null, this);
if (this.cache.preventDefault[event_name]) e.preventDefault();
if (this.cache.stopPropagation[event_name]) e.stopPropagation();
if (this.cache.stopImmediatePropagation[event_name]) e.stopImmediatePropagation();
// Call the single callback if it exists
this.cache.callbacks[event_name]?.(this);
}
function toggle_event_listener(method, ...events) {
const keys = events.length === 0
? Object.keys(this.cache.paused)
: events;
keys.forEach(key => {
if (!this.cache.paused.hasOwnProperty(key)) return;
this.targetElement?.[method](
key,
this.cache.__controllers__[key],
this.cache.options[key]
);
this.cache.paused[key] = method === 'removeEventListener';
});
return this;
}
const getEvent=(event = "")=>{
if(event.startsWith("Ptr"))return `pointer${event.split("Ptr")[1].toLowerCase()}`;
return event.toLowerCase()
};
class ZikoEvent {
constructor(signature, target = null, Events = [], details_setter, customizer){
this.target = target;
this.cache = {
signature,
currentEvent : null,
event: null,
options : {},
preventDefault : {},
stopPropagation : {},
stopImmediatePropagation : {},
paused : {},
callbacks : {},
__controllers__:{}
};
if (Events) this._register_events(Events, details_setter, customizer);
}
_register_events(Events, details_setter, customizer, REGISTER_METHODES = true) {
const events = Events?.map(n => getEvent(n));
events?.forEach((event, i) => {
this.cache.preventDefault[event] = false;
this.cache.options[event] = {};
this.cache.paused[event] = false;
this.cache.__controllers__[event] = (e) =>
event_controller.call(this, e, event, details_setter, customizer);
if (REGISTER_METHODES) {
this[`on${Events[i]}`] = (callback) =>
this.__onEvent(event, this.cache.options[event], {}, callback);
}
});
return this;
}
__onEvent(event, options, dispose, callback) {
if (!callback) return this;
this.cache.callbacks[event] = callback;
this.__handle(event, this.cache.__controllers__[event], options, dispose);
return this;
}
get targetElement(){
return this.target?.element;
}
get isParent(){
return this.target?.element === this.event?.srcElement;
}
get item(){
return this.target.find(n => n.element == this.event?.srcElement)?.[0];
}
get currentEvent(){
return this.cache.currentEvent;
}
get event(){
return this.cache.event;
}
get detail(){
return this.cache.event.detail
}
setTarget(UI){
this.target = UI;
return this;
}
__handle(event, handler, options){
this.targetElement?.addEventListener(event, handler, options);
return this;
}
#override(method, ...events) {
const keys = events.length === 0 ? Object.keys(this.cache[method]) : events;
keys.forEach(e => {
if (this.cache[method].hasOwnProperty(e)) this.cache[method][e] = true;
});
return this;
}
preventDefault(...events) {
return this.#override('preventDefault', ...events);
}
stopPropagation(...events) {
return this.#override('stopPropagation', ...events);
}
stopImmediatePropagation(...events) {
return this.#override('stopImmediatePropagation', ...events);
}
setEventOptions(event, options){
const evt = getEvent(event);
this.pause();
Object.assign(this.cache.options[evt], options);
this.resume();
return this;
}
pause(...events) {
return toggle_event_listener.call(this, 'removeEventListener', ...events)
}
resume(...events) {
return toggle_event_listener.call(this, 'addEventListener', ...events);
}
dispose(){
this.pause();
this.target.events[this.cache.signature] = null;
return this;
}
}
function key_details_setter(){
switch(this.currentEvent){
case "keydown" : {
this.kd = this.event.key;
} break;
case "keypress" : {
this.kp = this.event.key;
} break;
case "keyup" : {
this.ku = this.event.key;
} break;
}
}
function ptr_details_setter() {
const rect = this.targetElement.getBoundingClientRect();
const e = this.event;
let x = (e.clientX - rect.left) | 0;
let y = (e.clientY - rect.top) | 0;
if(this.cache.useNormalisedCoordinates){
const w = this.targetElement.clientWidth;
const h = this.targetElement.clientHeight;
x = +((x / w) * 2 - 1).toFixed(8);
y = +((y / h) * -2 + 1).toFixed(8);
}
switch (this.currentEvent) {
case "pointerdown":
this.dx = x;
this.dy = y;
this.isDown = true;
break;
case "pointermove":
this.mx = x;
this.my = y;
this.isMoving = true;
break;
case "pointerup":
this.ux = x;
this.uy = y;
this.isDown = false;
this.isMoving = false;
break;
}
}
function mouse_details_setter() {
const rect = this.targetElement.getBoundingClientRect();
const e = this.event;
let x = (e.clientX - rect.left) | 0;
let y = (e.clientY - rect.top) | 0;
if(this.cache.useNormalisedCoordinates){
const w = this.targetElement.clientWidth;
const h = this.targetElement.clientHeight;
x = +((x / w) * 2 - 1).toFixed(8);
y = +((y / h) * -2 + 1).toFixed(8);
}
switch (this.currentEvent) {
case "mousedown":
this.dx = x;
this.dy = y;
this.isDown = true;
break;
case "mousemove":
this.mx = x;
this.my = y;
this.isMoving = true;
break;
case "mouserup":
this.ux = x;
this.uy = y;
this.isDown = false;
this.isMoving = false;
break;
}
}
function touch_details_setter() {
const e = this.event;
const touch = e.touches?.[0] || e.changedTouches?.[0];
if (!touch) return; // should never happen but safe
const rect = this.targetElement.getBoundingClientRect();
let x = touch.clientX - rect.left;
let y = touch.clientY - rect.top;
if(this.cache.useNormalisedCoordinates){
const w = this.targetElement.clientWidth;
const h = this.targetElement.clientHeight;
x = +((x / w) * 2 - 1).toFixed(8);
y = +((y / h) * -2 + 1).toFixed(8);
}
switch (this.currentEvent) {
case "touchstart":
this.dx = x;
this.dy = y;
this.isDown = true;
break;
case "touchmove":
this.mx = x;
this.my = y;
this.isMoving = true;
break;
case "touchend":
this.ux = x;
this.uy = y;
this.isDown = false;
break;
}
}
class CoordinatesBasedEvent extends ZikoEvent{
constructor(signature, target = null, Events = [], details_setter, customizer){
super(signature, target, Events, details_setter, customizer);
Object.assign(this.cache,{
useNormalisedCoordinates : false
});
this.isDown = false;
this.isMoving = false;
this.dx = 0;
this.dy = 0;
this.mx = 0;
this.my = 0;
this.ux = 0;
this.uy = 0;
}
get isDragging(){
return this.isDown && this.isMoving
}
useNormalisedCoordinates(enable = true){
this.cache.useNormalisedCoordinates = enable;
return this;
}
}
class ClickAwayEvent extends Event {
constructor(originalEvent, targetElement) {
super("clickaway", { bubbles: true, cancelable: true });
this.originalEvent = originalEvent;
this.targetElement = targetElement;
}
}
function register_click_away_event(element) {
console.log(element);
function handler(e) {
if (!element.contains(e.target)) {
const clickAwayEvent = new ClickAwayEvent(e, element);
element.dispatchEvent(clickAwayEvent);
}
}
globalThis?.document?.addEventListener("click", handler);
return () => globalThis?.document?.removeEventListener("click", handler);
}
// // Example usage
// const box = document.querySelector("#my-box");
// const stop = listenClickAway(box);
// box.addEventListener("clickaway", (e) => {
// console.log("Clicked outside box!", e);
// });
// // later, you can stop listening:
// // stop();
const debounce=(fn,delay=1000)=>{
let id;
return (...args) => id ? clearTimeout(id) : setTimeout(()=>fn(...args),delay);
};
const throttle=(fn,delay)=>{
let lastTime=0;
return (...args) => {
const now = new Date().getTime();
if(now-lastTime < delay) return;
lastTime = now;
fn(...args);
}
};
class ViewEvent extends CustomEvent {
constructor(type, detail, { bubbles = true, cancelable = true } = {}) {
super(type, { detail, bubbles, cancelable });
}
}
function register_view_event(
element,
{
intersection = true,
resize = true,
threshold = 0,
throttleResize = 100,
throttleEnterExit = 0
} = {}
) {
let intersectionObserver, resizeObserver;
const resizeCallback = entries => {
for (let entry of entries) {
const { width, height } = entry.contentRect;
element.dispatchEvent(
new ViewEvent("resizeview", {
width,
height,
entry
})
);
}
};
const throttledResize = throttleResize > 0
? throttle(resizeCallback, throttleResize)
: resizeCallback;
const intersectionCallback = entries => {
for (let entry of entries) {
const type = entry.isIntersecting ? "enterview" : "exitview";
element.dispatchEvent(new ViewEvent(type, entry));
}
};
const throttledIntersections = throttleEnterExit > 0
? throttle(intersectionCallback, throttleEnterExit)
: intersectionCallback;
if (intersection) {
intersectionObserver = new IntersectionObserver(throttledIntersections, { threshold });
intersectionObserver.observe(element);
}
if (resize) {
resizeObserver = new ResizeObserver(throttledResize);
resizeObserver.observe(element);
}
// ---- UNREGISTER ----
return () => {
if (intersectionObserver) {
intersectionObserver.unobserve(element);
intersectionObserver.disconnect();
}
if (resizeObserver) {
resizeObserver.unobserve(element);
resizeObserver.disconnect();
}
};
}
class SwipeEvent extends CustomEvent {
constructor(type, detail) {
super(type, {
detail,
bubbles: true,
cancelable: true
});
}
}
function register_swipe_event(
element,
threshold = 50,
restraint = 100,
allowedTime = 500
) {
let startX = 0,
startY = 0,
startTime = 0,
isPointerDown = false;
function onPointerDown(e) {
startX = e.clientX;
startY = e.clientY;
startTime = performance.now();
isPointerDown = true;
}
function onPointerUp(e) {
if (!isPointerDown) return;
isPointerDown = false;
const distX = e.clientX - startX;
const distY = e.clientY - startY;
const elapsed = performance.now() - startTime;
let direction = null;
let eventName = null;
if (elapsed <= allowedTime) {
if (Math.abs(distX) >= threshold && Math.abs(distY) <= restraint) {
direction = distX < 0 ? "left" : "right";
eventName = "swipe" + direction;
}
else if (Math.abs(distY) >= threshold && Math.abs(distX) <= restraint) {
direction = distY < 0 ? "up" : "down";
eventName = "swipe" + direction;
}
}
// Emit event
if (eventName) {
element.dispatchEvent(
new SwipeEvent(eventName, {
direction,
distX,
distY,
originalEvent: e
})
);
}
}
element.addEventListener("pointerdown", onPointerDown, { passive: true });
element.addEventListener("pointerup", onPointerUp, { passive: true });
return () => {
element.removeEventListener("pointerdown", onPointerDown);
element.removeEventListener("pointerup", onPointerUp);
};
}
const bind_click_event = (target, customizer) => {
register_click_away_event(target.element);
return new ZikoEvent(
'click',
target,
EventsMap.Click,
null,
customizer
);
};
const bind_clipboard_event = (target, customizer) => new ZikoEvent(
'clipboard',
target,
EventsMap.Clipboard,
null,
customizer
);
const bind_drag_event = (target, customizer) => new ZikoEvent(
'drag',
target,
EventsMap.Drag,
null,
customizer
);
const bind_focus_event = (target, customizer) => new ZikoEvent(
'focus',
target,
EventsMap.Focus,
null,
customizer
);
const bind_key_event = (target, customizer) => new ZikoEvent(
'key',
target,
EventsMap.Key,
key_details_setter,
customizer
);
const bind_mouse_event = (target, customizer) => new CoordinatesBasedEvent(
'mouse',
target,
EventsMap.Mouse,
mouse_details_setter,
customizer
);
const bind_pointer_event = (target, customizer) => new CoordinatesBasedEvent(
'ptr',
target,
EventsMap.Ptr,
ptr_details_setter,
customizer
);
const bind_touch_event = (target, customizer) => new CoordinatesBasedEvent(
'touch',
target,
EventsMap.Touch,
touch_details_setter,
customizer
);
const bind_wheel_event = (target, customizer) => new ZikoEvent(
'wheel',
target,
EventsMap.Wheel,
null,
customizer
);
const bind_view_event = (target, customizer) => {
register_view_event(target.element);
return new ZikoEvent(
'view',
target,
EventsMap.View,
null,
customizer
)
};
const bind_swipe_event = (target, customizer) => {
register_swipe_event(target.element);
return new ZikoEvent(
'swipe',
target,
EventsMap.Swipe,
null,
customizer
)
};
class ZikoCustomEvent extends ZikoEvent{
constructor(target, events, customizer){
super('custom', target, events, details_setter, customizer);
}
_register_events(events){
super._register_events(events, null, null, false);
return this;
}
emit(event_name, detail = {}){
const event = new CustomEvent(event_name, {
detail,
bubbles: true,
cancelable: true
});
this.targetElement.dispatchEvent(event);
return this;
}
on(event_name, ...callbacks){
if(!this.cache.options.hasOwnProperty(event_name)) this._register_events([event_name]);
this.__onEvent(event_name, this.cache.options[event_name], {}, ...callbacks);
return this;
}
}
function details_setter(){
}
const bind_custom_event = (target, events, customizer) => new ZikoCustomEvent(target, events, customizer);
const binderMap = {
ptr: bind_pointer_event,
mouse : bind_mouse_event,
key: bind_key_event,
click : bind_click_event,
drag : bind_drag_event,
clipboard : bind_clipboard_event,
focus : bind_focus_event,
wheel : bind_wheel_event,
view : bind_view_event,
swipe : bind_swipe_event
};
const EventsMethodes = {
on(event_name,...callbacks){
if(!this.events.custom)this.events.custom = bind_custom_event(this);
this.events.custom.on(event_name,...callbacks);
return this;
},
emit(event_name,detail={}){
if(!this.events.custom)this.events.custom = bind_custom_event(this);
this.events.custom.emit(event_name,detail);
return this;
}
};
Object.entries(EventsMap).forEach(([name, eventList]) => {
const lname = name.toLowerCase();
eventList.forEach(event => {
const methodName = `on${event}`;
EventsMethodes[methodName] = function (callbacks) {
if (!this.events[lname]) this.events[lname] = binderMap[lname](this);
this.events[lname][methodName](callbacks);
return this;
};
});
});
function at(index) {
return this.items.at(index);
}
function forEach(callback) {
this.items.forEach(callback);
return this;
}
function map(callback) {
return this.items.map(callback);
}
function find(condition) {
return this.items.filter(condition);
}
var IndexingMethods = /*#__PURE__*/Object.freeze({
__proto__: null,
at: at,
find: find,
forEach: forEach,
map: map
});
function style(styles){
if(!this.element?.style) return this;
for(let key in styles){
const value = styles[key];
if(isStateGetter(value)){
const getter = value();
Object.assign(this.element.style, {[key] : getter.value});
getter._subscribe(
(newValue) => {
console.log({newValue});
Object.assign(this.element.style, {[key] : newValue});
},
// this
);
}
else Object.assign(this.element.style, {[key] : value});
}
return this;
}
function size(width, height){
return this.style({width, height})
}
function hide(){
}
function show(){
}
function animate(keyframe, {duration=1000, iterations=1, easing="ease"}={}){
this.element?.animate(keyframe,{duration, iterations, easing});
return this;
}
var StyleMethods = /*#__PURE__*/Object.freeze({
__proto__: null,
animate: animate,
hide: hide,
show: show,
size: size,
style: style
});
// import {
// // useCustomEvent,
// // useSwipeEvent,
// // watchIntersection,
// // watchSize,
// // watchAttr,
// // watchChildren
// } from "../../--reactivity-deprecated/events/custom-event.js"
let UIElement$1 = class UIElement extends UIElementCore{
constructor({element, name ='', type='html', render = __Ziko__.__Config__.default.render}={}){
super();
// console.log({type})
// console.log(this)
register_to_class(
this,
LifecycleMethods,
AttrsMethods,
DomMethods,
StyleMethods,
IndexingMethods,
EventsMethodes
);
// console.log(EventsMethodes)
if(element)this.init(element, name, type, render);
}
get element(){
return this.cache.element;
}
isInteractive(){
return this.cache.isInteractive;
}
useClient(directive){
if(!this.cache.isInteractive){
this.element.setAttribute('data-hydration-index', globalThis.__Ziko__.__HYDRATION__.index);
globalThis.__Ziko__.__HYDRATION__.register(() => this);
this.cache.isInteractive = true;
}
if(directive)this.element.setAttribute('data-hydration-directive', directive);
return this;
}
// isUIElement(){
// return true;
// }
get st(){
return this.cache.style;
}
get attr(){
return this.cache.attributes;
}
get evt(){
return this.events;
}
get html(){
return this.element.innerHTML;
}
get text(){
return this.element.textContent;
}
get isBody(){
return this.element === globalThis?.document.body;
}
get parent(){
return this.cache.parent;
}
get width(){
return this.element.getBoundingClientRect().width;
}
get height(){
return this.element.getBoundingClientRect().height;
}
get top(){
return this.element.getBoundingClientRect().top;
}
get right(){
return this.element.getBoundingClientRect().right;
}
get bottom(){
return this.element.getBoundingClientRect().bottom;
}
get left(){
return this.element.getBoundingClientRect().left;
}
// clone(render=false) {
// // UI.__proto__=this.__proto__;
// // if(this.items.length){
// // const items = [...this.items].map(n=>n.clone());
// // UI.append(...items);
// // }
// // else UI.element=this.element.cloneNode(true);
// // return UI.mount(render);
// }
// [Symbol.iterator]() {
// return this.items[Symbol.iterator]();
// }
// maintain() {
// for (let i = 0; i < this.items.length; i++) {
// Object.defineProperty(this, i, {
// value: this.items[i],
// writable: true,
// configurable: true,
// enumerable: false
// });
// }
// }
// freeze(freeze){
// this.cache.isFrozzen=freeze;
// return this;
// }
// setTarget(tg) {
// if(this.isBody) return ;
// if (tg?.isUIElement) tg = tg.element;
// this.unmount();
// this.target = tg;
// this.mount();
// return this;
// }
// describe(label){
// if(label)this.setAttr("aria-label",label)
// }
// get children() {
// return [...this.element.children];
// }
// get cloneElement() {
// return this.element.cloneNode(true);
// }
// setClasses(...value) {
// this.setAttr("class", value.join(" "));
// return this;
// }
// get classes(){
// const classes=this.element.getAttribute("class");
// return classes===null?[]:classes.split(" ");
// }
// addClass() {
// /*this.setAttr("class", value);
// return this;*/
// }
// setId(id) {
// this.setAttr("id", id);
// return this;
// }
// get id() {
// return this.element.getAttribute("id");
// }
// To Fix
// onKeysDown({keys=[],callback}={}){
// if(!this.events.key)this.events.key = useKeyEvent(this);
// this.events.key.handleSuccessifKeys({keys,callback});
// return this;
// }
// watchAttr(callback){
// if(!this.observer.attr)this.observer.attr = watchAttr(this,callback);
// return this;
// }
// watchChildren(callback){
// if(!this.observer.children)this.observer.children = watchChildren(this,callback);
// return this;
// }
// watchSize(callback)Remplaced By on onViewResize
// watchIntersection(callback,config) Remplaced By onViewEnter and onViewExit
};
class UIView extends UIElement$1{
constructor(...items){
super({element : 'div', name : 'view'});
this.append(...items);
}
}
const View = (...items) => new UIView(...items);
const HTMLTags = [
'a',
'abb',
'address',
'area',
'article',
'aside',
'audio',
'b',
'base',
'bdi',
'bdo',
'blockquote',
'br',
'button',
'canvas',
'caption',
'cite',
'code',
'col',
'colgroup',
'data',
'datalist',
'dd',
'del',
'details',
'dfn',
'dialog',
'div',
'dl',
'dt',
'em',
'embed',
'fieldset',
'figcaption',
'figure',
'footer',
'form',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'header',
'hgroup',
'hr',
'i',
'iframe',
'img',
'ipnut',
'ins',
'kbd',
'label',
'legend',
'li',
'main',
'map',
'mark',
'menu',
'meter',
'nav',
'object',
'ol',
'optgroup',
'option',
'output',
'p',
'param',
'picture',
'pre',
'progress',
'q',
'rp',
'rt',
'ruby',
's',
'samp',
'search',
'section',
'select',
'small',
'source',
'span',
'strong',
'sub',
'summary',
'sup',
'table',
'tbody',
'td',
'template',
'textarea',
'tfoot',
'th',
'thead',
'time',
'title',
'tr',
'track',
'u',
'ul',
'var',
'video',
'wbr'
];
const SVGTags = [
"svg", "g", "defs", "symbol", "use", "image", "switch",
"rect", "circle", "ellipse", "line", "polyline", "polygon", "path",
"text", "tspan", "textPath", "altGlyph", "altGlyphDef", "altGlyphItem", "glyph", "glyphRef",
"linearGradient", "radialGradient", "pattern", "solidColor",
"filter", "feBlend", "feColorMatrix", "feComponentTransfer", "feComposite", "feConvolveMatrix",
"feDiffuseLighting", "feDisplacementMap", "feDropShadow", "feFlood", "feFuncA", "feFuncR", "feFuncG", "feFuncB",
"feGaussianBlur", "feImage", "feMerge", "feMergeNode", "feMorphology", "feOffset", "feSpecularLighting",
"feTile", "feTurbulence",
"animate", "animateMotion", "animateTransform", "set",
"script",
"desc", "title", "metadata", "foreignObject"
];
// const h=(tag, attributes = {}, ...children)=> _h(tag, "html", attributes, ...children);
// const s=(tag, attributes = {}, ...children)=> _h(tag, "svg", attributes, ...children);
const tags = new Proxy({}, {
get(target, prop) {
if (typeof prop !== 'string') return undefined;
let tag = prop.replaceAll("_","-").toLowerCase();
let type ;
if(HTMLTags.includes(tag)) type = 'html';
if(SVGTags.includes(tag)) type = 'svg';
return (...args)=>{
// Fix undefined
// console.log(isStateGetter(args[0]))
// console.log(!!args)
if(args.length === 0) {
// console.log('length 0')
return new UIElement$1({element : tag, name : tag, type})
}
if(
['string', 'number'].includes(typeof args[0])
|| args[0] instanceof UIElement$1
|| (typeof args[0] === 'function' && args[0]().isStateGetter())
) return new UIElement$1({element : tag, name : tag, type}).append(...args);
// console.log(args[0])
return new UIElement$1({element : tag, type}).setAttr(args.shift()).append(...args)
}
// if(SVGTags.includes(tag)) return (...args) => new UIElement(tag,"",{el_type : "svg"}).append(...args);
// return (...args)=>{
// if(!(args[0] instanceof UIElement) && args[0] instanceof Object){
// let attributes = args.shift()
// return new UIElement(tag).setAttr(attributes).append(...args)
// }
// return new UIElement(tag).append(...args);
// }
// // switch(tag){
// case "html" : globalThis?.document?.createElement("html")
// case "head" :
// case "style" :
// case "link" :
// case "meta" :
// case "srcipt":
// case "body" : return null; break;
// default : return new UIElement(tag);
// }
}
});
class ZikoUIFlex extends UIElement$1 {
constructor(tag = "div", w = "100%", h = "100%") {
super({element : tag , name : "Flex"});
this.direction = "cols";
if (typeof w == "number") w += "%";
if (typeof h == "number") h += "%";
this.style({ width: w, height: h });
this.style({ display: "flex" });
// this.mount();
}
get isFlex(){
return true;
}
resp(px,wrap = true) {
this.wrap(wrap);
if (this.element.clientWidth < px) this.vertical();
else this.horizontal();
return this;
}
setSpaceAround() {
this.style({ justifyContent: "space-around" });
return this;
}
setSpaceBetween() {
this.style({ justifyContent: "space-between" });
return this;
}
setBaseline() {
this.style({ alignItems: "baseline" });
return this;
}
gap(g) {
if (this.direction === "row") this.style({ columnGap: g });
else if (this.direction === "column") this.style({ rowGap: g });
return this;
}
wrap(value = "wrap") {
const values = ["no-wrap", "wrap","wrap-reverse"];
this.style({
flexWrap: typeof value === "string" ? value : values[+value],
});
return this;
}
_justifyContent(align = "center") {
this.style({ justifyContent: align });
return this;
}
vertical(x, y, order=1) {
set_vertical.call(this,order);
this.style({
alignItems: typeof(x)==="number"?map_pos_x.call(this,x):x,
justifyContent: typeof(y)=="number"?map_pos_y.call(this,y):y
});
return this;
}
horizontal(x, y, order=1) {
set_horizontal.call(this,order);
this.style({
alignItems: typeof(y)=="number"?map_pos_y.call(this,y):y,
justifyContent: typeof(x)==="number"?map_pos_x.call(this,x):x
});
return this;
}
show() {
this.isHidden = false;
this.style({ display: "flex" });
return this;
}
}
const Flex = (...UIElement) =>{
let tag="div";
if(typeof UIElement[0]==="string"){
tag=UIElement[0];
UIElement.pop();
}
return new ZikoUIFlex(tag).append(...UIElement);
};
function set_vertical(direction){
direction == 1
? this.style({ flexDirection: "column" })
: direction == -1 && this.style({ flexDirection: "column-reverse" });
return this;
}
function set_horizontal(direction){
direction == 1
? this.style({ flexDirection: "row" })
: direction == -1 && this.style({ flexDirection: "row-reverse" });
return this;
}
function map_pos_x(align){
let pos = ["flex-start", "center", "flex-end"];
if (typeof align === "number") align = pos[align + 1];
return align;
}
function map_pos_y(align){
return map_pos_x(-align);
}
class UIElement extends UIElementCore{
constructor({element, name, type, render}){
super({element, name, type, render});
}
}
class ZikoUISuspense extends UIElement{
constructor(fallback_ui, callback){
super({element : "div", name : "suspense"});
this.setAttr({
dataTemp : "suspense"
});
this.fallback_ui = fallback_ui;
this.append(fallback_ui);
(async ()=>{
try{
const ui = await callback();
fallback_ui.unmount();
this.append(ui);
}
catch(error){
console.log({error});
}
})();
}
}
const Suspense = (fallback_ui, callback) => new ZikoUISuspense(fallback_ui, callback);
class UIHTMLWrapper extends UIElement$1 {
constructor(content){
super({element : 'div', name : 'html_wrappper'});
this.element.append(html2dom(content));
this.style({
display : 'contents'
});
}
}
function html2dom(htmlString) {
if(globalThis?.DOMParser){
const parser = new DOMParser();
const doc = parser.parseFromString(`<div>${htmlString}</div>`, 'text/html');
doc.body.firstChild.style.display = "contents";
return doc.body.firstChild;
}
}
const HTMLWrapper = (content) => new UIHTMLWrapper(content);
class UISVGWrapper extends UIElement$1 {
constructor(content){
super({element : 'div', name : 'html_wrappper'});
this.element.append(svg2dom(content));
this.style({
display : 'contents'
});
}
}
function svg2dom(svgString) {
if (typeof DOMParser !== "undefined") {
const parser = new DOMParser();
const doc = parser.parseFromString(svgString.trim(), "image/svg+xml");
const svg = doc.documentElement;
if (svg.nodeName === "parsererror") {
throw new Error("Invalid SVG string");
}
if(svg.hasAttribute('xmlns')) return svg
// TO Fix ...
const {children, attributes} = svg;
const element = document.createElementNS("http://www.w3.org/2000/svg", "svg");
for(let {name, value} of attributes){
element.setAttribute(name, value);
}
element.append(...children);
globalThis.svg = svg;
globalThis.children = children;
globalThis.attributes = attributes;
globalThis.element = element;
return element;
}
throw new Error("DOMParser is not available in this environment");
}
const SVGWrapper = (content) => new UISVGWrapper(content);
function define_wc(name, UIElement, props = {}, { mode = 'open'} = {}) {
if (globalThis.customElements?.get(name)) {
console.warn(`Custom element "${name}" is already defined`);
return;
}
if(name.search('-') === -1){
console.warn(`"${name}" is not a valid custom element name`);
return;
}
globalThis.customElements?.define(
name,
class extends HTMLElement {
static get observedAttributes() {
return ['style', ...Object.keys(props)];
}
constructor() {
super();
this.attachShadow({ mode });
this.props = {};
this.mask = {
...props,
// style: { type: Object }
};
}
connectedCallback() {
this.render();
}
render() {
this.shadowRoot.innerHTML = '';
const item = UIElement(this.props);
if(item instanceof Array) item.forEach(n => n.mount(this.shadowRoot));
else item.mount(this.shadowRoot);
}
attributeChangedCallback(name, _, newValue) {
Object.assign(this.props, {
[name]: this.mask[name].type(newValue)
});
this.render();
}
}
);
}
class UISwitch extends UIElement$1{
constructor(key, cases){
super();
this.key = key;
this.cases = cases;
this.init();
}
init(){
Object.values(this.cases).filter(n=>n != this.current).forEach(n=>n.unmount());
super.init(this.current.element);
}
get current(){
const matched = Object.keys(this.cases).find(n => n == this.key) ?? 'default';
return this.cases[matched]
}
updateKey(key){
this.key = key;
this.replaceElementWith(this.current.element);
// this.cache.element.replaceWith(this.current.element)
// this.cache.element = this.current.element;
return this;
}
}
const Switch=({key, cases})=> new UISwitch(key, cases);
// export const Switch=({key, cases}) => {
// const matched = Object.keys(cases).find(n => n == key) ?? 'default';
// return this.cases[matched]()
// }
const { PI, sqrt: sqrt$1, cos: cos$2, sin: sin$2, acos, pow } = Math;
const linear = t => t;
// --- Sin ---
const in_sin = t => 1 - cos$2((t * PI) / 2);
const out_sin = t => sin$2((t * PI) / 2);
const in_out_sin = t => -(cos$2(PI * t) - 1) / 2;
// --- Quad ---
const in_quad = t => t ** 2;
const out_quad = t => 1 - (1 - t) ** 2;
const in_out_quad = t =>
t < 0.5 ? 2 * (t ** 2) : 1 - (-2 * t + 2) ** 2 / 2;
// --- Cubic ---
const in_cubic = t => t ** 3;
const out_cubic = t => 1 - (1 - t) ** 3;
const in_out_cubic = t =>
t < 0.5 ? 4 * (t ** 3) : 1 - (-2 * t + 2) ** 3 / 2;
// --- Quart ---
const in_quart = t => t ** 4;
const out_quart = t => 1 - (1 - t) ** 4;
const in_out_quart = t =>
t < 0.5 ? 8 * (t ** 4) : 1 - (-2 * t + 2) ** 4 / 2;
// --- Quint ---
const in_quint = t => t ** 5;
const out_quint = t => 1 - (1 - t) ** 5;
const in_out_quint = t =>
t < 0.5 ? 16 * (t ** 5) : 1 - (-2 * t + 2) ** 5 / 2;
// --- Expo ---
const in_expo = t => (t === 0 ? 0 : 2 ** (10 * t - 10));
const out_expo = t => (t === 1 ? 1 : 1 - 2 ** (-10 * t));
const in_out_expo = t =>
t === 0
? 0
: t === 1
? 1
: t < 0.5
? 2 ** (20 * t - 10) / 2
: (2 - 2 ** (-20 * t + 10)) / 2;
// --- Circ ---
const in_circ = t => 1 - sqrt$1(1 - t ** 2);
const out_circ = t => sqrt$1(1 - (t - 1) ** 2);
const in_out_circ = t =>
t < 0.5
? (1 - sqrt$1(1 - (2 * t) ** 2)) / 2
: (sqrt$1(1 - (-2 * t + 2) ** 2) + 1) / 2;
// --- Arc ---
const arc = t => 1 - sin$2(acos(t));
// --- Back ---
const back = (t, x = 1) => (t ** 2) * ((x + 1) * t - x);
// --- Elastic ---
const elastic = t =>
-2 * pow(2, 10 * (t - 1)) * cos$2((20 * PI * t) / 3 * t);
// --- Back variations ---
const in_back = (t, c1 = 1.70158, c3 = c1 + 1) =>
c3 * pow(t, 3) - c1 * (t ** 2);
const out_back = (t, c1 = 1.70158, c3 = c1 + 1) =>
1 + c3 * pow(t - 1, 3) + c1 * pow(t - 1, 2);
const in_out_back = (t, c1 = 1.70158, c2 = c1 * 1.525) =>
t < 0.5
? (pow(2 * t, 2) * ((c2 + 1) * 2 * t - c2)) / 2
: (pow(2 * t - 2, 2) * ((c2 + 1) * (t * 2 - 2) + c2) + 2) / 2;
// --- Elastic variations ---
const in_elastic = (t, c4 = (2 * PI) / 3) =>
t === 0
? 0
: t === 1
? 1
: -pow(2, 10 * t - 10) * sin$2((t * 10 - 10.75) * c4);
const out_elastic = (t, c4 = (2 * PI) / 3) =>
t === 0
? 0
: t === 1
? 1
: pow(2, -10 * t) * sin$2((t * 10 - 0.75) * c4) + 1;
const in_out_elastic = (t, c5 = (2 * PI) / 4.5) =>
t === 0
? 0
: t === 1
? 1
: t < 0.5
? -(pow(2, 20 * t - 10) * sin$2((20 * t - 11.125) * c5)) / 2
: (pow(2, -20 * t + 10) * sin$2((20 * t - 11.125) * c5)) / 2 + 1;
// --- Bounce ---
const in_bounce = (t, n1 = 7.5625, d1 = 2.75) =>
1 - out_bounce(1 - t, n1, d1);
const out_bounce = (t, n1 = 7.5625, d1 = 2.75) => {
if (t < 1 / d1) return n1 * t * t;
if (t < 2 / d1) return n1 * (t -= 1.5 / d1) * t + 0.75;
if (t < 2.5 / d1) return n1 * (t -= 2.25 / d1) * t + 0.9375;
return n1 * (t -= 2.625 / d1) * t + 0.984375;
};
const in_out_bounce = (t, n1 = 7.5625, d1 = 2.75) =>
t < 0.5
? out_bounce(1 - 2 * t, n1, d1) / 2
: out_bounce(2 * t - 1, n1, d1) / 2;
// --- Step / Discrete ---
const step = (t, steps = 5) => Math.floor(t * steps) / steps;
const discret = (t, segments = 5) => Math.ceil(t * segments) / segments;
class TimeAnimation {
constructor(callback, { ease = linear, step = 50, t0 = 0, start = true, duration = 3000 } = {}) {
this.callback = callback;
this.state = {
isRunning: false,
animationId: null,
startTime: null,
ease,
step,
// interval: [t0, t1],
autoStart: start,
duration
};
this.t = 0; // elapsed time
this.tx = 0; // normalized [0,1]
this.ty = 0; // eased value
this.i = 0; // frame index
if (this.state.autoStart) {
this.start();
}
}
// ---- private loop handler ----
#tick = () => {
this.t += this.state.step;
this.i++;
this.tx = map$1(this.t, 0, this.state.duration, 0, 1);
this.ty = this.state.ease(this.tx);
this.callback(this);
if (this.t >= this.state.duration) {
clearInterval(this.state.animationId);
this.state.isRunning = false;
}
};
// ---- core runner ----
#run(reset = true) {
if (!this.state.isRunning) {
if (reset) this.reset(false);
this.state.isRunning = true;
this.state.startTime = Date.now();
this.state.animationId = setInterval(this.#tick, this.state.step);
}
return this;
}
// ---- lifecycle methods ----
start() {
return this.#run(true);
}
pause() {
if (this.state.isRunning) {
clearInterval(this.state.animationId);
this.state.isRunning = false;
}
return this;
}
resume() {
return this.#run(false);
}
stop() {
this.pause();
this.reset(false);
return this;
}
reset(restart = true) {
this.t = 0;
this.tx = 0;
this.ty = 0;
this.i = 0;
if (restart) this.start();
return this;
}
}
// Hook-style factory
const animation = (callback, {ease, t0, t1, start, duration} = {}) =>
new TimeAnimation(callback, {ease, t0, t1, start, duration});
class Tick {
constructor(fn, ms, count = Infinity, start) {
this.ms = ms;
this.fn = fn;
this.count = count;
this.frame = 1;
this.id = null;
this.running = false;
if(start) this.start();
}
start() {
if (!this.running) {
this.running = true;
this.frame = 1;
this.id = setInterval(() => {
if (this.frame > this.count) {
this.stop();
return;
}
this.fn.call(null, this);
this.frame++;
}, this.ms);
}
return this;
}
stop() {
if (this.running) {
this.running = false;
clearInterval(this.id);
this.id = null;
}
return this;
}
isRunning() {
return this.running;
}
}
// Helper factory
const tick = (fn, ms, count = Infinity, start = true) => new Tick(fn, ms, count, start);
class Clock extends Tick {
constructor(tickMs = 1000 / 60) {
super(tickMs, () => this._tick());
this.elapsed = 0;
this._lastTime = performance.now();
this._callbacks = new Set();
}
_tick() {
const now = performance.now();
const delta = now - this._lastTime;
this.elapsed += delta;
this._lastTime = now;
for (const cb of this._callbacks) {
cb({ elapsed: this.elapsed, delta });
}
}
onTick(cb) {
this._callbacks.add(cb);
return () => this._callbacks.delete(cb);
}
reset() {
this.elapsed = 0;
this._lastTime = performance.now();
}
pause() {
super.stop();
}
resume() {
this._lastTime = performance.now();
super.start();
}
}
const clock = (tickMs) => new Clock(tickMs);
/*
const clock = new Clock(200);
clock.onTick(({ elapsed, delta }) => {
console.log(`Elapsed: ${elapsed.toFixed(0)}ms, Delta: ${delta.toFixed(0)}ms`);
});
clock.start();
setTimeout(() => clock.pause(), 1000);
setTimeout(() => clock.resume(), 2000);
*/
class TimeScheduler {
constructor(tasks = [], { repeat = 1, loop = false } = {}) {
this.tasks = tasks;
this.repeat = repeat;
this.loop = loop;
this.stopped = false;
this.running = false;
// lifecycle hooks
this.onStart = null;
this.onTask = null;
this.onEnd = null;
}
async run() {
if (this.running) return;
this.running = true;
this.stopped = false;
if (this.onStart) this.onStart();
let repeatCount = this.repeat;
do {
for (const task of this.tasks) {
if (this.stopped) return;
if (Array.isArray(task)) {
// Parallel tasks
await Promise.all(
task.map(({ fn, delay = 0 }) =>
new Promise(async (resolve) => {
if (delay > 0) await new Promise(r => setTimeout(r, delay));
if (this.onTask) this.onTask(fn);
await fn();
resolve();
})
)
);
} else {
// Single task
const { fn, delay = 0 } = task;
if (delay > 0) await new Promise(r => setTimeout(r, delay));
if (this.onTask) this.onTask(fn);
await fn();
}
}
} while (this.loop && !this.stopped && (repeatCount === Infinity || repeatCount-- > 1));
if (!this.stopped && this.onEnd) this.onEnd();
this.running = false;
}
stop() {
this.stopped = true;
this.running = false;
}
addTask(task) {
this.tasks.push(task);
}
clearTasks() {
this.tasks = [];
}
}
const Scheduler = (tasks, { repeat = null} = {}) => new TimeScheduler(tasks, { repeat});
const step_fps = (step_or_fps) => 1000 / step_or_fps;
const sleep= ms => new Promise(res => setTimeout(res, ms));
function timeout(ms, fn) {
let id;
const promise = new Promise((resolve) => {
id = setTimeout(() => {
if (fn) fn();
resolve();
}, ms);
});
return {
id,
clear: () => clearTimeout(id),
promise
};
}
class TimeLoop {
constructor(callback, { step = 1000, t0 = 0, t1 = Infinity, autoplay = true } = {}) {
this.callback = callback;
this.cache = {
isRunning: false,
id: null,
last_tick: null,
step,
t0,
t1,
autoplay,
pauseTime: null,
frame : 0,
};
if (autoplay) {
t0 ? this.startAfter(t0) : this.start();
if (t1 !== Infinity) this.stopAfter(t1);
}
}
get frame(){
return this.cache.frame;
}
get elapsed(){
return this.cache.elapsed;
}
start() {
if (!this.cache.isRunning) {
this.cache.frame = 0;
this.cache.isRunning = true;
this.cache.last_tick = Date.now();
this.animate();
}
return this;
}
pause() {
if (this.cache.isRunning) {
clearTimeout(this.cache.id);
this.cache.isRunning = false;
this.cache.pauseTime = Date.now();
}
return this;
}
resume() {
if (!this.cache.isRunning) {
this.cache.isRunning = true;
if (this.cache.pauseTime) {
// adjust start time so delta stays consistent
const pausedDuration = Date.now() - this.cache.pauseTime;
this.cache.last_tick += pausedDuration;
}
this.animate();
}
return this;
}
stop() {
this.pause();
this.cache.frame = 0;
return this;
}
startAfter(t = 1000) {
setTimeout(() => this.start(), t);
return this;
}
stopAfter(t = 1000) {
setTimeout(() => this.stop(), t);
return this;
}
animate = () => {
if (this.cache.isRunning) {
const now = Date.now();
const delta = now - this.cache.last_tick;
if (delta >= this.cache.step) {
this.cache.elapsed = now - (this.cache.t0 || 0);
this.callback(this);
this.cache.frame++;
this.cache.last_tick = now - (delta % this.cache.step);
}
this.cache.id = setTimeout(this.animate, 0);
}
}
}
const loop = (callback, options = {}) => new TimeLoop(callback, options);
// Helpers
// const useFps = (fps) => 1000 / fps;
// const _loop = loop( e => {
// console.log("Frame:", e.frame, " Elapsed: ", e.elapsed);
// });
const time_memory_Taken = (callback) => {
const t0 = Date.now();
const m0 = performance.memory.usedJSHeapSize;
const result = callback();
const t1 = Date.now();
const m1 = performance.memory.usedJSHeapSize;
const elapsedTime = t1 - t0;
const usedMemory = m1 - m0;
return {
elapsedTime,
usedMemory,
result
};
};
const waitForUIElm=(UIElement)=>{
return new Promise(resolve => {
if (UIElement.element) {
return resolve(UIElement.element);
}
const observer = new MutationObserver(() => {
if (UIElement.element) {
resolve(UIElement.element);
observer.disconnect();
}
});
observer.observe(document?.body, {
childList: true,
subtree: true
});
});
};
const waitForUIElmSync=(UIElement,timeout=2000)=>{
const t0=Date.now();
while(Date.now()-t0<timeout){
if(UIElement.element)return UIElement.element
}
};
// import Ease from "./ease.js";
const wait=(delayInMS)=>{
return new Promise((resolve) => setTimeout(resolve, delayInMS));
};
const timeTaken = callback => {
console.time('timeTaken');
const r = callback();
console.timeEnd('timeTaken');
return r;
};
const preload=(url)=>{
const xhr = new XMLHttpRequest();
xhr.open("GET", url, false);
xhr.send();
if (xhr.status === 200) {
return xhr.responseText;
} else {
throw new Error(`Failed to fetch data from ${url}. Status: ${xhr.status}`);
}
};
async function fetchdom(url='https://github.com/zakarialaoui10') {
try {
const response = await fetch(url);
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
const html = await response.text();
const dom = new DOMParser().parseFromString(html, 'text/html');
return dom.documentElement;
} catch (err) {
console.error('Failed to fetch DOM:', err);
throw err;
}
}
function fetchdomSync(url='https://github.com/zakarialaoui10') {
try {
const data = preload(url);
const dom = new DOMParser().parseFromString(data, 'text/html');
return dom.documentElement;
} catch (err) {
console.error('Failed to fetch DOM synchronously:', err);
throw err;
}
}
globalThis.fetchdom=fetchdom;
globalThis.fetchdomSync=fetchdomSync;
const csv2arr = (csv, delimiter = ",")=>csv.trim().trimEnd().split("\n").map(n=>n.split(delimiter));
const csv2matrix = (csv, delimiter = ",")=>new Matrix(csv2arr(csv,delimiter));
const csv2object = (csv, delimiter = ",") => {
const [header, ...rows] = csv2arr(csv,delimiter);
const result = rows.map(row => {
const obj = {};
header.forEach((key, index) => {
obj[key] = row[index];
});
return obj;
});
return result;
};
const csv2json = (csv, delimiter = ",") => JSON.stringify(csv2object(csv,delimiter));
const csv2sql=(csv, Table)=>{
const lines = csv.trim().trimEnd().split('\n').filter(n=>n);
const columns = lines[0].split(',');
let sqlQuery = `INSERT INTO ${Table} (${columns.join(', ')}) Values `;
let sqlValues = [];
for (let i = 1; i < lines.length; i++) {
const values = lines[i].split(',');
sqlValues.push(`(${values})`);
}
return sqlQuery+sqlValues.join(",\n");
};
const _objects2arr=data=>data instanceof Array?[Object.keys(data[0]),...data.map(n=>Object.values(n))]:[Object.keys(data)];
const _objects2csv=(data,delimiter)=>_objects2arr(data).map(n=>n.join(delimiter)).join("\n");
const json2arr=json=>json instanceof Object?_objects2arr(json):_objects2arr(JSON.parse(json));
const json2csv=(json,delimiter=",")=>json instanceof Object?_objects2csv(json,delimiter):_objects2csv(JSON.parse(json),delimiter);
const json2csvFile=(json,delimiter)=>{
const str=json2csv(json,delimiter);
const blob=new Blob([str], { type: 'text/csv;charset=utf-8;' });
return {
str,
blob,
url:URL.createObjectURL(blob)
}
};
const _processObject=(obj, indent)=>{
const yml = [];
if (Array.isArray(obj)) {
obj.forEach(item => {
if (typeof item === 'object' && item !== null) {
yml.push(`${indent}-`);
const nestedLines = _processObject(item, `${indent} `);
yml.push(...nestedLines);
} else yml.push(`${indent}- ${item}`);
});
} else {
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
const value = obj[key];
if (typeof value === 'object' && value !== null) {
yml.push(`${indent}${key}:`);
const nestedLines = _processObject(value, `${indent} `);
yml.push(...nestedLines);
} else {
yml.push(`${indent}${key}: ${value}`);
}
}
}
}
return yml;
};
const _object2yml=(object,indent="")=>_processObject(object,indent).join('\n');
const json2yml=(json,indent)=>json instanceof Object?_object2yml(json,indent):_object2yml(JSON.parse(json),indent);
const json2ymlFile=(json,indent)=>{
const str=json2yml(json,indent);
const blob=new Blob([str], { type: 'text/yml;charset=utf-8;' });
return {
str,
blob,
url:URL.createObjectURL(blob)
}
};
const json2xml=(json, indent = 1)=>{
let xml = '';
for (const key in json) {
if (json.hasOwnProperty(key)) {
const value = json[key];
xml += '\n' + ' '.repeat(indent) + `<${key}>`;
(typeof value === 'object') ? xml += json2xml(value, indent + 2) : xml += `${value}`;
xml += `</${key}>`;
}
}
return xml.trim();
};
const json2xmlFile=(json,indent)=>{
const str=json2xml(json,indent);
const blob=new Blob([str], { type: 'text/xml;charset=utf-8;' });
return {
str,
blob,
url:URL.createObjectURL(blob)
}
};
const svg2str=svg=>(new XMLSerializer()).serializeToString(svg);
const svg2ascii=svg=>btoa(svg2str(svg));
const svg2imgUrl=svg=>'data:image/svg+xml;base64,'+svg2ascii(svg);
const svg2img=(svg,render=true)=>tags.img(svg2imgUrl(svg)).mount(render);
// const obj2str=(object)=>{
// const recursiveToString = (obj) => {
// if (Array.isArray(obj)) return arr2str(obj);
// if (typeof obj === 'object' && obj !== null) {
// return `{ ${Object.entries(obj)
// .map(([key, value]) => `${key}:${recursiveToString(value)}`)
// .join(" , ")} }`;
// }
// return String(obj);
// };
// return recursiveToString(object);
// };
// const obj2str = (object) => {
// const recursiveToString = (obj, indentLevel = 0) => {
// const indent = ' '.repeat(indentLevel);
// const nextIndent = ' '.repeat(indentLevel + 1);
// if(Array.isArray(obj)) return arr2str(obj, indentLevel);
// if(obj instanceof Complex || obj instanceof Matrix) return obj.toString();
// if (typeof obj === 'object' && obj !== null) {
// const entries = Object.entries(obj)
// .map(([key, value]) => `${nextIndent}${key}: ${recursiveToString(value, indentLevel + 1)}`)
// .join(",\n");
// return `{\n${entries}\n${indent}}`;
// }
// return String(obj);
// };
// return recursiveToString(object);
// };
// const obj2str = (object, useIndentation = true, indentLevel = 0) => {
// const recursiveToString = (obj, level = 0) => {
// const indent = useIndentation ? ' '.repeat(level) : '';
// const nextIndent = useIndentation ? ' '.repeat(level + 1) : '';
// if (Array.isArray(obj)) return arr2str(obj, false, level);
// if(obj instanceof Complex || obj instanceof Matrix) return obj.toString();
// if (typeof obj === 'object' && obj !== null) {
// const entries = Object.entries(obj)
// .map(([key, value]) => useIndentation
// ? `${nextIndent}${key}: ${recursiveToString(value, level + 1)}`
// : `${key}: ${recursiveToString(value, level + 1)}`
// ).join(useIndentation ? ",\n" : ", ");
// return useIndentation
// ? `{\n${entries}\n${indent}}`
// : `{${entries}}`;
// }
// return String(obj);
// };
// return recursiveToString(object, indentLevel);
// };
const obj2str=(obj)=>JSON.stringify(
mapfun(n=>{
if(["number","string","boolean","bigint"].includes(typeof n)) return String(n);
if(n instanceof Complex || n instanceof Matrix) return n.toString();
if(n instanceof Array) return arr2str(n)
},
obj), null, " ")
.replace(/"([^"]+)":/g, '$1:') // Remove Quotes from Keys
.replace(/: "([^"]+)"/g, ': $1'); // Remove Quotes from str values
const getMaxDepth = arr=> {
if (!Array.isArray(arr)) return 0;
let maxDepth = 1;
for (const element of arr) {
if (Array.isArray(element)) {
const depth = getMaxDepth(element);
if (depth + 1 > maxDepth) {
maxDepth = depth + 1;
}
}
}
return maxDepth;
};
const arr2str = (arr) => {
let level = 0;
function arrStringify(arr) {
let max = getMaxDepth(arr);
let useIdentation = 0;
if (arr.some((n) => Array.isArray(n))) {
level++;
useIdentation = 1;
}
return (
"[" +
arr.map((n, i) => {
if (["number", "string", "boolean", "bigint"].includes(typeof n))
return String(n);
if (n instanceof Complex) return n.toString();
if (n instanceof Array) {
return `\n${" ".repeat(level)}${arrStringify(n)}${i === arr.length - 1 ? "\n" : ""}`;
}
if( n instanceof Object) return obj2str(n);
})
+ `${" ".repeat((max+level+1) * useIdentation)}]`
);
}
return arrStringify(arr);
};
const json2css=(json, indentLevel = 0)=>{
json = trimKeys(json);
let cssText = '';
const indent = ' '.repeat(indentLevel);
for (let selector in json) {
if (typeof json[selector] === 'object') {
cssText += `${indent}${selector} {\n`;
const properties = json[selector];
for (let property in properties) {
if (typeof properties[property] === 'object') {
cssText += json2css({ [property]: properties[property] }, indentLevel + 1);
} else {
cssText += `${indent} ${property.replace(/[A-Z]/g, match => '-' + match.toLowerCase())}: ${properties[property]};\n`;
}
}
cssText += `${indent}}\n`;
}
}
return cssText;
};
function trimKeys(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
return Object.keys(obj).reduce((acc, key) => {
const trimmedKey = key.trim();
acc[trimmedKey] = trimKeys(obj[key]);
return acc;
}, Array.isArray(obj) ? [] : {});
}
// import { ZikoHead , useHead} from "../reactivity/hooks/head/index.js";
class ZikoApp {
constructor({head = null, wrapper = null, target = null}){
this.head = head;
this.wrapper = wrapper;
this.target = target;
this.init();
}
get isZikoApp(){
return true;
}
init(){
this.head && this.setHead(this.head);
this.wrapper && this.setWrapper(this.wrapper);
this.target && this.setTarget(this.target);
if(this.wrapper && this.target)this.wrapper.mount(this.target);
}
setTarget(target){
if(target instanceof HTMLElement) this.target = target;
else if (typeof target === "string") this.target = globalThis?.document?.querySelector(target);
return this;
}
setWrapper(wrapper){
if(wrapper?.isUIElement) this.wrapper = wrapper;
else if(typeof wrapper === "function") this.wrapper = wrapper();
return this;
}
// setHead(head){
// if(head instanceof ZikoHead) this.head = head;
// else this.head = useHead(head);
// return this;
// }
}
const App = ({head, wrapper, target}) => new ZikoApp({head, wrapper, target});
function routesMatcher(mask, route) {
const maskSegments = mask.split('/');
const routeSegments = route.split('/');
if (maskSegments.length !== routeSegments.length) {
return false;
}
for (let i = 0; i < maskSegments.length; i++) {
const maskSegment = maskSegments[i];
const routeSegment = routeSegments[i];
if (maskSegment.startsWith(':')) {
continue;
} else if (maskSegment !== routeSegment) {
return false;
}
}
return true;
}
function dynamicRoutesParser(mask, route) {
const maskSegments = mask.split('/');
const routeSegments = route.split('/');
const params = {};
if (maskSegments.length !== routeSegments.length) {
return params;
}
for (let i = 0; i < maskSegments.length; i++) {
const maskSegment = maskSegments[i];
const routeSegment = routeSegments[i];
if (maskSegment.startsWith(':')) {
const paramName = maskSegment.slice(1);
params[paramName] = routeSegment;
} else if (maskSegment !== routeSegment) {
return {};
}
}
return params;
}
function isDynamic(path) {
const DynamicPattern = /:\w+/;
return DynamicPattern.test(path);
}
// // Example usage:
// const mask = "app/lang/:lang/id/:id";
// const route = "app/lang/en/id/7";
// console.log(dynamicRoutesParser(mask, route)); // Should return { lang: "en", id: "7" }
class ZikoSPA extends ZikoApp{
constructor({head, wrapper, target, routes}){
super({head, wrapper, target});
this.routes=new Map([
["404",text("Error 404")],
...Object.entries(routes)
]);
this.clear();
globalThis.onpopstate = this.mount(location.pathname);
}
clear(){
[...this.routes].forEach(n=>{
!isDynamic(n[0]) && n[1]?.isUIElement && n[1].unmount();
});
// this.wrapper.clear();
return this;
}
mount(path){
const [mask, callback] = [...this.routes].find(route=>routesMatcher(route[0],path));
let element ;
if(isDynamic(mask)){
const params = dynamicRoutesParser(mask, path);
element = callback.call(this,params);
}
else {
callback?.isUIElement && callback.mount(this.wrapper);
if(typeof callback === "function") element = callback();
}
if(element?.isUIElement) element.mount(this.wrapper);
// if(element?.isZikoApp) element.mount(this.wrapper);
if(element instanceof Promise){
element.then(e=>e.mount(this.wrapper));
}
globalThis.history.pushState({}, "", path);
return this;
}
}
const SPA=({head, wrapper, target, routes})=>new ZikoSPA({head, wrapper, target, routes});
/*
// Static
S.get("/url",wrapper)
// Dynamique
s.get("/url/name/:name/id/:id",(path,name,id)=>handler())
// regEx
*/
function parseQueryParams(queryString) {
const params = {};
queryString.replace(/[A-Z0-9]+?=([\w|:|\/\.]*)/gi, (match) => {
const [key, value] = match.split('=');
params[key] = value;
});
return params;
}
function defineParamsGetter(target ){
Object.defineProperties(target, {
'QueryParams': {
get: function() {
return parseQueryParams(globalThis.location.search.substring(1));
},
configurable: false,
enumerable: true
},
'HashParams': {
get: function() {
const hash = globalThis.location.hash.substring(1);
return hash.split("#");
},
configurable: false,
enumerable: true
}
});
}
// import.meta.glob('./src/pages/**/*.js')
async function FileBasedRouting(pages /* use import.meta.glob */){
const routes = Object.keys(pages);
const root = findCommonPath(routes);
const pairs = {};
for(let i=0; i<routes.length; i++){
const module = await pages[routes[i]]();
const component = await module.default;
Object.assign(pairs,{[customPath(routes[i], root)]:component});
}
return SPA({
target : document.body,
routes : {
"/" : ()=>{},
...pairs
},
wrapper : tags.section()
})
}
function customPath(inputPath, root = './src/pages', extensions = ['js', 'ts']) {
if(root.at(-1)==="/") root = root.slice(0, -1);
const normalizedPath = inputPath.replace(/\\/g, '/').replace(/\[(\w+)\]/g, '$1/:$1');
const parts = normalizedPath.split('/');
const rootParts = root.split('/');
const rootIndex = parts.indexOf(rootParts.at(-1));
if (rootIndex !== -1) {
const subsequentParts = parts.slice(rootIndex + 1);
const lastPart = parts.at(-1);
const isIndexFile = lastPart === 'index.js' || lastPart === 'index.ts';
// console.log({extensions, subsequentParts, lastPart, isIndexFile, rootParts, rootIndex, parts})
const hasValidExtension = extensions.some(ext => lastPart === `.${ext}` || lastPart.endsWith(`.${ext}`));
if (isIndexFile) {
return '/' + (subsequentParts.length > 1 ? subsequentParts.slice(0, -1).join('/') : '');
}
if (hasValidExtension) {
return '/' + subsequentParts.join('/').replace(/\.(js|ts)$/, '');
}
}
return '';
}
function findCommonPath(paths) {
if (paths.length === 0) return '';
const splitPaths = paths.map(path => path.split('/'));
const minLength = Math.min(...splitPaths.map(parts => parts.length));
let commonParts = [];
for (let i = 0; i < minLength; i++) {
const part = splitPaths[0][i];
if (splitPaths.every(parts => parts[i] === part || parts[i].startsWith('['))) {
commonParts.push(part);
} else {
break;
}
}
const commonPath = commonParts.join('/') + (commonParts.length ? '/' : '');
return commonPath;
}
function useDerived(deriveFn, sources) {
let value = deriveFn(...sources.map(s => s().value));
const subscribers = new Set();
sources.forEach(source => {
const srcValue = source();
srcValue._subscribe(() => {
{
const newVal = deriveFn(...sources.map(s => s().value));
if (newVal !== value) {
value = newVal;
subscribers.forEach(fn => fn(value));
}
}
});
});
return () => ({
value,
isStateGetter : () => true,
_subscribe: (fn) => subscribers.add(fn)
})
}
const useReactive = (nested_value) => mapfun(
n => {
const state = useState(n);
return {
get : state[0],
set : state[1],
}
},
nested_value
);
class UseThread {
#worker;
#callbacks = new Map();
#idCounter = 0;
constructor() {
const workerCode = `
this.onmessage = function(e) {
const { id, funStr, args, close } = e.data;
try {
const func = new Function("return " + funStr)();
const result = func(...args);
postMessage({ id, result });
} catch (error) {
postMessage({ id, error: error.message });
} finally {
if (close) self.close();
}
}
`;
const blob = new Blob([workerCode], { type: "text/javascript" });
this.#worker = new Worker(URL.createObjectURL(blob));
this.#worker.addEventListener("message", (e) => {
const { id, result, error } = e.data;
const callback = this.#callbacks.get(id);
if (!callback) return;
callback(result, error);
this.#callbacks.delete(id);
});
}
call(func, callback, args = [], close = true) {
if (typeof func !== "function") throw new TypeError("func must be a function");
const id = ++this.#idCounter;
this.#callbacks.set(id, callback);
this.#worker.postMessage({
id,
funStr: func.toString(),
args,
close
});
return this;
}
terminate() {
this.#worker.terminate();
}
}
const useThread = (func, callback, args = [], close = true) => new UseThread().call(func, callback, args, close);
class UseEventEmitter {
constructor(maxListeners = 10) {
this.events = {};
this.maxListeners = maxListeners;
}
on(event, listener) {
if (!this.events[event]) this.events[event] = [];
this.events[event].push(listener);
if (this.events[event].length > this.maxListeners) {
console.warn(`Warning: Possible memory leak. Event '${event}' has more than ${this.maxListeners} listeners.`);
}
return this;
}
once(event, listener) {
const wrapper = (...args) => {
this.off(event, wrapper);
listener(...args);
};
return this.on(event, wrapper);
}
off(event, listener) {
const listeners = this.events[event];
if (!listeners) return this;
const index = listeners.indexOf(listener);
if (index !== -1) {
listeners.splice(index, 1);
}
return this;
}
emit(event, data) {
const listeners = this.events[event];
if (!listeners) return false;
// Make a copy so removing listeners inside callbacks doesn't affect iteration
[...listeners].forEach(listener => {
try {
listener(data);
} catch (e) {
console.error(`Error in listener for '${event}':`, e);
}
});
return true;
}
remove(event){
delete this.events[event];
return this;
}
clear() {
this.events = {};
return this;
}
setMaxListeners(max) {
this.maxListeners = max;
return this;
}
}
const useEventEmitter = (maxListeners) => new UseEventEmitter(maxListeners);
/*
[
{
query: '(min-width: 600px)',
callback: () => console.log(1)
},
{
query: '(max-width: 300px)',
callback: () => console.log(2)
}
]
*/
class UseMediaQuery {
#mediaQueryRules;
#fallback;
#lastCalledCallback = null;
constructor(mediaQueryRules = [], fallback = () => {}) {
this.#mediaQueryRules = mediaQueryRules;
this.#fallback = fallback;
this.#init();
}
// PRIVATE: check if ANY rule matches
#checkAllRules() {
return this.#mediaQueryRules.some(
({ query }) => globalThis.matchMedia(query).matches
);
}
// PRIVATE: installs listeners and initial checks
#init() {
this.#mediaQueryRules.forEach(({ query, callback }) => {
const mediaQueryList = globalThis.matchMedia(query);
const checkMatches = () => {
const anyMatch = this.#checkAllRules();
if (mediaQueryList.matches) {
callback();
this.#lastCalledCallback = callback;
} else if (!anyMatch && this.#lastCalledCallback !== this.#fallback) {
this.#fallback();
this.#lastCalledCallback = this.#fallback;
}
};
checkMatches();
mediaQueryList.addEventListener("change", checkMatches);
});
}
}
const useMediaQuery = (mediaQueryRules, fallback) =>
new UseMediaQuery(mediaQueryRules, fallback);
class UseTitle {
constructor(title = document.title, withEmitter = true) {
this.cache = {
emitter: null
};
if (withEmitter) this.useEventEmitter();
this.set(title);
}
useEventEmitter() {
this.cache.emitter = useEventEmitter();
return this;
}
setTitle(title) {
if (title !== document.title) {
document.title = title;
if (this.cache.emitter) {
this.cache.emitter.emit("ziko:title-changed", title);
}
}
return this;
}
get current() {
return document.title;
}
onChange(callback) {
if (this.cache.emitter) {
this.cache.emitter.on("ziko:title-changed", callback);
}
return this;
}
}
const useTitle = (title, withEmitter = true) => new UseTitle(title, withEmitter);
class UseRoot {
constructor(PropsMap, { namespace = 'Ziko', ValidateCssProps = false } = {}) {
this.currentPropsMap = PropsMap;
this.namespace = namespace;
this.ValidateCssProps = ValidateCssProps;
this.use(PropsMap);
}
use(PropsMap) {
if (this.ValidateCssProps) ValidateCssPropsFn(PropsMap);
this.currentPropsMap = PropsMap;
this.#maintain();
return this;
}
#maintain() {
const root = globalThis?.document?.documentElement?.style;
for (const prop in this.currentPropsMap) {
const cssProp = this.namespace ? `--${this.namespace}-${prop}` : `--${prop}`;
root.setProperty(cssProp, this.currentPropsMap[prop]);
Object.defineProperty(this, prop, {
value: `var(${cssProp})`,
writable: true,
configurable: true,
enumerable: false
});
}
}
}
function ValidateCssPropsFn(PropsMap) {
const validProps = new Set(Object.keys(document.documentElement.style));
for (const key in PropsMap) {
if (!validProps.has(key)) {
throw new Error(`Invalid CSS property: "${key}"`);
}
}
}
const useRoot = (PropsMap, options = {}) => new UseRoot(PropsMap, options);
// Usage
/*
const Styles = {
S1 : {
background : 'white',
color : 'darkblue'
border : '2px darkblue solid"'
},
S2 : {
background : 'darkblue',
color : 'white'
border : '2px green solid"'
}
}
const {use, border, background, color} = useRoot(Style.S1)
tags.p("Test useRoot ").style({
border,
color,
background,
padding : '10px'
})
*/
let {sqrt, cos: cos$1, sin: sin$1, exp, log, cosh: cosh$1, sinh} = Math;
// Math.abs = new Proxy(Math.abs, {
// apply(target, thisArg, args) {
// const x = args[0]
// if(typeof x === 'number') return target.apply(thisArg, args);
// if(x?.isComplex?.()){
// const {a, b, z, phi} = x
// const complex = (a, b) => new x.constructor(a, b)
// switch(target.name){
// case 'abs' : return a.z;
// case 'sqrt' : return complex(sqrt(z)*cos(phi/2),sqrt(z)*sin(phi/2));
// }
// }
// }
// });
for (const key of Object.getOwnPropertyNames(Math)) {
const fn = Math[key];
if (typeof fn === "function") {
Math[key] = new Proxy(fn, {
apply(target, thisArg, args) {
// console.log(target)
const x = args[0];
if(typeof x === 'number' || args.length === 0) return target.apply(thisArg, args);
if(x?.isComplex?.()){
const {a, b, z, phi} = x;
const complex = (a, b) => new x.constructor(a, b);
switch(target.name){
case 'abs' : return x.z;
case 'sqrt' : return complex(sqrt(z)*cos$1(phi/2),sqrt(z)*sin$1(phi/2));
case 'log' : return complex(log(z), phi);
case 'exp' : return complex(exp(a)*cos$1(b),exp(a)*sin$1(b));
case 'cos' : return complex(cos$1(a)*cosh$1(b),-(sin$1(a)*sinh(b)));
case 'sin' : return complex(sin$1(a)*cosh$1(b),cos$1(a)*sinh(b));
case 'tan' : {
const DEN = cos$1(2*a)+cosh$1(2*b);
return complex(sin$1(2*a) /DEN, sinh(2*b)/DEN);
}
case 'cosh' : return complex(cosh$1(a)*cos$1(b),sinh(a)*sin$1(b));
case 'sinh' : return complex(sinh(a)*cos$1(b),cosh$1(a)*sin$1(b));
case 'tanh' : {
const DEN=cosh$1(2*a)+cos$1(2*b);
return complex(sinh(2*a)/DEN,sin$1(2*b)/DEN)
}
default : return target.apply(thisArg, args)
}
}
// if( x.isMatrix?.()){
// const {rows, cols, arr} = x
// // return new x.constructor(rows, cols, arr.flat(1).map(n=>));
// }
throw new TypeError(`Math.${key} expects only numbers`);
}
});
}
}
if(globalThis?.document){
document?.addEventListener("DOMContentLoaded", __Ziko__.__Config__.init());
}
exports.App = App;
exports.Clock = Clock;
exports.Complex = Complex;
exports.E = E;
exports.EPSILON = EPSILON;
exports.FileBasedRouting = FileBasedRouting;
exports.Flex = Flex;
exports.HTMLWrapper = HTMLWrapper;
exports.Matrix = Matrix;
exports.PI = PI$1;
exports.Random = Random;
exports.SPA = SPA;
exports.SVGWrapper = SVGWrapper;
exports.Scheduler = Scheduler;
exports.Suspense = Suspense;
exports.Switch = Switch;
exports.Tick = Tick;
exports.TimeAnimation = TimeAnimation;
exports.TimeLoop = TimeLoop;
exports.TimeScheduler = TimeScheduler;
exports.UIElement = UIElement$1;
exports.UIHTMLWrapper = UIHTMLWrapper;
exports.UINode = UINode;
exports.UISVGWrapper = UISVGWrapper;
exports.UISwitch = UISwitch;
exports.UIView = UIView;
exports.UseRoot = UseRoot;
exports.UseThread = UseThread;
exports.Utils = Utils;
exports.View = View;
exports.ZikoApp = ZikoApp;
exports.ZikoEvent = ZikoEvent;
exports.ZikoSPA = ZikoSPA;
exports.ZikoUIFlex = ZikoUIFlex;
exports.ZikoUISuspense = ZikoUISuspense;
exports.ZikoUIText = ZikoUIText;
exports.abs = abs;
exports.accum_prod = accum_prod;
exports.accum_sum = accum_sum;
exports.acos = acos$1;
exports.acosh = acosh;
exports.acot = acot;
exports.add = add;
exports.and = and;
exports.animation = animation;
exports.apply_fun = apply_fun;
exports.arange = arange;
exports.arc = arc;
exports.arr2str = arr2str;
exports.asin = asin;
exports.asinh = asinh;
exports.atan = atan;
exports.atan2 = atan2;
exports.atanh = atanh;
exports.back = back;
exports.bind_click_event = bind_click_event;
exports.bind_clipboard_event = bind_clipboard_event;
exports.bind_drag_event = bind_drag_event;
exports.bind_focus_event = bind_focus_event;
exports.bind_key_event = bind_key_event;
exports.bind_mouse_event = bind_mouse_event;
exports.bind_pointer_event = bind_pointer_event;
exports.bind_swipe_event = bind_swipe_event;
exports.bind_touch_event = bind_touch_event;
exports.bind_view_event = bind_view_event;
exports.bind_wheel_event = bind_wheel_event;
exports.binomial = binomial;
exports.cartesianProduct = cartesianProduct;
exports.cbrt = cbrt;
exports.ceil = ceil;
exports.clamp = clamp;
exports.clock = clock;
exports.complex = complex;
exports.cos = cos$3;
exports.cosh = cosh$2;
exports.coth = coth;
exports.croot = croot;
exports.csv2arr = csv2arr;
exports.csv2json = csv2json;
exports.csv2matrix = csv2matrix;
exports.csv2object = csv2object;
exports.csv2sql = csv2sql;
exports.debounce = debounce;
exports.defineParamsGetter = defineParamsGetter;
exports.define_wc = define_wc;
exports.deg2rad = deg2rad;
exports.discret = discret;
exports.div = div;
exports.elastic = elastic;
exports.event_controller = event_controller;
exports.exp = exp$1;
exports.floor = floor;
exports.fract = fract;
exports.geomspace = geomspace;
exports.getEvent = getEvent;
exports.hypot = hypot;
exports.inRange = inRange;
exports.in_back = in_back;
exports.in_bounce = in_bounce;
exports.in_circ = in_circ;
exports.in_cubic = in_cubic;
exports.in_elastic = in_elastic;
exports.in_expo = in_expo;
exports.in_out_back = in_out_back;
exports.in_out_bounce = in_out_bounce;
exports.in_out_circ = in_out_circ;
exports.in_out_cubic = in_out_cubic;
exports.in_out_elastic = in_out_elastic;
exports.in_out_expo = in_out_expo;
exports.in_out_quad = in_out_quad;
exports.in_out_quart = in_out_quart;
exports.in_out_quint = in_out_quint;
exports.in_out_sin = in_out_sin;
exports.in_quad = in_quad;
exports.in_quart = in_quart;
exports.in_quint = in_quint;
exports.in_sin = in_sin;
exports.isApproximatlyEqual = isApproximatlyEqual;
exports.isStateGetter = isStateGetter;
exports.json2arr = json2arr;
exports.json2css = json2css;
exports.json2csv = json2csv;
exports.json2csvFile = json2csvFile;
exports.json2xml = json2xml;
exports.json2xmlFile = json2xmlFile;
exports.json2yml = json2yml;
exports.json2ymlFile = json2ymlFile;
exports.lerp = lerp;
exports.linear = linear;
exports.linspace = linspace;
exports.ln = ln;
exports.logspace = logspace;
exports.loop = loop;
exports.map = map$1;
exports.mapfun = mapfun;
exports.matrix = matrix;
exports.matrix2 = matrix2;
exports.matrix3 = matrix3;
exports.matrix4 = matrix4;
exports.max = max;
exports.mean = mean;
exports.median = median;
exports.min = min;
exports.modulo = modulo;
exports.mul = mul;
exports.nand = nand;
exports.nor = nor;
exports.norm = norm;
exports.nthr = nthr;
exports.nums = nums;
exports.obj2str = obj2str;
exports.ones = ones;
exports.or = or;
exports.out_back = out_back;
exports.out_bounce = out_bounce;
exports.out_circ = out_circ;
exports.out_cubic = out_cubic;
exports.out_elastic = out_elastic;
exports.out_expo = out_expo;
exports.out_quad = out_quad;
exports.out_quart = out_quart;
exports.out_quint = out_quint;
exports.out_sin = out_sin;
exports.percentile = percentile;
exports.pgcd = pgcd;
exports.pow = pow$1;
exports.ppcm = ppcm;
exports.preload = preload;
exports.rad2deg = rad2deg;
exports.round = round;
exports.sec = sec;
exports.sig = sig;
exports.sign = sign;
exports.sin = sin$3;
exports.sinh = sinh$1;
exports.sleep = sleep;
exports.sqrt = sqrt$2;
exports.std = std;
exports.step = step;
exports.step_fps = step_fps;
exports.sub = sub;
exports.svg2ascii = svg2ascii;
exports.svg2img = svg2img;
exports.svg2imgUrl = svg2imgUrl;
exports.svg2str = svg2str;
exports.tags = tags;
exports.tan = tan;
exports.tanh = tanh;
exports.text = text;
exports.throttle = throttle;
exports.tick = tick;
exports.timeTaken = timeTaken;
exports.time_memory_Taken = time_memory_Taken;
exports.timeout = timeout;
exports.toggle_event_listener = toggle_event_listener;
exports.trunc = trunc;
exports.useDerived = useDerived;
exports.useEventEmitter = useEventEmitter;
exports.useIPC = useIPC;
exports.useLocaleStorage = useLocaleStorage;
exports.useMediaQuery = useMediaQuery;
exports.useReactive = useReactive;
exports.useRoot = useRoot;
exports.useSessionStorage = useSessionStorage;
exports.useState = useState;
exports.useThread = useThread;
exports.useTitle = useTitle;
exports.variance = variance;
exports.wait = wait;
exports.waitForUIElm = waitForUIElm;
exports.waitForUIElmSync = waitForUIElmSync;
exports.xnor = xnor;
exports.xor = xor;
exports.zeros = zeros;
}));