vaderjs 1.3.3 → 1.3.4

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.
Files changed (113) hide show
  1. package/create-vader-app/example_proj/dist/vaderjs/index.js +5 -0
  2. package/create-vader-app/example_proj/dist/vaderjs/vader-min.js +1115 -0
  3. package/create-vader-app/example_proj/dist/vaderjs/vaderRouter-min.js +1 -0
  4. package/create-vader-app/example_proj/dist/vaderjs/worker.js +327 -0
  5. package/create-vader-app/example_proj/index.html +20 -0
  6. package/create-vader-app/example_proj/readme.md +2 -0
  7. package/create-vader-app/example_proj/src/pages/Index.js +13 -0
  8. package/create-vader-app/example_proj/src/views/app.html +16 -0
  9. package/create-vader-app/index.js +20 -0
  10. package/create-vader-app/node_modules/.package-lock.json +350 -0
  11. package/create-vader-app/node_modules/chalk/license +9 -0
  12. package/create-vader-app/node_modules/chalk/package.json +83 -0
  13. package/create-vader-app/node_modules/chalk/readme.md +325 -0
  14. package/create-vader-app/node_modules/chalk/source/index.d.ts +320 -0
  15. package/create-vader-app/node_modules/chalk/source/index.js +225 -0
  16. package/create-vader-app/node_modules/chalk/source/utilities.js +33 -0
  17. package/create-vader-app/node_modules/chalk/source/vendor/ansi-styles/index.d.ts +236 -0
  18. package/create-vader-app/node_modules/chalk/source/vendor/ansi-styles/index.js +223 -0
  19. package/create-vader-app/node_modules/chalk/source/vendor/supports-color/browser.d.ts +1 -0
  20. package/create-vader-app/node_modules/chalk/source/vendor/supports-color/browser.js +30 -0
  21. package/create-vader-app/node_modules/chalk/source/vendor/supports-color/index.d.ts +55 -0
  22. package/create-vader-app/node_modules/chalk/source/vendor/supports-color/index.js +182 -0
  23. package/create-vader-app/node_modules/commander/LICENSE +22 -0
  24. package/create-vader-app/node_modules/commander/Readme.md +1146 -0
  25. package/create-vader-app/node_modules/commander/esm.mjs +16 -0
  26. package/create-vader-app/node_modules/commander/index.js +27 -0
  27. package/create-vader-app/node_modules/commander/lib/argument.js +147 -0
  28. package/create-vader-app/node_modules/commander/lib/command.js +2196 -0
  29. package/create-vader-app/node_modules/commander/lib/error.js +45 -0
  30. package/create-vader-app/node_modules/commander/lib/help.js +464 -0
  31. package/create-vader-app/node_modules/commander/lib/option.js +331 -0
  32. package/create-vader-app/node_modules/commander/lib/suggestSimilar.js +100 -0
  33. package/create-vader-app/node_modules/commander/package-support.json +16 -0
  34. package/create-vader-app/node_modules/commander/package.json +90 -0
  35. package/create-vader-app/node_modules/commander/typings/esm.d.mts +3 -0
  36. package/create-vader-app/node_modules/commander/typings/index.d.ts +889 -0
  37. package/create-vader-app/node_modules/fs-extra/LICENSE +15 -0
  38. package/create-vader-app/node_modules/fs-extra/README.md +292 -0
  39. package/create-vader-app/node_modules/fs-extra/lib/copy/copy-sync.js +161 -0
  40. package/create-vader-app/node_modules/fs-extra/lib/copy/copy.js +238 -0
  41. package/create-vader-app/node_modules/fs-extra/lib/copy/index.js +7 -0
  42. package/create-vader-app/node_modules/fs-extra/lib/empty/index.js +39 -0
  43. package/create-vader-app/node_modules/fs-extra/lib/ensure/file.js +69 -0
  44. package/create-vader-app/node_modules/fs-extra/lib/ensure/index.js +23 -0
  45. package/create-vader-app/node_modules/fs-extra/lib/ensure/link.js +64 -0
  46. package/create-vader-app/node_modules/fs-extra/lib/ensure/symlink-paths.js +99 -0
  47. package/create-vader-app/node_modules/fs-extra/lib/ensure/symlink-type.js +31 -0
  48. package/create-vader-app/node_modules/fs-extra/lib/ensure/symlink.js +82 -0
  49. package/create-vader-app/node_modules/fs-extra/lib/esm.mjs +68 -0
  50. package/create-vader-app/node_modules/fs-extra/lib/fs/index.js +140 -0
  51. package/create-vader-app/node_modules/fs-extra/lib/index.js +16 -0
  52. package/create-vader-app/node_modules/fs-extra/lib/json/index.js +16 -0
  53. package/create-vader-app/node_modules/fs-extra/lib/json/jsonfile.js +11 -0
  54. package/create-vader-app/node_modules/fs-extra/lib/json/output-json-sync.js +12 -0
  55. package/create-vader-app/node_modules/fs-extra/lib/json/output-json.js +12 -0
  56. package/create-vader-app/node_modules/fs-extra/lib/mkdirs/index.js +14 -0
  57. package/create-vader-app/node_modules/fs-extra/lib/mkdirs/make-dir.js +27 -0
  58. package/create-vader-app/node_modules/fs-extra/lib/mkdirs/utils.js +21 -0
  59. package/create-vader-app/node_modules/fs-extra/lib/move/index.js +7 -0
  60. package/create-vader-app/node_modules/fs-extra/lib/move/move-sync.js +55 -0
  61. package/create-vader-app/node_modules/fs-extra/lib/move/move.js +76 -0
  62. package/create-vader-app/node_modules/fs-extra/lib/output-file/index.js +40 -0
  63. package/create-vader-app/node_modules/fs-extra/lib/path-exists/index.js +12 -0
  64. package/create-vader-app/node_modules/fs-extra/lib/remove/index.js +17 -0
  65. package/create-vader-app/node_modules/fs-extra/lib/util/stat.js +154 -0
  66. package/create-vader-app/node_modules/fs-extra/lib/util/utimes.js +26 -0
  67. package/create-vader-app/node_modules/fs-extra/package.json +71 -0
  68. package/create-vader-app/node_modules/graceful-fs/LICENSE +15 -0
  69. package/create-vader-app/node_modules/graceful-fs/README.md +143 -0
  70. package/create-vader-app/node_modules/graceful-fs/clone.js +23 -0
  71. package/create-vader-app/node_modules/graceful-fs/graceful-fs.js +448 -0
  72. package/create-vader-app/node_modules/graceful-fs/legacy-streams.js +118 -0
  73. package/create-vader-app/node_modules/graceful-fs/package.json +53 -0
  74. package/create-vader-app/node_modules/graceful-fs/polyfills.js +355 -0
  75. package/create-vader-app/node_modules/inherits/LICENSE +16 -0
  76. package/create-vader-app/node_modules/inherits/README.md +42 -0
  77. package/create-vader-app/node_modules/inherits/inherits.js +7 -0
  78. package/create-vader-app/node_modules/inherits/inherits_browser.js +23 -0
  79. package/create-vader-app/node_modules/inherits/package.json +29 -0
  80. package/create-vader-app/node_modules/jsonfile/CHANGELOG.md +171 -0
  81. package/create-vader-app/node_modules/jsonfile/LICENSE +15 -0
  82. package/create-vader-app/node_modules/jsonfile/README.md +230 -0
  83. package/create-vader-app/node_modules/jsonfile/index.js +88 -0
  84. package/create-vader-app/node_modules/jsonfile/package.json +40 -0
  85. package/create-vader-app/node_modules/jsonfile/utils.js +14 -0
  86. package/create-vader-app/node_modules/path/LICENSE +18 -0
  87. package/create-vader-app/node_modules/path/README.md +15 -0
  88. package/create-vader-app/node_modules/path/package.json +24 -0
  89. package/create-vader-app/node_modules/path/path.js +628 -0
  90. package/create-vader-app/node_modules/process/.eslintrc +21 -0
  91. package/create-vader-app/node_modules/process/LICENSE +22 -0
  92. package/create-vader-app/node_modules/process/README.md +26 -0
  93. package/create-vader-app/node_modules/process/browser.js +184 -0
  94. package/create-vader-app/node_modules/process/index.js +2 -0
  95. package/create-vader-app/node_modules/process/package.json +27 -0
  96. package/create-vader-app/node_modules/process/test.js +199 -0
  97. package/create-vader-app/node_modules/universalify/LICENSE +20 -0
  98. package/create-vader-app/node_modules/universalify/README.md +76 -0
  99. package/create-vader-app/node_modules/universalify/index.js +24 -0
  100. package/create-vader-app/node_modules/universalify/package.json +34 -0
  101. package/create-vader-app/node_modules/util/LICENSE +18 -0
  102. package/create-vader-app/node_modules/util/README.md +15 -0
  103. package/create-vader-app/node_modules/util/package.json +35 -0
  104. package/create-vader-app/node_modules/util/support/isBuffer.js +3 -0
  105. package/create-vader-app/node_modules/util/support/isBufferBrowser.js +6 -0
  106. package/create-vader-app/node_modules/util/util.js +586 -0
  107. package/create-vader-app/package-lock.json +384 -0
  108. package/create-vader-app/package.json +18 -0
  109. package/package.json +1 -1
  110. package/vader-min.js +1 -1
  111. package/vader.js +4 -4
  112. package/worker-min.js +1 -1
  113. package/worker.js +49 -24
