vaderjs 1.3.3-alpha-4 → 1.3.3-alpha-6
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 +16 -26
- package/package.json +3 -3
- package/runtime/vader.js +552 -0
- package/vader.js +3 -2
package/README.md
CHANGED
|
@@ -14,37 +14,24 @@
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
## Get Started
|
|
17
|
+
## Get Started
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
2. Install vaderjs
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
```sh
|
|
24
|
-
curl -fsSL https://bun.sh/install | bash # for macOS, Linux, and WSL
|
|
21
|
+
```bash
|
|
22
|
+
npm i vaderjs@latest
|
|
25
23
|
```
|
|
26
24
|
|
|
27
|
-
|
|
28
|
-
[How to open folder in wsl](https://code.visualstudio.com/docs/remote/wsl)
|
|
29
|
-
|
|
30
|
-
1. Open a WSL terminal window (using the start menu item or by typing wsl from a command prompt / PowerShell).
|
|
31
|
-
|
|
32
|
-
2. Navigate to a folder you'd like to open in VS Code (including, but not limited to, Windows filesystem mounts like /mnt/c)
|
|
25
|
+
3. Install five server - recommended to watch the index.html file as you edit your code
|
|
33
26
|
|
|
34
|
-
|
|
27
|
+
[Vscode 5 Server](https://marketplace.visualstudio.com/items?itemName=yandeu.five-server)
|
|
35
28
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
2. Installing vaderjs
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
npm i vaderjs
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
3. Create Proper Folders
|
|
29
|
+
4. Create Proper Folders
|
|
45
30
|
|
|
46
31
|
Create a pages folder - which allows you to have nextjs page like routing via buns file based router
|
|
47
32
|
|
|
33
|
+
Tip: Each folder can be deep nested up to 4 levels!
|
|
34
|
+
|
|
48
35
|
```bash
|
|
49
36
|
/pages/index.jsx = /
|
|
50
37
|
/pages/home/[page].jsx = /home/:page
|
|
@@ -62,14 +49,13 @@ public - used for anything
|
|
|
62
49
|
|
|
63
50
|
|
|
64
51
|
|
|
65
|
-
|
|
52
|
+
5. And your done - Run `npx vaderjs` and the compiled output is visible inside of the `/dist/` folder!
|
|
66
53
|
|
|
67
54
|
|
|
68
55
|
## Key Features & Examples
|
|
69
56
|
|
|
70
57
|
### File based routing
|
|
71
|
-
vader's compiler automatically handles routing so you wont need to!
|
|
72
|
-
below is valid paths for parsing per [Buns fileSystem Routing Api](https://bun.sh/docs/api/file-system-router)
|
|
58
|
+
vader's compiler automatically handles routing so you wont need to! - it uses a similar page routing to nextjs
|
|
73
59
|
|
|
74
60
|
```bash
|
|
75
61
|
/pages/index.jsx = /
|
|
@@ -78,7 +64,7 @@ below is valid paths for parsing per [Buns fileSystem Routing Api](https://bun.s
|
|
|
78
64
|
|
|
79
65
|
|
|
80
66
|
```
|
|
81
|
-
|
|
67
|
+
For pages that have [params] you can derive it using this.request
|
|
82
68
|
|
|
83
69
|
|
|
84
70
|
### Simplified Component Creation
|
|
@@ -145,6 +131,10 @@ Vaderjs allows you to bind functions directly to html elements just like react
|
|
|
145
131
|
function click(event, otherparams){
|
|
146
132
|
console.log(event.target, otherparams)
|
|
147
133
|
}
|
|
134
|
+
|
|
135
|
+
const hello = function(event, otherparams){
|
|
136
|
+
|
|
137
|
+
}
|
|
148
138
|
|
|
149
139
|
return <>
|
|
150
140
|
<button onclick={()=>click()}>Click Me</button>
|
package/package.json
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
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-
|
|
5
|
+
"version": "1.3.3-alpha-6",
|
|
6
6
|
"bin": {
|
|
7
7
|
"vader": "./vader.js"
|
|
8
8
|
},
|
|
9
9
|
"type": "module",
|
|
10
|
-
"
|
|
11
|
-
"glob": "
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"glob": "latest"
|
|
12
12
|
}
|
|
13
13
|
}
|
package/runtime/vader.js
ADDED
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
|
|
2
|
+
window.params = {};
|
|
3
|
+
window.Vader = {
|
|
4
|
+
version: "1.3.2",
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
let errors = {
|
|
8
|
+
"SyntaxError: Unexpected token '<'": "You forgot to enclose tags in a fragment <></>",
|
|
9
|
+
}
|
|
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
|
+
|
|
40
|
+
|
|
41
|
+
let invokes = []
|
|
42
|
+
let hasran = [];
|
|
43
|
+
let states = {};
|
|
44
|
+
let mounts = [];
|
|
45
|
+
export const strictMount = (key, callback) => {
|
|
46
|
+
let interval = setInterval(() => {
|
|
47
|
+
if(mounts.find(mount => mount.key === key)
|
|
48
|
+
&& !hasran.includes(callback.toString())
|
|
49
|
+
){
|
|
50
|
+
callback();
|
|
51
|
+
clearInterval(interval)
|
|
52
|
+
|
|
53
|
+
hasran.push(callback.toString());
|
|
54
|
+
}
|
|
55
|
+
},0);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
window.delegate = (event) => {
|
|
59
|
+
return event.detail.target
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let components = {};
|
|
63
|
+
|
|
64
|
+
let style = document.createElement("style");
|
|
65
|
+
document.head.appendChild(style);
|
|
66
|
+
|
|
67
|
+
const parseStyles = async (styles, className = '') => {
|
|
68
|
+
let css = await fetch(styles).then((res) => res.text());
|
|
69
|
+
let classes = css.split("}");
|
|
70
|
+
let parsedClasses = {};
|
|
71
|
+
classes.forEach((cls) => {
|
|
72
|
+
|
|
73
|
+
let name = cls.split(".")[1];
|
|
74
|
+
let value = cls.split("{")[1]
|
|
75
|
+
let keys = value.split(";");
|
|
76
|
+
let newKeys = [];
|
|
77
|
+
keys.forEach((key) => {
|
|
78
|
+
if (key.includes(":")) {
|
|
79
|
+
let newKey = key.split(":")[0].trim();
|
|
80
|
+
let newValue = key.split(":")[1].trim();
|
|
81
|
+
newKeys.push(`${newKey}: "${newValue}"`);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
value = `{${newKeys.join(",")}}`;
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
parsedClasses[name] = JSON.stringify(value);
|
|
88
|
+
});
|
|
89
|
+
return parsedClasses;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
export const stylis = {
|
|
94
|
+
/**
|
|
95
|
+
* @method create
|
|
96
|
+
* @param {*} styles
|
|
97
|
+
* @returns {Object} classes
|
|
98
|
+
* @description This method allows you to create css classes from an object
|
|
99
|
+
*/
|
|
100
|
+
create: async (/**@type {string} */ styles) => {
|
|
101
|
+
|
|
102
|
+
return await parseStyles(styles);
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @method mem
|
|
108
|
+
* @param {Component} component
|
|
109
|
+
* @returns {Component} Stateless Component
|
|
110
|
+
* @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
|
|
111
|
+
*/
|
|
112
|
+
export const mem = (/**@type {Component}**/ component) => {
|
|
113
|
+
// ensure component is instance of Component
|
|
114
|
+
switch (true) {
|
|
115
|
+
case !(component instanceof Component):
|
|
116
|
+
throw new Error("component must be an instance of Component");
|
|
117
|
+
case !component.key:
|
|
118
|
+
throw new Error("component must have a static key");
|
|
119
|
+
// check if key was randomly generated
|
|
120
|
+
}
|
|
121
|
+
let key = component.key;
|
|
122
|
+
if (!components[key]) {
|
|
123
|
+
components[key] = component;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return components[key];
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @method invoke
|
|
131
|
+
* @description This method allows you to invoke a function from its id
|
|
132
|
+
* @param {*} name
|
|
133
|
+
* @param {*} params
|
|
134
|
+
* @returns
|
|
135
|
+
* @example
|
|
136
|
+
* invoke(this.functions['test'], 'hello') // this will invoke the function test with the params hello
|
|
137
|
+
*/
|
|
138
|
+
|
|
139
|
+
let functions = {};
|
|
140
|
+
|
|
141
|
+
export const invoke = (func, params) => {
|
|
142
|
+
let name = func.name;
|
|
143
|
+
|
|
144
|
+
window[name] = function (params) {
|
|
145
|
+
return func(params);
|
|
146
|
+
}
|
|
147
|
+
window[name] = window[name].bind(this);
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
return `${name}(${params})`;
|
|
151
|
+
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Represents a component in the Vader framework.
|
|
156
|
+
*/
|
|
157
|
+
export class Component {
|
|
158
|
+
/**
|
|
159
|
+
* Creates an instance of Component.
|
|
160
|
+
*/
|
|
161
|
+
constructor() {
|
|
162
|
+
this.state = {};
|
|
163
|
+
this.key = null;
|
|
164
|
+
this.components = {};
|
|
165
|
+
this.mounted = false;
|
|
166
|
+
this.checkIFMounted();
|
|
167
|
+
this.currenthtml = null;
|
|
168
|
+
window.listeners = [];
|
|
169
|
+
this.functionMap = new Map();
|
|
170
|
+
this.freeMemoryFromFunctions();
|
|
171
|
+
this.memoizes = []
|
|
172
|
+
this.children = []
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
createComponent(/**@type {Component}**/component, props, children) {
|
|
176
|
+
|
|
177
|
+
if (!component) {
|
|
178
|
+
throw new Error("Component must be defined");
|
|
179
|
+
}
|
|
180
|
+
if(!props.key){
|
|
181
|
+
throw new Error('new components must have a key')
|
|
182
|
+
}
|
|
183
|
+
let comp = new component();
|
|
184
|
+
|
|
185
|
+
comp['props'] = props;
|
|
186
|
+
comp.children = children;
|
|
187
|
+
comp.props.children = children.join('')
|
|
188
|
+
comp.parentNode = this;
|
|
189
|
+
comp.key = props.key || null;
|
|
190
|
+
this.components[props.key] = comp
|
|
191
|
+
this.children.push(comp)
|
|
192
|
+
return this.components[props.key]
|
|
193
|
+
}
|
|
194
|
+
memoize(/**@type {Component}**/component){
|
|
195
|
+
if(!component.key){
|
|
196
|
+
throw new Error('Component must have a static key')
|
|
197
|
+
}
|
|
198
|
+
switch(true){
|
|
199
|
+
case !this.memoizes.includes(component.key):
|
|
200
|
+
this.memoizes.push(component.key)
|
|
201
|
+
this.components[component.key] = component;
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
let comp = this.components[component.key];
|
|
206
|
+
let h = comp.render()
|
|
207
|
+
|
|
208
|
+
if(h && h.split('>,').length > 1){
|
|
209
|
+
h = h.replaceAll('>,', '>')
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return `<div key="${component.key}">${h}</div>`
|
|
213
|
+
}
|
|
214
|
+
parseStyle(styles){
|
|
215
|
+
let css = ''
|
|
216
|
+
Object.keys(styles).forEach((key) => {
|
|
217
|
+
let value = styles[key]
|
|
218
|
+
key = key.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase()
|
|
219
|
+
css += `${key}:${value};`
|
|
220
|
+
})
|
|
221
|
+
return css
|
|
222
|
+
}
|
|
223
|
+
bindMount(){
|
|
224
|
+
mounts.push(this)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Hydrates the component by updating the HTML content if it has changed.
|
|
229
|
+
* @private
|
|
230
|
+
*/
|
|
231
|
+
hydrate() {
|
|
232
|
+
if (this.key) {
|
|
233
|
+
|
|
234
|
+
const el = document.querySelector(`[key="${this.key}"]`);
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
if (el) {
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
// Render the new HTML content
|
|
241
|
+
const newHtml = this.render();
|
|
242
|
+
// Compare the new HTML with the cached content
|
|
243
|
+
if (newHtml !== this.currentHtml) {
|
|
244
|
+
// Update the HTML only if it has changed
|
|
245
|
+
el.innerHTML = newHtml;
|
|
246
|
+
|
|
247
|
+
// Update the cached HTML content
|
|
248
|
+
this.currentHtml = newHtml;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Handles an object by parsing it as JSON and evaluating it.
|
|
256
|
+
* @param {string} obj - The object to handle.
|
|
257
|
+
* @returns {*} - The evaluated object.
|
|
258
|
+
* @prvate
|
|
259
|
+
*/
|
|
260
|
+
handleObject(obj) {
|
|
261
|
+
try {
|
|
262
|
+
obj = JSON.parse(obj);
|
|
263
|
+
} catch (error) {
|
|
264
|
+
// Handle JSON parsing error if needed
|
|
265
|
+
}
|
|
266
|
+
return eval(obj);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Frees memory from functions that have not been used for a certain period of time.
|
|
271
|
+
* @private
|
|
272
|
+
*/
|
|
273
|
+
freeMemoryFromFunctions() {
|
|
274
|
+
setInterval(() => {
|
|
275
|
+
for (var [key, value] in this.functionMap) {
|
|
276
|
+
if (Date.now() - value.lastUsed > 1000) {
|
|
277
|
+
this.functionMap.delete(key);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}, 1000);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Binds a function to the component.
|
|
285
|
+
* @param {string} funcData - The function data.
|
|
286
|
+
* @param {string} p - The parameter.
|
|
287
|
+
* @param {string} ref - The reference.
|
|
288
|
+
* @returns {string} - A valid inline JS function call.
|
|
289
|
+
*/
|
|
290
|
+
bind(funcData, d) {
|
|
291
|
+
|
|
292
|
+
const name = `func_${crypto ? crypto.getRandomValues(new Uint32Array(1))[0] : Math.random()}`;
|
|
293
|
+
|
|
294
|
+
var dynamicFunction = (params) => {
|
|
295
|
+
let func = new Function(`return (async (${params}) => {
|
|
296
|
+
console.log('called')
|
|
297
|
+
${funcData}
|
|
298
|
+
})()`);
|
|
299
|
+
func = func.bind(this);
|
|
300
|
+
func(params);
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
dynamicFunction = dynamicFunction.bind(this);
|
|
304
|
+
if (!this.functionMap.has(name)) {
|
|
305
|
+
document.addEventListener(`call_${name}`, (e) => {
|
|
306
|
+
|
|
307
|
+
dynamicFunction();
|
|
308
|
+
this.functionMap.set(e.detail.name, {
|
|
309
|
+
lastUsed: Date.now(),
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
this.functionMap.set(name, {
|
|
315
|
+
lastUsed: Date.now(),
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
window.call = (name, eventdata, params) => {
|
|
319
|
+
document.dispatchEvent(
|
|
320
|
+
new CustomEvent(`call_${name}`, {
|
|
321
|
+
detail: { name: `call_${name}`, target: eventdata },
|
|
322
|
+
})
|
|
323
|
+
);
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
// Return a valid inline js function call
|
|
327
|
+
return d.jsx ? dynamicFunction : `
|
|
328
|
+
((event) => {
|
|
329
|
+
event.target.setAttribute('data-ref', '${d.ref}');
|
|
330
|
+
let reference = event.target.getAttribute('data-ref');
|
|
331
|
+
event.target.eventData = event;
|
|
332
|
+
let domquery = queryRef(reference);
|
|
333
|
+
domquery.eventData = event;
|
|
334
|
+
domquery.eventData.detail.target = domquery;
|
|
335
|
+
call('${name}', {event:domquery.eventData}, '${d.params}')
|
|
336
|
+
})(event)
|
|
337
|
+
`;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Calls a function with the specified parameters. and dispatches an event.
|
|
342
|
+
* @param {string} func - The function name.
|
|
343
|
+
* @param {...*} params - The function parameters.
|
|
344
|
+
*/
|
|
345
|
+
callFunction(func, isInlineJsx, ...params) {
|
|
346
|
+
if(!isInlineJsx && params[0] && params[0].detail){
|
|
347
|
+
let el = params[0].detail.target.event.target
|
|
348
|
+
params[0].data = el.value;
|
|
349
|
+
params[0] = params[0].detail.target.event
|
|
350
|
+
}
|
|
351
|
+
func = func.replace(/'/g, '');
|
|
352
|
+
document.dispatchEvent(new CustomEvent(func, { detail: { name: func, params: params } }));
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Uses a function with the specified parameters.
|
|
357
|
+
* @param {Function} func - The function to use.
|
|
358
|
+
* @param {string} params - The function parameters.
|
|
359
|
+
* @param {boolean} [isInlineJsx=false] - Indicates if the function is an inline JSX.
|
|
360
|
+
* @returns {string} - The function call.
|
|
361
|
+
*/
|
|
362
|
+
useFunction(func, params, isInlineJsx = false) {
|
|
363
|
+
const sanitizedFuncName = func.name.trim().replace(/\s+/g, '_');
|
|
364
|
+
|
|
365
|
+
if (!invokes.includes(`'${sanitizedFuncName}'${this.key}`)) {
|
|
366
|
+
invokes.push(`'${sanitizedFuncName}'${this.key}`);
|
|
367
|
+
document.addEventListener(`call_${sanitizedFuncName}_${this.key}`, (e) => {
|
|
368
|
+
let { name, params } = e.detail;
|
|
369
|
+
if (name === `call_${sanitizedFuncName}_${this.key}`) {
|
|
370
|
+
let isarray = Array.isArray(params);
|
|
371
|
+
|
|
372
|
+
func(...(isarray ? params : [params]));
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
func = func.bind(this);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
try {
|
|
380
|
+
params = JSON.parse(params);
|
|
381
|
+
} catch (error) {
|
|
382
|
+
// Handle JSON parsing error if needed
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const returnString = isInlineJsx
|
|
386
|
+
? `'call_${sanitizedFuncName}_${this.key}'`
|
|
387
|
+
: `document.dispatchEvent(new CustomEvent('call_${sanitizedFuncName}_${this.key}', { detail: { name: 'call_${sanitizedFuncName}_${this.key}', params: ${JSON.stringify(params)} } }))`;
|
|
388
|
+
|
|
389
|
+
return returnString;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Uses state to dynamically update the component.
|
|
394
|
+
* @method useState
|
|
395
|
+
* @param {string} [key=null] - The auto-generated key.
|
|
396
|
+
* @param {*} initialState - The initial state.
|
|
397
|
+
* @param {Component.render} [func=null] - The render function.
|
|
398
|
+
* @returns {Array} - An array containing the state value and the setter function.
|
|
399
|
+
*/
|
|
400
|
+
useState(key = null, initialState) {
|
|
401
|
+
if (!this.state[key]) {
|
|
402
|
+
this.state[key] = initialState;
|
|
403
|
+
}
|
|
404
|
+
const getValue = () => this.state[key];
|
|
405
|
+
const set = (newValue) => {
|
|
406
|
+
this.state[key] = newValue;
|
|
407
|
+
this.hydrate();
|
|
408
|
+
};
|
|
409
|
+
return [getValue, set];
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
useRef(key = null, initialState) {
|
|
413
|
+
if (!this.state[key]) {
|
|
414
|
+
this.state[key] = initialState;
|
|
415
|
+
}
|
|
416
|
+
const getValue = () => this.state[key];
|
|
417
|
+
const set = (newValue) => {
|
|
418
|
+
this.state[key] = newValue;
|
|
419
|
+
this.hydrate();
|
|
420
|
+
};
|
|
421
|
+
return {
|
|
422
|
+
bind: key,
|
|
423
|
+
current: () => document.querySelector(`[ref="${key}"]`) || this.state[key],
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
useReducer(key = null, initialState, func = null) {
|
|
428
|
+
const getValue = () => this.state[key];
|
|
429
|
+
const set = (newValue) => {
|
|
430
|
+
|
|
431
|
+
this.hydrate();
|
|
432
|
+
};
|
|
433
|
+
return [getValue, set];
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Placeholder for content to be rendered.
|
|
438
|
+
* @method render
|
|
439
|
+
*/
|
|
440
|
+
render() {}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Checks if the component is mounted and triggers the onMount method.
|
|
444
|
+
* @private
|
|
445
|
+
*/
|
|
446
|
+
checkIFMounted() {
|
|
447
|
+
if (this.mounted) return;
|
|
448
|
+
let timer = setInterval(() => {
|
|
449
|
+
if (document.querySelector('[key="' + this.key + '"]')) {
|
|
450
|
+
clearInterval(timer);
|
|
451
|
+
this.mounted = true;
|
|
452
|
+
this.onMount();
|
|
453
|
+
}
|
|
454
|
+
}, 120);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Method that is called when the component is mounted.
|
|
459
|
+
* @method onMount
|
|
460
|
+
*/
|
|
461
|
+
onMount() {}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
let cache = {};
|
|
469
|
+
/**
|
|
470
|
+
* @method require
|
|
471
|
+
* @description Import CommonJS modules like Node.js for the browser
|
|
472
|
+
* @param {string} path
|
|
473
|
+
* @param {Boolean} noresolve - used to tell if the path should be automatically handled or manually handled - this is false by default
|
|
474
|
+
* @returns
|
|
475
|
+
*/
|
|
476
|
+
export const require = async (path, noresolve = false) => {
|
|
477
|
+
|
|
478
|
+
if (cache[path]) {
|
|
479
|
+
return cache[path];
|
|
480
|
+
}
|
|
481
|
+
let file = ''
|
|
482
|
+
try {
|
|
483
|
+
file = await fetch(path).then((res) => res.text());
|
|
484
|
+
} catch (error) {
|
|
485
|
+
console.error(error)
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
file = file + `\n//# sourceURL=${path}\n`;
|
|
489
|
+
|
|
490
|
+
let filetype = path.split(".").pop();
|
|
491
|
+
switch (true) {
|
|
492
|
+
case filetype === "js":
|
|
493
|
+
let exports = file.match(/module.exports\s*=\s*{.*}/gs) || file.match(/exports\s*=\s*{.*}/gs);
|
|
494
|
+
exports = exports ? exports[0] : null;
|
|
495
|
+
|
|
496
|
+
if (exports) {
|
|
497
|
+
let keys = exports.split("{")[1].split("}")[0].split(",");
|
|
498
|
+
let returnstring = "";
|
|
499
|
+
keys.forEach((key) => {
|
|
500
|
+
key = key.trim();
|
|
501
|
+
returnstring += `${key},`;
|
|
502
|
+
});
|
|
503
|
+
returnstring = `return {${returnstring}}`;
|
|
504
|
+
file = file += returnstring;
|
|
505
|
+
file = file.replaceAll(exports, "");
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
return new Function(`return (async () => { ${file} })()`)();
|
|
509
|
+
case filetype === "jsx":
|
|
510
|
+
return new Function(`return (async () => { ${file} })()`)()
|
|
511
|
+
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
window.require = require;
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* @method useState - type
|
|
520
|
+
* @param {*} initialState
|
|
521
|
+
* @returns {Array} [value, set]
|
|
522
|
+
* @description Allows you to use state to dynamically update your component
|
|
523
|
+
*/
|
|
524
|
+
export const useState = (initialState) => {
|
|
525
|
+
let value = initialState;
|
|
526
|
+
if (key && !states[key]) {
|
|
527
|
+
this.states[key] = initialState;
|
|
528
|
+
}
|
|
529
|
+
return [value, (newValue) => {}];
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
const constants = {};
|
|
533
|
+
let constantCounter = 0;
|
|
534
|
+
|
|
535
|
+
export const constant = (value) => {
|
|
536
|
+
const key = `constant_${constantCounter++}`;
|
|
537
|
+
if (!constants[key]) {
|
|
538
|
+
constants[key] = value;
|
|
539
|
+
}
|
|
540
|
+
return constants[key];
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
export default {
|
|
544
|
+
Component,
|
|
545
|
+
require,
|
|
546
|
+
invoke,
|
|
547
|
+
mem,
|
|
548
|
+
constant,
|
|
549
|
+
useState,
|
|
550
|
+
strictMount,
|
|
551
|
+
stylis,
|
|
552
|
+
}
|
package/vader.js
CHANGED
|
@@ -741,14 +741,15 @@ Building to ./dist
|
|
|
741
741
|
break;
|
|
742
742
|
default:
|
|
743
743
|
console.log(`
|
|
744
|
-
Vader.js is a reactive framework for building interactive applications
|
|
744
|
+
Vader.js is a reactive framework for building interactive applications inspired by React.js and Next.js
|
|
745
745
|
|
|
746
746
|
Usage: vader <command>
|
|
747
747
|
|
|
748
748
|
Commands:
|
|
749
749
|
--watch Watch the pages folder for changes and recompile
|
|
750
750
|
|
|
751
|
-
--build Build the project
|
|
751
|
+
--build Build the project - use this to initialize the project
|
|
752
|
+
|
|
752
753
|
Learn more about vader: https://vader-js.pages.dev/
|
|
753
754
|
|
|
754
755
|
`)
|