mono-jsx 0.6.1 → 0.6.3
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 +7 -7
- package/jsx-runtime.mjs +20 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ mono-jsx is a JSX runtime that renders `<html>` element to `Response` object in
|
|
|
7
7
|
- 🚀 No build step needed
|
|
8
8
|
- 🦋 Lightweight (10KB gzipped), zero dependencies
|
|
9
9
|
- 🚦 Signals as reactive primitives
|
|
10
|
-
- ⚡️ Use web
|
|
10
|
+
- ⚡️ Use web components, no virtual DOM
|
|
11
11
|
- 💡 Complete Web API TypeScript definitions
|
|
12
12
|
- ⏳ Streaming rendering
|
|
13
13
|
- 🗂️ Built-in router
|
|
@@ -810,15 +810,15 @@ You also can use signal `name` or `props`, change the signal value will trigger
|
|
|
810
810
|
```tsx
|
|
811
811
|
import { Profile, Projects, Settings } from "./pages.tsx"
|
|
812
812
|
|
|
813
|
-
|
|
814
|
-
this.page = "
|
|
813
|
+
function Dash(this: FC<{ page: "Profile" | "Projects" | "Settings" }>) {
|
|
814
|
+
this.page = "Profile";
|
|
815
815
|
|
|
816
816
|
return (
|
|
817
817
|
<>
|
|
818
818
|
<div class="tab">
|
|
819
|
-
<button onClick={e => this.page = "Profile"}>Profile</
|
|
820
|
-
<button onClick={e => this.page = "Projects"}>Projects</
|
|
821
|
-
<button onClick={e => this.page = "Settings"}>Settings</
|
|
819
|
+
<button onClick={e => this.page = "Profile"}>Profile</button>
|
|
820
|
+
<button onClick={e => this.page = "Projects"}>Projects</button>
|
|
821
|
+
<button onClick={e => this.page = "Settings"}>Settings</button>
|
|
822
822
|
</div>
|
|
823
823
|
<div class="page">
|
|
824
824
|
<component name={this.page} placeholder={<p>Loading...</p>} />
|
|
@@ -946,7 +946,7 @@ export default {
|
|
|
946
946
|
}
|
|
947
947
|
```
|
|
948
948
|
|
|
949
|
-
###
|
|
949
|
+
### Fallback(404)
|
|
950
950
|
|
|
951
951
|
You can add fallback(404) content to the `<router>` element as children, which will be displayed when no route matches the current URL:
|
|
952
952
|
|
package/jsx-runtime.mjs
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
// runtime/index.ts
|
|
2
|
-
var VERSION = "0.6.1";
|
|
3
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;}`;
|
|
4
|
-
var
|
|
3
|
+
var STYLE_JS = `{var c=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(",")),a=e=>typeof e=="string",l=e=>typeof e=="object"&&e!==null,u=e=>e.replace(/[a-z][A-Z]/g,o=>o.charAt(0)+"-"+o.charAt(1).toLowerCase());var p=e=>{let o=[],i=[],t=new g;for(let[n,r]of Object.entries(e))switch(n.charCodeAt(0)){case 58:i.push(null,n+"{"+s(r)+"}");break;case 64:i.push(n+"{",null,"{"+s(r)+"}}");break;case 38:i.push(null,n.slice(1)+"{"+s(r)+"}");break;default:o.push([n,r])}return o.length>0&&(t.inline=s(o)),i.length>0&&(t.css=i),t},f=(e,o)=>{let{inline:i,css:t}=p(o);if(t){let n="[data-css-"+Date.now().toString(36)+"]";document.head.appendChild(document.createElement("style")).textContent=(i?n+"{"+i+"}":"")+t.map(r=>r===null?n:r).join(""),e.getAttributeNames().forEach(r=>r.startsWith("data-css-")&&e.removeAttribute(r)),e.setAttribute(n.slice(1,-1),"")}else i&&e.setAttribute("style",i)},s=e=>{if(l(e)){let o="";for(let[i,t]of Array.isArray(e)?e:Object.entries(e))if(a(t)||typeof t=="number"){let n=u(i),r=typeof t=="number"?c.has(n)?""+t:t+"px":""+t;o+=(o?";":"")+n+":"+(n==="content"?JSON.stringify(r):r)}return o}return""},g=(()=>{function e(){}return e.prototype=Object.freeze(Object.create(null)),e})();window.$applyStyle=f;}`;
|
|
5
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)};}`;
|
|
6
|
-
var SIGNALS_JS = `{let p;const
|
|
5
|
+
var SIGNALS_JS = `{let p;const m=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,i=(c,l)=>{let o=n.get(c);return o||(o=new Set,n.set(c,o)),o.add(l),()=>{o.delete(l),o.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,o)=>{switch(l){case"$init":return r;case"$watch":return i;case"app":return d(0);case"refs":return s;default:return p?.(e,l),Reflect.get(c,l,o)}},set:(c,l,o,a)=>{if(o!==Reflect.get(c,l,a)){const f=n.get(l);return f&&queueMicrotask(()=>f.forEach(g=>g())),Reflect.set(c,l,o,a)}return!1}})},k=(e,t,r)=>{if(t==="toggle"){let n;return()=>{if(!n){const i=e.firstElementChild;i&&i.tagName==="TEMPLATE"&&i.hasAttribute("m-slot")?n=[...i.content.childNodes]:n=[...e.childNodes]}M(e,r()?n:[])}}if(t==="switch"){let n,i=u(e,"match"),s,c,l=o=>s.get(o)??s.set(o,[]).get(o);return()=>{if(!s){s=new Map,c=[];for(const o of e.childNodes)if(o.nodeType===1&&o.tagName==="TEMPLATE"&&o.hasAttribute("m-slot")){for(const a of o.content.childNodes)a.nodeType===1&&a.hasAttribute("slot")?l(u(a,"slot")).push(a):c.push(a);o.remove()}else i?l(i).push(o):c.push(o)}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),i=e.parentElement;return i.tagName==="M-GROUP"&&(i=i.previousElementSibling),()=>{const s=r();s===!1||s===null||s===void 0?i.removeAttribute(n):typeof s=="object"&&s!==null&&(n==="class"||n==="style"||n==="props")?n==="class"?y(i,n,$cx(s)):n==="style"?$applyStyle(i,s):y(i,n,JSON.stringify(s)):y(i,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(([i,s])=>{const c=k(e,u(e,"mode"),i.bind(t));s.forEach(l=>{const[o,a]=N(l);e.disposes.push(d(o).$watch(a,c))})})}}),T("m-effect",e=>{const{disposes:t}=e,r=Number(u(e,"scope")),n=Number(u(e,"n")),i=new Array(n);t.push(()=>{i.forEach(s=>typeof s=="function"&&s()),i.length=0});for(let s=0;s<n;s++){const c="$ME_"+r+"_"+s;w(()=>m[c]).then(l=>{const o=[],a=d(r),f=()=>{i[s]=l.call(a)};p=(g,h)=>o.push([g,h]),f(),p=void 0;for(const[g,h]of o)t.push(d(g).$watch(h,f))},()=>{})}}),m.$signals=e=>e!==void 0?d(e):void 0,m.$MS=(e,t)=>{const[r,n]=N(e);d(r).$init(n,t)},m.$MC=(e,t,r)=>{E.set(e,[t,r])},m.$merge=(e,...t)=>{for(const[r,...n]of t){let i=e;const s=n.pop();for(const c of n)i=i[c];i[s]=r}return e};}`;
|
|
7
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())})});}`;
|
|
8
|
-
var LAZY_JS = `{const
|
|
9
|
-
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={"x-route":"true","x-runtime-flag":""+$runtimeFlag,"x-scope-seq":""+$scopeSeq},e=new AbortController;this.#i?.abort(),this.#i=e;const s=await fetch(t,{headers:i,signal:e.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),
|
|
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={"x-route":"true","x-runtime-flag":""+$runtimeFlag,"x-scope-seq":""+$scopeSeq},e=new AbortController;this.#i?.abort(),this.#i=e;const s=await fetch(t,{headers:i,signal:e.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}});}`;
|
|
10
9
|
|
|
11
10
|
// runtime/utils.ts
|
|
12
11
|
var regexpHtmlSafe = /["'&<>]/;
|
|
@@ -123,9 +122,12 @@ var $fragment = Symbol.for("jsx.fragment");
|
|
|
123
122
|
var $html = Symbol.for("jsx.html");
|
|
124
123
|
var $signal = Symbol.for("mono.signal");
|
|
125
124
|
|
|
125
|
+
// version.ts
|
|
126
|
+
var VERSION = "0.6.3";
|
|
127
|
+
|
|
126
128
|
// render.ts
|
|
127
129
|
var RUNTIME_CX = 1;
|
|
128
|
-
var
|
|
130
|
+
var RUNTIME_STYLE = 2;
|
|
129
131
|
var RUNTIME_EVENT = 4;
|
|
130
132
|
var RUNTIME_SIGNALS = 8;
|
|
131
133
|
var RUNTIME_SUSPENSE = 16;
|
|
@@ -197,6 +199,9 @@ function renderHtml(node, options) {
|
|
|
197
199
|
status = 404;
|
|
198
200
|
}
|
|
199
201
|
}
|
|
202
|
+
if (components && !request) {
|
|
203
|
+
console.warn("The `components` prop in the `<html>` element is ignored when `request` is not provided.");
|
|
204
|
+
}
|
|
200
205
|
if (headersInit) {
|
|
201
206
|
for (const [key, value] of Object.entries(headersInit)) {
|
|
202
207
|
if (value) {
|
|
@@ -295,15 +300,15 @@ async function render(node, options, write, writeJS, componentMode) {
|
|
|
295
300
|
runtimeFlag |= RUNTIME_CX;
|
|
296
301
|
js += CX_JS;
|
|
297
302
|
}
|
|
298
|
-
if (rc.flags.runtime &
|
|
299
|
-
runtimeFlag |=
|
|
300
|
-
js +=
|
|
303
|
+
if (rc.flags.runtime & RUNTIME_STYLE && !(runtimeFlag & RUNTIME_STYLE)) {
|
|
304
|
+
runtimeFlag |= RUNTIME_STYLE;
|
|
305
|
+
js += STYLE_JS;
|
|
301
306
|
}
|
|
302
307
|
if (rc.mfs.size > 0 && !(runtimeFlag & RUNTIME_EVENT)) {
|
|
303
308
|
runtimeFlag |= RUNTIME_EVENT;
|
|
304
309
|
js += EVENT_JS;
|
|
305
310
|
}
|
|
306
|
-
if (
|
|
311
|
+
if (signals.store.size + rc.mcs.size + signals.effects.length > 0 && !(runtimeFlag & RUNTIME_SIGNALS)) {
|
|
307
312
|
runtimeFlag |= RUNTIME_SIGNALS;
|
|
308
313
|
js += SIGNALS_JS;
|
|
309
314
|
}
|
|
@@ -644,7 +649,7 @@ function renderAttr(rc, attrName, attrValue, stripSlotProp) {
|
|
|
644
649
|
if (attrName === "class") {
|
|
645
650
|
rc.flags.runtime |= RUNTIME_CX;
|
|
646
651
|
} else if (attrName === "style") {
|
|
647
|
-
rc.flags.runtime |=
|
|
652
|
+
rc.flags.runtime |= RUNTIME_STYLE;
|
|
648
653
|
}
|
|
649
654
|
signalValue = signal;
|
|
650
655
|
attrValue = signal[$signal].value;
|
|
@@ -661,7 +666,7 @@ function renderAttr(rc, attrName, attrValue, stripSlotProp) {
|
|
|
661
666
|
const { inline, css } = styleToCSS(attrValue);
|
|
662
667
|
if (css) {
|
|
663
668
|
const id = hashCode((inline ?? "") + css.join("")).toString(36);
|
|
664
|
-
addonHtml += '<style
|
|
669
|
+
addonHtml += '<style data-mono-jsx-css="' + id + '">' + (inline ? "[data-css-" + id + "]{" + escapeCSSText(inline) + "}" : "") + escapeCSSText(css.map((v) => v === null ? "[data-css-" + id + "]" : v).join("")) + "</style>";
|
|
665
670
|
attr = " data-css-" + id;
|
|
666
671
|
} else if (inline) {
|
|
667
672
|
attr = " style=" + toAttrStringLit(inline);
|
|
@@ -703,9 +708,10 @@ function renderAttr(rc, attrName, attrValue, stripSlotProp) {
|
|
|
703
708
|
default:
|
|
704
709
|
if (attrName.startsWith("on") && typeof attrValue === "function") {
|
|
705
710
|
attr = " " + escapeHTML(attrName.toLowerCase()) + '="$emit(event,$MF_' + rc.mfs.gen(attrValue) + toStr(rc.fcCtx?.scopeId, (i) => "," + i) + ')"';
|
|
706
|
-
} else if (
|
|
711
|
+
} else if (attrValue === false || attrValue === null || attrValue === void 0) {
|
|
712
|
+
} else {
|
|
707
713
|
attr = " " + escapeHTML(attrName);
|
|
708
|
-
if (attrValue !==
|
|
714
|
+
if (attrValue !== true) {
|
|
709
715
|
attr += "=" + toAttrStringLit(String(attrValue));
|
|
710
716
|
}
|
|
711
717
|
}
|