@@ -0,0 +1,1115 @@
1
+ // @ts-nocheck
2
+ let dom = [];
3
+ let states = {};
4
+
5
+ let worker = new Worker(new URL("./worker.js", import.meta.url));
6
+
7
+ /**
8
+ * @function useRef
9
+ * @description Allows you to get reference to DOM element
10
+ * @param {String} ref
11
+ * @returns {void | Object} {current, update}
12
+ */
13
+
14
+ export const useRef = (ref) => {
15
+ const element = document.querySelector(`[ref="${ref}"]`);
16
+ const getElement = () => element;
17
+
18
+ const update = (data) => {
19
+ const newDom = new DOMParser().parseFromString(data, "text/html");
20
+ const newElement = newDom.body.firstChild;
21
+
22
+ if (element) {
23
+ // @ts-ignore
24
+ const isDifferent = !newElement.isEqualNode(element);
25
+ if (isDifferent) {
26
+ // @ts-ignore
27
+ element.parentNode.replaceChild(newElement, element);
28
+ }
29
+ }
30
+ };
31
+
32
+ return {
33
+ current: getElement(),
34
+ update
35
+ };
36
+ };
37
+
38
+ let components = [];
39
+ /**
40
+ * @class Component
41
+ * @description Allows you to create a component
42
+ * @returns {void}
43
+ * @example
44
+ * import { Vader } from "../../dist/vader/index.js";
45
+ * export class Home extends Vader.Component {
46
+ * constructor() {
47
+ * super();
48
+ * }
49
+ * async render() {
50
+ * return this.html(`
51
+ * <div className="hero p-5">
52
+ * <h1>Home</h1>
53
+ * </div>
54
+ * `);
55
+ * }
56
+ * }
57
+ */
58
+ export class Component {
59
+ constructor() {
60
+ this.states = {};
61
+ //@ts-ignore
62
+ this.name = this.constructor.name;
63
+ this.executedEffects = {};
64
+ this.storedProps = {};
65
+ this.componentMounted = false;
66
+ this.hasMounted = false;
67
+ this.$_signal_subscribers = [];
68
+ /**
69
+ * @property {Array} $_signal_subscribers_ran
70
+ * @description Allows you to keep track of signal subscribers
71
+ * @private
72
+ */
73
+ this.$_signal_subscribers_ran = [];
74
+ this.effects = {};
75
+ this.$_useStore_subscribers = [];
76
+ this.init();
77
+ this.Componentcontent = null;
78
+ this.$_signal_dispatch_event = new CustomEvent("SignalDispatch", {
79
+ detail: {
80
+ hasUpdated: false,
81
+ state: null
82
+ }
83
+ });
84
+ /**
85
+ * @property {Object} $_signal_dispatch_cleanup_event
86
+ * @description Allows you to dispatch a signal cleanup event
87
+ * @private
88
+ */
89
+ this.$_signal_dispatch_cleanup_event = new CustomEvent(
90
+ "Signal_Cleanup_Dispatch",
91
+ {
92
+ detail: {
93
+ state: null,
94
+ lastState: null
95
+ }
96
+ }
97
+ );
98
+ /**
99
+ * @property {Array} snapshots
100
+ * @private
101
+ */
102
+ this.snapshots = [];
103
+ /**
104
+ * @property {Object} dom
105
+ * @description Allows you to get reference to DOM element
106
+ * @returns {void | HTMLElement}
107
+ *
108
+ */
109
+ this.dom = [];
110
+
111
+ /**
112
+ * @property {Boolean} cfr
113
+ * @description Allows you to compile html code on the fly - client fly rendering
114
+ *
115
+ */
116
+ this.cfr = false;
117
+ /**
118
+ * @property {Boolean} worker
119
+ * @description Allows you to use a web worker to compile html code on the fly - client fly rendering
120
+
121
+ */
122
+ }
123
+
124
+ /**
125
+ * @method adapter
126
+ * @description Allows you to create an adapter - this is used to create custom logic
127
+ *
128
+ *
129
+ */
130
+ adapter(options) {
131
+ // allow you to override the compoent logic
132
+ }
133
+ init() {
134
+ this.registerComponent();
135
+ }
136
+
137
+ registerComponent() {
138
+ components.push(this);
139
+ }
140
+
141
+ /**
142
+ * @method setState
143
+ * @description Allows you to set state
144
+ * @param {String} key
145
+ * @param {*} value
146
+ * @returns {void}
147
+ * @example
148
+ * this.setState('count', 1)
149
+ * */
150
+ setState(key, value) {
151
+ this.states[key] = value;
152
+ this.updateComponent();
153
+ }
154
+ /**
155
+ * @method componentUnmount
156
+ * @description Allows you to run code after component has unmounted
157
+ * @type {VoidFunction}
158
+ * @returns {void}
159
+ */
160
+ unmount() {
161
+ this.componentMounted = false;
162
+ this.componentWillUnmount();
163
+ // @ts-ignore
164
+ document.querySelector(`[data-component="${this.name}"]`).remove();
165
+ if (!document.querySelector(`[data-component="${this.name}"]`)) {
166
+ components = components.filter(
167
+ (component) => component.name !== this.name
168
+ );
169
+ }
170
+ }
171
+
172
+ /**
173
+ * @method componentUpdate
174
+ * @description Allows you to run code after component has updated
175
+ * @param {Object} prev_state
176
+ * @param {Object} prev_props
177
+ * @param {Object} snapshot
178
+ * @returns {void}
179
+ * @example
180
+ * componentUpdate(prev_state, prev_props, snapshot) {
181
+ * console.log(prev_state, prev_props, snapshot)
182
+ * }
183
+ * */
184
+ componentUpdate(prev_state, prev_props, snapshot) {}
185
+ /**
186
+ * @method componentDidMount
187
+ * @description Allows you to run code after component has mounted
188
+ */
189
+ componentDidMount() {}
190
+
191
+ /**
192
+ * @method componentWillUnmount
193
+ * @description Allows you to run code before component unmounts
194
+ * @type {VoidFunction}
195
+ * @returns {void}
196
+ */
197
+ componentWillUnmount() {}
198
+
199
+ /**
200
+ * @method signal
201
+ * @description Allows you to create a signal
202
+ * @param {String} key
203
+ * @param {any} initialState
204
+ * @returns {Object} {subscribe, cleanup, dispatch, call, set, get}
205
+ * @example
206
+ * let signal = this.signal('count', 0);
207
+ * signal.subscribe((value) => {
208
+ * console.log(value)
209
+ * }, false) // false means it will run every time
210
+ * signal.subscribe((value) => {
211
+ * console.log(value)
212
+ * }, true) // true means it will run once
213
+ * signal.call() // this will call all subscribers
214
+ * signal.set(1) // this will set the value of the signal
215
+ * signal.get() // this will get the value of the signal
216
+ * signal.cleanup() // this will remove all subscribers
217
+ */
218
+ signal = (key, initialState) => {
219
+ let hasCaller = false;
220
+ let [state, setState] = this.useState(key, initialState, () => {
221
+ if (this.$_signal_subscribers.length > 0) {
222
+ for (var i = 0; i < this.$_signal_subscribers.length; i++) {
223
+ if (!hasCaller) {
224
+ if (
225
+ this.$_signal_subscribers[i].runonce &&
226
+ // @ts-ignore
227
+ this.$_signal_subscribers_ran.includes(
228
+ this.$_signal_subscribers[i]
229
+ )
230
+ ) {
231
+ break;
232
+ } else {
233
+ this.$_signal_subscribers[i].function(state);
234
+ this.$_signal_subscribers_ran.push(this.$_signal_subscribers[i]);
235
+ return;
236
+ }
237
+ }
238
+ }
239
+ } else {
240
+ this.$_signal_dispatch_event.detail.hasUpdated = true;
241
+ this.$_signal_dispatch_event.detail.state = state;
242
+ window.dispatchEvent(this.$_signal_dispatch_event);
243
+ }
244
+ });
245
+ /**
246
+ * @function $_signal_subscribe
247
+ * @description Allows you to subscribe to a signal
248
+ * @param {*} fn
249
+ * @param {*} runonce
250
+ * @returns {void}
251
+ *
252
+ */
253
+ this.$_signal_subscribe = (fn, runonce) => {
254
+ this.$_signal_subscribers.push({
255
+ function: fn,
256
+ runonce: runonce
257
+ });
258
+ return fn;
259
+ };
260
+ this.$_signal_cleanup = (fn) => {
261
+ this.lastState = state;
262
+ this.$_signal_subscribers = this.$_signal_subscribers.filter(
263
+ (subscriber) => subscriber.function !== fn
264
+ );
265
+ // @ts-ignore
266
+ this.$_signal_dispatch_cleanup_event.detail.state = this.states;
267
+ // @ts-ignore
268
+ this.$_signal_dispatch_cleanup_event.detail.lastState = this.lastState;
269
+ window.dispatchEvent(this.$_signal_dispatch_event);
270
+ };
271
+ this.$_signal_dispatch = () => {
272
+ for (var i = 0; i < this.$_signal_subscribers.length; i++) {
273
+ if (
274
+ this.$_signal_subscribers[i].runonce &&
275
+ // @ts-ignore
276
+ this.$_signal_subscribers_ran.includes(this.$_signal_subscribers[i])
277
+ ) {
278
+ break;
279
+ } else {
280
+ this.$_signal_subscribers[i].function(state);
281
+ this.$_signal_subscribers_ran.push(this.$_signal_subscribers[i]);
282
+ }
283
+ }
284
+ };
285
+ this.$_signal_get = () => {
286
+ return state;
287
+ };
288
+ this.$_signal_call = () => {
289
+ hasCaller = true;
290
+ // @ts-ignore
291
+ this.$_signal_dispatch();
292
+ };
293
+ /**
294
+ * @function $_signal_set
295
+ * @description Allows you to set the value of a signal
296
+ * @param {*} detail
297
+ */
298
+ this.$_signal_set = (detail) => {
299
+ setState(detail);
300
+ };
301
+
302
+ return {
303
+ /**
304
+ * @function subscribe
305
+ * @description Allows you to subscribe to a signal
306
+ * @param {*} fn
307
+ * @param {*} runonce
308
+ */
309
+ subscribe: this.$_signal_subscribe,
310
+ /**
311
+ * @function cleanup
312
+ * @description Allows you to cleanup a signal
313
+ * @param {*} fn
314
+ * @returns {null}
315
+ */
316
+ cleanup: this.$_signal_cleanup,
317
+ /**
318
+ * @function dispatch
319
+ * @description Allows you to dispatch a signal
320
+ * @returns {null}
321
+ */
322
+ dispatch: this.$_signal_dispatch,
323
+ /**
324
+ * @function call
325
+ * @description Allows you to call a signal
326
+ * @returns {null}
327
+ */
328
+ call: this.$_signal_call,
329
+ /**
330
+ * @function set
331
+ * @description Allows you to set the value of a signal
332
+ * @param {*} detail
333
+ * @returns {null}
334
+ */
335
+ set: this.$_signal_set,
336
+ /**
337
+ * @function get
338
+ * @readonly
339
+ * @description Allows you to get the value of a signal
340
+ * @returns {any}
341
+ */
342
+ get: this.$_signal_get
343
+ };
344
+ };
345
+ /**
346
+ * @method useAuth
347
+ * @description Allows you to create an auth object
348
+ * @param {Object} options
349
+ * @param {Array} options.rulesets
350
+ * @param {Object} options.user
351
+ * @returns {Object} {can, hasRole, canWithRole, assignRule, revokeRule, canAnyOf, canAllOf, canGroup}
352
+ * @example
353
+ * let auth = this.useAuth({
354
+ * rulesets: [
355
+ * {
356
+ * action: 'create',
357
+ * condition: (user) => {
358
+ * return user.role === 'admin'
359
+ * }
360
+ * }
361
+ * ],
362
+ * user: {
363
+ * role: 'admin'
364
+ * }
365
+ * })
366
+ * auth.can('create') // true
367
+ */
368
+ useAuth(options) {
369
+ /**@type {Array}**/
370
+ let rules = options.rulesets;
371
+ if (!rules) {
372
+ throw new Error("No rulesets provided");
373
+ }
374
+ /**@type {Object}**/
375
+ let user = options.user;
376
+ let auth = {
377
+ can: (action) => {
378
+ let can = false;
379
+ rules.forEach((rule) => {
380
+ if (rule.action === action) {
381
+ if (rule.condition(user)) {
382
+ can = true;
383
+ }
384
+ }
385
+ });
386
+ return can;
387
+ },
388
+ /**
389
+ * @function hasRole
390
+ * @description Allows you to check if user has a role
391
+ * @param {String} role
392
+ * @returns {Boolean}
393
+ */
394
+ hasRole: (role) => {
395
+ return user.role && user.role.includes(role);
396
+ },
397
+ /**
398
+ * @function canWithRole
399
+ * @param {String} action
400
+ * @param {String} role
401
+ * @returns
402
+ */
403
+ canWithRole: (action, role) => {
404
+ return auth.can(action) && auth.hasRole(role);
405
+ },
406
+ assignRule: (rule) => {
407
+ if (
408
+ !rules.some((existingRule) => existingRule.action === rule.action)
409
+ ) {
410
+ rules.push(rule);
411
+ }
412
+ },
413
+ revokeRule: (action) => {
414
+ rules = rules.filter((rule) => rule.action !== action);
415
+ },
416
+ canAnyOf: (actions) => {
417
+ return actions.some((action) => auth.can(action));
418
+ },
419
+ canAllOf: (actions) => {
420
+ return actions.every((action) => auth.can(action));
421
+ },
422
+ canGroup: (actions, logicalOperator = "any") => {
423
+ return logicalOperator === "any"
424
+ ? auth.canAnyOf(actions)
425
+ : auth.canAllOf(actions);
426
+ }
427
+ };
428
+ return auth;
429
+ }
430
+ /**
431
+ * @method useReducer
432
+ * @description Allows you to create a reducer
433
+ * @param {*} key
434
+ * @param {*} reducer
435
+ * @param {*} initialState
436
+ * @url - useReducer works similarly to - https://react.dev/reference/react/useReducer
437
+ * @returns {Array} [state, dispatch]
438
+ * @example
439
+ * let [count, setCount] = this.useReducer('count', (state, action) => {
440
+ * switch (action.type) {
441
+ * case 'increment':
442
+ * return state + 1
443
+ * case 'decrement':
444
+ * return state - 1
445
+ * default:
446
+ * throw new Error()
447
+ * }
448
+ * }, 0)
449
+ * setCount({type: 'increment'})
450
+ */
451
+ useReducer(key, reducer, initialState) {
452
+ if (!this.states[key]) {
453
+ this.states[key] = initialState;
454
+ }
455
+ return [
456
+ this.states[key],
457
+ /**
458
+ * @function dispatch
459
+ * @description Allows you to dispatch a reducer
460
+ * @param {*} action
461
+ * @returns {void}
462
+ */
463
+ (action) => {
464
+ this.states[key] = reducer(this.states[key], action);
465
+ this.updateComponent();
466
+ }
467
+ ];
468
+ }
469
+
470
+ runEffects() {
471
+ Object.keys(this.effects).forEach((component) => {
472
+ this.effects[component].forEach((effect) => {
473
+ if (!this.executedEffects[effect]) {
474
+ effect();
475
+ this.executedEffects[effect] = true;
476
+ }
477
+ });
478
+ });
479
+ }
480
+
481
+ /**
482
+ * @method useSyncStore
483
+ * @description Allows you to create a store
484
+ * @param {String} storeName
485
+ * @param {*} initialState
486
+ * @returns {Object} {getField, setField, subscribe, clear}
487
+ * @example
488
+ * let store = this.useSyncStore('store', {count: 0})
489
+ * store.setField('count', 1)
490
+ * store.getField('count') // 1
491
+ *
492
+ */
493
+ useSyncStore(storeName, initialState) {
494
+ let [storedState, setStoredState] = this.useState(
495
+ storeName,
496
+ initialState ||
497
+ // @ts-ignore
498
+ localStorage.getItem(`$_vader_${storeName}`, (s) => {
499
+ localStorage.setItem(`$_vader_${storeName}`, JSON.stringify(s));
500
+ this.$_useStore_subscribers.forEach((subscriber) => {
501
+ subscriber(s);
502
+ });
503
+ }) ||
504
+ {}
505
+ );
506
+
507
+ const getField = (fieldName) => {
508
+ return storedState[fieldName];
509
+ };
510
+ const setField = (fieldName, value) => {
511
+ const newState = { ...storedState, [fieldName]: value };
512
+ setStoredState(newState);
513
+ };
514
+ const subscribe = (subscriber) => {
515
+ return this.$_useStore_subscribers.push(subscriber);
516
+ };
517
+
518
+ const clear = (fieldName) => {
519
+ let newState = storedState;
520
+ delete newState[fieldName];
521
+ setStoredState(newState);
522
+ };
523
+ return {
524
+ getField,
525
+ setField,
526
+ subscribe,
527
+ clear
528
+ };
529
+ }
530
+ /**
531
+ * @method useState
532
+ * @description Allows you to create a state
533
+ * @param {String} key
534
+ * @param {*} initialValue
535
+ * @param {*} callback
536
+ * @url - useState works similarly to - https://react.dev/reference/react/useState
537
+ * @returns {Array} [state, setState]
538
+ * @example
539
+ * let [count, setCount] = this.useState('count', 0, () => {
540
+ * console.log('count has been updated')
541
+ * })
542
+ *
543
+ * setCount(count + 1)
544
+ */
545
+ useState(key, initialValue, callback = null) {
546
+ if (!this.states[key]) {
547
+ this.states[key] = initialValue;
548
+ }
549
+
550
+ return [
551
+ this.states[key],
552
+ /**
553
+ * @function setState
554
+ * @description Allows you to set state
555
+ * @param {*} value
556
+ * @returns {void}
557
+ */
558
+ (value) => {
559
+ this.states[key] = value;
560
+ this.updateComponent();
561
+ // @ts-ignore
562
+ typeof callback === "function" ? callback() : null;
563
+ }
564
+ ];
565
+ }
566
+ /**
567
+ * @method useRef
568
+ * @memberof Component
569
+ * @param {string} ref
570
+ * @description Allows you to get reference to DOM elements from the dom array
571
+ * @returns {Object} {current, update}
572
+ * @example
573
+ * let ref = this.useRef('ref')
574
+ * ref.current // returns the DOM element
575
+
576
+ */
577
+
578
+ useRef(ref) {
579
+ // get ref from array
580
+ const element = this.dom[ref];
581
+
582
+ const getElement = () => element;
583
+
584
+ const update = (data) => {
585
+ const newDom = new DOMParser().parseFromString(data, "text/html");
586
+ const newElement = newDom.body.firstChild;
587
+
588
+ if (element) {
589
+ // @ts-ignore
590
+ const isDifferent = !newElement.isEqualNode(element);
591
+ if (isDifferent) {
592
+ // @ts-ignore
593
+ element.parentNode.replaceChild(newElement, element);
594
+ }
595
+ }
596
+ };
597
+
598
+ return {
599
+ /**@type {HTMLElement} */
600
+ // @ts-ignore
601
+ current: getElement,
602
+ /**@type {Function} */
603
+ update
604
+ };
605
+ }
606
+
607
+ /**
608
+ *
609
+ * @function useEffect
610
+ * @param {*} effectFn
611
+ * @param {*} dependencies
612
+ * @description Allows you to run side effects
613
+ * @deprecated - this is no longer suggested please use vader signals instead
614
+ * @returns {Object} {cleanup}
615
+ */
616
+ useEffect(effectFn, dependencies) {
617
+ if (!this.effects[this.name]) {
618
+ this.effects[this.name] = [];
619
+ }
620
+ this.effects[this.name].push(effectFn);
621
+
622
+ if (dependencies.length > 0) {
623
+ dependencies.forEach((d) => {
624
+ if (d.set) {
625
+ throw new Error(
626
+ "signal found, do not use effect and signals at the same time - signals are more efficient"
627
+ );
628
+ }
629
+ });
630
+ } else if (!this.hasMounted) {
631
+ effectFn();
632
+ this.hasMounted = true;
633
+ }
634
+
635
+ return {
636
+ cleanup: () => {
637
+ // @ts-ignore
638
+ this.effects[this.name] = this.effects[this.name].filter(
639
+ // @ts-ignore
640
+ (effect) => effect !== effectFn
641
+ );
642
+ }
643
+ };
644
+ }
645
+ /**
646
+ * @method $Function
647
+ * @description Allows you to create a function in global scope
648
+ * @returns {Function}
649
+ * @example
650
+ * let func = this.$Function(function add(e, a){
651
+ * return e + a
652
+ * })
653
+ * @param {*} fn
654
+ */
655
+ $Function(fn) {
656
+ // @ts-ignore
657
+ if (!typeof fn === "function") {
658
+ throw new Error("fn must be a function");
659
+ }
660
+ let name = fn.name;
661
+ if (!name) {
662
+ name = "anonymous" + Math.floor(Math.random() * 100000000000000000);
663
+ }
664
+ window[name] = fn;
665
+ // @ts-ignore
666
+ return `window.${name}()`;
667
+ }
668
+
669
+ // Add other methods like render, useEffect, useReducer, useAuth, etc.
670
+
671
+ updateComponent() {
672
+ const fragment = document.createDocumentFragment();
673
+ Object.keys(components).forEach(async (component) => {
674
+ const { name } = components[component];
675
+
676
+ let componentContainer = document.querySelector(
677
+ `[data-component="${name}"]`
678
+ );
679
+ let time = new Date().getTime();
680
+ /**
681
+ * @property {Object} snapshot
682
+ * @description Allows you to keep track of component snapshots
683
+ * @private
684
+ * @returns {Object} {name, time, prev_state, prev_props, content}
685
+ */
686
+ let snapshot = {
687
+ name: name,
688
+ time: time,
689
+ prev_state: this.states,
690
+ prev_props: this.storedProps,
691
+ // @ts-ignore
692
+ content: componentContainer.innerHTML
693
+ };
694
+
695
+ if (!componentContainer) return;
696
+ const newHtml = await new Function(
697
+ "useState",
698
+ "useEffect",
699
+ "useAuth",
700
+ "useReducer",
701
+ "useSyncStore",
702
+ "signal",
703
+ "rf",
704
+ "props",
705
+ "render",
706
+ "return `" + (await this.render()) + "`;"
707
+ )(
708
+ this.useState,
709
+ this.useEffect,
710
+ this.useAuth,
711
+ this.useReducer,
712
+ this.useSyncStore,
713
+ this.signal,
714
+ this.render
715
+ );
716
+
717
+ if (newHtml !== componentContainer.innerHTML) {
718
+ if (this.snapshots.length > 0) {
719
+ let lastSnapshot = this.snapshots[this.snapshots.length - 1];
720
+ if (lastSnapshot !== snapshot) {
721
+ this.snapshots.push(snapshot);
722
+ }
723
+ } else {
724
+ this.snapshots.push(snapshot);
725
+ }
726
+ this.componentUpdate(
727
+ snapshot.prev_state,
728
+ snapshot.prev_props,
729
+ snapshot.content
730
+ );
731
+ // batch updates
732
+ fragment.appendChild(
733
+ document.createRange().createContextualFragment(newHtml)
734
+ );
735
+ componentContainer.innerHTML = "";
736
+ componentContainer.appendChild(fragment);
737
+ this.runEffects();
738
+ }
739
+ });
740
+ }
741
+ /**
742
+ * @method validateClassName
743
+ * @param {String} className
744
+ * @private
745
+ * @returns {Boolean}
746
+ */
747
+ validateClassName(className) {
748
+ // validate classNames ensure they are camelCase but also allow for - and _
749
+ return /^[a-zA-Z0-9-_]+$/.test(className);
750
+ }
751
+
752
+ /**
753
+ * The `html` method generates and processes HTML content for a component, performing various validations and tasks.
754
+ *
755
+ * @param {String} strings - The HTML content to be processed.
756
+ * @param {...any} args - Dynamic values to be inserted into the template.
757
+ * @returns {string} - The processed HTML content as a string.
758
+ *
759
+ * @throws {SyntaxError} - Throws a `SyntaxError` if image-related attributes are missing or invalid.
760
+ * @throws {Error} - Throws an `Error` if there are issues with class names or relative paths.
761
+ *
762
+ * @example
763
+ * // Example usage within a component:
764
+ * const myComponent = new Component();
765
+ * const htmlContent = myComponent.html`
766
+ * <div>
767
+ * <img src="/images/example.jpg" alt="Example Image" />
768
+ * </div>
769
+ * `;
770
+ * document.body.innerHTML = htmlContent;
771
+ *
772
+ * @remarks
773
+ * The `html` method is a core function used in component rendering. It allows you to define and generate HTML content within your component while enforcing best practices and accessibility standards. The method performs several essential tasks:
774
+ *
775
+ * 1. **Image Validation**: It checks images for the presence of 'alt' attributes and their validity.
776
+ * - Throws a `SyntaxError` if an image is missing the 'alt' attribute.
777
+ * - Throws a `SyntaxError` if the 'alt' attribute is empty.
778
+ * - Checks for an 'aria-hidden' attribute for image elements.
779
+ *
780
+ * 2. **Class Attribute Handling**: It enforces class attribute usage and allows optional configuration via comments.
781
+ * - Throws an `Error` if 'class' attributes are used without permission.
782
+ * - Supports 'className' attributes for class definitions.
783
+ * - Allows or disallows class-related comments based on your configuration.
784
+ *
785
+ * 3. **Relative Path Handling**: It processes relative paths in 'href' and 'src' attributes, ensuring proper routing.
786
+ * - Converts relative 'href' attributes to anchor links with appropriate routing.
787
+ * - Converts relative 'src' attributes to absolute paths with 'public' directories.
788
+ *
789
+ * 4. **Custom Component Attributes**: It supports adding a 'data-component' attribute to the root element.
790
+ * - Ensures that the 'data-component' attribute is present for component identification.
791
+ *
792
+ * 5. **Lifecycle Method Invocation**: It invokes the `componentDidMount` method if called from a 'render' context.
793
+ * - Executes `componentDidMount` to handle component initialization once the DOM is ready.
794
+ *
795
+ * @see {@link Component}
796
+ * @see {@link Component#componentDidMount}
797
+ */
798
+
799
+ html(strings, ...args) {
800
+ // @ts-ignore
801
+ let timer = setInterval(() => {
802
+ if (document.querySelector(`[data-component="${this.name}"]`)) {
803
+ clearInterval(timer);
804
+ this.componentMounted = true;
805
+
806
+ document
807
+ .querySelector(`[data-component="${this.name}"]`)
808
+ ?.querySelectorAll("*")
809
+ .forEach((element) => {
810
+ if (element.hasAttribute("ref")) {
811
+ // @ts-ignore
812
+ this.dom[element.getAttribute("ref")] = element;
813
+ }
814
+ });
815
+ this.componentDidMount();
816
+ }
817
+ }, 100);
818
+ let script = document.createElement("script");
819
+ script.setAttribute("type", "text/javascript");
820
+ script.setAttribute(`data-component-script`, this.name);
821
+
822
+ worker.postMessage({
823
+ strings,
824
+ args,
825
+ location:
826
+ window.location.origin +
827
+ window.location.pathname.replace(/\/[^\/]*$/, "") +
828
+ "/public/",
829
+ name: this.name
830
+ });
831
+ let promise = new Promise((resolve, reject) => {
832
+ worker.onmessage = (e) => {
833
+ if (e.data.error) {
834
+ throw new Error(e.data.error);
835
+ }
836
+ const dom = this.dom; // Assuming this.dom is an object
837
+ let js = e.data.js;
838
+ let template = e.data.template;
839
+ // Bind the component's context
840
+
841
+ const useState = this.useState.bind(this); // Bind the component's context
842
+ const useEffect = this.useEffect.bind(this); // Bind the component's context
843
+ const useReducer = this.useReducer.bind(this); // Bind the component's context
844
+ const useAuth = this.useAuth.bind(this); // Bind the component's context
845
+ const useSyncStore = this.useSyncStore.bind(this); // Bind the component's context
846
+ const signal = this.signal.bind(this); // Bind the component's context
847
+ const $Function = this.$Function.bind(this); // Bind the component's context
848
+ let states = this.states;
849
+ const useRef = this.useRef.bind(this); // Bind the component's context
850
+ new Function(
851
+ "useState",
852
+ "useEffect",
853
+ "useAuth",
854
+ "useReducer",
855
+ "useSyncStore",
856
+ "signal",
857
+ "$Function",
858
+ "dom",
859
+ "render",
860
+ "states",
861
+ "useRef",
862
+ js
863
+ )(
864
+ useState,
865
+ useEffect,
866
+ useAuth,
867
+ useReducer,
868
+ useSyncStore,
869
+ signal,
870
+ $Function,
871
+ this.dom,
872
+ this.render,
873
+ this.states,
874
+ useRef
875
+ );
876
+
877
+ resolve(
878
+ handletemplate( new Function(
879
+ "useRef",
880
+ "states",
881
+ "signal",
882
+ "useState",
883
+ "useReducer",
884
+ "useAuth",
885
+ "useSyncStore",
886
+ "useRef",
887
+ "$Function",
888
+ "return" + "`" + template + "`"
889
+ )(
890
+ useRef,
891
+ states,
892
+ signal,
893
+ useState,
894
+ useReducer,
895
+ useAuth,
896
+ useSyncStore,
897
+ useRef,
898
+ $Function
899
+ ))
900
+ );
901
+ };
902
+ worker.onerror = (e) => {
903
+ reject(e);
904
+ };
905
+ });
906
+ // @ts-ignore
907
+ return promise;
908
+ }
909
+ // write types to ensure it returns a string
910
+ /**
911
+ * @method render
912
+ * @description Allows you to render html
913
+ * @returns {Promise <any>}
914
+ * @example
915
+ * async render() {
916
+ * return this.html(`
917
+ * <div className="hero p-5">
918
+ * <h1>Home</h1>
919
+ * </div>
920
+ * `);
921
+ */
922
+ async render(props) {}
923
+ }
924
+
925
+ /**
926
+ * @object Vader
927
+ * @property {class} Component
928
+ * @property {function} useRef
929
+ * @description Allows you to create a component
930
+ * @example
931
+ * import { Vader } from "../../dist/vader/vader.js";
932
+ * export class Home extends Vader.Component {
933
+ * constructor() {
934
+ * super('Home');
935
+ * }
936
+ * async render() {
937
+ * return this.html(`
938
+ * <div className="hero p-5">
939
+ * <h1>Home</h1>
940
+ * </div>
941
+ * `);
942
+ * }
943
+ */
944
+ const Vader = {
945
+ /**
946
+ * @class Component
947
+ * @description Allows you to create a component
948
+ * @returns {void}
949
+ * @memberof {Vader}
950
+ * @example
951
+ * import { Vader } from "../../dist/vader/index.js";
952
+ * export class Home extends Vader.Component {
953
+ * constructor() {
954
+ * super();
955
+ * }
956
+ * async render() {
957
+ * return this.html(`
958
+ * <div className="hero p-5">
959
+ * <h1>Home</h1>
960
+ * </div>
961
+ * `);
962
+ * }
963
+ * }
964
+ */
965
+ Component: Component,
966
+ useRef: useRef
967
+ };
968
+ /**
969
+ * @function component
970
+ * @description Allows you to create a component
971
+ * @returns {Component}
972
+ */
973
+ export const component = () => {
974
+ return new Component();
975
+ };
976
+
977
+ /**
978
+ * @function rf
979
+ * @param {*} name
980
+ * @param {*} fn
981
+ * @returns {void}
982
+ * @deprecated - rf has been replaced with Vader.Component.$Function
983
+ * @description Allows you to register function in global scope
984
+ */
985
+ export const rf = (name, fn) => {
986
+ window[name] = fn;
987
+ };
988
+ let cache = {};
989
+ async function handletemplate(data) {
990
+ let dom = new DOMParser().parseFromString(data, "text/html");
991
+ let elements = dom.documentElement.querySelectorAll("*");
992
+
993
+ if (elements.length > 0) {
994
+ for (var i = 0; i < elements.length; i++) {
995
+ if (elements[i].nodeName === "INCLUDE") {
996
+ if (
997
+ !elements[i].getAttribute("src") ||
998
+ elements[i].getAttribute("src") === ""
999
+ ) {
1000
+ throw new Error("Include tag must have src attribute");
1001
+ }
1002
+
1003
+ let componentName = elements[i]
1004
+ .getAttribute("src")
1005
+ ?.split("/")
1006
+ .pop()
1007
+ ?.split(".")[0];
1008
+ // @ts-ignore
1009
+ let filedata = await include(elements[i].getAttribute("src"));
1010
+ // replace ` with \`\` to allow for template literals
1011
+ filedata = filedata.replace(/`/g, "\\`");
1012
+ cache[elements[i].getAttribute("src")] = filedata;
1013
+ filedata = new Function(`return \`${filedata}\`;`)();
1014
+ let newdom = new DOMParser().parseFromString(filedata, "text/html");
1015
+
1016
+ newdom.querySelectorAll("include").forEach((el) => {
1017
+ el.remove();
1018
+ });
1019
+ // @ts-ignore
1020
+
1021
+ let els = dom.querySelectorAll(componentName);
1022
+
1023
+ els.forEach((el) => {
1024
+ if (el.attributes.length > 0) {
1025
+ for (var i = 0; i < el.attributes.length; i++) {
1026
+ // @ts-ignore
1027
+ let t = "{{" + el.attributes[i].name + "}}";
1028
+ if (newdom.body.innerHTML.includes(t)) {
1029
+ // @ts-ignore
1030
+ newdom.body.innerHTML = newdom.body.innerHTML.replaceAll(
1031
+ t,
1032
+ el.attributes[i].value
1033
+ );
1034
+ }
1035
+ }
1036
+ }
1037
+ if (el.children.length > 0 && newdom.body.querySelector("slot")) {
1038
+ for (var i = 0; i < el.children.length; i++) {
1039
+ let slots = newdom.body.querySelectorAll("slot");
1040
+ slots.forEach((slot) => {
1041
+ let id = slot.getAttribute("id");
1042
+
1043
+ if (
1044
+ (el.hasAttribute("key") && el.getAttribute("key") === id) ||
1045
+ (!el.hasAttribute("key") && el.nodeName === id)
1046
+ ) {
1047
+ if (el.children[i].innerHTML.length > 0) {
1048
+ slot.outerHTML = el.children[i].innerHTML;
1049
+ }
1050
+ }
1051
+ });
1052
+ }
1053
+ }
1054
+
1055
+ dom.body.querySelectorAll("include").forEach((el) => {
1056
+ el.remove();
1057
+ });
1058
+ // replace ` with \`\` to allow for template literals
1059
+ dom.body.outerHTML = dom.body.outerHTML.replace(/`/g, "\\`");
1060
+ dom.body.outerHTML = dom.body.outerHTML.replace(
1061
+ el.outerHTML,
1062
+ new Function(`return \`${newdom.body.outerHTML}\`;`)()
1063
+ );
1064
+ });
1065
+ }
1066
+ }
1067
+ }
1068
+
1069
+ // replace ` with \`\` to allow for template literals
1070
+ dom.body.outerHTML = dom.body.outerHTML.replace(/`/g, "\\`");
1071
+ data = new Function(`return \`${dom.body.outerHTML}\`;`)();
1072
+
1073
+ return data;
1074
+ }
1075
+ /**
1076
+ * @function include
1077
+ * @description Allows you to include html file
1078
+ * @returns {Promise} - modified string with html content
1079
+ * @param {string} path
1080
+ */
1081
+
1082
+ export const include = async (path) => {
1083
+ if (
1084
+ path.startsWith("/") &&
1085
+ !path.includes("/src/") &&
1086
+ !document.documentElement.outerHTML
1087
+ .trim()
1088
+ .includes("<!-- #vader-disable_relative-paths -->")
1089
+ ) {
1090
+ path = "/src/" + path;
1091
+ }
1092
+ // @ts-ignore
1093
+ if (cache[path]) {
1094
+ // @ts-ignore
1095
+ return cache[path];
1096
+ } else {
1097
+ return fetch(`./${path}`)
1098
+ .then((res) => {
1099
+ if (res.status === 404) {
1100
+ throw new Error(`No file found at ${path}`);
1101
+ }
1102
+ return res.text();
1103
+ })
1104
+ .then(async (data) => {
1105
+ // @ts-ignore
1106
+ cache[path] = data;
1107
+
1108
+
1109
+
1110
+ return data;
1111
+ });
1112
+ }
1113
+ };
1114
+
1115
+ export default Vader