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 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
- prevProps = prevProps || {};
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 ? domParentFiber.dom : null;
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
- function updateFunctionComponent(fiber: Fiber) {
384
+ function updateFunctionComponent(fiber: Fiber) {
350
385
  wipFiber = fiber;
351
386
  hookIndex = 0;
352
387
  fiber.hooks = fiber.alternate?.hooks || [];
353
388
 
354
- // Directly call the component function without memoization
355
- // The 'createComponent' call is removed.
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
- fiber.dom = createDom(fiber);
370
- }
371
- reconcileChildren(fiber, fiber.props.children);
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
- function reconcileChildren(wipFiber: Fiber, elements: VNode[]) {
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?.key ?? index;
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 the fiber
446
+ // Reuse old fiber for same type + key
404
447
  newFiber = {
405
- type: oldFiber.type,
448
+ ...oldFiber,
406
449
  props: element.props,
407
- dom: oldFiber.dom,
408
450
  parent: wipFiber,
409
451
  alternate: oldFiber,
410
452
  effectTag: "UPDATE",
411
- hooks: oldFiber.hooks,
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
- type: string | Function,
460
- props?: object,
461
- ...children: any[]
462
- ): VNode {
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
- ...props,
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: (msg) => logger.info(`[Plugin] ${msg}`),
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.5",
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(msg: string): void;
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