ziko 0.50.1 → 0.51.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.cjs +772 -898
- package/dist/ziko.js +509 -240
- package/dist/ziko.min.js +2 -2
- package/dist/ziko.mjs +506 -241
- package/package.json +1 -1
- package/src/__helpers__/checkers/index.js +1 -0
- package/src/data/api/fetchdom.js +27 -11
- package/src/events/binders/coordinates-based-event.js +25 -0
- package/src/events/binders/custom-event.js +1 -1
- package/src/events/binders/index.js +45 -12
- package/src/events/custom-events-registry/index.js +3 -1
- package/src/events/custom-events-registry/swipe.js +41 -23
- package/src/events/custom-events-registry/view.js +50 -19
- package/src/events/customizers/normalise-coordinates.js +0 -0
- package/src/events/details-setter/index.js +3 -1
- package/src/events/details-setter/mouse.js +35 -0
- package/src/events/details-setter/pointer.js +33 -31
- package/src/events/details-setter/touch.js +37 -0
- package/src/events/events-map/index.js +13 -5
- package/src/events/utils.js +31 -0
- package/src/events/ziko-event.js +59 -117
- package/src/router/file-based-router/index.js +46 -0
- package/src/router/index.js +2 -0
- package/src/router/utils/dynamic-routes-parser.js +76 -0
- package/src/router/utils/get-root.js +16 -0
- package/src/router/utils/index.js +5 -0
- package/src/router/utils/normalize-path.js +17 -0
- package/src/router/utils/routes-grouper.js +22 -0
- package/src/router/utils/routes-matcher.js +60 -0
- package/src/ui/__methods__/dom.js +0 -20
- package/src/ui/__methods__/events.js +8 -4
- package/src/ui/__methods__/index.js +3 -0
- package/src/ui/__methods__/lifecycle.js +54 -0
- package/src/ui/constructors/UIElement.js +4 -30
- package/src/ui/{constructors/UIElement-lite.js → mini/UIElement.js} +1 -1
- package/src/ui/suspense/index.js +1 -2
- package/types/data/api/index.d.ts +15 -0
- package/types/data/index.d.ts +1 -0
- package/types/data/string/checkers.d.ts +51 -0
- package/types/data/string/converters.d.ts +101 -0
- package/types/data/string/index.d.ts +2 -0
- package/types/index.d.ts +3 -1
- package/types/router/file-based-router/index.d.ts +20 -0
- package/types/router/index.d.ts +2 -0
- package/types/router/utils/dynamic-routes-parser.d.ts +14 -0
- package/types/router/utils/get-root.d.ts +11 -0
- package/types/router/utils/index.d.ts +5 -0
- package/types/router/utils/normalize-path.d.ts +15 -0
- package/types/router/utils/routes-grouper.d.ts +29 -0
- package/types/router/utils/routes-matcher.d.ts +1 -0
package/src/events/ziko-event.js
CHANGED
|
@@ -1,48 +1,54 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
getEvent,
|
|
3
|
+
event_controller,
|
|
4
|
+
toggle_event_listener
|
|
5
|
+
} from './utils.js'
|
|
2
6
|
class ZikoEvent {
|
|
3
|
-
constructor(target = null, Events = [], details_setter, customizer){
|
|
7
|
+
constructor(signature, target = null, Events = [], details_setter, customizer){
|
|
4
8
|
this.target = target;
|
|
5
9
|
this.cache = {
|
|
10
|
+
signature,
|
|
6
11
|
currentEvent : null,
|
|
7
12
|
event: null,
|
|
8
13
|
options : {},
|
|
9
14
|
preventDefault : {},
|
|
10
15
|
stopPropagation : {},
|
|
11
16
|
stopImmediatePropagation : {},
|
|
12
|
-
event_flow : {},
|
|
13
17
|
paused : {},
|
|
14
|
-
stream : {
|
|
15
|
-
enabled : {},
|
|
16
|
-
clear : {},
|
|
17
|
-
history : {}
|
|
18
|
-
},
|
|
19
18
|
callbacks : {},
|
|
20
19
|
__controllers__:{}
|
|
21
20
|
}
|
|
22
|
-
if(Events)this._register_events(Events, details_setter, customizer);
|
|
23
|
-
}
|
|
24
|
-
_register_events(Events, details_setter, customizer, REGISTER_METHODES = true){
|
|
25
|
-
const events = Events?.map(n=>getEvent(n))
|
|
26
|
-
events?.forEach((event,i)=>{
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
21
|
+
if (Events) this._register_events(Events, details_setter, customizer);
|
|
22
|
+
}
|
|
23
|
+
_register_events(Events, details_setter, customizer, REGISTER_METHODES = true) {
|
|
24
|
+
const events = Events?.map(n => getEvent(n));
|
|
25
|
+
events?.forEach((event, i) => {
|
|
26
|
+
this.cache.preventDefault[event] = false;
|
|
27
|
+
this.cache.options[event] = {};
|
|
28
|
+
this.cache.paused[event] = false;
|
|
29
|
+
this.cache.__controllers__[event] = (e) =>
|
|
30
|
+
event_controller.call(this, e, event, details_setter, customizer);
|
|
31
|
+
if (REGISTER_METHODES) {
|
|
32
|
+
this[`on${Events[i]}`] = (callback) =>
|
|
33
|
+
this.__onEvent(event, this.cache.options[event], {}, callback);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
__onEvent(event, options, dispose, callback) {
|
|
39
|
+
if (!callback) return this;
|
|
40
|
+
this.cache.callbacks[event] = callback;
|
|
41
|
+
this.__handle(event, this.cache.__controllers__[event], options, dispose);
|
|
36
42
|
return this;
|
|
37
43
|
}
|
|
38
44
|
get targetElement(){
|
|
39
45
|
return this.target?.element;
|
|
40
46
|
}
|
|
41
47
|
get isParent(){
|
|
42
|
-
return this.target?.element === this.event
|
|
48
|
+
return this.target?.element === this.event?.srcElement;
|
|
43
49
|
}
|
|
44
50
|
get item(){
|
|
45
|
-
return this.target.find(n=>n.element == this.event?.srcElement)?.[0];
|
|
51
|
+
return this.target.find(n => n.element == this.event?.srcElement)?.[0];
|
|
46
52
|
}
|
|
47
53
|
get currentEvent(){
|
|
48
54
|
return this.cache.currentEvent;
|
|
@@ -50,117 +56,53 @@ class ZikoEvent {
|
|
|
50
56
|
get event(){
|
|
51
57
|
return this.cache.event;
|
|
52
58
|
}
|
|
59
|
+
get detail(){
|
|
60
|
+
return this.cache.event.detail
|
|
61
|
+
}
|
|
53
62
|
setTarget(UI){
|
|
54
|
-
this.target=UI;
|
|
63
|
+
this.target = UI;
|
|
55
64
|
return this;
|
|
56
65
|
}
|
|
57
|
-
__handle(event, handler, options
|
|
66
|
+
__handle(event, handler, options){
|
|
58
67
|
this.targetElement?.addEventListener(event, handler, options);
|
|
59
68
|
return this;
|
|
60
69
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if(this.cache.
|
|
65
|
-
|
|
66
|
-
// this.cache.callbacks.map(n=>e=>n.call(this,e));
|
|
67
|
-
this.cache.callbacks[event].map(n=>e=>n.call(this,e))
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
return this;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
else this.cache.callbacks[event] = callbacks.map(n=>e=>n.call(this,e));
|
|
74
|
-
this.__handle(event, this.cache.__controllers__[event],options, dispose)
|
|
75
|
-
return this;
|
|
76
|
-
}
|
|
77
|
-
#override(methode, overrides, defaultValue){
|
|
78
|
-
if(defaultValue === "default") Object.assign(this.cache[methode], {...this.cache[methode], ...overrides});
|
|
79
|
-
const all = defaultValue === "default"
|
|
80
|
-
? this.cache[methode]
|
|
81
|
-
: Object.fromEntries(Object.keys(this.cache.preventDefault).map(n=>[n,defaultValue]))
|
|
82
|
-
Object.assign(this.cache[methode], {...all,...overrides});
|
|
83
|
-
return this
|
|
84
|
-
}
|
|
85
|
-
preventDefault(overrides = {}, defaultValue = "default"){
|
|
86
|
-
this.#override("preventDefault", overrides, defaultValue);
|
|
87
|
-
// const all=Object.fromEntries(Object.keys(this.cache.preventDefault).map(n=>[n,defaultValue]))
|
|
88
|
-
// Object.assign(this.cache.preventDefault, {...all,...overrides});
|
|
70
|
+
#override(method, ...events) {
|
|
71
|
+
const keys = events.length === 0 ? Object.keys(this.cache[method]) : events
|
|
72
|
+
keys.forEach(e => {
|
|
73
|
+
if (this.cache[method].hasOwnProperty(e)) this.cache[method][e] = true;
|
|
74
|
+
});
|
|
89
75
|
return this;
|
|
90
76
|
}
|
|
91
|
-
|
|
92
|
-
this.#override(
|
|
93
|
-
return this;
|
|
77
|
+
preventDefault(...events) {
|
|
78
|
+
return this.#override('preventDefault', ...events);
|
|
94
79
|
}
|
|
95
|
-
|
|
96
|
-
this.#override(
|
|
97
|
-
|
|
80
|
+
stopPropagation(...events) {
|
|
81
|
+
return this.#override('stopPropagation', ...events);
|
|
82
|
+
}
|
|
83
|
+
stopImmediatePropagation(...events) {
|
|
84
|
+
return this.#override('stopImmediatePropagation', ...events);
|
|
98
85
|
}
|
|
99
86
|
setEventOptions(event, options){
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
this.
|
|
87
|
+
const evt = getEvent(event);
|
|
88
|
+
this.pause();
|
|
89
|
+
Object.assign(this.cache.options[evt], options);
|
|
90
|
+
this.resume();
|
|
103
91
|
return this;
|
|
104
92
|
}
|
|
105
|
-
pause(
|
|
106
|
-
|
|
107
|
-
? this.cache.stream.enabled
|
|
108
|
-
: Object.entries(Object.keys(this.cache.stream.enabled).map(n=>[n,defaultValue]));
|
|
109
|
-
overrides={...all,...overrides};
|
|
110
|
-
for(let key in overrides){
|
|
111
|
-
if(overrides[key]){
|
|
112
|
-
this.targetElement?.removeEventListener(key, this.cache.__controllers__[key], this.cache.options[key]);
|
|
113
|
-
this.cache.paused[key]=true;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
return this;
|
|
93
|
+
pause(...events) {
|
|
94
|
+
return toggle_event_listener.call(this, 'removeEventListener', ...events)
|
|
117
95
|
}
|
|
118
|
-
resume(
|
|
119
|
-
|
|
120
|
-
? this.cache.stream.enabled
|
|
121
|
-
: Object.entries(Object.keys(this.cache.stream.enabled).map(n=>[n,defaultValue]));
|
|
122
|
-
overrides={...all,...overrides};
|
|
123
|
-
for(let key in overrides){
|
|
124
|
-
if(overrides[key]){
|
|
125
|
-
this.targetElement?.addEventListener(key,this.cache.__controllers__[key], this.cache.options[key]);
|
|
126
|
-
this.cache.paused[key]=false;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
return this;
|
|
130
|
-
}
|
|
131
|
-
stream(overrides = {}, defaultValue = "default"){
|
|
132
|
-
this.cache.stream.t0=Date.now();
|
|
133
|
-
const all=Object.fromEntries(Object.keys(this.cache.stream.enabled).map(n=>[n,defaultValue]))
|
|
134
|
-
overrides={...all,...overrides}
|
|
135
|
-
Object.assign(this.cache.stream.enabled,overrides);
|
|
136
|
-
return this;
|
|
137
|
-
}
|
|
138
|
-
clear(){
|
|
139
|
-
return this;
|
|
96
|
+
resume(...events) {
|
|
97
|
+
return toggle_event_listener.call(this, 'addEventListener', ...events);
|
|
140
98
|
}
|
|
141
|
-
dispose(
|
|
142
|
-
this.pause(
|
|
143
|
-
|
|
99
|
+
dispose(){
|
|
100
|
+
this.pause();
|
|
101
|
+
this.target.events[this.cache.signature] = null
|
|
144
102
|
return this;
|
|
145
103
|
}
|
|
146
104
|
}
|
|
147
|
-
|
|
148
|
-
function event_controller(e, event_name, details_setter, customizer, push_object){
|
|
149
|
-
this.cache.currentEvent = event_name;
|
|
150
|
-
this.cache.event = e;
|
|
151
|
-
details_setter?.call(this);
|
|
152
|
-
customizer?.hasOwnProperty("prototype") ? customizer?.call(this) : customizer?.call(null, this);
|
|
153
|
-
// if(customizer?.hasOwnProperty("prototype")) customizer?.call(this)
|
|
154
|
-
// else customizer?.call(null, this)
|
|
155
|
-
if(this.cache.preventDefault[event_name]) e.preventDefault();
|
|
156
|
-
if(this.cache.stopPropagation[event_name]) e.stopPropagation();
|
|
157
|
-
if(this.cache.stopImmediatePropagation[event_name]) e.stopImmediatePropagation();
|
|
158
|
-
|
|
159
|
-
if(this.cache.stream.enabled[event_name]&&push_object)this.cache.stream.history[event_name].push(push_object);
|
|
160
|
-
this.cache.callbacks[event_name]?.map(n=>n(this));
|
|
161
|
-
}
|
|
162
|
-
|
|
163
105
|
export {
|
|
164
106
|
ZikoEvent,
|
|
165
107
|
getEvent
|
|
166
|
-
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {
|
|
2
|
+
get_root,
|
|
3
|
+
normalize_path,
|
|
4
|
+
routes_matcher,
|
|
5
|
+
is_dynamic,
|
|
6
|
+
dynamic_routes_parser
|
|
7
|
+
} from "../utils/index.js"
|
|
8
|
+
export async function createSPAFileBasedRouter(
|
|
9
|
+
pages,
|
|
10
|
+
target = globalThis?.document?.body
|
|
11
|
+
) {
|
|
12
|
+
if(!(target instanceof HTMLElement) && target?.element instanceof HTMLElement) target = target?.element;
|
|
13
|
+
if (!(target instanceof HTMLElement)) {
|
|
14
|
+
throw new Error("Invalid mount target: must be HTMLElement or UIElement");
|
|
15
|
+
}
|
|
16
|
+
let path = decodeURIComponent(globalThis.location.pathname.replace(/\/$/, ''));
|
|
17
|
+
const routes = Object.keys(pages);
|
|
18
|
+
const root = get_root(routes);
|
|
19
|
+
|
|
20
|
+
const pairs = {};
|
|
21
|
+
for (const route of routes) {
|
|
22
|
+
const module = await pages[route]();
|
|
23
|
+
const modComponent = await module.default;
|
|
24
|
+
pairs[normalize_path(route, root)] = modComponent;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let mask = null;
|
|
28
|
+
let component = null;
|
|
29
|
+
|
|
30
|
+
for (const [routePath, comp] of Object.entries(pairs)) {
|
|
31
|
+
if (routes_matcher(routePath, `/${path}`)) {
|
|
32
|
+
mask = routePath;
|
|
33
|
+
component = comp;
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!mask) return; // no route matched
|
|
39
|
+
|
|
40
|
+
const params = is_dynamic(mask) ? dynamic_routes_parser(mask, path) : undefined;
|
|
41
|
+
const mounted = params ? await component(params) : await component();
|
|
42
|
+
|
|
43
|
+
if(mounted instanceof HTMLElement) target.append(mounted);
|
|
44
|
+
else mounted.mount(target);
|
|
45
|
+
|
|
46
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export function dynamic_routes_parser(mask, route) {
|
|
2
|
+
const maskSegments = mask.split("/").filter(Boolean);
|
|
3
|
+
const routeSegments = route.split("/").filter(Boolean);
|
|
4
|
+
const params = {};
|
|
5
|
+
let i = 0, j = 0;
|
|
6
|
+
while (i < maskSegments.length && j < routeSegments.length) {
|
|
7
|
+
const maskSegment = maskSegments[i];
|
|
8
|
+
const routeSegment = routeSegments[j];
|
|
9
|
+
if (maskSegment.startsWith("[...") && maskSegment.endsWith("]")) {
|
|
10
|
+
const paramName = maskSegment.slice(4, -1);
|
|
11
|
+
const remainingMaskSegments = maskSegments.length - i - 1;
|
|
12
|
+
if (remainingMaskSegments === 0) {
|
|
13
|
+
params[paramName] = routeSegments.slice(j).join("/");
|
|
14
|
+
break;
|
|
15
|
+
}
|
|
16
|
+
let requiredSegments = 0;
|
|
17
|
+
for (let k = i + 1; k < maskSegments.length; k++) {
|
|
18
|
+
if (!maskSegments[k].endsWith("]+")) requiredSegments++;
|
|
19
|
+
}
|
|
20
|
+
const remainingRouteSegments = routeSegments.length - j;
|
|
21
|
+
const segmentsToConsume = remainingRouteSegments - requiredSegments;
|
|
22
|
+
if (segmentsToConsume >= 1) {
|
|
23
|
+
params[paramName] = routeSegments
|
|
24
|
+
.slice(j, j + segmentsToConsume)
|
|
25
|
+
.join("/");
|
|
26
|
+
j += segmentsToConsume;
|
|
27
|
+
}
|
|
28
|
+
else return {};
|
|
29
|
+
i++;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (maskSegment.startsWith("[") && maskSegment.endsWith("]+")) {
|
|
33
|
+
const paramName = maskSegment.slice(1, -2);
|
|
34
|
+
if (routeSegment) {
|
|
35
|
+
params[paramName] = routeSegment;
|
|
36
|
+
j++;
|
|
37
|
+
}
|
|
38
|
+
i++;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (maskSegment.startsWith("[") && maskSegment.endsWith("]")) {
|
|
42
|
+
const paramName = maskSegment.slice(1, -1);
|
|
43
|
+
params[paramName] = routeSegment;
|
|
44
|
+
}
|
|
45
|
+
else if (maskSegment !== routeSegment) return {};
|
|
46
|
+
i++;
|
|
47
|
+
j++;
|
|
48
|
+
}
|
|
49
|
+
return params;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
// console.log("\n=== PARSER TESTS ===");
|
|
54
|
+
// console.log(dynamic_routes_parser("/user/[id]+", "/user"));
|
|
55
|
+
// // 👉 {}
|
|
56
|
+
|
|
57
|
+
// console.log(dynamic_routes_parser("/user/[id]+", "/user/42"));
|
|
58
|
+
// // 👉 { id: "42" }
|
|
59
|
+
|
|
60
|
+
// console.log(dynamic_routes_parser("/blog/[...slug]", "/blog/2025/oct/post"));
|
|
61
|
+
// // 👉 { slug: "2025/oct/post" }
|
|
62
|
+
|
|
63
|
+
// console.log(
|
|
64
|
+
// dynamic_routes_parser("/product/[category]/[id]+", "/product/electronics"),
|
|
65
|
+
// );
|
|
66
|
+
// // 👉 { category: "electronics" }
|
|
67
|
+
|
|
68
|
+
// console.log("\n=== FIX TEST ===");
|
|
69
|
+
// console.log(dynamic_routes_parser("/[...slug]/[id]", "/sl1/sl2/9"));
|
|
70
|
+
// // 👉 { slug: "sl1/sl2", id: "9" }
|
|
71
|
+
|
|
72
|
+
// console.log(dynamic_routes_parser("/[slug]/[...id]", "/sl1/id1/id2"));
|
|
73
|
+
// // 👉 { slug: "sl1", id: "id1/id2" }
|
|
74
|
+
|
|
75
|
+
// console.log(dynamic_routes_parser("/blog/lang/[lang]/id/[id]", "/blog/lang/en/id/10"));
|
|
76
|
+
// // 👉 { lang: "en", id: "10" }
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function get_root(paths) {
|
|
2
|
+
if (paths.length === 0) return '';
|
|
3
|
+
const splitPaths = paths.map(path => path.split('/'));
|
|
4
|
+
const minLength = Math.min(...splitPaths.map(parts => parts.length));
|
|
5
|
+
let commonParts = [];
|
|
6
|
+
for (let i = 0; i < minLength; i++) {
|
|
7
|
+
const part = splitPaths[0][i];
|
|
8
|
+
if (splitPaths.every(parts => parts[i] === part || parts[i].startsWith('['))) {
|
|
9
|
+
commonParts.push(part);
|
|
10
|
+
}
|
|
11
|
+
else break;
|
|
12
|
+
|
|
13
|
+
}
|
|
14
|
+
const root = commonParts.join('/') + (commonParts.length ? '/' : '');
|
|
15
|
+
return root;
|
|
16
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function normalize_path(inputPath, root = './src/pages', extensions = ['js', 'ts']) {
|
|
2
|
+
if(root.at(-1)==="/") root = root.slice(0, -1)
|
|
3
|
+
const normalizedPath = inputPath.replace(/\\/g, '/')
|
|
4
|
+
// .replace(/\[(\w+)\]/g, '$1/:$1');
|
|
5
|
+
const parts = normalizedPath.split('/');
|
|
6
|
+
const rootParts = root.split('/');
|
|
7
|
+
const rootIndex = parts.indexOf(rootParts[rootParts.length - 1]);
|
|
8
|
+
if (rootIndex !== -1) {
|
|
9
|
+
const subsequentParts = parts.slice(rootIndex + 1);
|
|
10
|
+
const lastPart = subsequentParts[subsequentParts.length - 1];
|
|
11
|
+
const isIndexFile = lastPart === 'index.js' || lastPart === 'index.ts';
|
|
12
|
+
const hasValidExtension = extensions.some(ext => lastPart === `.${ext}` || lastPart.endsWith(`.${ext}`));
|
|
13
|
+
if (isIndexFile) return '/' + (subsequentParts.length > 1 ? subsequentParts.slice(0, -1).join('/') : '');
|
|
14
|
+
if (hasValidExtension) return '/' + subsequentParts.join('/').replace(/\.(js|ts)$/, '');
|
|
15
|
+
}
|
|
16
|
+
return '';
|
|
17
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export function is_dynamic(path) {
|
|
2
|
+
const DynamicPattern = /(:\w+|\[\.\.\.\w+\]|\[\w+\]\+?)/;
|
|
3
|
+
return DynamicPattern.test(path);
|
|
4
|
+
}
|
|
5
|
+
export function routes_grouper(routeMap) {
|
|
6
|
+
const grouped = {
|
|
7
|
+
static: {},
|
|
8
|
+
dynamic: {},
|
|
9
|
+
};
|
|
10
|
+
for (const [path, value] of Object.entries(routeMap)) {
|
|
11
|
+
if (is_dynamic(path)) {
|
|
12
|
+
const segments = path.split("/").filter(Boolean);
|
|
13
|
+
const optionalIndex = segments.findIndex(seg => seg.endsWith("]+"));
|
|
14
|
+
const hasInvalidOptional =
|
|
15
|
+
optionalIndex !== -1 && optionalIndex !== segments.length - 1;
|
|
16
|
+
if (hasInvalidOptional) throw new Error(`Invalid optional param position in route: "${path}" — optional parameters can only appear at the end.`);
|
|
17
|
+
grouped.dynamic[path] = value;
|
|
18
|
+
}
|
|
19
|
+
else grouped.static[path] = value;
|
|
20
|
+
}
|
|
21
|
+
return grouped;
|
|
22
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export function routes_matcher(mask, route) {
|
|
2
|
+
const maskSegments = mask.split("/").filter(Boolean);
|
|
3
|
+
const routeSegments = route.split("/").filter(Boolean);
|
|
4
|
+
let i = 0, j = 0;
|
|
5
|
+
while (i < maskSegments.length && j < routeSegments.length) {
|
|
6
|
+
const maskSegment = maskSegments[i];
|
|
7
|
+
const routeSegment = routeSegments[j];
|
|
8
|
+
if (maskSegment.startsWith("[...") && maskSegment.endsWith("]")) {
|
|
9
|
+
const remainingMaskSegments = maskSegments.length - i - 1;
|
|
10
|
+
if (remainingMaskSegments === 0) return true;
|
|
11
|
+
// Calculate minimum required route segments for remaining mask
|
|
12
|
+
let requiredSegments = 0;
|
|
13
|
+
for (let k = i + 1; k < maskSegments.length; k++) {
|
|
14
|
+
if (!maskSegments[k].endsWith("]+")) {
|
|
15
|
+
requiredSegments++;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const remainingRouteSegments = routeSegments.length - j;
|
|
19
|
+
if (remainingRouteSegments < requiredSegments) return false;
|
|
20
|
+
const segmentsToConsume = remainingRouteSegments - requiredSegments;
|
|
21
|
+
if (segmentsToConsume < 1) return false;
|
|
22
|
+
j += segmentsToConsume;
|
|
23
|
+
i++;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (maskSegment.startsWith("[") && maskSegment.endsWith("]+")) {
|
|
27
|
+
if (routeSegment) j++;
|
|
28
|
+
i++;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (maskSegment.startsWith("[") && maskSegment.endsWith("]")) {
|
|
32
|
+
i++;
|
|
33
|
+
j++;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (maskSegment !== routeSegment) return false;
|
|
37
|
+
i++;
|
|
38
|
+
j++;
|
|
39
|
+
}
|
|
40
|
+
while (i < maskSegments.length) {
|
|
41
|
+
const seg = maskSegments[i];
|
|
42
|
+
if (seg.endsWith("]+")) {
|
|
43
|
+
i++;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
return i === maskSegments.length && j === routeSegments.length;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
// // DEMO
|
|
53
|
+
// console.log("=== EXISTING TESTS ===");
|
|
54
|
+
// console.log(routes_matcher("/user/[id]+", "/user")); // true
|
|
55
|
+
// console.log(routes_matcher("/user/[id]+", "/user/42")); // true
|
|
56
|
+
// console.log(routes_matcher("/blog/[...slug]", "/blog/a/b")); // true
|
|
57
|
+
// console.log(routes_matcher("/blog/[id]", "/blog")); // false
|
|
58
|
+
// console.log(routes_matcher("/product/:id", "/product/99")); // true
|
|
59
|
+
|
|
60
|
+
|
|
@@ -35,18 +35,6 @@ export function clear(){
|
|
|
35
35
|
this.element.innerHTML = "";
|
|
36
36
|
return this;
|
|
37
37
|
}
|
|
38
|
-
export function mount(target = this.target) {
|
|
39
|
-
if(this.isBody)return ;
|
|
40
|
-
if(target?.isUIElement)target=target.element;
|
|
41
|
-
this.target=target;
|
|
42
|
-
this.target?.appendChild(this.element);
|
|
43
|
-
return this;
|
|
44
|
-
}
|
|
45
|
-
export function unmount(){
|
|
46
|
-
if(this.cache.parent)this.cache.parent.remove(this);
|
|
47
|
-
else if(this.target?.children?.length && [...this.target?.children].includes(this.element)) this.target.removeChild(this.element);
|
|
48
|
-
return this;
|
|
49
|
-
}
|
|
50
38
|
export function replaceElementWith(new_element){
|
|
51
39
|
this.cache.element.replaceWith(new_element)
|
|
52
40
|
this.cache.element = new_element;
|
|
@@ -54,14 +42,6 @@ export function replaceElementWith(new_element){
|
|
|
54
42
|
// To do : Dispose Events and States
|
|
55
43
|
return this
|
|
56
44
|
}
|
|
57
|
-
export function renderAfter(t = 1) {
|
|
58
|
-
setTimeout(() => this.mount(), t);
|
|
59
|
-
return this;
|
|
60
|
-
}
|
|
61
|
-
export function unrenderAfter(t = 1) {
|
|
62
|
-
setTimeout(() => this.unmount(), t);
|
|
63
|
-
return this;
|
|
64
|
-
}
|
|
65
45
|
export function after(ui){
|
|
66
46
|
if(ui?.isUIElement) ui=ui.element;
|
|
67
47
|
this.element?.after(ui)
|
|
@@ -7,7 +7,9 @@ import {
|
|
|
7
7
|
bind_drag_event,
|
|
8
8
|
bind_clipboard_event,
|
|
9
9
|
bind_focus_event,
|
|
10
|
-
bind_wheel_event
|
|
10
|
+
bind_wheel_event,
|
|
11
|
+
bind_view_event,
|
|
12
|
+
bind_swipe_event
|
|
11
13
|
} from "../../events/binders/index.js";
|
|
12
14
|
|
|
13
15
|
import { bind_custom_event } from "../../events/binders/custom-event.js";
|
|
@@ -20,7 +22,9 @@ const binderMap = {
|
|
|
20
22
|
drag : bind_drag_event,
|
|
21
23
|
clipboard : bind_clipboard_event,
|
|
22
24
|
focus : bind_focus_event,
|
|
23
|
-
wheel : bind_wheel_event
|
|
25
|
+
wheel : bind_wheel_event,
|
|
26
|
+
view : bind_view_event,
|
|
27
|
+
swipe : bind_swipe_event
|
|
24
28
|
};
|
|
25
29
|
|
|
26
30
|
const EventsMethodes = {
|
|
@@ -40,9 +44,9 @@ Object.entries(EventsMap).forEach(([name, eventList]) => {
|
|
|
40
44
|
const lname = name.toLowerCase()
|
|
41
45
|
eventList.forEach(event => {
|
|
42
46
|
const methodName = `on${event}`;
|
|
43
|
-
EventsMethodes[methodName] = function (
|
|
47
|
+
EventsMethodes[methodName] = function (callbacks) {
|
|
44
48
|
if (!this.events[lname]) this.events[lname] = binderMap[lname](this);
|
|
45
|
-
this.events[lname][methodName](
|
|
49
|
+
this.events[lname][methodName](callbacks);
|
|
46
50
|
return this;
|
|
47
51
|
};
|
|
48
52
|
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// export function mount(target = this.target) {
|
|
2
|
+
// if(this.isBody) return ;
|
|
3
|
+
// if(target?.isUIElement)target=target.element;
|
|
4
|
+
// this.target=target;
|
|
5
|
+
// this.target?.appendChild(this.element);
|
|
6
|
+
// return this;
|
|
7
|
+
// }
|
|
8
|
+
// export function unmount(){
|
|
9
|
+
// if(this.cache.parent)this.cache.parent.remove(this);
|
|
10
|
+
// else if(this.target?.children?.length && [...this.target?.children].includes(this.element)) this.target.removeChild(this.element);
|
|
11
|
+
// return this;
|
|
12
|
+
// }
|
|
13
|
+
|
|
14
|
+
// export function mountAfter(target = this.target, t = 1) {
|
|
15
|
+
// setTimeout(() => this.mount(), t);
|
|
16
|
+
// return this;
|
|
17
|
+
// }
|
|
18
|
+
// export function unmountAfter(t = 1) {
|
|
19
|
+
// setTimeout(() => this.unmount(), t);
|
|
20
|
+
// return this;
|
|
21
|
+
// }
|
|
22
|
+
|
|
23
|
+
export function mount(target = this.target, delay = 0) {
|
|
24
|
+
if (delay > 0) {
|
|
25
|
+
setTimeout(() => this.mount(target, 0), delay);
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (this.isBody) return this;
|
|
30
|
+
|
|
31
|
+
if (target?.isUIElement) target = target.element;
|
|
32
|
+
this.target = target;
|
|
33
|
+
|
|
34
|
+
this.target?.appendChild(this.element);
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function unmount(delay = 0) {
|
|
39
|
+
if (delay > 0) {
|
|
40
|
+
setTimeout(() => this.unmount(0), delay);
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (this.cache.parent) {
|
|
45
|
+
this.cache.parent.remove(this);
|
|
46
|
+
} else if (
|
|
47
|
+
this.target?.children?.length &&
|
|
48
|
+
[...this.target.children].includes(this.element)
|
|
49
|
+
) {
|
|
50
|
+
this.target.removeChild(this.element);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return this;
|
|
54
|
+
}
|