ziko 1.1.1 → 1.3.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 19:50:38 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());
@@ -3479,6 +3502,63 @@ const Switch=({key, cases})=> new UISwitch(key, cases);
3479
3502
  // return this.cases[matched]()
3480
3503
  // }
3481
3504
 
3505
+ class UISwap extends UIElement$1 {
3506
+ #DISPLAYS_MAP = new WeakMap()
3507
+ constructor({ activeIndex = 0 } = {}, ...items) {
3508
+ super({ element: 'div' });
3509
+ this.style({ display: 'contents' });
3510
+
3511
+ this.states = {
3512
+ activeIndex
3513
+ };
3514
+
3515
+ this.append(...items);
3516
+ this.#setup();
3517
+ }
3518
+ get activeItem(){
3519
+ return this.items[this.states.activeIndex]
3520
+ }
3521
+ #setup() {
3522
+ this.items.forEach((n, i) => {
3523
+ // Store initial display style (fallback to empty string or default)
3524
+ const initialDisplay = n.element?.style?.display || '';
3525
+ this.#DISPLAYS_MAP.set(n, initialDisplay);
3526
+
3527
+ if (i !== this.states.activeIndex) {
3528
+ n.style({ display: 'none' });
3529
+ }
3530
+ });
3531
+ }
3532
+ next(n = 1) {
3533
+ return this.activate(this.states.activeIndex + n);
3534
+ }
3535
+ previous(n = 1) {
3536
+ return this.activate(this.states.activeIndex - n);
3537
+ }
3538
+ activate(index) {
3539
+ if (!this.items.length) return this;
3540
+
3541
+ const currentItem = this.items.at(this.states.activeIndex);
3542
+
3543
+ if (currentItem) {
3544
+ currentItem.style({ display: 'none' });
3545
+ }
3546
+
3547
+ const len = this.items.length;
3548
+ this.states.activeIndex = ((index % len) + len) % len;
3549
+
3550
+ const activeItem = this.items.at(this.states.activeIndex);
3551
+ if (activeItem) {
3552
+ const restoredDisplay = this.#DISPLAYS_MAP.get(activeItem) || 'block';
3553
+ activeItem.style({ display: restoredDisplay === 'none' ? 'block' : restoredDisplay });
3554
+ }
3555
+
3556
+ return this;
3557
+ }
3558
+ }
3559
+
3560
+ const Swap = call_with_optional_props(UISwap);
3561
+
3482
3562
  const { PI, sqrt: sqrt$1, cos: cos$2, sin: sin$2, acos, pow } = Math;
3483
3563
 
3484
3564
  const linear = t => t;
@@ -4884,4 +4964,4 @@ if(globalThis?.document){
4884
4964
  document?.addEventListener("DOMContentLoaded", __Ziko__.__Config__.init());
4885
4965
  }
4886
4966
 
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 };
4967
+ 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, Swap, SwipeEvent, Switch, Tick, TimeAnimation, TimeLoop, TimeScheduler, UIElement$1 as UIElement, UIFlex, UIHTMLWrapper, UINode, UISVGWrapper, UISwap, 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.3.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
  }
