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