vaderjs 1.3.3-alpha-19 → 1.3.3-alpha-20

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/README.md CHANGED
@@ -94,9 +94,10 @@ return {default:Home}
94
94
 
95
95
 
96
96
  ### State Management
97
+ Vaderjs uses partial hydration which is much better than react vdom, simply pass the ref key to state and only that element will update - no vdom required!!
97
98
 
98
99
  ```jsx
99
- let {Component, useState} = await import('vaderjs/client')
100
+ let {Component, useState, useRef} = await import('vaderjs/client')
100
101
 
101
102
  class MyApp extends Component{
102
103
  contructor(){
@@ -106,12 +107,16 @@ class MyApp extends Component{
106
107
 
107
108
  render(){
108
109
  let [count, setCount] = useState(0)
109
- function increment(){
110
- setCount(count()+ 1)
111
- }
110
+ let ref = useRef('')
111
+
112
112
  return <>
113
- <p>Count is ${count}</p>
114
- <button onclick={()=>increment()}>Increment</button>
113
+ <p ref={ref.bind}>Count is ${count}</p>
114
+ ${/**
115
+ pass anything used from the toplevel render to the lowerlevel function params to be able to invoke!
116
+ **/}
117
+ <button onclick={(setCount, count, ref)=>{
118
+ setCount(count + 1, ref.bind)
119
+ }}>Increment</button>
115
120
  </>
116
121
 
117
122
  }
@@ -124,6 +129,7 @@ return {default:MyApp}
124
129
  ### Function Binding
125
130
 
126
131
  Vaderjs allows you to bind functions directly to html elements just like react
132
+ there are two ways - top level invokes like below
127
133
 
128
134
  ```javascript
129
135
  // vader uses params[0] as the event target object and other parameters resolve after
@@ -141,8 +147,18 @@ return <>
141
147
  </>
142
148
  ```
143
149
 
144
-
145
-
150
+ and lower level invokes - these operate the same just allow you to pass items from top level to lower level: ex - I have a variable named car and i want the button to log it i can pass it as a parameter to allow it to be added to the buttons function scope
151
+
152
+ ```jsx
153
+ let car = {
154
+ model: 'tesla',
155
+ price: 'toomiuch'
156
+ }
157
+ return <>
158
+ <button onclick={(car)=>{
159
+ console.log(car.model)
160
+ }}>Log</button>
161
+ ```
146
162
 
147
163
 
148
164
 
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,47 @@ 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
+ // Remove trailing commas
438
+ paramNames.endsWith(',') ? paramNames = paramNames.slice(0, -1) : null;
439
+ console.log(paramNames)
440
+
441
+ params.forEach((param, index) => {
442
+ paramObject[newparamnames.split(',')[index]] = param;
443
+ });
444
+
445
+ paramNames = paramNames.replace(',,', ',');
446
+ let func = new Function(`${paramNames}`, `
447
+ return (async (${paramNames}) => {
448
+ ${funcData}
449
+ })(${Object.keys(paramObject).join(',')})
450
+ `);
451
+
452
+ // Bind and execute the function with the provided parameters
453
+ await func.bind(this)(...Object.values(paramObject));
312
454
  };
455
+
313
456
 
314
457
  dynamicFunction = dynamicFunction.bind(this);
315
458
  if (!this.functionMap.has(name)) {
316
459
  document.addEventListener(`call_${name}`, (e) => {
317
460
 
318
- dynamicFunction();
461
+ dynamicFunction(params);
319
462
  this.functionMap.set(e.detail.name, {
320
463
  lastUsed: Date.now(),
321
464
  });
@@ -335,15 +478,17 @@ export class Component {
335
478
  };
336
479
 
337
480
  // Return a valid inline js function call
338
- return d.jsx ? dynamicFunction : `
481
+ return jsx ? dynamicFunction : `
339
482
  ((event) => {
340
- event.target.setAttribute('data-ref', '${d.ref}');
483
+ event.target.setAttribute('data-ref', '${ref}');
341
484
  let reference = event.target.getAttribute('data-ref');
342
485
  event.target.eventData = event;
486
+
343
487
  let domquery = queryRef(reference);
344
- domquery.eventData = event;
345
- domquery.eventData.detail.target = domquery;
346
- call('${name}', {event:domquery.eventData}, '${d.params}')
488
+
489
+ domquery.eventData = event;
490
+ domquery.eventData.target = domquery;
491
+ call('${name}', {event:domquery.eventData}, '${paramNames}')
347
492
  })(event)
348
493
  `;
