@cruxjs/client 0.1.1 → 0.1.2

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 CHANGED
@@ -8,7 +8,7 @@
8
8
  </div>
9
9
 
10
10
  <div align="center">
11
- <img src="https://img.shields.io/badge/v-0.1.1-black"/>
11
+ <img src="https://img.shields.io/badge/v-0.1.2-black"/>
12
12
  <a href="https://github.com/cruxjs-org"><img src="https://img.shields.io/badge/🔥-@cruxjs-black"/></a>
13
13
  <br>
14
14
  <img src="https://img.shields.io/badge/coverage-~%25-brightgreen" alt="Test Coverage" />
@@ -140,8 +140,8 @@
140
140
  <h1>My App</h1>
141
141
  <nav>{/* navigation */}</nav>
142
142
  </header>
143
- <main data-page-slot></main>
144
- {/* Pages are rendered in [data-page-slot] */}
143
+ <main id="main-overlay"></main>
144
+ {/* Pages are rendered in #main-overlay */}
145
145
  <footer class="app-footer">
146
146
  <p>© 2026 My App</p>
147
147
  </footer>
@@ -155,7 +155,7 @@
155
155
  };
156
156
  ```
157
157
 
158
- > The `rootLayout` is rendered once and pages are mounted inside the element with `data-page-slot` attribute. This allows you to have persistent headers, footers, navigation, and modals that don't remount when routes change.
158
+ > The `rootLayout` is rendered once and pages are mounted inside the element with `#main-overlay` attribute. This allows you to have persistent headers, footers, navigation, and modals that don't remount when routes change.
159
159
 
160
160
  - #### Lifecycle Hooks
161
161
 
@@ -425,7 +425,7 @@
425
425
  return (
426
426
  <div class="app-container">
427
427
  <header>Header Content</header>
428
- <main data-page-slot></main>
428
+ <main id="main-overlay"></main>
429
429
  <footer>Footer Content</footer>
430
430
  </div>
431
431
  );
@@ -589,7 +589,7 @@
589
589
 
590
590
  > Mount router to DOM element with optional root layout
591
591
  > Sets up reactive routing, mounts root layout if provided, and initial render
592
- > Pages render inside `[data-page-slot]` if rootLayout exists, otherwise in the selector
592
+ > Pages render inside `#main-overlay` if rootLayout exists, otherwise in the selector
593
593
 
