vaderjs 2.3.5 → 2.3.7
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/config/index.ts +4 -1
- package/index.ts +108 -48
- package/main.js +7 -1
- package/package.json +3 -3
- package/plugins/index.ts +10 -1
package/config/index.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
type Config = {
|
|
1
|
+
export type Config = {
|
|
2
2
|
port: number,
|
|
3
3
|
host?: string,
|
|
4
|
+
plugin_config?: {
|
|
5
|
+
[key: string]: any
|
|
6
|
+
},
|
|
4
7
|
plugins?: any[],
|
|
5
8
|
generateTypes?: boolean,
|
|
6
9
|
host_provider?: 'vercel' | 'netlify' | 'aws' | 'gcp' | 'azure' | 'heroku' | 'custom' | 'apache' | 'none',
|
package/index.ts
CHANGED
|
@@ -104,9 +104,16 @@ function createDom(fiber: Fiber): Node {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
updateDom(dom, {}, fiber.props);
|
|
107
|
+
|
|
108
|
+
// Assign ref if this fiber has a ref prop
|
|
109
|
+
if (fiber.props && fiber.props.ref) {
|
|
110
|
+
fiber.props.ref.current = dom;
|
|
111
|
+
}
|
|
112
|
+
|
|
107
113
|
return dom;
|
|
108
114
|
}
|
|
109
115
|
|
|
116
|
+
|
|
110
117
|
function isSvgElement(fiber: Fiber): boolean {
|
|
111
118
|
// Check if the fiber is an <svg> itself or inside an <svg>
|
|
112
119
|
let parent = fiber.parent;
|
|
@@ -126,11 +133,19 @@ function isSvgElement(fiber: Fiber): boolean {
|
|
|
126
133
|
* @param {object} nextProps - The new properties.
|
|
127
134
|
*/
|
|
128
135
|
function updateDom(dom: Node, prevProps: any, nextProps: any): void {
|
|
129
|
-
|
|
136
|
+
prevProps = prevProps || {};
|
|
130
137
|
nextProps = nextProps || {};
|
|
131
138
|
|
|
132
139
|
const isSvg = dom instanceof SVGElement;
|
|
133
140
|
|
|
141
|
+
// Handle ref updates
|
|
142
|
+
if (prevProps.ref && prevProps.ref !== nextProps.ref) {
|
|
143
|
+
prevProps.ref.current = null;
|
|
144
|
+
}
|
|
145
|
+
if (nextProps.ref && nextProps.ref !== prevProps.ref) {
|
|
146
|
+
nextProps.ref.current = dom;
|
|
147
|
+
}
|
|
148
|
+
|
|
134
149
|
// Remove old or changed event listeners
|
|
135
150
|
Object.keys(prevProps)
|
|
136
151
|
.filter(isEvent)
|
|
@@ -231,18 +246,31 @@ function commitRoot(): void {
|
|
|
231
246
|
* @param {Fiber} fiber - The fiber to commit.
|
|
232
247
|
*/
|
|
233
248
|
function commitWork(fiber: Fiber | null): void {
|
|
234
|
-
if (!fiber)
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
249
|
+
if (!fiber) return;
|
|
237
250
|
|
|
238
251
|
let domParentFiber = fiber.parent;
|
|
239
252
|
while (domParentFiber && !domParentFiber.dom) {
|
|
240
253
|
domParentFiber = domParentFiber.parent;
|
|
241
254
|
}
|
|
242
|
-
const domParent = domParentFiber
|
|
255
|
+
const domParent = domParentFiber?.dom ?? null;
|
|
243
256
|
|
|
244
257
|
if (fiber.effectTag === "PLACEMENT" && fiber.dom != null) {
|
|
245
258
|
if (domParent) domParent.appendChild(fiber.dom);
|
|
259
|
+
|
|
260
|
+
// ⚡ Assign refs immediately when DOM is placed
|
|
261
|
+
if (fiber.props && fiber.props.ref) {
|
|
262
|
+
fiber.props.ref.current = fiber.dom;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Also check for useRef hooks in this fiber
|
|
266
|
+
if (fiber.hooks) {
|
|
267
|
+
for (const hook of fiber.hooks) {
|
|
268
|
+
if ("current" in hook && !hook._isRef && fiber.dom) {
|
|
269
|
+
// This is likely a DOM ref hook
|
|
270
|
+
hook.current = fiber.dom;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
246
274
|
} else if (fiber.effectTag === "UPDATE" && fiber.dom != null) {
|
|
247
275
|
updateDom(fiber.dom, fiber.alternate?.props ?? {}, fiber.props);
|
|
248
276
|
} else if (fiber.effectTag === "DELETION") {
|
|
@@ -253,14 +281,21 @@ function commitWork(fiber: Fiber | null): void {
|
|
|
253
281
|
commitWork(fiber.sibling);
|
|
254
282
|
}
|
|
255
283
|
|
|
284
|
+
|
|
256
285
|
/**
|
|
257
286
|
* Recursively removes a fiber and its children from the DOM.
|
|
258
287
|
* @param {Fiber} fiber - The fiber to remove.
|
|
259
288
|
*/
|
|
260
|
-
function commitDeletion(fiber: Fiber | null): void {
|
|
289
|
+
function commitDeletion(fiber: Fiber | null): void {
|
|
261
290
|
if (!fiber) {
|
|
262
291
|
return;
|
|
263
292
|
}
|
|
293
|
+
|
|
294
|
+
// Clear refs when element is removed
|
|
295
|
+
if (fiber.props && fiber.props.ref) {
|
|
296
|
+
fiber.props.ref.current = null;
|
|
297
|
+
}
|
|
298
|
+
|
|
264
299
|
if (fiber.dom) {
|
|
265
300
|
if (fiber.dom.parentNode) {
|
|
266
301
|
fiber.dom.parentNode.removeChild(fiber.dom);
|
|
@@ -346,29 +381,38 @@ function performUnitOfWork(fiber: Fiber): Fiber | null {
|
|
|
346
381
|
* Updates a function component fiber.
|
|
347
382
|
* @param {Fiber} fiber - The function component fiber to update.
|
|
348
383
|
*/
|
|
349
|
-
|
|
384
|
+
function updateFunctionComponent(fiber: Fiber) {
|
|
350
385
|
wipFiber = fiber;
|
|
351
386
|
hookIndex = 0;
|
|
352
387
|
fiber.hooks = fiber.alternate?.hooks || [];
|
|
353
388
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
const children = [(fiber.type as Function)(fiber.props)]
|
|
357
|
-
.flat()
|
|
358
|
-
.filter(child => child != null && typeof child !== 'boolean')
|
|
359
|
-
.map(child => typeof child === 'object' ? child : createTextElement(child));
|
|
389
|
+
const rawChildren = (fiber.type as Function)(fiber.props);
|
|
390
|
+
const children = normalizeChildren(rawChildren, fiber);
|
|
360
391
|
|
|
361
392
|
reconcileChildren(fiber, children);
|
|
362
393
|
}
|
|
394
|
+
function normalizeChildren(children: any, parentFiber: Fiber): VNode[] {
|
|
395
|
+
if (!children) return [];
|
|
396
|
+
let arr = Array.isArray(children) ? children : [children];
|
|
397
|
+
|
|
398
|
+
return arr.flatMap((child, index) => {
|
|
399
|
+
if (child == null || typeof child === "boolean") return [];
|
|
400
|
+
if (typeof child === "string" || typeof child === "number") return [createTextElement(String(child))];
|
|
401
|
+
|
|
402
|
+
// Ensure every child has a stable key
|
|
403
|
+
const key = child.key ?? child.props?.id ?? `${parentFiber.key ?? "root"}-${index}`;
|
|
404
|
+
return [{ ...child, key }];
|
|
405
|
+
});
|
|
406
|
+
}
|
|
363
407
|
/**
|
|
364
408
|
* Updates a host component fiber (DOM element).
|
|
365
409
|
* @param {Fiber} fiber - The host component fiber to update.
|
|
366
410
|
*/
|
|
367
411
|
function updateHostComponent(fiber: Fiber): void {
|
|
368
|
-
if (!fiber.dom)
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
reconcileChildren(fiber,
|
|
412
|
+
if (!fiber.dom) fiber.dom = createDom(fiber);
|
|
413
|
+
|
|
414
|
+
const children = normalizeChildren(fiber.props.children, fiber);
|
|
415
|
+
reconcileChildren(fiber, children);
|
|
372
416
|
}
|
|
373
417
|
|
|
374
418
|
/**
|
|
@@ -376,12 +420,11 @@ function updateHostComponent(fiber: Fiber): void {
|
|
|
376
420
|
* @param {Fiber} wipFiber - The work-in-progress fiber.
|
|
377
421
|
* @param {VNode[]} elements - The new child elements.
|
|
378
422
|
*/
|
|
379
|
-
|
|
423
|
+
function reconcileChildren(wipFiber: Fiber, elements: VNode[]) {
|
|
380
424
|
let index = 0;
|
|
381
425
|
let oldFiber = wipFiber.alternate?.child;
|
|
382
426
|
let prevSibling: Fiber | null = null;
|
|
383
|
-
|
|
384
|
-
// Create map of existing fibers by key
|
|
427
|
+
|
|
385
428
|
const existingFibers = new Map<string | number | null, Fiber>();
|
|
386
429
|
while (oldFiber) {
|
|
387
430
|
const key = oldFiber.key ?? index;
|
|
@@ -393,23 +436,21 @@ function updateHostComponent(fiber: Fiber): void {
|
|
|
393
436
|
index = 0;
|
|
394
437
|
for (; index < elements.length; index++) {
|
|
395
438
|
const element = elements[index];
|
|
396
|
-
const key = element
|
|
439
|
+
const key = element.key ?? index;
|
|
397
440
|
const oldFiber = existingFibers.get(key);
|
|
398
|
-
|
|
441
|
+
|
|
399
442
|
const sameType = oldFiber && element && element.type === oldFiber.type;
|
|
400
443
|
let newFiber: Fiber | null = null;
|
|
401
444
|
|
|
402
445
|
if (sameType) {
|
|
403
|
-
// Reuse
|
|
446
|
+
// Reuse old fiber for same type + key
|
|
404
447
|
newFiber = {
|
|
405
|
-
|
|
448
|
+
...oldFiber,
|
|
406
449
|
props: element.props,
|
|
407
|
-
dom: oldFiber.dom,
|
|
408
450
|
parent: wipFiber,
|
|
409
451
|
alternate: oldFiber,
|
|
410
452
|
effectTag: "UPDATE",
|
|
411
|
-
|
|
412
|
-
key
|
|
453
|
+
_needsUpdate: false,
|
|
413
454
|
};
|
|
414
455
|
existingFibers.delete(key);
|
|
415
456
|
} else if (element) {
|
|
@@ -421,7 +462,8 @@ function updateHostComponent(fiber: Fiber): void {
|
|
|
421
462
|
parent: wipFiber,
|
|
422
463
|
alternate: null,
|
|
423
464
|
effectTag: "PLACEMENT",
|
|
424
|
-
key
|
|
465
|
+
key,
|
|
466
|
+
_needsUpdate: true,
|
|
425
467
|
};
|
|
426
468
|
}
|
|
427
469
|
|
|
@@ -436,9 +478,7 @@ function updateHostComponent(fiber: Fiber): void {
|
|
|
436
478
|
prevSibling.sibling = newFiber;
|
|
437
479
|
}
|
|
438
480
|
|
|
439
|
-
if (newFiber)
|
|
440
|
-
prevSibling = newFiber;
|
|
441
|
-
}
|
|
481
|
+
if (newFiber) prevSibling = newFiber;
|
|
442
482
|
}
|
|
443
483
|
|
|
444
484
|
// Mark remaining old fibers for deletion
|
|
@@ -455,23 +495,17 @@ function updateHostComponent(fiber: Fiber): void {
|
|
|
455
495
|
* @param {...any} children - The element's children.
|
|
456
496
|
* @returns {VNode} The created virtual DOM element.
|
|
457
497
|
*/
|
|
458
|
-
export function createElement(
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
)
|
|
498
|
+
export function createElement(type: string | Function, props?: any, ...children: any[]): VNode {
|
|
499
|
+
const rawChildren = children.flat().filter(c => c != null && typeof c !== "boolean");
|
|
500
|
+
const normalizedChildren = rawChildren.map((child, i) => {
|
|
501
|
+
if (typeof child === "object") return child;
|
|
502
|
+
return createTextElement(String(child));
|
|
503
|
+
});
|
|
504
|
+
|
|
463
505
|
return {
|
|
464
506
|
type,
|
|
465
|
-
props: {
|
|
466
|
-
|
|
467
|
-
children: children
|
|
468
|
-
.flat()
|
|
469
|
-
.filter(child => child != null && typeof child !== "boolean")
|
|
470
|
-
.map(child =>
|
|
471
|
-
typeof child === "object" ? child : createTextElement(child)
|
|
472
|
-
),
|
|
473
|
-
},
|
|
474
|
-
key: props?.key ?? null,
|
|
507
|
+
props: { ...props, children: normalizedChildren },
|
|
508
|
+
key: props?.key ?? props?.id ?? null,
|
|
475
509
|
};
|
|
476
510
|
}
|
|
477
511
|
|
|
@@ -598,10 +632,36 @@ export function Switch({ children }: { children: VNode[] }): VNode | null {
|
|
|
598
632
|
export function Match({ when, children }: { when: boolean, children: VNode[] }): VNode | null {
|
|
599
633
|
return when ? children : null;
|
|
600
634
|
}
|
|
601
|
-
|
|
635
|
+
/**
|
|
636
|
+
* Wraps a functional component into a VNode for Vader.js rendering.
|
|
637
|
+
* @param {Function} fn - The function component to wrap.
|
|
638
|
+
* @returns {Function} A function that creates a VNode when called with props.
|
|
639
|
+
*/
|
|
640
|
+
export function component<P extends object>(
|
|
641
|
+
fn: (props: P) => VNode | VNode[]
|
|
642
|
+
): (props: P & { key?: string | number }) => VNode {
|
|
643
|
+
return (props: P & { key?: string | number }) => {
|
|
644
|
+
return createElement(fn, props);
|
|
645
|
+
};
|
|
646
|
+
}
|
|
602
647
|
export function Show({ when, children }: { when: boolean, children: VNode[] }): VNode | null {
|
|
603
648
|
return when ? children : null;
|
|
604
649
|
}
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* For TypeScript to recognize your JSX factory,
|
|
653
|
+
* you often need the global namespace declaration as well:
|
|
654
|
+
*/
|
|
655
|
+
declare global {
|
|
656
|
+
namespace JSX {
|
|
657
|
+
interface IntrinsicElements {
|
|
658
|
+
[elemName: string]: any;
|
|
659
|
+
}
|
|
660
|
+
interface Element {
|
|
661
|
+
[key: string]: any;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
605
665
|
|
|
606
666
|
/**
|
|
607
667
|
* A React-like useRef hook for mutable references.
|
|
@@ -616,7 +676,7 @@ export function useRef<T>(initial: T): { current: T } {
|
|
|
616
676
|
|
|
617
677
|
let hook = wipFiber.hooks[hookIndex];
|
|
618
678
|
if (!hook) {
|
|
619
|
-
hook = { current: initial };
|
|
679
|
+
hook = { current: initial, _isRef: true };
|
|
620
680
|
wipFiber.hooks[hookIndex] = hook;
|
|
621
681
|
}
|
|
622
682
|
|
package/main.js
CHANGED
|
@@ -75,7 +75,13 @@ const vaderAPI = {
|
|
|
75
75
|
await p.exited;
|
|
76
76
|
},
|
|
77
77
|
injectHTML: (content) => htmlInjections.push(content),
|
|
78
|
-
log:
|
|
78
|
+
log: {
|
|
79
|
+
warn: (msg) => logger.warn(msg),
|
|
80
|
+
info: (msg) => logger.info(msg),
|
|
81
|
+
error: (msg) => logger.error(msg),
|
|
82
|
+
success: (msg) => logger.success(msg),
|
|
83
|
+
step: (msg) => logger.step(msg)
|
|
84
|
+
},
|
|
79
85
|
getProjectRoot: () => PROJECT_ROOT,
|
|
80
86
|
getDistDir: () => DIST_DIR,
|
|
81
87
|
getPublicDir: () => PUBLIC_DIR,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vaderjs",
|
|
3
|
-
"version": "2.3.
|
|
4
|
-
"description": "A simple and powerful JavaScript library for building modern web applications.",
|
|
3
|
+
"version": "2.3.7",
|
|
4
|
+
"description": "A simple and powerful JavaScript library for building modern web applications.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"vaderjs": "./main.js"
|
|
7
7
|
},
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"type": "git",
|
|
10
10
|
"url": "https://github.com/Postr-Inc/Vader.js"
|
|
11
11
|
},
|
|
12
|
-
"license":"MIT",
|
|
12
|
+
"license": "MIT",
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"ansi-colors": "latest"
|
|
15
15
|
}
|
package/plugins/index.ts
CHANGED
|
@@ -9,7 +9,13 @@ export interface VaderAPI {
|
|
|
9
9
|
injectHTML(content: string): void;
|
|
10
10
|
|
|
11
11
|
/** Log a message prefixed with [Vader Plugin] */
|
|
12
|
-
log
|
|
12
|
+
log : {
|
|
13
|
+
warn: (msg: any) => void,
|
|
14
|
+
info: (msg: any) => void,
|
|
15
|
+
error: (msg: any) => void,
|
|
16
|
+
success: (msg: any) => void,
|
|
17
|
+
step: (msg: any) => void
|
|
18
|
+
}
|
|
13
19
|
|
|
14
20
|
/** Get absolute path to the project root */
|
|
15
21
|
getProjectRoot(): string;
|
|
@@ -33,6 +39,9 @@ export type PluginHookName =
|
|
|
33
39
|
|
|
34
40
|
/** Interface for a single plugin */
|
|
35
41
|
export interface VaderPlugin {
|
|
42
|
+
name: string;
|
|
43
|
+
description: string;
|
|
44
|
+
version: string;
|
|
36
45
|
/** Called before build starts */
|
|
37
46
|
onBuildStart?(api: VaderAPI): Promise<void> | void;
|
|
38
47
|
|