vaderjs 1.3.3-alpha-19 → 1.3.3-alpha-21

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,7 +1,7 @@
1
1
 
2
2
  window.params = {};
3
3
  window.Vader = {
4
- version: "1.3.2",
4
+ version: "1.3.3",
5
5
  };
6
6
 
7
7
  let errors = {
@@ -43,16 +43,13 @@ let hasran = [];
43
43
  let states = {};
44
44
  let mounts = [];
45
45
  export const strictMount = (key, callback) => {
46
- let interval = setInterval(() => {
47
- if(mounts.find(mount => mount.key === key)
48
- && !hasran.includes(callback.toString())
49
- ){
46
+ let timer = setInterval(() => {
47
+ if (document.querySelector('[key="' + key + '"]')) {
48
+ console.log('mounted')
49
+ clearInterval(timer);
50
50
  callback();
51
- clearInterval(interval)
52
-
53
- hasran.push(callback.toString());
54
- }
55
- },0);
51
+ }
52
+ }, 120);
56
53
  };
57
54
 
58
55
  window.delegate = (event) => {
@@ -167,9 +164,93 @@ export class Component {
167
164
  window.listeners = [];
168
165
  this.functionMap = new Map();
169
166
  this.freeMemoryFromFunctions();
167
+ this.checkIFMounted();
170
168
  this.memoizes = []
169
+
170
+ this.vdom = []
171
+
171
172
  this.children = []
173
+ let dom = new DOMParser().parseFromString(this.render(), 'text/html').body.firstChild;
174
+ dom.querySelectorAll('*').forEach((el) => {
175
+ let obj = {
176
+ el: el,
177
+ tag: el.tagName,
178
+ html: el.innerHTML,
179
+ content: el.textContent,
180
+ value: el.value,
181
+ attributes: el.attributes,
182
+ children: el.childNodes,
183
+ }
184
+ this.vdom.push(obj)
185
+ });
186
+
187
+ /**
188
+ * Parent of the current component.
189
+ * @type {Component}
190
+ */
191
+ this.parentNode = {}
192
+
193
+ /**
194
+ * Request object.
195
+ */
196
+ this.request = {
197
+ /**
198
+ * @type {string}
199
+ * @description The headers for the current route
200
+ */
201
+ headers:{},
202
+ /**
203
+ * @type {string}
204
+ * @description The method for the current route
205
+ */
206
+ method: "GET",
207
+ /**
208
+ * @type {string}
209
+ * @description params for the given route /:id/:name etc
210
+ */
211
+ params: {},
212
+ /**
213
+ * @type {string}
214
+ * @description path: current route path
215
+ */
216
+ path: "",
217
+ /**
218
+ * @type {string}
219
+ * @description query: query object for the current route ?name=hello -> {name: 'hello'}
220
+ */
221
+ query: {},
222
+ },
223
+ /**
224
+ * @type {string}
225
+ * @description The response object for the current route
226
+ */
227
+ this.response = {
228
+ /**
229
+ * @method json
230
+ * @description This method allows you to send json data to the client
231
+ * @param {*} data
232
+ */
233
+ json: (data) => {},
234
+ /**
235
+ * @method send
236
+ * @description This method allows you to send text data to the client
237
+ * @param {*} data
238
+ */
239
+ send: (data) => {},
240
+ /**
241
+ * @method redirect
242
+ * @description This method allows you to redirect the client to a new route
243
+ * @param {*} path
244
+ */
245
+ redirect: (path) => {},
246
+ /**
247
+ * @method render
248
+ * @description render a new component to the client
249
+ * @param {*} Component
250
+ */
251
+ render: async (Component) => {},
172
252
  }
253
+ }
173
254
 
174
255
  createComponent(/**@type {Component}**/component, props, children) {
175
256
 
@@ -179,26 +260,16 @@ export class Component {
179
260
  if(!props.key){
180
261
  throw new Error('new components must have a key')
181
262
  }
182
- let comp = new component();
183
- Object.keys(props).forEach((key) => {
184
- // some props are this.bind inside of "" so we need to handle that
185
- let newFunc = props[key].match(/this.bind\((.*)\)/gs);
186
- if (newFunc) {
187
- newFunc = newFunc[0].replace(/this.bind\((.*)\)/gs, "$1");
188
- newFunc = newFunc.split('`')[1]
189
- props[key] = this.bind(newFunc, { jsx: true, params: props[key], ref: props.ref });
190
- return
191
- }
192
-
193
-
194
-
195
- props[key] = props[key].toString().replace('"', '').replace("'", '').replace('${', '').replace('}', '')
196
- });
263
+ let comp = new component(props);
264
+ if(this.components[props.key]){
265
+ return this.components[props.key]
266
+ }
197
267
  comp['props'] = props;
198
268
  comp.children = children;
199
269
  comp.props.children = children.join('')
200
270
  comp.parentNode = this;
201
271
  comp.key = props.key || null;
272
+
202
273
  this.components[props.key] = comp
203
274
  this.children.push(comp)
204
275
  return this.components[props.key]
@@ -215,6 +286,7 @@ export class Component {
215
286
  }
216
287
 
217
288
  let comp = this.components[component.key];
289
+
218
290
  let h = comp.render()
219
291
 
220
292
  if(h && h.split('>,').length > 1){
@@ -240,28 +312,75 @@ export class Component {
240
312
  * Hydrates the component by updating the HTML content if it has changed.
241
313
  * @private
242
314
  */
243
- hydrate() {
244
- if (this.key) {
245
-
246
- const el = document.querySelector(`[key="${this.key}"]`);
247
315
 
248
-
249
- if (el) {
250
-
251
-
252
- // Render the new HTML content
253
- const newHtml = this.render();
254
- // Compare the new HTML with the cached content
255
- if (newHtml !== this.currentHtml) {
256
- // Update the HTML only if it has changed
257
- el.innerHTML = newHtml;
258
-
259
- // Update the cached HTML content
260
- this.currentHtml = newHtml;
316
+ domDifference(oldDom, newDom) {
317
+ let diff = [];
318
+
319
+ for (let i = 0; i < oldDom.length; i++) {
320
+ let oldEl = oldDom[i];
321
+ let newEl = newDom[i];
322
+
323
+ if (oldEl && newEl && !oldEl.isEqualNode(newEl)) {
324
+ diff.push({
325
+ type: 'replace',
326
+ old: oldEl,
327
+ new: newEl.cloneNode(true),
328
+ });
329
+ }
330
+ }
331
+
332
+ return diff;
333
+ }
334
+
335
+ updateChangedElements(diff) {
336
+ diff.forEach((change) => {
337
+ switch (change.type) {
338
+ case 'replace':
339
+ change.old.parentNode.replaceChild(change.new, change.old);
340
+ break;
341
+ case 'remove':
342
+ change.old.remove();
343
+ break;
344
+ case 'add':
345
+ change.old.appendChild(change.new.cloneNode(true));
346
+ break;
347
+ default:
348
+ break;
349
+ }
350
+ });
351
+ }
352
+
353
+ hydrate(hook) {
354
+ if (this.key) {
355
+ if (hook) {
356
+ let newDom = new DOMParser().parseFromString(this.render(), 'text/html').body.firstChild;
357
+
358
+ let oldElements = document.body.querySelectorAll(`[ref="${hook}"]`);
359
+ let newElements = newDom.querySelectorAll(`[ref="${hook}"]`);
360
+ let diff = this.domDifference(oldElements, newElements);
361
+ this.updateChangedElements(diff);
362
+ } else {
363
+ const targetElement = document.querySelector(`[key="${this.key}"]`);
364
+ if (targetElement) {
365
+ targetElement.innerHTML = this.render();
366
+ } else {
367
+ console.error('Target element not found.');
261
368
  }
262
369
  }
263
370
  }
264
371
  }
372
+
373
+
374
+
375
+ patch(oldElements, newElements) {
376
+ const diff = this.domDifference(oldElements, newElements);
377
+
378
+ this.updateChangedElements(diff);
379
+ }
380
+
381
+
382
+
383
+
265
384
 
266
385
  /**
267
386
  * Handles an object by parsing it as JSON and evaluating it.
@@ -279,7 +398,7 @@ export class Component {
279
398
  }
280
399
 
281
400
  /**
282
- * Frees memory from functions that have not been used for a certain period of time.
401
+ * Frees memory from functions that have not been used for a certain period of time.c
283
402
  * @private
284
403
  */
285
404
  freeMemoryFromFunctions() {
@@ -299,23 +418,53 @@ export class Component {
299
418
  * @param {string} ref - The reference.
300
419
  * @returns {string} - A valid inline JS function call.
301
420
  */
302
- bind(funcData, d) {
421
+ bind(funcData,jsx,ref, paramNames, ...params) {
422
+
303
423
 
304
424
  const name = `func_${crypto ? crypto.getRandomValues(new Uint32Array(1))[0] : Math.random()}`;
305
425
 
306
- var dynamicFunction = (params) => {
307
- let func = new Function(`return (async () => {
308
- ${funcData}
309
- })()`);
310
- func = func.bind(this);
311
- func(params);
426
+ var dynamicFunction = async (...params) => {
427
+
428
+ // Replace double commas with a single comma
429
+
430
+
431
+ // Turn params into a destructured object
432
+ let paramObject = {};
433
+ params = params[0]
434
+
435
+ paramNames = paramNames.replace(/,,/g, ',');
436
+ let newparamnames = paramNames.replaceAll(',,', ',')
437
+ params.forEach((param, index) => {
438
+ if(param && Object.keys(param).includes('detail')){
439
+ param = param['detail']['target']['event']
440
+ params[index] = param
441
+ }
442
+ });
443
+ // Remove trailing commas
444
+ paramNames.endsWith(',') ? paramNames = paramNames.slice(0, -1) : null;
445
+ console.log(paramNames)
446
+
447
+ params.forEach((param, index) => {
448
+ paramObject[newparamnames.split(',')[index]] = param;
449
+ });
450
+
451
+ paramNames = paramNames.replace(',,', ',');
452
+ let func = new Function(`${paramNames}`, `
453
+ return (async (${paramNames}) => {
454
+ ${funcData}
455
+ })(${Object.keys(paramObject).join(',')})
456
+ `);
457
+
458
+ // Bind and execute the function with the provided parameters
459
+ await func.bind(this)(...Object.values(paramObject));
312
460
  };
461
+
313
462
 
314
463
  dynamicFunction = dynamicFunction.bind(this);
315
464
  if (!this.functionMap.has(name)) {
316
465
  document.addEventListener(`call_${name}`, (e) => {
317
466
 
318
- dynamicFunction();
467
+ dynamicFunction(params);
319
468
  this.functionMap.set(e.detail.name, {
320
469
  lastUsed: Date.now(),
321
470
  });
@@ -335,15 +484,17 @@ export class Component {
335
484
  };
336
485
 
337
486
  // Return a valid inline js function call
338
- return d.jsx ? dynamicFunction : `
487
+ return jsx ? dynamicFunction : `
339
488
  ((event) => {
340
- event.target.setAttribute('data-ref', '${d.ref}');
489
+ event.target.setAttribute('data-ref', '${ref}');
341
490
  let reference = event.target.getAttribute('data-ref');
342
491
  event.target.eventData = event;
492
+
343
493
  let domquery = queryRef(reference);
344
- domquery.eventData = event;
345
- domquery.eventData.detail.target = domquery;
346
- call('${name}', {event:domquery.eventData}, '${d.params}')
494
+
495
+ domquery.eventData = event;
496
+ domquery.eventData.target = domquery;
497
+ call('${name}', {event:domquery.eventData}, '${paramNames}')
347
498
  })(event)
348
499
  `;
349
500
  }
@@ -412,11 +563,14 @@ export class Component {
412
563
  if (!this.state[key]) {
413
564
  this.state[key] = initialState;
414
565
  }
415
- const getValue = () => this.state[key];
416
- const set = (newValue) => {
566
+ let updatedValue = () => this.state[key];
567
+ const getValue = updatedValue()
568
+ const set = (newValue, hook) => {
417
569
  this.state[key] = newValue;
418
- this.hydrate();
570
+ this.hydrate(hook);
419
571
  };
572
+ this[`set${key}`] = set;
573
+ this[`get${key}`] = getValue;
420
574
  return [getValue, set];
421
575
  }
422
576
 
@@ -429,9 +583,11 @@ export class Component {
429
583
  this.state[key] = newValue;
430
584
  this.hydrate();
431
585
  };
586
+
587
+
432
588
  return {
433
- bind: key,
434
- current: () => document.querySelector(`[ref="${key}"]`) || this.state[key],
589
+ bind: key + this.key,
590
+ current: document.querySelector(`[ref="${key + this.key}"]`) || initialState
435
591
  }
436
592
  }
437
593
 
@@ -455,7 +611,7 @@ export class Component {
455
611
  * @private
456
612
  */
457
613
  checkIFMounted() {
458
- if (this.mounted) return;
614
+ if (this.mounted || !this.key) return;
459
615
  let timer = setInterval(() => {
460
616
  if (document.querySelector('[key="' + this.key + '"]')) {
461
617
  clearInterval(timer);
@@ -533,6 +689,7 @@ window.require = require;
533
689
  * @description Allows you to use state to dynamically update your component
534
690
  */
535
691
  export const useState = (initialState) => {
692
+ let key = ''
536
693
  let value = initialState;
537
694
  if (key && !states[key]) {
538
695
  this.states[key] = initialState;
@@ -540,6 +697,16 @@ export const useState = (initialState) => {
540
697
  return [value, (newValue) => {}];
541
698
  };
542
699
 
700
+ /**
701
+ * @method useReducer
702
+ * @param {*} initialState
703
+ * @param {*} reducer
704
+ * @returns {Array} [value, set]
705
+ */
706
+ export const useReducer = (/**@type {*}**/initialState, /**@type {function}**/reducer) => {
707
+ return [initialState, (newValue) => {}];
708
+ };
709
+
543
710
  const constants = {};
544
711
  let constantCounter = 0;
545
712
 
@@ -550,13 +717,27 @@ export const constant = (value) => {
550
717
  }
551
718
  return constants[key];
552
719
  };
720
+ /**
721
+ * @method useRef
722
+ * @description Allows you to use a reference to a DOM element
723
+ * @param {*} initialState
724
+ * @returns
725
+ */
553
726
 
727
+ export const useRef = (initialState) => {
728
+ return {
729
+ current: initialState,
730
+ bind: '',
731
+ };
732
+ };
554
733
  export default {
555
734
  Component,
556
735
  require,
557
736
  invoke,
558
737
  mem,
559
738
  constant,
739
+ useRef,
740
+ useReducer,
560
741
  useState,
561
742
  strictMount,
562
743
  stylis,
package/logo.png CHANGED
File without changes
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "vaderjs",
3
3
  "description": "A Reactive library aimed to helping you build reactive applications inspired by react.js",
4
4
  "module": "vader.js",
5
- "version": "1.3.3-alpha-19",
5
+ "version": "1.3.3-alpha-21",
6
6
  "bin": {
7
7
  "vader": "./vader.js"
8
8
  },
File without changes
package/runtime/router.js CHANGED
@@ -198,8 +198,9 @@ class VaderRouter{
198
198
  });
199
199
  }
200
200
  },
201
- redirect: (path) => {
202
- window.location.hash = path;
201
+ redirect: (path) => {
202
+ !path.startsWith('/') ? path = `/${path}` : null;
203
+ window.location.hash = `#${path}`;
203
204
  },
204
205
  render: async (/**@type {Component} */ Component, req, res) => {
205
206