@zenithbuild/core 0.4.6 → 0.5.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenithbuild/core",
3
- "version": "0.4.6",
3
+ "version": "0.5.0",
4
4
  "description": "Core library for the Zenith framework",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -61,7 +61,9 @@
61
61
  "dependencies": {
62
62
  "@types/marked": "^6.0.0",
63
63
  "@types/parse5": "^7.0.0",
64
+ "es-module-lexer": "^2.0.0",
64
65
  "marked": "^17.0.1",
65
- "parse5": "^8.0.0"
66
+ "parse5": "^8.0.0",
67
+ "picocolors": "^1.1.1"
66
68
  }
67
69
  }
@@ -282,6 +282,144 @@ export function generateBundleJS(): string {
282
282
  unmountCallbacks.length = 0;
283
283
  }
284
284
 
285
+ // ============================================
286
+ // Component Instance System
287
+ // ============================================
288
+ // Each component instance gets isolated state, effects, and lifecycles
289
+ // Instances are tied to DOM elements via hydration markers
290
+
291
+ const componentRegistry = {};
292
+
293
+ function createComponentInstance(componentName, rootElement) {
294
+ const instanceMountCallbacks = [];
295
+ const instanceUnmountCallbacks = [];
296
+ const instanceEffects = [];
297
+ let instanceMounted = false;
298
+
299
+ return {
300
+ // DOM reference
301
+ root: rootElement,
302
+
303
+ // Lifecycle hooks (instance-scoped)
304
+ onMount: function(fn) {
305
+ if (instanceMounted) {
306
+ const cleanup = fn();
307
+ if (typeof cleanup === 'function') {
308
+ instanceUnmountCallbacks.push(cleanup);
309
+ }
310
+ } else {
311
+ instanceMountCallbacks.push(fn);
312
+ }
313
+ },
314
+ onUnmount: function(fn) {
315
+ instanceUnmountCallbacks.push(fn);
316
+ },
317
+
318
+ // Reactivity (uses global primitives but tracks for cleanup)
319
+ signal: function(initial) {
320
+ return zenSignal(initial);
321
+ },
322
+ state: function(initial) {
323
+ return zenState(initial);
324
+ },
325
+ ref: function(initial) {
326
+ return zenRef(initial);
327
+ },
328
+ effect: function(fn) {
329
+ const cleanup = zenEffect(fn);
330
+ instanceEffects.push(cleanup);
331
+ return cleanup;
332
+ },
333
+ memo: function(fn) {
334
+ return zenMemo(fn);
335
+ },
336
+ batch: function(fn) {
337
+ zenBatch(fn);
338
+ },
339
+ untrack: function(fn) {
340
+ return zenUntrack(fn);
341
+ },
342
+
343
+ // Lifecycle execution
344
+ mount: function() {
345
+ instanceMounted = true;
346
+ for (let i = 0; i < instanceMountCallbacks.length; i++) {
347
+ try {
348
+ const cleanup = instanceMountCallbacks[i]();
349
+ if (typeof cleanup === 'function') {
350
+ instanceUnmountCallbacks.push(cleanup);
351
+ }
352
+ } catch(e) {
353
+ console.error('[Zenith] Component mount error:', componentName, e);
354
+ }
355
+ }
356
+ instanceMountCallbacks.length = 0;
357
+ },
358
+ unmount: function() {
359
+ instanceMounted = false;
360
+ // Cleanup effects
361
+ for (let i = 0; i < instanceEffects.length; i++) {
362
+ try {
363
+ if (typeof instanceEffects[i] === 'function') instanceEffects[i]();
364
+ } catch(e) {
365
+ console.error('[Zenith] Effect cleanup error:', e);
366
+ }
367
+ }
368
+ instanceEffects.length = 0;
369
+ // Run unmount callbacks
370
+ for (let i = 0; i < instanceUnmountCallbacks.length; i++) {
371
+ try { instanceUnmountCallbacks[i](); } catch(e) { console.error('[Zenith] Unmount error:', e); }
372
+ }
373
+ instanceUnmountCallbacks.length = 0;
374
+ }
375
+ };
376
+ }
377
+
378
+ function defineComponent(name, factory) {
379
+ componentRegistry[name] = factory;
380
+ }
381
+
382
+ function instantiateComponent(name, props, rootElement) {
383
+ const factory = componentRegistry[name];
384
+ if (!factory) {
385
+ console.warn('[Zenith] Component not found:', name);
386
+ return null;
387
+ }
388
+ return factory(props, rootElement);
389
+ }
390
+
391
+ /**
392
+ * Hydrate components by discovering data-zen-component markers
393
+ * This is the ONLY place component instantiation should happen
394
+ */
395
+ function hydrateComponents(container) {
396
+ const componentElements = container.querySelectorAll('[data-zen-component]');
397
+
398
+ for (let i = 0; i < componentElements.length; i++) {
399
+ const el = componentElements[i];
400
+ const componentName = el.getAttribute('data-zen-component');
401
+
402
+ // Skip if already hydrated
403
+ if (el.__zenith_instance) continue;
404
+
405
+ // Parse props from data attribute if present
406
+ const propsJson = el.getAttribute('data-zen-props') || '{}';
407
+ let props = {};
408
+ try {
409
+ props = JSON.parse(propsJson);
410
+ } catch(e) {
411
+ console.warn('[Zenith] Invalid props JSON for', componentName);
412
+ }
413
+
414
+ // Instantiate component and bind to DOM element
415
+ const instance = instantiateComponent(componentName, props, el);
416
+
417
+ if (instance) {
418
+ el.__zenith_instance = instance;
419
+ }
420
+ }
421
+ }
422
+
285
423
  // ============================================
286
424
  // Expression Registry & Hydration
287
425
  // ============================================
@@ -701,8 +839,13 @@ export function generateBundleJS(): string {
701
839
  triggerUnmount: triggerUnmount,
702
840
  // Hydration
703
841
  hydrate: zenithHydrate,
842
+ hydrateComponents: hydrateComponents, // Marker-driven component instantiation
704
843
  registerExpression: registerExpression,
705
- getExpression: getExpression
844
+ getExpression: getExpression,
845
+ // Component instance system
846
+ createInstance: createComponentInstance,
847
+ defineComponent: defineComponent,
848
+ instantiate: instantiateComponent
706
849
  };
707
850
 
708
851
  // Expose with zen* prefix for direct usage