mono-jsx 0.6.5 → 0.6.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -150,13 +150,11 @@ mono-jsx supports [pseudo classes](https://developer.mozilla.org/en-US/docs/Web/
150
150
  ```tsx
151
151
  <a
152
152
  style={{
153
- display: "inline-flex",
154
- gap: "0.5em",
155
153
  color: "black",
156
154
  "::after": { content: "↩️" },
157
155
  ":hover": { textDecoration: "underline" },
158
156
  "@media (prefers-color-scheme: dark)": { color: "white" },
159
- "& .icon": { width: "1em", height: "1em" },
157
+ "& .icon": { width: "1em", height: "1em", marginRight: "0.5em" },
160
158
  }}
161
159
  >
162
160
  <img class="icon" src="link.png" />
@@ -363,7 +361,7 @@ interface AppSignals {
363
361
  function Header(this: FC<{}, AppSignals>) {
364
362
  return (
365
363
  <header>
366
- <h1 style={{ color: this.app.themeColor }}>Welcome to mono-jsx!</h1>
364
+ <h1 style={this.computed(() => ({ color: this.app.themeColor }))}>Welcome to mono-jsx!</h1>
367
365
  </header>
368
366
  )
369
367
  }
@@ -371,7 +369,7 @@ function Header(this: FC<{}, AppSignals>) {
371
369
  function Footer(this: FC<{}, AppSignals>) {
372
370
  return (
373
371
  <footer>
374
- <p style={{ color: this.app.themeColor }}>(c) 2025 mono-jsx.</p>
372
+ <p style={this.computed(() => ({ color: this.app.themeColor }))}>(c) 2025 mono-jsx.</p>
375
373
  </footer>
376
374
  )
377
375
  }
@@ -838,7 +836,7 @@ export default {
838
836
  }
839
837
  ```
840
838
 
841
- ## Using Router(SPA Mode)
839
+ ## Using Router(SPA)
842
840
 
843
841
  mono-jsx provides a built-in `<router>` element that allows your app to render components based on the current URL. On client side, it listens all `click` events on `<a>` elements and asynchronously fetches the route component without reloading the entire page.
844
842
 
@@ -855,11 +853,13 @@ const routes = {
855
853
  export default {
856
854
  fetch: (req) => (
857
855
  <html request={req} routes={routes}>
858
- <nav>
859
- <a href="/">Home</a>
860
- <a href="/about">About</a>
861
- <a href="/blog">Blog</a>
862
- </nav>
856
+ <header>
857
+ <nav>
858
+ <a href="/">Home</a>
859
+ <a href="/about">About</a>
860
+ <a href="/blog">Blog</a>
861
+ </nav>
862
+ </header>
863
863
  <router />
864
864
  </html>
865
865
  )
@@ -872,10 +872,12 @@ mono-jsx router requires [URLPattern](https://developer.mozilla.org/en-US/docs/W
872
872
  - ✅ Cloudflare Workers
873
873
  - ✅ Nodejs (>= 24)
874
874
 
875
- For Bun users, mono-jsx provides a `buildRoutes` function that uses Bun's built-in server routing:
875
+ For Bun users, mono-jsx provides a `monoRoutes` function that uses Bun's built-in routing:
876
876
 
877
877
  ```tsx
878
- import { buildRoutes } from "mono-jsx"
878
+ // bun app.tsx
879
+
880
+ import { monoRoutes } from "mono-jsx"
879
881
 
880
882
  const routes = {
881
883
  "/": Home,
@@ -884,18 +886,13 @@ const routes = {
884
886
  "/post/:id": Post,
885
887
  }
886
888
 
887
- Bun.serve({
888
- routes: buildRoutes((req) => (
889
- <html request={req} routes={routes}>
890
- <nav>
891
- <a href="/">Home</a>
892
- <a href="/about">About</a>
893
- <a href="/blog">Blog</a>
894
- </nav>
889
+ export default {
890
+ routes: monoRoutes(routes, (request) => (
891
+ <html request={request}>
895
892
  <router />
896
893
  </html>
897
894
  ))
898
- })
895
+ }
899
896
  ```
900
897
 
901
898
  ### Using Route `params`
@@ -912,22 +909,18 @@ function Post(this: FC) {
912
909
  }
913
910
  ```
914
911
 
915
- ### Navigation between Pages
912
+ ### Using DB/Storage in Route Components
916
913
 
917
- To navigate between pages, you can use `<a>` elements with `href` attributes that match the defined routes. The router will intercept the click events of these links and fetch the corresponding route component without reloading the page:
914
+ Route components are always rendered on server-side, you can use any database or storage API to fetch data in your route components.
918
915
 
919
916
  ```tsx
920
- function App() {
921
- export default {
922
- fetch: (req) => (
923
- <html request={req} routes={routes}>
924
- <nav>
925
- <a href="/">Home</a>
926
- <a href="/about">About</a>
927
- <a href="/blog">Blog</a>
928
- </nav>
929
- <router />
930
- </html>
917
+ async function Post(this: FC) {
918
+ const post = await sql`SELECT * FROM posts WHERE id = ${ this.request.params!.id }`
919
+ return (
920
+ <article>
921
+ <h2>{post.title}<h2>
922
+ <div>html`${post.content}`</div>
923
+ </article>
931
924
  )
932
925
  }
933
926
  ```
@@ -940,35 +933,19 @@ Links under the `<nav>` element will be treated as navigation links by the route
940
933
  export default {
941
934
  fetch: (req) => (
942
935
  <html request={req} routes={routes}>
943
- <nav style={{ "& a.active": { fontWeight: "bold" } }} data-active-class="active">
944
- <a href="/">Home</a>
945
- <a href="/about">About</a>
946
- <a href="/blog">Blog</a>
947
- </nav>
936
+ <header>
937
+ <nav style={{ "& a.active": { fontWeight: "bold" } }} data-active-class="active">
938
+ <a href="/">Home</a>
939
+ <a href="/about">About</a>
940
+ <a href="/blog">Blog</a>
941
+ </nav>
942
+ </header>
948
943
  <router />
949
944
  </html>
950
945
  )
951
946
  }
952
947
  ```
953
948
 
954
- ### Using DB/Storage in Route Components
955
-
956
- Route components are always rendered on server-side, you can use any database or storage API to fetch data in your route components.
957
-
958
- ```tsx
959
- async function Post(this: FC) {
960
- const post = await sql`SELECT * FROM posts WHERE id = ${ this.request.params!.id }`
961
- return (
962
- <article>
963
- <h2>{post.title}<h2>
964
- <section>
965
- {html(post.content)}
966
- </section>
967
- </article>
968
- )
969
- }
970
- ```
971
-
972
949
  ### Fallback(404)
973
950
 
974
951
  You can add fallback(404) content to the `<router>` element as children, which will be displayed when no route matches the current URL.
package/index.mjs CHANGED
@@ -1,8 +1,4 @@
1
1
  // index.ts
2
- function buildRoutes(handler) {
3
- const { routes = {} } = handler(Symbol.for("mono.peek"));
4
- return monoRoutes(routes, handler);
5
- }
6
2
  function monoRoutes(routes, handler) {
7
3
  const handlers = {};
8
4
  for (const [path, fc] of Object.entries(routes)) {
@@ -14,6 +10,5 @@ function monoRoutes(routes, handler) {
14
10
  return handlers;
15
11
  }
16
12
  export {
17
- buildRoutes,
18
13
  monoRoutes
19
14
  };
package/jsx-runtime.mjs CHANGED
@@ -1,6 +1,11 @@
1
- // render.ts
2
- import { F_CX, F_EVENT, F_LAZY, F_ROUTER, F_SIGNALS, F_STYLE, F_SUSPENSE } from "./runtime/index.mjs";
3
- import { CX_JS, EVENT_JS, LAZY_JS, ROUTER_JS, SIGNALS_JS, STYLE_JS, SUSPENSE_JS } from "./runtime/index.mjs";
1
+ // runtime/index.ts
2
+ var CX_JS = `{var i=new Set("animation-iteration-count,aspect-ratio,border-image-outset,border-image-slice,border-image-width,box-flex-group,box-flex,box-ordinal-group,column-count,columns,fill-opacity,flex-grow,flex-negative,flex-order,flex-positive,flex-shrink,flex,flood-opacity,font-weight,grid-area,grid-column-end,grid-column-span,grid-column-start,grid-column,grid-row-end,grid-row-span,grid-row-start,grid-row,line-clamp,line-height,opacity,order,orphans,stop-opacity,stroke-dasharray,stroke-dashoffset,stroke-miterlimit,stroke-opacity,stroke-width,tab-size,widows,z-index,zoom".split(",")),r=e=>typeof e=="string",o=e=>typeof e=="object"&&e!==null;var n=e=>r(e)?e:o(e)?Array.isArray(e)?e.map(n).filter(Boolean).join(" "):Object.entries(e).filter(([,t])=>!!t).map(([t])=>t).join(" "):"";window.$cx=n;}`;
3
+ var STYLE_JS = `{var a=new Set("animation-iteration-count,aspect-ratio,border-image-outset,border-image-slice,border-image-width,box-flex-group,box-flex,box-ordinal-group,column-count,columns,fill-opacity,flex-grow,flex-negative,flex-order,flex-positive,flex-shrink,flex,flood-opacity,font-weight,grid-area,grid-column-end,grid-column-span,grid-column-start,grid-column,grid-row-end,grid-row-span,grid-row-start,grid-row,line-clamp,line-height,opacity,order,orphans,stop-opacity,stroke-dasharray,stroke-dashoffset,stroke-miterlimit,stroke-opacity,stroke-width,tab-size,widows,z-index,zoom".split(",")),l=e=>typeof e=="string",u=e=>typeof e=="object"&&e!==null,p=e=>e.replace(/[a-z][A-Z]/g,n=>n.charAt(0)+"-"+n.charAt(1).toLowerCase());var f=e=>{let n=[],r=[],t=new d;for(let[o,i]of Object.entries(e))switch(o.charCodeAt(0)){case 58:r.push(null,o+"{"+c(i)+"}");break;case 64:r.push(o+"{",null,"{"+c(i)+"}}");break;case 38:r.push(null,o.slice(1)+"{"+c(i)+"}");break;default:n.push([o,i])}return n.length>0&&(t.inline=c(n)),r.length>0&&(t.css=r),t},g=(e,n)=>{let{inline:r,css:t}=f(n);if(t){let o="data-css-",i="["+o+(Date.now()+Math.random()).toString(36).replace(".","")+"]";document.head.appendChild(document.createElement("style")).textContent=(r?i+"{"+r+"}":"")+t.map(s=>s===null?i:s).join(""),e.getAttributeNames().forEach(s=>s.startsWith(o)&&e.removeAttribute(s)),e.setAttribute(i.slice(1,-1),"")}else r&&e.setAttribute("style",r)},c=e=>{if(u(e)){let n="";for(let[r,t]of Array.isArray(e)?e:Object.entries(e))if(l(t)||typeof t=="number"){let o=p(r),i=typeof t=="number"?a.has(o)?""+t:t+"px":""+t;n+=(n?";":"")+o+":"+(o==="content"?JSON.stringify(i):i)}return n}return""},d=(()=>{function e(){}return e.prototype=Object.freeze(Object.create(null)),e})();window.$applyStyle=g;}`;
4
+ var EVENT_JS = `{var w=window;w.$emit=(e,f,s)=>f.call(w.$signals?.(s)??e.target,e.type==="mount"?e.target:e);w.$onsubmit=(e,f,s)=>{e.preventDefault();f.call(w.$signals?.(s)??e.target,new FormData(e.target),e)};}`;
5
+ var SIGNALS_JS = `{let p;const h=window,E=new Map,b=new Map,d=e=>b.get(e)??b.set(e,S(e)).get(e),u=(e,t)=>e.getAttribute(t),y=(e,t,r)=>e.setAttribute(t,r),M=(e,t)=>e.replaceChildren(...t),v=()=>Object.create(null),S=e=>{const t=v(),r=(c,l)=>{t[c]=l},n=new Map,o=(c,l)=>{let i=n.get(c);return i||(i=new Set,n.set(c,i)),i.add(l),()=>{i.delete(l),i.size===0&&n.delete(c)}},s=new Proxy(v(),{get:(c,l)=>document.querySelector("[data-ref='"+e+":"+l+"']")});return new Proxy(t,{get:(c,l,i)=>{switch(l){case"$init":return r;case"$watch":return o;case"app":return d(0);case"refs":return s;default:return p?.(e,l),Reflect.get(c,l,i)}},set:(c,l,i,a)=>{if(i!==Reflect.get(c,l,a)){const f=n.get(l);return f&&queueMicrotask(()=>f.forEach(g=>g())),Reflect.set(c,l,i,a)}return!1}})},k=(e,t,r)=>{if(t==="toggle"){let n;return()=>{if(!n){const o=e.firstElementChild;o&&o.tagName==="TEMPLATE"&&o.hasAttribute("m-slot")?n=[...o.content.childNodes]:n=[...e.childNodes]}M(e,r()?n:[])}}if(t==="switch"){let n,o=u(e,"match"),s,c,l=i=>s.get(i)??s.set(i,[]).get(i);return()=>{if(!s){s=new Map,c=[];for(const i of e.childNodes)if(i.nodeType===1&&i.tagName==="TEMPLATE"&&i.hasAttribute("m-slot")){for(const a of i.content.childNodes)a.nodeType===1&&a.hasAttribute("slot")?l(u(a,"slot")).push(a):c.push(a);i.remove()}else o?l(o).push(i):c.push(i)}n=""+r(),M(e,s.has(n)?s.get(n):c)}}if(t&&t.length>2&&t.startsWith("[")&&t.endsWith("]")){let n=t.slice(1,-1),o=e.parentElement;return o.tagName==="M-GROUP"&&(o=o.previousElementSibling),()=>{const s=r();s===!1||s===null||s===void 0?o.removeAttribute(n):typeof s=="object"&&s!==null&&(n==="class"||n==="style"||n==="props")?n==="class"?y(o,n,$cx(s)):n==="style"?$applyStyle(o,s):y(o,n,JSON.stringify(s)):y(o,n,s===!0?"":s)}}return()=>e.textContent=""+r()},N=e=>{const t=e.indexOf(":");return t>0?[Number(e.slice(0,t)),e.slice(t+1)]:null},w=async e=>{const t=e();return t!==void 0?t:(await new Promise(r=>setTimeout(r,0)),w(e))},T=(e,t)=>customElements.define(e,class extends HTMLElement{disposes=[];connectedCallback(){t(this)}disconnectedCallback(){this.disposes.forEach(r=>r()),this.disposes.length=0}});T("m-signal",e=>{const t=d(Number(u(e,"scope"))),r=u(e,"key");if(r)e.disposes.push(t.$watch(r,k(e,u(e,"mode"),()=>t[r])));else{const n=Number(u(e,"computed"));w(()=>E.get(n)).then(([o,s])=>{const c=k(e,u(e,"mode"),o.bind(t));s.forEach(l=>{const[i,a]=N(l);e.disposes.push(d(i).$watch(a,c))})})}}),T("m-effect",e=>{const{disposes:t}=e,r=Number(u(e,"scope")),n=Number(u(e,"n")),o=new Array(n);t.push(()=>{o.forEach(s=>typeof s=="function"&&s()),o.length=0});for(let s=0;s<n;s++){const c="$ME_"+r+"_"+s;w(()=>h[c]).then(l=>{const i=[],a=d(r),f=()=>{o[s]=l.call(a)};p=(g,m)=>i.push([g,m]),f(),p=void 0;for(const[g,m]of i)t.push(d(g).$watch(m,f))},()=>{})}}),h.$signals=e=>e!==void 0?d(e):void 0,h.$MS=(e,t)=>{const[r,n]=N(e);d(r).$init(n,t)},h.$MC=(e,t,r)=>{E.set(e,[t,r])},h.$patch=(e,...t)=>{for(const[r,...n]of t){const o=n.pop();let s=e;for(const c of n)s=s[c];s[o]=r}return e};}`;
6
+ var SUSPENSE_JS = `{const s=new Map,i=e=>e.getAttribute("chunk-id"),l=(e,t)=>customElements.define(e,class extends HTMLElement{connectedCallback(){t(this)}});l("m-portal",e=>{s.set(i(e),e)}),l("m-chunk",e=>{setTimeout(()=>{const t=e.firstChild?.content.childNodes,o=i(e),n=s.get(o);n&&(e.hasAttribute("next")?n.before(...t):(s.delete(o),e.hasAttribute("done")?n.remove():n.replaceWith(...t)),e.remove())})});}`;
7
+ var LAZY_JS = `{const r=document,o=(t,e)=>t.getAttribute(e),i=(t,e=[])=>t.replaceChildren(...e);customElements.define("m-component",class extends HTMLElement{static observedAttributes=["name","props"];#e;#i;#n;#t;#s;async#r(){const t={"x-component":this.#e,"x-props":this.#i??"{}","x-runtime-flag":""+$runtimeFlag,"x-scope-seq":""+$scopeSeq},e=new AbortController;this.#s?.abort(),this.#s=e,i(this,this.#n);const s=await fetch(location.href,{headers:t,signal:e.signal});if(!s.ok)throw i(this),new Error("Failed to fetch component '"+name+"'");const[l,n]=await s.json();this.innerHTML=l,n&&(r.body.appendChild(r.createElement("script")).textContent=n)}connectedCallback(){setTimeout(()=>{if(!this.#e){const t=o(this,"name"),e=o(this,"props");if(!t)throw new Error("Component name is required");this.#e=t,this.#i=e?.startsWith("base64,")?atob(e.slice(7)):null,this.#n=[...this.childNodes]}this.#r()})}disconnectedCallback(){i(this,this.#n),this.#s?.abort(),this.#t&&clearTimeout(this.#t),this.#s=void 0,this.#t=void 0}attributeChangedCallback(t,e,s){this.#e&&s&&e!==s&&(t==="name"?this.#e=s:t==="props"&&(this.#i=s),this.#t&&clearTimeout(this.#t),this.#t=setTimeout(()=>{this.#t=void 0,this.#r()},20))}});}`;
8
+ var ROUTER_JS = `{const n=document,a=t=>t.split("#",1)[0];customElements.define("m-router",class extends HTMLElement{#t;#e;#s;#i;async#o(t){const i=new AbortController,e={"x-route":"true","x-runtime-flag":""+$runtimeFlag,"x-scope-seq":""+$scopeSeq};this.#i?.abort(),this.#i=i;const s=await fetch(t,{headers:e,signal:i.signal});if(s.status===404){this.replaceChildren(...this.#t);return}if(!s.ok)throw this.replaceChildren(),new Error("Failed to fetch route: "+s.status+" "+s.statusText);const[o,r]=await s.json();this.innerHTML=o,r&&(n.body.appendChild(n.createElement("script")).textContent=r)}#n(){n.querySelectorAll("nav a").forEach(t=>{const{href:i,classList:e}=t,s=t.closest("nav")?.getAttribute("data-active-class")??"active";a(i)===a(location.href)?e.add(s):e.remove(s)})}#a(t){this.#o(t),this.#n()}connectedCallback(){setTimeout(()=>{if(!this.#t)if(this.getAttribute("status")==="404")this.#t=[...this.childNodes];else{this.#t=[];for(const t of this.childNodes)if(t.nodeType===1&&t.tagName==="TEMPLATE"&&t.hasAttribute("m-slot")){this.#t.push(...t.content.childNodes),t.remove();break}}}),this.#e=t=>{if(t.defaultPrevented||t.altKey||t.ctrlKey||t.metaKey||t.shiftKey||!(t.target instanceof HTMLAnchorElement))return;const{download:i,href:e,rel:s,target:o}=t.target;i||s==="external"||o==="_blank"||!e||!e.startsWith(location.origin)||a(e)===a(location.href)||(t.preventDefault(),history.pushState({},"",e),this.#a(e))},this.#s=()=>this.#a(location.href),addEventListener("popstate",this.#s),n.addEventListener("click",this.#e),setTimeout(()=>this.#n())}disconnectedCallback(){removeEventListener("popstate",this.#s),n.removeEventListener("click",this.#e),this.#i?.abort(),this.#s=void 0,this.#e=void 0,this.#i=void 0}});}`;
4
9
 
5
10
  // runtime/utils.ts
6
11
  var regexpHtmlSafe = /["'&<>]/;
@@ -116,12 +121,18 @@ var $vnode = Symbol.for("jsx.vnode");
116
121
  var $fragment = Symbol.for("jsx.fragment");
117
122
  var $html = Symbol.for("jsx.html");
118
123
  var $signal = Symbol.for("mono.signal");
119
- var $peek = Symbol.for("mono.peek");
120
124
 
121
125
  // version.ts
122
- var VERSION = "0.6.4";
126
+ var VERSION = "0.6.6";
123
127
 
124
128
  // render.ts
129
+ var RUNTIME_CX = 1;
130
+ var RUNTIME_STYLE = 2;
131
+ var RUNTIME_EVENT = 4;
132
+ var RUNTIME_SIGNALS = 8;
133
+ var RUNTIME_SUSPENSE = 16;
134
+ var RUNTIME_LAZY = 32;
135
+ var RUNTIME_ROUTER = 64;
125
136
  var cdn = "https://raw.esm.sh";
126
137
  var encoder = new TextEncoder();
127
138
  var customElements = /* @__PURE__ */ new Map();
@@ -285,38 +296,38 @@ async function render(node, options, write, writeJS, componentMode) {
285
296
  };
286
297
  const finalize = async () => {
287
298
  let js = "";
288
- if (rc.flags.runtime & F_CX && !(runtimeFlag & F_CX)) {
289
- runtimeFlag |= F_CX;
299
+ if (rc.flags.runtime & RUNTIME_CX && !(runtimeFlag & RUNTIME_CX)) {
300
+ runtimeFlag |= RUNTIME_CX;
290
301
  js += CX_JS;
291
302
  }
292
- if (rc.flags.runtime & F_STYLE && !(runtimeFlag & F_STYLE)) {
293
- runtimeFlag |= F_STYLE;
303
+ if (rc.flags.runtime & RUNTIME_STYLE && !(runtimeFlag & RUNTIME_STYLE)) {
304
+ runtimeFlag |= RUNTIME_STYLE;
294
305
  js += STYLE_JS;
295
306
  }
296
- if (rc.mfs.size > 0 && !(runtimeFlag & F_EVENT)) {
297
- runtimeFlag |= F_EVENT;
307
+ if (rc.mfs.size > 0 && !(runtimeFlag & RUNTIME_EVENT)) {
308
+ runtimeFlag |= RUNTIME_EVENT;
298
309
  js += EVENT_JS;
299
310
  }
300
- if ((signals.store.size > 0 || rc.mcs.size > 0 || signals.effects.length > 0) && !(runtimeFlag & F_SIGNALS)) {
301
- runtimeFlag |= F_SIGNALS;
311
+ if ((signals.store.size > 0 || rc.mcs.size > 0 || signals.effects.length > 0) && !(runtimeFlag & RUNTIME_SIGNALS)) {
312
+ runtimeFlag |= RUNTIME_SIGNALS;
302
313
  js += SIGNALS_JS;
303
314
  }
304
- if (suspenses.length > 0 && !(runtimeFlag & F_SUSPENSE)) {
305
- runtimeFlag |= F_SUSPENSE;
315
+ if (suspenses.length > 0 && !(runtimeFlag & RUNTIME_SUSPENSE)) {
316
+ runtimeFlag |= RUNTIME_SUSPENSE;
306
317
  js += SUSPENSE_JS;
307
318
  }
308
- if (rc.flags.runtime & F_LAZY && !(runtimeFlag & F_LAZY)) {
309
- runtimeFlag |= F_LAZY;
319
+ if (rc.flags.runtime & RUNTIME_LAZY && !(runtimeFlag & RUNTIME_LAZY)) {
320
+ runtimeFlag |= RUNTIME_LAZY;
310
321
  js += LAZY_JS;
311
322
  }
312
- if (rc.flags.runtime & F_ROUTER && !(runtimeFlag & F_ROUTER)) {
313
- runtimeFlag |= F_ROUTER;
323
+ if (rc.flags.runtime & RUNTIME_ROUTER && !(runtimeFlag & RUNTIME_ROUTER)) {
324
+ runtimeFlag |= RUNTIME_ROUTER;
314
325
  js += ROUTER_JS;
315
326
  }
316
327
  if (js.length > 0) {
317
328
  js = "(()=>{" + js + "})();/* --- */window.$runtimeFlag=" + runtimeFlag + ";";
318
329
  }
319
- if (runtimeFlag & F_LAZY || runtimeFlag & F_ROUTER) {
330
+ if (runtimeFlag & RUNTIME_LAZY || runtimeFlag & RUNTIME_ROUTER) {
320
331
  js += "window.$scopeSeq=" + rc.flags.scope + ";";
321
332
  }
322
333
  if (rc.mfs.size > 0) {
@@ -425,27 +436,8 @@ async function renderNode(rc, node, stripSlotProp) {
425
436
  }
426
437
  // `<toggle>` element
427
438
  case "toggle": {
428
- let { show, hidden, children } = props;
439
+ const { show, children } = props;
429
440
  if (children !== void 0) {
430
- if (show === void 0 && hidden !== void 0) {
431
- if (isSignal(hidden)) {
432
- let { scope, key, value } = hidden[$signal];
433
- if (typeof key === "string") {
434
- key = {
435
- compute: "()=>!this[" + JSON.stringify(key) + "]",
436
- deps: /* @__PURE__ */ new Set([scope + ":" + key])
437
- };
438
- } else {
439
- key = {
440
- compute: "()=>!(" + key.compute + ")()",
441
- deps: key.deps
442
- };
443
- }
444
- show = Signal(scope, key, !value);
445
- } else {
446
- show = !hidden;
447
- }
448
- }
449
441
  if (isSignal(show)) {
450
442
  const { scope, key, value } = show[$signal];
451
443
  let buf = '<m-signal mode="toggle" scope="' + scope + '" ';
@@ -555,7 +547,7 @@ async function renderNode(rc, node, stripSlotProp) {
555
547
  buf += "<m-group>" + attrModifiers + "</m-group>";
556
548
  }
557
549
  write(buf);
558
- rc.flags.runtime |= F_LAZY;
550
+ rc.flags.runtime |= RUNTIME_LAZY;
559
551
  break;
560
552
  }
561
553
  // `<router>` element
@@ -582,7 +574,7 @@ async function renderNode(rc, node, stripSlotProp) {
582
574
  }
583
575
  buf += "</m-router>";
584
576
  write(buf);
585
- rc.flags.runtime |= F_ROUTER;
577
+ rc.flags.runtime |= RUNTIME_ROUTER;
586
578
  break;
587
579
  }
588
580
  default: {
@@ -655,9 +647,9 @@ function renderAttr(rc, attrName, attrValue, stripSlotProp) {
655
647
  }
656
648
  if (signal) {
657
649
  if (attrName === "class") {
658
- rc.flags.runtime |= F_CX;
650
+ rc.flags.runtime |= RUNTIME_CX;
659
651
  } else if (attrName === "style") {
660
- rc.flags.runtime |= F_STYLE;
652
+ rc.flags.runtime |= RUNTIME_STYLE;
661
653
  }
662
654
  signalValue = signal;
663
655
  attrValue = signal[$signal].value;
@@ -889,7 +881,6 @@ function createSignals(scopeId, appSignals, context = new NullProtoObj(), reques
889
881
  case "refs":
890
882
  return refs;
891
883
  case "computed":
892
- case "$":
893
884
  return computed;
894
885
  case "effect":
895
886
  return (effect) => {
@@ -986,9 +977,6 @@ var jsx = (tag, props = new NullProtoObj(), key) => {
986
977
  props.key = key;
987
978
  }
988
979
  if (tag === "html") {
989
- if (props.request === $peek) {
990
- return props;
991
- }
992
980
  const renderOptions = new NullProtoObj();
993
981
  const optionsKeys = /* @__PURE__ */ new Set(["app", "context", "components", "routes", "request", "status", "headers", "htmx"]);
994
982
  for (const [key2, value] of Object.entries(props)) {
@@ -1023,12 +1011,7 @@ Object.assign(globalThis, {
1023
1011
  });
1024
1012
  export {
1025
1013
  Fragment,
1026
- JSX,
1027
- html as css,
1028
- html,
1029
- html as js,
1030
1014
  jsx,
1031
1015
  jsx as jsxDEV,
1032
- jsxEscape,
1033
1016
  jsx as jsxs
1034
1017
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mono-jsx",
3
- "version": "0.6.5",
3
+ "version": "0.6.6",
4
4
  "description": "`<html>` as a `Response`.",
5
5
  "type": "module",
6
6
  "module": "./index.mjs",
package/types/index.d.ts CHANGED
@@ -1,16 +1,5 @@
1
1
  import type { FC } from "./jsx.d.ts";
2
2
 
3
- /**
4
- * `buildRoute` creates a routing map for bun server.
5
- */
6
- export function buildRoute(
7
- handler: (req: Request) => Response,
8
- ): Record<string, (req: Request) => Response>;
9
-
10
- /**
11
- * `monoRoutes` creates a routing map for bun server.
12
- * @deprecated Use `buildRoute` instead.
13
- */
14
3
  export function monoRoutes(
15
4
  routes: Record<string, FC<any> | Promise<{ default: FC<any> }>>,
16
5
  handler: (req: Request) => Response,
@@ -1,8 +1,7 @@
1
1
  import type { FC, VNode } from "./jsx.d.ts";
2
2
 
3
- export const html: JSX.Raw;
4
- export const JSX: typeof globalThis.JSX;
5
- export const Fragment: (props: Record<string, unknown>) => VNode;
6
- export const jsx: (tag: string | FC, props: Record<string, unknown>, key?: string | number) => VNode;
3
+ export function jsx(tag: string | FC, props: Record<string, unknown>, key?: string | number): VNode;
7
4
 
8
- export { html as css, html as js, jsx as jsxDEV, jsx as jsxs };
5
+ export function Fragment(props: Record<string, unknown>): VNode;
6
+
7
+ export { jsx as jsxDEV, jsx as jsxs };
package/types/mono.d.ts CHANGED
@@ -91,27 +91,20 @@ export interface AsyncComponentAttributes {
91
91
 
92
92
  export interface Elements {
93
93
  /**
94
- * The `toggle` element is a built-in element that toggles the visibility of its children.
94
+ * The `toggle` element is a builtin element that toggles the visibility of its children.
95
95
  */
96
96
  toggle: BaseAttributes & {
97
- show?: any;
98
- hidden?: any;
97
+ show?: boolean | 0 | 1;
99
98
  };
100
99
  /**
101
- * The `switch` element is a built-in element that chooses one of its children based on the `slot` attribute to display.
100
+ * The `switch` element is a builtin element that chooses one of its children based on the `slot` attribute to display.
102
101
  * It is similar to a switch statement in programming languages.
103
102
  */
104
103
  switch: BaseAttributes & {
105
104
  value?: string | number | boolean | null;
106
105
  };
107
106
  /**
108
- * The `for` element is a built-in element for list rendering with signals.
109
- */
110
- for: BaseAttributes & {
111
- items?: unknown[];
112
- };
113
- /**
114
- * The `component` element is a built-in element that is used to load components lazily,
107
+ * The `component` element is a builtin element that is used to load components lazily,
115
108
  * which can improve performance by reducing the initial load time of the application.
116
109
  */
117
110
  component: BaseAttributes & AsyncComponentAttributes & {
@@ -119,7 +112,7 @@ export interface Elements {
119
112
  props?: Record<string, unknown>;
120
113
  };
121
114
  /**
122
- * The `router` element is a built-in element that implements client-side routing.
115
+ * The `router` element is a builtin element that implements client-side routing.
123
116
  */
124
117
  router: BaseAttributes & AsyncComponentAttributes & {};
125
118
  }
@@ -137,17 +130,17 @@ declare global {
137
130
  */
138
131
  type FC<Signals = {}, AppSignals = {}, Context = {}> = {
139
132
  /**
140
- * The global signals shared across the application.
133
+ * Application signals.
141
134
  */
142
135
  readonly app: AppSignals;
143
136
  /**
144
- * The rendering context.
137
+ * Rendering context.
145
138
  *
146
139
  * **⚠ This is a server-side only API.**
147
140
  */
148
141
  readonly context: Context;
149
142
  /**
150
- * The `request` object contains the current request information.
143
+ * Current request object.
151
144
  *
152
145
  * **⚠ This is a server-side only API.**
153
146
  */
@@ -160,14 +153,10 @@ declare global {
160
153
  * The `computed` method is used to create a computed signal.
161
154
  */
162
155
  readonly computed: <T = unknown>(fn: () => T) => T;
163
- /**
164
- * `this.$(fn)` is just a shortcut for `this.computed(fn)`.
165
- */
166
- readonly $: <T = unknown>(fn: () => T) => T;
167
156
  /**
168
157
  * The `effect` method is used to create a side effect.
169
158
  * **The effect function is only called on client side.**
170
159
  */
171
160
  readonly effect: (fn: () => void | (() => void)) => void;
172
- } & Omit<Signals, "app" | "context" | "request" | "refs" | "computed" | "$" | "effect">;
161
+ } & Omit<Signals, "app" | "context" | "request" | "computed" | "effect">;
173
162
  }
package/types/render.d.ts CHANGED
@@ -11,7 +11,7 @@ type HtmxExts = {
11
11
  | boolean;
12
12
  };
13
13
 
14
- export type MaybeModule<T> = T | Promise<{ default: T }>;
14
+ export type FCModule = FC<any> | Promise<{ default: FC<any> }>;
15
15
 
16
16
  /**
17
17
  * Render options for the `render` function.
@@ -28,11 +28,11 @@ export interface RenderOptions extends Partial<HtmxExts> {
28
28
  /**
29
29
  * Components to be rendered by the `<lazy>` element.
30
30
  */
31
- components?: Record<string, MaybeModule<FC<any>>>;
31
+ components?: Record<string, FCModule>;
32
32
  /**
33
33
  * Routes to be used by the `<router>` element.
34
34
  */
35
- routes?: Record<string, MaybeModule<FC<any>>>;
35
+ routes?: Record<string, FCModule>;
36
36
  /**
37
37
  * Current `Request` object to be passed to components.
38
38
  */