frontend-hamroun 1.1.50 → 1.1.52

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/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let e=!1;const t=[];function n(n){if(e)t.push(n);else{e=!0;try{for(n();t.length>0;){const e=t.shift();null==e||e()}}finally{e=!1}}}let r=0;const o=new Map,s=new Map,i=new Map,a=new Map,c=new Map;let l=null,p=null,u=null;const d="undefined"==typeof window,f=new Map;function h(t){if(!r)throw new Error("useState must be called within a render");if(d){f.has(r)||f.set(r,new Map);const e=f.get(r),n=s.get(r)||0;e.has(n)||e.set(n,t);const o=e.get(n),i=e=>{};return s.set(r,n+1),[o,i]}o.has(r)||o.set(r,[]);const i=o.get(r),a=s.get(r);a>=i.length&&i.push(t);const c=i[a];return s.set(r,a+1),[c,t=>{const o="function"==typeof t?t(i[a]):t;i[a]!==o&&(i[a]=o,e?n((()=>y(r))):y(r))}]}function w(e,t){if(!r)throw new Error("useEffect must be called within a render");const n=s.get(r);i.has(r)||i.set(r,[]);const o=i.get(r),a=o[n];a&&t&&a.deps&&!t.some(((e,t)=>e!==a.deps[t]))||((null==a?void 0:a.cleanup)&&a.cleanup(),queueMicrotask((()=>{const r=e()||void 0;o[n]={cleanup:r,deps:t}}))),s.set(r,n+1)}async function y(e){try{const t=i.get(e);t&&(t.forEach((e=>{e.cleanup&&e.cleanup()})),i.set(e,[])),l&&p&&u&&await l(u,p)}catch(t){console.error("Error during rerender:",t)}}function m(e,t){console.log("JSX Transform:",{type:e,props:t});const n={...t};return arguments.length>2&&(n.children=Array.prototype.slice.call(arguments,2)),{type:e,props:n}}async function g(e){var t;if(console.log("Creating element from:",e),null==e)return document.createTextNode("");if("boolean"==typeof e)return document.createTextNode("");if("number"==typeof e||"string"==typeof e)return document.createTextNode(String(e));if(Array.isArray(e)){const t=document.createDocumentFragment();for(const n of e){const e=await g(n);t.appendChild(e)}return t}if("type"in e&&void 0!==e.props){const{type:r,props:o}=e;if("function"==typeof r)try{const e=await r(o||{}),t=await g(e);return t instanceof Element&&t.setAttribute("data-component-id",r.name||r.toString()),t}catch(n){return console.error("Error rendering component:",n),document.createTextNode("")}const s=document.createElement(r);for(const[e,n]of Object.entries(o||{}))if("children"!==e)if(e.startsWith("on")&&"function"==typeof n){const r=e.toLowerCase().slice(2),o=null==(t=s.__events)?void 0:t[r];o&&s.removeEventListener(r,o),s.addEventListener(r,n),s.__events||(s.__events={}),s.__events[r]=n}else"style"===e&&"object"==typeof n?Object.assign(s.style,n):"className"===e?s.setAttribute("class",String(n)):"key"!==e&&"ref"!==e&&s.setAttribute(e,String(n));const i=null==o?void 0:o.children;if(null!=i){const e=Array.isArray(i)?i.flat():[i];for(const t of e){const e=await g(t);s.appendChild(e)}}return s}return document.createTextNode(String(e))}let b=!1;async function v(e,t){console.log("Rendering to:",t.id),n((async()=>{r++,s.set(r,0);try{!function(e,t,n){l=e,p=n,u=t}(v,e,t);const n=await g(e);b||(t.innerHTML=""),t.appendChild(n)}finally{d&&f.delete(r),r=0}}))}async function x(e){var t,n;if(null==e||"boolean"==typeof e)return"";if("number"==typeof e||"string"==typeof e)return $(String(e));if("function"==typeof e){return x(await e({}))}if(e.type){if("function"==typeof e.type){return x(await e.type(e.props||{}))}let r=`<${e.type}`;for(const[t,o]of Object.entries(e.props||{}))"children"!==t&&"key"!==t&&"ref"!==t&&("className"===t?r+=` class="${$(String(o))}"`:"style"===t&&"object"==typeof o&&null!==o?r+=` style="${n=o,Object.entries(n).map((([e,t])=>`${e}: ${t}`)).join("; ")}"`:t.startsWith("on")||(r+=` ${t}="${$(String(o))}"`));if(r+=">",null==(t=e.props)?void 0:t.children){const t=Array.isArray(e.props.children)?e.props.children:[e.props.children];for(const e of t)r+=await x(e)}return r+=`</${e.type}>`,r}return""}function $(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}let S={pathname:"undefined"!=typeof window?window.location.pathname:"/",search:"undefined"!=typeof window?window.location.search:"",hash:"undefined"!=typeof window?window.location.hash:"",params:{}};const E=new Set;function j(e,t={}){"undefined"!=typeof window&&function(e,t={}){const n=new URL(e,window.location.origin),r={pathname:n.pathname,search:n.search,hash:n.hash,params:{}};t.replace?window.history.replaceState(r,"",n.toString()):window.history.pushState(r,"",n.toString()),S=r,E.forEach((e=>e(r))),t.scroll&&window.scrollTo(0,0)}(e,t)}exports.Fragment=({children:e})=>e,exports.Link=function({href:e,children:t,replace:n=!1,className:r,style:o,...s}){return{type:"a",props:{href:e,onClick:t=>{t.preventDefault(),j(e,{replace:n})},className:r,style:o,...s,children:t}}},exports.batchUpdates=n,exports.createContext=function(e){return{Provider:({value:e,children:t})=>t,Consumer:({children:t})=>t(e),_id:Symbol(),useSelector:t=>t(e)}},exports.createElement=g,exports.hydrate=async function(e,t){b=!0;try{await v(e,t)}finally{b=!1}},exports.jsx=m,exports.jsxs=m,exports.render=v,exports.renderToString=async function(e,t={}){try{return function(e,t){const{title:n,description:r="",scripts:o=[],styles:s=[],initialState:i={},meta:a={},bodyAttrs:c={},htmlAttrs:l={lang:"en"}}=t,p=Object.entries(l).map((([e,t])=>`${e}="${t}"`)).join(" "),u=Object.entries(c).map((([e,t])=>`${e}="${t}"`)).join(" ");return`<!DOCTYPE html>\n<html ${p}>\n <head>\n <meta charset="UTF-8">\n <meta name="viewport" content="width=device-width, initial-scale=1.0">\n ${r?`<meta name="description" content="${r}">\n`:""}${Object.entries(a).map((([e,t])=>` <meta name="${e}" content="${t}">`)).join("\n")}\n <title>${n}</title>\n${s.map((e=>` <link rel="stylesheet" href="${e}">`)).join("\n")}\n <script>\n window.__INITIAL_STATE__ = ${JSON.stringify(i)};\n <\/script>\n </head>\n <body ${u}>\n <div id="root">${e}</div>\n${o.map((e=>` <script src="${e}" defer><\/script>`)).join("\n")}\n </body>\n</html>`}(await x(e),{title:"Frontend Hamroun App",...t})}catch(n){return console.error("Error during server rendering:",n),""}},exports.useContext=function(e){return e},exports.useEffect=w,exports.useErrorBoundary=function(){const[e,t]=h(null);return[e,()=>t(null)]},exports.useMemo=function(e,t){if(!r)throw new Error("useMemo must be called within a render");const n=s.get(r);a.has(r)||a.set(r,[]);const o=a.get(r),i=o[n];if(!i||t&&t.some(((e,t)=>!Object.is(e,i.deps[t])))){const i=e();return o[n]={value:i,deps:t},s.set(r,n+1),i}return s.set(r,n+1),i.value},exports.useRef=function(e){if(!r)throw new Error("useRef must be called within a render");const t=s.get(r);c.has(r)||c.set(r,[]);const n=c.get(r);if(t>=n.length){const o={current:e};return n.push(o),s.set(r,t+1),o}const o=n[t];return s.set(r,t+1),o},exports.useRouter=function(){const[e,t]=h(S);return w((()=>{const e=e=>{t(e)},n=()=>{S={pathname:window.location.pathname,search:window.location.search,hash:window.location.hash,params:{}},t(S)};return E.add(e),window.addEventListener("popstate",n),()=>{E.delete(e),window.removeEventListener("popstate",n)}}),[]),{...e,push:(e,t)=>j(e,t),replace:(e,t)=>j(e,{...t,replace:!0}),back:()=>window.history.back(),forward:()=>window.history.forward()}},exports.useState=h;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let e=!1;const t=[];function n(n){if(e)t.push(n);else{e=!0;try{for(n();t.length>0;){const e=t.shift();null==e||e()}}finally{e=!1}}}let r=0;const o=new Map,s=new Map,i=new Map,a=new Map,c=new Map;let l=null,p=null,u=null;const d="undefined"==typeof window,f=new Map;function h(t){if(!r)throw new Error("useState must be called within a render");if(d){f.has(r)||f.set(r,new Map);const e=f.get(r),n=s.get(r)||0;e.has(n)||e.set(n,t);const o=e.get(n),i=e=>{};return s.set(r,n+1),[o,i]}o.has(r)||o.set(r,[]);const i=o.get(r),a=s.get(r);a>=i.length&&i.push(t);const c=i[a];return s.set(r,a+1),[c,t=>{const o="function"==typeof t?t(i[a]):t;i[a]!==o&&(i[a]=o,e?n((()=>w(r))):w(r))}]}function y(e,t){if(!r)throw new Error("useEffect must be called within a render");const n=s.get(r);i.has(r)||i.set(r,[]);const o=i.get(r),a=o[n];a&&t&&a.deps&&!t.some(((e,t)=>e!==a.deps[t]))||((null==a?void 0:a.cleanup)&&a.cleanup(),queueMicrotask((()=>{const r=e()||void 0;o[n]={cleanup:r,deps:t}}))),s.set(r,n+1)}async function w(e){try{const t=i.get(e);t&&(t.forEach((e=>{e.cleanup&&e.cleanup()})),i.set(e,[])),l&&p&&u&&await l(u,p)}catch(t){console.error("Error during rerender:",t)}}function m(e,t){console.log("JSX Transform:",{type:e,props:t});const n={...t};return arguments.length>2&&(n.children=Array.prototype.slice.call(arguments,2)),{type:e,props:n}}async function g(e){var t;if(console.log("Creating element from:",e),null==e)return document.createTextNode("");if("boolean"==typeof e)return document.createTextNode("");if("number"==typeof e||"string"==typeof e)return document.createTextNode(String(e));if(Array.isArray(e)){const t=document.createDocumentFragment();for(const n of e){const e=await g(n);t.appendChild(e)}return t}if("type"in e&&void 0!==e.props){const{type:r,props:o}=e;if("function"==typeof r)try{const e=await r(o||{}),t=await g(e);return t instanceof Element&&t.setAttribute("data-component-id",r.name||r.toString()),t}catch(n){return console.error("Error rendering component:",n),document.createTextNode("")}const s=document.createElement(r);for(const[e,n]of Object.entries(o||{}))if("children"!==e)if(e.startsWith("on")&&"function"==typeof n){const r=e.toLowerCase().slice(2),o=null==(t=s.__events)?void 0:t[r];o&&s.removeEventListener(r,o),s.addEventListener(r,n),s.__events||(s.__events={}),s.__events[r]=n}else"style"===e&&"object"==typeof n?Object.assign(s.style,n):"className"===e?s.setAttribute("class",String(n)):"key"!==e&&"ref"!==e&&s.setAttribute(e,String(n));const i=null==o?void 0:o.children;if(null!=i){const e=Array.isArray(i)?i.flat():[i];for(const t of e){const e=await g(t);s.appendChild(e)}}return s}return document.createTextNode(String(e))}let b=!1;async function v(e,t){console.log("Rendering to:",t.id),n((async()=>{r++,s.set(r,0);try{!function(e,t,n){l=e,p=n,u=t}(v,e,t);const n=await g(e);b||(t.innerHTML=""),t.appendChild(n)}finally{d&&f.delete(r),r=0}}))}async function $(e){var t;if(null==e||"boolean"==typeof e)return"";if("number"==typeof e||"string"==typeof e)return S(String(e));if(Array.isArray(e)){return(await Promise.all(e.map((e=>$(e))))).join("")}if("function"==typeof e){e.name;try{return $(await e({}))}finally{}}if(e.type){if("function"==typeof e.type){e.type.name,e.props;try{return $(await e.type(e.props||{}))}finally{}}let n=`<${e.type}`;e.props&&(n+=function(e){let t="";for(const[n,r]of Object.entries(e))"children"!==n&&"key"!==n&&"ref"!==n&&("className"!==n?"style"!==n||"object"!=typeof r||null===r?n.startsWith("on")||("boolean"!=typeof r?null!=r&&(t+=` ${n}="${S(String(r))}"`):r&&(t+=` ${n}`)):t+=` style="${x(r)}"`:r&&(t+=` class="${S(String(r))}"`));return t}(e.props));if(new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]).has(e.type))return n+"/>";if(n+=">",null==(t=e.props)?void 0:t.children){const t=Array.isArray(e.props.children)?e.props.children:[e.props.children];for(const e of t)n+=await $(e)}return n+`</${e.type}>`}return""}function S(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}function x(e){return Object.entries(e).map((([e,t])=>{return`${n=e,n.replace(/[A-Z]/g,(e=>"-"+e.toLowerCase()))}: ${t}`;var n})).join("; ")}let E={pathname:"undefined"!=typeof window?window.location.pathname:"/",search:"undefined"!=typeof window?window.location.search:"",hash:"undefined"!=typeof window?window.location.hash:"",params:{}};const j=new Set;function A(e,t={}){"undefined"!=typeof window&&function(e,t={}){const n=new URL(e,window.location.origin),r={pathname:n.pathname,search:n.search,hash:n.hash,params:{}};t.replace?window.history.replaceState(r,"",n.toString()):window.history.pushState(r,"",n.toString()),E=r,j.forEach((e=>e(r))),t.scroll&&window.scrollTo(0,0)}(e,t)}exports.Fragment=({children:e})=>e,exports.Link=function({href:e,children:t,replace:n=!1,className:r,style:o,...s}){return{type:"a",props:{href:e,onClick:t=>{t.preventDefault(),A(e,{replace:n})},className:r,style:o,...s,children:t}}},exports.batchUpdates=n,exports.createContext=function(e){return{Provider:({value:e,children:t})=>t,Consumer:({children:t})=>t(e),_id:Symbol(),useSelector:t=>t(e)}},exports.createElement=g,exports.hydrate=async function(e,t){b=!0;try{await v(e,t)}finally{b=!1}},exports.jsx=m,exports.jsxs=m,exports.render=v,exports.renderToString=async function(e,t={}){var n;try{const r=await $(e),o=null==(n=t.scripts)?void 0:n.map((e=>"string"==typeof e?{src:e,defer:!0}:{...e,defer:e.defer??!0}));return function(e,t){const{title:n,description:r="",scripts:o=[],styles:s=[],initialState:i={},meta:a={},bodyAttrs:c={},htmlAttrs:l={lang:"en"}}=t,p=Object.entries(l).map((([e,t])=>`${e}="${t}"`)).join(" "),u=Object.entries(c).map((([e,t])=>`${e}="${t}"`)).join(" "),d=Object.entries(a).map((([e,t])=>` <meta name="${e}" content="${t}">`)).join("\n"),f=o.map((e=>{if("string"==typeof e)return` <script src="${e}" defer><\/script>`;const{src:t,defer:n=!0,async:r=!1,type:o}=e;return` <script src="${t}"${n?" defer":""}${r?" async":""}${o?` type="${o}"`:""}><\/script>`})).join("\n");return`<!DOCTYPE html>\n<html ${p}>\n <head>\n <meta charset="UTF-8">\n <meta name="viewport" content="width=device-width, initial-scale=1.0">\n ${r?`<meta name="description" content="${r}">\n`:""}${d}\n <title>${n}</title>\n${s.map((e=>` <link rel="stylesheet" href="${e}">`)).join("\n")}\n <script>\n window.__INITIAL_STATE__ = ${JSON.stringify(i)};\n <\/script>\n </head>\n <body ${u}>\n <div id="root">${e}</div>\n${f}\n </body>\n</html>`}(r,{title:"Frontend Hamroun App",...t,scripts:o})}catch(r){if(console.error("Server rendering error:",r),"development"===process.env.NODE_ENV){return`\n <!DOCTYPE html>\n <html>\n <head><title>Rendering Error</title></head>\n <body>\n <h1>Server Rendering Error</h1>\n <pre>${S(r instanceof Error?r.stack||r.message:String(r))}</pre>\n </body>\n </html>\n `}return""}},exports.useContext=function(e){return e},exports.useEffect=y,exports.useErrorBoundary=function(){const[e,t]=h(null);return[e,()=>t(null)]},exports.useMemo=function(e,t){if(!r)throw new Error("useMemo must be called within a render");const n=s.get(r);a.has(r)||a.set(r,[]);const o=a.get(r),i=o[n];if(!i||t&&t.some(((e,t)=>!Object.is(e,i.deps[t])))){const i=e();return o[n]={value:i,deps:t},s.set(r,n+1),i}return s.set(r,n+1),i.value},exports.useRef=function(e){if(!r)throw new Error("useRef must be called within a render");const t=s.get(r);c.has(r)||c.set(r,[]);const n=c.get(r);if(t>=n.length){const o={current:e};return n.push(o),s.set(r,t+1),o}const o=n[t];return s.set(r,t+1),o},exports.useRouter=function(){const[e,t]=h(E);return y((()=>{const e=e=>{t(e)},n=()=>{E={pathname:window.location.pathname,search:window.location.search,hash:window.location.hash,params:{}},t(E)};return j.add(e),window.addEventListener("popstate",n),()=>{j.delete(e),window.removeEventListener("popstate",n)}}),[]),{...e,push:(e,t)=>A(e,t),replace:(e,t)=>A(e,{...t,replace:!0}),back:()=>window.history.back(),forward:()=>window.history.forward()}},exports.useState=h;
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/batch.ts","../src/hooks.ts","../src/jsx-runtime.ts","../src/renderer.ts","../src/server-renderer.ts","../src/router.ts","../src/link.tsx","../src/context.ts","../src/templates/default.ts"],"sourcesContent":["export let isBatching = false;\r\nconst queue: Function[] = [];\r\n\r\nexport function batchUpdates(fn: Function) {\r\n if (isBatching) {\r\n queue.push(fn);\r\n return;\r\n }\r\n\r\n isBatching = true;\r\n try {\r\n fn();\r\n while (queue.length > 0) {\r\n const nextFn = queue.shift();\r\n nextFn?.();\r\n }\r\n } finally {\r\n isBatching = false;\r\n }\r\n}\r\n\r\nexport function getIsBatching() {\r\n return isBatching;\r\n}\r\n","import { createElement } from './jsx-runtime';\r\nimport { batchUpdates, isBatching } from './batch';\r\nimport { diff } from './vdom';\r\n\r\nlet currentRender: number = 0;\r\nconst states = new Map<number, any[]>();\r\nconst stateIndices = new Map<number, number>();\r\nconst effects = new Map<number, Effect[]>();\r\nconst memos = new Map<number, { value: any; deps: any[] }[]>();\r\nconst refs = new Map<number, any[]>();\r\n\r\ninterface Effect {\r\n cleanup?: () => void;\r\n deps?: any[];\r\n}\r\n\r\n// Add at the top with other declarations\r\nlet globalRenderCallback: ((element: any, container: HTMLElement) => void) | null = null;\r\nlet globalContainer: HTMLElement | null = null;\r\nlet currentElement: any = null;\r\n\r\nconst isServer = typeof window === 'undefined';\r\nconst serverStates = new Map<number, any>();\r\n\r\nexport function setRenderCallback(\r\n callback: (element: any, container: HTMLElement) => void,\r\n element: any,\r\n container: HTMLElement\r\n) {\r\n globalRenderCallback = callback;\r\n globalContainer = container;\r\n currentElement = element;\r\n}\r\n\r\nexport function prepareRender() {\r\n currentRender++;\r\n stateIndices.set(currentRender, 0);\r\n return currentRender;\r\n}\r\n\r\nexport function finishRender() {\r\n if (isServer) {\r\n serverStates.delete(currentRender);\r\n }\r\n currentRender = 0;\r\n}\r\n\r\nexport function useState<T>(initial: T): [T, (value: T | ((prev: T) => T)) => void] {\r\n if (!currentRender) {\r\n throw new Error('useState must be called within a render');\r\n }\r\n\r\n if (isServer) {\r\n // Server-side state handling\r\n if (!serverStates.has(currentRender)) {\r\n serverStates.set(currentRender, new Map());\r\n }\r\n const componentState = serverStates.get(currentRender)!;\r\n const index = stateIndices.get(currentRender) || 0;\r\n \r\n if (!componentState.has(index)) {\r\n componentState.set(index, initial);\r\n }\r\n\r\n const state = componentState.get(index);\r\n const setState = (newValue: T | ((prev: T) => T)) => {\r\n // No-op for server-side\r\n };\r\n\r\n stateIndices.set(currentRender, index + 1);\r\n return [state, setState];\r\n }\r\n\r\n if (!states.has(currentRender)) {\r\n states.set(currentRender, []);\r\n }\r\n\r\n const componentStates = states.get(currentRender)!;\r\n const index = stateIndices.get(currentRender)!;\r\n \r\n if (index >= componentStates.length) {\r\n componentStates.push(initial);\r\n }\r\n\r\n const state = componentStates[index];\r\n const setState = (newValue: T | ((prev: T) => T)) => {\r\n const nextValue = typeof newValue === 'function' \r\n ? (newValue as Function)(componentStates[index])\r\n : newValue;\r\n\r\n if (componentStates[index] === nextValue) return; // Skip if value hasn't changed\r\n \r\n componentStates[index] = nextValue;\r\n \r\n if (isBatching) {\r\n batchUpdates(() => rerender(currentRender));\r\n } else {\r\n rerender(currentRender);\r\n }\r\n };\r\n\r\n stateIndices.set(currentRender, index + 1);\r\n return [state, setState];\r\n}\r\n\r\nexport function useEffect(callback: () => (() => void) | void, deps?: any[]) {\r\n if (!currentRender) throw new Error('useEffect must be called within a render');\r\n \r\n const effectIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!effects.has(currentRender)) {\r\n effects.set(currentRender, []);\r\n }\r\n\r\n const componentEffects = effects.get(currentRender)!;\r\n const prevEffect = componentEffects[effectIndex];\r\n \r\n // Run effect if deps changed\r\n if (!prevEffect || !deps || !prevEffect.deps || \r\n deps.some((dep, i) => dep !== prevEffect.deps![i])) {\r\n \r\n // Cleanup previous effect\r\n if (prevEffect?.cleanup) {\r\n prevEffect.cleanup();\r\n }\r\n\r\n // Schedule new effect\r\n queueMicrotask(() => {\r\n const cleanup = callback() || undefined;\r\n componentEffects[effectIndex] = { cleanup: cleanup, deps };\r\n });\r\n }\r\n \r\n stateIndices.set(currentRender, effectIndex + 1);\r\n}\r\n\r\nexport function useMemo<T>(factory: () => T, deps: any[]): T {\r\n if (!currentRender) throw new Error('useMemo must be called within a render');\r\n \r\n const memoIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!memos.has(currentRender)) {\r\n memos.set(currentRender, []);\r\n }\r\n\r\n const componentMemos = memos.get(currentRender)!;\r\n const prevMemo = componentMemos[memoIndex];\r\n \r\n if (!prevMemo || (deps && deps.some((dep, i) => !Object.is(dep, prevMemo.deps[i])))) {\r\n const value = factory();\r\n componentMemos[memoIndex] = { value, deps };\r\n stateIndices.set(currentRender, memoIndex + 1);\r\n return value;\r\n }\r\n\r\n stateIndices.set(currentRender, memoIndex + 1);\r\n return prevMemo.value;\r\n}\r\n\r\nexport function useRef<T>(initial: T) {\r\n if (!currentRender) throw new Error('useRef must be called within a render');\r\n \r\n const refIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!refs.has(currentRender)) {\r\n refs.set(currentRender, []);\r\n }\r\n\r\n const componentRefs = refs.get(currentRender)!;\r\n if (refIndex >= componentRefs.length) {\r\n // Initialize with an object that has a current property\r\n const ref = { current: initial };\r\n componentRefs.push(ref);\r\n stateIndices.set(currentRender, refIndex + 1);\r\n return ref;\r\n }\r\n\r\n const ref = componentRefs[refIndex];\r\n stateIndices.set(currentRender, refIndex + 1);\r\n return ref;\r\n}\r\n\r\n// Add a map to track component DOM nodes\r\nconst componentNodes = new Map<Function, Node>();\r\n\r\nasync function rerender(rendererId: number) {\r\n try {\r\n // Clean up effects\r\n const componentEffects = effects.get(rendererId);\r\n if (componentEffects) {\r\n componentEffects.forEach(effect => {\r\n if (effect.cleanup) effect.cleanup();\r\n });\r\n effects.set(rendererId, []);\r\n }\r\n\r\n if (globalRenderCallback && globalContainer && currentElement) {\r\n await globalRenderCallback(currentElement, globalContainer);\r\n }\r\n } catch (error) {\r\n console.error('Error during rerender:', error);\r\n }\r\n}\r\n\r\n// Add new hook for error boundaries\r\nexport function useErrorBoundary(): [Error | null, () => void] {\r\n const [error, setError] = useState<Error | null>(null);\r\n return [error, () => setError(null)];\r\n}\r\n\r\n// Remove withHooks export\r\n","import type { Component } from './component';\r\n\r\ninterface VNode {\r\n type: string | Function;\r\n props: Record<string, any>;\r\n}\r\n\r\nfunction jsx(type: string | Function, props: any): VNode {\r\n console.log('JSX Transform:', { type, props });\r\n const processedProps = { ...props };\r\n \r\n // Handle children properly\r\n if (arguments.length > 2) {\r\n processedProps.children = Array.prototype.slice.call(arguments, 2);\r\n }\r\n \r\n return { type, props: processedProps };\r\n}\r\n\r\nconst Fragment = ({ children }: { children: any }) => children;\r\n\r\nasync function createElement(vnode: VNode | any): Promise<Node> {\r\n console.log('Creating element from:', vnode);\r\n\r\n // Handle primitives and null\r\n if (vnode == null) {\r\n return document.createTextNode('');\r\n }\r\n \r\n if (typeof vnode === 'boolean') {\r\n return document.createTextNode('');\r\n }\r\n\r\n if (typeof vnode === 'number' || typeof vnode === 'string') {\r\n return document.createTextNode(String(vnode));\r\n }\r\n\r\n // Handle arrays\r\n if (Array.isArray(vnode)) {\r\n const fragment = document.createDocumentFragment();\r\n for (const child of vnode) {\r\n const node = await createElement(child);\r\n fragment.appendChild(node);\r\n }\r\n return fragment;\r\n }\r\n\r\n // Handle VNode\r\n if ('type' in vnode && vnode.props !== undefined) {\r\n const { type, props } = vnode;\r\n \r\n // Handle function components\r\n if (typeof type === 'function') {\r\n try {\r\n const result = await type(props || {});\r\n const node = await createElement(result);\r\n if (node instanceof Element) {\r\n node.setAttribute('data-component-id', type.name || type.toString());\r\n }\r\n return node;\r\n } catch (error) {\r\n console.error('Error rendering component:', error);\r\n return document.createTextNode('');\r\n }\r\n }\r\n\r\n // Create DOM element\r\n const element = document.createElement(type as string);\r\n \r\n // Handle props\r\n for (const [key, value] of Object.entries(props || {})) {\r\n if (key === 'children') continue;\r\n if (key.startsWith('on') && typeof value === 'function') {\r\n const eventName = key.toLowerCase().slice(2);\r\n // Remove existing event listener if any\r\n const existingHandler = (element as any).__events?.[eventName];\r\n if (existingHandler) {\r\n element.removeEventListener(eventName, existingHandler);\r\n }\r\n \r\n // Add new event listener\r\n element.addEventListener(eventName, value as EventListener);\r\n if (!(element as any).__events) {\r\n (element as any).__events = {};\r\n }\r\n (element as any).__events[eventName] = value;\r\n } else if (key === 'style' && typeof value === 'object') {\r\n Object.assign(element.style, value);\r\n } else if (key === 'className') {\r\n element.setAttribute('class', String(value));\r\n } else if (key !== 'key' && key !== 'ref') {\r\n element.setAttribute(key, String(value));\r\n }\r\n }\r\n\r\n // Handle children\r\n const children = props?.children;\r\n if (children != null) {\r\n const childArray = Array.isArray(children) ? children.flat() : [children];\r\n for (const child of childArray) {\r\n const childNode = await createElement(child);\r\n element.appendChild(childNode);\r\n }\r\n }\r\n\r\n return element;\r\n }\r\n\r\n // Handle other objects by converting to string\r\n return document.createTextNode(String(vnode));\r\n}\r\n\r\n// Export named functions and aliases without duplicates\r\nexport {\r\n jsx,\r\n jsx as jsxs,\r\n jsx as jsxDEV,\r\n Fragment,\r\n createElement\r\n};\r\n\r\n// Named exports object\r\nconst jsxRuntime = {\r\n jsx,\r\n jsxs: jsx,\r\n jsxDEV: jsx,\r\n Fragment,\r\n createElement\r\n};\r\n\r\nexport default jsxRuntime;\r\n","import { createElement } from './jsx-runtime';\r\nimport { prepareRender, finishRender, setRenderCallback } from './hooks';\r\nimport { batchUpdates } from './batch';\r\n\r\nlet isHydrating = false;\r\n\r\nexport async function hydrate(element: any, container: HTMLElement) {\r\n isHydrating = true;\r\n try {\r\n await render(element, container);\r\n } finally {\r\n isHydrating = false;\r\n }\r\n}\r\n\r\nexport async function render(element: any, container: HTMLElement) {\r\n console.log('Rendering to:', container.id);\r\n \r\n batchUpdates(async () => {\r\n const rendererId = prepareRender();\r\n try {\r\n setRenderCallback(render, element, container);\r\n const domNode = await createElement(element);\r\n \r\n if (!isHydrating) {\r\n container.innerHTML = '';\r\n }\r\n container.appendChild(domNode);\r\n \r\n } finally {\r\n finishRender();\r\n }\r\n });\r\n}\r\n","import { VNode } from './types';\r\nimport { defaultTemplate, TemplateOptions } from './templates/default';\r\n\r\nexport async function renderToString(\r\n element: JSX.Element, \r\n options: Partial<TemplateOptions> = {}\r\n): Promise<string> {\r\n try {\r\n const content = await renderNodeToString(element);\r\n return defaultTemplate(content, {\r\n title: 'Frontend Hamroun App',\r\n ...options\r\n });\r\n } catch (error) {\r\n console.error('Error during server rendering:', error);\r\n return '';\r\n }\r\n}\r\n\r\nasync function renderNodeToString(node: VNode | any): Promise<string> {\r\n if (node == null || typeof node === 'boolean') {\r\n return '';\r\n }\r\n\r\n if (typeof node === 'number' || typeof node === 'string') {\r\n return escapeHtml(String(node));\r\n }\r\n\r\n if (typeof node === 'function') {\r\n const result = await node({ });\r\n return renderNodeToString(result);\r\n }\r\n\r\n if (node.type) {\r\n if (typeof node.type === 'function') {\r\n const result = await node.type(node.props || {});\r\n return renderNodeToString(result);\r\n }\r\n\r\n let html = `<${node.type}`;\r\n \r\n // Handle props\r\n for (const [key, value] of Object.entries(node.props || {})) {\r\n if (key === 'children' || key === 'key' || key === 'ref') continue;\r\n if (key === 'className') {\r\n html += ` class=\"${escapeHtml(String(value))}\"`;\r\n } else if (key === 'style' && typeof value === 'object' && value !== null) {\r\n html += ` style=\"${styleToString(value)}\"`;\r\n } else if (!key.startsWith('on')) {\r\n html += ` ${key}=\"${escapeHtml(String(value))}\"`;\r\n }\r\n }\r\n\r\n html += '>';\r\n\r\n // Handle children\r\n if (node.props?.children) {\r\n const children = Array.isArray(node.props.children) \r\n ? node.props.children \r\n : [node.props.children];\r\n \r\n for (const child of children) {\r\n html += await renderNodeToString(child);\r\n }\r\n }\r\n\r\n html += `</${node.type}>`;\r\n return html;\r\n }\r\n\r\n return '';\r\n}\r\n\r\nfunction escapeHtml(str: string): string {\r\n return str\r\n .replace(/&/g, '&amp;')\r\n .replace(/</g, '&lt;')\r\n .replace(/>/g, '&gt;')\r\n .replace(/\"/g, '&quot;')\r\n .replace(/'/g, '&#039;');\r\n}\r\n\r\nfunction styleToString(style: Record<string, any>): string {\r\n return Object.entries(style)\r\n .map(([key, value]) => `${key}: ${value}`)\r\n .join('; ');\r\n}\r\n","import { useState, useEffect } from './hooks';\r\n\r\ninterface RouterState {\r\n pathname: string;\r\n search: string;\r\n hash: string;\r\n params: Record<string, string>;\r\n}\r\n\r\ninterface RouterOptions {\r\n replace?: boolean;\r\n scroll?: boolean;\r\n}\r\n\r\nlet currentState: RouterState = {\r\n pathname: typeof window !== 'undefined' ? window.location.pathname : '/',\r\n search: typeof window !== 'undefined' ? window.location.search : '',\r\n hash: typeof window !== 'undefined' ? window.location.hash : '',\r\n params: {}\r\n};\r\n\r\nconst listeners = new Set<(state: RouterState) => void>();\r\n\r\n// Parse route pattern and extract params\r\nfunction matchRoute(pattern: string, pathname: string): Record<string, string> | null {\r\n const paramNames: string[] = [];\r\n const regexPattern = pattern.replace(/:([^/]+)/g, (_, name) => {\r\n paramNames.push(name);\r\n return '([^/]+)';\r\n });\r\n\r\n const match = pathname.match(new RegExp(`^${regexPattern}$`));\r\n if (!match) return null;\r\n\r\n const params: Record<string, string> = {};\r\n paramNames.forEach((name, i) => {\r\n params[name] = match[i + 1];\r\n });\r\n\r\n return params;\r\n}\r\n\r\nfunction updateState(newPath: string, options: RouterOptions = {}) {\r\n const url = new URL(newPath, window.location.origin);\r\n const newState: RouterState = {\r\n pathname: url.pathname,\r\n search: url.search,\r\n hash: url.hash,\r\n params: {}\r\n };\r\n\r\n if (options.replace) {\r\n window.history.replaceState(newState, '', url.toString());\r\n } else {\r\n window.history.pushState(newState, '', url.toString());\r\n }\r\n\r\n currentState = newState;\r\n listeners.forEach(listener => listener(newState));\r\n\r\n if (options.scroll) {\r\n window.scrollTo(0, 0);\r\n }\r\n}\r\n\r\nexport function navigate(to: string, options: RouterOptions = {}) {\r\n if (typeof window === 'undefined') return;\r\n updateState(to, options);\r\n}\r\n\r\nexport function useRouter() {\r\n const [state, setState] = useState<RouterState>(currentState);\r\n\r\n useEffect(() => {\r\n const handleRouteChange = (newState: RouterState) => {\r\n setState(newState);\r\n };\r\n\r\n const handlePopState = () => {\r\n currentState = {\r\n pathname: window.location.pathname,\r\n search: window.location.search,\r\n hash: window.location.hash,\r\n params: {}\r\n };\r\n setState(currentState);\r\n };\r\n\r\n listeners.add(handleRouteChange);\r\n window.addEventListener('popstate', handlePopState);\r\n\r\n return () => {\r\n listeners.delete(handleRouteChange);\r\n window.removeEventListener('popstate', handlePopState);\r\n };\r\n }, []);\r\n\r\n return {\r\n ...state,\r\n push: (to: string, options?: RouterOptions) => navigate(to, options),\r\n replace: (to: string, options?: RouterOptions) => navigate(to, { ...options, replace: true }),\r\n back: () => window.history.back(),\r\n forward: () => window.history.forward()\r\n };\r\n}\r\n\r\nexport function useRoute(pattern: string) {\r\n const { pathname } = useRouter();\r\n const [params, setParams] = useState<Record<string, string>>({});\r\n const [isMatch, setIsMatch] = useState(false);\r\n\r\n useEffect(() => {\r\n const matchedParams = matchRoute(pattern, pathname);\r\n setIsMatch(!!matchedParams);\r\n setParams(matchedParams || {});\r\n }, [pattern, pathname]);\r\n\r\n return { isMatch, params };\r\n}\r\n\r\nexport function useParams<T extends Record<string, string>>() {\r\n const router = useRouter();\r\n return router.params as T;\r\n}\r\n\r\nexport function useSearchParams() {\r\n const { search } = useRouter();\r\n return new URLSearchParams(search);\r\n}\r\n","import { navigate } from './router';\r\n\r\ninterface LinkProps {\r\n href: string;\r\n children?: any;\r\n replace?: boolean;\r\n className?: string;\r\n style?: Record<string, string>;\r\n [key: string]: any;\r\n}\r\n\r\nexport function Link({ \r\n href, \r\n children, \r\n replace = false, \r\n className,\r\n style,\r\n ...rest \r\n}: LinkProps) {\r\n const handleClick = (e: MouseEvent) => {\r\n e.preventDefault();\r\n navigate(href, { replace });\r\n };\r\n\r\n return {\r\n type: 'a',\r\n props: {\r\n href,\r\n onClick: handleClick,\r\n className,\r\n style,\r\n ...rest,\r\n children\r\n }\r\n };\r\n}\r\n","\r\n\r\nconst contexts = new Map<symbol, any>();\r\nlet currentRender: Function | null = null;\r\n\r\nexport interface Context<T> {\r\n Provider: (props: { value: T; children?: any }) => any;\r\n Consumer: (props: { children: (value: T) => any }) => any;\r\n _id: symbol;\r\n useSelector: <S>(selector: (state: T) => S) => S;\r\n}\r\n\r\nexport function createContext<T>(defaultValue: T): Context<T> {\r\n const context = {\r\n Provider: ({ value, children }: { value: T, children?: any }) => {\r\n return children;\r\n },\r\n Consumer: ({ children }: { children: (value: T) => any }) => {\r\n return children(defaultValue);\r\n },\r\n _id: Symbol(),\r\n useSelector: <S>(selector: (state: T) => S) => {\r\n return selector(defaultValue);\r\n }\r\n };\r\n\r\n return context;\r\n}\r\n\r\nexport function useContext<T>(context: any): T {\r\n return context;\r\n}\r\n","export interface TemplateOptions {\r\n title: string;\r\n description?: string;\r\n scripts?: string[];\r\n styles?: string[];\r\n initialState?: any;\r\n meta?: Record<string, string>;\r\n bodyAttrs?: Record<string, string>;\r\n htmlAttrs?: Record<string, string>;\r\n}\r\n\r\nexport function defaultTemplate(content: string, options: TemplateOptions): string {\r\n const {\r\n title,\r\n description = '',\r\n scripts = [],\r\n styles = [],\r\n initialState = {},\r\n meta = {},\r\n bodyAttrs = {},\r\n htmlAttrs = { lang: 'en' }\r\n } = options;\r\n\r\n const htmlAttributes = Object.entries(htmlAttrs)\r\n .map(([key, value]) => `${key}=\"${value}\"`)\r\n .join(' ');\r\n\r\n const bodyAttributes = Object.entries(bodyAttrs)\r\n .map(([key, value]) => `${key}=\"${value}\"`)\r\n .join(' ');\r\n\r\n const metaTags = Object.entries(meta)\r\n .map(([name, content]) => ` <meta name=\"${name}\" content=\"${content}\">`)\r\n .join('\\n');\r\n\r\n return `<!DOCTYPE html>\r\n<html ${htmlAttributes}>\r\n <head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n ${description ? `<meta name=\"description\" content=\"${description}\">\\n` : ''}${metaTags}\r\n <title>${title}</title>\r\n${styles.map(href => ` <link rel=\"stylesheet\" href=\"${href}\">`).join('\\n')}\r\n <script>\r\n window.__INITIAL_STATE__ = ${JSON.stringify(initialState)};\r\n </script>\r\n </head>\r\n <body ${bodyAttributes}>\r\n <div id=\"root\">${content}</div>\r\n${scripts.map(src => ` <script src=\"${src}\" defer></script>`).join('\\n')}\r\n </body>\r\n</html>`;\r\n}\r\n"],"names":["isBatching","queue","batchUpdates","fn","push","length","nextFn","shift","currentRender","states","Map","stateIndices","effects","memos","refs","globalRenderCallback","globalContainer","currentElement","isServer","window","serverStates","useState","initial","Error","has","set","componentState","get","index","state","setState","newValue","componentStates","nextValue","rerender","useEffect","callback","deps","effectIndex","componentEffects","prevEffect","some","dep","i","cleanup","queueMicrotask","async","rendererId","forEach","effect","error","console","jsx","type","props","log","processedProps","arguments","children","Array","prototype","slice","call","createElement","vnode","document","createTextNode","String","isArray","fragment","createDocumentFragment","child","node","appendChild","result","Element","setAttribute","name","toString","element","key","value","Object","entries","startsWith","eventName","toLowerCase","existingHandler","_a","__events","removeEventListener","addEventListener","assign","style","childArray","flat","childNode","isHydrating","render","container","id","setRenderCallback","domNode","innerHTML","delete","renderNodeToString","escapeHtml","html","map","join","str","replace","currentState","pathname","location","search","hash","params","listeners","Set","navigate","to","options","newPath","url","URL","origin","newState","history","replaceState","pushState","listener","scroll","scrollTo","updateState","href","className","rest","onClick","e","preventDefault","defaultValue","Provider","Consumer","_id","Symbol","useSelector","selector","content","title","description","scripts","styles","initialState","meta","bodyAttrs","htmlAttrs","lang","htmlAttributes","bodyAttributes","JSON","stringify","src","defaultTemplate","context","setError","factory","memoIndex","componentMemos","prevMemo","is","refIndex","componentRefs","ref","current","handleRouteChange","handlePopState","add","back","forward"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/batch.ts","../src/hooks.ts","../src/jsx-runtime.ts","../src/renderer.ts","../src/server-renderer.ts","../src/router.ts","../src/link.tsx","../src/context.ts","../src/templates/default.ts"],"sourcesContent":["export let isBatching = false;\r\nconst queue: Function[] = [];\r\n\r\nexport function batchUpdates(fn: Function) {\r\n if (isBatching) {\r\n queue.push(fn);\r\n return;\r\n }\r\n\r\n isBatching = true;\r\n try {\r\n fn();\r\n while (queue.length > 0) {\r\n const nextFn = queue.shift();\r\n nextFn?.();\r\n }\r\n } finally {\r\n isBatching = false;\r\n }\r\n}\r\n\r\nexport function getIsBatching() {\r\n return isBatching;\r\n}\r\n","import { createElement } from './jsx-runtime';\r\nimport { batchUpdates, isBatching } from './batch';\r\nimport { diff } from './vdom';\r\n\r\nlet currentRender: number = 0;\r\nconst states = new Map<number, any[]>();\r\nconst stateIndices = new Map<number, number>();\r\nconst effects = new Map<number, Effect[]>();\r\nconst memos = new Map<number, { value: any; deps: any[] }[]>();\r\nconst refs = new Map<number, any[]>();\r\n\r\ninterface Effect {\r\n cleanup?: () => void;\r\n deps?: any[];\r\n}\r\n\r\n// Add at the top with other declarations\r\nlet globalRenderCallback: ((element: any, container: HTMLElement) => void) | null = null;\r\nlet globalContainer: HTMLElement | null = null;\r\nlet currentElement: any = null;\r\n\r\nconst isServer = typeof window === 'undefined';\r\nconst serverStates = new Map<number, any>();\r\n\r\nexport function setRenderCallback(\r\n callback: (element: any, container: HTMLElement) => void,\r\n element: any,\r\n container: HTMLElement\r\n) {\r\n globalRenderCallback = callback;\r\n globalContainer = container;\r\n currentElement = element;\r\n}\r\n\r\nexport function prepareRender() {\r\n currentRender++;\r\n stateIndices.set(currentRender, 0);\r\n return currentRender;\r\n}\r\n\r\nexport function finishRender() {\r\n if (isServer) {\r\n serverStates.delete(currentRender);\r\n }\r\n currentRender = 0;\r\n}\r\n\r\nexport function useState<T>(initial: T): [T, (value: T | ((prev: T) => T)) => void] {\r\n if (!currentRender) {\r\n throw new Error('useState must be called within a render');\r\n }\r\n\r\n if (isServer) {\r\n // Server-side state handling\r\n if (!serverStates.has(currentRender)) {\r\n serverStates.set(currentRender, new Map());\r\n }\r\n const componentState = serverStates.get(currentRender)!;\r\n const index = stateIndices.get(currentRender) || 0;\r\n \r\n if (!componentState.has(index)) {\r\n componentState.set(index, initial);\r\n }\r\n\r\n const state = componentState.get(index);\r\n const setState = (newValue: T | ((prev: T) => T)) => {\r\n // No-op for server-side\r\n };\r\n\r\n stateIndices.set(currentRender, index + 1);\r\n return [state, setState];\r\n }\r\n\r\n if (!states.has(currentRender)) {\r\n states.set(currentRender, []);\r\n }\r\n\r\n const componentStates = states.get(currentRender)!;\r\n const index = stateIndices.get(currentRender)!;\r\n \r\n if (index >= componentStates.length) {\r\n componentStates.push(initial);\r\n }\r\n\r\n const state = componentStates[index];\r\n const setState = (newValue: T | ((prev: T) => T)) => {\r\n const nextValue = typeof newValue === 'function' \r\n ? (newValue as Function)(componentStates[index])\r\n : newValue;\r\n\r\n if (componentStates[index] === nextValue) return; // Skip if value hasn't changed\r\n \r\n componentStates[index] = nextValue;\r\n \r\n if (isBatching) {\r\n batchUpdates(() => rerender(currentRender));\r\n } else {\r\n rerender(currentRender);\r\n }\r\n };\r\n\r\n stateIndices.set(currentRender, index + 1);\r\n return [state, setState];\r\n}\r\n\r\nexport function useEffect(callback: () => (() => void) | void, deps?: any[]) {\r\n if (!currentRender) throw new Error('useEffect must be called within a render');\r\n \r\n const effectIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!effects.has(currentRender)) {\r\n effects.set(currentRender, []);\r\n }\r\n\r\n const componentEffects = effects.get(currentRender)!;\r\n const prevEffect = componentEffects[effectIndex];\r\n \r\n // Run effect if deps changed\r\n if (!prevEffect || !deps || !prevEffect.deps || \r\n deps.some((dep, i) => dep !== prevEffect.deps![i])) {\r\n \r\n // Cleanup previous effect\r\n if (prevEffect?.cleanup) {\r\n prevEffect.cleanup();\r\n }\r\n\r\n // Schedule new effect\r\n queueMicrotask(() => {\r\n const cleanup = callback() || undefined;\r\n componentEffects[effectIndex] = { cleanup: cleanup, deps };\r\n });\r\n }\r\n \r\n stateIndices.set(currentRender, effectIndex + 1);\r\n}\r\n\r\nexport function useMemo<T>(factory: () => T, deps: any[]): T {\r\n if (!currentRender) throw new Error('useMemo must be called within a render');\r\n \r\n const memoIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!memos.has(currentRender)) {\r\n memos.set(currentRender, []);\r\n }\r\n\r\n const componentMemos = memos.get(currentRender)!;\r\n const prevMemo = componentMemos[memoIndex];\r\n \r\n if (!prevMemo || (deps && deps.some((dep, i) => !Object.is(dep, prevMemo.deps[i])))) {\r\n const value = factory();\r\n componentMemos[memoIndex] = { value, deps };\r\n stateIndices.set(currentRender, memoIndex + 1);\r\n return value;\r\n }\r\n\r\n stateIndices.set(currentRender, memoIndex + 1);\r\n return prevMemo.value;\r\n}\r\n\r\nexport function useRef<T>(initial: T) {\r\n if (!currentRender) throw new Error('useRef must be called within a render');\r\n \r\n const refIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!refs.has(currentRender)) {\r\n refs.set(currentRender, []);\r\n }\r\n\r\n const componentRefs = refs.get(currentRender)!;\r\n if (refIndex >= componentRefs.length) {\r\n // Initialize with an object that has a current property\r\n const ref = { current: initial };\r\n componentRefs.push(ref);\r\n stateIndices.set(currentRender, refIndex + 1);\r\n return ref;\r\n }\r\n\r\n const ref = componentRefs[refIndex];\r\n stateIndices.set(currentRender, refIndex + 1);\r\n return ref;\r\n}\r\n\r\n// Add a map to track component DOM nodes\r\nconst componentNodes = new Map<Function, Node>();\r\n\r\nasync function rerender(rendererId: number) {\r\n try {\r\n // Clean up effects\r\n const componentEffects = effects.get(rendererId);\r\n if (componentEffects) {\r\n componentEffects.forEach(effect => {\r\n if (effect.cleanup) effect.cleanup();\r\n });\r\n effects.set(rendererId, []);\r\n }\r\n\r\n if (globalRenderCallback && globalContainer && currentElement) {\r\n await globalRenderCallback(currentElement, globalContainer);\r\n }\r\n } catch (error) {\r\n console.error('Error during rerender:', error);\r\n }\r\n}\r\n\r\n// Add new hook for error boundaries\r\nexport function useErrorBoundary(): [Error | null, () => void] {\r\n const [error, setError] = useState<Error | null>(null);\r\n return [error, () => setError(null)];\r\n}\r\n\r\n// Remove withHooks export\r\n","import type { Component } from './component';\r\n\r\ninterface VNode {\r\n type: string | Function;\r\n props: Record<string, any>;\r\n}\r\n\r\nfunction jsx(type: string | Function, props: any): VNode {\r\n console.log('JSX Transform:', { type, props });\r\n const processedProps = { ...props };\r\n \r\n // Handle children properly\r\n if (arguments.length > 2) {\r\n processedProps.children = Array.prototype.slice.call(arguments, 2);\r\n }\r\n \r\n return { type, props: processedProps };\r\n}\r\n\r\nconst Fragment = ({ children }: { children: any }) => children;\r\n\r\nasync function createElement(vnode: VNode | any): Promise<Node> {\r\n console.log('Creating element from:', vnode);\r\n\r\n // Handle primitives and null\r\n if (vnode == null) {\r\n return document.createTextNode('');\r\n }\r\n \r\n if (typeof vnode === 'boolean') {\r\n return document.createTextNode('');\r\n }\r\n\r\n if (typeof vnode === 'number' || typeof vnode === 'string') {\r\n return document.createTextNode(String(vnode));\r\n }\r\n\r\n // Handle arrays\r\n if (Array.isArray(vnode)) {\r\n const fragment = document.createDocumentFragment();\r\n for (const child of vnode) {\r\n const node = await createElement(child);\r\n fragment.appendChild(node);\r\n }\r\n return fragment;\r\n }\r\n\r\n // Handle VNode\r\n if ('type' in vnode && vnode.props !== undefined) {\r\n const { type, props } = vnode;\r\n \r\n // Handle function components\r\n if (typeof type === 'function') {\r\n try {\r\n const result = await type(props || {});\r\n const node = await createElement(result);\r\n if (node instanceof Element) {\r\n node.setAttribute('data-component-id', type.name || type.toString());\r\n }\r\n return node;\r\n } catch (error) {\r\n console.error('Error rendering component:', error);\r\n return document.createTextNode('');\r\n }\r\n }\r\n\r\n // Create DOM element\r\n const element = document.createElement(type as string);\r\n \r\n // Handle props\r\n for (const [key, value] of Object.entries(props || {})) {\r\n if (key === 'children') continue;\r\n if (key.startsWith('on') && typeof value === 'function') {\r\n const eventName = key.toLowerCase().slice(2);\r\n // Remove existing event listener if any\r\n const existingHandler = (element as any).__events?.[eventName];\r\n if (existingHandler) {\r\n element.removeEventListener(eventName, existingHandler);\r\n }\r\n \r\n // Add new event listener\r\n element.addEventListener(eventName, value as EventListener);\r\n if (!(element as any).__events) {\r\n (element as any).__events = {};\r\n }\r\n (element as any).__events[eventName] = value;\r\n } else if (key === 'style' && typeof value === 'object') {\r\n Object.assign(element.style, value);\r\n } else if (key === 'className') {\r\n element.setAttribute('class', String(value));\r\n } else if (key !== 'key' && key !== 'ref') {\r\n element.setAttribute(key, String(value));\r\n }\r\n }\r\n\r\n // Handle children\r\n const children = props?.children;\r\n if (children != null) {\r\n const childArray = Array.isArray(children) ? children.flat() : [children];\r\n for (const child of childArray) {\r\n const childNode = await createElement(child);\r\n element.appendChild(childNode);\r\n }\r\n }\r\n\r\n return element;\r\n }\r\n\r\n // Handle other objects by converting to string\r\n return document.createTextNode(String(vnode));\r\n}\r\n\r\n// Export named functions and aliases without duplicates\r\nexport {\r\n jsx,\r\n jsx as jsxs,\r\n jsx as jsxDEV,\r\n Fragment,\r\n createElement\r\n};\r\n\r\n// Named exports object\r\nconst jsxRuntime = {\r\n jsx,\r\n jsxs: jsx,\r\n jsxDEV: jsx,\r\n Fragment,\r\n createElement\r\n};\r\n\r\nexport default jsxRuntime;\r\n","import { createElement } from './jsx-runtime';\r\nimport { prepareRender, finishRender, setRenderCallback } from './hooks';\r\nimport { batchUpdates } from './batch';\r\n\r\nlet isHydrating = false;\r\n\r\nexport async function hydrate(element: any, container: HTMLElement) {\r\n isHydrating = true;\r\n try {\r\n await render(element, container);\r\n } finally {\r\n isHydrating = false;\r\n }\r\n}\r\n\r\nexport async function render(element: any, container: HTMLElement) {\r\n console.log('Rendering to:', container.id);\r\n \r\n batchUpdates(async () => {\r\n const rendererId = prepareRender();\r\n try {\r\n setRenderCallback(render, element, container);\r\n const domNode = await createElement(element);\r\n \r\n if (!isHydrating) {\r\n container.innerHTML = '';\r\n }\r\n container.appendChild(domNode);\r\n \r\n } finally {\r\n finishRender();\r\n }\r\n });\r\n}\r\n","import { VNode } from './types';\r\nimport { defaultTemplate, TemplateOptions, ScriptConfig } from './templates/default';\r\n\r\n// Track component instances during SSR\r\nconst componentStack: any[] = [];\r\nlet currentComponent: any = null;\r\n\r\nexport async function renderToString(\r\n element: JSX.Element,\r\n options: Partial<TemplateOptions> = {}\r\n): Promise<string> {\r\n componentStack.length = 0;\r\n currentComponent = null;\r\n\r\n try {\r\n // Render the app to string\r\n const content = await renderNodeToString(element);\r\n\r\n const processedScripts = options.scripts?.map(script => \r\n typeof script === 'string' \r\n ? { src: script, defer: true } as ScriptConfig\r\n : { ...script, defer: script.defer ?? true }\r\n );\r\n\r\n // Generate the full HTML document\r\n return defaultTemplate(content, {\r\n title: 'Frontend Hamroun App',\r\n ...options,\r\n scripts: processedScripts\r\n });\r\n } catch (error) {\r\n console.error('Server rendering error:', error);\r\n // Return error page in development\r\n if (process.env.NODE_ENV === 'development') {\r\n const errorMessage = error instanceof Error \r\n ? error.stack || error.message \r\n : String(error);\r\n \r\n return `\r\n <!DOCTYPE html>\r\n <html>\r\n <head><title>Rendering Error</title></head>\r\n <body>\r\n <h1>Server Rendering Error</h1>\r\n <pre>${escapeHtml(errorMessage)}</pre>\r\n </body>\r\n </html>\r\n `;\r\n }\r\n return '';\r\n } finally {\r\n // Cleanup\r\n componentStack.length = 0;\r\n currentComponent = null;\r\n }\r\n}\r\n\r\nasync function renderNodeToString(node: VNode | any): Promise<string> {\r\n // Handle null and boolean\r\n if (node == null || typeof node === 'boolean') return '';\r\n\r\n // Handle primitives\r\n if (typeof node === 'number' || typeof node === 'string') {\r\n return escapeHtml(String(node));\r\n }\r\n\r\n // Handle arrays\r\n if (Array.isArray(node)) {\r\n const results = await Promise.all(\r\n node.map(child => renderNodeToString(child))\r\n );\r\n return results.join('');\r\n }\r\n\r\n // Handle functional components\r\n if (typeof node === 'function') {\r\n const prevComponent = currentComponent;\r\n currentComponent = { type: node.name || 'Anonymous' };\r\n componentStack.push(currentComponent);\r\n\r\n try {\r\n const result = await node({});\r\n return renderNodeToString(result);\r\n } finally {\r\n componentStack.pop();\r\n currentComponent = prevComponent;\r\n }\r\n }\r\n\r\n // Handle VNodes\r\n if (node.type) {\r\n if (typeof node.type === 'function') {\r\n const prevComponent = currentComponent;\r\n currentComponent = {\r\n type: node.type.name || 'Anonymous',\r\n props: node.props || {}\r\n };\r\n componentStack.push(currentComponent);\r\n\r\n try {\r\n const result = await node.type(node.props || {});\r\n return renderNodeToString(result);\r\n } finally {\r\n componentStack.pop();\r\n currentComponent = prevComponent;\r\n }\r\n }\r\n\r\n // Handle HTML elements\r\n let html = `<${node.type}`;\r\n \r\n // Add props\r\n if (node.props) {\r\n html += renderProps(node.props);\r\n }\r\n\r\n // Self-closing tags\r\n const voidElements = new Set([\r\n 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',\r\n 'link', 'meta', 'param', 'source', 'track', 'wbr'\r\n ]);\r\n\r\n if (voidElements.has(node.type)) {\r\n return html + '/>';\r\n }\r\n\r\n html += '>';\r\n\r\n // Render children\r\n if (node.props?.children) {\r\n const children = Array.isArray(node.props.children)\r\n ? node.props.children\r\n : [node.props.children];\r\n\r\n for (const child of children) {\r\n html += await renderNodeToString(child);\r\n }\r\n }\r\n\r\n return html + `</${node.type}>`;\r\n }\r\n\r\n // Handle other cases\r\n return '';\r\n}\r\n\r\nfunction renderProps(props: Record<string, any>): string {\r\n let html = '';\r\n\r\n for (const [key, value] of Object.entries(props)) {\r\n // Skip special props\r\n if (key === 'children' || key === 'key' || key === 'ref') continue;\r\n\r\n // Handle className\r\n if (key === 'className') {\r\n if (value) html += ` class=\"${escapeHtml(String(value))}\"`;\r\n continue;\r\n }\r\n\r\n // Handle style objects\r\n if (key === 'style' && typeof value === 'object' && value !== null) {\r\n html += ` style=\"${styleToString(value)}\"`;\r\n continue;\r\n }\r\n\r\n // Skip event handlers\r\n if (key.startsWith('on')) continue;\r\n\r\n // Handle boolean attributes\r\n if (typeof value === 'boolean') {\r\n if (value) html += ` ${key}`;\r\n continue;\r\n }\r\n\r\n // Handle other attributes\r\n if (value != null) {\r\n html += ` ${key}=\"${escapeHtml(String(value))}\"`;\r\n }\r\n }\r\n\r\n return html;\r\n}\r\n\r\nfunction escapeHtml(str: string): string {\r\n return str\r\n .replace(/&/g, '&amp;')\r\n .replace(/</g, '&lt;')\r\n .replace(/>/g, '&gt;')\r\n .replace(/\"/g, '&quot;')\r\n .replace(/'/g, '&#039;');\r\n}\r\n\r\nfunction styleToString(style: Record<string, any>): string {\r\n return Object.entries(style)\r\n .map(([key, value]) => `${hyphenate(key)}: ${value}`)\r\n .join('; ');\r\n}\r\n\r\n// Convert camelCase to kebab-case\r\nfunction hyphenate(str: string): string {\r\n return str.replace(/[A-Z]/g, m => '-' + m.toLowerCase());\r\n}\r\n","import { useState, useEffect } from './hooks';\r\n\r\ninterface RouterState {\r\n pathname: string;\r\n search: string;\r\n hash: string;\r\n params: Record<string, string>;\r\n}\r\n\r\ninterface RouterOptions {\r\n replace?: boolean;\r\n scroll?: boolean;\r\n}\r\n\r\nlet currentState: RouterState = {\r\n pathname: typeof window !== 'undefined' ? window.location.pathname : '/',\r\n search: typeof window !== 'undefined' ? window.location.search : '',\r\n hash: typeof window !== 'undefined' ? window.location.hash : '',\r\n params: {}\r\n};\r\n\r\nconst listeners = new Set<(state: RouterState) => void>();\r\n\r\n// Parse route pattern and extract params\r\nfunction matchRoute(pattern: string, pathname: string): Record<string, string> | null {\r\n const paramNames: string[] = [];\r\n const regexPattern = pattern.replace(/:([^/]+)/g, (_, name) => {\r\n paramNames.push(name);\r\n return '([^/]+)';\r\n });\r\n\r\n const match = pathname.match(new RegExp(`^${regexPattern}$`));\r\n if (!match) return null;\r\n\r\n const params: Record<string, string> = {};\r\n paramNames.forEach((name, i) => {\r\n params[name] = match[i + 1];\r\n });\r\n\r\n return params;\r\n}\r\n\r\nfunction updateState(newPath: string, options: RouterOptions = {}) {\r\n const url = new URL(newPath, window.location.origin);\r\n const newState: RouterState = {\r\n pathname: url.pathname,\r\n search: url.search,\r\n hash: url.hash,\r\n params: {}\r\n };\r\n\r\n if (options.replace) {\r\n window.history.replaceState(newState, '', url.toString());\r\n } else {\r\n window.history.pushState(newState, '', url.toString());\r\n }\r\n\r\n currentState = newState;\r\n listeners.forEach(listener => listener(newState));\r\n\r\n if (options.scroll) {\r\n window.scrollTo(0, 0);\r\n }\r\n}\r\n\r\nexport function navigate(to: string, options: RouterOptions = {}) {\r\n if (typeof window === 'undefined') return;\r\n updateState(to, options);\r\n}\r\n\r\nexport function useRouter() {\r\n const [state, setState] = useState<RouterState>(currentState);\r\n\r\n useEffect(() => {\r\n const handleRouteChange = (newState: RouterState) => {\r\n setState(newState);\r\n };\r\n\r\n const handlePopState = () => {\r\n currentState = {\r\n pathname: window.location.pathname,\r\n search: window.location.search,\r\n hash: window.location.hash,\r\n params: {}\r\n };\r\n setState(currentState);\r\n };\r\n\r\n listeners.add(handleRouteChange);\r\n window.addEventListener('popstate', handlePopState);\r\n\r\n return () => {\r\n listeners.delete(handleRouteChange);\r\n window.removeEventListener('popstate', handlePopState);\r\n };\r\n }, []);\r\n\r\n return {\r\n ...state,\r\n push: (to: string, options?: RouterOptions) => navigate(to, options),\r\n replace: (to: string, options?: RouterOptions) => navigate(to, { ...options, replace: true }),\r\n back: () => window.history.back(),\r\n forward: () => window.history.forward()\r\n };\r\n}\r\n\r\nexport function useRoute(pattern: string) {\r\n const { pathname } = useRouter();\r\n const [params, setParams] = useState<Record<string, string>>({});\r\n const [isMatch, setIsMatch] = useState(false);\r\n\r\n useEffect(() => {\r\n const matchedParams = matchRoute(pattern, pathname);\r\n setIsMatch(!!matchedParams);\r\n setParams(matchedParams || {});\r\n }, [pattern, pathname]);\r\n\r\n return { isMatch, params };\r\n}\r\n\r\nexport function useParams<T extends Record<string, string>>() {\r\n const router = useRouter();\r\n return router.params as T;\r\n}\r\n\r\nexport function useSearchParams() {\r\n const { search } = useRouter();\r\n return new URLSearchParams(search);\r\n}\r\n","import { navigate } from './router';\r\n\r\ninterface LinkProps {\r\n href: string;\r\n children?: any;\r\n replace?: boolean;\r\n className?: string;\r\n style?: Record<string, string>;\r\n [key: string]: any;\r\n}\r\n\r\nexport function Link({ \r\n href, \r\n children, \r\n replace = false, \r\n className,\r\n style,\r\n ...rest \r\n}: LinkProps) {\r\n const handleClick = (e: MouseEvent) => {\r\n e.preventDefault();\r\n navigate(href, { replace });\r\n };\r\n\r\n return {\r\n type: 'a',\r\n props: {\r\n href,\r\n onClick: handleClick,\r\n className,\r\n style,\r\n ...rest,\r\n children\r\n }\r\n };\r\n}\r\n","\r\n\r\nconst contexts = new Map<symbol, any>();\r\nlet currentRender: Function | null = null;\r\n\r\nexport interface Context<T> {\r\n Provider: (props: { value: T; children?: any }) => any;\r\n Consumer: (props: { children: (value: T) => any }) => any;\r\n _id: symbol;\r\n useSelector: <S>(selector: (state: T) => S) => S;\r\n}\r\n\r\nexport function createContext<T>(defaultValue: T): Context<T> {\r\n const context = {\r\n Provider: ({ value, children }: { value: T, children?: any }) => {\r\n return children;\r\n },\r\n Consumer: ({ children }: { children: (value: T) => any }) => {\r\n return children(defaultValue);\r\n },\r\n _id: Symbol(),\r\n useSelector: <S>(selector: (state: T) => S) => {\r\n return selector(defaultValue);\r\n }\r\n };\r\n\r\n return context;\r\n}\r\n\r\nexport function useContext<T>(context: any): T {\r\n return context;\r\n}\r\n","export interface ScriptConfig {\r\n src: string;\r\n defer?: boolean;\r\n async?: boolean;\r\n type?: string;\r\n}\r\n\r\nexport interface TemplateOptions {\r\n title: string;\r\n description?: string;\r\n scripts?: (string | ScriptConfig)[];\r\n styles?: string[];\r\n initialState?: any;\r\n meta?: Record<string, string>;\r\n bodyAttrs?: Record<string, string>;\r\n htmlAttrs?: Record<string, string>;\r\n}\r\n\r\nexport function defaultTemplate(content: string, options: TemplateOptions): string {\r\n const {\r\n title,\r\n description = '',\r\n scripts = [],\r\n styles = [],\r\n initialState = {},\r\n meta = {},\r\n bodyAttrs = {},\r\n htmlAttrs = { lang: 'en' }\r\n } = options;\r\n\r\n const htmlAttributes = Object.entries(htmlAttrs)\r\n .map(([key, value]) => `${key}=\"${value}\"`)\r\n .join(' ');\r\n\r\n const bodyAttributes = Object.entries(bodyAttrs)\r\n .map(([key, value]) => `${key}=\"${value}\"`)\r\n .join(' ');\r\n\r\n const metaTags = Object.entries(meta)\r\n .map(([name, content]) => ` <meta name=\"${name}\" content=\"${content}\">`)\r\n .join('\\n');\r\n\r\n const scriptTags = scripts.map(script => {\r\n if (typeof script === 'string') {\r\n return ` <script src=\"${script}\" defer></script>`;\r\n }\r\n const { src, defer = true, async = false, type } = script;\r\n return ` <script src=\"${src}\"${defer ? ' defer' : ''}${async ? ' async' : ''}${type ? ` type=\"${type}\"` : ''}></script>`;\r\n }).join('\\n');\r\n\r\n return `<!DOCTYPE html>\r\n<html ${htmlAttributes}>\r\n <head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n ${description ? `<meta name=\"description\" content=\"${description}\">\\n` : ''}${metaTags}\r\n <title>${title}</title>\r\n${styles.map(href => ` <link rel=\"stylesheet\" href=\"${href}\">`).join('\\n')}\r\n <script>\r\n window.__INITIAL_STATE__ = ${JSON.stringify(initialState)};\r\n </script>\r\n </head>\r\n <body ${bodyAttributes}>\r\n <div id=\"root\">${content}</div>\r\n${scriptTags}\r\n </body>\r\n</html>`;\r\n}\r\n"],"names":["isBatching","queue","batchUpdates","fn","push","length","nextFn","shift","currentRender","states","Map","stateIndices","effects","memos","refs","globalRenderCallback","globalContainer","currentElement","isServer","window","serverStates","useState","initial","Error","has","set","componentState","get","index","state","setState","newValue","componentStates","nextValue","rerender","useEffect","callback","deps","effectIndex","componentEffects","prevEffect","some","dep","i","cleanup","queueMicrotask","async","rendererId","forEach","effect","error","console","jsx","type","props","log","processedProps","arguments","children","Array","prototype","slice","call","createElement","vnode","document","createTextNode","String","isArray","fragment","createDocumentFragment","child","node","appendChild","result","Element","setAttribute","name","toString","element","key","value","Object","entries","startsWith","eventName","toLowerCase","existingHandler","_a","__events","removeEventListener","addEventListener","assign","style","childArray","flat","childNode","isHydrating","render","container","id","setRenderCallback","domNode","innerHTML","delete","renderNodeToString","escapeHtml","Promise","all","map","join","html","styleToString","renderProps","Set","str","replace","m","currentState","pathname","location","search","hash","params","listeners","navigate","to","options","newPath","url","URL","origin","newState","history","replaceState","pushState","listener","scroll","scrollTo","updateState","href","className","rest","onClick","e","preventDefault","defaultValue","Provider","Consumer","_id","Symbol","useSelector","selector","content","processedScripts","scripts","script","src","defer","title","description","styles","initialState","meta","bodyAttrs","htmlAttrs","lang","htmlAttributes","bodyAttributes","metaTags","scriptTags","JSON","stringify","defaultTemplate","process","env","NODE_ENV","stack","message","context","setError","factory","memoIndex","componentMemos","prevMemo","is","refIndex","componentRefs","ref","current","handleRouteChange","handlePopState","add","back","forward"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -298,6 +298,13 @@ function defaultTemplate(content, options) {
298
298
  const htmlAttributes = Object.entries(htmlAttrs).map(([key, value]) => `${key}="${value}"`).join(" ");
