ziko 0.68.0 → 0.68.1

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