vaderjs 1.3.3-alpha-41 → 1.3.3-alpha-43

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/client/index.js CHANGED
@@ -1,153 +1,29 @@
1
-
2
- window.params = {};
3
1
  window.Vader = {
4
- version: "1.3.3",
2
+ version: "1.3.3",
5
3
  };
6
4
 
7
5
  let errors = {
8
6
  "SyntaxError: Unexpected token '<'": "You forgot to enclose tags in a fragment <></>",
9
7
  }
10
-
11
- const path = {
12
- basename: (path) => {
13
- return path.split("/").pop();
14
- },
15
-
16
- }
17
-
18
- window.queryRef = (ref) => {
19
- return document.querySelector(`[data-ref="${ref}"]`)
20
- }
21
- window.reinvoke = (eventtype, element) => {
22
- const eventListener = (e) => {
23
- return e
24
- };
25
-
26
- // Check if the event listener has not been added before adding it
27
- if (!element._eventListenerAdded) {
28
- element.addEventListener(eventtype, eventListener);
29
-
30
- // Set the flag to indicate that the event listener has been added
31
- element._eventListenerAdded = true;
32
-
33
- // Trigger the event without overwriting existing data or listeners
34
- element.dispatchEvent(new Event(eventtype));
35
- }
36
- };
37
-
38
-
39
8
 
40
-
41
- let invokes = []
42
- let hasran = [];
43
- let states = {};
44
9
  let mounts = [];