299
299
  const bodyAttributes = Object.entries(bodyAttrs).map(([key, value]) => `${key}="${value}"`).join(" ");
300
300
  const metaTags = Object.entries(meta).map(([name, content2]) => ` <meta name="${name}" content="${content2}">`).join("\n");
301
+ const scriptTags = scripts.map((script) => {
302
+ if (typeof script === "string") {
303
+ return ` <script src="${script}" defer><\/script>`;
304
+ }
305
+ const { src, defer = true, async = false, type } = script;
306
+ return ` <script src="${src}"${defer ? " defer" : ""}${async ? " async" : ""}${type ? ` type="${type}"` : ""}><\/script>`;
307
+ }).join("\n");
301
308
  return `<!DOCTYPE html>
302
309
  <html ${htmlAttributes}>
303
310
  <head>
@@ -313,50 +320,96 @@ ${styles.map((href) => ` <link rel="stylesheet" href="${href}">`).join("\n")}
313
320
  </head>
314
321
  <body ${bodyAttributes}>
315
322
  <div id="root">${content}</div>
316
- ${scripts.map((src) => ` <script src="${src}" defer><\/script>`).join("\n")}
323
+ ${scriptTags}
317
324
  </body>
318
325
  </html>`;
319
326
  }
320
327
  async function renderToString(element, options = {}) {
328
+ var _a;
321
329
  try {
322
330
  const content = await renderNodeToString(element);
331
+ const processedScripts = (_a = options.scripts) == null ? void 0 : _a.map(
332
+ (script) => typeof script === "string" ? { src: script, defer: true } : { ...script, defer: script.defer ?? true }
333
+ );
323
334
  return defaultTemplate(content, {
324
335
  title: "Frontend Hamroun App",
325
- ...options
336
+ ...options,
337
+ scripts: processedScripts
326
338
  });
327
339
  } catch (error) {
328
- console.error("Error during server rendering:", error);
340
+ console.error("Server rendering error:", error);
341
+ if (process.env.NODE_ENV === "development") {
342
+ const errorMessage = error instanceof Error ? error.stack || error.message : String(error);
343
+ return `
344
+ <!DOCTYPE html>
345
+ <html>
346
+ <head><title>Rendering Error</title></head>
347
+ <body>
348
+ <h1>Server Rendering Error</h1>
349
+ <pre>${escapeHtml(errorMessage)}</pre>
350
+ </body>
351
+ </html>
352
+ `;
353
+ }
329
354
  return "";
355
+ } finally {
330
356
  }
331
357
  }