@@ -0,0 +1 @@
1
+ export * from './swap/index.js'
@@ -0,0 +1,80 @@
1
+ import { UIElement } from "../../constructors/UIElement.js";
2
+
3
+ /**
4
+ * Options for configuring the UISwap component.
5
+ */
6
+ export interface UISwapOptions {
7
+ /**
8
+ * The initial index of the item to display as active.
9
+ * @default 0
10
+ */
11
+ activeIndex?: number;
12
+ }
13
+
14
+ /**
15
+ * A logical sequence-based view control component that swaps visibility of child items.
16
+ */
17
+ export class UISwap extends UIElement {
18
+ /**
19
+ * Internal reactive state object holding current component properties.
20
+ */
21
+ states: {
22
+ activeIndex: number;
23
+ };
24
+
25
+
26
+ /**
27
+ * Creates a new UISwap instance.
28
+ *
29
+ * @param options Configuration options for the Swap component.
30
+ * @param items Initial UI elements to add to the swap container.
31
+ */
32
+ constructor(options?: UISwapOptions, ...items: UIElement[]);
33
+
34
+ /**
35
+ * Gets the currently active UI item.
36
+ */
37
+ get currentActiveItem(): UIElement | undefined;
38
+
39
+ /**
40
+ * Advances forward by `n` items in the sequence.
41
+ *
42
+ * @param n The number of steps to advance forward. Defaults to 1.
43
+ * @returns The current `UISwap` instance for chaining.
44
+ */
45
+ next(n?: number): this;
46
+
47
+ /**
48
+ * Moves backward by `n` items in the sequence.
49
+ *
50
+ * @param n The number of steps to retreat backward. Defaults to 1.
51
+ * @returns The current `UISwap` instance for chaining.
52
+ */
53
+ previous(n?: number): this;
54
+
55
+ /**
56
+ * Activates and displays the child element at the target index.
57
+ *
58
+ * @param index The target index to activate (supports negative modulo wrapping).
59
+ * @returns The current `UISwap` instance for chaining.
60
+ */
61
+ activate(index: number): this;
62
+ }
63
+
64
+ /**
65
+ * Factory function helper to create a `UISwap` component instance.
66
+ * Supports optional properties object signature.
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * const swapper = Swap({ activeIndex: 0 }, itemA, itemB, itemC);
71
+ * swapper.next();
72
+ * ```
73
+ */
74
+
75
+ export function Swap(
76
+ options: { activeIndex?: number },
77
+ ...items: UIElement[]
78
+ ): UISwap;
79
+
80
+ export function Swap(...items: UIElement[]): UISwap;
@@ -0,0 +1,59 @@
1
+ import { UIElement } from "../../constructors/UIElement.js";
2
+ import { call_with_optional_props } from '../../utils/index.js';
3
+
4
+ export class UISwap extends UIElement {
5
+ #DISPLAYS_MAP = new WeakMap()
6
+ constructor({ activeIndex = 0 } = {}, ...items) {
7
+ super({ element: 'div' });
8
+ this.style({ display: 'contents' });
9
+
10
+ this.states = {
11
+ activeIndex
12
+ };
13
+
14
+ this.append(...items);
15
+ this.#setup();
16
+ }
17
+ get activeItem(){
18
+ return this.items[this.states.activeIndex]
19
+ }
20
+ #setup() {
21
+ this.items.forEach((n, i) => {
22
+ // Store initial display style (fallback to empty string or default)
23
+ const initialDisplay = n.element?.style?.display || '';
24
+ this.#DISPLAYS_MAP.set(n, initialDisplay);
25
+
26
+ if (i !== this.states.activeIndex) {
27
+ n.style({ display: 'none' });
28
+ }
29
+ });
30
+ }
31
+ next(n = 1) {
32
+ return this.activate(this.states.activeIndex + n);
33
+ }
34
+ previous(n = 1) {
35
+ return this.activate(this.states.activeIndex - n);
36
+ }
37
+ activate(index) {
38
+ if (!this.items.length) return this;
39
+
40
+ const currentItem = this.items.at(this.states.activeIndex);
41
+
42
+ if (currentItem) {
43
+ currentItem.style({ display: 'none' });
44
+ }
45
+
46
+ const len = this.items.length;
47
+ this.states.activeIndex = ((index % len) + len) % len;
48
+
49
+ const activeItem = this.items.at(this.states.activeIndex);
50
+ if (activeItem) {
51
+ const restoredDisplay = this.#DISPLAYS_MAP.get(activeItem) || 'block';
52
+ activeItem.style({ display: restoredDisplay === 'none' ? 'block' : restoredDisplay });
53
+ }
54
+
55
+ return this;
56
+ }
57
+ }
58
+
59
+ export const Swap = call_with_optional_props(UISwap);
package/src/dom/index.js CHANGED
@@ -10,4 +10,6 @@ export * from './suspense/index.js';
10
10
  export * from './wrappers/index.js';
11
11
  // export * from './graphics/index.js'
12
12
  export * from './web-component/index.js'
13
- export * from './logic/index.js'
13
+ export * from './logic/index.js'
14
+
15
+ export * from './components/index.js'
@@ -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
+ };