ziko 0.49.5 → 0.49.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ziko.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  /*
3
3
  Project: ziko.js
4
4
  Author: Zakaria Elalaoui
5
- Date : Wed Nov 26 2025 11:58:54 GMT+0100 (UTC+01:00)
5
+ Date : Sat Nov 29 2025 19:48:11 GMT+0100 (UTC+01:00)
6
6
  Git-Repo : https://github.com/zakarialaoui10/ziko.js
7
7
  Git-Wiki : https://github.com/zakarialaoui10/ziko.js/wiki
8
8
  Released under MIT License
@@ -1178,132 +1178,180 @@ const __CACHE__ = {
1178
1178
  };
1179
1179
 
1180
1180
  class UseChannel {
1181
+ #channel;
1182
+ #eventData;
1183
+ #handlers;
1184
+ #uuid;
1185
+ #subscribers;
1186
+ #currentRooms;
1181
1187
  constructor(name = "") {
1182
- this.channel = new BroadcastChannel(name);
1183
- this.eventData = new Map();
1184
- this.handlers = new Map();
1185
- this.uuid = "ziko-channel:" + Random.string(10);
1186
- this.subscribers = new Set([this.uuid]);
1187
-
1188
- this.channel.addEventListener("message", (e) => {
1189
- const { last_sent_event, userId, eventData } = e.data;
1190
-
1191
- // ignore own events
1192
- if (userId === this.uuid) return;
1193
-
1194
- this.subscribers.add(userId);
1195
-
1196
- // sync data
1197
- this.eventData = new Map(eventData);
1198
-
1199
- const data = this.eventData.get(last_sent_event);
1200
- const handlers = this.handlers.get(last_sent_event);
1201
-
1202
- if (handlers) {
1203
- handlers.forEach(fn => fn(data));
1204
- }
1188
+ this.#channel = new BroadcastChannel(name);
1189
+ this.#eventData = new Map();
1190
+ this.#handlers = new Map(); // Map<event, Array<{fn, rooms}>>
1191
+ this.#uuid = "ziko-channel:" + Random.string(10);
1192
+ this.#subscribers = new Set([this.#uuid]);
1193
+ this.#currentRooms = new Set();
1194
+ this.#channel.addEventListener("message", (e) => {
1195
+ const { last_sent_event, userId, eventData, rooms } = e.data;
1196
+ if (userId === this.#uuid) return; // ignore own messages
1197
+ // broadcast if no rooms, else check intersection
1198
+ if (rooms && rooms.length && !rooms.some(r => this.#currentRooms.has(r))) return;
1199
+ this.#subscribers.add(userId);
1200
+ this.#eventData = new Map(eventData);
1201
+ const handlersList = this.#handlers.get(last_sent_event);
1202
+ if (!handlersList) return;
1203
+ handlersList.forEach(({ fn, rooms: handlerRooms }) => {
1204
+ // trigger if listener has no room filter, or intersects subscriber rooms
1205
+ if (!handlerRooms || handlerRooms.length === 0 ||
1206
+ !rooms || rooms.some(r => handlerRooms.includes(r))) {
1207
+ fn(this.#eventData.get(last_sent_event));
1208
+ }
1209
+ });
1205
1210
  });
1206
1211
  }
1207
1212
 
1208
- emit(event, data) {
1209
- this.eventData.set(event, data);
1210
-
1211
- this.channel.postMessage({
1212
- eventData: this.eventData,
1213
+ emit(event, data, rooms) {
1214
+ this.#eventData.set(event, data);
1215
+ if(typeof rooms === 'string') rooms = [rooms];
1216
+ this.#channel.postMessage({
1217
+ eventData: Array.from(this.#eventData.entries()),
1213
1218
  last_sent_event: event,
1214
- userId: this.uuid
1219
+ userId: this.#uuid,
1220
+ rooms: rooms && rooms.length ? rooms : undefined
1215
1221
  });
1216
1222
  return this;
1217
1223
  }
1218
-
1219
- on(event, handler = console.log) {
1220
- if (!this.handlers.has(event)) {
1221
- this.handlers.set(event, []);
1222
- }
1223
- this.handlers.get(event).push(handler);
1224
+ on(event, handler = console.log, rooms) {
1225
+ if (!this.#handlers.has(event)) this.#handlers.set(event, []);
1226
+ if(typeof rooms === 'string') rooms = [rooms];
1227
+ this.#handlers.get(event).push({ fn: handler, rooms });
1224
1228
  return this;
1225
1229
  }
1226
-
1227
- close() {
1228
- this.channel.close();
1230
+ off(event, handler) {
1231
+ if (!this.#handlers.has(event)) return this;
1232
+ this.#handlers.set(
1233
+ event,
1234
+ this.#handlers.get(event).filter(h => h.fn !== handler)
1235
+ );
1229
1236
  return this;
1230
1237
  }
1231
-
1232
- get broadcast() {
1238
+ once(event, handler, rooms) {
1239
+ const wrapper = (data) => {
1240
+ handler(data);
1241
+ this.off(event, wrapper);
1242
+ };
1243
+ this.on(event, wrapper, rooms);
1244
+ return this;
1245
+ }
1246
+ join(...rooms) {
1247
+ rooms.forEach(r => this.#currentRooms.add(r));
1248
+ return this;
1249
+ }
1250
+ leave(...rooms) {
1251
+ if (!rooms.length) this.#currentRooms.clear();
1252
+ else rooms.forEach(r => this.#currentRooms.delete(r));
1253
+ return this;
1254
+ }
1255
+ close() {
1256
+ this.#channel.close();
1233
1257
  return this;
1234
1258
  }
1235
1259
  }
1236
1260
 
1237
1261
  const useChannel = (name) => new UseChannel(name);
1238
1262
 
1239
- // To do : remove old items
1240
- class UseStorage{
1241
- constructor(storage, globalKey, initialValue){
1242
- this.cache={
1263
+ class UseStorage {
1264
+ constructor(storage, globalKey, initialValue, use_channel = true) {
1265
+ this.cache = {
1243
1266
  storage,
1244
1267
  globalKey,
1245
- channel:useChannel(`Ziko:useStorage-${globalKey}`),
1246
- oldItemKeys:new Set()
1268
+ channel: use_channel ? useChannel(`Ziko:useStorage-${globalKey}`) : null,
1269
+ oldItemKeys: new Set()
1247
1270
  };
1248
- this.#init(initialValue);
1249
- this.#maintain();
1271
+
1272
+ this.#init(initialValue, use_channel);
1250
1273
  }
1251
- get items(){
1252
- return JSON.parse(this.cache.storage[this.cache.globalKey]??null);
1274
+
1275
+ get items() {
1276
+ const raw = this.cache.storage.getItem(this.cache.globalKey);
1277
+ if (!raw) return {};
1278
+ try {
1279
+ return JSON.parse(raw);
1280
+ } catch {
1281
+ return {};
1282
+ }
1253
1283
  }
1284
+
1254
1285
  #maintain() {
1255
- for(let i in this.items)Object.assign(this, { [[i]]: this.items[i] });
1256
- }
1257
- #init(initialValue){
1258
- this.cache.channel=useChannel(`Ziko:useStorage-${this.cache.globalKey}`);
1259
- this.cache.channel.on("Ziko-Storage-Updated",()=>this.#maintain());
1260
- if(!initialValue)return;
1261
- if(this.cache.storage[this.cache.globalKey]){
1262
- Object.keys(this.items).forEach(key=>this.cache.oldItemKeys.add(key));
1263
- // console.group("Ziko:useStorage")
1264
- // console.warn(`Storage key '${this.cache.globalKey}' already exists. we will not overwrite it.`);
1265
- // console.info(`%cWe'll keep the existing data.`,"background-color:#2222dd; color:gold;");
1266
- // console.group("")
1286
+ const items = this.items;
1287
+ this.cache.oldItemKeys.forEach(k => delete this[k]);
1288
+ for (const key in items) {
1289
+ this[key] = items[key];
1290
+ this.cache.oldItemKeys.add(key);
1291
+ }
1292
+ }
1293
+ #init(initialValue, use_channel) {
1294
+ if (use_channel && this.cache.channel) this.cache.channel.on("Ziko-Storage-Updated", () => this.#maintain());
1295
+ if (!initialValue) {
1296
+ this.#maintain();
1297
+ return;
1267
1298
  }
1299
+ if (this.cache.storage.getItem(this.cache.globalKey)) {
1300
+ const existing = this.items;
1301
+ Object.keys(existing).forEach(k => this.cache.oldItemKeys.add(k));
1302
+ this.#maintain();
1303
+ }
1268
1304
  else this.set(initialValue);
1269
1305
  }
1270
- set(data){
1271
- this.cache.storage.setItem(this.cache.globalKey,JSON.stringify(data));
1272
- this.cache.channel.emit("Ziko-Storage-Updated",{});
1273
- Object.keys(data).forEach(key=>this.cache.oldItemKeys.add(key));
1306
+
1307
+ set(data) {
1308
+ this.cache.storage.setItem(this.cache.globalKey, JSON.stringify(data));
1309
+ if (this.cache.channel) this.cache.channel.emit("Ziko-Storage-Updated", data);
1274
1310
  this.#maintain();
1275
- return this
1311
+ return this;
1276
1312
  }
1277
- add(data){
1278
- const db={
1313
+
1314
+ add(data) {
1315
+ this.set({
1279
1316
  ...this.items,
1280
1317
  ...data
1281
- };
1282
- this.cache.storage.setItem(this.cache.globalKey,JSON.stringify(db));
1283
- this.#maintain();
1318
+ });
1284
1319
  return this;
1285
1320
  }
1286
- remove(...keys){
1287
- const db={...this.items};
1288
- for(let i=0;i<keys.length;i++){
1289
- delete db[keys[i]];
1290
- delete this[keys[i]];
1291
- }
1292
- this.set(db);
1321
+ remove(...keys) {
1322
+ const items = { ...this.items };
1323
+ keys.forEach(key => {
1324
+ delete items[key];
1325
+ delete this[key];
1326
+ this.cache.oldItemKeys.delete(key);
1327
+ });
1328
+ this.set(items);
1293
1329
  return this;
1294
1330
  }
1295
- get(key){
1331
+ get(key) {
1296
1332
  return this.items[key];
1297
1333
  }
1298
- clear(){
1334
+ clear() {
1299
1335
  this.cache.storage.removeItem(this.cache.globalKey);
1336
+ this.cache.oldItemKeys.forEach(k => delete this[k]);
1337
+ this.cache.oldItemKeys.clear();
1300
1338
  this.#maintain();
1301
1339
  return this;
1302
1340
  }
1303
-
1341
+ onStorageUpdated(callback) {
1342
+ if (this.cache.channel) {
1343
+ this.cache.channel.on("Ziko-Storage-Updated", callback);
1344
+ }
1345
+ return this;
1346
+ }
1304
1347
  }
1305
- const useLocaleStorage=(key,initialValue)=>new UseStorage(localStorage,key,initialValue);
1306
- const useSessionStorage=(key,initialValue)=>new UseStorage(sessionStorage,key,initialValue);
1348
+
1349
+ // factory functions
1350
+ const useLocaleStorage = (key, initialValue, use_channel = true) =>
1351
+ new UseStorage(localStorage, key, initialValue, use_channel);
1352
+
1353
+ const useSessionStorage = (key, initialValue, use_channel = true) =>
1354
+ new UseStorage(sessionStorage, key, initialValue, use_channel);
1307
1355
 
1308
1356
  const __State__ = {
1309
1357
  store : new Map(),
@@ -4755,76 +4803,79 @@ const timeTaken = callback => {
4755
4803
  };
4756
4804
 
4757
4805
  class UseEventEmitter {
4758
- constructor() {
4759
- this.events = {};
4760
- this.maxListeners = 10;
4806
+ constructor(maxListeners = 10) {
4807
+ this.events = {};
4808
+ this.maxListeners = maxListeners;
4761
4809
  }
4810
+
4762
4811
  on(event, listener) {
4763
- if (!this.events[event]) {
4764
- this.events[event] = [];
4765
- }
4766
- this.events[event].push(listener);
4767
- if (this.events[event].length > this.maxListeners) {
4768
- console.warn(`Warning: Possible memory leak. Event '${event}' has more than ${this.maxListeners} listeners.`);
4769
- }
4812
+ if (!this.events[event]) this.events[event] = [];
4813
+ this.events[event].push(listener);
4814
+ if (this.events[event].length > this.maxListeners) {
4815
+ console.warn(`Warning: Possible memory leak. Event '${event}' has more than ${this.maxListeners} listeners.`);
4816
+ }
4817
+ return this;
4770
4818
  }
4819
+
4771
4820
  once(event, listener) {
4772
- const onceListener = (data) => {
4773
- this.off(event, onceListener); // Remove the listener after it's been called
4774
- listener(data);
4775
- };
4776
- this.on(event, onceListener);
4821
+ const wrapper = (...args) => {
4822
+ this.off(event, wrapper);
4823
+ listener(...args);
4824
+ };
4825
+ return this.on(event, wrapper);
4777
4826
  }
4778
-
4827
+
4779
4828
  off(event, listener) {
4780
- const listeners = this.events[event];
4781
- if (listeners) {
4829
+ const listeners = this.events[event];
4830
+ if (!listeners) return this;
4831
+
4782
4832
  const index = listeners.indexOf(listener);
4783
4833
  if (index !== -1) {
4784
- listeners.splice(index, 1);
4834
+ listeners.splice(index, 1);
4785
4835
  }
4786
- }
4836
+
4837
+ return this;
4787
4838
  }
4788
-
4839
+
4789
4840
  emit(event, data) {
4790
- const listeners = this.events[event];
4791
- if (listeners) {
4792
- listeners.forEach(listener => {
4793
- listener(data);
4841
+ const listeners = this.events[event];
4842
+ if (!listeners) return false;
4843
+
4844
+ // Make a copy so removing listeners inside callbacks doesn't affect iteration
4845
+ [...listeners].forEach(listener => {
4846
+ try {
4847
+ listener(data);
4848
+ } catch (e) {
4849
+ console.error(`Error in listener for '${event}':`, e);
4850
+ }
4794
4851
  });
4795
- }
4796
- }
4797
-
4798
- clear(event) {
4799
- if (event) {
4800
- delete this.events[event];
4801
- } else {
4802
- this.events = {};
4803
- }
4852
+
4853
+ return true;
4804
4854
  }
4805
-
4806
- setMaxListener(event, max) {
4807
- this.maxListeners = max;
4855
+ remove(event){
4856
+ delete this.events[event];
4857
+ return this;
4808
4858
  }
4809
-
4810
- removeAllListeners(event) {
4811
- if (event) {
4812
- this.events[event] = [];
4813
- } else {
4859
+ clear() {
4814
4860
  this.events = {};
4815
- }
4861
+ return this;
4816
4862
  }
4817
- }
4818
4863
 
4819
- const useEventEmitter=()=>new UseEventEmitter();
4864
+ setMaxListeners(max) {
4865
+ this.maxListeners = max;
4866
+ return this;
4867
+ }
4868
+ }
4869
+
4870
+ const useEventEmitter = (maxListeners) => new UseEventEmitter(maxListeners);
4820
4871
 
4821
4872
  class ZikoUseFavIcon{
4822
- constructor(FavIcon,useEventEmitter=true){
4873
+ constructor(FavIcon,withEmitter=true){
4823
4874
  this.#init();
4824
4875
  this.cache={
4825
4876
  Emitter:null
4826
4877
  };
4827
- if(useEventEmitter)this.useEventEmitter();
4878
+ if(withEmitter)this.useEventEmitter();
4828
4879
  this.set(FavIcon);
4829
4880
  }
4830
4881
  #init(){
@@ -4853,7 +4904,7 @@ class ZikoUseFavIcon{
4853
4904
  }
4854
4905
 
4855
4906
  }
4856
- const useFavIcon=(FavIcon,useEventEmitter)=>new ZikoUseFavIcon(FavIcon,useEventEmitter);
4907
+ const useFavIcon=(FavIcon,withEmitter)=>new ZikoUseFavIcon(FavIcon,withEmitter);
4857
4908
 
4858
4909
  class ZikoMeta{
4859
4910
  constructor({viewport,charset,description,author,keywords}){
@@ -4933,7 +4984,7 @@ class ZikoUseTitle{
4933
4984
  return this;
4934
4985
  }
4935
4986
  }
4936
- const useTitle=(title, useEventEmitter)=>new ZikoUseTitle(title, useEventEmitter);
4987
+ const useTitle$1=(title, useEventEmitter)=>new ZikoUseTitle(title, useEventEmitter);
4937
4988
 
4938
4989
  // import {useLink} from "./";
4939
4990
  class ZikoHead{
@@ -4941,7 +4992,7 @@ class ZikoHead{
4941
4992
  this.html = globalThis?.document?.documentElement;
4942
4993
  this.head = globalThis?.document?.head;
4943
4994
 
4944
- title && useTitle(title);
4995
+ title && useTitle$1(title);
4945
4996
  lang && this.setLang(lang);
4946
4997
  icon && useFavIcon(icon);
4947
4998
  meta && useMeta(meta);
@@ -5178,7 +5229,7 @@ function useDerived(deriveFn, sources) {
5178
5229
  const subscribers = new Set();
5179
5230
 
5180
5231
  sources.forEach(source => {
5181
- const srcValue = source(); // getValue()
5232
+ const srcValue = source();
5182
5233
  srcValue._subscribe(() => {
5183
5234
  {
5184
5235
  const newVal = deriveFn(...sources.map(s => s().value));
@@ -5207,121 +5258,155 @@ const useReactive = (nested_value) => mapfun$1(
5207
5258
  nested_value
5208
5259
  );
5209
5260
 
5210
- class UseThreed {
5211
- #workerContent;
5261
+ class UseThread {
5262
+ #worker;
5263
+ #callbacks = new Map();
5264
+ #idCounter = 0;
5265
+
5212
5266
  constructor() {
5213
- this.#workerContent = (
5214
- function (msg) {
5267
+ const workerCode = `
5268
+ this.onmessage = function(e) {
5269
+ const { id, funStr, args, close } = e.data;
5215
5270
  try {
5216
- const func = new Function("return " + msg.data.fun)();
5217
- let result = func();
5218
- postMessage({ result });
5271
+ const func = new Function("return " + funStr)();
5272
+ const result = func(...args);
5273
+ postMessage({ id, result });
5219
5274
  } catch (error) {
5220
- postMessage({ error: error.message });
5275
+ postMessage({ id, error: error.message });
5221
5276
  } finally {
5222
- if (msg.data.close) self.close();
5277
+ if (close) self.close();
5223
5278
  }
5224
5279
  }
5225
- ).toString();
5226
- this.blob = new Blob(["this.onmessage = " + this.#workerContent], { type: "text/javascript" });
5227
- this.worker = new Worker(window.URL.createObjectURL(this.blob));
5280
+ `;
5281
+ const blob = new Blob([workerCode], { type: "text/javascript" });
5282
+ this.#worker = new Worker(URL.createObjectURL(blob));
5283
+
5284
+ this.#worker.addEventListener("message", (e) => {
5285
+ const { id, result, error } = e.data;
5286
+ const callback = this.#callbacks.get(id);
5287
+ if (!callback) return;
5288
+
5289
+ callback(result, error);
5290
+ this.#callbacks.delete(id);
5291
+ });
5228
5292
  }
5229
- call(func, callback, close = true) {
5230
- this.worker.postMessage({
5231
- fun: func.toString(),
5293
+ call(func, callback, args = [], close = true) {
5294
+ if (typeof func !== "function") throw new TypeError("func must be a function");
5295
+ const id = ++this.#idCounter;
5296
+ this.#callbacks.set(id, callback);
5297
+
5298
+ this.#worker.postMessage({
5299
+ id,
5300
+ funStr: func.toString(),
5301
+ args,
5232
5302
  close
5233
5303
  });
5234
- this.worker.onmessage = function (e) {
5235
- if (e.data.error) {
5236
- console.error(e.data.error);
5237
- } else {
5238
- callback(e.data.result);
5239
- }
5240
- };
5304
+
5241
5305
  return this;
5242
5306
  }
5243
- }
5244
5307
 
5245
- const useThread = (func, callback , close) => {
5246
- const T = new UseThreed();
5247
- if (func) {
5248
- T.call(func, callback , close);
5308
+ terminate() {
5309
+ this.#worker.terminate();
5249
5310
  }
5250
- return T;
5251
- };
5311
+ }
5252
5312
 
5253
- class UseRoot {
5254
- constructor(PropsMap, {namespace = 'Ziko', register, ValidateCssProps = false} = {}){
5255
- this.currentPropsMap = PropsMap;
5256
- this.namespace = namespace;
5257
- this.ValidateCssProps = ValidateCssProps;
5258
- // this.pairs = {};
5259
- // this.#maintain()
5260
- this.use(PropsMap);
5261
- }
5262
- use(PropsMap){
5263
- if(this.ValidateCssProps) ValidateCssProps(PropsMap);
5264
- this.currentPropsMap = PropsMap;
5265
- this.#maintain();
5266
- return this;
5313
+ /*
5314
+ [
5315
+ {
5316
+ query: '(min-width: 600px)',
5317
+ callback: () => console.log(1)
5318
+ },
5319
+ {
5320
+ query: '(max-width: 300px)',
5321
+ callback: () => console.log(2)
5267
5322
  }
5268
- #maintain(){
5269
- const root = globalThis?.document?.documentElement?.style;
5270
- for(let prop in this.currentPropsMap){
5271
- const cssProp = this.namespace ? `--${this.namespace}-${prop}` : `--${prop}`;
5272
- root.setProperty(
5273
- cssProp,
5274
- this.currentPropsMap[prop]
5275
- );
5276
- // Object.assign(this.pairs, {
5277
- // [prop] : `var(--${this.namespace}-${prop})`
5278
- // })
5279
- Object.defineProperty(this, prop, {
5280
- value: `var(${cssProp})`,
5281
- writable: true,
5282
- configurable: true,
5283
- enumerable: false
5284
- });
5285
- }
5323
+ ]
5324
+ */
5325
+
5326
+ class UseMediaQuery {
5327
+ #mediaQueryRules;
5328
+ #fallback;
5329
+ #lastCalledCallback = null;
5330
+
5331
+ constructor(mediaQueryRules = [], fallback = () => {}) {
5332
+ this.#mediaQueryRules = mediaQueryRules;
5333
+ this.#fallback = fallback;
5334
+
5335
+ this.#init();
5286
5336
  }
5287
- }
5288
5337
 