332
358
  async function renderNodeToString(node) {
333
359
  var _a;
334
- if (node == null || typeof node === "boolean") {
360
+ if (node == null || typeof node === "boolean")
335
361
  return "";
336
- }
337
362
  if (typeof node === "number" || typeof node === "string") {
338
363
  return escapeHtml(String(node));
339
364
  }
365
+ if (Array.isArray(node)) {
366
+ const results = await Promise.all(
367
+ node.map((child) => renderNodeToString(child))
368
+ );
369
+ return results.join("");
370
+ }
340
371
  if (typeof node === "function") {
341
- const result = await node({});
342
- return renderNodeToString(result);
372
+ ({ type: node.name || "Anonymous" });
373
+ try {
374
+ const result = await node({});
375
+ return renderNodeToString(result);
376
+ } finally {
377
+ }
343
378
  }
344
379
  if (node.type) {
345
380
  if (typeof node.type === "function") {
346
- const result = await node.type(node.props || {});
347
- return renderNodeToString(result);
381
+ ({
382
+ type: node.type.name || "Anonymous",
383
+ props: node.props || {}
384
+ });
385
+ try {
386
+ const result = await node.type(node.props || {});
387
+ return renderNodeToString(result);
388
+ } finally {
389
+ }
348
390
  }
349
391
  let html = `<${node.type}`;
350
- for (const [key, value] of Object.entries(node.props || {})) {
351
- if (key === "children" || key === "key" || key === "ref")
352
- continue;
353
- if (key === "className") {
354
- html += ` class="${escapeHtml(String(value))}"`;
355
- } else if (key === "style" && typeof value === "object" && value !== null) {
356
- html += ` style="${styleToString(value)}"`;
357
- } else if (!key.startsWith("on")) {
358
- html += ` ${key}="${escapeHtml(String(value))}"`;
359
- }
392
+ if (node.props) {
393
+ html += renderProps(node.props);
394
+ }
395
+ const voidElements = /* @__PURE__ */ new Set([
396
+ "area",
397
+ "base",
398
+ "br",
399
+ "col",
400
+ "embed",
401
+ "hr",
402
+ "img",
403
+ "input",
404
+ "link",
405
+ "meta",
406
+ "param",
407
+ "source",
408
+ "track",
409
+ "wbr"
410
+ ]);
411
+ if (voidElements.has(node.type)) {
412
+ return html + "/>";
360
413
  }
361
414
  html += ">";
362
415
  if ((_a = node.props) == null ? void 0 : _a.children) {
@@ -365,16 +418,45 @@ async function renderNodeToString(node) {
365
418
  html += await renderNodeToString(child);
366
419
  }
367
420
  }
368
- html += `</${node.type}>`;
369
- return html;
421
+ return html + `</${node.type}>`;
370
422
  }
371
423
  return "";
372
424
  }
425
+ function renderProps(props) {
426
+ let html = "";
427
+ for (const [key, value] of Object.entries(props)) {
428
+ if (key === "children" || key === "key" || key === "ref")
429
+ continue;
430
+ if (key === "className") {
431
+ if (value)
432
+ html += ` class="${escapeHtml(String(value))}"`;
433
+ continue;
434
+ }
435
+ if (key === "style" && typeof value === "object" && value !== null) {
436
+ html += ` style="${styleToString(value)}"`;
437
+ continue;
438
+ }
439
+ if (key.startsWith("on"))
440
+ continue;
441
+ if (typeof value === "boolean") {
442
+ if (value)
443
+ html += ` ${key}`;
444
+ continue;
445
+ }
446
+ if (value != null) {
447
+ html += ` ${key}="${escapeHtml(String(value))}"`;
448
+ }
449
+ }
450
+ return html;
451
+ }
373
452
  function escapeHtml(str) {
374
453
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
375
454
  }
376
455
  function styleToString(style) {
377
- return Object.entries(style).map(([key, value]) => `${key}: ${value}`).join("; ");
456
+ return Object.entries(style).map(([key, value]) => `${hyphenate(key)}: ${value}`).join("; ");
457
+ }
458
+ function hyphenate(str) {
459
+ return str.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
378
460
  }
379
461
  let currentState = {
380
462
  pathname: typeof window !== "undefined" ? window.location.pathname : "/",
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/batch.ts","../src/hooks.ts","../src/jsx-runtime.ts","../src/context.ts","../src/renderer.ts","../src/templates/default.ts","../src/server-renderer.ts","../src/router.ts","../src/link.tsx"],"sourcesContent":["export let isBatching = false;\r\nconst queue: Function[] = [];\r\n\r\nexport function batchUpdates(fn: Function) {\r\n if (isBatching) {\r\n queue.push(fn);\r\n return;\r\n }\r\n\r\n isBatching = true;\r\n try {\r\n fn();\r\n while (queue.length > 0) {\r\n const nextFn = queue.shift();\r\n nextFn?.();\r\n }\r\n } finally {\r\n isBatching = false;\r\n }\r\n}\r\n\r\nexport function getIsBatching() {\r\n return isBatching;\r\n}\r\n","import { createElement } from './jsx-runtime';\r\nimport { batchUpdates, isBatching } from './batch';\r\nimport { diff } from './vdom';\r\n\r\nlet currentRender: number = 0;\r\nconst states = new Map<number, any[]>();\r\nconst stateIndices = new Map<number, number>();\r\nconst effects = new Map<number, Effect[]>();\r\nconst memos = new Map<number, { value: any; deps: any[] }[]>();\r\nconst refs = new Map<number, any[]>();\r\n\r\ninterface Effect {\r\n cleanup?: () => void;\r\n deps?: any[];\r\n}\r\n\r\n// Add at the top with other declarations\r\nlet globalRenderCallback: ((element: any, container: HTMLElement) => void) | null = null;\r\nlet globalContainer: HTMLElement | null = null;\r\nlet currentElement: any = null;\r\n\r\nconst isServer = typeof window === 'undefined';\r\nconst serverStates = new Map<number, any>();\r\n\r\nexport function setRenderCallback(\r\n callback: (element: any, container: HTMLElement) => void,\r\n element: any,\r\n container: HTMLElement\r\n) {\r\n globalRenderCallback = callback;\r\n globalContainer = container;\r\n currentElement = element;\r\n}\r\n\r\nexport function prepareRender() {\r\n currentRender++;\r\n stateIndices.set(currentRender, 0);\r\n return currentRender;\r\n}\r\n\r\nexport function finishRender() {\r\n if (isServer) {\r\n serverStates.delete(currentRender);\r\n }\r\n currentRender = 0;\r\n}\r\n\r\nexport function useState<T>(initial: T): [T, (value: T | ((prev: T) => T)) => void] {\r\n if (!currentRender) {\r\n throw new Error('useState must be called within a render');\r\n }\r\n\r\n if (isServer) {\r\n // Server-side state handling\r\n if (!serverStates.has(currentRender)) {\r\n serverStates.set(currentRender, new Map());\r\n }\r\n const componentState = serverStates.get(currentRender)!;\r\n const index = stateIndices.get(currentRender) || 0;\r\n \r\n if (!componentState.has(index)) {\r\n componentState.set(index, initial);\r\n }\r\n\r\n const state = componentState.get(index);\r\n const setState = (newValue: T | ((prev: T) => T)) => {\r\n // No-op for server-side\r\n };\r\n\r\n stateIndices.set(currentRender, index + 1);\r\n return [state, setState];\r\n }\r\n\r\n if (!states.has(currentRender)) {\r\n states.set(currentRender, []);\r\n }\r\n\r\n const componentStates = states.get(currentRender)!;\r\n const index = stateIndices.get(currentRender)!;\r\n \r\n if (index >= componentStates.length) {\r\n componentStates.push(initial);\r\n }\r\n\r\n const state = componentStates[index];\r\n const setState = (newValue: T | ((prev: T) => T)) => {\r\n const nextValue = typeof newValue === 'function' \r\n ? (newValue as Function)(componentStates[index])\r\n : newValue;\r\n\r\n if (componentStates[index] === nextValue) return; // Skip if value hasn't changed\r\n \r\n componentStates[index] = nextValue;\r\n \r\n if (isBatching) {\r\n batchUpdates(() => rerender(currentRender));\r\n } else {\r\n rerender(currentRender);\r\n }\r\n };\r\n\r\n stateIndices.set(currentRender, index + 1);\r\n return [state, setState];\r\n}\r\n\r\nexport function useEffect(callback: () => (() => void) | void, deps?: any[]) {\r\n if (!currentRender) throw new Error('useEffect must be called within a render');\r\n \r\n const effectIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!effects.has(currentRender)) {\r\n effects.set(currentRender, []);\r\n }\r\n\r\n const componentEffects = effects.get(currentRender)!;\r\n const prevEffect = componentEffects[effectIndex];\r\n \r\n // Run effect if deps changed\r\n if (!prevEffect || !deps || !prevEffect.deps || \r\n deps.some((dep, i) => dep !== prevEffect.deps![i])) {\r\n \r\n // Cleanup previous effect\r\n if (prevEffect?.cleanup) {\r\n prevEffect.cleanup();\r\n }\r\n\r\n // Schedule new effect\r\n queueMicrotask(() => {\r\n const cleanup = callback() || undefined;\r\n componentEffects[effectIndex] = { cleanup: cleanup, deps };\r\n });\r\n }\r\n \r\n stateIndices.set(currentRender, effectIndex + 1);\r\n}\r\n\r\nexport function useMemo<T>(factory: () => T, deps: any[]): T {\r\n if (!currentRender) throw new Error('useMemo must be called within a render');\r\n \r\n const memoIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!memos.has(currentRender)) {\r\n memos.set(currentRender, []);\r\n }\r\n\r\n const componentMemos = memos.get(currentRender)!;\r\n const prevMemo = componentMemos[memoIndex];\r\n \r\n if (!prevMemo || (deps && deps.some((dep, i) => !Object.is(dep, prevMemo.deps[i])))) {\r\n const value = factory();\r\n componentMemos[memoIndex] = { value, deps };\r\n stateIndices.set(currentRender, memoIndex + 1);\r\n return value;\r\n }\r\n\r\n stateIndices.set(currentRender, memoIndex + 1);\r\n return prevMemo.value;\r\n}\r\n\r\nexport function useRef<T>(initial: T) {\r\n if (!currentRender) throw new Error('useRef must be called within a render');\r\n \r\n const refIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!refs.has(currentRender)) {\r\n refs.set(currentRender, []);\r\n }\r\n\r\n const componentRefs = refs.get(currentRender)!;\r\n if (refIndex >= componentRefs.length) {\r\n // Initialize with an object that has a current property\r\n const ref = { current: initial };\r\n componentRefs.push(ref);\r\n stateIndices.set(currentRender, refIndex + 1);\r\n return ref;\r\n }\r\n\r\n const ref = componentRefs[refIndex];\r\n stateIndices.set(currentRender, refIndex + 1);\r\n return ref;\r\n}\r\n\r\n// Add a map to track component DOM nodes\r\nconst componentNodes = new Map<Function, Node>();\r\n\r\nasync function rerender(rendererId: number) {\r\n try {\r\n // Clean up effects\r\n const componentEffects = effects.get(rendererId);\r\n if (componentEffects) {\r\n componentEffects.forEach(effect => {\r\n if (effect.cleanup) effect.cleanup();\r\n });\r\n effects.set(rendererId, []);\r\n }\r\n\r\n if (globalRenderCallback && globalContainer && currentElement) {\r\n await globalRenderCallback(currentElement, globalContainer);\r\n }\r\n } catch (error) {\r\n console.error('Error during rerender:', error);\r\n }\r\n}\r\n\r\n// Add new hook for error boundaries\r\nexport function useErrorBoundary(): [Error | null, () => void] {\r\n const [error, setError] = useState<Error | null>(null);\r\n return [error, () => setError(null)];\r\n}\r\n\r\n// Remove withHooks export\r\n","import type { Component } from './component';\r\n\r\ninterface VNode {\r\n type: string | Function;\r\n props: Record<string, any>;\r\n}\r\n\r\nfunction jsx(type: string | Function, props: any): VNode {\r\n console.log('JSX Transform:', { type, props });\r\n const processedProps = { ...props };\r\n \r\n // Handle children properly\r\n if (arguments.length > 2) {\r\n processedProps.children = Array.prototype.slice.call(arguments, 2);\r\n }\r\n \r\n return { type, props: processedProps };\r\n}\r\n\r\nconst Fragment = ({ children }: { children: any }) => children;\r\n\r\nasync function createElement(vnode: VNode | any): Promise<Node> {\r\n console.log('Creating element from:', vnode);\r\n\r\n // Handle primitives and null\r\n if (vnode == null) {\r\n return document.createTextNode('');\r\n }\r\n \r\n if (typeof vnode === 'boolean') {\r\n return document.createTextNode('');\r\n }\r\n\r\n if (typeof vnode === 'number' || typeof vnode === 'string') {\r\n return document.createTextNode(String(vnode));\r\n }\r\n\r\n // Handle arrays\r\n if (Array.isArray(vnode)) {\r\n const fragment = document.createDocumentFragment();\r\n for (const child of vnode) {\r\n const node = await createElement(child);\r\n fragment.appendChild(node);\r\n }\r\n return fragment;\r\n }\r\n\r\n // Handle VNode\r\n if ('type' in vnode && vnode.props !== undefined) {\r\n const { type, props } = vnode;\r\n \r\n // Handle function components\r\n if (typeof type === 'function') {\r\n try {\r\n const result = await type(props || {});\r\n const node = await createElement(result);\r\n if (node instanceof Element) {\r\n node.setAttribute('data-component-id', type.name || type.toString());\r\n }\r\n return node;\r\n } catch (error) {\r\n console.error('Error rendering component:', error);\r\n return document.createTextNode('');\r\n }\r\n }\r\n\r\n // Create DOM element\r\n const element = document.createElement(type as string);\r\n \r\n // Handle props\r\n for (const [key, value] of Object.entries(props || {})) {\r\n if (key === 'children') continue;\r\n if (key.startsWith('on') && typeof value === 'function') {\r\n const eventName = key.toLowerCase().slice(2);\r\n // Remove existing event listener if any\r\n const existingHandler = (element as any).__events?.[eventName];\r\n if (existingHandler) {\r\n element.removeEventListener(eventName, existingHandler);\r\n }\r\n \r\n // Add new event listener\r\n element.addEventListener(eventName, value as EventListener);\r\n if (!(element as any).__events) {\r\n (element as any).__events = {};\r\n }\r\n (element as any).__events[eventName] = value;\r\n } else if (key === 'style' && typeof value === 'object') {\r\n Object.assign(element.style, value);\r\n } else if (key === 'className') {\r\n element.setAttribute('class', String(value));\r\n } else if (key !== 'key' && key !== 'ref') {\r\n element.setAttribute(key, String(value));\r\n }\r\n }\r\n\r\n // Handle children\r\n const children = props?.children;\r\n if (children != null) {\r\n const childArray = Array.isArray(children) ? children.flat() : [children];\r\n for (const child of childArray) {\r\n const childNode = await createElement(child);\r\n element.appendChild(childNode);\r\n }\r\n }\r\n\r\n return element;\r\n }\r\n\r\n // Handle other objects by converting to string\r\n return document.createTextNode(String(vnode));\r\n}\r\n\r\n// Export named functions and aliases without duplicates\r\nexport {\r\n jsx,\r\n jsx as jsxs,\r\n jsx as jsxDEV,\r\n Fragment,\r\n createElement\r\n};\r\n\r\n// Named exports object\r\nconst jsxRuntime = {\r\n jsx,\r\n jsxs: jsx,\r\n jsxDEV: jsx,\r\n Fragment,\r\n createElement\r\n};\r\n\r\nexport default jsxRuntime;\r\n","\r\n\r\nconst contexts = new Map<symbol, any>();\r\nlet currentRender: Function | null = null;\r\n\r\nexport interface Context<T> {\r\n Provider: (props: { value: T; children?: any }) => any;\r\n Consumer: (props: { children: (value: T) => any }) => any;\r\n _id: symbol;\r\n useSelector: <S>(selector: (state: T) => S) => S;\r\n}\r\n\r\nexport function createContext<T>(defaultValue: T): Context<T> {\r\n const context = {\r\n Provider: ({ value, children }: { value: T, children?: any }) => {\r\n return children;\r\n },\r\n Consumer: ({ children }: { children: (value: T) => any }) => {\r\n return children(defaultValue);\r\n },\r\n _id: Symbol(),\r\n useSelector: <S>(selector: (state: T) => S) => {\r\n return selector(defaultValue);\r\n }\r\n };\r\n\r\n return context;\r\n}\r\n\r\nexport function useContext<T>(context: any): T {\r\n return context;\r\n}\r\n","import { createElement } from './jsx-runtime';\r\nimport { prepareRender, finishRender, setRenderCallback } from './hooks';\r\nimport { batchUpdates } from './batch';\r\n\r\nlet isHydrating = false;\r\n\r\nexport async function hydrate(element: any, container: HTMLElement) {\r\n isHydrating = true;\r\n try {\r\n await render(element, container);\r\n } finally {\r\n isHydrating = false;\r\n }\r\n}\r\n\r\nexport async function render(element: any, container: HTMLElement) {\r\n console.log('Rendering to:', container.id);\r\n \r\n batchUpdates(async () => {\r\n const rendererId = prepareRender();\r\n try {\r\n setRenderCallback(render, element, container);\r\n const domNode = await createElement(element);\r\n \r\n if (!isHydrating) {\r\n container.innerHTML = '';\r\n }\r\n container.appendChild(domNode);\r\n \r\n } finally {\r\n finishRender();\r\n }\r\n });\r\n}\r\n","export interface TemplateOptions {\r\n title: string;\r\n description?: string;\r\n scripts?: string[];\r\n styles?: string[];\r\n initialState?: any;\r\n meta?: Record<string, string>;\r\n bodyAttrs?: Record<string, string>;\r\n htmlAttrs?: Record<string, string>;\r\n}\r\n\r\nexport function defaultTemplate(content: string, options: TemplateOptions): string {\r\n const {\r\n title,\r\n description = '',\r\n scripts = [],\r\n styles = [],\r\n initialState = {},\r\n meta = {},\r\n bodyAttrs = {},\r\n htmlAttrs = { lang: 'en' }\r\n } = options;\r\n\r\n const htmlAttributes = Object.entries(htmlAttrs)\r\n .map(([key, value]) => `${key}=\"${value}\"`)\r\n .join(' ');\r\n\r\n const bodyAttributes = Object.entries(bodyAttrs)\r\n .map(([key, value]) => `${key}=\"${value}\"`)\r\n .join(' ');\r\n\r\n const metaTags = Object.entries(meta)\r\n .map(([name, content]) => ` <meta name=\"${name}\" content=\"${content}\">`)\r\n .join('\\n');\r\n\r\n return `<!DOCTYPE html>\r\n<html ${htmlAttributes}>\r\n <head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n ${description ? `<meta name=\"description\" content=\"${description}\">\\n` : ''}${metaTags}\r\n <title>${title}</title>\r\n${styles.map(href => ` <link rel=\"stylesheet\" href=\"${href}\">`).join('\\n')}\r\n <script>\r\n window.__INITIAL_STATE__ = ${JSON.stringify(initialState)};\r\n </script>\r\n </head>\r\n <body ${bodyAttributes}>\r\n <div id=\"root\">${content}</div>\r\n${scripts.map(src => ` <script src=\"${src}\" defer></script>`).join('\\n')}\r\n </body>\r\n</html>`;\r\n}\r\n","import { VNode } from './types';\r\nimport { defaultTemplate, TemplateOptions } from './templates/default';\r\n\r\nexport async function renderToString(\r\n element: JSX.Element, \r\n options: Partial<TemplateOptions> = {}\r\n): Promise<string> {\r\n try {\r\n const content = await renderNodeToString(element);\r\n return defaultTemplate(content, {\r\n title: 'Frontend Hamroun App',\r\n ...options\r\n });\r\n } catch (error) {\r\n console.error('Error during server rendering:', error);\r\n return '';\r\n }\r\n}\r\n\r\nasync function renderNodeToString(node: VNode | any): Promise<string> {\r\n if (node == null || typeof node === 'boolean') {\r\n return '';\r\n }\r\n\r\n if (typeof node === 'number' || typeof node === 'string') {\r\n return escapeHtml(String(node));\r\n }\r\n\r\n if (typeof node === 'function') {\r\n const result = await node({ });\r\n return renderNodeToString(result);\r\n }\r\n\r\n if (node.type) {\r\n if (typeof node.type === 'function') {\r\n const result = await node.type(node.props || {});\r\n return renderNodeToString(result);\r\n }\r\n\r\n let html = `<${node.type}`;\r\n \r\n // Handle props\r\n for (const [key, value] of Object.entries(node.props || {})) {\r\n if (key === 'children' || key === 'key' || key === 'ref') continue;\r\n if (key === 'className') {\r\n html += ` class=\"${escapeHtml(String(value))}\"`;\r\n } else if (key === 'style' && typeof value === 'object' && value !== null) {\r\n html += ` style=\"${styleToString(value)}\"`;\r\n } else if (!key.startsWith('on')) {\r\n html += ` ${key}=\"${escapeHtml(String(value))}\"`;\r\n }\r\n }\r\n\r\n html += '>';\r\n\r\n // Handle children\r\n if (node.props?.children) {\r\n const children = Array.isArray(node.props.children) \r\n ? node.props.children \r\n : [node.props.children];\r\n \r\n for (const child of children) {\r\n html += await renderNodeToString(child);\r\n }\r\n }\r\n\r\n html += `</${node.type}>`;\r\n return html;\r\n }\r\n\r\n return '';\r\n}\r\n\r\nfunction escapeHtml(str: string): string {\r\n return str\r\n .replace(/&/g, '&amp;')\r\n .replace(/</g, '&lt;')\r\n .replace(/>/g, '&gt;')\r\n .replace(/\"/g, '&quot;')\r\n .replace(/'/g, '&#039;');\r\n}\r\n\r\nfunction styleToString(style: Record<string, any>): string {\r\n return Object.entries(style)\r\n .map(([key, value]) => `${key}: ${value}`)\r\n .join('; ');\r\n}\r\n","import { useState, useEffect } from './hooks';\r\n\r\ninterface RouterState {\r\n pathname: string;\r\n search: string;\r\n hash: string;\r\n params: Record<string, string>;\r\n}\r\n\r\ninterface RouterOptions {\r\n replace?: boolean;\r\n scroll?: boolean;\r\n}\r\n\r\nlet currentState: RouterState = {\r\n pathname: typeof window !== 'undefined' ? window.location.pathname : '/',\r\n search: typeof window !== 'undefined' ? window.location.search : '',\r\n hash: typeof window !== 'undefined' ? window.location.hash : '',\r\n params: {}\r\n};\r\n\r\nconst listeners = new Set<(state: RouterState) => void>();\r\n\r\n// Parse route pattern and extract params\r\nfunction matchRoute(pattern: string, pathname: string): Record<string, string> | null {\r\n const paramNames: string[] = [];\r\n const regexPattern = pattern.replace(/:([^/]+)/g, (_, name) => {\r\n paramNames.push(name);\r\n return '([^/]+)';\r\n });\r\n\r\n const match = pathname.match(new RegExp(`^${regexPattern}$`));\r\n if (!match) return null;\r\n\r\n const params: Record<string, string> = {};\r\n paramNames.forEach((name, i) => {\r\n params[name] = match[i + 1];\r\n });\r\n\r\n return params;\r\n}\r\n\r\nfunction updateState(newPath: string, options: RouterOptions = {}) {\r\n const url = new URL(newPath, window.location.origin);\r\n const newState: RouterState = {\r\n pathname: url.pathname,\r\n search: url.search,\r\n hash: url.hash,\r\n params: {}\r\n };\r\n\r\n if (options.replace) {\r\n window.history.replaceState(newState, '', url.toString());\r\n } else {\r\n window.history.pushState(newState, '', url.toString());\r\n }\r\n\r\n currentState = newState;\r\n listeners.forEach(listener => listener(newState));\r\n\r\n if (options.scroll) {\r\n window.scrollTo(0, 0);\r\n }\r\n}\r\n\r\nexport function navigate(to: string, options: RouterOptions = {}) {\r\n if (typeof window === 'undefined') return;\r\n updateState(to, options);\r\n}\r\n\r\nexport function useRouter() {\r\n const [state, setState] = useState<RouterState>(currentState);\r\n\r\n useEffect(() => {\r\n const handleRouteChange = (newState: RouterState) => {\r\n setState(newState);\r\n };\r\n\r\n const handlePopState = () => {\r\n currentState = {\r\n pathname: window.location.pathname,\r\n search: window.location.search,\r\n hash: window.location.hash,\r\n params: {}\r\n };\r\n setState(currentState);\r\n };\r\n\r\n listeners.add(handleRouteChange);\r\n window.addEventListener('popstate', handlePopState);\r\n\r\n return () => {\r\n listeners.delete(handleRouteChange);\r\n window.removeEventListener('popstate', handlePopState);\r\n };\r\n }, []);\r\n\r\n return {\r\n ...state,\r\n push: (to: string, options?: RouterOptions) => navigate(to, options),\r\n replace: (to: string, options?: RouterOptions) => navigate(to, { ...options, replace: true }),\r\n back: () => window.history.back(),\r\n forward: () => window.history.forward()\r\n };\r\n}\r\n\r\nexport function useRoute(pattern: string) {\r\n const { pathname } = useRouter();\r\n const [params, setParams] = useState<Record<string, string>>({});\r\n const [isMatch, setIsMatch] = useState(false);\r\n\r\n useEffect(() => {\r\n const matchedParams = matchRoute(pattern, pathname);\r\n setIsMatch(!!matchedParams);\r\n setParams(matchedParams || {});\r\n }, [pattern, pathname]);\r\n\r\n return { isMatch, params };\r\n}\r\n\r\nexport function useParams<T extends Record<string, string>>() {\r\n const router = useRouter();\r\n return router.params as T;\r\n}\r\n\r\nexport function useSearchParams() {\r\n const { search } = useRouter();\r\n return new URLSearchParams(search);\r\n}\r\n","import { navigate } from './router';\r\n\r\ninterface LinkProps {\r\n href: string;\r\n children?: any;\r\n replace?: boolean;\r\n className?: string;\r\n style?: Record<string, string>;\r\n [key: string]: any;\r\n}\r\n\r\nexport function Link({ \r\n href, \r\n children, \r\n replace = false, \r\n className,\r\n style,\r\n ...rest \r\n}: LinkProps) {\r\n const handleClick = (e: MouseEvent) => {\r\n e.preventDefault();\r\n navigate(href, { replace });\r\n };\r\n\r\n return {\r\n type: 'a',\r\n props: {\r\n href,\r\n onClick: handleClick,\r\n className,\r\n style,\r\n ...rest,\r\n children\r\n }\r\n };\r\n}\r\n"],"names":["index","state","setState","ref","content"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/batch.ts","../src/hooks.ts","../src/jsx-runtime.ts","../src/context.ts","../src/renderer.ts","../src/templates/default.ts","../src/server-renderer.ts","../src/router.ts","../src/link.tsx"],"sourcesContent":["export let isBatching = false;\r\nconst queue: Function[] = [];\r\n\r\nexport function batchUpdates(fn: Function) {\r\n if (isBatching) {\r\n queue.push(fn);\r\n return;\r\n }\r\n\r\n isBatching = true;\r\n try {\r\n fn();\r\n while (queue.length > 0) {\r\n const nextFn = queue.shift();\r\n nextFn?.();\r\n }\r\n } finally {\r\n isBatching = false;\r\n }\r\n}\r\n\r\nexport function getIsBatching() {\r\n return isBatching;\r\n}\r\n","import { createElement } from './jsx-runtime';\r\nimport { batchUpdates, isBatching } from './batch';\r\nimport { diff } from './vdom';\r\n\r\nlet currentRender: number = 0;\r\nconst states = new Map<number, any[]>();\r\nconst stateIndices = new Map<number, number>();\r\nconst effects = new Map<number, Effect[]>();\r\nconst memos = new Map<number, { value: any; deps: any[] }[]>();\r\nconst refs = new Map<number, any[]>();\r\n\r\ninterface Effect {\r\n cleanup?: () => void;\r\n deps?: any[];\r\n}\r\n\r\n// Add at the top with other declarations\r\nlet globalRenderCallback: ((element: any, container: HTMLElement) => void) | null = null;\r\nlet globalContainer: HTMLElement | null = null;\r\nlet currentElement: any = null;\r\n\r\nconst isServer = typeof window === 'undefined';\r\nconst serverStates = new Map<number, any>();\r\n\r\nexport function setRenderCallback(\r\n callback: (element: any, container: HTMLElement) => void,\r\n element: any,\r\n container: HTMLElement\r\n) {\r\n globalRenderCallback = callback;\r\n globalContainer = container;\r\n currentElement = element;\r\n}\r\n\r\nexport function prepareRender() {\r\n currentRender++;\r\n stateIndices.set(currentRender, 0);\r\n return currentRender;\r\n}\r\n\r\nexport function finishRender() {\r\n if (isServer) {\r\n serverStates.delete(currentRender);\r\n }\r\n currentRender = 0;\r\n}\r\n\r\nexport function useState<T>(initial: T): [T, (value: T | ((prev: T) => T)) => void] {\r\n if (!currentRender) {\r\n throw new Error('useState must be called within a render');\r\n }\r\n\r\n if (isServer) {\r\n // Server-side state handling\r\n if (!serverStates.has(currentRender)) {\r\n serverStates.set(currentRender, new Map());\r\n }\r\n const componentState = serverStates.get(currentRender)!;\r\n const index = stateIndices.get(currentRender) || 0;\r\n \r\n if (!componentState.has(index)) {\r\n componentState.set(index, initial);\r\n }\r\n\r\n const state = componentState.get(index);\r\n const setState = (newValue: T | ((prev: T) => T)) => {\r\n // No-op for server-side\r\n };\r\n\r\n stateIndices.set(currentRender, index + 1);\r\n return [state, setState];\r\n }\r\n\r\n if (!states.has(currentRender)) {\r\n states.set(currentRender, []);\r\n }\r\n\r\n const componentStates = states.get(currentRender)!;\r\n const index = stateIndices.get(currentRender)!;\r\n \r\n if (index >= componentStates.length) {\r\n componentStates.push(initial);\r\n }\r\n\r\n const state = componentStates[index];\r\n const setState = (newValue: T | ((prev: T) => T)) => {\r\n const nextValue = typeof newValue === 'function' \r\n ? (newValue as Function)(componentStates[index])\r\n : newValue;\r\n\r\n if (componentStates[index] === nextValue) return; // Skip if value hasn't changed\r\n \r\n componentStates[index] = nextValue;\r\n \r\n if (isBatching) {\r\n batchUpdates(() => rerender(currentRender));\r\n } else {\r\n rerender(currentRender);\r\n }\r\n };\r\n\r\n stateIndices.set(currentRender, index + 1);\r\n return [state, setState];\r\n}\r\n\r\nexport function useEffect(callback: () => (() => void) | void, deps?: any[]) {\r\n if (!currentRender) throw new Error('useEffect must be called within a render');\r\n \r\n const effectIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!effects.has(currentRender)) {\r\n effects.set(currentRender, []);\r\n }\r\n\r\n const componentEffects = effects.get(currentRender)!;\r\n const prevEffect = componentEffects[effectIndex];\r\n \r\n // Run effect if deps changed\r\n if (!prevEffect || !deps || !prevEffect.deps || \r\n deps.some((dep, i) => dep !== prevEffect.deps![i])) {\r\n \r\n // Cleanup previous effect\r\n if (prevEffect?.cleanup) {\r\n prevEffect.cleanup();\r\n }\r\n\r\n // Schedule new effect\r\n queueMicrotask(() => {\r\n const cleanup = callback() || undefined;\r\n componentEffects[effectIndex] = { cleanup: cleanup, deps };\r\n });\r\n }\r\n \r\n stateIndices.set(currentRender, effectIndex + 1);\r\n}\r\n\r\nexport function useMemo<T>(factory: () => T, deps: any[]): T {\r\n if (!currentRender) throw new Error('useMemo must be called within a render');\r\n \r\n const memoIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!memos.has(currentRender)) {\r\n memos.set(currentRender, []);\r\n }\r\n\r\n const componentMemos = memos.get(currentRender)!;\r\n const prevMemo = componentMemos[memoIndex];\r\n \r\n if (!prevMemo || (deps && deps.some((dep, i) => !Object.is(dep, prevMemo.deps[i])))) {\r\n const value = factory();\r\n componentMemos[memoIndex] = { value, deps };\r\n stateIndices.set(currentRender, memoIndex + 1);\r\n return value;\r\n }\r\n\r\n stateIndices.set(currentRender, memoIndex + 1);\r\n return prevMemo.value;\r\n}\r\n\r\nexport function useRef<T>(initial: T) {\r\n if (!currentRender) throw new Error('useRef must be called within a render');\r\n \r\n const refIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!refs.has(currentRender)) {\r\n refs.set(currentRender, []);\r\n }\r\n\r\n const componentRefs = refs.get(currentRender)!;\r\n if (refIndex >= componentRefs.length) {\r\n // Initialize with an object that has a current property\r\n const ref = { current: initial };\r\n componentRefs.push(ref);\r\n stateIndices.set(currentRender, refIndex + 1);\r\n return ref;\r\n }\r\n\r\n const ref = componentRefs[refIndex];\r\n stateIndices.set(currentRender, refIndex + 1);\r\n return ref;\r\n}\r\n\r\n// Add a map to track component DOM nodes\r\nconst componentNodes = new Map<Function, Node>();\r\n\r\nasync function rerender(rendererId: number) {\r\n try {\r\n // Clean up effects\r\n const componentEffects = effects.get(rendererId);\r\n if (componentEffects) {\r\n componentEffects.forEach(effect => {\r\n if (effect.cleanup) effect.cleanup();\r\n });\r\n effects.set(rendererId, []);\r\n }\r\n\r\n if (globalRenderCallback && globalContainer && currentElement) {\r\n await globalRenderCallback(currentElement, globalContainer);\r\n }\r\n } catch (error) {\r\n console.error('Error during rerender:', error);\r\n }\r\n}\r\n\r\n// Add new hook for error boundaries\r\nexport function useErrorBoundary(): [Error | null, () => void] {\r\n const [error, setError] = useState<Error | null>(null);\r\n return [error, () => setError(null)];\r\n}\r\n\r\n// Remove withHooks export\r\n","import type { Component } from './component';\r\n\r\ninterface VNode {\r\n type: string | Function;\r\n props: Record<string, any>;\r\n}\r\n\r\nfunction jsx(type: string | Function, props: any): VNode {\r\n console.log('JSX Transform:', { type, props });\r\n const processedProps = { ...props };\r\n \r\n // Handle children properly\r\n if (arguments.length > 2) {\r\n processedProps.children = Array.prototype.slice.call(arguments, 2);\r\n }\r\n \r\n return { type, props: processedProps };\r\n}\r\n\r\nconst Fragment = ({ children }: { children: any }) => children;\r\n\r\nasync function createElement(vnode: VNode | any): Promise<Node> {\r\n console.log('Creating element from:', vnode);\r\n\r\n // Handle primitives and null\r\n if (vnode == null) {\r\n return document.createTextNode('');\r\n }\r\n \r\n if (typeof vnode === 'boolean') {\r\n return document.createTextNode('');\r\n }\r\n\r\n if (typeof vnode === 'number' || typeof vnode === 'string') {\r\n return document.createTextNode(String(vnode));\r\n }\r\n\r\n // Handle arrays\r\n if (Array.isArray(vnode)) {\r\n const fragment = document.createDocumentFragment();\r\n for (const child of vnode) {\r\n const node = await createElement(child);\r\n fragment.appendChild(node);\r\n }\r\n return fragment;\r\n }\r\n\r\n // Handle VNode\r\n if ('type' in vnode && vnode.props !== undefined) {\r\n const { type, props } = vnode;\r\n \r\n // Handle function components\r\n if (typeof type === 'function') {\r\n try {\r\n const result = await type(props || {});\r\n const node = await createElement(result);\r\n if (node instanceof Element) {\r\n node.setAttribute('data-component-id', type.name || type.toString());\r\n }\r\n return node;\r\n } catch (error) {\r\n console.error('Error rendering component:', error);\r\n return document.createTextNode('');\r\n }\r\n }\r\n\r\n // Create DOM element\r\n const element = document.createElement(type as string);\r\n \r\n // Handle props\r\n for (const [key, value] of Object.entries(props || {})) {\r\n if (key === 'children') continue;\r\n if (key.startsWith('on') && typeof value === 'function') {\r\n const eventName = key.toLowerCase().slice(2);\r\n // Remove existing event listener if any\r\n const existingHandler = (element as any).__events?.[eventName];\r\n if (existingHandler) {\r\n element.removeEventListener(eventName, existingHandler);\r\n }\r\n \r\n // Add new event listener\r\n element.addEventListener(eventName, value as EventListener);\r\n if (!(element as any).__events) {\r\n (element as any).__events = {};\r\n }\r\n (element as any).__events[eventName] = value;\r\n } else if (key === 'style' && typeof value === 'object') {\r\n Object.assign(element.style, value);\r\n } else if (key === 'className') {\r\n element.setAttribute('class', String(value));\r\n } else if (key !== 'key' && key !== 'ref') {\r\n element.setAttribute(key, String(value));\r\n }\r\n }\r\n\r\n // Handle children\r\n const children = props?.children;\r\n if (children != null) {\r\n const childArray = Array.isArray(children) ? children.flat() : [children];\r\n for (const child of childArray) {\r\n const childNode = await createElement(child);\r\n element.appendChild(childNode);\r\n }\r\n }\r\n\r\n return element;\r\n }\r\n\r\n // Handle other objects by converting to string\r\n return document.createTextNode(String(vnode));\r\n}\r\n\r\n// Export named functions and aliases without duplicates\r\nexport {\r\n jsx,\r\n jsx as jsxs,\r\n jsx as jsxDEV,\r\n Fragment,\r\n createElement\r\n};\r\n\r\n// Named exports object\r\nconst jsxRuntime = {\r\n jsx,\r\n jsxs: jsx,\r\n jsxDEV: jsx,\r\n Fragment,\r\n createElement\r\n};\r\n\r\nexport default jsxRuntime;\r\n","\r\n\r\nconst contexts = new Map<symbol, any>();\r\nlet currentRender: Function | null = null;\r\n\r\nexport interface Context<T> {\r\n Provider: (props: { value: T; children?: any }) => any;\r\n Consumer: (props: { children: (value: T) => any }) => any;\r\n _id: symbol;\r\n useSelector: <S>(selector: (state: T) => S) => S;\r\n}\r\n\r\nexport function createContext<T>(defaultValue: T): Context<T> {\r\n const context = {\r\n Provider: ({ value, children }: { value: T, children?: any }) => {\r\n return children;\r\n },\r\n Consumer: ({ children }: { children: (value: T) => any }) => {\r\n return children(defaultValue);\r\n },\r\n _id: Symbol(),\r\n useSelector: <S>(selector: (state: T) => S) => {\r\n return selector(defaultValue);\r\n }\r\n };\r\n\r\n return context;\r\n}\r\n\r\nexport function useContext<T>(context: any): T {\r\n return context;\r\n}\r\n","import { createElement } from './jsx-runtime';\r\nimport { prepareRender, finishRender, setRenderCallback } from './hooks';\r\nimport { batchUpdates } from './batch';\r\n\r\nlet isHydrating = false;\r\n\r\nexport async function hydrate(element: any, container: HTMLElement) {\r\n isHydrating = true;\r\n try {\r\n await render(element, container);\r\n } finally {\r\n isHydrating = false;\r\n }\r\n}\r\n\r\nexport async function render(element: any, container: HTMLElement) {\r\n console.log('Rendering to:', container.id);\r\n \r\n batchUpdates(async () => {\r\n const rendererId = prepareRender();\r\n try {\r\n setRenderCallback(render, element, container);\r\n const domNode = await createElement(element);\r\n \r\n if (!isHydrating) {\r\n container.innerHTML = '';\r\n }\r\n container.appendChild(domNode);\r\n \r\n } finally {\r\n finishRender();\r\n }\r\n });\r\n}\r\n","export interface ScriptConfig {\r\n src: string;\r\n defer?: boolean;\r\n async?: boolean;\r\n type?: string;\r\n}\r\n\r\nexport interface TemplateOptions {\r\n title: string;\r\n description?: string;\r\n scripts?: (string | ScriptConfig)[];\r\n styles?: string[];\r\n initialState?: any;\r\n meta?: Record<string, string>;\r\n bodyAttrs?: Record<string, string>;\r\n htmlAttrs?: Record<string, string>;\r\n}\r\n\r\nexport function defaultTemplate(content: string, options: TemplateOptions): string {\r\n const {\r\n title,\r\n description = '',\r\n scripts = [],\r\n styles = [],\r\n initialState = {},\r\n meta = {},\r\n bodyAttrs = {},\r\n htmlAttrs = { lang: 'en' }\r\n } = options;\r\n\r\n const htmlAttributes = Object.entries(htmlAttrs)\r\n .map(([key, value]) => `${key}=\"${value}\"`)\r\n .join(' ');\r\n\r\n const bodyAttributes = Object.entries(bodyAttrs)\r\n .map(([key, value]) => `${key}=\"${value}\"`)\r\n .join(' ');\r\n\r\n const metaTags = Object.entries(meta)\r\n .map(([name, content]) => ` <meta name=\"${name}\" content=\"${content}\">`)\r\n .join('\\n');\r\n\r\n const scriptTags = scripts.map(script => {\r\n if (typeof script === 'string') {\r\n return ` <script src=\"${script}\" defer></script>`;\r\n }\r\n const { src, defer = true, async = false, type } = script;\r\n return ` <script src=\"${src}\"${defer ? ' defer' : ''}${async ? ' async' : ''}${type ? ` type=\"${type}\"` : ''}></script>`;\r\n }).join('\\n');\r\n\r\n return `<!DOCTYPE html>\r\n<html ${htmlAttributes}>\r\n <head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n ${description ? `<meta name=\"description\" content=\"${description}\">\\n` : ''}${metaTags}\r\n <title>${title}</title>\r\n${styles.map(href => ` <link rel=\"stylesheet\" href=\"${href}\">`).join('\\n')}\r\n <script>\r\n window.__INITIAL_STATE__ = ${JSON.stringify(initialState)};\r\n </script>\r\n </head>\r\n <body ${bodyAttributes}>\r\n <div id=\"root\">${content}</div>\r\n${scriptTags}\r\n </body>\r\n</html>`;\r\n}\r\n","import { VNode } from './types';\r\nimport { defaultTemplate, TemplateOptions, ScriptConfig } from './templates/default';\r\n\r\n// Track component instances during SSR\r\nconst componentStack: any[] = [];\r\nlet currentComponent: any = null;\r\n\r\nexport async function renderToString(\r\n element: JSX.Element,\r\n options: Partial<TemplateOptions> = {}\r\n): Promise<string> {\r\n componentStack.length = 0;\r\n currentComponent = null;\r\n\r\n try {\r\n // Render the app to string\r\n const content = await renderNodeToString(element);\r\n\r\n const processedScripts = options.scripts?.map(script => \r\n typeof script === 'string' \r\n ? { src: script, defer: true } as ScriptConfig\r\n : { ...script, defer: script.defer ?? true }\r\n );\r\n\r\n // Generate the full HTML document\r\n return defaultTemplate(content, {\r\n title: 'Frontend Hamroun App',\r\n ...options,\r\n scripts: processedScripts\r\n });\r\n } catch (error) {\r\n console.error('Server rendering error:', error);\r\n // Return error page in development\r\n if (process.env.NODE_ENV === 'development') {\r\n const errorMessage = error instanceof Error \r\n ? error.stack || error.message \r\n : String(error);\r\n \r\n return `\r\n <!DOCTYPE html>\r\n <html>\r\n <head><title>Rendering Error</title></head>\r\n <body>\r\n <h1>Server Rendering Error</h1>\r\n <pre>${escapeHtml(errorMessage)}</pre>\r\n </body>\r\n </html>\r\n `;\r\n }\r\n return '';\r\n } finally {\r\n // Cleanup\r\n componentStack.length = 0;\r\n currentComponent = null;\r\n }\r\n}\r\n\r\nasync function renderNodeToString(node: VNode | any): Promise<string> {\r\n // Handle null and boolean\r\n if (node == null || typeof node === 'boolean') return '';\r\n\r\n // Handle primitives\r\n if (typeof node === 'number' || typeof node === 'string') {\r\n return escapeHtml(String(node));\r\n }\r\n\r\n // Handle arrays\r\n if (Array.isArray(node)) {\r\n const results = await Promise.all(\r\n node.map(child => renderNodeToString(child))\r\n );\r\n return results.join('');\r\n }\r\n\r\n // Handle functional components\r\n if (typeof node === 'function') {\r\n const prevComponent = currentComponent;\r\n currentComponent = { type: node.name || 'Anonymous' };\r\n componentStack.push(currentComponent);\r\n\r\n try {\r\n const result = await node({});\r\n return renderNodeToString(result);\r\n } finally {\r\n componentStack.pop();\r\n currentComponent = prevComponent;\r\n }\r\n }\r\n\r\n // Handle VNodes\r\n if (node.type) {\r\n if (typeof node.type === 'function') {\r\n const prevComponent = currentComponent;\r\n currentComponent = {\r\n type: node.type.name || 'Anonymous',\r\n props: node.props || {}\r\n };\r\n componentStack.push(currentComponent);\r\n\r\n try {\r\n const result = await node.type(node.props || {});\r\n return renderNodeToString(result);\r\n } finally {\r\n componentStack.pop();\r\n currentComponent = prevComponent;\r\n }\r\n }\r\n\r\n // Handle HTML elements\r\n let html = `<${node.type}`;\r\n \r\n // Add props\r\n if (node.props) {\r\n html += renderProps(node.props);\r\n }\r\n\r\n // Self-closing tags\r\n const voidElements = new Set([\r\n 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',\r\n 'link', 'meta', 'param', 'source', 'track', 'wbr'\r\n ]);\r\n\r\n if (voidElements.has(node.type)) {\r\n return html + '/>';\r\n }\r\n\r\n html += '>';\r\n\r\n // Render children\r\n if (node.props?.children) {\r\n const children = Array.isArray(node.props.children)\r\n ? node.props.children\r\n : [node.props.children];\r\n\r\n for (const child of children) {\r\n html += await renderNodeToString(child);\r\n }\r\n }\r\n\r\n return html + `</${node.type}>`;\r\n }\r\n\r\n // Handle other cases\r\n return '';\r\n}\r\n\r\nfunction renderProps(props: Record<string, any>): string {\r\n let html = '';\r\n\r\n for (const [key, value] of Object.entries(props)) {\r\n // Skip special props\r\n if (key === 'children' || key === 'key' || key === 'ref') continue;\r\n\r\n // Handle className\r\n if (key === 'className') {\r\n if (value) html += ` class=\"${escapeHtml(String(value))}\"`;\r\n continue;\r\n }\r\n\r\n // Handle style objects\r\n if (key === 'style' && typeof value === 'object' && value !== null) {\r\n html += ` style=\"${styleToString(value)}\"`;\r\n continue;\r\n }\r\n\r\n // Skip event handlers\r\n if (key.startsWith('on')) continue;\r\n\r\n // Handle boolean attributes\r\n if (typeof value === 'boolean') {\r\n if (value) html += ` ${key}`;\r\n continue;\r\n }\r\n\r\n // Handle other attributes\r\n if (value != null) {\r\n html += ` ${key}=\"${escapeHtml(String(value))}\"`;\r\n }\r\n }\r\n\r\n return html;\r\n}\r\n\r\nfunction escapeHtml(str: string): string {\r\n return str\r\n .replace(/&/g, '&amp;')\r\n .replace(/</g, '&lt;')\r\n .replace(/>/g, '&gt;')\r\n .replace(/\"/g, '&quot;')\r\n .replace(/'/g, '&#039;');\r\n}\r\n\r\nfunction styleToString(style: Record<string, any>): string {\r\n return Object.entries(style)\r\n .map(([key, value]) => `${hyphenate(key)}: ${value}`)\r\n .join('; ');\r\n}\r\n\r\n// Convert camelCase to kebab-case\r\nfunction hyphenate(str: string): string {\r\n return str.replace(/[A-Z]/g, m => '-' + m.toLowerCase());\r\n}\r\n","import { useState, useEffect } from './hooks';\r\n\r\ninterface RouterState {\r\n pathname: string;\r\n search: string;\r\n hash: string;\r\n params: Record<string, string>;\r\n}\r\n\r\ninterface RouterOptions {\r\n replace?: boolean;\r\n scroll?: boolean;\r\n}\r\n\r\nlet currentState: RouterState = {\r\n pathname: typeof window !== 'undefined' ? window.location.pathname : '/',\r\n search: typeof window !== 'undefined' ? window.location.search : '',\r\n hash: typeof window !== 'undefined' ? window.location.hash : '',\r\n params: {}\r\n};\r\n\r\nconst listeners = new Set<(state: RouterState) => void>();\r\n\r\n// Parse route pattern and extract params\r\nfunction matchRoute(pattern: string, pathname: string): Record<string, string> | null {\r\n const paramNames: string[] = [];\r\n const regexPattern = pattern.replace(/:([^/]+)/g, (_, name) => {\r\n paramNames.push(name);\r\n return '([^/]+)';\r\n });\r\n\r\n const match = pathname.match(new RegExp(`^${regexPattern}$`));\r\n if (!match) return null;\r\n\r\n const params: Record<string, string> = {};\r\n paramNames.forEach((name, i) => {\r\n params[name] = match[i + 1];\r\n });\r\n\r\n return params;\r\n}\r\n\r\nfunction updateState(newPath: string, options: RouterOptions = {}) {\r\n const url = new URL(newPath, window.location.origin);\r\n const newState: RouterState = {\r\n pathname: url.pathname,\r\n search: url.search,\r\n hash: url.hash,\r\n params: {}\r\n };\r\n\r\n if (options.replace) {\r\n window.history.replaceState(newState, '', url.toString());\r\n } else {\r\n window.history.pushState(newState, '', url.toString());\r\n }\r\n\r\n currentState = newState;\r\n listeners.forEach(listener => listener(newState));\r\n\r\n if (options.scroll) {\r\n window.scrollTo(0, 0);\r\n }\r\n}\r\n\r\nexport function navigate(to: string, options: RouterOptions = {}) {\r\n if (typeof window === 'undefined') return;\r\n updateState(to, options);\r\n}\r\n\r\nexport function useRouter() {\r\n const [state, setState] = useState<RouterState>(currentState);\r\n\r\n useEffect(() => {\r\n const handleRouteChange = (newState: RouterState) => {\r\n setState(newState);\r\n };\r\n\r\n const handlePopState = () => {\r\n currentState = {\r\n pathname: window.location.pathname,\r\n search: window.location.search,\r\n hash: window.location.hash,\r\n params: {}\r\n };\r\n setState(currentState);\r\n };\r\n\r\n listeners.add(handleRouteChange);\r\n window.addEventListener('popstate', handlePopState);\r\n\r\n return () => {\r\n listeners.delete(handleRouteChange);\r\n window.removeEventListener('popstate', handlePopState);\r\n };\r\n }, []);\r\n\r\n return {\r\n ...state,\r\n push: (to: string, options?: RouterOptions) => navigate(to, options),\r\n replace: (to: string, options?: RouterOptions) => navigate(to, { ...options, replace: true }),\r\n back: () => window.history.back(),\r\n forward: () => window.history.forward()\r\n };\r\n}\r\n\r\nexport function useRoute(pattern: string) {\r\n const { pathname } = useRouter();\r\n const [params, setParams] = useState<Record<string, string>>({});\r\n const [isMatch, setIsMatch] = useState(false);\r\n\r\n useEffect(() => {\r\n const matchedParams = matchRoute(pattern, pathname);\r\n setIsMatch(!!matchedParams);\r\n setParams(matchedParams || {});\r\n }, [pattern, pathname]);\r\n\r\n return { isMatch, params };\r\n}\r\n\r\nexport function useParams<T extends Record<string, string>>() {\r\n const router = useRouter();\r\n return router.params as T;\r\n}\r\n\r\nexport function useSearchParams() {\r\n const { search } = useRouter();\r\n return new URLSearchParams(search);\r\n}\r\n","import { navigate } from './router';\r\n\r\ninterface LinkProps {\r\n href: string;\r\n children?: any;\r\n replace?: boolean;\r\n className?: string;\r\n style?: Record<string, string>;\r\n [key: string]: any;\r\n}\r\n\r\nexport function Link({ \r\n href, \r\n children, \r\n replace = false, \r\n className,\r\n style,\r\n ...rest \r\n}: LinkProps) {\r\n const handleClick = (e: MouseEvent) => {\r\n e.preventDefault();\r\n navigate(href, { replace });\r\n };\r\n\r\n return {\r\n type: 'a',\r\n props: {\r\n href,\r\n onClick: handleClick,\r\n className,\r\n style,\r\n ...rest,\r\n children\r\n }\r\n };\r\n}\r\n"],"names":["index","state","setState","ref","content"],"mappings":"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"}
@@ -1,7 +1,13 @@
1
+ export interface ScriptConfig {
2
+ src: string;
3
+ defer?: boolean;
4
+ async?: boolean;
5
+ type?: string;
6
+ }
1
7
  export interface TemplateOptions {
2
8
  title: string;
3
9
  description?: string;
4
- scripts?: string[];
10
+ scripts?: (string | ScriptConfig)[];
5
11
  styles?: string[];
6
12
  initialState?: any;
7
13
  meta?: Record<string, string>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  {
3
3
  "name": "frontend-hamroun",
4
- "version": "1.1.50",
4
+ "version": "1.1.52",
5
5
  "description": "A lightweight frontend framework with hooks and virtual DOM",
6
6
  "type": "module",
7
7
  "main": "./dist/index.js",
@@ -13,7 +13,7 @@
13
13
  },
14
14
  "dependencies": {
15
15
  "express": "^4.18.2",
16
- "frontend-hamroun": "link:../.."
16
+ "frontend-hamroun": "latest"
17
17
  },
18
18
  "devDependencies": {
19
19
  "@types/express": "^4.17.17",
@@ -0,0 +1,49 @@
1
+ :root {
2
+ --bg-color: #ffffff;
3
+ --text-color: #000000;
4
+ }
5
+
6
+ [data-theme="dark"] {
7
+ --bg-color: #1a1a1a;
8
+ --text-color: #ffffff;
9
+ }
10
+
11
+ body {
12
+ background-color: var(--bg-color);
13
+ color: var(--text-color);
14
+ transition: background-color 0.3s, color 0.3s;
15
+ }
16
+
17
+ nav {
18
+ padding: 1rem;
19
+ display: flex;
20
+ gap: 1rem;
21
+ }
22
+
23
+ nav a {
24
+ color: var(--text-color);
25
+ text-decoration: none;
26
+ }
27
+
28
+ nav a:hover {
29
+ text-decoration: underline;
30
+ }
31
+
32
+ main {
33
+ padding: 2rem;
34
+ max-width: 800px;
35
+ margin: 0 auto;
36
+ }
37
+
38
+ .app {
39
+ min-height: 100vh;
40
+ display: flex;
41
+ flex-direction: column;
42
+ }
43
+
44
+ footer {
45
+ margin-top: auto;
46
+ padding: 1rem;
47
+ text-align: center;
48
+ opacity: 0.7;
49
+ }
@@ -1,4 +1,4 @@
1
- import { useState, useEffect, Link, useRouter } from 'frontend-hamroun';
1
+ import { useState, useEffect, Link, useRouter, createContext, useContext } from 'frontend-hamroun';
2
2
 
3
3
  interface AppProps {
4
4
  url: string;
@@ -8,27 +8,50 @@ interface AppProps {
8
8
  };
9
9
  }
10
10
 
11
- export function App({ url, user, settings }: AppProps) {
12
- const [theme, setTheme] = useState(settings.theme);
13
- const router = useRouter();
14
-
15
- useEffect(() => {
16
- document.documentElement.dataset.theme = theme;
17
- }, [theme]);
11
+ // Create theme context
12
+ const ThemeContext = createContext<{
13
+ theme: string;
14
+ setTheme: (theme: string) => void;
15
+ }>({ theme: 'light', setTheme: () => {} });
18
16
 
17
+ // Layout component
18
+ function Layout({ children }: { children: any }) {
19
+ const { theme, setTheme } = useContext(ThemeContext);
20
+ const router = useRouter();
21
+
19
22
  return (
20
- <div className="app">
23
+ <div className="app" data-theme={theme}>
21
24
  <header>
22
25
  <nav>
23
26
  <Link href="/">Home</Link>
24
27
  <Link href="/about">About</Link>
25
- <button onClick={() => setTheme(t => t === 'light' ? 'dark' : 'light')}>
28
+ <Link href="/users">Users</Link>
29
+ <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
26
30
  {theme === 'light' ? '🌙' : '☀️'}
27
31
  </button>
28
32
  </nav>
29
33
  </header>
30
-
31
34
  <main>
35
+ {children}
36
+ </main>
37
+ <footer>
38
+ <p>Current route: {router.pathname}</p>
39
+ </footer>
40
+ </div>
41
+ );
42
+ }
43
+
44
+ export function App({ url, user, settings }: AppProps) {
45
+ const [theme, setTheme] = useState(settings.theme);
46
+ const router = useRouter();
47
+
48
+ useEffect(() => {
49
+ document.documentElement.dataset.theme = theme;
50
+ }, [theme]);
51
+
52
+ return (
53
+ <ThemeContext.Provider value={{ theme, setTheme }}>
54
+ <Layout>
32
55
  {router.pathname === '/' && (
33
56
  <section>
34
57
  <h1>Welcome</h1>
@@ -46,7 +69,42 @@ export function App({ url, user, settings }: AppProps) {
46
69
  <p>This is a server-side rendered app.</p>
47
70
  </section>
48
71
  )}
49
- </main>
50
- </div>
72
+
73
+ {router.pathname === '/users' && (
74
+ <section>
75
+ <h1>Users</h1>
76
+ <UserList />
77
+ </section>
78
+ )}
79
+ </Layout>
80
+ </ThemeContext.Provider>
81
+ );
82
+ }
83
+
84
+ // Add new UserList component
85
+ function UserList() {
86
+ const [users, setUsers] = useState<any[]>([]);
87
+ const [loading, setLoading] = useState(true);
88
+
89
+ useEffect(() => {
90
+ fetch('https://jsonplaceholder.typicode.com/users')
91
+ .then(res => res.json())
92
+ .then(data => {
93
+ setUsers(data);
94
+ setLoading(false);
95
+ });
96
+ }, []);
97
+
98
+ if (loading) return <div>Loading users...</div>;
99
+
100
+ return (
101
+ <ul>
102
+ {users.map(user => (
103
+ <li key={user.id}>
104
+ <h3>{user.name}</h3>
105
+ <p>{user.email}</p>
106
+ </li>
107
+ ))}
108
+ </ul>
51
109
  );
52
110
  }
@@ -10,36 +10,50 @@ const app = express();
10
10
  // Static files
11
11
  app.use(express.static(path.join(__dirname, 'dist')));
12
12
 
13
+ // Add API endpoints
14
+ app.get('/api/users', async (_req, res) => {
15
+ try {
16
+ const response = await fetch('https://jsonplaceholder.typicode.com/users');
17
+ const users = await response.json();
18
+ res.json(users);
19
+ } catch (error) {
20
+ res.status(500).json({ error: 'Failed to fetch users' });
21
+ }
22
+ });
23
+
13
24
  app.get('*', async (req, res) => {
14
25
  try {
15
- // Create initial state
26
+ // Get initial state based on route
16
27
  const initialState = {
17
28
  url: req.url,
18
29
  user: null,
19
30
  settings: { theme: 'light' }
20
31
  };
21
32
 
22
- // Use renderToString with proper options
33
+ // Add dynamic meta tags based on route
34
+ const meta: Record<string, string> = {
35
+ 'viewport': 'width=device-width, initial-scale=1.0',
36
+ 'theme-color': '#ffffff',
37
+ };
38
+
39
+ if (req.url === '/users') {
40
+ meta['description'] = 'View all users';
41
+ meta['og:title'] = 'Users List';
42
+ }
43
+
23
44
  const html = await renderToString(<App {...initialState} />, {
24
- title: 'SSR Demo',
25
- description: 'Server-side rendered app with Frontend Hamroun',
26
- scripts: [
27
- '/client.js' // Client entry point
28
- ],
29
- styles: ['/styles.css'],
45
+ title: `SSR Demo${req.url === '/' ? '' : ` - ${req.url.slice(1)}`}`,
46
+ description: 'Server-side rendered application',
47
+ scripts: ['/assets/client.js'],
48
+ styles: ['/assets/styles.css'],
30
49
  initialState,
31
- meta: {
32
- 'viewport': 'width=device-width, initial-scale=1.0',
33
- 'theme-color': '#ffffff',
34
- 'og:title': 'SSR Demo',
35
- 'og:description': 'A server-rendered application'
36
- },
37
- htmlAttrs: {
38
- lang: 'en',
39
- 'data-theme': initialState.settings.theme
50
+ meta,
51
+ bodyAttrs: {
52
+ 'data-theme': initialState.settings.theme,
53
+ 'data-route': req.url
40
54
  }
41
55
  });
42
-
56
+
43
57
  res.send(html);
44
58
  } catch (error) {
45
59
  console.error('SSR Error:', error);