10
+ /**
11
+ * @method strictMount
12
+ * @description This method allows you to await until the component is mounted before running a callback
13
+ * @param {*} key
14
+ * @param {*} callback
15
+ */
45
16
  export const strictMount = (key, callback) => {
46
17
  let timer = setInterval(() => {
47
- if (document.querySelector('[key="' + key + '"]')) {
48
- console.log('mounted')
18
+ if (mounts.find((m) => m.key === key)) {
49
19
  clearInterval(timer);
50
20
  callback();
51
21
  }
52
22
  }, 120);
53
23
  };
54
24
 
55
- window.delegate = (event) => {
56
- return event.detail.target
57
- }
58
-
59
- let components = {};
60
-
61
- let style = document.createElement("style");
62
- document.head.appendChild(style);
63
-
64
- const parseStyles = async (styles, className = '') => {
65
- let css = await fetch(styles).then((res) => res.text());
66
- let classes = css.split("}");
67
- let parsedClasses = {};
68
- classes.forEach((cls) => {
69
-
70
- let name = cls.split(".")[1];
71
- let value = cls.split("{")[1]
72
- let keys = value.split(";");
73
- let newKeys = [];
74
- keys.forEach((key) => {
75
- if (key.includes(":")) {
76
- let newKey = key.split(":")[0].trim();
77
- let newValue = key.split(":")[1].trim();
78
- newKeys.push(`${newKey}: "${newValue}"`);
79
- }
80
- });
81
- value = `{${newKeys.join(",")}}`;
82
-
83
-
84
- parsedClasses[name] = JSON.stringify(value);
85
- });
86
- return parsedClasses;
87
- };
88
25
 
89
26
 
90
- export const stylis = {
91
- /**
92
- * @method create
93
- * @param {*} styles
94
- * @returns {Object} classes
95
- * @description This method allows you to create css classes from an object
96
- */
97
- create: async (/**@type {string} */ styles) => {
98
-
99
- return await parseStyles(styles);
100
- },
101
- };
102
-
103
- /**
104
- * @method mem
105
- * @param {Component} component
106
- * @returns {Component} Stateless Component
107
- * @description This method allows you to memoize a component - this means it will be intialized only once and can be reused multiple times baased on a static key
108
- */
109
- export const mem = (/**@type {Component}**/ component) => {
110
- // ensure component is instance of Component
111
- switch (true) {
112
- case !(component instanceof Component):
113
- throw new Error("component must be an instance of Component");
114
- case !component.key:
115
- throw new Error("component must have a static key");
116
- // check if key was randomly generated
117
- }
118
- let key = component.key;
119
- if (!components[key]) {
120
- components[key] = component;
121
- }
122
-
123
- return components[key];
124
- };
125
-
126
- /**
127
- * @method invoke
128
- * @description This method allows you to invoke a function from its id
129
- * @param {*} name
130
- * @param {*} params
131
- * @returns
132
- * @example
133
- * invoke(this.functions['test'], 'hello') // this will invoke the function test with the params hello
134
- */
135
-
136
- let functions = {};
137
-
138
- export const invoke = (func, params) => {
139
- let name = func.name;
140
-
141
- window[name] = function (params) {
142
- return func(params);
143
- }
144
- window[name] = window[name].bind(this);
145
-
146
-
147
- return `${name}(${params})`;
148
-
149
- };
150
-
151
27
  /**
152
28
  * Represents a component in the Vader framework.
153
29
  */
@@ -159,55 +35,50 @@ export class Component {
159
35
  this.state = {};
160
36
  this.key = null;
161
37
  this.components = {};
162
- this.mounted = false;
163
- this.currenthtml = null;
164
- window.listeners = [];
165
- this.functionMap = new Map();
166
- this.freeMemoryFromFunctions();
38
+ this.mounted = false;
167
39
  this.checkIFMounted();
168
40
  this.memoizes = []
169
-
170
- this.vdom = []
171
-
41
+ this.functions = []
42
+
172
43
  this.children = []
173
-
174
-
44
+
45
+
175
46
  /**
176
47
  * Parent of the current component.
177
48
  * @type {Component}
178
49
  */
179
- this.parentNode = {}
180
-
50
+ this.parentNode = {}
51
+
52
+ /**
53
+ * Request object.
54
+ */
55
+ this.request = {
181
56
  /**
182
- * Request object.
57
+ * @type {string}
58
+ * @description The headers for the current route
183
59
  */
184
- this.request = {
185
- /**
186
- * @type {string}
187
- * @description The headers for the current route
188
- */
189
- headers:{},
190
- /**
191
- * @type {string}
192
- * @description The method for the current route
193
- */
194
- method: "GET",
195
- /**
196
- * @type {string}
197
- * @description params for the given route /:id/:name etc
198
- */
199
- params: {},
200
- /**
201
- * @type {string}
202
- * @description path: current route path
203
- */
204
- path: "",
205
- /**
206
- * @type {string}
207
- * @description query: query object for the current route ?name=hello -> {name: 'hello'}
208
- */
209
- query: {},
210
- },
60
+ headers: {},
61
+ /**
62
+ * @type {string}
63
+ * @description The method for the current route
64
+ */
65
+ method: "GET",
66
+ /**
67
+ * @type {string}
68
+ * @description params for the given route /:id/:name etc
69
+ */
70
+ params: {},
71
+ /**
72
+ * @type {string}
73
+ * @description path: current route path
74
+ */
75
+ path: "",
76
+ /**
77
+ * @type {string}
78
+ * @description query: query object for the current route ?name=hello -> {name: 'hello'}
79
+ */
80
+ query: {},
81
+ },
211
82
  /**
212
83
  * @type {string}
213
84
  * @description The response object for the current route
@@ -218,83 +89,123 @@ export class Component {
218
89
  * @description This method allows you to send json data to the client
219
90
  * @param {*} data
220
91
  */
221
- json: (data) => {},
92
+ json: (data) => { },
222
93
  /**
223
94
  * @method send
224
95
  * @description This method allows you to send text data to the client
225
96
  * @param {*} data
226
97
  */
227
- send: (data) => {},
98
+ send: (data) => { },
228
99
  /**
229
100
  * @method redirect
230
101
  * @description This method allows you to redirect the client to a new route
231
102
  * @param {*} path
232
103
  */
233
- redirect: (path) => {},
104
+ redirect: (path) => { },
234
105
  /**
235
106
  * @method render
236
107
  * @description render a new component to the client
237
108
  * @param {*} Component
238
109
  */
239
- render: async (Component) => {},
110
+ render: async (Component) => { },
111
+ /**
112
+ * @method log
113
+ * @description This method is used to log the request and response
114
+ * @param {String} type
115
+ */
116
+ log: (type) => { },
117
+ /**
118
+ * @method setQuery
119
+ * @description This method is used to set the query object for the current route
120
+ */
121
+ setQuery: (query) => { },
122
+
123
+ }
124
+ /**
125
+ * @method router
126
+ * @description use router methods directly from the parent component
127
+ */
128
+
129
+ this.router = {
130
+ /**
131
+ * @method use
132
+ * @description add a middleware to the current route
133
+ * @param {Function} middleware
134
+ * @returns {void}
135
+ */
136
+ use: (/**@type {Function} */ middleware) => { },
137
+ }
240
138
  }
