@cruxjs/client 0.2.7 → 0.2.8

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.2.7-black"/>
11
+ <img src="https://img.shields.io/badge/v-0.2.8-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" />
@@ -72,6 +72,7 @@
72
72
  },
73
73
 
74
74
  notFoundComponent : NotFoundPage,
75
+ allowedQueryParams? : (string | RegExp)[]
75
76
 
76
77
  lifecycle: {
77
78
  onBoot : () => console.log('App booting...'),
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var signals=require('@minejs/signals'),jsx=require('@minejs/jsx'),browser=require('@minejs/browser'),i18n=require('@minejs/i18n');var d,a=class{constructor(e){this.lifecycle="booting";this.hooks={};this.extensions=[];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.extensions=e.extensions??[],this.routeComponents=e.routes,this.eventsManager=new browser.EventsManager,this.windowManager=new browser.WindowManager;let t=Object.entries(e.routes).map(([n,r])=>({path:n,component:r}));this.router=browser.createRouter({routes:t,notFoundComponent:e.notFoundComponent}),this.router.afterEach(n=>{this.currentPathSignal.set(n.path);}),d=this,this.log("[INIT] ClientManager created");}on(e,t,n,r){return typeof e=="string"&&e.startsWith("on")?(this.hooks[e]=t,this):this.eventsManager.on(e,t,n,r)}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.extensions)e.onBoot&&(this.log(`\u2192 Extension onBoot: ${e.name}`),await e.onBoot({debug:this.debug,config:{},cconfig: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.extensions)t.onReady&&(this.log(`\u2192 Extension onReady: ${t.name}`),await t.onReady({debug:this.debug,config:{},cconfig: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.extensions.length-1;e>=0;e--){let t=this.extensions[e];t.onDestroy&&(this.log(`\u2192 Extension onDestroy: ${t.name}`),await t.onDestroy({debug:this.debug,config:{},cconfig: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 r=this.config.rootLayout();if(r){jsx.mount(r,t),this.log("\u2192 Root layout mounted");let i=t.querySelector("#main-overlay");i?n=i:console.warn("[ClientManager] Page slot #main-overlay not found in root layout. Pages will render to the root container.");}}catch(r){console.error("[ClientManager] Error rendering root layout:",r),t.innerHTML="<p>Error loading root layout</p>";return}signals.effect(()=>{let r=this.currentPathSignal(),i=this.routeComponents[r]||this.config.notFoundComponent||null;if(n.innerHTML="",i)try{let s=i();s&&jsx.mount(s,n);}catch(s){console.error("[ClientManager] Error rendering component:",r,s),n.innerHTML="<p>Error loading component</p>";}else n.innerHTML="<p>No component found for this route</p>";this.log(`\u2192 Route changed to: ${r}`);}),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 window.__i18n}t(e,t,n){return window.__i18n?window.__i18n.t(e,t)??n??e:(console.warn("[ClientManager] i18n not initialized. Using default value or key."),n??e)}getPhase(){return this.lifecycle}isReady(){return this.lifecycle==="ready"}log(e){this.debug&&console.log(`[ClientManager] ${e}`);}},l=()=>d,g=()=>l()?.getRouter(),x=()=>g()?.back(),b=()=>g()?.forward(),L=o=>g()?.push(o),R=o=>g()?.replace(o),h=()=>l()?.getI18n(),k=()=>h()?.getLanguage(),P=o=>h()?.setLanguage(o),T=(o,e,t)=>l()?.t(o,e,t),H=(o,e,t,n)=>h()?.tLang(o,e,t,n)??n??e;async function A(o){let e=document.querySelector('meta[name="app-i18n"]');if(e){let n=JSON.parse(e.getAttribute("content")||"{}");o.i18n=n;}let t=new a(o);return window.__i18n=await i18n.setupI18n(o.i18n||{defaultLanguage:"en",supportedLanguages:["en"]}),t.boot(),t.ready(),window.addEventListener("beforeunload",async()=>{await t.destroy();}),t}exports.CM=l;exports.ClientManager=a;exports.back=x;exports.forward=b;exports.getI18n=h;exports.getLang=k;exports.getRouter=g;exports.push=L;exports.replace=R;exports.setLang=P;exports.start=A;exports.t=T;exports.tLang=H;//# sourceMappingURL=index.cjs.map
1
+ 'use strict';var signals=require('@minejs/signals'),jsx=require('@minejs/jsx'),browser=require('@minejs/browser'),i18n=require('@minejs/i18n');var d,s=class{constructor(e){this.lifecycle="booting";this.hooks={};this.extensions=[];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.extensions=e.extensions??[],this.routeComponents=e.routes,this.eventsManager=new browser.EventsManager,this.windowManager=new browser.WindowManager;let t=Object.entries(e.routes).map(([n,r])=>({path:n,component:r}));this.router=browser.createRouter({routes:t,notFoundComponent:e.notFoundComponent,allowedQueryParams:e.allowedQueryParams}),this.router.afterEach(n=>{this.currentPathSignal.set(n.path);}),d=this,this.log("[INIT] ClientManager created");}on(e,t,n,r){return typeof e=="string"&&e.startsWith("on")?(this.hooks[e]=t,this):this.eventsManager.on(e,t,n,r)}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.extensions)e.onBoot&&(this.log(`\u2192 Extension onBoot: ${e.name}`),await e.onBoot({debug:this.debug,config:{},cconfig: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.extensions)t.onReady&&(this.log(`\u2192 Extension onReady: ${t.name}`),await t.onReady({debug:this.debug,config:{},cconfig: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.extensions.length-1;e>=0;e--){let t=this.extensions[e];t.onDestroy&&(this.log(`\u2192 Extension onDestroy: ${t.name}`),await t.onDestroy({debug:this.debug,config:{},cconfig: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 r=this.config.rootLayout();if(r){jsx.mount(r,t),this.log("\u2192 Root layout mounted");let i=t.querySelector("#main-overlay");i?n=i:console.warn("[ClientManager] Page slot #main-overlay not found in root layout. Pages will render to the root container.");}}catch(r){console.error("[ClientManager] Error rendering root layout:",r),t.innerHTML="<p>Error loading root layout</p>";return}signals.effect(()=>{let r=this.currentPathSignal(),i=this.routeComponents[r]||this.config.notFoundComponent||null;if(n.innerHTML="",i)try{let a=i();a&&jsx.mount(a,n);}catch(a){console.error("[ClientManager] Error rendering component:",r,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: ${r}`);}),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 window.__i18n}t(e,t,n){return window.__i18n?window.__i18n.t(e,t)??n??e:(console.warn("[ClientManager] i18n not initialized. Using default value or key."),n??e)}getPhase(){return this.lifecycle}isReady(){return this.lifecycle==="ready"}log(e){this.debug&&console.log(`[ClientManager] ${e}`);}},l=()=>d,g=()=>l()?.getRouter(),x=()=>g()?.back(),b=()=>g()?.forward(),L=o=>g()?.push(o),R=o=>g()?.replace(o),h=()=>l()?.getI18n(),k=()=>h()?.getLanguage(),P=o=>h()?.setLanguage(o),T=(o,e,t)=>l()?.t(o,e,t),H=(o,e,t,n)=>h()?.tLang(o,e,t,n)??n??e;async function A(o){let e=document.querySelector('meta[name="app-i18n"]');if(e){let n=JSON.parse(e.getAttribute("content")||"{}");o.i18n=n;}let t=new s(o);return window.__i18n=await i18n.setupI18n(o.i18n||{defaultLanguage:"en",supportedLanguages:["en"]}),t.boot(),t.ready(),window.addEventListener("beforeunload",async()=>{await t.destroy();}),t}exports.CM=l;exports.ClientManager=s;exports.back=x;exports.forward=b;exports.getI18n=h;exports.getLang=k;exports.getRouter=g;exports.push=L;exports.replace=R;exports.setLang=P;exports.start=A;exports.t=T;exports.tLang=H;//# sourceMappingURL=index.cjs.map
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/mod/client_manager.ts","../src/index.ts"],"names":["globalClientManagerInstance","ClientManager","config","signal","EventsManager","WindowManager","routesArray","path","component","createRouter","to","eventOrTarget","callbackOrEvent","handler","options","extension","err","selector","i","container","pageContainer","layoutJsx","mountJSX","pageSlot","effect","currentPath","Component","jsx","e","target","event","key","params","defaultValue","message","CM","getRouter","back","forward","push","replace","getI18n","getLang","setLang","lang","t","tLang","start","metaI18n","i18nData","manager","setupI18n"],"mappings":"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","file":"index.cjs","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\r\n// src/mpd/client_manager.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 { 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 extensions : types.ClientExtension[] = [];\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 extensions from config\r\n this.extensions = config.extensions ?? [];\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 extensions onBoot hooks\r\n for (const extension of this.extensions) {\r\n if (extension.onBoot) {\r\n this.log(`→ Extension onBoot: ${extension.name}`);\r\n await extension.onBoot({\r\n debug: this.debug,\r\n config: {},\r\n cconfig: 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 extensions onReady hooks\r\n for (const extension of this.extensions) {\r\n if (extension.onReady) {\r\n this.log(`→ Extension onReady: ${extension.name}`);\r\n await extension.onReady({\r\n debug: this.debug,\r\n config: {},\r\n cconfig: 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 extensions onDestroy hooks (in reverse order)\r\n for (let i = this.extensions.length - 1; i >= 0; i--) {\r\n const extension = this.extensions[i];\r\n if (extension.onDestroy) {\r\n this.log(`→ Extension onDestroy: ${extension.name}`);\r\n await extension.onDestroy({\r\n debug: this.debug,\r\n config: {},\r\n cconfig: 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 (window as any).__i18n;\r\n }\r\n\r\n /**\r\n * Get translation string\r\n */\r\n t(key: string, params?: any, defaultValue?: string) {\r\n if (!(window as any).__i18n) {\r\n console.warn('[ClientManager] i18n not initialized. Using default value or key.');\r\n return defaultValue ?? key;\r\n }\r\n return (window as any).__i18n.t(key, params) ?? 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 // Quick access\r\n export const CM = (): ClientManager | undefined => globalClientManagerInstance;\r\n\r\n // Router\r\n export const getRouter = () => CM()?.getRouter();\r\n export const back = () => getRouter()?.back();\r\n export const forward = () => getRouter()?.forward();\r\n export const push = (path: string) => getRouter()?.push(path);\r\n export const replace = (path: string) => getRouter()?.replace(path);\r\n\r\n // i18n\r\n export const getI18n = () => CM()?.getI18n();\r\n export const getLang = () => getI18n()?.getLanguage();\r\n export const setLang = (lang: string) => getI18n()?.setLanguage(lang);\r\n export const t = (key: string, params?: any, defaultValue?: string) => CM()?.t(key, params, defaultValue);\r\n export const tLang = (lang: string, key: string, params?: any, defaultValue?: string) => getI18n()?.tLang(lang, key, params, defaultValue) ?? (defaultValue ?? key);\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\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 { ClientManagerConfig } from './types';\r\n import { ClientManager } from './mod/client_manager';\r\n import { setupI18n } from '@minejs/i18n';\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ MAIN ════════════════════════════════════════╗\r\n\r\n export * from './types';\r\n export * from './mod/client_manager';\r\n\r\n // Start\r\n export async function start(config: 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: Setup I18N\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n (window as any).__i18n = 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"]}
1
+ {"version":3,"sources":["../src/mod/client_manager.ts","../src/index.ts"],"names":["globalClientManagerInstance","ClientManager","config","signal","EventsManager","WindowManager","routesArray","path","component","createRouter","to","eventOrTarget","callbackOrEvent","handler","options","extension","err","selector","i","container","pageContainer","layoutJsx","mountJSX","pageSlot","effect","currentPath","Component","jsx","e","target","event","key","params","defaultValue","message","CM","getRouter","back","forward","push","replace","getI18n","getLang","setLang","lang","t","tLang","start","metaI18n","i18nData","manager","setupI18n"],"mappings":"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","file":"index.cjs","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\r\n// src/mpd/client_manager.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 { 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 extensions : types.ClientExtension[] = [];\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 extensions from config\r\n this.extensions = config.extensions ?? [];\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 allowedQueryParams: config.allowedQueryParams\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 extensions onBoot hooks\r\n for (const extension of this.extensions) {\r\n if (extension.onBoot) {\r\n this.log(`→ Extension onBoot: ${extension.name}`);\r\n await extension.onBoot({\r\n debug: this.debug,\r\n config: {},\r\n cconfig: 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 extensions onReady hooks\r\n for (const extension of this.extensions) {\r\n if (extension.onReady) {\r\n this.log(`→ Extension onReady: ${extension.name}`);\r\n await extension.onReady({\r\n debug: this.debug,\r\n config: {},\r\n cconfig: 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 extensions onDestroy hooks (in reverse order)\r\n for (let i = this.extensions.length - 1; i >= 0; i--) {\r\n const extension = this.extensions[i];\r\n if (extension.onDestroy) {\r\n this.log(`→ Extension onDestroy: ${extension.name}`);\r\n await extension.onDestroy({\r\n debug: this.debug,\r\n config: {},\r\n cconfig: 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 (window as any).__i18n;\r\n }\r\n\r\n /**\r\n * Get translation string\r\n */\r\n t(key: string, params?: any, defaultValue?: string) {\r\n if (!(window as any).__i18n) {\r\n console.warn('[ClientManager] i18n not initialized. Using default value or key.');\r\n return defaultValue ?? key;\r\n }\r\n return (window as any).__i18n.t(key, params) ?? 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 // Quick access\r\n export const CM = (): ClientManager | undefined => globalClientManagerInstance;\r\n\r\n // Router\r\n export const getRouter = () => CM()?.getRouter();\r\n export const back = () => getRouter()?.back();\r\n export const forward = () => getRouter()?.forward();\r\n export const push = (path: string) => getRouter()?.push(path);\r\n export const replace = (path: string) => getRouter()?.replace(path);\r\n\r\n // i18n\r\n export const getI18n = () => CM()?.getI18n();\r\n export const getLang = () => getI18n()?.getLanguage();\r\n export const setLang = (lang: string) => getI18n()?.setLanguage(lang);\r\n export const t = (key: string, params?: any, defaultValue?: string) => CM()?.t(key, params, defaultValue);\r\n export const tLang = (lang: string, key: string, params?: any, defaultValue?: string) => getI18n()?.tLang(lang, key, params, defaultValue) ?? (defaultValue ?? key);\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\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 { ClientManagerConfig } from './types';\r\n import { ClientManager } from './mod/client_manager';\r\n import { setupI18n } from '@minejs/i18n';\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ MAIN ════════════════════════════════════════╗\r\n\r\n export * from './types';\r\n export * from './mod/client_manager';\r\n\r\n // Start\r\n export async function start(config: 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: Setup I18N\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n (window as any).__i18n = 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"]}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import {signal,effect}from'@minejs/signals';import {mount}from'@minejs/jsx';import {EventsManager,WindowManager,createRouter}from'@minejs/browser';import {setupI18n}from'@minejs/i18n';var d,a=class{constructor(e){this.lifecycle="booting";this.hooks={};this.extensions=[];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.extensions=e.extensions??[],this.routeComponents=e.routes,this.eventsManager=new EventsManager,this.windowManager=new WindowManager;let t=Object.entries(e.routes).map(([n,r])=>({path:n,component:r}));this.router=createRouter({routes:t,notFoundComponent:e.notFoundComponent}),this.router.afterEach(n=>{this.currentPathSignal.set(n.path);}),d=this,this.log("[INIT] ClientManager created");}on(e,t,n,r){return typeof e=="string"&&e.startsWith("on")?(this.hooks[e]=t,this):this.eventsManager.on(e,t,n,r)}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.extensions)e.onBoot&&(this.log(`\u2192 Extension onBoot: ${e.name}`),await e.onBoot({debug:this.debug,config:{},cconfig: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.extensions)t.onReady&&(this.log(`\u2192 Extension onReady: ${t.name}`),await t.onReady({debug:this.debug,config:{},cconfig: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.extensions.length-1;e>=0;e--){let t=this.extensions[e];t.onDestroy&&(this.log(`\u2192 Extension onDestroy: ${t.name}`),await t.onDestroy({debug:this.debug,config:{},cconfig: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 r=this.config.rootLayout();if(r){mount(r,t),this.log("\u2192 Root layout mounted");let i=t.querySelector("#main-overlay");i?n=i:console.warn("[ClientManager] Page slot #main-overlay not found in root layout. Pages will render to the root container.");}}catch(r){console.error("[ClientManager] Error rendering root layout:",r),t.innerHTML="<p>Error loading root layout</p>";return}effect(()=>{let r=this.currentPathSignal(),i=this.routeComponents[r]||this.config.notFoundComponent||null;if(n.innerHTML="",i)try{let s=i();s&&mount(s,n);}catch(s){console.error("[ClientManager] Error rendering component:",r,s),n.innerHTML="<p>Error loading component</p>";}else n.innerHTML="<p>No component found for this route</p>";this.log(`\u2192 Route changed to: ${r}`);}),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 window.__i18n}t(e,t,n){return window.__i18n?window.__i18n.t(e,t)??n??e:(console.warn("[ClientManager] i18n not initialized. Using default value or key."),n??e)}getPhase(){return this.lifecycle}isReady(){return this.lifecycle==="ready"}log(e){this.debug&&console.log(`[ClientManager] ${e}`);}},l=()=>d,g=()=>l()?.getRouter(),x=()=>g()?.back(),b=()=>g()?.forward(),L=o=>g()?.push(o),R=o=>g()?.replace(o),h=()=>l()?.getI18n(),k=()=>h()?.getLanguage(),P=o=>h()?.setLanguage(o),T=(o,e,t)=>l()?.t(o,e,t),H=(o,e,t,n)=>h()?.tLang(o,e,t,n)??n??e;async function A(o){let e=document.querySelector('meta[name="app-i18n"]');if(e){let n=JSON.parse(e.getAttribute("content")||"{}");o.i18n=n;}let t=new a(o);return window.__i18n=await setupI18n(o.i18n||{defaultLanguage:"en",supportedLanguages:["en"]}),t.boot(),t.ready(),window.addEventListener("beforeunload",async()=>{await t.destroy();}),t}export{l as CM,a as ClientManager,x as back,b as forward,h as getI18n,k as getLang,g as getRouter,L as push,R as replace,P as setLang,A as start,T as t,H as tLang};//# sourceMappingURL=index.js.map
1
+ import {signal,effect}from'@minejs/signals';import {mount}from'@minejs/jsx';import {EventsManager,WindowManager,createRouter}from'@minejs/browser';import {setupI18n}from'@minejs/i18n';var d,s=class{constructor(e){this.lifecycle="booting";this.hooks={};this.extensions=[];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.extensions=e.extensions??[],this.routeComponents=e.routes,this.eventsManager=new EventsManager,this.windowManager=new WindowManager;let t=Object.entries(e.routes).map(([n,r])=>({path:n,component:r}));this.router=createRouter({routes:t,notFoundComponent:e.notFoundComponent,allowedQueryParams:e.allowedQueryParams}),this.router.afterEach(n=>{this.currentPathSignal.set(n.path);}),d=this,this.log("[INIT] ClientManager created");}on(e,t,n,r){return typeof e=="string"&&e.startsWith("on")?(this.hooks[e]=t,this):this.eventsManager.on(e,t,n,r)}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.extensions)e.onBoot&&(this.log(`\u2192 Extension onBoot: ${e.name}`),await e.onBoot({debug:this.debug,config:{},cconfig: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.extensions)t.onReady&&(this.log(`\u2192 Extension onReady: ${t.name}`),await t.onReady({debug:this.debug,config:{},cconfig: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.extensions.length-1;e>=0;e--){let t=this.extensions[e];t.onDestroy&&(this.log(`\u2192 Extension onDestroy: ${t.name}`),await t.onDestroy({debug:this.debug,config:{},cconfig: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 r=this.config.rootLayout();if(r){mount(r,t),this.log("\u2192 Root layout mounted");let i=t.querySelector("#main-overlay");i?n=i:console.warn("[ClientManager] Page slot #main-overlay not found in root layout. Pages will render to the root container.");}}catch(r){console.error("[ClientManager] Error rendering root layout:",r),t.innerHTML="<p>Error loading root layout</p>";return}effect(()=>{let r=this.currentPathSignal(),i=this.routeComponents[r]||this.config.notFoundComponent||null;if(n.innerHTML="",i)try{let a=i();a&&mount(a,n);}catch(a){console.error("[ClientManager] Error rendering component:",r,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: ${r}`);}),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 window.__i18n}t(e,t,n){return window.__i18n?window.__i18n.t(e,t)??n??e:(console.warn("[ClientManager] i18n not initialized. Using default value or key."),n??e)}getPhase(){return this.lifecycle}isReady(){return this.lifecycle==="ready"}log(e){this.debug&&console.log(`[ClientManager] ${e}`);}},l=()=>d,g=()=>l()?.getRouter(),x=()=>g()?.back(),b=()=>g()?.forward(),L=o=>g()?.push(o),R=o=>g()?.replace(o),h=()=>l()?.getI18n(),k=()=>h()?.getLanguage(),P=o=>h()?.setLanguage(o),T=(o,e,t)=>l()?.t(o,e,t),H=(o,e,t,n)=>h()?.tLang(o,e,t,n)??n??e;async function A(o){let e=document.querySelector('meta[name="app-i18n"]');if(e){let n=JSON.parse(e.getAttribute("content")||"{}");o.i18n=n;}let t=new s(o);return window.__i18n=await setupI18n(o.i18n||{defaultLanguage:"en",supportedLanguages:["en"]}),t.boot(),t.ready(),window.addEventListener("beforeunload",async()=>{await t.destroy();}),t}export{l as CM,s as ClientManager,x as back,b as forward,h as getI18n,k as getLang,g as getRouter,L as push,R as replace,P as setLang,A as start,T as t,H as tLang};//# sourceMappingURL=index.js.map
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/mod/client_manager.ts","../src/index.ts"],"names":["globalClientManagerInstance","ClientManager","config","signal","EventsManager","WindowManager","routesArray","path","component","createRouter","to","eventOrTarget","callbackOrEvent","handler","options","extension","err","selector","i","container","pageContainer","layoutJsx","mountJSX","pageSlot","effect","currentPath","Component","jsx","e","target","event","key","params","defaultValue","message","CM","getRouter","back","forward","push","replace","getI18n","getLang","setLang","lang","t","tLang","start","metaI18n","i18nData","manager","setupI18n"],"mappings":"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","file":"index.js","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\r\n// src/mpd/client_manager.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 { 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 extensions : types.ClientExtension[] = [];\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 extensions from config\r\n this.extensions = config.extensions ?? [];\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 extensions onBoot hooks\r\n for (const extension of this.extensions) {\r\n if (extension.onBoot) {\r\n this.log(`→ Extension onBoot: ${extension.name}`);\r\n await extension.onBoot({\r\n debug: this.debug,\r\n config: {},\r\n cconfig: 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 extensions onReady hooks\r\n for (const extension of this.extensions) {\r\n if (extension.onReady) {\r\n this.log(`→ Extension onReady: ${extension.name}`);\r\n await extension.onReady({\r\n debug: this.debug,\r\n config: {},\r\n cconfig: 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 extensions onDestroy hooks (in reverse order)\r\n for (let i = this.extensions.length - 1; i >= 0; i--) {\r\n const extension = this.extensions[i];\r\n if (extension.onDestroy) {\r\n this.log(`→ Extension onDestroy: ${extension.name}`);\r\n await extension.onDestroy({\r\n debug: this.debug,\r\n config: {},\r\n cconfig: 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 (window as any).__i18n;\r\n }\r\n\r\n /**\r\n * Get translation string\r\n */\r\n t(key: string, params?: any, defaultValue?: string) {\r\n if (!(window as any).__i18n) {\r\n console.warn('[ClientManager] i18n not initialized. Using default value or key.');\r\n return defaultValue ?? key;\r\n }\r\n return (window as any).__i18n.t(key, params) ?? 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 // Quick access\r\n export const CM = (): ClientManager | undefined => globalClientManagerInstance;\r\n\r\n // Router\r\n export const getRouter = () => CM()?.getRouter();\r\n export const back = () => getRouter()?.back();\r\n export const forward = () => getRouter()?.forward();\r\n export const push = (path: string) => getRouter()?.push(path);\r\n export const replace = (path: string) => getRouter()?.replace(path);\r\n\r\n // i18n\r\n export const getI18n = () => CM()?.getI18n();\r\n export const getLang = () => getI18n()?.getLanguage();\r\n export const setLang = (lang: string) => getI18n()?.setLanguage(lang);\r\n export const t = (key: string, params?: any, defaultValue?: string) => CM()?.t(key, params, defaultValue);\r\n export const tLang = (lang: string, key: string, params?: any, defaultValue?: string) => getI18n()?.tLang(lang, key, params, defaultValue) ?? (defaultValue ?? key);\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\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 { ClientManagerConfig } from './types';\r\n import { ClientManager } from './mod/client_manager';\r\n import { setupI18n } from '@minejs/i18n';\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ MAIN ════════════════════════════════════════╗\r\n\r\n export * from './types';\r\n export * from './mod/client_manager';\r\n\r\n // Start\r\n export async function start(config: 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: Setup I18N\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n (window as any).__i18n = 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"]}
1
+ {"version":3,"sources":["../src/mod/client_manager.ts","../src/index.ts"],"names":["globalClientManagerInstance","ClientManager","config","signal","EventsManager","WindowManager","routesArray","path","component","createRouter","to","eventOrTarget","callbackOrEvent","handler","options","extension","err","selector","i","container","pageContainer","layoutJsx","mountJSX","pageSlot","effect","currentPath","Component","jsx","e","target","event","key","params","defaultValue","message","CM","getRouter","back","forward","push","replace","getI18n","getLang","setLang","lang","t","tLang","start","metaI18n","i18nData","manager","setupI18n"],"mappings":"wLAoBI,IAAIA,EAESC,CAAAA,CAAN,KAAoB,CAenB,WAAA,CAAYC,CAAAA,CAAmC,CAR/C,KAAQ,SAAA,CAAyE,SAAA,CAEjF,KAAQ,KAAA,CAAiD,GACzD,IAAA,CAAQ,UAAA,CAAgD,EAAC,CAEzD,IAAA,CAAQ,eAAA,CAA6D,EAAC,CACtE,IAAA,CAAQ,iBAAA,CAAsBC,MAAAA,CAAe,MAAA,CAAO,QAAA,CAAS,UAAY,GAAG,CAAA,CAGxE,IAAA,CAAK,MAAA,CAASD,CAAAA,CACd,IAAA,CAAK,MAAQA,CAAAA,CAAO,KAAA,EAAS,MAE7B,IAAA,CAAK,GAAA,CAAI,+BAA+B,CAAA,CAGpCA,CAAAA,CAAO,SAAA,GACP,IAAA,CAAK,KAAA,CAAQ,CAAE,GAAGA,CAAAA,CAAO,SAAU,CAAA,CAAA,CAIvC,IAAA,CAAK,UAAA,CAAaA,CAAAA,CAAO,YAAc,EAAC,CAGxC,IAAA,CAAK,eAAA,CAAkBA,CAAAA,CAAO,MAAA,CAG9B,KAAK,aAAA,CAAgB,IAAIE,aAAAA,CACzB,IAAA,CAAK,aAAA,CAAgB,IAAIC,cAGzB,IAAMC,CAAAA,CAAc,MAAA,CAAO,OAAA,CAAQJ,CAAAA,CAAO,MAAM,EAAE,GAAA,CAAI,CAAC,CAACK,CAAAA,CAAMC,CAAS,CAAA,IAAO,CAC1E,IAAA,CAAAD,CAAAA,CACA,SAAA,CAAAC,CACJ,CAAA,CAAE,CAAA,CAEF,KAAK,MAAA,CAASC,YAAAA,CAAa,CACvB,MAAA,CAAQH,CAAAA,CACR,kBAAmBJ,CAAAA,CAAO,iBAAA,CAC1B,kBAAA,CAAoBA,CAAAA,CAAO,kBAC/B,CAAC,EAGD,IAAA,CAAK,MAAA,CAAO,SAAA,CAAWQ,CAAAA,EAAO,CAC1B,IAAA,CAAK,kBAAkB,GAAA,CAAIA,CAAAA,CAAG,IAAI,EACtC,CAAC,CAAA,CAIDV,EAA8B,IAAA,CAE9B,IAAA,CAAK,IAAI,8BAA8B,EAC3C,CAmBA,EAAA,CACIW,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACmB,CAEnB,OAAI,OAAOH,CAAAA,EAAkB,QAAA,EAAYA,CAAAA,CAAc,UAAA,CAAW,IAAI,GAClE,IAAA,CAAK,KAAA,CAAMA,CAA+C,CAAA,CAAIC,CAAAA,CACvD,IAAA,EAIJ,KAAK,aAAA,CAAc,EAAA,CACtBD,EACAC,CAAAA,CACAC,CAAAA,CACAC,CACJ,CACJ,CAUA,MAAM,IAAA,EAAsB,CACxB,GAAI,KAAK,SAAA,GAAc,SAAA,CAAW,CAC9B,OAAA,CAAQ,IAAA,CAAK,6CAA6C,EAC1D,MACJ,CAEA,IAAA,CAAK,GAAA,CAAI,oBAAe,CAAA,CAExB,GAAI,CAEA,IAAA,IAAWC,CAAAA,IAAa,IAAA,CAAK,UAAA,CACrBA,CAAAA,CAAU,SACV,IAAA,CAAK,GAAA,CAAI,CAAA,yBAAA,EAAuBA,CAAAA,CAAU,IAAI,CAAA,CAAE,EAChD,MAAMA,CAAAA,CAAU,MAAA,CAAO,CACnB,KAAA,CAAO,IAAA,CAAK,MACZ,MAAA,CAAQ,EAAC,CACT,OAAA,CAAS,IAAA,CAAK,MAClB,CAAC,CAAA,CAAA,CAKL,IAAA,CAAK,MAAM,MAAA,GACX,IAAA,CAAK,IAAI,4BAAuB,CAAA,CAChC,MAAM,IAAA,CAAK,KAAA,CAAM,MAAA,IAGrB,IAAA,CAAK,GAAA,CAAI,4BAAuB,EACpC,CAAA,MAASC,CAAAA,CAAK,CACV,MAAA,OAAA,CAAQ,KAAA,CAAM,8BAAA,CAAgCA,CAAG,CAAA,CAC3CA,CACV,CACJ,CAQA,MAAM,OAAuB,CACzB,GAAI,KAAK,SAAA,GAAc,SAAA,CAAW,CAC9B,OAAA,CAAQ,IAAA,CAAK,qDAAqD,EAClE,MACJ,CAEA,IAAA,CAAK,GAAA,CAAI,qBAAgB,CAAA,CAEzB,GAAI,CACA,IAAMC,CAAAA,CAAW,MAAA,CAGhB,QAAA,CAAS,aAAA,CAAcA,CAAQ,CAAA,CAAkB,EAAA,CAAK,OAGvD,IAAA,CAAK,KAAA,CAAMA,CAAQ,CAAA,CAEnB,IAAA,CAAK,GAAA,CAAI,uBAAkB,CAAA,CAG3B,IAAA,IAAWF,KAAa,IAAA,CAAK,UAAA,CACrBA,CAAAA,CAAU,OAAA,GACV,IAAA,CAAK,GAAA,CAAI,6BAAwBA,CAAAA,CAAU,IAAI,CAAA,CAAE,CAAA,CACjD,MAAMA,CAAAA,CAAU,QAAQ,CACpB,KAAA,CAAO,IAAA,CAAK,KAAA,CACZ,MAAA,CAAQ,GACR,OAAA,CAAS,IAAA,CAAK,MAClB,CAAC,CAAA,CAAA,CAKL,IAAA,CAAK,MAAM,OAAA,GACX,IAAA,CAAK,GAAA,CAAI,6BAAwB,CAAA,CACjC,MAAM,KAAK,KAAA,CAAM,OAAA,EAAQ,CAAA,CAG7B,IAAA,CAAK,SAAA,CAAY,OAAA,CACjB,KAAK,GAAA,CAAI,6BAAwB,EACjC,IAAA,CAAK,GAAA,CAAI,sBAAiB,EAC9B,CAAA,MAASC,CAAAA,CAAK,CACV,MAAA,OAAA,CAAQ,KAAA,CAAM,gCAAiCA,CAAG,CAAA,CAC5CA,CACV,CACJ,CAKA,MAAM,SAAyB,CAC3B,GAAI,IAAA,CAAK,SAAA,GAAc,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,CAAAA,CAAI,IAAA,CAAK,UAAA,CAAW,MAAA,CAAS,EAAGA,CAAAA,EAAK,CAAA,CAAGA,CAAAA,EAAAA,CAAK,CAClD,IAAMH,CAAAA,CAAY,KAAK,UAAA,CAAWG,CAAC,EAC/BH,CAAAA,CAAU,SAAA,GACV,KAAK,GAAA,CAAI,CAAA,4BAAA,EAA0BA,CAAAA,CAAU,IAAI,CAAA,CAAE,CAAA,CACnD,MAAMA,CAAAA,CAAU,SAAA,CAAU,CACtB,KAAA,CAAO,IAAA,CAAK,KAAA,CACZ,OAAQ,EAAC,CACT,OAAA,CAAS,IAAA,CAAK,MAClB,CAAC,GAET,CAGI,IAAA,CAAK,KAAA,CAAM,SAAA,GACX,IAAA,CAAK,GAAA,CAAI,+BAA0B,CAAA,CACnC,MAAM,IAAA,CAAK,KAAA,CAAM,SAAA,EAAU,CAAA,CAI/B,KAAK,aAAA,CAAc,OAAA,EAAQ,CAC3B,IAAA,CAAK,aAAA,CAAc,OAAA,GAEnB,IAAA,CAAK,SAAA,CAAY,WAAA,CACjB,IAAA,CAAK,GAAA,CAAI,+BAA0B,EACvC,CAAA,MAASC,CAAAA,CAAK,CACV,MAAA,OAAA,CAAQ,KAAA,CAAM,kCAAmCA,CAAG,CAAA,CAC9CA,CACV,CACJ,CAUA,QAAA,CAAST,EAAoB,CACzB,IAAA,CAAK,MAAA,CAAO,IAAA,CAAKA,CAAI,EACzB,CAOA,KAAA,CAAMU,CAAAA,CAAsC,CACxC,IAAME,CAAAA,CAAY,OAAOF,GAAa,QAAA,CAC/B,QAAA,CAAS,cAAcA,CAAQ,CAAA,CAChCA,EAEN,GAAI,CAACE,CAAAA,CAAW,CACZ,OAAA,CAAQ,IAAA,CAAK,0CAA2CF,CAAQ,CAAA,CAChE,MACJ,CAEA,IAAIG,CAAAA,CAAgBD,EAGpB,GAAI,IAAA,CAAK,MAAA,CAAO,UAAA,CACZ,GAAI,CACA,IAAME,CAAAA,CAAY,IAAA,CAAK,OAAO,UAAA,EAAW,CACzC,GAAIA,CAAAA,CAAW,CACXC,KAAAA,CAASD,CAAAA,CAAWF,CAAS,CAAA,CAC7B,KAAK,GAAA,CAAI,4BAAuB,CAAA,CAGhC,IAAMI,CAAAA,CAAWJ,CAAAA,CAAU,cAAc,eAAe,CAAA,CACpDI,CAAAA,CACAH,CAAAA,CAAgBG,CAAAA,CAEhB,OAAA,CAAQ,KAAK,4GAA4G,EAEjI,CACJ,CAAA,MAASP,CAAAA,CAAK,CACV,QAAQ,KAAA,CAAM,8CAAA,CAAgDA,CAAG,CAAA,CACjEG,CAAAA,CAAU,SAAA,CAAY,mCACtB,MACJ,CAIJK,MAAAA,CAAO,IAAM,CACT,IAAMC,EAAc,IAAA,CAAK,iBAAA,EAAkB,CACrCC,CAAAA,CAAY,IAAA,CAAK,eAAA,CAAgBD,CAAW,CAAA,EAC3C,IAAA,CAAK,OAAO,iBAAA,EACZ,IAAA,CAKP,GAFAL,CAAAA,CAAc,SAAA,CAAY,EAAA,CAEtBM,CAAAA,CACA,GAAI,CACA,IAAMC,CAAAA,CAAMD,CAAAA,EAAU,CAElBC,CAAAA,EACAL,KAAAA,CAASK,CAAAA,CAAKP,CAAa,EAEnC,CAAA,MAASJ,CAAAA,CAAK,CACV,OAAA,CAAQ,KAAA,CAAM,6CAA8CS,CAAAA,CAAaT,CAAG,EAC5EI,CAAAA,CAAc,SAAA,CAAY,iCAC9B,CAAA,KAEAA,CAAAA,CAAc,SAAA,CAAY,0CAAA,CAG9B,IAAA,CAAK,GAAA,CAAI,4BAAuBK,CAAW,CAAA,CAAE,EACjD,CAAC,CAAA,CAGD,IAAA,CAAK,OAAO,IAAA,CAAK,IAAA,CAAK,iBAAA,EAAmB,CAAA,CACzC,IAAA,CAAK,IAAI,+BAA0B,EACvC,CAKA,cAAA,EAAiB,CACb,OAAO,IAAA,CAAK,iBAChB,CAKA,iBAAA,CAAkBlB,CAAAA,CAAc,CAC5B,OAAQqB,CAAAA,EAAkB,CACtBA,CAAAA,CAAE,cAAA,EAAe,CACjB,IAAA,CAAK,SAASrB,CAAI,EACtB,CACJ,CAKA,SAAA,EAAY,CACR,OAAO,IAAA,CAAK,MAChB,CAUA,GAAA,CAAIsB,CAAAA,CAAqBC,CAAAA,CAAejB,EAA8B,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,aAAA,CAAc,aAC9B,CAKA,kBAAkC,CAC9B,OAAO,KAAK,aAChB,CAUA,OAAA,EAAU,CACN,OAAQ,MAAA,CAAe,MAC3B,CAKA,CAAA,CAAEkB,CAAAA,CAAaC,CAAAA,CAAcC,CAAAA,CAAuB,CAChD,OAAM,MAAA,CAAe,MAAA,CAIb,MAAA,CAAe,MAAA,CAAO,CAAA,CAAEF,CAAAA,CAAKC,CAAM,CAAA,EAAKC,CAAAA,EAAgBF,GAH5D,OAAA,CAAQ,IAAA,CAAK,mEAAmE,CAAA,CACzEE,CAAAA,EAAgBF,CAAAA,CAG/B,CAUA,QAAA,EAAW,CACP,OAAO,IAAA,CAAK,SAChB,CAKA,OAAA,EAAmB,CACf,OAAO,KAAK,SAAA,GAAc,OAC9B,CAKQ,GAAA,CAAIG,CAAAA,CAAuB,CAC3B,KAAK,KAAA,EACL,OAAA,CAAQ,IAAI,CAAA,gBAAA,EAAmBA,CAAO,EAAE,EAEhD,CAIR,CAAA,CASaC,CAAAA,CAAa,IAAiCnC,CAAAA,CAG9CoC,EAAa,IAAqBD,CAAAA,EAAG,EAAG,SAAA,EAAU,CAClDE,CAAAA,CAAa,IAAqBD,CAAAA,EAAU,EAAG,IAAA,EAAK,CACpDE,CAAAA,CAAa,IAAqBF,GAAU,EAAG,OAAA,EAAQ,CACvDG,CAAAA,CAAchC,CAAAA,EAAoB6B,CAAAA,IAAa,IAAA,CAAK7B,CAAI,CAAA,CACxDiC,CAAAA,CAAcjC,CAAAA,EAAoB6B,CAAAA,IAAa,OAAA,CAAQ7B,CAAI,CAAA,CAG3DkC,CAAAA,CAAa,IAAqBN,CAAAA,IAAM,OAAA,EAAQ,CAChDO,CAAAA,CAAa,IAAqBD,CAAAA,EAAQ,EAAG,aAAY,CACzDE,CAAAA,CAAcC,GAAoBH,CAAAA,EAAQ,EAAG,YAAYG,CAAI,CAAA,CAC7DC,CAAAA,CAAa,CAACd,CAAAA,CAAaC,CAAAA,CAAcC,IAA0BE,CAAAA,EAAG,EAAG,CAAA,CAAEJ,CAAAA,CAAKC,CAAAA,CAAQC,CAAY,EACpGa,CAAAA,CAAa,CAACF,CAAAA,CAAcb,CAAAA,CAAaC,CAAAA,CAAcC,CAAAA,GAA0BQ,GAAQ,EAAG,KAAA,CAAMG,EAAMb,CAAAA,CAAKC,CAAAA,CAAQC,CAAY,CAAA,EAAMA,CAAAA,EAAgBF,EC3cpK,eAAsBgB,CAAAA,CAAM7C,CAAAA,CAAqD,CAE7E,IAAM8C,CAAAA,CAAW,SAAS,aAAA,CAAc,uBAAuB,CAAA,CAC/D,GAAIA,CAAAA,CAAU,CACV,IAAMC,CAAAA,CAAW,IAAA,CAAK,MAAMD,CAAAA,CAAS,YAAA,CAAa,SAAS,CAAA,EAAK,IAAI,CAAA,CACpE9C,CAAAA,CAAO,IAAA,CAAO+C,EAClB,CAGA,IAAMC,CAAAA,CAAU,IAAIjD,CAAAA,CAAcC,CAAM,CAAA,CAIxC,OAAC,MAAA,CAAe,MAAA,CAAS,MAAMiD,SAAAA,CAAUjD,CAAAA,CAAO,IAAA,EAAQ,CACpD,eAAA,CAAiB,IAAA,CACjB,kBAAA,CAAoB,CAAC,IAAI,CAC7B,CAAC,CAAA,CAGDgD,CAAAA,CAAQ,IAAA,EAAK,CAGbA,CAAAA,CAAQ,KAAA,GAGR,MAAA,CAAO,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/mpd/client_manager.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 { 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 extensions : types.ClientExtension[] = [];\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 extensions from config\r\n this.extensions = config.extensions ?? [];\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 allowedQueryParams: config.allowedQueryParams\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 extensions onBoot hooks\r\n for (const extension of this.extensions) {\r\n if (extension.onBoot) {\r\n this.log(`→ Extension onBoot: ${extension.name}`);\r\n await extension.onBoot({\r\n debug: this.debug,\r\n config: {},\r\n cconfig: 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 extensions onReady hooks\r\n for (const extension of this.extensions) {\r\n if (extension.onReady) {\r\n this.log(`→ Extension onReady: ${extension.name}`);\r\n await extension.onReady({\r\n debug: this.debug,\r\n config: {},\r\n cconfig: 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 extensions onDestroy hooks (in reverse order)\r\n for (let i = this.extensions.length - 1; i >= 0; i--) {\r\n const extension = this.extensions[i];\r\n if (extension.onDestroy) {\r\n this.log(`→ Extension onDestroy: ${extension.name}`);\r\n await extension.onDestroy({\r\n debug: this.debug,\r\n config: {},\r\n cconfig: 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 (window as any).__i18n;\r\n }\r\n\r\n /**\r\n * Get translation string\r\n */\r\n t(key: string, params?: any, defaultValue?: string) {\r\n if (!(window as any).__i18n) {\r\n console.warn('[ClientManager] i18n not initialized. Using default value or key.');\r\n return defaultValue ?? key;\r\n }\r\n return (window as any).__i18n.t(key, params) ?? 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 // Quick access\r\n export const CM = (): ClientManager | undefined => globalClientManagerInstance;\r\n\r\n // Router\r\n export const getRouter = () => CM()?.getRouter();\r\n export const back = () => getRouter()?.back();\r\n export const forward = () => getRouter()?.forward();\r\n export const push = (path: string) => getRouter()?.push(path);\r\n export const replace = (path: string) => getRouter()?.replace(path);\r\n\r\n // i18n\r\n export const getI18n = () => CM()?.getI18n();\r\n export const getLang = () => getI18n()?.getLanguage();\r\n export const setLang = (lang: string) => getI18n()?.setLanguage(lang);\r\n export const t = (key: string, params?: any, defaultValue?: string) => CM()?.t(key, params, defaultValue);\r\n export const tLang = (lang: string, key: string, params?: any, defaultValue?: string) => getI18n()?.tLang(lang, key, params, defaultValue) ?? (defaultValue ?? key);\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\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 { ClientManagerConfig } from './types';\r\n import { ClientManager } from './mod/client_manager';\r\n import { setupI18n } from '@minejs/i18n';\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ MAIN ════════════════════════════════════════╗\r\n\r\n export * from './types';\r\n export * from './mod/client_manager';\r\n\r\n // Start\r\n export async function start(config: 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: Setup I18N\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n (window as any).__i18n = 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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cruxjs/client",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "description": "Client application manager with routing, lifecycle hooks, and plugin-based extensibility.",
5
5
  "keywords": ["cruxjs", "client"],
6
6
  "license": "MIT",
@@ -40,7 +40,7 @@
40
40
  "bun": "^1.3.3"
41
41
  },
42
42
  "dependencies": {
43
- "@cruxjs/base": "^0.1.9",
43
+ "@cruxjs/base": "^0.2.0",
44
44
  "@cruxkit/core": "^0.0.2",
45
45
  "@minejs/browser": "^0.0.5",
46
46
  "@minejs/i18n": "^0.1.7",