ziko 1.1.1 → 1.2.0

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 : Tue Jul 28 2026 17:04:51 GMT+0100 (UTC+01:00)
5
+ Date : Thu Jul 30 2026 14:31:45 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
@@ -1874,115 +1874,134 @@ class UseIPC {
1874
1874
  const useIPC = (name) => new UseIPC(name);
1875
1875
 
1876
1876
  class UseStorage {
1877
- constructor(storage, globalKey, initialValue, use_channel = true) {
1878
- this.cache = {
1879
- storage,
1880
- globalKey,
1881
- channel: use_channel ? useIPC(`Ziko:useStorage-${globalKey}`) : null,
1882
- oldItemKeys: new Set()
1883
- };
1877
+ static RESERVED_KEYS = new Set([
1878
+ "cache", "items", "set", "add", "remove", "get", "clear", "onStorageUpdated"
1879
+ ]);
1884
1880
 
1885
- this.#init(initialValue, use_channel);
1886
- }
1881
+ constructor(storage, globalKey, initialValue, use_channel = true) {
1882
+ this.cache = {
1883
+ storage,
1884
+ globalKey,
1885
+ channel: use_channel ? useIPC(`Ziko:useStorage-${globalKey}`) : null,
1886
+ oldItemKeys: new Set()
1887
+ };
1887
1888
 
1888
- get items() {
1889
- const raw = this.cache.storage.getItem(this.cache.globalKey);
1890
- if (!raw) return {};
1891
- try {
1892
- return JSON.parse(raw);
1893
- } catch {
1894
- return {};
1895
- }
1896
- }
1889
+ this.#init(initialValue, use_channel);
1890
+ }
1897
1891
 
1898
- #maintain() {
1899
- const items = this.items;
1900
- this.cache.oldItemKeys.forEach(k => delete this[k]);
1901
- for (const key in items) {
1902
- this[key] = items[key];
1903
- this.cache.oldItemKeys.add(key);
1904
- }
1905
- }
1906
- #init(initialValue, use_channel) {
1907
- if (use_channel && this.cache.channel) this.cache.channel.on("Ziko-Storage-Updated", () => this.#maintain());
1908
- if (!initialValue) {
1909
- this.#maintain();
1910
- return;
1911
- }
1912
- if (this.cache.storage.getItem(this.cache.globalKey)) {
1913
- const existing = this.items;
1914
- Object.keys(existing).forEach(k => this.cache.oldItemKeys.add(k));
1915
- this.#maintain();
1916
- }
1917
- else this.set(initialValue);
1892
+ get items() {
1893
+ const raw = this.cache.storage.getItem(this.cache.globalKey);
1894
+ if (!raw) return {};
1895
+ try {
1896
+ return JSON.parse(raw);
1897
+ } catch {
1898
+ return {};
1918
1899
  }
1900
+ }
1919
1901
 
1920
- set(data) {
1921
- this.cache.storage.setItem(this.cache.globalKey, JSON.stringify(data));
1922
- if (this.cache.channel) this.cache.channel.emit("Ziko-Storage-Updated", data);
1923
- this.#maintain();
1924
- return this;
1925
- }
1902
+ #maintain() {
1903
+ const currentItems = this.items;
1904
+ const currentKeys = new Set(Object.keys(currentItems));
1926
1905
 
1927
- add(data) {
1928
- this.set({
1929
- ...this.items,
1930
- ...data
1931
- });
1932
- return this;
1906
+ // Cleanup keys that were removed
1907
+ this.cache.oldItemKeys.forEach(key => {
1908
+ if (!currentKeys.has(key)) {
1909
+ delete this[key];
1910
+ this.cache.oldItemKeys.delete(key);
1911
+ }
1912
+ });
1913
+
1914
+ // Populate keys from storage onto `this`
1915
+ for (const key in currentItems) {
1916
+ if (!UseStorage.RESERVED_KEYS.has(key)) {
1917
+ this[key] = currentItems[key];
1918
+ this.cache.oldItemKeys.add(key);
1919
+ }
1933
1920
  }
1934
- remove(...keys) {
1935
- const items = { ...this.items };
1936
- keys.forEach(key => {
1937
- delete items[key];
1938
- delete this[key];
1939
- this.cache.oldItemKeys.delete(key);
1940
- });
1941
- this.set(items);
1942
- return this;
1921
+ }
1922
+
1923
+ #init(initialValue, use_channel) {
1924
+ if (use_channel && this.cache.channel) {
1925
+ this.cache.channel.on("Ziko-Storage-Updated", () => this.#maintain());
1943
1926
  }
1944
- get(key) {
1945
- return this.items[key];
1927
+
1928
+ const hasStoredData = this.cache.storage.getItem(this.cache.globalKey) !== null;
1929
+
1930
+ if (hasStoredData) {
1931
+ // Key already exists in storage -> Restore data to instance
1932
+ this.#maintain();
1933
+ } else if (initialValue !== undefined) {
1934
+ // Key doesn't exist -> Seed with initialValue
1935
+ this.set(initialValue);
1936
+ } else {
1937
+ // Key doesn't exist and no initialValue provided -> Default to empty
1938
+ this.#maintain();
1946
1939
  }
1947
- clear() {
1948
- this.cache.storage.removeItem(this.cache.globalKey);
1949
- this.cache.oldItemKeys.forEach(k => delete this[k]);
1950
- this.cache.oldItemKeys.clear();
1951
- this.#maintain();
1952
- return this;
1940
+ }
1941
+
1942
+ set(data) {
1943
+ this.cache.storage.setItem(this.cache.globalKey, JSON.stringify(data));
1944
+ if (this.cache.channel) {
1945
+ this.cache.channel.emit("Ziko-Storage-Updated", data);
1953
1946
  }
1954
- onStorageUpdated(callback) {
1955
- if (this.cache.channel) {
1956
- this.cache.channel.on("Ziko-Storage-Updated", callback);
1957
- }
1958
- return this;
1947
+ this.#maintain();
1948
+ return this;
1949
+ }
1950
+
1951
+ add(data) {
1952
+ return this.set({
1953
+ ...this.items,
1954
+ ...data
1955
+ });
1956
+ }
1957
+
1958
+ remove(...keys) {
1959
+ const items = { ...this.items };
1960
+ keys.forEach(key => delete items[key]);
1961
+ return this.set(items);
1962
+ }
1963
+
1964
+ get(key) {
1965
+ return this.items[key];
1966
+ }
1967
+
1968
+ clear() {
1969
+ this.cache.storage.removeItem(this.cache.globalKey);
1970
+ this.#maintain();
1971
+ return this;
1972
+ }
1973
+
1974
+ onStorageUpdated(callback) {
1975
+ if (this.cache.channel) {
1976
+ this.cache.channel.on("Ziko-Storage-Updated", callback);
1959
1977
  }
1978
+ return this;
1979
+ }
1960
1980
  }
1961
1981
 
1962
- // factory functions
1963
- const useLocaleStorage = (key, initialValue, use_channel = true) =>
1964
- new UseStorage(localStorage, key, initialValue, use_channel);
1982
+ const useLocalStorage = (key, initialValue, use_channel = true) =>
1983
+ new UseStorage(localStorage, key, initialValue, use_channel);
1965
1984
 
1966
1985
  const useSessionStorage = (key, initialValue, use_channel = true) =>
1967
- new UseStorage(sessionStorage, key, initialValue, use_channel);
1986
+ new UseStorage(sessionStorage, key, initialValue, use_channel);
1968
1987
 
1969
1988
  var __State__ = {
1970
1989
  store : new Map(),
1971
1990
  index : 0,
1972
1991
  session_storage : null,
1973
1992
  register: function(state){
1974
- if(!import.meta.env.SSR && import.meta.env.DEV){
1975
- if(!this.session) this.session_storage = useSessionStorage('ziko-state', {});
1976
- const savedValue = this.session_storage.get(this.index);
1977
- if(!savedValue) this.session_storage.add({[this.index] : state.value});
1978
- else state.value = savedValue;
1979
- }
1980
- this.store.set(this.index++, state);
1993
+ // if(!import.meta?.env?.SSR && import.meta?.env?.DEV){
1994
+ // if(!this.session) this.session_storage = useSessionStorage('ziko-state', {})
1995
+ // const savedValue = this.session_storage.get(this.index)
1996
+ // if(!savedValue) this.session_storage.add({[this.index] : state.value});
1997
+ // else state.value = savedValue
1998
+ // }
1999
+ // this.store.set(this.index++, state)
1981
2000
  },
1982
2001
  update: function(index, value){
1983
- if(!import.meta.env.SSR && import.meta.env.DEV){
1984
- this.session_storage.add({[index] : value});
1985
- }
2002
+ // if(!import.meta?.env?.SSR && import.meta?.env?.DEV){
2003
+ // this.session_storage.add({[index] : value})
2004
+ // }
1986
2005
  },
1987
2006
 
1988
2007
  };
@@ -2159,57 +2178,61 @@ var LifecycleMethods = /*#__PURE__*/Object.freeze({
2159
2178
  unmount: unmount
2160
2179
  });
2161
2180
 
2162
- if(!globalThis.__Ziko__) __init__global__();
2181
+ // import { __init__global__ } from "../__ziko__/index.js";
2182
+
2183
+ // if (!globalThis.__Ziko__) __init__global__();
2163
2184
 
2164
2185
  function useState(initialValue) {
2165
2186
 
2166
- const {store, index} = __Ziko__.__State__;
2167
- __Ziko__.__State__.register({
2168
- value : initialValue,
2169
- subscribers : new Set(),
2170
- paused : false
2171
- });
2172
-
2173
- let current = store.get(index);
2187
+ const state = {
2188
+ value: initialValue,
2189
+ subscribers: new Set(),
2190
+ paused: false,
2191
+ };
2174
2192
 
2175
2193
  function getValue() {
2176
2194
  return {
2177
- value: current.value,
2195
+ value: state.value,
2178
2196
  isStateGetter: () => true,
2179
- _subscribe: (fn) => current.subscribers.add(fn),
2197
+ _subscribe: (fn) => {
2198
+ state.subscribers.add(fn);
2199
+ return () => state.subscribers.delete(fn);
2200
+ },
2180
2201
  };
2181
2202
  }
2182
2203
 
2183
2204
  function setValue(newValue) {
2184
- if (current.paused) return;
2205
+ if (state.paused) return;
2206
+
2185
2207
  if (typeof newValue === "function") {
2186
- newValue = newValue(current.value);
2208
+ newValue = newValue(state.value);
2187
2209
  }
2188
- if (newValue !== current.value) {
2189
- current.value = newValue;
2190
- current.subscribers.forEach(fn => fn(current.value));
2191
- __Ziko__.__State__.update(index, newValue);
2210
+
2211
+ if (!Object.is(newValue, state.value)) {
2212
+ state.value = newValue;
2213
+ state.subscribers.forEach((fn) => fn(state.value));
2192
2214
  }
2193
2215
  }
2194
2216
 
2195
2217
  const controller = {
2196
- pause: () => { current.paused = true; },
2197
- resume: () => { current.paused = false; },
2198
- clear: () => { current.subscribers.clear(); },
2218
+ pause: () => { state.paused = true; },
2219
+ resume: () => { state.paused = false; },
2220
+ clear: () => { state.subscribers.clear(); },
2199
2221
  force: (newValue) => {
2200
- if (typeof newValue === "function") newValue = newValue(current.value);
2201
- current.value = newValue;
2202
- current.subscribers.forEach(fn => fn(current.value));
2222
+ if (typeof newValue === "function") {
2223
+ newValue = newValue(state.value);
2224
+ }
2225
+ state.value = newValue;
2226
+ state.subscribers.forEach((fn) => fn(state.value));
2203
2227
  },
2204
- getSubscribers: () => new Set(current.subscribers),
2228
+ getSubscribers: () => new Set(state.subscribers),
2205
2229
  };
2206
2230
 
2207
2231
  return [getValue, setValue, controller];
2208
2232
  }
2209
2233
 
2210
-
2211
2234
  const isStateGetter = (arg) => {
2212
- return typeof arg === 'function' && arg?.()?.isStateGetter?.();
2235
+ return typeof arg === "function" && arg?.()?.isStateGetter?.() === true;
2213
2236
  };
2214
2237
 
2215
2238
  const camel2hyphencase = (text = '') => text.replace(/[A-Z]/g, match => '-' + match.toLowerCase());
@@ -4884,4 +4907,4 @@ if(globalThis?.document){
4884
4907
  document?.addEventListener("DOMContentLoaded", __Ziko__.__Config__.init());
4885
4908
  }
4886
4909
 
4887
- export { App, ClickAwayEvent, ClickListeners, Clock, CloneElement, Complex, E, EPSILON, EventController, FileBasedRouting, Flex, HTMLWrapper, KeyListeners, Matrix, PI$1 as PI, PtrListeners, Random, SPA, SVGWrapper, Scheduler, Suspense, SwipeEvent, Switch, Tick, TimeAnimation, TimeLoop, TimeScheduler, UIElement$1 as UIElement, UIFlex, UIHTMLWrapper, UINode, UISVGWrapper, UISwitch, UIView, UseRoot, UseThread, View, ViewEvent, ViewListeners, ZikoApp, ZikoSPA, ZikoUISuspense, ZikoUIText, abs, accum_prod, accum_sum, acos$1 as acos, acosh, acot, add, add_class, add_vendor_prefix, and, animation, apply_fun, arc, asin, asinh, atan, atan2, atanh, back, binomial, call_with_optional_props, cbrt, ceil, clamp, clock, cloneUI, complex, cos$3 as cos, cosh$2 as cosh, coth, croot, csv2arr, csv2json, csv2matrix, csv2object, csv2sql, debounce, defineParamsGetter, define_wc, deg2rad, discret, div, elastic, exp$1 as exp, floor, fract, hypot, 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, isPrimitive, isStateGetter, json2arr, json2css, json2csv, json2csvFile, json2xml, json2xmlFile, json2yml, json2ymlFile, lerp, linear, linkStyle, ln, loop, map$1 as map, mapfun$1 as mapfun, matrix, matrix2, matrix3, matrix4, max, mean, median, min, modulo, mul, nand, nor, norm, normalize_css_value, nthr, or, out_back, out_bounce, out_circ, out_cubic, out_elastic, out_expo, out_quad, out_quart, out_quint, out_sin, percentile, pow$1 as pow, rad2deg, register_click_away_event, register_swipe_event, register_view_event, remove_class, round, script, sec, sig, sign, sin$3 as sin, sinh$1 as sinh, sleep, sqrt$2 as sqrt, std, step, step_fps, style, sub, svg2ascii, svg2img, svg2imgUrl, svg2str, tags, tan, tanh, text, throttle, tick, timeTaken, time_memory_Taken, timeout, trunc, useDerived, useEventEmitter, useIPC, useLocaleStorage, useMediaQuery, useQueryParams, useReactive, useRoot, useSessionStorage, useState, useThread, useTitle, variance, wait, waitElm, waitForUIElm, waitForUIElmSync, watchQueryParams, xnor, xor };
4910
+ export { App, ClickAwayEvent, ClickListeners, Clock, CloneElement, Complex, E, EPSILON, EventController, FileBasedRouting, Flex, HTMLWrapper, KeyListeners, Matrix, PI$1 as PI, PtrListeners, Random, SPA, SVGWrapper, Scheduler, Suspense, SwipeEvent, Switch, Tick, TimeAnimation, TimeLoop, TimeScheduler, UIElement$1 as UIElement, UIFlex, UIHTMLWrapper, UINode, UISVGWrapper, UISwitch, UIView, UseRoot, UseThread, View, ViewEvent, ViewListeners, ZikoApp, ZikoSPA, ZikoUISuspense, ZikoUIText, abs, accum_prod, accum_sum, acos$1 as acos, acosh, acot, add, add_class, add_vendor_prefix, and, animation, apply_fun, arc, asin, asinh, atan, atan2, atanh, back, binomial, call_with_optional_props, cbrt, ceil, clamp, clock, cloneUI, complex, cos$3 as cos, cosh$2 as cosh, coth, croot, csv2arr, csv2json, csv2matrix, csv2object, csv2sql, debounce, defineParamsGetter, define_wc, deg2rad, discret, div, elastic, exp$1 as exp, floor, fract, hypot, 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, isPrimitive, isStateGetter, json2arr, json2css, json2csv, json2csvFile, json2xml, json2xmlFile, json2yml, json2ymlFile, lerp, linear, linkStyle, ln, loop, map$1 as map, mapfun$1 as mapfun, matrix, matrix2, matrix3, matrix4, max, mean, median, min, modulo, mul, nand, nor, norm, normalize_css_value, nthr, or, out_back, out_bounce, out_circ, out_cubic, out_elastic, out_expo, out_quad, out_quart, out_quint, out_sin, percentile, pow$1 as pow, rad2deg, register_click_away_event, register_swipe_event, register_view_event, remove_class, round, script, sec, sig, sign, sin$3 as sin, sinh$1 as sinh, sleep, sqrt$2 as sqrt, std, step, step_fps, style, sub, svg2ascii, svg2img, svg2imgUrl, svg2str, tags, tan, tanh, text, throttle, tick, timeTaken, time_memory_Taken, timeout, trunc, useDerived, useEventEmitter, useIPC, useLocalStorage, useMediaQuery, useQueryParams, useReactive, useRoot, useSessionStorage, useState, useThread, useTitle, variance, wait, waitElm, waitForUIElm, waitForUIElmSync, watchQueryParams, xnor, xor };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ziko",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "A versatile JavaScript library offering a rich set of Hyperscript Based UI components, advanced mathematical utilities, interactivity ,animations, client side routing and more ...",
5
5
  "keywords": [
6
6
  "front-end",
@@ -4,18 +4,18 @@ export var __State__ = {
4
4
  index : 0,
5
5
  session_storage : null,
6
6
  register: function(state){
7
- if(!import.meta.env.SSR && import.meta.env.DEV){
8
- if(!this.session) this.session_storage = useSessionStorage('ziko-state', {})
9
- const savedValue = this.session_storage.get(this.index)
10
- if(!savedValue) this.session_storage.add({[this.index] : state.value});
11
- else state.value = savedValue
12
- }
13
- this.store.set(this.index++, state)
7
+ // if(!import.meta?.env?.SSR && import.meta?.env?.DEV){
8
+ // if(!this.session) this.session_storage = useSessionStorage('ziko-state', {})
9
+ // const savedValue = this.session_storage.get(this.index)
10
+ // if(!savedValue) this.session_storage.add({[this.index] : state.value});
11
+ // else state.value = savedValue
12
+ // }
13
+ // this.store.set(this.index++, state)
14
14
  },
15
15
  update: function(index, value){
16
- if(!import.meta.env.SSR && import.meta.env.DEV){
17
- this.session_storage.add({[index] : value})
18
- }
16
+ // if(!import.meta?.env?.SSR && import.meta?.env?.DEV){
17
+ // this.session_storage.add({[index] : value})
18
+ // }
19
19
  },
20
20
 
21
21
  }
@@ -1,54 +1,56 @@
1
- import { __init__global__ } from "../__ziko__/index.js";
1
+ // import { __init__global__ } from "../__ziko__/index.js";
2
2
 
3
- if(!globalThis.__Ziko__) __init__global__()
3
+ // if (!globalThis.__Ziko__) __init__global__();
4
4
 
5
5
  export function useState(initialValue) {
6
6
 
7
- const {store, index} = __Ziko__.__State__
8
- __Ziko__.__State__.register({
9
- value : initialValue,
10
- subscribers : new Set(),
11
- paused : false
12
- })
13
-
14
- let current = store.get(index);
7
+ const state = {
8
+ value: initialValue,
9
+ subscribers: new Set(),
10
+ paused: false,
11
+ };
15
12
 
16
13
  function getValue() {
17
14
  return {
18
- value: current.value,
15
+ value: state.value,
19
16
  isStateGetter: () => true,
20
- _subscribe: (fn) => current.subscribers.add(fn),
17
+ _subscribe: (fn) => {
18
+ state.subscribers.add(fn);
19
+ return () => state.subscribers.delete(fn);
20
+ },
21
21
  };
22
22
  }
23
23
 
24
24
  function setValue(newValue) {
25
- if (current.paused) return;
25
+ if (state.paused) return;
26
+
26
27
  if (typeof newValue === "function") {
27
- newValue = newValue(current.value);
28
+ newValue = newValue(state.value);
28
29
  }
29
- if (newValue !== current.value) {
30
- current.value = newValue;
31
- current.subscribers.forEach(fn => fn(current.value));
32
- __Ziko__.__State__.update(index, newValue)
30
+
31
+ if (!Object.is(newValue, state.value)) {
32
+ state.value = newValue;
33
+ state.subscribers.forEach((fn) => fn(state.value));
33
34
  }
34
35
  }
35
36
 
36
37
  const controller = {
37
- pause: () => { current.paused = true; },
38
- resume: () => { current.paused = false; },
39
- clear: () => { current.subscribers.clear(); },
38
+ pause: () => { state.paused = true; },
39
+ resume: () => { state.paused = false; },
40
+ clear: () => { state.subscribers.clear(); },
40
41
  force: (newValue) => {
41
- if (typeof newValue === "function") newValue = newValue(current.value);
42
- current.value = newValue;
43
- current.subscribers.forEach(fn => fn(current.value));
42
+ if (typeof newValue === "function") {
43
+ newValue = newValue(state.value);
44
+ }
45
+ state.value = newValue;
46
+ state.subscribers.forEach((fn) => fn(state.value));
44
47
  },
45
- getSubscribers: () => new Set(current.subscribers),
48
+ getSubscribers: () => new Set(state.subscribers),
46
49
  };
47
50
 
48
51
  return [getValue, setValue, controller];
49
52
  }
50
53
 
51
-
52
54
  export const isStateGetter = (arg) => {
53
- return typeof arg === 'function' && arg?.()?.isStateGetter?.();
54
- };
55
+ return typeof arg === "function" && arg?.()?.isStateGetter?.() === true;
56
+ };
@@ -1,99 +1,118 @@
1
1
  import { useIPC } from "./use-ipc.js";
2
2
 
3
3
  class UseStorage {
4
- constructor(storage, globalKey, initialValue, use_channel = true) {
5
- this.cache = {
6
- storage,
7
- globalKey,
8
- channel: use_channel ? useIPC(`Ziko:useStorage-${globalKey}`) : null,
9
- oldItemKeys: new Set()
10
- };
11
-
12
- this.#init(initialValue, use_channel);
13
- }
4
+ static RESERVED_KEYS = new Set([
5
+ "cache", "items", "set", "add", "remove", "get", "clear", "onStorageUpdated"
6
+ ]);
14
7
 
15
- get items() {
16
- const raw = this.cache.storage.getItem(this.cache.globalKey);
17
- if (!raw) return {};
18
- try {
19
- return JSON.parse(raw);
20
- } catch {
21
- return {};
22
- }
23
- }
8
+ constructor(storage, globalKey, initialValue, use_channel = true) {
9
+ this.cache = {
10
+ storage,
11
+ globalKey,
12
+ channel: use_channel ? useIPC(`Ziko:useStorage-${globalKey}`) : null,
13
+ oldItemKeys: new Set()
14
+ };
24
15
 
25
- #maintain() {
26
- const items = this.items;
27
- this.cache.oldItemKeys.forEach(k => delete this[k]);
28
- for (const key in items) {
29
- this[key] = items[key];
30
- this.cache.oldItemKeys.add(key);
31
- }
32
- }
33
- #init(initialValue, use_channel) {
34
- if (use_channel && this.cache.channel) this.cache.channel.on("Ziko-Storage-Updated", () => this.#maintain());
35
- if (!initialValue) {
36
- this.#maintain();
37
- return;
38
- }
39
- if (this.cache.storage.getItem(this.cache.globalKey)) {
40
- const existing = this.items;
41
- Object.keys(existing).forEach(k => this.cache.oldItemKeys.add(k));
42
- this.#maintain();
43
- }
44
- else this.set(initialValue);
45
- }
16
+ this.#init(initialValue, use_channel);
17
+ }
46
18
 
47
- set(data) {
48
- this.cache.storage.setItem(this.cache.globalKey, JSON.stringify(data));
49
- if (this.cache.channel) this.cache.channel.emit("Ziko-Storage-Updated", data);
50
- this.#maintain();
51
- return this;
19
+ get items() {
20
+ const raw = this.cache.storage.getItem(this.cache.globalKey);
21
+ if (!raw) return {};
22
+ try {
23
+ return JSON.parse(raw);
24
+ } catch {
25
+ return {};
52
26
  }
27
+ }
53
28
 
54
- add(data) {
55
- this.set({
56
- ...this.items,
57
- ...data
58
- });
59
- return this;
29
+ #maintain() {
30
+ const currentItems = this.items;
31
+ const currentKeys = new Set(Object.keys(currentItems));
32
+
33
+ // Cleanup keys that were removed
34
+ this.cache.oldItemKeys.forEach(key => {
35
+ if (!currentKeys.has(key)) {
36
+ delete this[key];
37
+ this.cache.oldItemKeys.delete(key);
38
+ }
39
+ });
40
+
41
+ // Populate keys from storage onto `this`
42
+ for (const key in currentItems) {
43
+ if (!UseStorage.RESERVED_KEYS.has(key)) {
44
+ this[key] = currentItems[key];
45
+ this.cache.oldItemKeys.add(key);
46
+ }
60
47
  }
61
- remove(...keys) {
62
- const items = { ...this.items };
63
- keys.forEach(key => {
64
- delete items[key];
65
- delete this[key];
66
- this.cache.oldItemKeys.delete(key);
67
- });
68
- this.set(items);
69
- return this;
48
+ }
49
+
50
+ #init(initialValue, use_channel) {
51
+ if (use_channel && this.cache.channel) {
52
+ this.cache.channel.on("Ziko-Storage-Updated", () => this.#maintain());
70
53
  }
71
- get(key) {
72
- return this.items[key];
54
+
55
+ const hasStoredData = this.cache.storage.getItem(this.cache.globalKey) !== null;
56
+
57
+ if (hasStoredData) {
58
+ // Key already exists in storage -> Restore data to instance
59
+ this.#maintain();
60
+ } else if (initialValue !== undefined) {
61
+ // Key doesn't exist -> Seed with initialValue
62
+ this.set(initialValue);
63
+ } else {
64
+ // Key doesn't exist and no initialValue provided -> Default to empty
65
+ this.#maintain();
73
66
  }
74
- clear() {
75
- this.cache.storage.removeItem(this.cache.globalKey);
76
- this.cache.oldItemKeys.forEach(k => delete this[k]);
77
- this.cache.oldItemKeys.clear();
78
- this.#maintain();
79
- return this;
67
+ }
68
+
69
+ set(data) {
70
+ this.cache.storage.setItem(this.cache.globalKey, JSON.stringify(data));
71
+ if (this.cache.channel) {
72
+ this.cache.channel.emit("Ziko-Storage-Updated", data);
80
73
  }
81
- onStorageUpdated(callback) {
82
- if (this.cache.channel) {
83
- this.cache.channel.on("Ziko-Storage-Updated", callback);
84
- }
85
- return this;
74
+ this.#maintain();
75
+ return this;
76
+ }
77
+
78
+ add(data) {
79
+ return this.set({
80
+ ...this.items,
81
+ ...data
82
+ });
83
+ }
84
+
85
+ remove(...keys) {
86
+ const items = { ...this.items };
87
+ keys.forEach(key => delete items[key]);
88
+ return this.set(items);
89
+ }
90
+
91
+ get(key) {
92
+ return this.items[key];
93
+ }
94
+
95
+ clear() {
96
+ this.cache.storage.removeItem(this.cache.globalKey);
97
+ this.#maintain();
98
+ return this;
99
+ }
100
+
101
+ onStorageUpdated(callback) {
102
+ if (this.cache.channel) {
103
+ this.cache.channel.on("Ziko-Storage-Updated", callback);
86
104
  }
105
+ return this;
106
+ }
87
107
  }
88
108
 
89
- // factory functions
90
- const useLocaleStorage = (key, initialValue, use_channel = true) =>
91
- new UseStorage(localStorage, key, initialValue, use_channel);
109
+ const useLocalStorage = (key, initialValue, use_channel = true) =>
110
+ new UseStorage(localStorage, key, initialValue, use_channel);
92
111
 
93
112
  const useSessionStorage = (key, initialValue, use_channel = true) =>
94
- new UseStorage(sessionStorage, key, initialValue, use_channel);
113
+ new UseStorage(sessionStorage, key, initialValue, use_channel);
95
114
 
96
115
  export {
97
- useLocaleStorage,
98
- useSessionStorage
99
- };
116
+ useLocalStorage,
117
+ useSessionStorage
118
+ };