5289
- function ValidateCssProps(PropsMap){
5290
- const validProps = new Set(Object.keys(document.documentElement.style));
5291
- for (let key in PropsMap) {
5292
- if (!validProps.has(key)) {
5293
- throw new Error(`Invalid CSS property: "${key}"`);
5294
- }
5338
+ // PRIVATE: check if ANY rule matches
5339
+ #checkAllRules() {
5340
+ return this.#mediaQueryRules.some(
5341
+ ({ query }) => globalThis.matchMedia(query).matches
5342
+ );
5295
5343
  }
5296
- }
5297
5344
 
5298
- const useRoot = (PropsMap, {namespace, register, ValidateCssProps} = {}) => new UseRoot(PropsMap, {namespace, register, ValidateCssProps});
5345
+ // PRIVATE: installs listeners and initial checks
5346
+ #init() {
5347
+ this.#mediaQueryRules.forEach(({ query, callback }) => {
5348
+ const mediaQueryList = globalThis.matchMedia(query);
5299
5349
 
5300
- // Usage
5350
+ const checkMatches = () => {
5351
+ const anyMatch = this.#checkAllRules();
5301
5352
 
5302
- /*
5303
- const Styles = {
5304
- S1 : {
5305
- background : 'white',
5306
- color : 'darkblue'
5307
- border : '2px darkblue solid"'
5308
- },
5309
- S2 : {
5310
- background : 'darkblue',
5311
- color : 'white'
5312
- border : '2px green solid"'
5313
- }
5353
+ if (mediaQueryList.matches) {
5354
+ callback();
5355
+ this.#lastCalledCallback = callback;
5356
+ } else if (!anyMatch && this.#lastCalledCallback !== this.#fallback) {
5357
+ this.#fallback();
5358
+ this.#lastCalledCallback = this.#fallback;
5359
+ }
5360
+ };
5361
+
5362
+ checkMatches();
5363
+ mediaQueryList.addEventListener("change", checkMatches);
5364
+ });
5365
+ }
5314
5366
  }
5315
- const {use, border, background, color} = useRoot(Style.S1)
5316
5367
 
5317
- tags.p("Test useRoot ").style({
5318
- border,
5319
- color,
5320
- background,
5321
- padding : '10px'
5322
- })
5368
+ const useMediaQuery = (mediaQueryRules, fallback) =>
5369
+ new UseMediaQuery(mediaQueryRules, fallback);
5370
+
5371
+ class UseTitle {
5372
+ constructor(title = document.title, withEmitter = true) {
5373
+ this.cache = {
5374
+ emitter: null
5375
+ };
5323
5376
 
5324
- */
5377
+ if (withEmitter) this.useEventEmitter();
5378
+ this.set(title);
5379
+ }
5380
+
5381
+ useEventEmitter() {
5382
+ this.cache.emitter = useEventEmitter();
5383
+ return this;
5384
+ }
5385
+
5386
+ setTitle(title) {
5387
+ if (title !== document.title) {
5388
+ document.title = title;
5389
+
5390
+ if (this.cache.emitter) {
5391
+ this.cache.emitter.emit("ziko:title-changed", title);
5392
+ }
5393
+ }
5394
+ return this;
5395
+ }
5396
+
5397
+ get current() {
5398
+ return document.title;
5399
+ }
5400
+
5401
+ onChange(callback) {
5402
+ if (this.cache.emitter) {
5403
+ this.cache.emitter.on("ziko:title-changed", callback);
5404
+ }
5405
+ return this;
5406
+ }
5407
+ }
5408
+
5409
+ const useTitle = (title, withEmitter = true) => new UseTitle(title, withEmitter);
5325
5410
 