241
- }
242
139
 
243
140
  createComponent(/**@type {Component}**/component, props, children) {
244
-
141
+
245
142
  if (!component) {
246
143
  throw new Error("Component must be defined");
247
144
  }
248
- if(!props.key){
145
+ if (!props.key) {
249
146
  throw new Error('new components must have a key')
250
- }
147
+ }
251
148
  let comp = new component(props);
252
-
149
+
253
150
  comp['props'] = props;
254
- comp.children = children;
151
+ comp.children = children;
255
152
  comp.props.children = children.join('')
256
- comp.parentNode = this;
153
+ comp.parentNode = this;
257
154
  comp.request = this.request;
258
155
  comp.response = this.response;
259
156
  comp.key = props.key || null;
260
-
261
- this.components[props.key] = comp
157
+
158
+ if (!this.components[props.key]) {
159
+ this.components[props.key] = comp;
160
+ }
262
161
  this.children.push(comp)
263
- return this.components[props.key]
162
+ return this.components[props.key]
163
+ }
164
+ reset() {
165
+ console.log('reset')
166
+ Object.keys(this.components).forEach((key) => {
167
+ this.components[key].onUnmount()
168
+ delete this.components[key]
169
+ })
170
+ this.state = {}
171
+ this.children = []
264
172
  }
