ziko 2.0.0-beta.15 → 2.0.0-beta.16.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ziko",
3
- "version": "2.0.0-beta.15",
3
+ "version": "2.0.0-beta.16.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",
@@ -1,9 +1,9 @@
1
1
  import { UIElement as UIElementCore } from "../../mini-dom/UIElement/index.js";
2
2
  import { register_to_class } from "../../internal-utils/register/register-to-class.js";
3
- import {
3
+ import {
4
4
  // LifecycleMethods,
5
5
  AttrsMethods,
6
- DomMethods,
6
+ // DomMethods,
7
7
  // IndexingMethods,
8
8
  // StyleMethods,
9
9
  } from "../../mini-dom/mixins/index.js";
@@ -14,21 +14,26 @@ import {
14
14
  ClickListeners,
15
15
  KeyListeners,
16
16
  ViewListeners,
17
- } from '../../events/index.js'
17
+ } from "../../events/index.js";
18
18
  import { isStateGetter } from "../../hooks/use-state.js";
19
- class UIElement extends UIElementCore{
20
- constructor({element, name ='', type = 'html', render = __Ziko__.__Config__.default.render, props}={}){
21
- super()
19
+ import { text } from "../../mini-dom/text/index.js";
20
+ export class UIElement extends UIElementCore {
21
+ constructor({
22
+ element,
23
+ name = "",
24
+ type = "html",
25
+ render = __Ziko__.__Config__.default.render,
26
+ props,
27
+ } = {}) {
28
+ super();
22
29
  this.exp = {
23
- events : {
24
-
25
- }
26
- }
30
+ events: {},
31
+ };
27
32
  register_to_class(
28
- this,
33
+ this,
29
34
  // LifecycleMethods,
30
- AttrsMethods,
31
- DomMethods,
35
+ AttrsMethods,
36
+ // DomMethods,
32
37
  // StyleMethods,
33
38
  // IndexingMethods,
34
39
  PtrListeners,
@@ -37,80 +42,100 @@ class UIElement extends UIElementCore{
37
42
  ViewListeners,
38
43
  );
39
44
 
40
- if(element) this.init({element, name, type, render, props});
41
- }
42
- on(event_name, callback, {details_setter, category = 'global', isCustom = false, preventDefault = false} = {}){
43
- if(event_name instanceof Array) event_name.forEach(
44
- event => this.on(
45
- event,
46
- callback,
47
- {details_setter, category, isCustom, preventDefault}
48
- )
49
- )
50
- if(category && !this.exp.events.hasOwnProperty(category)) this.exp.events[category] = new EventController(this, category);
51
- isCustom && this.exp.events[category].cache.customEvents.add(event_name)
45
+ if (element) this.init({ element, name, type, render, props });
46
+ }
47
+ on(
48
+ event_name,
49
+ callback,
50
+ {
51
+ details_setter,
52
+ category = "global",
53
+ isCustom = false,
54
+ preventDefault = false,
55
+ } = {},
56
+ ) {
57
+ if (event_name instanceof Array)
58
+ event_name.forEach((event) =>
59
+ this.on(event, callback, {
60
+ details_setter,
61
+ category,
62
+ isCustom,
63
+ preventDefault,
64
+ }),
65
+ );
66
+ if (category && !this.exp.events.hasOwnProperty(category))
67
+ this.exp.events[category] = new EventController(this, category);
68
+ isCustom && this.exp.events[category].cache.customEvents.add(event_name);
52
69
  const EVENT = this.exp.events[category];
53
- EVENT.addListener(event_name, (e)=>{
54
- if(details_setter) details_setter(EVENT);
55
- callback(e)
56
- },{
57
- preventDefault
58
- });
70
+ EVENT.addListener(
71
+ event_name,
72
+ (e) => {
73
+ if (details_setter) details_setter(EVENT);
74
+ callback(e);
75
+ },
76
+ {
77
+ preventDefault,
78
+ },
79
+ );
59
80
  return this;
60
81
  }
61
- off(event, category = 'global'){
82
+ off(event, category = "global") {
62
83
  this.exp.events[category].removeListener(event);
63
- return this
84
+ return this;
64
85
  }
65
- get element(){
86
+ get element() {
66
87
  return this.cache.element;
67
88
  }
68
- get itemsTarget(){
69
- return this.cache.itemsTarget;
89
+ get itemsTarget() {
90
+ return this.cache.itemsTarget;
70
91
  }
71
- get itemsTargetElement(){
92
+ get itemsTargetElement() {
72
93
  return this.itemsTarget.element;
73
94
  }
74
- setItemsTarget(parent){
95
+ setItemsTarget(parent) {
75
96
  this.cache.itemsTarget = parent;
76
97
  this.items = parent.items;
77
98
  return this;
78
99
  }
79
- isInteractive(){
100
+ isInteractive() {
80
101
  return this.cache.isInteractive;
81
102
  }
82
- useClient(directive){
83
- if(!this.cache.isInteractive){
84
- this.element.setAttribute('data-hydration-index', globalThis.__Ziko__.__HYDRATION__.index);
103
+ useClient(directive) {
104
+ if (!this.cache.isInteractive) {
105
+ this.element.setAttribute(
106
+ "data-hydration-index",
107
+ globalThis.__Ziko__.__HYDRATION__.index,
108
+ );
85
109
  globalThis.__Ziko__.__HYDRATION__.register(() => this.constructor);
86
110
  this.cache.isInteractive = true;
87
111
  }
88
- if(directive)this.element.setAttribute('data-hydration-directive', directive);
112
+ if (directive)
113
+ this.element.setAttribute("data-hydration-directive", directive);
89
114
  return this;
90
115
  }
91
116
  // get st(){
92
117
  // return this.cache.style;
93
118
  // }
94
- get attr(){
119
+ get attr() {
95
120
  return this.cache.attributes;
96
121
  }
97
- get evt(){
122
+ get evt() {
98
123
  return this.events;
99
124
  }
100
- get html(){
125
+ get html() {
101
126
  return this.element.innerHTML;
102
127
  }
103
- get text(){
128
+ get text() {
104
129
  return this.element.textContent;
105
130
  }
106
131
  // get isBody(){
107
132
  // return this.element === globalThis?.document.body;
108
133
  // }
109
- get parent(){
134
+ get parent() {
110
135
  return this.cache.parent;
111
136
  }
112
- get rect(){
113
- return this.element.getBoundingClientRect()
137
+ get rect() {
138
+ return this.element.getBoundingClientRect();
114
139
  }
115
140
  // get width(){
116
141
  // return this.element.getBoundingClientRect().width;
@@ -142,19 +167,19 @@ class UIElement extends UIElementCore{
142
167
  }
143
168
  unmount() {
144
169
  if (this.cache.parent) {
145
- this.cache.parent.remove(this);
146
- }
147
- else if (
148
- this.target?.children?.length &&
149
- [...this.target.children].includes(this.element)
150
- )this.target.removeChild(this.element);
170
+ this.cache.parent.remove(this);
171
+ } else if (
172
+ this.target?.children?.length &&
173
+ [...this.target.children].includes(this.element)
174
+ )
175
+ this.target.removeChild(this.element);
151
176
  return this;
152
177
  }
153
178
 
154
179
  // Indexing
155
180
 
156
181
  at(index) {
157
- return this.items.at(index);
182
+ return this.items.at(index);
158
183
  }
159
184
  forEach(callback) {
160
185
  this.items.forEach(callback);
@@ -166,35 +191,104 @@ class UIElement extends UIElementCore{
166
191
  find(condition) {
167
192
  return this.items.filter(condition);
168
193
  }
169
- // Styling
170
- style(styles){
171
- if(!this.element?.style) return this;
172
- for(let key in styles){
194
+ // Styling
195
+ style(styles) {
196
+ if (!this.element?.style) return this;
197
+ for (let key in styles) {
173
198
  const value = styles[key];
174
- if(isStateGetter(value)){
175
- const getter = value()
176
- Object.assign(this.element.style, {[key] : getter.value})
199
+ if (isStateGetter(value)) {
200
+ const getter = value();
201
+ Object.assign(this.element.style, { [key]: getter.value });
177
202
  getter._subscribe(
178
203
  (newValue) => {
179
- Object.assign(this.element.style, {[key] : newValue})
204
+ Object.assign(this.element.style, { [key]: newValue });
180
205
  },
181
- // this
206
+ // this
182
207
  );
183
- }
184
- else Object.assign(this.element.style, {[key] : value})
208
+ } else Object.assign(this.element.style, { [key]: value });
185
209
  }
186
210
  return this;
187
211
  }
188
- size(width, height){
189
- return this.style({width, height})
212
+ size(width, height) {
213
+ return this.style({ width, height });
190
214
  }
191
- hide(){
215
+ hide() {}
216
+ show() {}
192
217
 
193
- }
194
- show(){
218
+ // Dom
195
219
 
220
+ append(...ele) {
221
+ this.__addItems__("append", "push", ...ele);
222
+ return this;
196
223
  }
224
+ prepend(...ele) {
225
+ this.this.__addItems__("prepend", "unshift", ...ele);
226
+ return this;
227
+ }
228
+ insertAt(index, ...ele) {
229
+ const target = this.itemsTarget;
230
+ if (index >= target.items.length) return this.append(...ele);
231
+ for (let i = 0; i < ele.length; i++) {
232
+ if (["number", "string"].includes(typeof ele[i])) ele[i] = text(ele[i]);
233
+ target.element?.insertBefore(ele[i].element, target.items[index].element);
234
+ target.items.splice(index, 0, ele[i]);
235
+ }
236
+ target.maintain();
237
+ return this;
238
+ }
239
+ remove(...ele) {
240
+ const remove = (ele) => {
241
+ if (typeof ele === "number") ele = this.items[ele];
242
+ if (ele?.isUIElement) this.itemsTarget.element?.removeChild(ele.element);
243
+ this.items = this.items.filter((n) => n !== ele);
244
+ };
245
+ for (let i = 0; i < ele.length; i++) remove(ele[i]);
246
+ for (let i = 0; i < this.items.length; i++)
247
+ Object.assign(this, { [[i]]: this.items[i] });
248
+ // Remove from item
249
+ return this;
250
+ }
251
+
252
+ async __addItem__(adder, pusher, item, referenceNode = null, index = null) {
253
+ const { element: itemsTargetEl, items } = this.itemsTarget;
254
+ if (["number", "string"].includes(typeof item)) item = text(item);
255
+ if (typeof item === "function" && isStateGetter(item)) {
256
+ const getter = item();
257
+ item = getter.value;
197
258
 
259
+ getter._subscribe((newValue) => {
260
+ if (newValue?.isUIElement?.()) {
261
+ item.element.replaceWith(newValue.element);
262
+ item = newValue;
263
+ } else {
264
+ item.element.textContent = newValue;
265
+ }
266
+ });
267
+ }
268
+ if (
269
+ typeof globalThis?.Node === "function" &&
270
+ item instanceof globalThis.Node
271
+ )
272
+ item = new UIElement({element : item});
273
+ if (item instanceof Promise) item = await item;
274
+ if (item?.isUINode) {
275
+ item.cache.parent = this;
276
+ item.target = itemsTargetEl;
277
+ if (adder === "insertBefore" && itemsTargetEl)
278
+ itemsTargetEl.insertBefore(item.element, referenceNode);
279
+ else if (typeof itemsTargetEl?.[adder] === "function")
280
+ itemsTargetEl[adder](item.element);
281
+ if (pusher === "splice" && index !== null) items.splice(index, 0, item);
282
+ else if (typeof items?.[pusher] === "function") items[pusher](item);
283
+ return;
284
+ }
285
+ }
198
286
 
287
+ async __addItems__(adder, pusher, ...elements) {
288
+ for (const item of elements) {
289
+ await this.__addItem__(adder, pusher, item);
290
+ }
291
+ this.maintain();
292
+ return this;
293
+ }
199
294
  }
200
- export { UIElement }
@@ -13,15 +13,17 @@ export const tags = new Proxy({}, {
13
13
  if(SVGTags.includes(tag)) type = 'svg';
14
14
  if(MathMLTags.includes(tag)) type = 'mathml';
15
15
  return (...args) => {
16
+ const ui = new UIElement({element : tag, name : tag, type});
17
+ const first = args[0]
16
18
  if(args.length === 0) {
17
- return new UIElement({element : tag, name : tag, type})
19
+ return ui
18
20
  }
19
21
  if(
20
- ['string', 'number'].includes(typeof args[0])
21
- || args[0] instanceof UIElement
22
- || isStateGetter(args[0])
23
- || args[0] instanceof HTMLElement
24
- ) return new UIElement({element : tag, name : tag, type}).append(...args);
22
+ ['string', 'number'].includes(typeof first)
23
+ || first instanceof UIElement
24
+ || isStateGetter(first)
25
+ || first instanceof HTMLElement
26
+ ) return ui.append(...args);
25
27
  return new UIElement({element : tag, type, props : args.shift()}).append(...args)
26
28
  }
27
29
  }
@@ -1,24 +1,84 @@
1
- // createSPAFileBasedRouter.d.ts
2
-
3
1
  import { UIElement } from '../../dom/UIElement'
2
+ import type { UILayout } from '../../Layout'
3
+
4
+ export type Component<T = unknown> =
5
+ | ((params?: Record<string, string>) => T)
6
+ | T
7
+ | T[]
8
+
9
+ export type Renderer<TComponent = unknown, TTarget = unknown> = (
10
+ target: TTarget,
11
+ component: TComponent | TComponent[] | null,
12
+ params: Record<string, string>,
13
+ wrapper?: unknown
14
+ ) => void | Promise<void>
15
+
16
+ export interface CreateFileBasedRouterOptions<
17
+ TComponent = unknown,
18
+ TTarget = unknown
19
+ > {
20
+ pages?: Record<
21
+ string,
22
+ () => Promise<{
23
+ default: (params?: Record<string, string>) => TComponent
24
+ [key: string]: unknown
25
+ }>
26
+ >
27
+
28
+ target?: TTarget | null
29
+
30
+ extensions?: string[]
31
+
32
+ renderer?: Renderer<TComponent, TTarget>
33
+
34
+ wrapper?: unknown
35
+
36
+ lazy?: boolean
37
+
38
+ base?: string
39
+
40
+ url?: string
41
+
42
+ namedExportHandler?: Record<
43
+ string,
44
+ (
45
+ exportedFn: unknown,
46
+ context: {
47
+ route: string | null
48
+ mask: string | null
49
+ module: unknown
50
+ currentPath: string
51
+ params: Record<string, string>
52
+ }
53
+ ) => unknown | Promise<unknown>
54
+ >
55
+ }
56
+
57
+ export interface FileBasedRouterResult<TComponent = unknown> {
58
+ mask: string | null
59
+ component: TComponent | null
60
+ params: Record<string, string>
61
+ namedExports?: Record<string, unknown>
62
+ matched: boolean
63
+ error?: unknown
64
+ }
65
+
66
+ export declare function _createFileBasedRouter<
67
+ TComponent = unknown,
68
+ TTarget = unknown
69
+ >(
70
+ options?: CreateFileBasedRouterOptions<TComponent, TTarget>
71
+ ): Promise<FileBasedRouterResult<TComponent>>
72
+
73
+
74
+ export type ZikoComponent =
75
+ | UIElement
76
+ | UIElement[]
77
+ | UILayout
4
78
 
5
- /**
6
- * Creates a SPA (Single Page Application) file-based router.
7
- * Automatically loads and mounts the component corresponding to the current path.
8
- * Supports dynamic routes and parameter extraction.
9
- *
10
- * @param pages - An object mapping route paths to async module functions that return a component.
11
- * Example: { "/user/[id]": () => import("./pages/user/[id].js") }
12
- * @param target - Optional DOM element to mount the component. Defaults to `document.body`.
13
- */
14
- export function createSPAFileBasedRouter(
15
- options : {
16
- pages: Record<
17
- string,
18
- () => Promise<{ default: (param? : Record<string, string>) => UIElement | UIElement[]}>
19
- >,
20
- target?: HTMLElement | UIElement
21
- extensions : string[],
22
- wrapper : Function
23
- },
24
- ): Promise<void>;
79
+ export declare function createFileBasedRouter(
80
+ options?: CreateFileBasedRouterOptions<
81
+ ZikoComponent,
82
+ HTMLElement | UIElement
83
+ >
84
+ ): Promise<FileBasedRouterResult<ZikoComponent>>
@@ -161,7 +161,4 @@ export async function createFileBasedRouter({
161
161
  namedExports,
162
162
  matched: true
163
163
  };
164
- }
165
-
166
- // Backward-compatible alias for SPA usage
167
- export const createSPAFileBasedRouter = createFileBasedRouter;
164
+ }
@@ -1,24 +1,62 @@
1
- export const camel2hyphencase = (text = '') => text.replace(/[A-Z]/g, match => '-' + match.toLowerCase());
2
- export const camel2snakecase = (text = '') => text.replace(/[A-Z]/g, match => '_' + match.toLowerCase());
1
+ export const camel2hyphencase = (text = '') =>
2
+ text.replace(/[A-Z]/g, (match, index) =>
3
+ index ? `-${match.toLowerCase()}` : match.toLowerCase()
4
+ );
5
+ export const camel2snakecase = (text = '') =>
6
+ text.replace(/[A-Z]/g, (match, index) =>
7
+ index ? `_${match.toLowerCase()}` : match.toLowerCase()
8
+ );
3
9
  export const camel2pascalcase = (text = '') => text.charAt(0).toUpperCase() + text.slice(1);
4
- export const camel2constantcase = (text = '') => text.replace(/[A-Z]/g, match => '_' + match).toUpperCase();
10
+ export const camel2constantcase = (text = '') => text
11
+ .replace(/[A-Z]/g, (match, index) =>
12
+ index ? `_${match}` : match
13
+ )
14
+ .toUpperCase();
5
15
 
6
- export const pascal2snakecase = (text = '') => text.replace(/([A-Z])/g, (match, _, offset) => offset ? '_' + match.toLowerCase() : match.toLowerCase());
7
- export const pascal2hyphencase = (text = '') => text.replace(/([A-Z])/g, (match, _, offset) => offset ? '-' + match.toLowerCase() : match.toLowerCase());
8
- export const pascal2constantcase = (text = '') => text.replace(/([A-Z])/g, (match, _, offset) => offset ? '_' + match : match).toUpperCase();
16
+
17
+ export const pascal2snakecase = (text = '') =>
18
+ text.replace(/[A-Z]/g, (match, offset) =>
19
+ offset === 0
20
+ ? match.toLowerCase()
21
+ : `_${match.toLowerCase()}`
22
+ );
23
+
24
+ export const pascal2hyphencase = (text = '') =>
25
+ text.replace(/[A-Z]/g, (match, offset) =>
26
+ offset === 0
27
+ ? match.toLowerCase()
28
+ : `-${match.toLowerCase()}`
29
+ );
30
+
31
+ export const pascal2constantcase = (text = '') =>
32
+ text
33
+ .replace(/[A-Z]/g, (match, offset) =>
34
+ offset === 0 ? match : `_${match}`
35
+ )
36
+ .toUpperCase();
9
37
  export const pascal2camelcase = (text = '') => text.charAt(0).toLowerCase() + text.slice(1);
10
38
 
11
- export const snake2camelcase = (text = '') => text.replace(/(_\w)/g, match => match[1].toUpperCase());
12
- export const snake2hyphencase = (text = '') => text.replace(/_/g, "-");
13
- export const snake2pascalcase = (text = '') => text.split('_').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join('');
39
+ export const snake2camelcase = (text = '') => text.replace(/_([a-zA-Z])/g, (_, char) => char.toUpperCase());
40
+ export const snake2hyphencase = (text = '') => text.replace(/_/g, '-');
41
+ export const snake2pascalcase = (text = '') => text
42
+ .split('_')
43
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
44
+ .join('');
14
45
  export const snake2constantcase = (text = '') => text.toUpperCase();
15
46
 
16
- export const hyphen2camelcase = (text = '') => text.replace(/-([a-z])/g, match => match[1].toUpperCase());
47
+ export const hyphen2camelcase = (text = '') => text.replace(/-([a-zA-Z])/g, (_, char) => char.toUpperCase());
17
48
  export const hyphen2snakecase = (text = '') => text.replace(/-/g, '_');
18
- export const hyphen2pascalcase = (text = '') => text.split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join('');
49
+ export const hyphen2pascalcase = (text = '') => text
50
+ .split('-')
51
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
52
+ .join('');
19
53
  export const hyphen2constantcase = (text = '') => text.replace(/-/g, '_').toUpperCase();
20
54
 
21
- export const constant2camelcase = (text = '') => text.toLowerCase().replace(/_([a-z])/g, match => match[1].toUpperCase());
55
+ export const constant2camelcase = (text = '') => text.toLowerCase().replace(/_([a-z])/g, (_, char) => char.toUpperCase());
22
56
  export const constant2snakecase = (text = '') => text.toLowerCase();
23
- export const constant2pascalcase = (text = '') => text.toLowerCase().split('_').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join('');
57
+ export const constant2pascalcase = (text = '') => text
58
+ .toLowerCase()
59
+ .split('_')
60
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
61
+ .join('');
24
62
  export const constant2hyphencase = (text = '') => text.toLowerCase().replace(/_/g, '-');