ziko 0.68.0 → 0.68.2

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 : Fri Feb 20 2026 11:36:37 GMT+0000 (UTC)
5
+ Date : Thu Feb 26 2026 13:06:11 GMT+0000 (UTC)
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
@@ -2649,6 +2649,68 @@ var StyleMethods = /*#__PURE__*/Object.freeze({
2649
2649
  style: style$1
2650
2650
  });
2651
2651
 
2652
+ class EventController {
2653
+ constructor(target, category){
2654
+ this.cache = {
2655
+ category,
2656
+ target,
2657
+ listeners : {},
2658
+ currentEvent : null,
2659
+ event : null,
2660
+ customEvents : new Set()
2661
+ };
2662
+ }
2663
+ get event(){
2664
+ return this.cache.event
2665
+ }
2666
+ get target(){
2667
+ return this.cache.target;
2668
+ }
2669
+ get element(){
2670
+ return this.cache.target.element;
2671
+ }
2672
+ get currentEvent(){
2673
+ return this.cache.currentEvent;
2674
+ }
2675
+ addListener(event_name, callback, {preventDefault = false, paused = false} = {}){
2676
+ this.cache.listeners[event_name] = {
2677
+ callback : e =>{
2678
+ this.cache.event = e;
2679
+ if(this.cache.listeners[event_name].preventDefault) e.preventDefault();
2680
+ if(!this.cache.listeners[event_name].paused) {
2681
+ this.cache.currentEvent = event_name;
2682
+ callback.call(this, this);
2683
+ }
2684
+ },
2685
+ preventDefault,
2686
+ paused,
2687
+ };
2688
+ this.element.addEventListener(event_name, this.cache.listeners[event_name].callback);
2689
+ return this;
2690
+ }
2691
+ removeListener(event_name){
2692
+ this.element.removeEventListener(event_name, this.cache.listeners[event_name].callback);
2693
+ return this;
2694
+ }
2695
+ pause(event_name){
2696
+ this.cache.listeners[event_name].paused = true;
2697
+ return this;
2698
+ }
2699
+ resume(event_name){
2700
+ this.cache.listeners[event_name].paused = false;
2701
+ return this;
2702
+ }
2703
+ preventDefault(event_name){
2704
+ // if(!event_name)
2705
+ this.cache.listeners[event_name].preventDefault = true;
2706
+ return this;
2707
+ }
2708
+ useDefault(event_name){
2709
+ this.cache.listeners[event_name].preventDefault = false;
2710
+ return this;
2711
+ }
2712
+ }
2713
+
2652
2714
  class ClickAwayEvent extends Event {
2653
2715
  constructor(originalEvent, targetElement) {
2654
2716
  super("clickaway", { bubbles: true, cancelable: true });
@@ -2684,26 +2746,6 @@ function register_click_away_event(element) {
2684
2746
  // // later, you can stop listening:
2685
2747
  // // stop();
2686
2748
 
2687
- const CATEGORY$2 = 'click';
2688
- const ClickListeners = {
2689
- onClick(callback){
2690
- this._on(
2691
- 'click', callback,
2692
- { category : CATEGORY$2 });
2693
- },
2694
- onDblClick(callback){
2695
- this._on(
2696
- 'dblclick', callback,
2697
- { category : CATEGORY$2});
2698
- },
2699
- onClickAway(callback){
2700
- register_click_away_event(this.element);
2701
- this._on(
2702
- 'clickaway', callback,
2703
- { category : CATEGORY$2});
2704
- },
2705
- };
2706
-
2707
2749
  const getCoordinates = (ctx, normalized = false) =>{
2708
2750
  const rect = ctx.element.getBoundingClientRect();
2709
2751
  const e = ctx.event;
@@ -2718,38 +2760,60 @@ const getCoordinates = (ctx, normalized = false) =>{
2718
2760
  }
2719
2761
 
2720
2762
  return {x, y};
2763
+ };
2764
+
2765
+ const isCustomEventRegistred = (ctx, category, event_name) => ctx.exp.events?.[category]?.cache?.customEvents?.has(event_name);
2766
+
2767
+ const CATEGORY$3 = 'click';
2768
+ const ClickListeners = {
2769
+ onClick(callback){
2770
+ return this.on(
2771
+ 'click', callback,
2772
+ { category : CATEGORY$3 })
2773
+ },
2774
+ onDblClick(callback){
2775
+ return this.on(
2776
+ 'dblclick', callback,
2777
+ { category : CATEGORY$3})
2778
+ },
2779
+ onClickAway(callback){
2780
+ if(!isCustomEventRegistred(this, CATEGORY$3, 'clickaway')) register_click_away_event(this.element);
2781
+ return this.on(
2782
+ 'clickaway', callback,
2783
+ { category : CATEGORY$3, isCustom : true})
2784
+ },
2721
2785
  };
2722
2786
 
2723
- const CATEGORY$1 = 'ptr';
2787
+ const CATEGORY$2 = 'ptr';
2724
2788
  const PtrListeners = {
2725
2789
  onPtrDown(callback, useNormalizedCoordinates = false){
2726
- this._on(
2790
+ return this.on(
2727
2791
  'pointerdown', callback,
2728
- { category : CATEGORY$1, details_setter : (ctx)=> {
2792
+ { category : CATEGORY$2, details_setter : (ctx)=> {
2729
2793
  const {x, y} = getCoordinates(ctx, useNormalizedCoordinates);
2730
2794
  ctx.dx = x;
2731
2795
  ctx.dy = y;
2732
2796
  ctx.isDown = true;
2733
2797
  ctx.isDragging = ctx.isMoving ?? false;
2734
2798
  }}
2735
- );
2799
+ )
2736
2800
  },
2737
2801
  onPtrMove(callback, useNormalizedCoordinates = false){
2738
- this._on(
2802
+ return this.on(
2739
2803
  'pointermove', callback,
2740
- { category : CATEGORY$1, details_setter : (ctx)=> {
2804
+ { category : CATEGORY$2, details_setter : (ctx)=> {
2741
2805
  const {x, y} = getCoordinates(ctx, useNormalizedCoordinates);
2742
2806
  ctx.mx = x;
2743
2807
  ctx.my = y;
2744
2808
  ctx.isMoving = true;
2745
2809
  ctx.isDragging = ctx.isDown ?? false;
2746
2810
  }}
2747
- );
2811
+ )
2748
2812
  },
2749
2813
  onPtrUp(callback, useNormalizedCoordinates = false){
2750
- this._on(
2814
+ return this.on(
2751
2815
  'pointerup', callback,
2752
- { category : CATEGORY$1, details_setter : (ctx)=> {
2816
+ { category : CATEGORY$2, details_setter : (ctx)=> {
2753
2817
  const {x, y} = getCoordinates(ctx, useNormalizedCoordinates);
2754
2818
  ctx.ux = x;
2755
2819
  ctx.uy = y;
@@ -2757,89 +2821,208 @@ const PtrListeners = {
2757
2821
  ctx.isMoving = false;
2758
2822
  ctx.isDragging = false;
2759
2823
  }}
2760
- );
2824
+ )
2761
2825
  }
2762
2826
  };
2763
2827
 
2764
- const CATEGORY = 'key';
2828
+ const CATEGORY$1 = 'key';
2765
2829
  const KeyListeners = {
2766
2830
  onKeyDown(callback){
2767
- this._on(
2831
+ return this.on(
2768
2832
  'keydown', callback,
2769
- { category : CATEGORY, details_setter : ctx=> { ctx.kd = ctx.event.key; }
2770
- });
2833
+ { category : CATEGORY$1, details_setter : ctx=> { ctx.kd = ctx.event.key; }
2834
+ })
2771
2835
  },
2772
2836
  onKeyPress(callback){
2773
- this._on(
2837
+ return this.on(
2774
2838
  'keypress', callback,
2775
- { category : CATEGORY, details_setter : ctx=> { ctx.kp = ctx.event.key; }
2776
- });
2839
+ { category : CATEGORY$1, details_setter : ctx=> { ctx.kp = ctx.event.key; }
2840
+ })
2777
2841
  },
2778
2842
  onKeyUp(callback){
2779
- this._on(
2843
+ return this.on(
2780
2844
  'keydown', callback,
2781
- { category : CATEGORY, details_setter : ctx=> { ctx.ku = ctx.event.key; }
2782
- });
2845
+ { category : CATEGORY$1, details_setter : ctx=> { ctx.ku = ctx.event.key; }
2846
+ })
2783
2847
  },
2784
2848
 
2785
2849
  };
2786
2850
 
2787
- class EventController {
2788
- constructor(target, category){
2789
- this.cache = {
2790
- category,
2791
- target,
2792
- listeners : {},
2793
- currentEvent : null,
2794
- event : null
2851
+ const debounce=(fn,delay=1000)=>{
2852
+ let id;
2853
+ return (...args) => id ? clearTimeout(id) : setTimeout(()=>fn(...args),delay);
2854
+ };
2855
+ const throttle=(fn,delay)=>{
2856
+ let lastTime=0;
2857
+ return (...args) => {
2858
+ const now = new Date().getTime();
2859
+ if(now-lastTime < delay) return;
2860
+ lastTime = now;
2861
+ fn(...args);
2862
+ }
2863
+ };
2864
+
2865
+ class ViewEvent extends CustomEvent {
2866
+ constructor(type, detail, { bubbles = true, cancelable = true } = {}) {
2867
+ super(type, { detail, bubbles, cancelable });
2868
+ }
2869
+ }
2870
+
2871
+ function register_view_event(
2872
+ element,
2873
+ {
2874
+ intersection = true,
2875
+ resize = true,
2876
+ threshold = 0,
2877
+ throttleResize = 100,
2878
+ throttleEnterExit = 0
2879
+ } = {}
2880
+ ) {
2881
+ let intersectionObserver, resizeObserver;
2882
+ const resizeCallback = entries => {
2883
+ for (let entry of entries) {
2884
+ const { width, height } = entry.contentRect;
2885
+
2886
+ element.dispatchEvent(
2887
+ new ViewEvent("resizeview", {
2888
+ width,
2889
+ height,
2890
+ entry
2891
+ })
2892
+ );
2893
+ }
2795
2894
  };
2796
- }
2797
- get event(){
2798
- return this.cache.event
2799
- }
2800
- get element(){
2801
- return this.cache.target.element;
2802
- }
2803
- get currentEvent(){
2804
- return this.cache.currentEvent;
2805
- }
2806
- addListener(event_name, callback, {preventDefault = false, paused = false} = {}){
2807
- this.cache.listeners[event_name] = {
2808
- callback : e =>{
2809
- this.cache.event = e;
2810
- if(this.cache.listeners[event_name].preventDefault) e.preventDefault();
2811
- if(!this.cache.listeners[event_name].paused) {
2812
- this.cache.currentEvent = event_name;
2813
- callback.call(this, this);
2895
+
2896
+ const throttledResize = throttleResize > 0
2897
+ ? throttle(resizeCallback, throttleResize)
2898
+ : resizeCallback;
2899
+
2900
+ const intersectionCallback = entries => {
2901
+ for (let entry of entries) {
2902
+ const type = entry.isIntersecting ? "enterview" : "exitview";
2903
+ element.dispatchEvent(new ViewEvent(type, entry));
2814
2904
  }
2815
- },
2816
- preventDefault,
2817
- paused,
2818
2905
  };
2819
- this.element.addEventListener(event_name, this.cache.listeners[event_name].callback);
2820
- return this;
2821
- }
2822
- removeListener(event_name){
2823
- this.element.removeEventListener(event_name, this.cache.listeners[event_name].callback);
2824
- return this;
2825
- }
2826
- pause(event_name){
2827
- this.cache.listeners[event_name].paused = true;
2828
- return this;
2829
- }
2830
- resume(event_name){
2831
- this.cache.listeners[event_name].paused = false;
2832
- return this;
2906
+
2907
+ const throttledIntersections = throttleEnterExit > 0
2908
+ ? throttle(intersectionCallback, throttleEnterExit)
2909
+ : intersectionCallback;
2910
+
2911
+ if (intersection) {
2912
+ intersectionObserver = new IntersectionObserver(throttledIntersections, { threshold });
2913
+ intersectionObserver.observe(element);
2914
+ }
2915
+
2916
+ if (resize) {
2917
+ resizeObserver = new ResizeObserver(throttledResize);
2918
+ resizeObserver.observe(element);
2919
+ }
2920
+
2921
+ // ---- UNREGISTER ----
2922
+ return () => {
2923
+ if (intersectionObserver) {
2924
+ intersectionObserver.unobserve(element);
2925
+ intersectionObserver.disconnect();
2926
+ }
2927
+ if (resizeObserver) {
2928
+ resizeObserver.unobserve(element);
2929
+ resizeObserver.disconnect();
2930
+ }
2931
+ };
2932
+ }
2933
+
2934
+ const CATEGORY = 'view';
2935
+ const ViewListeners = {
2936
+ onEnterView(callback){
2937
+ if(!this.exp.events?.[CATEGORY]) register_view_event(this.element);
2938
+ return this.on(
2939
+ 'enterview', callback,
2940
+ { category : CATEGORY, isCustom : true})
2941
+ },
2942
+ onExitView(callback){
2943
+ if(!this.exp.events?.[CATEGORY]) register_view_event(this.element);
2944
+ return this.on(
2945
+ 'exitview', callback,
2946
+ { category : CATEGORY, isCustom : true})
2947
+ },
2948
+ onResizeView(callback){
2949
+ if(!this.exp.events?.[CATEGORY]) register_view_event(this.element);
2950
+ return this.on(
2951
+ 'resizeview', callback,
2952
+ { category : CATEGORY, isCustom : true})
2953
+ },
2954
+ };
2955
+
2956
+ class SwipeEvent extends CustomEvent {
2957
+ constructor(type, detail) {
2958
+ super(type, {
2959
+ detail,
2960
+ bubbles: true,
2961
+ cancelable: true
2962
+ });
2833
2963
  }
2834
- preventDefault(event_name){
2835
- // if(!event_name)
2836
- this.cache.listeners[event_name].preventDefault = true;
2837
- return this;
2964
+ }
2965
+
2966
+ function register_swipe_event(
2967
+ element,
2968
+ threshold = 5,
2969
+ restraint = 100,
2970
+ allowedTime = 500
2971
+ ) {
2972
+ let startX = 0,
2973
+ startY = 0,
2974
+ startTime = 0,
2975
+ isPointerDown = false;
2976
+
2977
+ function onPointerDown(e) {
2978
+ startX = e.clientX;
2979
+ startY = e.clientY;
2980
+ startTime = performance.now();
2981
+ isPointerDown = true;
2838
2982
  }
2839
- useDefault(event_name){
2840
- this.cache.listeners[event_name].preventDefault = false;
2841
- return this;
2983
+
2984
+ function onPointerUp(e) {
2985
+ if (!isPointerDown) return;
2986
+ isPointerDown = false;
2987
+
2988
+ const distX = e.clientX - startX;
2989
+ const distY = e.clientY - startY;
2990
+ const elapsed = performance.now() - startTime;
2991
+
2992
+ let direction = null;
2993
+ let eventName = null;
2994
+
2995
+ if (elapsed <= allowedTime) {
2996
+ if (Math.abs(distX) >= threshold && Math.abs(distY) <= restraint) {
2997
+ direction = distX < 0 ? "left" : "right";
2998
+ eventName = "swipe" + direction;
2999
+ }
3000
+ else if (Math.abs(distY) >= threshold && Math.abs(distX) <= restraint) {
3001
+ direction = distY < 0 ? "up" : "down";
3002
+ eventName = "swipe" + direction;
3003
+ }
3004
+ }
3005
+
3006
+ // Emit event
3007
+ if (eventName) {
3008
+ element.dispatchEvent(
3009
+ new SwipeEvent(eventName, {
3010
+ direction,
3011
+ distX,
3012
+ distY,
3013
+ originalEvent: e
3014
+ })
3015
+ );
3016
+ }
2842
3017
  }
3018
+
3019
+ element.addEventListener("pointerdown", onPointerDown, { passive: true });
3020
+ element.addEventListener("pointerup", onPointerUp, { passive: true });
3021
+
3022
+ return () => {
3023
+ element.removeEventListener("pointerdown", onPointerDown);
3024
+ element.removeEventListener("pointerup", onPointerUp);
3025
+ };
2843
3026
  }
2844
3027
 
2845
3028
  let UIElement$1 = class UIElement extends UIElementCore{
@@ -2856,24 +3039,26 @@ let UIElement$1 = class UIElement extends UIElementCore{
2856
3039
  AttrsMethods,
2857
3040
  DomMethods,
2858
3041
  StyleMethods,
2859
- IndexingMethods,
3042
+ IndexingMethods,
2860
3043
  PtrListeners,
2861
3044
  ClickListeners,
2862
- KeyListeners
3045
+ KeyListeners,
3046
+ ViewListeners,
2863
3047
  );
2864
3048
 
2865
3049
  if(element)this.init(element, name, type, render);
2866
3050
  }
2867
- _on(event, callback, {details_setter, category = 'global', preventDefault = false} = {}){
3051
+ on(event_name, callback, {details_setter, category = 'global', isCustom = false,preventDefault = false} = {}){
2868
3052
  if(category && !this.exp.events.hasOwnProperty(category)) this.exp.events[category] = new EventController(this, category);
3053
+ isCustom && this.exp.events[category].cache.customEvents.add(event_name);
2869
3054
  const EVENT = this.exp.events[category];
2870
- EVENT.addListener(event, (e)=>{
3055
+ EVENT.addListener(event_name, (e)=>{
2871
3056
  if(details_setter) details_setter(EVENT);
2872
3057
  callback(e);
2873
3058
  },{
2874
3059
  preventDefault
2875
3060
  });
2876
-
3061
+ return this;
2877
3062
  }
2878
3063
  _off(event, category = 'global'){
2879
3064
  this.exp.events[category].removeListener(event);
@@ -3861,20 +4046,6 @@ const Scheduler = (tasks, { repeat = null} = {}) => new TimeScheduler(tasks, { r
3861
4046
 
3862
4047
  const step_fps = (step_or_fps) => 1000 / step_or_fps;
3863
4048
 
3864
- const debounce=(fn,delay=1000)=>{
3865
- let id;
3866
- return (...args) => id ? clearTimeout(id) : setTimeout(()=>fn(...args),delay);
3867
- };
3868
- const throttle=(fn,delay)=>{
3869
- let lastTime=0;
3870
- return (...args) => {
3871
- const now = new Date().getTime();
3872
- if(now-lastTime < delay) return;
3873
- lastTime = now;
3874
- fn(...args);
3875
- }
3876
- };
3877
-
3878
4049
  const sleep= ms => new Promise(res => setTimeout(res, ms));
3879
4050
  function timeout(ms, fn) {
3880
4051
  let id;
@@ -4892,6 +5063,8 @@ if(globalThis?.document){
4892
5063
  }
4893
5064
 
4894
5065
  exports.App = App;
5066
+ exports.ClickAwayEvent = ClickAwayEvent;
5067
+ exports.ClickListeners = ClickListeners;
4895
5068
  exports.Clock = Clock;
4896
5069
  exports.CloneElement = CloneElement;
4897
5070
  exports.Complex = Complex;
@@ -4901,13 +5074,16 @@ exports.EventController = EventController;
4901
5074
  exports.FileBasedRouting = FileBasedRouting;
4902
5075
  exports.Flex = Flex;
4903
5076
  exports.HTMLWrapper = HTMLWrapper;
5077
+ exports.KeyListeners = KeyListeners;
4904
5078
  exports.Matrix = Matrix;
4905
5079
  exports.PI = PI$1;
5080
+ exports.PtrListeners = PtrListeners;
4906
5081
  exports.Random = Random;
4907
5082
  exports.SPA = SPA;
4908
5083
  exports.SVGWrapper = SVGWrapper;
4909
5084
  exports.Scheduler = Scheduler;
4910
5085
  exports.Suspense = Suspense;
5086
+ exports.SwipeEvent = SwipeEvent;
4911
5087
  exports.Switch = Switch;
4912
5088
  exports.Tick = Tick;
4913
5089
  exports.TimeAnimation = TimeAnimation;
@@ -4924,6 +5100,8 @@ exports.UseRoot = UseRoot;
4924
5100
  exports.UseThread = UseThread;
4925
5101
  exports.Utils = Utils;
4926
5102
  exports.View = View;
5103
+ exports.ViewEvent = ViewEvent;
5104
+ exports.ViewListeners = ViewListeners;
4927
5105
  exports.ZikoApp = ZikoApp;
4928
5106
  exports.ZikoSPA = ZikoSPA;
4929
5107
  exports.ZikoUISuspense = ZikoUISuspense;
@@ -5054,6 +5232,9 @@ exports.pgcd = pgcd;
5054
5232
  exports.pow = pow$1;
5055
5233
  exports.ppcm = ppcm;
5056
5234
  exports.rad2deg = rad2deg;
5235
+ exports.register_click_away_event = register_click_away_event;
5236
+ exports.register_swipe_event = register_swipe_event;
5237
+ exports.register_view_event = register_view_event;
5057
5238
  exports.remove_class = remove_class;
5058
5239
  exports.round = round;
5059
5240
  exports.script = script;