594
594
  ```typescript
595
595
  manager.mount('body');
@@ -857,7 +857,7 @@
857
857
  return (
858
858
  <div>
859
859
  <header>Persistent Header</header>
860
- <main data-page-slot></main>
860
+ <main id="main-overlay"></main>
861
861
  <footer>Persistent Footer</footer>
862
862
  </div>
863
863
  );
@@ -865,7 +865,7 @@
865
865
 
866
866
  const config = {
867
867
  routes: { /* ... */ },
868
- rootLayout: AppLayout, // Pages render inside [data-page-slot]
868
+ rootLayout: AppLayout, // Pages render inside #main-overlay
869
869
  };
870
870
 
871
871
  // ❌ DON'T: Create layout inside each page
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var signals=require('@minejs/signals'),i18n=require('@minejs/i18n'),jsx=require('@minejs/jsx'),browser=require('@minejs/browser');var h,s=class{constructor(e){this.lifecycle="booting";this.hooks={};this.plugins=[];this.routeComponents={};this.currentPathSignal=signals.signal(window.location.pathname??"/");this.config=e,this.debug=e.debug??false,this.log("[INIT] Creating ClientManager"),e.lifecycle&&(this.hooks={...e.lifecycle}),this.plugins=e.plugins??[],this.routeComponents=e.routes,this.eventsManager=new browser.EventsManager,this.windowManager=new browser.WindowManager;let t=Object.entries(e.routes).map(([n,o])=>({path:n,component:o}));this.router=browser.createRouter({routes:t,notFoundComponent:e.notFoundComponent}),this.router.afterEach(n=>{this.currentPathSignal.set(n.path);}),h=this,this.log("[INIT] ClientManager created");}on(e,t,n,o){return typeof e=="string"&&e.startsWith("on")?(this.hooks[e]=t,this):this.eventsManager.on(e,t,n,o)}async boot(){if(this.lifecycle!=="booting"){console.warn("[ClientManager] Already booted or destroyed");return}this.log("\u26A1 Phase: BOOT");try{for(let e of this.plugins)e.onBoot&&(this.log(`\u2192 Plugin onBoot: ${e.name}`),await e.onBoot({debug:this.debug,config:this.config}));this.hooks.onBoot&&(this.log("\u2192 Calling onBoot hook"),await this.hooks.onBoot()),this.log("\u2713 BOOT phase complete");}catch(e){throw console.error("[ClientManager] Boot failed:",e),e}}async ready(){if(this.lifecycle!=="booting"){console.warn("[ClientManager] Cannot ready - not in booting phase");return}this.log("\u26A1 Phase: READY");try{let e="body";document.querySelector(e).id="root",this.mount(e),this.log("\u2192 Router mounted");for(let t of this.plugins)t.onReady&&(this.log(`\u2192 Plugin onReady: ${t.name}`),await t.onReady({debug:this.debug,config:this.config}));this.hooks.onReady&&(this.log("\u2192 Calling onReady hook"),await this.hooks.onReady()),this.lifecycle="ready",this.log("\u2713 READY phase complete"),this.log("\u2713 App is ready!");}catch(e){throw console.error("[ClientManager] Ready failed:",e),e}}async destroy(){if(this.lifecycle==="destroyed"){console.warn("[ClientManager] Already destroyed");return}this.lifecycle="destroying",this.log("\u26A1 Phase: DESTROY");try{for(let e=this.plugins.length-1;e>=0;e--){let t=this.plugins[e];t.onDestroy&&(this.log(`\u2192 Plugin onDestroy: ${t.name}`),await t.onDestroy({debug:this.debug,config:this.config}));}this.hooks.onDestroy&&(this.log("\u2192 Calling onDestroy hook"),await this.hooks.onDestroy()),this.eventsManager.destroy(),this.windowManager.destroy(),this.lifecycle="destroyed",this.log("\u2713 DESTROY phase complete");}catch(e){throw console.error("[ClientManager] Destroy failed:",e),e}}navigate(e){this.router.push(e);}mount(e){let t=typeof e=="string"?document.querySelector(e):e;if(!t){console.warn("[ClientManager] Mount target not found:",e);return}let n=t;if(this.config.rootLayout)try{let o=this.config.rootLayout();if(o){jsx.mount(o,t),this.log("\u2192 Root layout mounted");let r=t.querySelector("[data-page-slot]");r?n=r:console.warn("[ClientManager] Page slot [data-page-slot] not found in root layout. Pages will render to the root container.");}}catch(o){console.error("[ClientManager] Error rendering root layout:",o),t.innerHTML="<p>Error loading root layout</p>";return}signals.effect(()=>{let o=this.currentPathSignal(),r=this.routeComponents[o]||this.config.notFoundComponent||null;if(n.innerHTML="",r)try{let a=r();a&&jsx.mount(a,n);}catch(a){console.error("[ClientManager] Error rendering component:",o,a),n.innerHTML="<p>Error loading component</p>";}else n.innerHTML="<p>No component found for this route</p>";this.log(`\u2192 Route changed to: ${o}`);}),this.router.push(this.currentPathSignal()),this.log("\u2192 Routing setup complete");}getCurrentPath(){return this.currentPathSignal}createLinkHandler(e){return t=>{t.preventDefault(),this.navigate(e);}}getRouter(){return this.router}off(e,t,n){this.eventsManager.off(e,t,n);}getEventsManager(){return this.eventsManager}getViewport(){return this.windowManager.getViewport()}getWindowManager(){return this.windowManager}getI18n(){return i18n.getI18n()}t(e,t){let n=i18n.getI18n();return n?n.t(e)??t??e:(console.warn("[ClientManager] i18n not initialized. Using default value or key."),t??e)}getPhase(){return this.lifecycle}isReady(){return this.lifecycle==="ready"}log(e){this.debug&&console.log(`[ClientManager] ${e}`);}};function E(){return h}async function b(i){let e=document.querySelector('meta[name="app-i18n"]');if(e){let n=JSON.parse(e.getAttribute("content")||"{}");i.i18n=n;}let t=new s(i);return await i18n.setupI18n(i.i18n||{defaultLanguage:"en",supportedLanguages:["en"]}),t.boot(),t.ready(),window.addEventListener("beforeunload",async()=>{await t.destroy();}),t}Object.defineProperty(exports,"t",{enumerable:true,get:function(){return i18n.t}});exports.ClientManager=s;exports.getGlobalClientManager=E;exports.start=b;//# sourceMappingURL=index.cjs.map
1
+ 'use strict';var signals=require('@minejs/signals'),i18n=require('@minejs/i18n'),jsx=require('@minejs/jsx'),browser=require('@minejs/browser');var h,s=class{constructor(e){this.lifecycle="booting";this.hooks={};this.plugins=[];this.routeComponents={};this.currentPathSignal=signals.signal(window.location.pathname??"/");this.config=e,this.debug=e.debug??false,this.log("[INIT] Creating ClientManager"),e.lifecycle&&(this.hooks={...e.lifecycle}),this.plugins=e.plugins??[],this.routeComponents=e.routes,this.eventsManager=new browser.EventsManager,this.windowManager=new browser.WindowManager;let t=Object.entries(e.routes).map(([n,o])=>({path:n,component:o}));this.router=browser.createRouter({routes:t,notFoundComponent:e.notFoundComponent}),this.router.afterEach(n=>{this.currentPathSignal.set(n.path);}),h=this,this.log("[INIT] ClientManager created");}on(e,t,n,o){return typeof e=="string"&&e.startsWith("on")?(this.hooks[e]=t,this):this.eventsManager.on(e,t,n,o)}async boot(){if(this.lifecycle!=="booting"){console.warn("[ClientManager] Already booted or destroyed");return}this.log("\u26A1 Phase: BOOT");try{for(let e of this.plugins)e.onBoot&&(this.log(`\u2192 Plugin onBoot: ${e.name}`),await e.onBoot({debug:this.debug,config:this.config}));this.hooks.onBoot&&(this.log("\u2192 Calling onBoot hook"),await this.hooks.onBoot()),this.log("\u2713 BOOT phase complete");}catch(e){throw console.error("[ClientManager] Boot failed:",e),e}}async ready(){if(this.lifecycle!=="booting"){console.warn("[ClientManager] Cannot ready - not in booting phase");return}this.log("\u26A1 Phase: READY");try{let e="body";document.querySelector(e).id="root",this.mount(e),this.log("\u2192 Router mounted");for(let t of this.plugins)t.onReady&&(this.log(`\u2192 Plugin onReady: ${t.name}`),await t.onReady({debug:this.debug,config:this.config}));this.hooks.onReady&&(this.log("\u2192 Calling onReady hook"),await this.hooks.onReady()),this.lifecycle="ready",this.log("\u2713 READY phase complete"),this.log("\u2713 App is ready!");}catch(e){throw console.error("[ClientManager] Ready failed:",e),e}}async destroy(){if(this.lifecycle==="destroyed"){console.warn("[ClientManager] Already destroyed");return}this.lifecycle="destroying",this.log("\u26A1 Phase: DESTROY");try{for(let e=this.plugins.length-1;e>=0;e--){let t=this.plugins[e];t.onDestroy&&(this.log(`\u2192 Plugin onDestroy: ${t.name}`),await t.onDestroy({debug:this.debug,config:this.config}));}this.hooks.onDestroy&&(this.log("\u2192 Calling onDestroy hook"),await this.hooks.onDestroy()),this.eventsManager.destroy(),this.windowManager.destroy(),this.lifecycle="destroyed",this.log("\u2713 DESTROY phase complete");}catch(e){throw console.error("[ClientManager] Destroy failed:",e),e}}navigate(e){this.router.push(e);}mount(e){let t=typeof e=="string"?document.querySelector(e):e;if(!t){console.warn("[ClientManager] Mount target not found:",e);return}let n=t;if(this.config.rootLayout)try{let o=this.config.rootLayout();if(o){jsx.mount(o,t),this.log("\u2192 Root layout mounted");let r=t.querySelector("#main-overlay");r?n=r:console.warn("[ClientManager] Page slot #main-overlay not found in root layout. Pages will render to the root container.");}}catch(o){console.error("[ClientManager] Error rendering root layout:",o),t.innerHTML="<p>Error loading root layout</p>";return}signals.effect(()=>{let o=this.currentPathSignal(),r=this.routeComponents[o]||this.config.notFoundComponent||null;if(n.innerHTML="",r)try{let a=r();a&&jsx.mount(a,n);}catch(a){console.error("[ClientManager] Error rendering component:",o,a),n.innerHTML="<p>Error loading component</p>";}else n.innerHTML="<p>No component found for this route</p>";this.log(`\u2192 Route changed to: ${o}`);}),this.router.push(this.currentPathSignal()),this.log("\u2192 Routing setup complete");}getCurrentPath(){return this.currentPathSignal}createLinkHandler(e){return t=>{t.preventDefault(),this.navigate(e);}}getRouter(){return this.router}off(e,t,n){this.eventsManager.off(e,t,n);}getEventsManager(){return this.eventsManager}getViewport(){return this.windowManager.getViewport()}getWindowManager(){return this.windowManager}getI18n(){return i18n.getI18n()}t(e,t){let n=i18n.getI18n();return n?n.t(e)??t??e:(console.warn("[ClientManager] i18n not initialized. Using default value or key."),t??e)}getPhase(){return this.lifecycle}isReady(){return this.lifecycle==="ready"}log(e){this.debug&&console.log(`[ClientManager] ${e}`);}};function E(){return h}async function b(i){let e=document.querySelector('meta[name="app-i18n"]');if(e){let n=JSON.parse(e.getAttribute("content")||"{}");i.i18n=n;}let t=new s(i);return await i18n.setupI18n(i.i18n||{defaultLanguage:"en",supportedLanguages:["en"]}),t.boot(),t.ready(),window.addEventListener("beforeunload",async()=>{await t.destroy();}),t}Object.defineProperty(exports,"t",{enumerable:true,get:function(){return i18n.t}});exports.ClientManager=s;exports.getGlobalClientManager=E;exports.start=b;//# sourceMappingURL=index.cjs.map
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["globalClientManagerInstance","ClientManager","config","signal","EventsManager","WindowManager","routesArray","path","component","createRouter","to","eventOrTarget","callbackOrEvent","handler","options","plugin","err","selector","i","container","pageContainer","layoutJsx","mountJSX","pageSlot","effect","currentPath","Component","jsx","e","target","event","getI18n","key","defaultValue","i18n","message","getGlobalClientManager","start","metaI18n","i18nData","manager","setupI18n"],"mappings":"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","file":"index.cjs","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\r\n// src/index.ts\r\n//\r\n// Made with ❤️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import * as types from './types';\r\n import { signal, effect } from '@minejs/signals';\r\n import { setupI18n, getI18n } from '@minejs/i18n';\r\n import { mount as mountJSX } from '@minejs/jsx';\r\n import { EventsManager, Router, WindowManager, createRouter } from '@minejs/browser';\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ CORE ════════════════════════════════════════╗\r\n\r\n let globalClientManagerInstance: ClientManager | undefined;\r\n\r\n export class ClientManager {\r\n\r\n // ┌──────────────────────────────── INIT ──────────────────────────────┐\r\n\r\n private router : Router;\r\n private eventsManager : EventsManager;\r\n private windowManager : WindowManager;\r\n private lifecycle : 'booting' | 'ready' | 'destroying' | 'destroyed' = 'booting';\r\n private config : types.ClientManagerConfig;\r\n private hooks : types.ClientManagerHooks = {};\r\n private plugins : types.ClientPlugin[] = [];\r\n private debug : boolean;\r\n private routeComponents : Record<string, types.RouteComponent> = {};\r\n private currentPathSignal = signal<string>(window.location.pathname ?? '/');\r\n\r\n constructor(config: types.ClientManagerConfig) {\r\n this.config = config;\r\n this.debug = config.debug ?? false;\r\n\r\n this.log('[INIT] Creating ClientManager');\r\n\r\n // Merge lifecycle hooks from config\r\n if (config.lifecycle) {\r\n this.hooks = { ...config.lifecycle };\r\n }\r\n\r\n // Store plugins from config\r\n this.plugins = config.plugins ?? [];\r\n\r\n // Store route components provided by user\r\n this.routeComponents = config.routes;\r\n\r\n // Initialize managers from @minejs/browser\r\n this.eventsManager = new EventsManager();\r\n this.windowManager = new WindowManager();\r\n\r\n // Initialize router with user-provided routes\r\n const routesArray = Object.entries(config.routes).map(([path, component]) => ({\r\n path,\r\n component\r\n }));\r\n\r\n this.router = createRouter({\r\n routes: routesArray,\r\n notFoundComponent: config.notFoundComponent,\r\n });\r\n\r\n // Connect router changes to signal for automatic re-rendering\r\n this.router.afterEach((to) => {\r\n this.currentPathSignal.set(to.path);\r\n });\r\n\r\n // Store clientManager instance\r\n // eslint-disable-next-line @typescript-eslint/no-this-alias\r\n globalClientManagerInstance = this;\r\n\r\n this.log('[INIT] ClientManager created');\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Setup lifecycle hooks OR bind events\r\n * Overloaded: on(event: 'onBoot'|'onReady'|'onDestroy', callback) - lifecycle\r\n * on(target, event, handler) - event binding\r\n */\r\n on(event: keyof types.ClientManagerHooks, callback: any): this;\r\n on<K extends keyof HTMLElementEventMap>(\r\n target: EventTarget,\r\n event: K | string,\r\n handler: EventListener,\r\n options?: AddEventListenerOptions\r\n ): () => void;\r\n on(\r\n eventOrTarget: keyof types.ClientManagerHooks | EventTarget,\r\n callbackOrEvent?: any,\r\n handler?: EventListener,\r\n options?: AddEventListenerOptions\r\n ): this | (() => void) {\r\n // Check if this is a lifecycle hook call\r\n if (typeof eventOrTarget === 'string' && eventOrTarget.startsWith('on')) {\r\n this.hooks[eventOrTarget as keyof types.ClientManagerHooks] = callbackOrEvent;\r\n return this;\r\n }\r\n\r\n // Otherwise it's an event binding\r\n return this.eventsManager.on(\r\n eventOrTarget as EventTarget,\r\n callbackOrEvent as string,\r\n handler as EventListener,\r\n options\r\n );\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Bootstrap the app - Phase 1: BOOT\r\n */\r\n async boot(): Promise<void> {\r\n if (this.lifecycle !== 'booting') {\r\n console.warn('[ClientManager] Already booted or destroyed');\r\n return;\r\n }\r\n\r\n this.log('⚡ Phase: BOOT');\r\n\r\n try {\r\n // Call plugins onBoot hooks\r\n for (const plugin of this.plugins) {\r\n if (plugin.onBoot) {\r\n this.log(`→ Plugin onBoot: ${plugin.name}`);\r\n await plugin.onBoot({\r\n debug: this.debug,\r\n config: this.config\r\n });\r\n }\r\n }\r\n\r\n // Call user onBoot hook\r\n if (this.hooks.onBoot) {\r\n this.log('→ Calling onBoot hook');\r\n await this.hooks.onBoot();\r\n }\r\n\r\n this.log('✓ BOOT phase complete');\r\n } catch (err) {\r\n console.error('[ClientManager] Boot failed:', err);\r\n throw err;\r\n }\r\n }\r\n\r\n /**\r\n * Ready the app - Phase 2: READY\r\n * Mount to DOM and make everything live\r\n *\r\n * Root selector is always 'body'.\r\n */\r\n async ready(): Promise<void> {\r\n if (this.lifecycle !== 'booting') {\r\n console.warn('[ClientManager] Cannot ready - not in booting phase');\r\n return;\r\n }\r\n\r\n this.log('⚡ Phase: READY');\r\n\r\n try {\r\n const selector = 'body';\r\n\r\n // Set body id to 'root' for mounting\r\n (document.querySelector(selector) as HTMLElement).id = 'root';\r\n\r\n // Mount router\r\n this.mount(selector);\r\n\r\n this.log('→ Router mounted');\r\n\r\n // Call plugins onReady hooks\r\n for (const plugin of this.plugins) {\r\n if (plugin.onReady) {\r\n this.log(`→ Plugin onReady: ${plugin.name}`);\r\n await plugin.onReady({\r\n debug: this.debug,\r\n config: this.config\r\n });\r\n }\r\n }\r\n\r\n // Call user onReady hook\r\n if (this.hooks.onReady) {\r\n this.log('→ Calling onReady hook');\r\n await this.hooks.onReady();\r\n }\r\n\r\n this.lifecycle = 'ready';\r\n this.log('✓ READY phase complete');\r\n this.log('✓ App is ready!');\r\n } catch (err) {\r\n console.error('[ClientManager] Ready failed:', err);\r\n throw err;\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown the app - Phase 3: DESTROY\r\n */\r\n async destroy(): Promise<void> {\r\n if (this.lifecycle === 'destroyed') {\r\n console.warn('[ClientManager] Already destroyed');\r\n return;\r\n }\r\n\r\n this.lifecycle = 'destroying';\r\n this.log('⚡ Phase: DESTROY');\r\n\r\n try {\r\n // Call plugins onDestroy hooks (in reverse order)\r\n for (let i = this.plugins.length - 1; i >= 0; i--) {\r\n const plugin = this.plugins[i];\r\n if (plugin.onDestroy) {\r\n this.log(`→ Plugin onDestroy: ${plugin.name}`);\r\n await plugin.onDestroy({\r\n debug: this.debug,\r\n config: this.config\r\n });\r\n }\r\n }\r\n\r\n // Call user onDestroy hook\r\n if (this.hooks.onDestroy) {\r\n this.log('→ Calling onDestroy hook');\r\n await this.hooks.onDestroy();\r\n }\r\n\r\n // Cleanup managers\r\n this.eventsManager.destroy();\r\n this.windowManager.destroy();\r\n\r\n this.lifecycle = 'destroyed';\r\n this.log('✓ DESTROY phase complete');\r\n } catch (err) {\r\n console.error('[ClientManager] Destroy failed:', err);\r\n throw err;\r\n }\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Navigate to path\r\n */\r\n navigate(path: string): void {\r\n this.router.push(path);\r\n }\r\n\r\n /**\r\n * Mount router to DOM element and setup reactive routing\r\n * Automatically re-renders when route changes\r\n * If rootLayout is provided, it wraps all pages\r\n */\r\n mount(selector: string | HTMLElement): void {\r\n const container = typeof selector === 'string'\r\n ? (document.querySelector(selector) as HTMLElement)\r\n : selector;\r\n\r\n if (!container) {\r\n console.warn('[ClientManager] Mount target not found:', selector);\r\n return;\r\n }\r\n\r\n let pageContainer = container;\r\n\r\n // If rootLayout is provided, mount it first (only once)\r\n if (this.config.rootLayout) {\r\n try {\r\n const layoutJsx = this.config.rootLayout();\r\n if (layoutJsx) {\r\n mountJSX(layoutJsx, container);\r\n this.log('→ Root layout mounted');\r\n\r\n // Find the page slot for rendering pages\r\n const pageSlot = container.querySelector('[data-page-slot]');\r\n if (pageSlot) {\r\n pageContainer = pageSlot as HTMLElement;\r\n } else {\r\n console.warn('[ClientManager] Page slot [data-page-slot] not found in root layout. Pages will render to the root container.');\r\n }\r\n }\r\n } catch (err) {\r\n console.error('[ClientManager] Error rendering root layout:', err);\r\n container.innerHTML = '<p>Error loading root layout</p>';\r\n return;\r\n }\r\n }\r\n\r\n // Setup reactive routing effect - re-renders when currentPathSignal changes\r\n effect(() => {\r\n const currentPath = this.currentPathSignal();\r\n const Component = this.routeComponents[currentPath]\r\n || this.config.notFoundComponent\r\n || null;\r\n\r\n // Clear only the page container (not the entire root if layout exists)\r\n pageContainer.innerHTML = '';\r\n\r\n if (Component) {\r\n try {\r\n const jsx = Component();\r\n // Use @minejs/jsx mount function to properly render JSX\r\n if (jsx) {\r\n mountJSX(jsx, pageContainer);\r\n }\r\n } catch (err) {\r\n console.error('[ClientManager] Error rendering component:', currentPath, err);\r\n pageContainer.innerHTML = '<p>Error loading component</p>';\r\n }\r\n } else {\r\n pageContainer.innerHTML = '<p>No component found for this route</p>';\r\n }\r\n\r\n this.log(`→ Route changed to: ${currentPath}`);\r\n });\r\n\r\n // Trigger initial render by pushing the current path\r\n this.router.push(this.currentPathSignal());\r\n this.log('→ Routing setup complete');\r\n }\r\n\r\n /**\r\n * Get current path signal for reactivity\r\n */\r\n getCurrentPath() {\r\n return this.currentPathSignal;\r\n }\r\n\r\n /**\r\n * Create navigation link handler\r\n */\r\n createLinkHandler(path: string) {\r\n return (e: MouseEvent) => {\r\n e.preventDefault();\r\n this.navigate(path);\r\n };\r\n }\r\n\r\n /**\r\n * Get underlying router for advanced usage\r\n */\r\n getRouter() {\r\n return this.router;\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Unbind event\r\n */\r\n off(target: EventTarget, event: string, handler: EventListener): void {\r\n this.eventsManager.off(target, event, handler);\r\n }\r\n\r\n /**\r\n * Get events manager directly\r\n */\r\n getEventsManager(): EventsManager {\r\n return this.eventsManager;\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Get viewport info as reactive signal\r\n */\r\n getViewport() {\r\n return this.windowManager.getViewport();\r\n }\r\n\r\n /**\r\n * Get window manager directly\r\n */\r\n getWindowManager(): WindowManager {\r\n return this.windowManager;\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Get i18n instance for translations\r\n */\r\n getI18n() {\r\n return getI18n();\r\n }\r\n\r\n /**\r\n * Get translation string\r\n */\r\n t(key: string, defaultValue?: string) {\r\n const i18n = getI18n();\r\n if (!i18n) {\r\n console.warn('[ClientManager] i18n not initialized. Using default value or key.');\r\n return defaultValue ?? key;\r\n }\r\n return i18n.t(key) ?? defaultValue ?? key;\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Get lifecycle phase\r\n */\r\n getPhase() {\r\n return this.lifecycle;\r\n }\r\n\r\n /**\r\n * Check if ready\r\n */\r\n isReady(): boolean {\r\n return this.lifecycle === 'ready';\r\n }\r\n\r\n /**\r\n * Internal logging\r\n */\r\n private log(message: string): void {\r\n if (this.debug) {\r\n console.log(`[ClientManager] ${message}`);\r\n }\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n }\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ ════ ════════════════════════════════════════╗\r\n\r\n /**\r\n * Get ClientManager instance if available\r\n */\r\n export function getGlobalClientManager(): ClientManager | undefined {\r\n return globalClientManagerInstance;\r\n }\r\n\r\n export async function start(config: types.ClientManagerConfig): Promise<ClientManager> {\r\n // Read i18n config from HTML meta tag (injected by server)\r\n const metaI18n = document.querySelector('meta[name=\"app-i18n\"]');\r\n if (metaI18n) {\r\n const i18nData = JSON.parse(metaI18n.getAttribute('content') || '{}');\r\n config.i18n = i18nData;\r\n }\r\n\r\n // Create ClientManager instance\r\n const manager = new ClientManager(config);\r\n\r\n // Phase 0: I18N Setup\r\n await setupI18n(config.i18n || {\r\n defaultLanguage: 'en',\r\n supportedLanguages: ['en'],\r\n });\r\n\r\n // Phase 1: BOOT\r\n manager.boot();\r\n\r\n // Phase 2: READY\r\n manager.ready();\r\n\r\n // Handle cleanup on page unload\r\n window.addEventListener('beforeunload', async () => {\r\n await manager.destroy();\r\n });\r\n\r\n return manager;\r\n }\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ ════ ════════════════════════════════════════╗\r\n\r\n export * from './types';\r\n export { t } from '@minejs/i18n';\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["globalClientManagerInstance","ClientManager","config","signal","EventsManager","WindowManager","routesArray","path","component","createRouter","to","eventOrTarget","callbackOrEvent","handler","options","plugin","err","selector","i","container","pageContainer","layoutJsx","mountJSX","pageSlot","effect","currentPath","Component","jsx","e","target","event","getI18n","key","defaultValue","i18n","message","getGlobalClientManager","start","metaI18n","i18nData","manager","setupI18n"],"mappings":"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","file":"index.cjs","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\r\n// src/index.ts\r\n//\r\n// Made with ❤️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import * as types from './types';\r\n import { signal, effect } from '@minejs/signals';\r\n import { setupI18n, getI18n } from '@minejs/i18n';\r\n import { mount as mountJSX } from '@minejs/jsx';\r\n import { EventsManager, Router, WindowManager, createRouter } from '@minejs/browser';\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ CORE ════════════════════════════════════════╗\r\n\r\n let globalClientManagerInstance: ClientManager | undefined;\r\n\r\n export class ClientManager {\r\n\r\n // ┌──────────────────────────────── INIT ──────────────────────────────┐\r\n\r\n private router : Router;\r\n private eventsManager : EventsManager;\r\n private windowManager : WindowManager;\r\n private lifecycle : 'booting' | 'ready' | 'destroying' | 'destroyed' = 'booting';\r\n private config : types.ClientManagerConfig;\r\n private hooks : types.ClientManagerHooks = {};\r\n private plugins : types.ClientPlugin[] = [];\r\n private debug : boolean;\r\n private routeComponents : Record<string, types.RouteComponent> = {};\r\n private currentPathSignal = signal<string>(window.location.pathname ?? '/');\r\n\r\n constructor(config: types.ClientManagerConfig) {\r\n this.config = config;\r\n this.debug = config.debug ?? false;\r\n\r\n this.log('[INIT] Creating ClientManager');\r\n\r\n // Merge lifecycle hooks from config\r\n if (config.lifecycle) {\r\n this.hooks = { ...config.lifecycle };\r\n }\r\n\r\n // Store plugins from config\r\n this.plugins = config.plugins ?? [];\r\n\r\n // Store route components provided by user\r\n this.routeComponents = config.routes;\r\n\r\n // Initialize managers from @minejs/browser\r\n this.eventsManager = new EventsManager();\r\n this.windowManager = new WindowManager();\r\n\r\n // Initialize router with user-provided routes\r\n const routesArray = Object.entries(config.routes).map(([path, component]) => ({\r\n path,\r\n component\r\n }));\r\n\r\n this.router = createRouter({\r\n routes: routesArray,\r\n notFoundComponent: config.notFoundComponent,\r\n });\r\n\r\n // Connect router changes to signal for automatic re-rendering\r\n this.router.afterEach((to) => {\r\n this.currentPathSignal.set(to.path);\r\n });\r\n\r\n // Store clientManager instance\r\n // eslint-disable-next-line @typescript-eslint/no-this-alias\r\n globalClientManagerInstance = this;\r\n\r\n this.log('[INIT] ClientManager created');\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Setup lifecycle hooks OR bind events\r\n * Overloaded: on(event: 'onBoot'|'onReady'|'onDestroy', callback) - lifecycle\r\n * on(target, event, handler) - event binding\r\n */\r\n on(event: keyof types.ClientManagerHooks, callback: any): this;\r\n on<K extends keyof HTMLElementEventMap>(\r\n target: EventTarget,\r\n event: K | string,\r\n handler: EventListener,\r\n options?: AddEventListenerOptions\r\n ): () => void;\r\n on(\r\n eventOrTarget: keyof types.ClientManagerHooks | EventTarget,\r\n callbackOrEvent?: any,\r\n handler?: EventListener,\r\n options?: AddEventListenerOptions\r\n ): this | (() => void) {\r\n // Check if this is a lifecycle hook call\r\n if (typeof eventOrTarget === 'string' && eventOrTarget.startsWith('on')) {\r\n this.hooks[eventOrTarget as keyof types.ClientManagerHooks] = callbackOrEvent;\r\n return this;\r\n }\r\n\r\n // Otherwise it's an event binding\r\n return this.eventsManager.on(\r\n eventOrTarget as EventTarget,\r\n callbackOrEvent as string,\r\n handler as EventListener,\r\n options\r\n );\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Bootstrap the app - Phase 1: BOOT\r\n */\r\n async boot(): Promise<void> {\r\n if (this.lifecycle !== 'booting') {\r\n console.warn('[ClientManager] Already booted or destroyed');\r\n return;\r\n }\r\n\r\n this.log('⚡ Phase: BOOT');\r\n\r\n try {\r\n // Call plugins onBoot hooks\r\n for (const plugin of this.plugins) {\r\n if (plugin.onBoot) {\r\n this.log(`→ Plugin onBoot: ${plugin.name}`);\r\n await plugin.onBoot({\r\n debug: this.debug,\r\n config: this.config\r\n });\r\n }\r\n }\r\n\r\n // Call user onBoot hook\r\n if (this.hooks.onBoot) {\r\n this.log('→ Calling onBoot hook');\r\n await this.hooks.onBoot();\r\n }\r\n\r\n this.log('✓ BOOT phase complete');\r\n } catch (err) {\r\n console.error('[ClientManager] Boot failed:', err);\r\n throw err;\r\n }\r\n }\r\n\r\n /**\r\n * Ready the app - Phase 2: READY\r\n * Mount to DOM and make everything live\r\n *\r\n * Root selector is always 'body'.\r\n */\r\n async ready(): Promise<void> {\r\n if (this.lifecycle !== 'booting') {\r\n console.warn('[ClientManager] Cannot ready - not in booting phase');\r\n return;\r\n }\r\n\r\n this.log('⚡ Phase: READY');\r\n\r\n try {\r\n const selector = 'body';\r\n\r\n // Set body id to 'root' for mounting\r\n (document.querySelector(selector) as HTMLElement).id = 'root';\r\n\r\n // Mount router\r\n this.mount(selector);\r\n\r\n this.log('→ Router mounted');\r\n\r\n // Call plugins onReady hooks\r\n for (const plugin of this.plugins) {\r\n if (plugin.onReady) {\r\n this.log(`→ Plugin onReady: ${plugin.name}`);\r\n await plugin.onReady({\r\n debug: this.debug,\r\n config: this.config\r\n });\r\n }\r\n }\r\n\r\n // Call user onReady hook\r\n if (this.hooks.onReady) {\r\n this.log('→ Calling onReady hook');\r\n await this.hooks.onReady();\r\n }\r\n\r\n this.lifecycle = 'ready';\r\n this.log('✓ READY phase complete');\r\n this.log('✓ App is ready!');\r\n } catch (err) {\r\n console.error('[ClientManager] Ready failed:', err);\r\n throw err;\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown the app - Phase 3: DESTROY\r\n */\r\n async destroy(): Promise<void> {\r\n if (this.lifecycle === 'destroyed') {\r\n console.warn('[ClientManager] Already destroyed');\r\n return;\r\n }\r\n\r\n this.lifecycle = 'destroying';\r\n this.log('⚡ Phase: DESTROY');\r\n\r\n try {\r\n // Call plugins onDestroy hooks (in reverse order)\r\n for (let i = this.plugins.length - 1; i >= 0; i--) {\r\n const plugin = this.plugins[i];\r\n if (plugin.onDestroy) {\r\n this.log(`→ Plugin onDestroy: ${plugin.name}`);\r\n await plugin.onDestroy({\r\n debug: this.debug,\r\n config: this.config\r\n });\r\n }\r\n }\r\n\r\n // Call user onDestroy hook\r\n if (this.hooks.onDestroy) {\r\n this.log('→ Calling onDestroy hook');\r\n await this.hooks.onDestroy();\r\n }\r\n\r\n // Cleanup managers\r\n this.eventsManager.destroy();\r\n this.windowManager.destroy();\r\n\r\n this.lifecycle = 'destroyed';\r\n this.log('✓ DESTROY phase complete');\r\n } catch (err) {\r\n console.error('[ClientManager] Destroy failed:', err);\r\n throw err;\r\n }\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Navigate to path\r\n */\r\n navigate(path: string): void {\r\n this.router.push(path);\r\n }\r\n\r\n /**\r\n * Mount router to DOM element and setup reactive routing\r\n * Automatically re-renders when route changes\r\n * If rootLayout is provided, it wraps all pages\r\n */\r\n mount(selector: string | HTMLElement): void {\r\n const container = typeof selector === 'string'\r\n ? (document.querySelector(selector) as HTMLElement)\r\n : selector;\r\n\r\n if (!container) {\r\n console.warn('[ClientManager] Mount target not found:', selector);\r\n return;\r\n }\r\n\r\n let pageContainer = container;\r\n\r\n // If rootLayout is provided, mount it first (only once)\r\n if (this.config.rootLayout) {\r\n try {\r\n const layoutJsx = this.config.rootLayout();\r\n if (layoutJsx) {\r\n mountJSX(layoutJsx, container);\r\n this.log('→ Root layout mounted');\r\n\r\n // Find the page slot for rendering pages\r\n const pageSlot = container.querySelector('#main-overlay');\r\n if (pageSlot) {\r\n pageContainer = pageSlot as HTMLElement;\r\n } else {\r\n console.warn('[ClientManager] Page slot #main-overlay not found in root layout. Pages will render to the root container.');\r\n }\r\n }\r\n } catch (err) {\r\n console.error('[ClientManager] Error rendering root layout:', err);\r\n container.innerHTML = '<p>Error loading root layout</p>';\r\n return;\r\n }\r\n }\r\n\r\n // Setup reactive routing effect - re-renders when currentPathSignal changes\r\n effect(() => {\r\n const currentPath = this.currentPathSignal();\r\n const Component = this.routeComponents[currentPath]\r\n || this.config.notFoundComponent\r\n || null;\r\n\r\n // Clear only the page container (not the entire root if layout exists)\r\n pageContainer.innerHTML = '';\r\n\r\n if (Component) {\r\n try {\r\n const jsx = Component();\r\n // Use @minejs/jsx mount function to properly render JSX\r\n if (jsx) {\r\n mountJSX(jsx, pageContainer);\r\n }\r\n } catch (err) {\r\n console.error('[ClientManager] Error rendering component:', currentPath, err);\r\n pageContainer.innerHTML = '<p>Error loading component</p>';\r\n }\r\n } else {\r\n pageContainer.innerHTML = '<p>No component found for this route</p>';\r\n }\r\n\r\n this.log(`→ Route changed to: ${currentPath}`);\r\n });\r\n\r\n // Trigger initial render by pushing the current path\r\n this.router.push(this.currentPathSignal());\r\n this.log('→ Routing setup complete');\r\n }\r\n\r\n /**\r\n * Get current path signal for reactivity\r\n */\r\n getCurrentPath() {\r\n return this.currentPathSignal;\r\n }\r\n\r\n /**\r\n * Create navigation link handler\r\n */\r\n createLinkHandler(path: string) {\r\n return (e: MouseEvent) => {\r\n e.preventDefault();\r\n this.navigate(path);\r\n };\r\n }\r\n\r\n /**\r\n * Get underlying router for advanced usage\r\n */\r\n getRouter() {\r\n return this.router;\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Unbind event\r\n */\r\n off(target: EventTarget, event: string, handler: EventListener): void {\r\n this.eventsManager.off(target, event, handler);\r\n }\r\n\r\n /**\r\n * Get events manager directly\r\n */\r\n getEventsManager(): EventsManager {\r\n return this.eventsManager;\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Get viewport info as reactive signal\r\n */\r\n getViewport() {\r\n return this.windowManager.getViewport();\r\n }\r\n\r\n /**\r\n * Get window manager directly\r\n */\r\n getWindowManager(): WindowManager {\r\n return this.windowManager;\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Get i18n instance for translations\r\n */\r\n getI18n() {\r\n return getI18n();\r\n }\r\n\r\n /**\r\n * Get translation string\r\n */\r\n t(key: string, defaultValue?: string) {\r\n const i18n = getI18n();\r\n if (!i18n) {\r\n console.warn('[ClientManager] i18n not initialized. Using default value or key.');\r\n return defaultValue ?? key;\r\n }\r\n return i18n.t(key) ?? defaultValue ?? key;\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Get lifecycle phase\r\n */\r\n getPhase() {\r\n return this.lifecycle;\r\n }\r\n\r\n /**\r\n * Check if ready\r\n */\r\n isReady(): boolean {\r\n return this.lifecycle === 'ready';\r\n }\r\n\r\n /**\r\n * Internal logging\r\n */\r\n private log(message: string): void {\r\n if (this.debug) {\r\n console.log(`[ClientManager] ${message}`);\r\n }\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n }\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ ════ ════════════════════════════════════════╗\r\n\r\n /**\r\n * Get ClientManager instance if available\r\n */\r\n export function getGlobalClientManager(): ClientManager | undefined {\r\n return globalClientManagerInstance;\r\n }\r\n\r\n export async function start(config: types.ClientManagerConfig): Promise<ClientManager> {\r\n // Read i18n config from HTML meta tag (injected by server)\r\n const metaI18n = document.querySelector('meta[name=\"app-i18n\"]');\r\n if (metaI18n) {\r\n const i18nData = JSON.parse(metaI18n.getAttribute('content') || '{}');\r\n config.i18n = i18nData;\r\n }\r\n\r\n // Create ClientManager instance\r\n const manager = new ClientManager(config);\r\n\r\n // Phase 0: I18N Setup\r\n await setupI18n(config.i18n || {\r\n defaultLanguage: 'en',\r\n supportedLanguages: ['en'],\r\n });\r\n\r\n // Phase 1: BOOT\r\n manager.boot();\r\n\r\n // Phase 2: READY\r\n manager.ready();\r\n\r\n // Handle cleanup on page unload\r\n window.addEventListener('beforeunload', async () => {\r\n await manager.destroy();\r\n });\r\n\r\n return manager;\r\n }\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ ════ ════════════════════════════════════════╗\r\n\r\n export * from './types';\r\n export { t } from '@minejs/i18n';\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n"]}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import {signal,effect}from'@minejs/signals';import {getI18n,setupI18n}from'@minejs/i18n';export{t}from'@minejs/i18n';import {mount}from'@minejs/jsx';import {EventsManager,WindowManager,createRouter}from'@minejs/browser';var h,s=class{constructor(e){this.lifecycle="booting";this.hooks={};this.plugins=[];this.routeComponents={};this.currentPathSignal=signal(window.location.pathname??"/");this.config=e,this.debug=e.debug??false,this.log("[INIT] Creating ClientManager"),e.lifecycle&&(this.hooks={...e.lifecycle}),this.plugins=e.plugins??[],this.routeComponents=e.routes,this.eventsManager=new EventsManager,this.windowManager=new WindowManager;let t=Object.entries(e.routes).map(([n,o])=>({path:n,component:o}));this.router=createRouter({routes:t,notFoundComponent:e.notFoundComponent}),this.router.afterEach(n=>{this.currentPathSignal.set(n.path);}),h=this,this.log("[INIT] ClientManager created");}on(e,t,n,o){return typeof e=="string"&&e.startsWith("on")?(this.hooks[e]=t,this):this.eventsManager.on(e,t,n,o)}async boot(){if(this.lifecycle!=="booting"){console.warn("[ClientManager] Already booted or destroyed");return}this.log("\u26A1 Phase: BOOT");try{for(let e of this.plugins)e.onBoot&&(this.log(`\u2192 Plugin onBoot: ${e.name}`),await e.onBoot({debug:this.debug,config:this.config}));this.hooks.onBoot&&(this.log("\u2192 Calling onBoot hook"),await this.hooks.onBoot()),this.log("\u2713 BOOT phase complete");}catch(e){throw console.error("[ClientManager] Boot failed:",e),e}}async ready(){if(this.lifecycle!=="booting"){console.warn("[ClientManager] Cannot ready - not in booting phase");return}this.log("\u26A1 Phase: READY");try{let e="body";document.querySelector(e).id="root",this.mount(e),this.log("\u2192 Router mounted");for(let t of this.plugins)t.onReady&&(this.log(`\u2192 Plugin onReady: ${t.name}`),await t.onReady({debug:this.debug,config:this.config}));this.hooks.onReady&&(this.log("\u2192 Calling onReady hook"),await this.hooks.onReady()),this.lifecycle="ready",this.log("\u2713 READY phase complete"),this.log("\u2713 App is ready!");}catch(e){throw console.error("[ClientManager] Ready failed:",e),e}}async destroy(){if(this.lifecycle==="destroyed"){console.warn("[ClientManager] Already destroyed");return}this.lifecycle="destroying",this.log("\u26A1 Phase: DESTROY");try{for(let e=this.plugins.length-1;e>=0;e--){let t=this.plugins[e];t.onDestroy&&(this.log(`\u2192 Plugin onDestroy: ${t.name}`),await t.onDestroy({debug:this.debug,config:this.config}));}this.hooks.onDestroy&&(this.log("\u2192 Calling onDestroy hook"),await this.hooks.onDestroy()),this.eventsManager.destroy(),this.windowManager.destroy(),this.lifecycle="destroyed",this.log("\u2713 DESTROY phase complete");}catch(e){throw console.error("[ClientManager] Destroy failed:",e),e}}navigate(e){this.router.push(e);}mount(e){let t=typeof e=="string"?document.querySelector(e):e;if(!t){console.warn("[ClientManager] Mount target not found:",e);return}let n=t;if(this.config.rootLayout)try{let o=this.config.rootLayout();if(o){mount(o,t),this.log("\u2192 Root layout mounted");let r=t.querySelector("[data-page-slot]");r?n=r:console.warn("[ClientManager] Page slot [data-page-slot] not found in root layout. Pages will render to the root container.");}}catch(o){console.error("[ClientManager] Error rendering root layout:",o),t.innerHTML="<p>Error loading root layout</p>";return}effect(()=>{let o=this.currentPathSignal(),r=this.routeComponents[o]||this.config.notFoundComponent||null;if(n.innerHTML="",r)try{let a=r();a&&mount(a,n);}catch(a){console.error("[ClientManager] Error rendering component:",o,a),n.innerHTML="<p>Error loading component</p>";}else n.innerHTML="<p>No component found for this route</p>";this.log(`\u2192 Route changed to: ${o}`);}),this.router.push(this.currentPathSignal()),this.log("\u2192 Routing setup complete");}getCurrentPath(){return this.currentPathSignal}createLinkHandler(e){return t=>{t.preventDefault(),this.navigate(e);}}getRouter(){return this.router}off(e,t,n){this.eventsManager.off(e,t,n);}getEventsManager(){return this.eventsManager}getViewport(){return this.windowManager.getViewport()}getWindowManager(){return this.windowManager}getI18n(){return getI18n()}t(e,t){let n=getI18n();return n?n.t(e)??t??e:(console.warn("[ClientManager] i18n not initialized. Using default value or key."),t??e)}getPhase(){return this.lifecycle}isReady(){return this.lifecycle==="ready"}log(e){this.debug&&console.log(`[ClientManager] ${e}`);}};function E(){return h}async function b(i){let e=document.querySelector('meta[name="app-i18n"]');if(e){let n=JSON.parse(e.getAttribute("content")||"{}");i.i18n=n;}let t=new s(i);return await setupI18n(i.i18n||{defaultLanguage:"en",supportedLanguages:["en"]}),t.boot(),t.ready(),window.addEventListener("beforeunload",async()=>{await t.destroy();}),t}export{s as ClientManager,E as getGlobalClientManager,b as start};//# sourceMappingURL=index.js.map
1
+ import {signal,effect}from'@minejs/signals';import {getI18n,setupI18n}from'@minejs/i18n';export{t}from'@minejs/i18n';import {mount}from'@minejs/jsx';import {EventsManager,WindowManager,createRouter}from'@minejs/browser';var h,s=class{constructor(e){this.lifecycle="booting";this.hooks={};this.plugins=[];this.routeComponents={};this.currentPathSignal=signal(window.location.pathname??"/");this.config=e,this.debug=e.debug??false,this.log("[INIT] Creating ClientManager"),e.lifecycle&&(this.hooks={...e.lifecycle}),this.plugins=e.plugins??[],this.routeComponents=e.routes,this.eventsManager=new EventsManager,this.windowManager=new WindowManager;let t=Object.entries(e.routes).map(([n,o])=>({path:n,component:o}));this.router=createRouter({routes:t,notFoundComponent:e.notFoundComponent}),this.router.afterEach(n=>{this.currentPathSignal.set(n.path);}),h=this,this.log("[INIT] ClientManager created");}on(e,t,n,o){return typeof e=="string"&&e.startsWith("on")?(this.hooks[e]=t,this):this.eventsManager.on(e,t,n,o)}async boot(){if(this.lifecycle!=="booting"){console.warn("[ClientManager] Already booted or destroyed");return}this.log("\u26A1 Phase: BOOT");try{for(let e of this.plugins)e.onBoot&&(this.log(`\u2192 Plugin onBoot: ${e.name}`),await e.onBoot({debug:this.debug,config:this.config}));this.hooks.onBoot&&(this.log("\u2192 Calling onBoot hook"),await this.hooks.onBoot()),this.log("\u2713 BOOT phase complete");}catch(e){throw console.error("[ClientManager] Boot failed:",e),e}}async ready(){if(this.lifecycle!=="booting"){console.warn("[ClientManager] Cannot ready - not in booting phase");return}this.log("\u26A1 Phase: READY");try{let e="body";document.querySelector(e).id="root",this.mount(e),this.log("\u2192 Router mounted");for(let t of this.plugins)t.onReady&&(this.log(`\u2192 Plugin onReady: ${t.name}`),await t.onReady({debug:this.debug,config:this.config}));this.hooks.onReady&&(this.log("\u2192 Calling onReady hook"),await this.hooks.onReady()),this.lifecycle="ready",this.log("\u2713 READY phase complete"),this.log("\u2713 App is ready!");}catch(e){throw console.error("[ClientManager] Ready failed:",e),e}}async destroy(){if(this.lifecycle==="destroyed"){console.warn("[ClientManager] Already destroyed");return}this.lifecycle="destroying",this.log("\u26A1 Phase: DESTROY");try{for(let e=this.plugins.length-1;e>=0;e--){let t=this.plugins[e];t.onDestroy&&(this.log(`\u2192 Plugin onDestroy: ${t.name}`),await t.onDestroy({debug:this.debug,config:this.config}));}this.hooks.onDestroy&&(this.log("\u2192 Calling onDestroy hook"),await this.hooks.onDestroy()),this.eventsManager.destroy(),this.windowManager.destroy(),this.lifecycle="destroyed",this.log("\u2713 DESTROY phase complete");}catch(e){throw console.error("[ClientManager] Destroy failed:",e),e}}navigate(e){this.router.push(e);}mount(e){let t=typeof e=="string"?document.querySelector(e):e;if(!t){console.warn("[ClientManager] Mount target not found:",e);return}let n=t;if(this.config.rootLayout)try{let o=this.config.rootLayout();if(o){mount(o,t),this.log("\u2192 Root layout mounted");let r=t.querySelector("#main-overlay");r?n=r:console.warn("[ClientManager] Page slot #main-overlay not found in root layout. Pages will render to the root container.");}}catch(o){console.error("[ClientManager] Error rendering root layout:",o),t.innerHTML="<p>Error loading root layout</p>";return}effect(()=>{let o=this.currentPathSignal(),r=this.routeComponents[o]||this.config.notFoundComponent||null;if(n.innerHTML="",r)try{let a=r();a&&mount(a,n);}catch(a){console.error("[ClientManager] Error rendering component:",o,a),n.innerHTML="<p>Error loading component</p>";}else n.innerHTML="<p>No component found for this route</p>";this.log(`\u2192 Route changed to: ${o}`);}),this.router.push(this.currentPathSignal()),this.log("\u2192 Routing setup complete");}getCurrentPath(){return this.currentPathSignal}createLinkHandler(e){return t=>{t.preventDefault(),this.navigate(e);}}getRouter(){return this.router}off(e,t,n){this.eventsManager.off(e,t,n);}getEventsManager(){return this.eventsManager}getViewport(){return this.windowManager.getViewport()}getWindowManager(){return this.windowManager}getI18n(){return getI18n()}t(e,t){let n=getI18n();return n?n.t(e)??t??e:(console.warn("[ClientManager] i18n not initialized. Using default value or key."),t??e)}getPhase(){return this.lifecycle}isReady(){return this.lifecycle==="ready"}log(e){this.debug&&console.log(`[ClientManager] ${e}`);}};function E(){return h}async function b(i){let e=document.querySelector('meta[name="app-i18n"]');if(e){let n=JSON.parse(e.getAttribute("content")||"{}");i.i18n=n;}let t=new s(i);return await setupI18n(i.i18n||{defaultLanguage:"en",supportedLanguages:["en"]}),t.boot(),t.ready(),window.addEventListener("beforeunload",async()=>{await t.destroy();}),t}export{s as ClientManager,E as getGlobalClientManager,b as start};//# sourceMappingURL=index.js.map
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["globalClientManagerInstance","ClientManager","config","signal","EventsManager","WindowManager","routesArray","path","component","createRouter","to","eventOrTarget","callbackOrEvent","handler","options","plugin","err","selector","i","container","pageContainer","layoutJsx","mountJSX","pageSlot","effect","currentPath","Component","jsx","e","target","event","getI18n","key","defaultValue","i18n","message","getGlobalClientManager","start","metaI18n","i18nData","manager","setupI18n"],"mappings":"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","file":"index.js","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\r\n// src/index.ts\r\n//\r\n// Made with ❤️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import * as types from './types';\r\n import { signal, effect } from '@minejs/signals';\r\n import { setupI18n, getI18n } from '@minejs/i18n';\r\n import { mount as mountJSX } from '@minejs/jsx';\r\n import { EventsManager, Router, WindowManager, createRouter } from '@minejs/browser';\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ CORE ════════════════════════════════════════╗\r\n\r\n let globalClientManagerInstance: ClientManager | undefined;\r\n\r\n export class ClientManager {\r\n\r\n // ┌──────────────────────────────── INIT ──────────────────────────────┐\r\n\r\n private router : Router;\r\n private eventsManager : EventsManager;\r\n private windowManager : WindowManager;\r\n private lifecycle : 'booting' | 'ready' | 'destroying' | 'destroyed' = 'booting';\r\n private config : types.ClientManagerConfig;\r\n private hooks : types.ClientManagerHooks = {};\r\n private plugins : types.ClientPlugin[] = [];\r\n private debug : boolean;\r\n private routeComponents : Record<string, types.RouteComponent> = {};\r\n private currentPathSignal = signal<string>(window.location.pathname ?? '/');\r\n\r\n constructor(config: types.ClientManagerConfig) {\r\n this.config = config;\r\n this.debug = config.debug ?? false;\r\n\r\n this.log('[INIT] Creating ClientManager');\r\n\r\n // Merge lifecycle hooks from config\r\n if (config.lifecycle) {\r\n this.hooks = { ...config.lifecycle };\r\n }\r\n\r\n // Store plugins from config\r\n this.plugins = config.plugins ?? [];\r\n\r\n // Store route components provided by user\r\n this.routeComponents = config.routes;\r\n\r\n // Initialize managers from @minejs/browser\r\n this.eventsManager = new EventsManager();\r\n this.windowManager = new WindowManager();\r\n\r\n // Initialize router with user-provided routes\r\n const routesArray = Object.entries(config.routes).map(([path, component]) => ({\r\n path,\r\n component\r\n }));\r\n\r\n this.router = createRouter({\r\n routes: routesArray,\r\n notFoundComponent: config.notFoundComponent,\r\n });\r\n\r\n // Connect router changes to signal for automatic re-rendering\r\n this.router.afterEach((to) => {\r\n this.currentPathSignal.set(to.path);\r\n });\r\n\r\n // Store clientManager instance\r\n // eslint-disable-next-line @typescript-eslint/no-this-alias\r\n globalClientManagerInstance = this;\r\n\r\n this.log('[INIT] ClientManager created');\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Setup lifecycle hooks OR bind events\r\n * Overloaded: on(event: 'onBoot'|'onReady'|'onDestroy', callback) - lifecycle\r\n * on(target, event, handler) - event binding\r\n */\r\n on(event: keyof types.ClientManagerHooks, callback: any): this;\r\n on<K extends keyof HTMLElementEventMap>(\r\n target: EventTarget,\r\n event: K | string,\r\n handler: EventListener,\r\n options?: AddEventListenerOptions\r\n ): () => void;\r\n on(\r\n eventOrTarget: keyof types.ClientManagerHooks | EventTarget,\r\n callbackOrEvent?: any,\r\n handler?: EventListener,\r\n options?: AddEventListenerOptions\r\n ): this | (() => void) {\r\n // Check if this is a lifecycle hook call\r\n if (typeof eventOrTarget === 'string' && eventOrTarget.startsWith('on')) {\r\n this.hooks[eventOrTarget as keyof types.ClientManagerHooks] = callbackOrEvent;\r\n return this;\r\n }\r\n\r\n // Otherwise it's an event binding\r\n return this.eventsManager.on(\r\n eventOrTarget as EventTarget,\r\n callbackOrEvent as string,\r\n handler as EventListener,\r\n options\r\n );\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Bootstrap the app - Phase 1: BOOT\r\n */\r\n async boot(): Promise<void> {\r\n if (this.lifecycle !== 'booting') {\r\n console.warn('[ClientManager] Already booted or destroyed');\r\n return;\r\n }\r\n\r\n this.log('⚡ Phase: BOOT');\r\n\r\n try {\r\n // Call plugins onBoot hooks\r\n for (const plugin of this.plugins) {\r\n if (plugin.onBoot) {\r\n this.log(`→ Plugin onBoot: ${plugin.name}`);\r\n await plugin.onBoot({\r\n debug: this.debug,\r\n config: this.config\r\n });\r\n }\r\n }\r\n\r\n // Call user onBoot hook\r\n if (this.hooks.onBoot) {\r\n this.log('→ Calling onBoot hook');\r\n await this.hooks.onBoot();\r\n }\r\n\r\n this.log('✓ BOOT phase complete');\r\n } catch (err) {\r\n console.error('[ClientManager] Boot failed:', err);\r\n throw err;\r\n }\r\n }\r\n\r\n /**\r\n * Ready the app - Phase 2: READY\r\n * Mount to DOM and make everything live\r\n *\r\n * Root selector is always 'body'.\r\n */\r\n async ready(): Promise<void> {\r\n if (this.lifecycle !== 'booting') {\r\n console.warn('[ClientManager] Cannot ready - not in booting phase');\r\n return;\r\n }\r\n\r\n this.log('⚡ Phase: READY');\r\n\r\n try {\r\n const selector = 'body';\r\n\r\n // Set body id to 'root' for mounting\r\n (document.querySelector(selector) as HTMLElement).id = 'root';\r\n\r\n // Mount router\r\n this.mount(selector);\r\n\r\n this.log('→ Router mounted');\r\n\r\n // Call plugins onReady hooks\r\n for (const plugin of this.plugins) {\r\n if (plugin.onReady) {\r\n this.log(`→ Plugin onReady: ${plugin.name}`);\r\n await plugin.onReady({\r\n debug: this.debug,\r\n config: this.config\r\n });\r\n }\r\n }\r\n\r\n // Call user onReady hook\r\n if (this.hooks.onReady) {\r\n this.log('→ Calling onReady hook');\r\n await this.hooks.onReady();\r\n }\r\n\r\n this.lifecycle = 'ready';\r\n this.log('✓ READY phase complete');\r\n this.log('✓ App is ready!');\r\n } catch (err) {\r\n console.error('[ClientManager] Ready failed:', err);\r\n throw err;\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown the app - Phase 3: DESTROY\r\n */\r\n async destroy(): Promise<void> {\r\n if (this.lifecycle === 'destroyed') {\r\n console.warn('[ClientManager] Already destroyed');\r\n return;\r\n }\r\n\r\n this.lifecycle = 'destroying';\r\n this.log('⚡ Phase: DESTROY');\r\n\r\n try {\r\n // Call plugins onDestroy hooks (in reverse order)\r\n for (let i = this.plugins.length - 1; i >= 0; i--) {\r\n const plugin = this.plugins[i];\r\n if (plugin.onDestroy) {\r\n this.log(`→ Plugin onDestroy: ${plugin.name}`);\r\n await plugin.onDestroy({\r\n debug: this.debug,\r\n config: this.config\r\n });\r\n }\r\n }\r\n\r\n // Call user onDestroy hook\r\n if (this.hooks.onDestroy) {\r\n this.log('→ Calling onDestroy hook');\r\n await this.hooks.onDestroy();\r\n }\r\n\r\n // Cleanup managers\r\n this.eventsManager.destroy();\r\n this.windowManager.destroy();\r\n\r\n this.lifecycle = 'destroyed';\r\n this.log('✓ DESTROY phase complete');\r\n } catch (err) {\r\n console.error('[ClientManager] Destroy failed:', err);\r\n throw err;\r\n }\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Navigate to path\r\n */\r\n navigate(path: string): void {\r\n this.router.push(path);\r\n }\r\n\r\n /**\r\n * Mount router to DOM element and setup reactive routing\r\n * Automatically re-renders when route changes\r\n * If rootLayout is provided, it wraps all pages\r\n */\r\n mount(selector: string | HTMLElement): void {\r\n const container = typeof selector === 'string'\r\n ? (document.querySelector(selector) as HTMLElement)\r\n : selector;\r\n\r\n if (!container) {\r\n console.warn('[ClientManager] Mount target not found:', selector);\r\n return;\r\n }\r\n\r\n let pageContainer = container;\r\n\r\n // If rootLayout is provided, mount it first (only once)\r\n if (this.config.rootLayout) {\r\n try {\r\n const layoutJsx = this.config.rootLayout();\r\n if (layoutJsx) {\r\n mountJSX(layoutJsx, container);\r\n this.log('→ Root layout mounted');\r\n\r\n // Find the page slot for rendering pages\r\n const pageSlot = container.querySelector('[data-page-slot]');\r\n if (pageSlot) {\r\n pageContainer = pageSlot as HTMLElement;\r\n } else {\r\n console.warn('[ClientManager] Page slot [data-page-slot] not found in root layout. Pages will render to the root container.');\r\n }\r\n }\r\n } catch (err) {\r\n console.error('[ClientManager] Error rendering root layout:', err);\r\n container.innerHTML = '<p>Error loading root layout</p>';\r\n return;\r\n }\r\n }\r\n\r\n // Setup reactive routing effect - re-renders when currentPathSignal changes\r\n effect(() => {\r\n const currentPath = this.currentPathSignal();\r\n const Component = this.routeComponents[currentPath]\r\n || this.config.notFoundComponent\r\n || null;\r\n\r\n // Clear only the page container (not the entire root if layout exists)\r\n pageContainer.innerHTML = '';\r\n\r\n if (Component) {\r\n try {\r\n const jsx = Component();\r\n // Use @minejs/jsx mount function to properly render JSX\r\n if (jsx) {\r\n mountJSX(jsx, pageContainer);\r\n }\r\n } catch (err) {\r\n console.error('[ClientManager] Error rendering component:', currentPath, err);\r\n pageContainer.innerHTML = '<p>Error loading component</p>';\r\n }\r\n } else {\r\n pageContainer.innerHTML = '<p>No component found for this route</p>';\r\n }\r\n\r\n this.log(`→ Route changed to: ${currentPath}`);\r\n });\r\n\r\n // Trigger initial render by pushing the current path\r\n this.router.push(this.currentPathSignal());\r\n this.log('→ Routing setup complete');\r\n }\r\n\r\n /**\r\n * Get current path signal for reactivity\r\n */\r\n getCurrentPath() {\r\n return this.currentPathSignal;\r\n }\r\n\r\n /**\r\n * Create navigation link handler\r\n */\r\n createLinkHandler(path: string) {\r\n return (e: MouseEvent) => {\r\n e.preventDefault();\r\n this.navigate(path);\r\n };\r\n }\r\n\r\n /**\r\n * Get underlying router for advanced usage\r\n */\r\n getRouter() {\r\n return this.router;\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Unbind event\r\n */\r\n off(target: EventTarget, event: string, handler: EventListener): void {\r\n this.eventsManager.off(target, event, handler);\r\n }\r\n\r\n /**\r\n * Get events manager directly\r\n */\r\n getEventsManager(): EventsManager {\r\n return this.eventsManager;\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Get viewport info as reactive signal\r\n */\r\n getViewport() {\r\n return this.windowManager.getViewport();\r\n }\r\n\r\n /**\r\n * Get window manager directly\r\n */\r\n getWindowManager(): WindowManager {\r\n return this.windowManager;\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Get i18n instance for translations\r\n */\r\n getI18n() {\r\n return getI18n();\r\n }\r\n\r\n /**\r\n * Get translation string\r\n */\r\n t(key: string, defaultValue?: string) {\r\n const i18n = getI18n();\r\n if (!i18n) {\r\n console.warn('[ClientManager] i18n not initialized. Using default value or key.');\r\n return defaultValue ?? key;\r\n }\r\n return i18n.t(key) ?? defaultValue ?? key;\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Get lifecycle phase\r\n */\r\n getPhase() {\r\n return this.lifecycle;\r\n }\r\n\r\n /**\r\n * Check if ready\r\n */\r\n isReady(): boolean {\r\n return this.lifecycle === 'ready';\r\n }\r\n\r\n /**\r\n * Internal logging\r\n */\r\n private log(message: string): void {\r\n if (this.debug) {\r\n console.log(`[ClientManager] ${message}`);\r\n }\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n }\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ ════ ════════════════════════════════════════╗\r\n\r\n /**\r\n * Get ClientManager instance if available\r\n */\r\n export function getGlobalClientManager(): ClientManager | undefined {\r\n return globalClientManagerInstance;\r\n }\r\n\r\n export async function start(config: types.ClientManagerConfig): Promise<ClientManager> {\r\n // Read i18n config from HTML meta tag (injected by server)\r\n const metaI18n = document.querySelector('meta[name=\"app-i18n\"]');\r\n if (metaI18n) {\r\n const i18nData = JSON.parse(metaI18n.getAttribute('content') || '{}');\r\n config.i18n = i18nData;\r\n }\r\n\r\n // Create ClientManager instance\r\n const manager = new ClientManager(config);\r\n\r\n // Phase 0: I18N Setup\r\n await setupI18n(config.i18n || {\r\n defaultLanguage: 'en',\r\n supportedLanguages: ['en'],\r\n });\r\n\r\n // Phase 1: BOOT\r\n manager.boot();\r\n\r\n // Phase 2: READY\r\n manager.ready();\r\n\r\n // Handle cleanup on page unload\r\n window.addEventListener('beforeunload', async () => {\r\n await manager.destroy();\r\n });\r\n\r\n return manager;\r\n }\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ ════ ════════════════════════════════════════╗\r\n\r\n export * from './types';\r\n export { t } from '@minejs/i18n';\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["globalClientManagerInstance","ClientManager","config","signal","EventsManager","WindowManager","routesArray","path","component","createRouter","to","eventOrTarget","callbackOrEvent","handler","options","plugin","err","selector","i","container","pageContainer","layoutJsx","mountJSX","pageSlot","effect","currentPath","Component","jsx","e","target","event","getI18n","key","defaultValue","i18n","message","getGlobalClientManager","start","metaI18n","i18nData","manager","setupI18n"],"mappings":"4NAqBI,IAAIA,EAESC,CAAAA,CAAN,KAAoB,CAenB,WAAA,CAAYC,CAAAA,CAAmC,CAR/C,IAAA,CAAQ,SAAA,CAAyE,UAEjF,IAAA,CAAQ,KAAA,CAAiD,EAAC,CAC1D,IAAA,CAAQ,OAAA,CAA6C,EAAC,CAEtD,IAAA,CAAQ,gBAA6D,EAAC,CACtE,KAAQ,iBAAA,CAAsBC,MAAAA,CAAe,OAAO,QAAA,CAAS,QAAA,EAAY,GAAG,CAAA,CAGxE,IAAA,CAAK,OAASD,CAAAA,CACd,IAAA,CAAK,MAAQA,CAAAA,CAAO,KAAA,EAAS,MAE7B,IAAA,CAAK,GAAA,CAAI,+BAA+B,CAAA,CAGpCA,CAAAA,CAAO,YACP,IAAA,CAAK,KAAA,CAAQ,CAAE,GAAGA,CAAAA,CAAO,SAAU,CAAA,CAAA,CAIvC,IAAA,CAAK,QAAUA,CAAAA,CAAO,OAAA,EAAW,EAAC,CAGlC,IAAA,CAAK,gBAAkBA,CAAAA,CAAO,MAAA,CAG9B,KAAK,aAAA,CAAgB,IAAIE,aAAAA,CACzB,IAAA,CAAK,aAAA,CAAgB,IAAIC,cAGzB,IAAMC,CAAAA,CAAc,OAAO,OAAA,CAAQJ,CAAAA,CAAO,MAAM,CAAA,CAAE,GAAA,CAAI,CAAC,CAACK,CAAAA,CAAMC,CAAS,CAAA,IAAO,CAC1E,KAAAD,CAAAA,CACA,SAAA,CAAAC,CACJ,CAAA,CAAE,CAAA,CAEF,KAAK,MAAA,CAASC,YAAAA,CAAa,CACvB,MAAA,CAAQH,CAAAA,CACR,kBAAmBJ,CAAAA,CAAO,iBAC9B,CAAC,CAAA,CAGD,IAAA,CAAK,OAAO,SAAA,CAAWQ,CAAAA,EAAO,CAC1B,IAAA,CAAK,iBAAA,CAAkB,IAAIA,CAAAA,CAAG,IAAI,EACtC,CAAC,CAAA,CAIDV,CAAAA,CAA8B,IAAA,CAE9B,IAAA,CAAK,GAAA,CAAI,8BAA8B,EAC3C,CAmBA,GACIW,CAAAA,CACAC,CAAAA,CACAC,EACAC,CAAAA,CACmB,CAEnB,OAAI,OAAOH,CAAAA,EAAkB,UAAYA,CAAAA,CAAc,UAAA,CAAW,IAAI,CAAA,EAClE,IAAA,CAAK,MAAMA,CAA+C,CAAA,CAAIC,EACvD,IAAA,EAIJ,IAAA,CAAK,cAAc,EAAA,CACtBD,CAAAA,CACAC,EACAC,CAAAA,CACAC,CACJ,CACJ,CAUA,MAAM,MAAsB,CACxB,GAAI,KAAK,SAAA,GAAc,SAAA,CAAW,CAC9B,OAAA,CAAQ,IAAA,CAAK,6CAA6C,CAAA,CAC1D,MACJ,CAEA,IAAA,CAAK,GAAA,CAAI,oBAAe,EAExB,GAAI,CAEA,QAAWC,CAAAA,IAAU,IAAA,CAAK,QAClBA,CAAAA,CAAO,MAAA,GACP,KAAK,GAAA,CAAI,CAAA,sBAAA,EAAoBA,EAAO,IAAI,CAAA,CAAE,EAC1C,MAAMA,CAAAA,CAAO,OAAO,CAChB,KAAA,CAAO,KAAK,KAAA,CACZ,MAAA,CAAQ,KAAK,MACjB,CAAC,GAKL,IAAA,CAAK,KAAA,CAAM,SACX,IAAA,CAAK,GAAA,CAAI,4BAAuB,CAAA,CAChC,MAAM,KAAK,KAAA,CAAM,MAAA,IAGrB,IAAA,CAAK,GAAA,CAAI,4BAAuB,EACpC,CAAA,MAASC,CAAAA,CAAK,CACV,MAAA,OAAA,CAAQ,KAAA,CAAM,+BAAgCA,CAAG,CAAA,CAC3CA,CACV,CACJ,CAQA,MAAM,KAAA,EAAuB,CACzB,GAAI,IAAA,CAAK,SAAA,GAAc,UAAW,CAC9B,OAAA,CAAQ,KAAK,qDAAqD,CAAA,CAClE,MACJ,CAEA,IAAA,CAAK,IAAI,qBAAgB,CAAA,CAEzB,GAAI,CACA,IAAMC,EAAW,MAAA,CAGhB,QAAA,CAAS,cAAcA,CAAQ,CAAA,CAAkB,GAAK,MAAA,CAGvD,IAAA,CAAK,MAAMA,CAAQ,CAAA,CAEnB,KAAK,GAAA,CAAI,uBAAkB,EAG3B,IAAA,IAAWF,CAAAA,IAAU,IAAA,CAAK,OAAA,CAClBA,CAAAA,CAAO,OAAA,GACP,KAAK,GAAA,CAAI,CAAA,uBAAA,EAAqBA,EAAO,IAAI,CAAA,CAAE,EAC3C,MAAMA,CAAAA,CAAO,QAAQ,CACjB,KAAA,CAAO,KAAK,KAAA,CACZ,MAAA,CAAQ,KAAK,MACjB,CAAC,GAKL,IAAA,CAAK,KAAA,CAAM,UACX,IAAA,CAAK,GAAA,CAAI,6BAAwB,CAAA,CACjC,MAAM,KAAK,KAAA,CAAM,OAAA,IAGrB,IAAA,CAAK,SAAA,CAAY,QACjB,IAAA,CAAK,GAAA,CAAI,6BAAwB,CAAA,CACjC,IAAA,CAAK,IAAI,sBAAiB,EAC9B,OAASC,CAAAA,CAAK,CACV,MAAA,OAAA,CAAQ,KAAA,CAAM,+BAAA,CAAiCA,CAAG,EAC5CA,CACV,CACJ,CAKA,MAAM,OAAA,EAAyB,CAC3B,GAAI,IAAA,CAAK,YAAc,WAAA,CAAa,CAChC,QAAQ,IAAA,CAAK,mCAAmC,EAChD,MACJ,CAEA,KAAK,SAAA,CAAY,YAAA,CACjB,IAAA,CAAK,GAAA,CAAI,uBAAkB,CAAA,CAE3B,GAAI,CAEA,IAAA,IAASE,EAAI,IAAA,CAAK,OAAA,CAAQ,OAAS,CAAA,CAAGA,CAAAA,EAAK,EAAGA,CAAAA,EAAAA,CAAK,CAC/C,IAAMH,CAAAA,CAAS,IAAA,CAAK,QAAQG,CAAC,CAAA,CACzBH,EAAO,SAAA,GACP,IAAA,CAAK,GAAA,CAAI,CAAA,yBAAA,EAAuBA,CAAAA,CAAO,IAAI,EAAE,CAAA,CAC7C,MAAMA,EAAO,SAAA,CAAU,CACnB,MAAO,IAAA,CAAK,KAAA,CACZ,OAAQ,IAAA,CAAK,MACjB,CAAC,CAAA,EAET,CAGI,KAAK,KAAA,CAAM,SAAA,GACX,KAAK,GAAA,CAAI,+BAA0B,EACnC,MAAM,IAAA,CAAK,MAAM,SAAA,EAAU,CAAA,CAI/B,KAAK,aAAA,CAAc,OAAA,GACnB,IAAA,CAAK,aAAA,CAAc,SAAQ,CAE3B,IAAA,CAAK,UAAY,WAAA,CACjB,IAAA,CAAK,IAAI,+BAA0B,EACvC,OAASC,CAAAA,CAAK,CACV,MAAA,OAAA,CAAQ,KAAA,CAAM,iCAAA,CAAmCA,CAAG,EAC9CA,CACV,CACJ,CAUA,QAAA,CAAST,CAAAA,CAAoB,CACzB,IAAA,CAAK,MAAA,CAAO,KAAKA,CAAI,EACzB,CAOA,KAAA,CAAMU,CAAAA,CAAsC,CACxC,IAAME,CAAAA,CAAY,OAAOF,CAAAA,EAAa,QAAA,CAC/B,SAAS,aAAA,CAAcA,CAAQ,EAChCA,CAAAA,CAEN,GAAI,CAACE,CAAAA,CAAW,CACZ,QAAQ,IAAA,CAAK,yCAAA,CAA2CF,CAAQ,CAAA,CAChE,MACJ,CAEA,IAAIG,CAAAA,CAAgBD,EAGpB,GAAI,IAAA,CAAK,OAAO,UAAA,CACZ,GAAI,CACA,IAAME,CAAAA,CAAY,IAAA,CAAK,OAAO,UAAA,EAAW,CACzC,GAAIA,CAAAA,CAAW,CACXC,MAASD,CAAAA,CAAWF,CAAS,EAC7B,IAAA,CAAK,GAAA,CAAI,4BAAuB,CAAA,CAGhC,IAAMI,EAAWJ,CAAAA,CAAU,aAAA,CAAc,eAAe,CAAA,CACpDI,CAAAA,CACAH,EAAgBG,CAAAA,CAEhB,OAAA,CAAQ,KAAK,4GAA4G,EAEjI,CACJ,CAAA,MAASP,CAAAA,CAAK,CACV,OAAA,CAAQ,KAAA,CAAM,+CAAgDA,CAAG,CAAA,CACjEG,EAAU,SAAA,CAAY,kCAAA,CACtB,MACJ,CAIJK,MAAAA,CAAO,IAAM,CACT,IAAMC,CAAAA,CAAc,IAAA,CAAK,iBAAA,EAAkB,CACrCC,EAAY,IAAA,CAAK,eAAA,CAAgBD,CAAW,CAAA,EAC3C,IAAA,CAAK,OAAO,iBAAA,EACZ,IAAA,CAKP,GAFAL,CAAAA,CAAc,SAAA,CAAY,GAEtBM,CAAAA,CACA,GAAI,CACA,IAAMC,CAAAA,CAAMD,GAAU,CAElBC,CAAAA,EACAL,KAAAA,CAASK,CAAAA,CAAKP,CAAa,EAEnC,OAASJ,CAAAA,CAAK,CACV,QAAQ,KAAA,CAAM,4CAAA,CAA8CS,EAAaT,CAAG,CAAA,CAC5EI,EAAc,SAAA,CAAY,iCAC9B,MAEAA,CAAAA,CAAc,SAAA,CAAY,2CAG9B,IAAA,CAAK,GAAA,CAAI,4BAAuBK,CAAW,CAAA,CAAE,EACjD,CAAC,CAAA,CAGD,IAAA,CAAK,OAAO,IAAA,CAAK,IAAA,CAAK,mBAAmB,CAAA,CACzC,KAAK,GAAA,CAAI,+BAA0B,EACvC,CAKA,cAAA,EAAiB,CACb,OAAO,IAAA,CAAK,iBAChB,CAKA,iBAAA,CAAkBlB,EAAc,CAC5B,OAAQqB,GAAkB,CACtBA,CAAAA,CAAE,gBAAe,CACjB,IAAA,CAAK,SAASrB,CAAI,EACtB,CACJ,CAKA,SAAA,EAAY,CACR,OAAO,IAAA,CAAK,MAChB,CAUA,GAAA,CAAIsB,EAAqBC,CAAAA,CAAejB,CAAAA,CAA8B,CAClE,IAAA,CAAK,aAAA,CAAc,GAAA,CAAIgB,CAAAA,CAAQC,CAAAA,CAAOjB,CAAO,EACjD,CAKA,gBAAA,EAAkC,CAC9B,OAAO,IAAA,CAAK,aAChB,CAUA,WAAA,EAAc,CACV,OAAO,IAAA,CAAK,cAAc,WAAA,EAC9B,CAKA,gBAAA,EAAkC,CAC9B,OAAO,IAAA,CAAK,aAChB,CAUA,OAAA,EAAU,CACN,OAAOkB,OAAAA,EACX,CAKA,CAAA,CAAEC,CAAAA,CAAaC,EAAuB,CAClC,IAAMC,EAAOH,OAAAA,EAAQ,CACrB,OAAKG,CAAAA,CAIEA,CAAAA,CAAK,EAAEF,CAAG,CAAA,EAAKC,GAAgBD,CAAAA,EAHlC,OAAA,CAAQ,IAAA,CAAK,mEAAmE,CAAA,CACzEC,CAAAA,EAAgBD,EAG/B,CAUA,QAAA,EAAW,CACP,OAAO,IAAA,CAAK,SAChB,CAKA,OAAA,EAAmB,CACf,OAAO,IAAA,CAAK,YAAc,OAC9B,CAKQ,IAAIG,CAAAA,CAAuB,CAC3B,KAAK,KAAA,EACL,OAAA,CAAQ,IAAI,CAAA,gBAAA,EAAmBA,CAAO,EAAE,EAEhD,CAIR,EAWO,SAASC,CAAAA,EAAoD,CAChE,OAAOpC,CACX,CAEA,eAAsBqC,CAAAA,CAAMnC,EAA2D,CAEnF,IAAMoC,EAAW,QAAA,CAAS,aAAA,CAAc,uBAAuB,CAAA,CAC/D,GAAIA,CAAAA,CAAU,CACV,IAAMC,CAAAA,CAAW,KAAK,KAAA,CAAMD,CAAAA,CAAS,aAAa,SAAS,CAAA,EAAK,IAAI,CAAA,CACpEpC,CAAAA,CAAO,KAAOqC,EAClB,CAGA,IAAMC,CAAAA,CAAU,IAAIvC,EAAcC,CAAM,CAAA,CAGxC,aAAMuC,SAAAA,CAAUvC,CAAAA,CAAO,IAAA,EAAQ,CAC3B,eAAA,CAAiB,IAAA,CACjB,mBAAoB,CAAC,IAAI,CAC7B,CAAC,CAAA,CAGDsC,EAAQ,IAAA,EAAK,CAGbA,EAAQ,KAAA,EAAM,CAGd,OAAO,gBAAA,CAAiB,cAAA,CAAgB,SAAY,CAChD,MAAMA,EAAQ,OAAA,GAClB,CAAC,CAAA,CAEMA,CACX","file":"index.js","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\r\n// src/index.ts\r\n//\r\n// Made with ❤️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import * as types from './types';\r\n import { signal, effect } from '@minejs/signals';\r\n import { setupI18n, getI18n } from '@minejs/i18n';\r\n import { mount as mountJSX } from '@minejs/jsx';\r\n import { EventsManager, Router, WindowManager, createRouter } from '@minejs/browser';\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ CORE ════════════════════════════════════════╗\r\n\r\n let globalClientManagerInstance: ClientManager | undefined;\r\n\r\n export class ClientManager {\r\n\r\n // ┌──────────────────────────────── INIT ──────────────────────────────┐\r\n\r\n private router : Router;\r\n private eventsManager : EventsManager;\r\n private windowManager : WindowManager;\r\n private lifecycle : 'booting' | 'ready' | 'destroying' | 'destroyed' = 'booting';\r\n private config : types.ClientManagerConfig;\r\n private hooks : types.ClientManagerHooks = {};\r\n private plugins : types.ClientPlugin[] = [];\r\n private debug : boolean;\r\n private routeComponents : Record<string, types.RouteComponent> = {};\r\n private currentPathSignal = signal<string>(window.location.pathname ?? '/');\r\n\r\n constructor(config: types.ClientManagerConfig) {\r\n this.config = config;\r\n this.debug = config.debug ?? false;\r\n\r\n this.log('[INIT] Creating ClientManager');\r\n\r\n // Merge lifecycle hooks from config\r\n if (config.lifecycle) {\r\n this.hooks = { ...config.lifecycle };\r\n }\r\n\r\n // Store plugins from config\r\n this.plugins = config.plugins ?? [];\r\n\r\n // Store route components provided by user\r\n this.routeComponents = config.routes;\r\n\r\n // Initialize managers from @minejs/browser\r\n this.eventsManager = new EventsManager();\r\n this.windowManager = new WindowManager();\r\n\r\n // Initialize router with user-provided routes\r\n const routesArray = Object.entries(config.routes).map(([path, component]) => ({\r\n path,\r\n component\r\n }));\r\n\r\n this.router = createRouter({\r\n routes: routesArray,\r\n notFoundComponent: config.notFoundComponent,\r\n });\r\n\r\n // Connect router changes to signal for automatic re-rendering\r\n this.router.afterEach((to) => {\r\n this.currentPathSignal.set(to.path);\r\n });\r\n\r\n // Store clientManager instance\r\n // eslint-disable-next-line @typescript-eslint/no-this-alias\r\n globalClientManagerInstance = this;\r\n\r\n this.log('[INIT] ClientManager created');\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Setup lifecycle hooks OR bind events\r\n * Overloaded: on(event: 'onBoot'|'onReady'|'onDestroy', callback) - lifecycle\r\n * on(target, event, handler) - event binding\r\n */\r\n on(event: keyof types.ClientManagerHooks, callback: any): this;\r\n on<K extends keyof HTMLElementEventMap>(\r\n target: EventTarget,\r\n event: K | string,\r\n handler: EventListener,\r\n options?: AddEventListenerOptions\r\n ): () => void;\r\n on(\r\n eventOrTarget: keyof types.ClientManagerHooks | EventTarget,\r\n callbackOrEvent?: any,\r\n handler?: EventListener,\r\n options?: AddEventListenerOptions\r\n ): this | (() => void) {\r\n // Check if this is a lifecycle hook call\r\n if (typeof eventOrTarget === 'string' && eventOrTarget.startsWith('on')) {\r\n this.hooks[eventOrTarget as keyof types.ClientManagerHooks] = callbackOrEvent;\r\n return this;\r\n }\r\n\r\n // Otherwise it's an event binding\r\n return this.eventsManager.on(\r\n eventOrTarget as EventTarget,\r\n callbackOrEvent as string,\r\n handler as EventListener,\r\n options\r\n );\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Bootstrap the app - Phase 1: BOOT\r\n */\r\n async boot(): Promise<void> {\r\n if (this.lifecycle !== 'booting') {\r\n console.warn('[ClientManager] Already booted or destroyed');\r\n return;\r\n }\r\n\r\n this.log('⚡ Phase: BOOT');\r\n\r\n try {\r\n // Call plugins onBoot hooks\r\n for (const plugin of this.plugins) {\r\n if (plugin.onBoot) {\r\n this.log(`→ Plugin onBoot: ${plugin.name}`);\r\n await plugin.onBoot({\r\n debug: this.debug,\r\n config: this.config\r\n });\r\n }\r\n }\r\n\r\n // Call user onBoot hook\r\n if (this.hooks.onBoot) {\r\n this.log('→ Calling onBoot hook');\r\n await this.hooks.onBoot();\r\n }\r\n\r\n this.log('✓ BOOT phase complete');\r\n } catch (err) {\r\n console.error('[ClientManager] Boot failed:', err);\r\n throw err;\r\n }\r\n }\r\n\r\n /**\r\n * Ready the app - Phase 2: READY\r\n * Mount to DOM and make everything live\r\n *\r\n * Root selector is always 'body'.\r\n */\r\n async ready(): Promise<void> {\r\n if (this.lifecycle !== 'booting') {\r\n console.warn('[ClientManager] Cannot ready - not in booting phase');\r\n return;\r\n }\r\n\r\n this.log('⚡ Phase: READY');\r\n\r\n try {\r\n const selector = 'body';\r\n\r\n // Set body id to 'root' for mounting\r\n (document.querySelector(selector) as HTMLElement).id = 'root';\r\n\r\n // Mount router\r\n this.mount(selector);\r\n\r\n this.log('→ Router mounted');\r\n\r\n // Call plugins onReady hooks\r\n for (const plugin of this.plugins) {\r\n if (plugin.onReady) {\r\n this.log(`→ Plugin onReady: ${plugin.name}`);\r\n await plugin.onReady({\r\n debug: this.debug,\r\n config: this.config\r\n });\r\n }\r\n }\r\n\r\n // Call user onReady hook\r\n if (this.hooks.onReady) {\r\n this.log('→ Calling onReady hook');\r\n await this.hooks.onReady();\r\n }\r\n\r\n this.lifecycle = 'ready';\r\n this.log('✓ READY phase complete');\r\n this.log('✓ App is ready!');\r\n } catch (err) {\r\n console.error('[ClientManager] Ready failed:', err);\r\n throw err;\r\n }\r\n }\r\n\r\n /**\r\n * Shutdown the app - Phase 3: DESTROY\r\n */\r\n async destroy(): Promise<void> {\r\n if (this.lifecycle === 'destroyed') {\r\n console.warn('[ClientManager] Already destroyed');\r\n return;\r\n }\r\n\r\n this.lifecycle = 'destroying';\r\n this.log('⚡ Phase: DESTROY');\r\n\r\n try {\r\n // Call plugins onDestroy hooks (in reverse order)\r\n for (let i = this.plugins.length - 1; i >= 0; i--) {\r\n const plugin = this.plugins[i];\r\n if (plugin.onDestroy) {\r\n this.log(`→ Plugin onDestroy: ${plugin.name}`);\r\n await plugin.onDestroy({\r\n debug: this.debug,\r\n config: this.config\r\n });\r\n }\r\n }\r\n\r\n // Call user onDestroy hook\r\n if (this.hooks.onDestroy) {\r\n this.log('→ Calling onDestroy hook');\r\n await this.hooks.onDestroy();\r\n }\r\n\r\n // Cleanup managers\r\n this.eventsManager.destroy();\r\n this.windowManager.destroy();\r\n\r\n this.lifecycle = 'destroyed';\r\n this.log('✓ DESTROY phase complete');\r\n } catch (err) {\r\n console.error('[ClientManager] Destroy failed:', err);\r\n throw err;\r\n }\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Navigate to path\r\n */\r\n navigate(path: string): void {\r\n this.router.push(path);\r\n }\r\n\r\n /**\r\n * Mount router to DOM element and setup reactive routing\r\n * Automatically re-renders when route changes\r\n * If rootLayout is provided, it wraps all pages\r\n */\r\n mount(selector: string | HTMLElement): void {\r\n const container = typeof selector === 'string'\r\n ? (document.querySelector(selector) as HTMLElement)\r\n : selector;\r\n\r\n if (!container) {\r\n console.warn('[ClientManager] Mount target not found:', selector);\r\n return;\r\n }\r\n\r\n let pageContainer = container;\r\n\r\n // If rootLayout is provided, mount it first (only once)\r\n if (this.config.rootLayout) {\r\n try {\r\n const layoutJsx = this.config.rootLayout();\r\n if (layoutJsx) {\r\n mountJSX(layoutJsx, container);\r\n this.log('→ Root layout mounted');\r\n\r\n // Find the page slot for rendering pages\r\n const pageSlot = container.querySelector('#main-overlay');\r\n if (pageSlot) {\r\n pageContainer = pageSlot as HTMLElement;\r\n } else {\r\n console.warn('[ClientManager] Page slot #main-overlay not found in root layout. Pages will render to the root container.');\r\n }\r\n }\r\n } catch (err) {\r\n console.error('[ClientManager] Error rendering root layout:', err);\r\n container.innerHTML = '<p>Error loading root layout</p>';\r\n return;\r\n }\r\n }\r\n\r\n // Setup reactive routing effect - re-renders when currentPathSignal changes\r\n effect(() => {\r\n const currentPath = this.currentPathSignal();\r\n const Component = this.routeComponents[currentPath]\r\n || this.config.notFoundComponent\r\n || null;\r\n\r\n // Clear only the page container (not the entire root if layout exists)\r\n pageContainer.innerHTML = '';\r\n\r\n if (Component) {\r\n try {\r\n const jsx = Component();\r\n // Use @minejs/jsx mount function to properly render JSX\r\n if (jsx) {\r\n mountJSX(jsx, pageContainer);\r\n }\r\n } catch (err) {\r\n console.error('[ClientManager] Error rendering component:', currentPath, err);\r\n pageContainer.innerHTML = '<p>Error loading component</p>';\r\n }\r\n } else {\r\n pageContainer.innerHTML = '<p>No component found for this route</p>';\r\n }\r\n\r\n this.log(`→ Route changed to: ${currentPath}`);\r\n });\r\n\r\n // Trigger initial render by pushing the current path\r\n this.router.push(this.currentPathSignal());\r\n this.log('→ Routing setup complete');\r\n }\r\n\r\n /**\r\n * Get current path signal for reactivity\r\n */\r\n getCurrentPath() {\r\n return this.currentPathSignal;\r\n }\r\n\r\n /**\r\n * Create navigation link handler\r\n */\r\n createLinkHandler(path: string) {\r\n return (e: MouseEvent) => {\r\n e.preventDefault();\r\n this.navigate(path);\r\n };\r\n }\r\n\r\n /**\r\n * Get underlying router for advanced usage\r\n */\r\n getRouter() {\r\n return this.router;\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Unbind event\r\n */\r\n off(target: EventTarget, event: string, handler: EventListener): void {\r\n this.eventsManager.off(target, event, handler);\r\n }\r\n\r\n /**\r\n * Get events manager directly\r\n */\r\n getEventsManager(): EventsManager {\r\n return this.eventsManager;\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Get viewport info as reactive signal\r\n */\r\n getViewport() {\r\n return this.windowManager.getViewport();\r\n }\r\n\r\n /**\r\n * Get window manager directly\r\n */\r\n getWindowManager(): WindowManager {\r\n return this.windowManager;\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Get i18n instance for translations\r\n */\r\n getI18n() {\r\n return getI18n();\r\n }\r\n\r\n /**\r\n * Get translation string\r\n */\r\n t(key: string, defaultValue?: string) {\r\n const i18n = getI18n();\r\n if (!i18n) {\r\n console.warn('[ClientManager] i18n not initialized. Using default value or key.');\r\n return defaultValue ?? key;\r\n }\r\n return i18n.t(key) ?? defaultValue ?? key;\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n\r\n // ┌──────────────────────────────── ──── ──────────────────────────────┐\r\n\r\n /**\r\n * Get lifecycle phase\r\n */\r\n getPhase() {\r\n return this.lifecycle;\r\n }\r\n\r\n /**\r\n * Check if ready\r\n */\r\n isReady(): boolean {\r\n return this.lifecycle === 'ready';\r\n }\r\n\r\n /**\r\n * Internal logging\r\n */\r\n private log(message: string): void {\r\n if (this.debug) {\r\n console.log(`[ClientManager] ${message}`);\r\n }\r\n }\r\n\r\n // └────────────────────────────────────────────────────────────────────┘\r\n\r\n }\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ ════ ════════════════════════════════════════╗\r\n\r\n /**\r\n * Get ClientManager instance if available\r\n */\r\n export function getGlobalClientManager(): ClientManager | undefined {\r\n return globalClientManagerInstance;\r\n }\r\n\r\n export async function start(config: types.ClientManagerConfig): Promise<ClientManager> {\r\n // Read i18n config from HTML meta tag (injected by server)\r\n const metaI18n = document.querySelector('meta[name=\"app-i18n\"]');\r\n if (metaI18n) {\r\n const i18nData = JSON.parse(metaI18n.getAttribute('content') || '{}');\r\n config.i18n = i18nData;\r\n }\r\n\r\n // Create ClientManager instance\r\n const manager = new ClientManager(config);\r\n\r\n // Phase 0: I18N Setup\r\n await setupI18n(config.i18n || {\r\n defaultLanguage: 'en',\r\n supportedLanguages: ['en'],\r\n });\r\n\r\n // Phase 1: BOOT\r\n manager.boot();\r\n\r\n // Phase 2: READY\r\n manager.ready();\r\n\r\n // Handle cleanup on page unload\r\n window.addEventListener('beforeunload', async () => {\r\n await manager.destroy();\r\n });\r\n\r\n return manager;\r\n }\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ ════ ════════════════════════════════════════╗\r\n\r\n export * from './types';\r\n export { t } from '@minejs/i18n';\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cruxjs/client",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Client application manager with routing, lifecycle hooks, and plugin-based extensibility.",
5
5
  "keywords": ["cruxjs", "client"],
6
6
  "license": "MIT",