349
494
  }
@@ -412,11 +557,14 @@ export class Component {
412
557
  if (!this.state[key]) {
413
558
  this.state[key] = initialState;
414
559
  }
415
- const getValue = () => this.state[key];
416
- const set = (newValue) => {
560
+ let updatedValue = () => this.state[key];
561
+ const getValue = updatedValue()
562
+ const set = (newValue, hook) => {
417
563
  this.state[key] = newValue;
418
- this.hydrate();
564
+ this.hydrate(hook);
419
565
  };
566
+ this[`set${key}`] = set;
567
+ this[`get${key}`] = getValue;
420
568
  return [getValue, set];
421
569
  }
422
570
 
@@ -429,9 +577,11 @@ export class Component {
429
577
  this.state[key] = newValue;
430
578
  this.hydrate();
431
579
  };
580
+
581
+
432
582
  return {
433
- bind: key,
434
- current: () => document.querySelector(`[ref="${key}"]`) || this.state[key],
583
+ bind: key + this.key,
584
+ current: document.querySelector(`[ref="${key + this.key}"]`) || initialState
435
585
  }
436
586
  }
437
587
 
@@ -455,7 +605,7 @@ export class Component {
455
605
  * @private
456
606
  */
457
607
  checkIFMounted() {
458
- if (this.mounted) return;
608
+ if (this.mounted || !this.key) return;
459
609
  let timer = setInterval(() => {
460
610
  if (document.querySelector('[key="' + this.key + '"]')) {
461
611
  clearInterval(timer);
@@ -533,6 +683,7 @@ window.require = require;
533
683
  * @description Allows you to use state to dynamically update your component
534
684
  */
535
685
  export const useState = (initialState) => {
686
+ let key = ''
536
687
  let value = initialState;
537
688
  if (key && !states[key]) {
538
689
  this.states[key] = initialState;
@@ -540,6 +691,16 @@ export const useState = (initialState) => {
540
691
  return [value, (newValue) => {}];
541
692
  };
542
693
 
694
+ /**
695
+ * @method useReducer
696
+ * @param {*} initialState
697
+ * @param {*} reducer
698
+ * @returns {Array} [value, set]
699
+ */
700
+ export const useReducer = (/**@type {*}**/initialState, /**@type {function}**/reducer) => {
701
+ return [initialState, (newValue) => {}];
702
+ };
703
+
543
704
  const constants = {};
544
705
  let constantCounter = 0;
545
706
 
@@ -551,12 +712,20 @@ export const constant = (value) => {
551
712
  return constants[key];
552
713
  };
553
714
 
715
+ export const useRef = (initialState) => {
716
+ return {
717
+ current: initialState,
718
+ bind: '',
719
+ };
720
+ };
554
721
  export default {
555
722
  Component,
556
723
  require,
557
724
  invoke,
558
725
  mem,
559
726
  constant,
727
+ useRef,
728
+ useReducer,
560
729
  useState,
561
730
  strictMount,
562
731
  stylis,
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-20",
6
6
  "bin": {
7
7
  "vader": "./vader.js"
8
8
  },
package/runtime/vader.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,13 +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
-
263
+ let comp = new component(props);
264
+ if(this.components[props.key]){
265
+ return this.components[props.key]
266
+ }
184
267
  comp['props'] = props;
185
268
  comp.children = children;
186
269
  comp.props.children = children.join('')
187
270
  comp.parentNode = this;
188
271
  comp.key = props.key || null;
272
+
189
273
  this.components[props.key] = comp
190
274
  this.children.push(comp)
191
275
  return this.components[props.key]
@@ -202,6 +286,7 @@ export class Component {
202
286
  }
203
287
 
204
288
  let comp = this.components[component.key];
289
+
205
290
  let h = comp.render()
206
291
 
207
292
  if(h && h.split('>,').length > 1){
@@ -227,28 +312,75 @@ export class Component {
227
312
  * Hydrates the component by updating the HTML content if it has changed.
228
313
  * @private
229
314
  */
230
- hydrate() {
231
- if (this.key) {
232
-
233
- const el = document.querySelector(`[key="${this.key}"]`);
234
315
 
235
-
236
- if (el) {
237
-
238
-
239
- // Render the new HTML content
240
- const newHtml = this.render();
241
- // Compare the new HTML with the cached content
242
- if (newHtml !== this.currentHtml) {
243
- // Update the HTML only if it has changed
244
- el.innerHTML = newHtml;
245
-
246
- // Update the cached HTML content
247
- 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.');
248
368
  }
249
369
  }
250
370
  }
251
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
+
252
384
 
253
385
  /**
254
386
  * Handles an object by parsing it as JSON and evaluating it.
@@ -266,7 +398,7 @@ export class Component {
266
398
  }
267
399
 
268
400
  /**
269
- * 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
270
402
  * @private
271
403
  */
272
404
  freeMemoryFromFunctions() {
@@ -286,24 +418,47 @@ export class Component {
286
418
  * @param {string} ref - The reference.
287
419
  * @returns {string} - A valid inline JS function call.
288
420
  */
289
- bind(funcData,jsx,ref, params) {
421
+ bind(funcData,jsx,ref, paramNames, ...params) {
422
+
290
423
 
291
- console.log(jsx)
292
424
  const name = `func_${crypto ? crypto.getRandomValues(new Uint32Array(1))[0] : Math.random()}`;
293
425
 
294
- var dynamicFunction = (params) => {
295
- let func = new Function(`return (async () => {
296
- ${funcData}
297
- })()`);
298
- func = func.bind(this);
299
- 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
+ // Remove trailing commas
438
+ paramNames.endsWith(',') ? paramNames = paramNames.slice(0, -1) : null;
439
+ console.log(paramNames)
440
+
441
+ params.forEach((param, index) => {
442
+ paramObject[newparamnames.split(',')[index]] = param;
443
+ });
444
+
445
+ paramNames = paramNames.replace(',,', ',');
446
+ let func = new Function(`${paramNames}`, `
447
+ return (async (${paramNames}) => {
448
+ ${funcData}
449
+ })(${Object.keys(paramObject).join(',')})
450
+ `);
451
+
452
+ // Bind and execute the function with the provided parameters
453
+ await func.bind(this)(...Object.values(paramObject));
300
454
  };
455
+
301
456
 
302
457
  dynamicFunction = dynamicFunction.bind(this);
303
458
  if (!this.functionMap.has(name)) {
304
459
  document.addEventListener(`call_${name}`, (e) => {
305
460
 
306
- dynamicFunction();
461
+ dynamicFunction(params);
307
462
  this.functionMap.set(e.detail.name, {
308
463
  lastUsed: Date.now(),
309
464
  });
@@ -325,13 +480,15 @@ export class Component {
325
480
  // Return a valid inline js function call
326
481
  return jsx ? dynamicFunction : `
327
482
  ((event) => {
328
- event.target.setAttribute('data-ref', '${ref}}');
483
+ event.target.setAttribute('data-ref', '${ref}');
329
484
  let reference = event.target.getAttribute('data-ref');
330
485
  event.target.eventData = event;
486
+
331
487
  let domquery = queryRef(reference);
332
- domquery.eventData = event;
333
- domquery.eventData.detail.target = domquery;
334
- call('${name}', {event:domquery.eventData}, '${params}')
488
+
489
+ domquery.eventData = event;
490
+ domquery.eventData.target = domquery;
491
+ call('${name}', {event:domquery.eventData}, '${paramNames}')
335
492
  })(event)
336
493
  `;
337
494
  }
@@ -400,11 +557,14 @@ export class Component {
400
557
  if (!this.state[key]) {
401
558
  this.state[key] = initialState;
402
559
  }
403
- const getValue = () => this.state[key];
404
- const set = (newValue) => {
560
+ let updatedValue = () => this.state[key];
561
+ const getValue = updatedValue()
562
+ const set = (newValue, hook) => {
405
563
  this.state[key] = newValue;
406
- this.hydrate();
564
+ this.hydrate(hook);
407
565
  };
566
+ this[`set${key}`] = set;
567
+ this[`get${key}`] = getValue;
408
568
  return [getValue, set];
409
569
  }
410
570
 
@@ -417,9 +577,11 @@ export class Component {
417
577
  this.state[key] = newValue;
418
578
  this.hydrate();
419
579
  };
580
+
581
+
420
582
  return {
421
- bind: key,
422
- current: () => document.querySelector(`[ref="${key}"]`) || this.state[key],
583
+ bind: key + this.key,
584
+ current: document.querySelector(`[ref="${key + this.key}"]`) || initialState
423
585
  }
424
586
  }
425
587
 
@@ -443,7 +605,7 @@ export class Component {
443
605
  * @private
444
606
  */
445
607
  checkIFMounted() {
446
- if (this.mounted) return;
608
+ if (this.mounted || !this.key) return;
447
609
  let timer = setInterval(() => {
448
610
  if (document.querySelector('[key="' + this.key + '"]')) {
449
611
  clearInterval(timer);
@@ -521,6 +683,7 @@ window.require = require;
521
683
  * @description Allows you to use state to dynamically update your component
522
684
  */
523
685
  export const useState = (initialState) => {
686
+ let key = ''
524
687
  let value = initialState;
525
688
  if (key && !states[key]) {
526
689
  this.states[key] = initialState;
@@ -528,6 +691,16 @@ export const useState = (initialState) => {
528
691
  return [value, (newValue) => {}];
529
692
  };
530
693
 
694
+ /**
695
+ * @method useReducer
696
+ * @param {*} initialState
697
+ * @param {*} reducer
698
+ * @returns {Array} [value, set]
699
+ */
700
+ export const useReducer = (/**@type {*}**/initialState, /**@type {function}**/reducer) => {
701
+ return [initialState, (newValue) => {}];
702
+ };
703
+
531
704
  const constants = {};
532
705
  let constantCounter = 0;
533
706
 
@@ -539,12 +712,20 @@ export const constant = (value) => {
539
712
  return constants[key];
540
713
  };
541
714
 
715
+ export const useRef = (initialState) => {
716
+ return {
717
+ current: initialState,
718
+ bind: '',
719
+ };
720
+ };
542
721
  export default {
543
722
  Component,
544
723
  require,
545
724
  invoke,
546
725
  mem,
547
726
  constant,
727
+ useRef,
728
+ useReducer,
548
729
  useState,
549
730
  strictMount,
550
731
  stylis,
package/vader.js CHANGED
@@ -39,8 +39,7 @@ function Compiler(func) {
39
39
  )
40
40
  ) {
41
41
  return;
42
- }
43
- let code = string;
42
+ }
44
43
 
45
44
  let name = func.split(" ")[1].split("(")[0].trim();
46
45
 
@@ -159,7 +158,7 @@ function Compiler(func) {
159
158
  let params = hasParams
160
159
  ? line.split("(")[1].split(")")[0].trim()
161
160
  : null;
162
-
161
+
163
162
  if (
164
163
  functionparams.length > 0 &&
165
164
  functionparams.find((p) => p.name == name)
@@ -188,7 +187,7 @@ function Compiler(func) {
188
187
  newvalue = newvalue.replace(
189
188
  hasParams ? `${name}(${params})` : name,
190
189
  `this.callFunction(\${${replacement}}, ${isJSXComponent ? true : false
191
- }, event,${params || null})`
190
+ }, event, \${JSON.stringify(${params || null})})`
192
191
  );
193
192
  }
194
193
  }
@@ -215,14 +214,19 @@ function Compiler(func) {
215
214
 
216
215
 
217
216
  let otherdata = {};
217
+
218
218
  params ? (otherdata["params"] = params) : null;
219
219
  otherdata["jsx"] = isJSXComponent;
220
220
  otherdata["ref"] = ref;
221
221
 
222
222
  newvalue = newvalue.split('\n').map(line => line.trim() ? line.trim() + ';' : line).join('\n');
223
223
 
224
+ // turn params into param1, param2, param3
224
225
 
225
- let newatribute = `${attributeName}="\${this.bind(\`${newvalue}\`, ${isJSXComponent ? true : false}, '${ref}', ${params || null})}"`
226
+
227
+ let paramString = params ? params.split(' ').map(param => param + ',').join('') : "";
228
+
229
+ let newatribute = `${attributeName}="\${this.bind(\`${newvalue}\`, ${isJSXComponent ? true : false}, '${ref}', "${paramString}", ${params || null})}"`
226
230
 
227
231
 
228
232
  attribute[attributeName] = {
@@ -258,7 +262,10 @@ function Compiler(func) {
258
262
  otherdata["ref"] = ref;
259
263
  // since js is all in one line split it
260
264
  newvalue = newvalue.split('\n').map(line => line.trim() ? line.trim() + ';' : line).join('\n');
261
- let newattribute = `${attributeName}="\${this.bind(\`${newvalue}\`, ${isJSXComponent ? true : false}, '${ref}', ${params || null})}"`
265
+ // param1, param2, param3
266
+ let length = params ? params.split(' ').length : 0;
267
+ let paramString = params ? params.split(' ').map(param => param + ',').join('') : "";
268
+ let newattribute = `${attributeName}="\${this.bind(\`${newvalue}\`, ${isJSXComponent ? true : false}, '${ref}', "${paramString}", ${params || null})}"`
262
269
  newattribute = newattribute.replace(/\s+/g, " ")
263
270
  string = string.replace(old, newattribute);
264
271
  }
@@ -295,6 +302,7 @@ function Compiler(func) {
295
302
  let contents = "";
296
303
  let updatedContents = "";
297
304
  outerReturn.forEach((returnStatement) => {
305
+
298
306
  let lines = returnStatement.split("\n");
299
307
 
300
308
  for (let i = 0; i < lines.length; i++) {
@@ -303,7 +311,7 @@ function Compiler(func) {
303
311
  continue;
304
312
  }
305
313
  contents += line + "\n";
306
- }
314
+ }
307
315
 
308
316
  // Remove trailing ']'
309
317
  contents = contents.trim().replace(/\]$/, "");
@@ -321,19 +329,19 @@ function Compiler(func) {
321
329
 
322
330
  let value = attributes[key];
323
331
  let oldvalue = value;
324
- if (value && !value.new) {
325
- if (value && value.includes("{")) {
332
+ if (value && !value.new) {
333
+ if (value && value.includes("={")) {
326
334
  value = value.replace("=", "");
327
335
  value == "undefined" ? (value = '"') : (value = value);
328
336
  key == 'style' ? value = `{this.parseStyle({${value.split('{{')[1].split('}}')[0]}})}` : null
329
337
 
330
338
 
331
339
  value = `="\$${value}",`;
332
- string = string.replaceAll(oldvalue, value);
340
+ string = string.replace(oldvalue, value);
333
341
 
334
- } else if (value && value.includes("`")) {
342
+ } else if (value && value.includes("={`")) {
335
343
  value = value.replace("=", "");
336
-
344
+
337
345
  value = `"\$${value}",`;
338
346
  string = string.replace(oldvalue, value);
339
347
 
@@ -405,16 +413,15 @@ function Compiler(func) {
405
413
  let setKey = line.split("=")[0].split(",")[1].trim().replace("]", "");
406
414
 
407
415
  key = key.replace("[", "").replace(",", "");
408
- let value = line
409
- .split("=")[1]
410
- .split("useState")[1]
411
- .split("(")[1]
412
- .split(")")[0]
413
- .trim();
414
- let newState = `${type} [${key}, ${setKey}] = this.useState('${key}', ${value})
415
- this.${key} = ${key}
416
- this.${setKey} = ${setKey}
416
+ let value = line.split("=")[1].split("useState(")[1]
417
+ let regex = /useState\((.*)\)/gs
418
+ value = value.match(regex) ? value.match(regex)[0].split("useState(")[1].split(")")[0].trim() : value
419
+
420
+
421
+ let newState = `${type} [${key}, ${setKey}] = this.useState('${key}', ${value}
422
+
417
423
  `;
424
+
418
425
 
419
426
  // get setkey calls and replace with this.setKey
420
427
  string.split("\n").forEach((line) => {
@@ -429,18 +436,28 @@ function Compiler(func) {
429
436
  }
430
437
  });
431
438
  string = string.replace(line, newState);
432
- } else if (line.includes("useRef")) {
439
+ } else if (line.includes("useRef") && !line.includes("import")) {
433
440
  line = line.trim();
434
441
  // let ref = useRef(null)
435
442
  let type = line.split(" ")[0];
436
443
  let key = line.split("=")[0].split(" ")[1].trim();
437
- let value = line
438
- .split("=")[1]
439
- .split("useRef")[1]
440
- .split("(")[1]
441
- .split(")")[0]
442
- .trim();
443
- let newState = `${type} ${key} = this.useRef('${key}', ${value})`;
444
+ let value = line.split("=")[1].split("useRef(")[1]
445
+
446
+ let regex = /useState\((.*)\)/gs
447
+ value = value.match(regex) ? value.match(regex)[0].split("useRef(")[1].split(")")[0].trim() : value
448
+ let newState = `${type} ${key} = this.useRef('${key}', ${value}`;
449
+
450
+ string = string.replace(line, newState);
451
+ }else if (line.includes("useReducer") && !line.includes("import")){
452
+ line = line.trim();
453
+ // let ref = useRef(null)
454
+ let type = line.split(" ")[0];
455
+ let key = line.split("=")[0].split(" ")[1].trim();
456
+ let value = line.split("=")[1].split("useReducer(")[1]
457
+
458
+ let regex = /useReducer\((.*)\)/gs
459
+ value = value.match(regex) ? value.match(regex)[0].split("useReducer(")[1].split(")")[0].trim() : value
460
+ let newState = `${type} ${key} = this.useReducer('${key}', ${value}`;
444
461
 
445
462
  string = string.replace(line, newState);
446
463
  }
@@ -475,6 +492,12 @@ function Compiler(func) {
475
492
  return array;
476
493
  };
477
494
 
495
+ // replaceall comments ${/* */} with ''
496
+ string = string.replaceAll(/\$\{\/\*.*\*\/\}/gs, "");
497
+
498
+ string = string.replaceAll('../src', './src')
499
+
500
+
478
501
  // capture <Component />, <Component></Component>, and <Component>content</Component>
479
502
 
480
503
  // Example usage
@@ -495,7 +518,7 @@ function Compiler(func) {
495
518
 
496
519
  let name = component.split("<")[1].split(">")[0].split(" ")[0].replace("/", "");
497
520
  let props = component.split(`<${name}`)[1].split(">")[0].trim()
498
- console.log(props)
521
+
499
522
 
500
523
  let savedname = name;
501
524
  let children = props
@@ -551,6 +574,7 @@ function Compiler(func) {
551
574
  // remove trailing ,
552
575
  .replace(/,\s*$/, "")
553
576
  props = props.replace(/:('[^']*'|"[^"]*")/g, ':$1,');
577
+ props = props.replaceAll(',,', ',')
554
578
 
555
579
 
556
580
 
@@ -724,9 +748,7 @@ async function Build() {
724
748
  });
725
749
 
726
750
  }
727
-
728
751
 
729
- console.log(`Compilation completed`)
730
752
  globalThis.isBuilding = false
731
753
  }
732
754
  import { watch } from "fs";