5326
5411
  let {sqrt, cos, sin, exp, log, cosh, sinh} = Math;
5327
5412
  // Math.abs = new Proxy(Math.abs, {
@@ -5386,4 +5471,4 @@ if(globalThis?.document){
5386
5471
  document?.addEventListener("DOMContentLoaded", __Ziko__.__Config__.init());
5387
5472
  }
5388
5473
 
5389
- export { App, Base, Clock, Combinaison, Complex, E, EPSILON, FileBasedRouting, Flex, HTMLWrapper, Logic$1 as Logic, Matrix, PI$2 as PI, Permutation, Random, SPA, SVGWrapper, Scheduler, Suspense, Switch, Tick, TimeAnimation, TimeLoop, TimeScheduler, UIElement$1 as UIElement, UIHTMLWrapper, UINode, UISVGWrapper, UISwitch, UIView, UseRoot, Utils, View, ZikoApp, ZikoEventClick, ZikoEventClipboard, ZikoEventCustom, ZikoEventDrag, ZikoEventFocus, ZikoEventHash, ZikoEventKey, ZikoEventMouse, ZikoEventPointer, ZikoEventTouch, ZikoEventWheel, ZikoSPA, ZikoUIFlex, ZikoUISuspense, ZikoUIText, __ZikoEvent__, abs, accum, acos$1 as acos, acosh, acot, add, animation, arange, arc, arr2str, asin, asinh, atan, atan2, atanh, back, bindCustomEvent, bindHashEvent, bindTouchEvent, bind_click_event, bind_clipboard_event, bind_drag_event, bind_focus_event, bind_key_event, bind_mouse_event, bind_pointer_event, bind_wheel_event, cartesianProduct, ceil, clamp, clock, combinaison, complex, cos$2 as cos, cosh$1 as cosh, cot, coth, csc, csv2arr, csv2json, csv2matrix, csv2object, csv2sql, debounce, defineParamsGetter, define_wc, deg2rad, discret, div, e, elastic, fact, floor, geomspace, getEvent, hypot, inRange, in_back, in_bounce, in_circ, in_cubic, in_elastic, in_expo, in_out_back, in_out_bounce, in_out_circ, in_out_cubic, in_out_elastic, in_out_expo, in_out_quad, in_out_quart, in_out_quint, in_out_sin, in_quad, in_quart, in_quint, in_sin, isApproximatlyEqual, isStateGetter, json2arr, json2css, json2csv, json2csvFile, json2xml, json2xmlFile, json2yml, json2ymlFile, lerp, linear, linspace, ln, logspace, loop, map$1 as map, mapfun$1 as mapfun, matrix, matrix2, matrix3, matrix4, max, min, modulo, mul, norm, nums, obj2str, ones, out_back, out_bounce, out_circ, out_cubic, out_elastic, out_expo, out_quad, out_quart, out_quint, out_sin, pgcd, pow$1 as pow, powerSet, ppcm, preload, prod, rad2deg, round, sec, sig, sign, sin$2 as sin, sinc, sinh$1 as sinh, sleep, sqrt$2 as sqrt, sqrtn, step, step_fps, sub, subSet, sum, svg2ascii, svg2img, svg2imgUrl, svg2str, tags, tan, tanh, text, throttle, tick, timeTaken, time_memory_Taken, timeout, useDerived, useEventEmitter, useLocaleStorage, useReactive, useRoot, useSessionStorage, useState, useThread, wait, waitForUIElm, waitForUIElmSync, zeros };
5474
+ export { App, Base, Clock, Combinaison, Complex, E, EPSILON, FileBasedRouting, Flex, HTMLWrapper, Logic$1 as Logic, Matrix, PI$2 as PI, Permutation, Random, SPA, SVGWrapper, Scheduler, Suspense, Switch, Tick, TimeAnimation, TimeLoop, TimeScheduler, UIElement$1 as UIElement, UIHTMLWrapper, UINode, UISVGWrapper, UISwitch, UIView, UseThread, Utils, View, ZikoApp, ZikoEventClick, ZikoEventClipboard, ZikoEventCustom, ZikoEventDrag, ZikoEventFocus, ZikoEventHash, ZikoEventKey, ZikoEventMouse, ZikoEventPointer, ZikoEventTouch, ZikoEventWheel, ZikoSPA, ZikoUIFlex, ZikoUISuspense, ZikoUIText, __ZikoEvent__, abs, accum, acos$1 as acos, acosh, acot, add, animation, arange, arc, arr2str, asin, asinh, atan, atan2, atanh, back, bindCustomEvent, bindHashEvent, bindTouchEvent, bind_click_event, bind_clipboard_event, bind_drag_event, bind_focus_event, bind_key_event, bind_mouse_event, bind_pointer_event, bind_wheel_event, cartesianProduct, ceil, clamp, clock, combinaison, complex, cos$2 as cos, cosh$1 as cosh, cot, coth, csc, csv2arr, csv2json, csv2matrix, csv2object, csv2sql, debounce, defineParamsGetter, define_wc, deg2rad, discret, div, e, elastic, fact, floor, geomspace, getEvent, hypot, inRange, in_back, in_bounce, in_circ, in_cubic, in_elastic, in_expo, in_out_back, in_out_bounce, in_out_circ, in_out_cubic, in_out_elastic, in_out_expo, in_out_quad, in_out_quart, in_out_quint, in_out_sin, in_quad, in_quart, in_quint, in_sin, isApproximatlyEqual, isStateGetter, json2arr, json2css, json2csv, json2csvFile, json2xml, json2xmlFile, json2yml, json2ymlFile, lerp, linear, linspace, ln, logspace, loop, map$1 as map, mapfun$1 as mapfun, matrix, matrix2, matrix3, matrix4, max, min, modulo, mul, norm, nums, obj2str, ones, out_back, out_bounce, out_circ, out_cubic, out_elastic, out_expo, out_quad, out_quart, out_quint, out_sin, pgcd, pow$1 as pow, powerSet, ppcm, preload, prod, rad2deg, round, sec, sig, sign, sin$2 as sin, sinc, sinh$1 as sinh, sleep, sqrt$2 as sqrt, sqrtn, step, step_fps, sub, subSet, sum, svg2ascii, svg2img, svg2imgUrl, svg2str, tags, tan, tanh, text, throttle, tick, timeTaken, time_memory_Taken, timeout, useChannel, useDerived, useEventEmitter, useLocaleStorage, useMediaQuery, useReactive, useSessionStorage, useState, useTitle, wait, waitForUIElm, waitForUIElmSync, zeros };