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.cjs 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
@@ -1180,132 +1180,180 @@ const __CACHE__ = {
1180
1180
  };
1181
1181
 
1182
1182
  class UseChannel {
1183
+ #channel;
1184
+ #eventData;
1185
+ #handlers;
1186
+ #uuid;
1187
+ #subscribers;
1188
+ #currentRooms;
1183
1189
  constructor(name = "") {
1184
- this.channel = new BroadcastChannel(name);
1185
- this.eventData = new Map();
1186
- this.handlers = new Map();
1187
- this.uuid = "ziko-channel:" + Random.string(10);
1188
- this.subscribers = new Set([this.uuid]);
1189
-
1190
- this.channel.addEventListener("message", (e) => {
1191
- const { last_sent_event, userId, eventData } = e.data;
1192
-
1193
- // ignore own events
1194
- if (userId === this.uuid) return;
1195
-
1196
- this.subscribers.add(userId);
1197
-
1198
- // sync data
1199
- this.eventData = new Map(eventData);
1200
-
1201
- const data = this.eventData.get(last_sent_event);
1202
- const handlers = this.handlers.get(last_sent_event);
1203
-
1204
- if (handlers) {
1205
- handlers.forEach(fn => fn(data));
1206
- }
1190
+ this.#channel = new BroadcastChannel(name);
1191
+ this.#eventData = new Map();
1192
+ this.#handlers = new Map(); // Map<event, Array<{fn, rooms}>>
1193
+ this.#uuid = "ziko-channel:" + Random.string(10);
1194
+ this.#subscribers = new Set([this.#uuid]);
1195
+ this.#currentRooms = new Set();
1196
+ this.#channel.addEventListener("message", (e) => {
1197
+ const { last_sent_event, userId, eventData, rooms } = e.data;
1198
+ if (userId === this.#uuid) return; // ignore own messages
1199
+ // broadcast if no rooms, else check intersection
1200
+ if (rooms && rooms.length && !rooms.some(r => this.#currentRooms.has(r))) return;
1201
+ this.#subscribers.add(userId);
1202
+ this.#eventData = new Map(eventData);
1203
+ const handlersList = this.#handlers.get(last_sent_event);
1204
+ if (!handlersList) return;
1205
+ handlersList.forEach(({ fn, rooms: handlerRooms }) => {
1206
+ // trigger if listener has no room filter, or intersects subscriber rooms
1207
+ if (!handlerRooms || handlerRooms.length === 0 ||
1208
+ !rooms || rooms.some(r => handlerRooms.includes(r))) {
1209
+ fn(this.#eventData.get(last_sent_event));
1210
+ }
1211
+ });
1207
1212
  });
1208
1213
  }
1209
1214
 
1210
- emit(event, data) {
1211
- this.eventData.set(event, data);
1212
-
1213
- this.channel.postMessage({
1214
- eventData: this.eventData,
1215
+ emit(event, data, rooms) {
1216
+ this.#eventData.set(event, data);
1217
+ if(typeof rooms === 'string') rooms = [rooms];
1218
+ this.#channel.postMessage({
1219
+ eventData: Array.from(this.#eventData.entries()),
1215
1220
  last_sent_event: event,
1216
- userId: this.uuid
1221
+ userId: this.#uuid,
1222
+ rooms: rooms && rooms.length ? rooms : undefined
1217
1223
  });
1218
1224
  return this;
1219
1225
  }
1220
-
1221
- on(event, handler = console.log) {
1222
- if (!this.handlers.has(event)) {
1223
- this.handlers.set(event, []);
1224
- }
1225
- this.handlers.get(event).push(handler);
1226
+ on(event, handler = console.log, rooms) {
1227
+ if (!this.#handlers.has(event)) this.#handlers.set(event, []);
1228
+ if(typeof rooms === 'string') rooms = [rooms];
1229
+ this.#handlers.get(event).push({ fn: handler, rooms });
1226
1230
  return this;
1227
1231
  }
1228
-
1229
- close() {
1230
- this.channel.close();
1232
+ off(event, handler) {
1233
+ if (!this.#handlers.has(event)) return this;
1234
+ this.#handlers.set(
1235
+ event,
1236
+ this.#handlers.get(event).filter(h => h.fn !== handler)
1237
+ );
1231
1238
  return this;
1232
1239
  }
1233
-
1234
- get broadcast() {
1240
+ once(event, handler, rooms) {
1241
+ const wrapper = (data) => {
1242
+ handler(data);
1243
+ this.off(event, wrapper);
1244
+ };
1245
+ this.on(event, wrapper, rooms);
1246
+ return this;
1247
+ }
1248
+ join(...rooms) {
1249
+ rooms.forEach(r => this.#currentRooms.add(r));
1250
+ return this;
1251
+ }
1252
+ leave(...rooms) {
1253
+ if (!rooms.length) this.#currentRooms.clear();
1254
+ else rooms.forEach(r => this.#currentRooms.delete(r));
1255
+ return this;
1256
+ }
1257
+ close() {
1258
+ this.#channel.close();
1235
1259
  return this;
1236
1260
  }
1237
1261
  }
1238
1262
 
1239
1263
  const useChannel = (name) => new UseChannel(name);
1240
1264
 
1241
- // To do : remove old items
1242
- class UseStorage{
1243
- constructor(storage, globalKey, initialValue){
1244
- this.cache={
1265
+ class UseStorage {
1266
+ constructor(storage, globalKey, initialValue, use_channel = true) {
1267
+ this.cache = {
1245
1268
  storage,
1246
1269
  globalKey,
1247
- channel:useChannel(`Ziko:useStorage-${globalKey}`),
1248
- oldItemKeys:new Set()
1270
+ channel: use_channel ? useChannel(`Ziko:useStorage-${globalKey}`) : null,
1271
+ oldItemKeys: new Set()
1249
1272
  };
1250
- this.#init(initialValue);
1251
- this.#maintain();
1273
+
1274
+ this.#init(initialValue, use_channel);
1252
1275
  }
1253
- get items(){
1254
- return JSON.parse(this.cache.storage[this.cache.globalKey]??null);
1276
+
1277
+ get items() {
1278
+ const raw = this.cache.storage.getItem(this.cache.globalKey);
1279
+ if (!raw) return {};
1280
+ try {
1281
+ return JSON.parse(raw);
1282
+ } catch {
1283
+ return {};
1284
+ }
1255
1285
  }
1286
+
1256
1287
  #maintain() {
1257
- for(let i in this.items)Object.assign(this, { [[i]]: this.items[i] });
1258
- }
1259
- #init(initialValue){
1260
- this.cache.channel=useChannel(`Ziko:useStorage-${this.cache.globalKey}`);
1261
- this.cache.channel.on("Ziko-Storage-Updated",()=>this.#maintain());
1262
- if(!initialValue)return;
1263
- if(this.cache.storage[this.cache.globalKey]){
1264
- Object.keys(this.items).forEach(key=>this.cache.oldItemKeys.add(key));
1265
- // console.group("Ziko:useStorage")
1266
- // console.warn(`Storage key '${this.cache.globalKey}' already exists. we will not overwrite it.`);
1267
- // console.info(`%cWe'll keep the existing data.`,"background-color:#2222dd; color:gold;");
1268
- // console.group("")
1288
+ const items = this.items;
1289
+ this.cache.oldItemKeys.forEach(k => delete this[k]);
1290
+ for (const key in items) {
1291
+ this[key] = items[key];
1292
+ this.cache.oldItemKeys.add(key);
1293
+ }
1294
+ }
1295
+ #init(initialValue, use_channel) {
1296
+ if (use_channel && this.cache.channel) this.cache.channel.on("Ziko-Storage-Updated", () => this.#maintain());
1297
+ if (!initialValue) {
1298
+ this.#maintain();
1299
+ return;
1269
1300
  }
1301
+ if (this.cache.storage.getItem(this.cache.globalKey)) {
1302
+ const existing = this.items;
1303
+ Object.keys(existing).forEach(k => this.cache.oldItemKeys.add(k));
1304
+ this.#maintain();
1305
+ }
1270
1306
  else this.set(initialValue);
1271
1307
  }
1272
- set(data){
1273
- this.cache.storage.setItem(this.cache.globalKey,JSON.stringify(data));
1274
- this.cache.channel.emit("Ziko-Storage-Updated",{});
1275
- Object.keys(data).forEach(key=>this.cache.oldItemKeys.add(key));
1308
+
1309
+ set(data) {
1310
+ this.cache.storage.setItem(this.cache.globalKey, JSON.stringify(data));
1311
+ if (this.cache.channel) this.cache.channel.emit("Ziko-Storage-Updated", data);
1276
1312
  this.#maintain();
1277
- return this
1313
+ return this;
1278
1314
  }
1279
- add(data){
1280
- const db={
1315
+
1316
+ add(data) {
1317
+ this.set({
1281
1318
  ...this.items,
1282
1319
  ...data
1283
- };
1284
- this.cache.storage.setItem(this.cache.globalKey,JSON.stringify(db));
1285
- this.#maintain();
1320
+ });
1286
1321
  return this;
1287
1322
  }
1288
- remove(...keys){
1289
- const db={...this.items};
1290
- for(let i=0;i<keys.length;i++){
1291
- delete db[keys[i]];
1292
- delete this[keys[i]];
1293
- }
1294
- this.set(db);
1323
+ remove(...keys) {
1324
+ const items = { ...this.items };
1325
+ keys.forEach(key => {
1326
+ delete items[key];
1327
+ delete this[key];
1328
+ this.cache.oldItemKeys.delete(key);
1329
+ });
1330
+ this.set(items);
1295
1331
  return this;
1296
1332
  }
1297
- get(key){
1333
+ get(key) {
1298
1334
  return this.items[key];
1299
1335
  }
1300
- clear(){
1336
+ clear() {
1301
1337
  this.cache.storage.removeItem(this.cache.globalKey);
1338
+ this.cache.oldItemKeys.forEach(k => delete this[k]);
1339
+ this.cache.oldItemKeys.clear();
1302
1340
  this.#maintain();
1303
1341
  return this;
1304
1342
  }
1305
-
1343
+ onStorageUpdated(callback) {
1344
+ if (this.cache.channel) {
1345
+ this.cache.channel.on("Ziko-Storage-Updated", callback);
1346
+ }
1347
+ return this;
1348
+ }
1306
1349
  }
1307
- const useLocaleStorage=(key,initialValue)=>new UseStorage(localStorage,key,initialValue);
1308
- const useSessionStorage=(key,initialValue)=>new UseStorage(sessionStorage,key,initialValue);
1350
+
1351
+ // factory functions
1352
+ const useLocaleStorage = (key, initialValue, use_channel = true) =>
1353
+ new UseStorage(localStorage, key, initialValue, use_channel);
1354
+
1355
+ const useSessionStorage = (key, initialValue, use_channel = true) =>
1356
+ new UseStorage(sessionStorage, key, initialValue, use_channel);
1309
1357
 
1310
1358
  const __State__ = {
1311
1359
  store : new Map(),
@@ -4757,76 +4805,79 @@ const timeTaken = callback => {
4757
4805
  };
4758
4806
 
4759
4807
  class UseEventEmitter {
4760
- constructor() {
4761
- this.events = {};
4762
- this.maxListeners = 10;
4808
+ constructor(maxListeners = 10) {
4809
+ this.events = {};
4810
+ this.maxListeners = maxListeners;
4763
4811
  }
4812
+
4764
4813
  on(event, listener) {
4765
- if (!this.events[event]) {
4766
- this.events[event] = [];
4767
- }
4768
- this.events[event].push(listener);
4769
- if (this.events[event].length > this.maxListeners) {
4770
- console.warn(`Warning: Possible memory leak. Event '${event}' has more than ${this.maxListeners} listeners.`);
4771
- }
4814
+ if (!this.events[event]) this.events[event] = [];
4815
+ this.events[event].push(listener);
4816
+ if (this.events[event].length > this.maxListeners) {
4817
+ console.warn(`Warning: Possible memory leak. Event '${event}' has more than ${this.maxListeners} listeners.`);
4818
+ }
4819
+ return this;
4772
4820
  }
4821
+
4773
4822
  once(event, listener) {
4774
- const onceListener = (data) => {
4775
- this.off(event, onceListener); // Remove the listener after it's been called
4776
- listener(data);
4777
- };
4778
- this.on(event, onceListener);
4823
+ const wrapper = (...args) => {
4824
+ this.off(event, wrapper);
4825
+ listener(...args);
4826
+ };
4827
+ return this.on(event, wrapper);
4779
4828
  }
4780
-
4829
+
4781
4830
  off(event, listener) {
4782
- const listeners = this.events[event];
4783
- if (listeners) {
4831
+ const listeners = this.events[event];
4832
+ if (!listeners) return this;
4833
+
4784
4834
  const index = listeners.indexOf(listener);
4785
4835
  if (index !== -1) {
4786
- listeners.splice(index, 1);
4836
+ listeners.splice(index, 1);
4787
4837
  }
4788
- }
4838
+
4839
+ return this;
4789
4840
  }
4790
-
4841
+
4791
4842
  emit(event, data) {
4792
- const listeners = this.events[event];
4793
- if (listeners) {
4794
- listeners.forEach(listener => {
4795
- listener(data);
4843
+ const listeners = this.events[event];
4844
+ if (!listeners) return false;
4845
+
4846
+ // Make a copy so removing listeners inside callbacks doesn't affect iteration
4847
+ [...listeners].forEach(listener => {
4848
+ try {
4849
+ listener(data);
4850
+ } catch (e) {
4851
+ console.error(`Error in listener for '${event}':`, e);
4852
+ }
4796
4853
  });
4797
- }
4798
- }
4799
-
4800
- clear(event) {
4801
- if (event) {
4802
- delete this.events[event];
4803
- } else {
4804
- this.events = {};
4805
- }
4854
+
4855
+ return true;
4806
4856
  }
4807
-
4808
- setMaxListener(event, max) {
4809
- this.maxListeners = max;
4857
+ remove(event){
4858
+ delete this.events[event];
4859
+ return this;
4810
4860
  }
4811
-
4812
- removeAllListeners(event) {
4813
- if (event) {
4814
- this.events[event] = [];
4815
- } else {
4861
+ clear() {
4816
4862
  this.events = {};
4817
- }
4863
+ return this;
4818
4864
  }
4819
- }
4820
4865
 
4821
- const useEventEmitter=()=>new UseEventEmitter();
4866
+ setMaxListeners(max) {
4867
+ this.maxListeners = max;
4868
+ return this;
4869
+ }
4870
+ }
4871
+
4872
+ const useEventEmitter = (maxListeners) => new UseEventEmitter(maxListeners);
4822
4873
 
4823
4874
  class ZikoUseFavIcon{
4824
- constructor(FavIcon,useEventEmitter=true){
4875
+ constructor(FavIcon,withEmitter=true){
4825
4876
  this.#init();
4826
4877
  this.cache={
4827
4878
  Emitter:null
4828
4879
  };
4829
- if(useEventEmitter)this.useEventEmitter();
4880
+ if(withEmitter)this.useEventEmitter();
4830
4881
  this.set(FavIcon);
4831
4882
  }
4832
4883
  #init(){
@@ -4855,7 +4906,7 @@ class ZikoUseFavIcon{
4855
4906
  }
4856
4907
 
4857
4908
  }
4858
- const useFavIcon=(FavIcon,useEventEmitter)=>new ZikoUseFavIcon(FavIcon,useEventEmitter);
4909
+ const useFavIcon=(FavIcon,withEmitter)=>new ZikoUseFavIcon(FavIcon,withEmitter);
4859
4910
 
4860
4911
  class ZikoMeta{
4861
4912
  constructor({viewport,charset,description,author,keywords}){
@@ -4935,7 +4986,7 @@ class ZikoUseTitle{
4935
4986
  return this;
4936
4987
  }
4937
4988
  }
4938
- const useTitle=(title, useEventEmitter)=>new ZikoUseTitle(title, useEventEmitter);
4989
+ const useTitle$1=(title, useEventEmitter)=>new ZikoUseTitle(title, useEventEmitter);
4939
4990
 
4940
4991
  // import {useLink} from "./";
4941
4992
  class ZikoHead{
@@ -4943,7 +4994,7 @@ class ZikoHead{
4943
4994
  this.html = globalThis?.document?.documentElement;
4944
4995
  this.head = globalThis?.document?.head;
4945
4996
 
4946
- title && useTitle(title);
4997
+ title && useTitle$1(title);
4947
4998
  lang && this.setLang(lang);
4948
4999
  icon && useFavIcon(icon);
4949
5000
  meta && useMeta(meta);
@@ -5180,7 +5231,7 @@ function useDerived(deriveFn, sources) {
5180
5231
  const subscribers = new Set();
5181
5232
 
5182
5233
  sources.forEach(source => {
5183
- const srcValue = source(); // getValue()
5234
+ const srcValue = source();
5184
5235
  srcValue._subscribe(() => {
5185
5236
  {
5186
5237
  const newVal = deriveFn(...sources.map(s => s().value));
@@ -5209,121 +5260,155 @@ const useReactive = (nested_value) => mapfun$1(
5209
5260
  nested_value
5210
5261
  );
5211
5262
 
5212
- class UseThreed {
5213
- #workerContent;
5263
+ class UseThread {
5264
+ #worker;
5265
+ #callbacks = new Map();
5266
+ #idCounter = 0;
5267
+
5214
5268
  constructor() {
5215
- this.#workerContent = (
5216
- function (msg) {
5269
+ const workerCode = `
5270
+ this.onmessage = function(e) {
5271
+ const { id, funStr, args, close } = e.data;
5217
5272
  try {
5218
- const func = new Function("return " + msg.data.fun)();
5219
- let result = func();
5220
- postMessage({ result });
5273
+ const func = new Function("return " + funStr)();
5274
+ const result = func(...args);
5275
+ postMessage({ id, result });
5221
5276
  } catch (error) {
5222
- postMessage({ error: error.message });
5277
+ postMessage({ id, error: error.message });
5223
5278
  } finally {
5224
- if (msg.data.close) self.close();
5279
+ if (close) self.close();
5225
5280
  }
5226
5281
  }
5227
- ).toString();
5228
- this.blob = new Blob(["this.onmessage = " + this.#workerContent], { type: "text/javascript" });
5229
- this.worker = new Worker(window.URL.createObjectURL(this.blob));
5282
+ `;
5283
+ const blob = new Blob([workerCode], { type: "text/javascript" });
5284
+ this.#worker = new Worker(URL.createObjectURL(blob));
5285
+
5286
+ this.#worker.addEventListener("message", (e) => {
5287
+ const { id, result, error } = e.data;
5288
+ const callback = this.#callbacks.get(id);
5289
+ if (!callback) return;
5290
+
5291
+ callback(result, error);
5292
+ this.#callbacks.delete(id);
5293
+ });
5230
5294
  }
5231
- call(func, callback, close = true) {
5232
- this.worker.postMessage({
5233
- fun: func.toString(),
5295
+ call(func, callback, args = [], close = true) {
5296
+ if (typeof func !== "function") throw new TypeError("func must be a function");
5297
+ const id = ++this.#idCounter;
5298
+ this.#callbacks.set(id, callback);
5299
+
5300
+ this.#worker.postMessage({
5301
+ id,
5302
+ funStr: func.toString(),
5303
+ args,
5234
5304
  close
5235
5305
  });
5236
- this.worker.onmessage = function (e) {
5237
- if (e.data.error) {
5238
- console.error(e.data.error);
5239
- } else {
5240
- callback(e.data.result);
5241
- }
5242
- };
5306
+
5243
5307
  return this;
5244
5308
  }
5245
- }
5246
5309
 
5247
- const useThread = (func, callback , close) => {
5248
- const T = new UseThreed();
5249
- if (func) {
5250
- T.call(func, callback , close);
5310
+ terminate() {
5311
+ this.#worker.terminate();
5251
5312
  }
5252
- return T;
5253
- };
5313
+ }
5254
5314
 
5255
- class UseRoot {
5256
- constructor(PropsMap, {namespace = 'Ziko', register, ValidateCssProps = false} = {}){
5257
- this.currentPropsMap = PropsMap;
5258
- this.namespace = namespace;
5259
- this.ValidateCssProps = ValidateCssProps;
5260
- // this.pairs = {};
5261
- // this.#maintain()
5262
- this.use(PropsMap);
5263
- }
5264
- use(PropsMap){
5265
- if(this.ValidateCssProps) ValidateCssProps(PropsMap);
5266
- this.currentPropsMap = PropsMap;
5267
- this.#maintain();
5268
- return this;
5315
+ /*
5316
+ [
5317
+ {
5318
+ query: '(min-width: 600px)',
5319
+ callback: () => console.log(1)
5320
+ },
5321
+ {
5322
+ query: '(max-width: 300px)',
5323
+ callback: () => console.log(2)
5269
5324
  }
5270
- #maintain(){
5271
- const root = globalThis?.document?.documentElement?.style;
5272
- for(let prop in this.currentPropsMap){
5273
- const cssProp = this.namespace ? `--${this.namespace}-${prop}` : `--${prop}`;
5274
- root.setProperty(
5275
- cssProp,
5276
- this.currentPropsMap[prop]
5277
- );
5278
- // Object.assign(this.pairs, {
5279
- // [prop] : `var(--${this.namespace}-${prop})`
5280
- // })
5281
- Object.defineProperty(this, prop, {
5282
- value: `var(${cssProp})`,
5283
- writable: true,
5284
- configurable: true,
5285
- enumerable: false
5286
- });
5287
- }
5325
+ ]
5326
+ */
5327
+
5328
+ class UseMediaQuery {
5329
+ #mediaQueryRules;
5330
+ #fallback;
5331
+ #lastCalledCallback = null;
5332
+
5333
+ constructor(mediaQueryRules = [], fallback = () => {}) {
5334
+ this.#mediaQueryRules = mediaQueryRules;
5335
+ this.#fallback = fallback;
5336
+
5337
+ this.#init();
5288
5338
  }
5289
- }
5290
5339
 
5291
- function ValidateCssProps(PropsMap){
5292
- const validProps = new Set(Object.keys(document.documentElement.style));
5293
- for (let key in PropsMap) {
5294
- if (!validProps.has(key)) {
5295
- throw new Error(`Invalid CSS property: "${key}"`);
5296
- }
5340
+ // PRIVATE: check if ANY rule matches
5341
+ #checkAllRules() {
5342
+ return this.#mediaQueryRules.some(
5343
+ ({ query }) => globalThis.matchMedia(query).matches
5344
+ );
5297
5345
  }
5298
- }
5299
5346
 
5300
- const useRoot = (PropsMap, {namespace, register, ValidateCssProps} = {}) => new UseRoot(PropsMap, {namespace, register, ValidateCssProps});
5347
+ // PRIVATE: installs listeners and initial checks
5348
+ #init() {
5349
+ this.#mediaQueryRules.forEach(({ query, callback }) => {
5350
+ const mediaQueryList = globalThis.matchMedia(query);
5301
5351
 
5302
- // Usage
5352
+ const checkMatches = () => {
5353
+ const anyMatch = this.#checkAllRules();
5303
5354
 
5304
- /*
5305
- const Styles = {
5306
- S1 : {
5307
- background : 'white',
5308
- color : 'darkblue'
5309
- border : '2px darkblue solid"'
5310
- },
5311
- S2 : {
5312
- background : 'darkblue',
5313
- color : 'white'
5314
- border : '2px green solid"'
5315
- }
5355
+ if (mediaQueryList.matches) {
5356
+ callback();
5357
+ this.#lastCalledCallback = callback;
5358
+ } else if (!anyMatch && this.#lastCalledCallback !== this.#fallback) {
5359
+ this.#fallback();
5360
+ this.#lastCalledCallback = this.#fallback;
5361
+ }
5362
+ };
5363
+
5364
+ checkMatches();
5365
+ mediaQueryList.addEventListener("change", checkMatches);
5366
+ });
5367
+ }
5316
5368
  }
5317
- const {use, border, background, color} = useRoot(Style.S1)
5318
5369
 
5319
- tags.p("Test useRoot ").style({
5320
- border,
5321
- color,
5322
- background,
5323
- padding : '10px'
5324
- })
5370
+ const useMediaQuery = (mediaQueryRules, fallback) =>
5371
+ new UseMediaQuery(mediaQueryRules, fallback);
5372
+
5373
+ class UseTitle {
5374
+ constructor(title = document.title, withEmitter = true) {
5375
+ this.cache = {
5376
+ emitter: null
5377
+ };
5325
5378
 
5326
- */
5379
+ if (withEmitter) this.useEventEmitter();
5380
+ this.set(title);
5381
+ }
5382
+
5383
+ useEventEmitter() {
5384
+ this.cache.emitter = useEventEmitter();
5385
+ return this;
5386
+ }
5387
+
5388
+ setTitle(title) {
5389
+ if (title !== document.title) {
5390
+ document.title = title;
5391
+
5392
+ if (this.cache.emitter) {
5393
+ this.cache.emitter.emit("ziko:title-changed", title);
5394
+ }
5395
+ }
5396
+ return this;
5397
+ }
5398
+
5399
+ get current() {
5400
+ return document.title;
5401
+ }
5402
+
5403
+ onChange(callback) {
5404
+ if (this.cache.emitter) {
5405
+ this.cache.emitter.on("ziko:title-changed", callback);
5406
+ }
5407
+ return this;
5408
+ }
5409
+ }
5410
+
5411
+ const useTitle = (title, withEmitter = true) => new UseTitle(title, withEmitter);
5327
5412
 
5328
5413
  let {sqrt, cos, sin, exp, log, cosh, sinh} = Math;
5329
5414
  // Math.abs = new Proxy(Math.abs, {
@@ -5418,7 +5503,7 @@ exports.UINode = UINode;
5418
5503
  exports.UISVGWrapper = UISVGWrapper;
5419
5504
  exports.UISwitch = UISwitch;
5420
5505
  exports.UIView = UIView;
5421
- exports.UseRoot = UseRoot;
5506
+ exports.UseThread = UseThread;
5422
5507
  exports.Utils = Utils;
5423
5508
  exports.View = View;
5424
5509
  exports.ZikoApp = ZikoApp;
@@ -5590,14 +5675,15 @@ exports.tick = tick;
5590
5675
  exports.timeTaken = timeTaken;
5591
5676
  exports.time_memory_Taken = time_memory_Taken;
5592
5677
  exports.timeout = timeout;
5678
+ exports.useChannel = useChannel;
5593
5679
  exports.useDerived = useDerived;
5594
5680
  exports.useEventEmitter = useEventEmitter;
5595
5681
  exports.useLocaleStorage = useLocaleStorage;
5682
+ exports.useMediaQuery = useMediaQuery;
5596
5683
  exports.useReactive = useReactive;
5597
- exports.useRoot = useRoot;
5598
5684
  exports.useSessionStorage = useSessionStorage;
5599
5685
  exports.useState = useState;
5600
- exports.useThread = useThread;
5686
+ exports.useTitle = useTitle;
5601
5687
  exports.wait = wait;
5602
5688
  exports.waitForUIElm = waitForUIElm;
5603
5689
  exports.waitForUIElmSync = waitForUIElmSync;