265
- memoize(/**@type {Component}**/component){
266
- if(!component.key){
173
+ memoize(/**@type {Component}**/component) {
174
+ if (!component.key) {
267
175
  throw new Error('Component must have a static key')
268
176
  }
269
- switch(true){
177
+ switch (true) {
270
178
  case !this.memoizes.includes(component.key):
271
179
  this.memoizes.push(component.key)
272
180
  this.components[component.key] = component;
273
181
  break;
274
182
  }
275
-
183
+
276
184
  let comp = this.components[component.key];
277
- console.log(component.props)
185
+ comp.bindMount();
186
+ comp.parentNode = this;
278
187
  comp.props = component.props;
279
- let h = comp.render()
280
-
281
- if(h && h.split('>,').length > 1){
188
+ comp.request = this.request;
189
+ comp.response = this.response;
190
+ let h = comp.render()
191
+
192
+ if (h && h.split('>,').length > 1) {
282
193
  h = h.replaceAll('>,', '>')
283
194
  }
284
195
 
285
196
  return `<div key="${component.key}">${h}</div>`
286
197
  }
287
- parseStyle(styles){
198
+ parseStyle(styles) {
288
199
  let css = ''
289
- Object.keys(styles).forEach((key) => {
200
+ Object.keys(styles).forEach((key) => {
290
201
  let value = styles[key]
291
- key = key.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase()
292
- css += `${key}:${value};`
202
+ key = key.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase()
203
+ css += `${key}:${value};`
293
204
  })
294
205
  return css
295
206
  }
296
- bindMount(){
297
- mounts.push(this)
207
+ bindMount() {
208
+ mounts.push(this)
298
209
  }
299
210
 
300
211
  /**
@@ -302,13 +213,13 @@ export class Component {
302
213
  * @private
303
214
  */
304
215
 
305
- domDifference(oldDom, newDom) {
216
+ domDifference(oldDom, newDom) {
306
217
  let diff = [];
307
-
218
+
308
219
  for (let i = 0; i < oldDom.length; i++) {
309
220
  let oldEl = oldDom[i];
310
221
  let newEl = newDom[i];
311
-
222
+
312
223
  if (oldEl && newEl && !oldEl.isEqualNode(newEl)) {
313
224
  diff.push({
314
225
  type: 'replace',
@@ -317,11 +228,11 @@ export class Component {
317
228
  });
318
229
  }
319
230
  }
320
-
231
+
321
232
  return diff;
322
233
  }
323
-
324
- updateChangedElements(diff) {
234
+
235
+ updateChangedElements(diff) {
325
236
  diff.forEach((change) => {
326
237
  switch (change.type) {
327
238
  case 'replace':
@@ -338,12 +249,12 @@ export class Component {
338
249
  }
339
250
  });
340
251
  }
341
-
342
- hydrate(hook) {
252
+
253
+ hydrate(hook) {
343
254
  if (this.key) {
344
255
  if (hook) {
345
256
  let newDom = new DOMParser().parseFromString(this.render(), 'text/html').body.firstChild;
346
-
257
+
347
258
  let oldElements = document.body.querySelectorAll(`[ref="${hook}"]`);
348
259
  let newElements = newDom.querySelectorAll(`[ref="${hook}"]`);
349
260
  let diff = this.domDifference(oldElements, newElements);
@@ -351,25 +262,25 @@ export class Component {
351
262
  } else {
352
263
  const targetElement = document.querySelector(`[key="${this.key}"]`);
353
264
  if (targetElement) {
354
- targetElement.innerHTML = this.render();
265
+ targetElement.outerHTML = this.render();
355
266
  } else {
356
267
  console.error('Target element not found.');
357
268
  }
358
269
  }
359
270
  }
360
271
  }
361
-
362
-
363
-
272
+
273
+
274
+
364
275
  patch(oldElements, newElements) {
365
276
  const diff = this.domDifference(oldElements, newElements);
366
-
277
+
367
278
  this.updateChangedElements(diff);
368
279
  }
369
-
370
-
371
-
372
-
280
+
281
+
282
+
283
+
373
284
 
374
285
  /**
375
286
  * Handles an object by parsing it as JSON and evaluating it.
@@ -386,19 +297,7 @@ export class Component {
386
297
  return eval(obj);
387
298
  }
388
299
 
389
- /**
390
- * Frees memory from functions that have not been used for a certain period of time.c
391
- * @private
392
- */
393
- freeMemoryFromFunctions() {
394
- setInterval(() => {
395
- for (var [key, value] in this.functionMap) {
396
- if (Date.now() - value.lastUsed > 1000) {
397
- this.functionMap.delete(key);
398
- }
399
- }
400
- }, 1000);
401
- }
300
+
402
301
 
403
302
  /**
404
303
  * Binds a function to the component.
@@ -407,128 +306,65 @@ export class Component {
407
306
  * @param {string} ref - The reference.
408
307
  * @returns {string} - A valid inline JS function call.
409
308
  */
410
- bind(funcData,jsx,ref, paramNames, ...params) {
411
-
412
-
413
- const name = `func_${crypto ? crypto.getRandomValues(new Uint32Array(1))[0] : Math.random()}`;
414
-
415
- var dynamicFunction = async (...params) => {
416
-
417
- // Replace double commas with a single comma
418
-
419
-
420
- // Turn params into a destructured object
421
- let paramObject = {};
422
- params = params[0]
423
-
424
- paramNames = paramNames.replace(/,,/g, ',');
425
- let newparamnames = paramNames.replaceAll(',,', ',')
426
-
427
-
428
- for(var i in params){
429
- paramObject[newparamnames.split(',')[i]] = params[i]
430
- }
431
-
432
-
433
-
434
- paramNames = paramNames.replace(',,', ',');
435
- let func = new Function(`${paramNames}`, `
436
- return (async (${paramNames}) => {
437
- ${funcData}
438
- })(${Object.keys(paramObject).join(',')})
439
- `);
440
- await func.bind(this)(...Object.values(paramObject));
441
-
442
- };
443
-
444
-
445
- dynamicFunction = dynamicFunction.bind(this);
446
- if (!this.functionMap.has(name)) {
447
- document.addEventListener(`call_${name}`, (e) => {
448
-
449
- dynamicFunction(params)
450
- this.functionMap.set(e.detail.name, {
451
- lastUsed: Date.now(),
452
- });
453
- });
454
- }
309
+ bind(funcTion, isTerny, jsx, ref, paramNames, ...params) {
310
+ ref = ref + this.key;
455
311
 
456
- this.functionMap.set(name, {
457
- lastUsed: Date.now(),
458
- });
312
+ let paramObject = {};
459
313
 
460
- window.call = (name, eventdata, params) => {
461
- document.dispatchEvent(
462
- new CustomEvent(`call_${name}`, {
463
- detail: { name: `call_${name}`, target: eventdata },
464
- })
465
- );
466
- };
467
314
 
468
- // Return a valid inline js function call
469
- return jsx ? dynamicFunction : `
470
- ((event) => {
471
- event.target.setAttribute('data-ref', '${ref}');
472
- let reference = event.target.getAttribute('data-ref');
473
- event.target.eventData = event;
474
- event.target.data = event
475
- call('${name}', {event:event.target.data}, '${paramNames}')
476
- })(event)
477
- `;
478
- }
315
+ paramNames = paramNames.replace(/,,/g, ',');
316
+ let newparamnames = paramNames.replaceAll(',,', ',')
479
317
 
480
- /**
481
- * Calls a function with the specified parameters. and dispatches an event.
482
- * @param {string} func - The function name.
483
- * @param {...*} params - The function parameters.
484
- */
485
- callFunction(func, isInlineJsx, ...params) {
486
- if(!isInlineJsx && params[0] && params[0].detail){
487
- let el = params[0].detail.target.event.target
488
- params[0].data = el.value;
489
- params[0] = params[0].detail.target.event
490
- }
491
- func = func.replace(/'/g, '');
492
- document.dispatchEvent(new CustomEvent(func, { detail: { name: func, params: params } }));
493
- }
318
+ for (var i in params) {
319
+ let param = params[i]
320
+ let paramname = newparamnames.split(',')[i]
321
+ paramObject[paramname] = param
322
+ }
494
323
 
495
- /**
496
- * Uses a function with the specified parameters.
497
- * @param {Function} func - The function to use.
498
- * @param {string} params - The function parameters.
499
- * @param {boolean} [isInlineJsx=false] - Indicates if the function is an inline JSX.
500
- * @returns {string} - The function call.
501
- */
502
- useFunction(func, params, isInlineJsx = false) {
503
- const sanitizedFuncName = func.name.trim().replace(/\s+/g, '_');
504
324
 
505
- if (!invokes.includes(`'${sanitizedFuncName}'${this.key}`)) {
506
- invokes.push(`'${sanitizedFuncName}'${this.key}`);
507
- document.addEventListener(`call_${sanitizedFuncName}_${this.key}`, (e) => {
508
- let { name, params } = e.detail;
509
- if (name === `call_${sanitizedFuncName}_${this.key}`) {
510
- let isarray = Array.isArray(params);
511
325
 
512
- func(...(isarray ? params : [params]));
326
+ let ranfunctionanme = Math.random().toString(36).substring(7).slice(0, 5).replace(/[^a-z0-9]+/g, '')
327
+ // no numbers
328
+ ranfunctionanme = ranfunctionanme.replace(/[0-9]/g, '')
329
+ let tfunc = funcTion.toString().replace('async', '').replace('function', `function ${ranfunctionanme}`)
330
+
331
+ paramNames = paramNames.replace(',,', ',');
332
+
333
+ let func = new Function(`${paramNames}`, `
334
+ return (async (${paramNames}) => {
335
+ ${tfunc}
336
+ })(${Object.keys(paramObject).join(',')})
337
+ `);
338
+ func = func.bind(this)
339
+
340
+ if (!this.functions.find((f) => f.ref === ref)) {
341
+ document.addEventListener(`$dispatch_#id=${ref}`, (e) => {
342
+ let { name, event } = e.detail;
343
+ if (name === ref) {
344
+ let params = this.functions.find((f) => f.ref === ref).params
345
+ Object.keys(params).forEach((key) => {
346
+ if (params[key] instanceof CustomEvent) {
347
+ delete params[key]
348
+ }
349
+ params[key] === undefined ? delete params[key] : params[key]
350
+ })
351
+ isTerny ? funcTion(event, ...Object.values(params)) : func(...Object.values(params))
513
352
  }
514
353
  });
515
354
 
516
- func = func.bind(this);
517
355
  }
518
356
 
519
- try {
520
- params = JSON.parse(params);
521
- } catch (error) {
522
- // Handle JSON parsing error if needed
357
+ window.callFunction = (name, event) => {
358
+ document.dispatchEvent(new CustomEvent(`$dispatch_#id=${name}`, { detail: { name: name, params: null, event: event } }));
523
359
  }
360
+ !this.functions.find((f) => f.ref === ref) ? this.functions.push({ ref: ref, params: paramObject }) : !isTerny ? this.functions.find((f) => f.ref === ref).params = paramObject : null
524
361
 
525
- const returnString = isInlineJsx
526
- ? `'call_${sanitizedFuncName}_${this.key}'`
527
- : `document.dispatchEvent(new CustomEvent('call_${sanitizedFuncName}_${this.key}', { detail: { name: 'call_${sanitizedFuncName}_${this.key}', params: ${JSON.stringify(params)} } }))`;
528
362
 
529
- return returnString;
363
+ return jsx ? funcTion : `((event)=>{event.target.ev = event; callFunction('${ref}', event.target.ev)})(event)`;
530
364
  }
531
365
 
366
+
367
+
532
368
  /**
533
369
  * useState hook.
534
370
  *
@@ -537,145 +373,111 @@ export class Component {
537
373
  * @param {T} initialState - The initial state value.
538
374
  * @returns {[() => T, (newValue: T, hook: Function) => void]} - A tuple with getter and setter functions.
539
375
  */
540
- useState(key, initialState) {
541
- if (!this.state[key]) {
542
- this.state[key] = initialState;
543
- }
376
+ useState(key, initialState) {
377
+ if (!this.state[key]) {
378
+ this.state[key] = initialState;
379
+ }
544
380
 
545
- /**
546
- * Get the current state value.
547
- *
548
- * @returns {T} The current state value.
549
- */
550
- let updatedValue = () => this.state[key];
381
+ /**
382
+ * Get the current state value.
383
+ *
384
+ * @returns {T} The current state value.
385
+ */
386
+ let updatedValue = () => this.state[key];
551
387
 
552
- const getValue = updatedValue();
388
+ const getValue = updatedValue();
553
389
 
554
- /**
555
- * Set a new value for the state.
556
- *
557
- * @param {T} newValue - The new value to set.
558
- * @param {Function} hook - The hook to hydrate after setting the value.
559
- */
560
- const set = (newValue, hook) => {
561
- this.state[key] = newValue;
562
- this.hydrate(hook);
563
- };
390
+ /**
391
+ * Set a new value for the state.
392
+ *
393
+ * @param {T} newValue - The new value to set.
394
+ * @param {Function} hook - The hook to hydrate after setting the value.
395
+ */
396
+ const set = (newValue, hook) => {
397
+ this.state[key] = newValue;
398
+ this.hydrate(hook);
399
+ };
564
400
 
565
-
566
401
 
567
- return [this.state[key], set];
568
- }
569
402
 
570
-
403
+ return [getValue, set];
404
+ }
405
+
406
+
571
407
 
572
408
  useRef(key = null, initialState) {
573
409
  if (!this.state[key]) {
574
410
  this.state[key] = initialState;
575
411
  }
576
- const getValue = () => this.state[key];
412
+ const getValue = () => document.querySelector(`[ref="${key + this.key}"]`) || initialState;
577
413
  const set = (newValue) => {
578
414
  this.state[key] = newValue;
579
415
  this.hydrate();
580
416
  };
581
-
582
-
583
- return {
584
- bind: key + this.key,
585
- current: document.querySelector(`[ref="${key + this.key}"]`) || initialState
417
+
418
+
419
+ return {
420
+ bind: key + this.key,
421
+ current: getValue(),
586
422
  }
587
423
  }
588
424
 
589
425
  useReducer(key = null, initialState, func = null) {
590
426
  const getValue = () => this.state[key];
427
+ const value = getValue();
591
428
  const set = (newValue) => {
592
-
593
- this.hydrate();
429
+ const nextState = func ? func(this.state[key], newValue) : newValue;
430
+ this.state[key] = nextState;
594
431
  };
595
- return [getValue, set];
432
+ return [value, set];
596
433
  }
597
434
 
435
+
598
436
  /**
599
437
  * Placeholder for content to be rendered.
600
438
  * @method render
601
439
  */
602
- render() {}
440
+ render() { }
603
441
 
604
442
  /**
605
443
  * Checks if the component is mounted and triggers the onMount method.
606
444
  * @private
607
445
  */
608
446
  checkIFMounted() {
609
- if (this.mounted || !this.key) return;
610
- let timer = setInterval(() => {
611
- if (document.querySelector('[key="' + this.key + '"]')) {
612
- clearInterval(timer);
613
- this.mounted = true;
614
- this.onMount();
615
- }
616
- }, 120);
447
+ let observer = new MutationObserver((mutations) => {
448
+ mutations.forEach((mutation) => {
449
+
450
+ if (mutation.target.querySelector(`[key="${this.key}"]`) && !this.mounted) {
451
+ this.onMount();
452
+ this.mounted = true;
453
+ }
454
+
455
+ if (Array.from(mutation.removedNodes).find((node) => node.attributes && node.attributes.key && node.attributes.key.value === this.key)) {
456
+ this.onUnmount();
457
+ this.reset();
458
+ }
459
+ })
460
+ })
461
+ observer.observe(document.body, {
462
+ childList: true,
463
+ subtree: true,
464
+ });
617
465
  }
618
466
 
619
467
  /**
620
468
  * Method that is called when the component is mounted.
621
469
  * @method onMount
622
470
  */
623
- onMount() {}
471
+ onMount() { }
472
+ /**
473
+ * Method that is called when the component is unmounted.
474
+ * @method onUnmount
475
+ */
476
+ onUnmount() { }
624
477
  }
625
478
 
626
479
 
627
480
 
628
-
629
-
630
- let cache = {};
631
- /**
632
- * @method require
633
- * @description Import CommonJS modules like Node.js for the browser
634
- * @param {string} path
635
- * @param {Boolean} noresolve - used to tell if the path should be automatically handled or manually handled - this is false by default
636
- * @returns
637
- */
638
- export const require = async (path, noresolve = false) => {
639
-
640
- if (cache[path]) {
641
- return cache[path];
642
- }
643
- let file = ''
644
- try {
645
- file = await fetch(path).then((res) => res.text());
646
- } catch (error) {
647
- console.error(error)
648
- }
649
-
650
- file = file + `\n//# sourceURL=${path}\n`;
651
-
652
- let filetype = path.split(".").pop();
653
- switch (true) {
654
- case filetype === "js":
655
- let exports = file.match(/module.exports\s*=\s*{.*}/gs) || file.match(/exports\s*=\s*{.*}/gs);
656
- exports = exports ? exports[0] : null;
657
-
658
- if (exports) {
659
- let keys = exports.split("{")[1].split("}")[0].split(",");
660
- let returnstring = "";
661
- keys.forEach((key) => {
662
- key = key.trim();
663
- returnstring += `${key},`;
664
- });
665
- returnstring = `return {${returnstring}}`;
666
- file = file += returnstring;
667
- file = file.replaceAll(exports, "");
668
- }
669
-
670
- return new Function(`return (async () => { ${file} })()`)();
671
- case filetype === "jsx":
672
- return new Function(`return (async () => { ${file} })()`)()
673
-
674
- }
675
- };
676
-
677
-
678
- window.require = require;
679
481
  /**
680
482
  * useState hook.
681
483
  *
@@ -709,7 +511,7 @@ export const useState = (key, initialState) => {
709
511
  return [states[key], set];
710
512
  };
711
513
 
712
-
514
+
713
515
 
714
516
  /**
715
517
  * @method useReducer
@@ -718,35 +520,26 @@ export const useState = (key, initialState) => {
718
520
  * @returns {Array} [value, set]
719
521
  */
720
522
  export const useReducer = (/**@type {*}**/initialState, /**@type {function}**/reducer) => {
721
- return [initialState, (newValue) => {}];
523
+ return [initialState, (newValue) => { }];
722
524
  };
723
525
 
724
- const constants = {};
725
- let constantCounter = 0;
726
526
 
727
- export const constant = (value) => {
728
- const key = `constant_${constantCounter++}`;
729
- if (!constants[key]) {
730
- constants[key] = value;
731
- }
732
- return constants[key];
733
- };
734
-
735
- /**
736
- * useRef hook.
737
- *
738
- * @param {*} initialState - The initial state value for the ref.
739
- * @returns {{ current: *, bind: string }} - An object containing the current value and a bind string.
740
- */
527
+ /**
528
+ * useRef hook.
529
+ *
530
+ * @param {*} initialState - The initial state value for the ref.
531
+ * @returns {{ current: *, bind: string }} - An object containing the current value and a bind string.
532
+ */
741
533
  export const useRef = (initialState) => {
742
534
  return {
743
535
  /**
744
536
  * @description The current value of the ref.
745
-
537
+ @type {*}
746
538
  */
747
539
  current: initialState,
748
540
  /**
749
541
  * @description A unique string that can be used to bind the ref to an element.
542
+ * @type {HTMLElement|string}
750
543
  */
751
544
  bind: '',
752
545
  };
@@ -754,13 +547,8 @@ export const useRef = (initialState) => {
754
547
 
755
548
  export default {
756
549
  Component,
757
- require,
758
- invoke,
759
- mem,
760
- constant,
761
550
  useRef,
762
551
  useReducer,
763
552
  useState,
764
553
  strictMount,
765
- stylis,
766
554
  }