mono-jsx 0.6.10 → 0.6.12

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
@@ -543,6 +543,15 @@ function App(this: FC<{ value: string }>) {
543
543
  }
544
544
  ```
545
545
 
546
+ You can also use the `$checked` attribute to bind a signal to the checked state of a checkbox or radio input element.
547
+
548
+ ```tsx
549
+ function App(this: FC<{ checked: boolean }>) {
550
+ this.checked = false;
551
+ return <input type="checkbox" $checked={this.checked} />;
552
+ }
553
+ ```
554
+
546
555
  ### Limitation of Signals
547
556
 
548
557
  1\. Arrow function are non-stateful components.
@@ -1063,6 +1072,38 @@ export default {
1063
1072
  }
1064
1073
  ```
1065
1074
 
1075
+ ## Using View Transition
1076
+
1077
+ mono-jsx supports [View Transition](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API) to create smooth transitions between views. To use view transition, add `viewTransition` attribute to below components:
1078
+
1079
+ - `<toggle viewTransition="transition-name">`
1080
+ - `<switch viewTransition="transition-name">`
1081
+ - `<component viewTransition="transition-name">`
1082
+ - `<router viewTransition="transition-name">`
1083
+
1084
+ You can set custom transition animation by adding [`::view-transition-group`](https://developer.mozilla.org/en-US/docs/Web/CSS/::view-transition-group) and [`::view-transition-old`](https://developer.mozilla.org/en-US/docs/Web/CSS/::view-transition-old) and [`::view-transition-new`](https://developer.mozilla.org/en-US/docs/Web/CSS/::view-transition-new) pseudo-elements with your own CSS animation. For example,
1085
+
1086
+ ```tsx
1087
+ function App(this: FC<{ show: boolean }>) {
1088
+ return (
1089
+ <div
1090
+ style={{
1091
+ "@keyframes fade-in": { from: { opacity: 0 }, to: { opacity: 1 } },
1092
+ "@keyframes fade-out": { from: { opacity: 1 }, to: { opacity: 0 } },
1093
+ "::view-transition-group(fade)": { animationDuration: "0.5s" },
1094
+ "::view-transition-old(fade)": { animation: "0.5s ease-in both fade-out" },
1095
+ "::view-transition-new(fade)": { animation: "0.5s ease-in both fade-in" },
1096
+ }}
1097
+ >
1098
+ <toggle show={this.show} viewTransition="fade">
1099
+ <h1>Hello world!</h1>
1100
+ </toggle>
1101
+ <button onClick={() => this.show = !this.show}>Toggle</button>
1102
+ </div>
1103
+ )
1104
+ }
1105
+ ```
1106
+
1066
1107
  ## Customizing html Response
1067
1108
 
1068
1109
  You can add `status` or `headers` attributes to the root `<html>` element to customize the http response:
package/jsx-runtime.mjs CHANGED
@@ -11,14 +11,14 @@ var LAZY = 256;
11
11
  var ROUTER = 512;
12
12
  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)};}`;
13
13
  var CX_JS = `{var n=e=>typeof e=="string"?e:typeof e=="object"&&e!==null?Array.isArray(e)?e.map(n).filter(Boolean).join(" "):Object.entries(e).filter(([,t])=>!!t).map(([t])=>t).join(" "):"";window.$cx=n;}`;
14
- var STYLE_JS = `{var a=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;var l=e=>typeof e=="string";var u=e=>e.replace(/[a-z][A-Z]/g,r=>r.charAt(0)+"-"+r.charAt(1).toLowerCase());var p=e=>{let r=[],t=[],n=new g;for(let[o,s]of Object.entries(e))switch(o.charCodeAt(0)){case 58:t.push(null,o+"{"+c(s)+"}");break;case 64:t.push(o+"{",null,"{"+c(s)+"}}");break;case 38:t.push(null,o.slice(1)+"{"+c(s)+"}");break;default:r.push([o,s])}return r.length>0&&(n.inline=c(r)),t.length>0&&(n.css=t),n},f=(e,r)=>{let{inline:t,css:n}=p(r);if(n){let o="data-css-",s="["+o+(Date.now()+Math.random()).toString(36).replace(".","")+"]";document.head.appendChild(document.createElement("style")).textContent=(t?s+"{"+t+"}":"")+n.map(i=>i===null?s:i).join(""),e.getAttributeNames().forEach(i=>i.startsWith(o)&&e.removeAttribute(i)),e.setAttribute(s.slice(1,-1),"")}else t&&e.setAttribute("style",t)},c=e=>{if(typeof e=="object"&&e!==null){let r="";for(let[t,n]of Array.isArray(e)?e:Object.entries(e))if(l(n)||typeof n=="number"){let o=u(t),s=typeof n=="number"?a.test(t)?""+n:n+"px":""+n;r+=(r?";":"")+o+":"+(o==="content"?JSON.stringify(s):s)}return r}return""},g=(()=>{function e(){}return e.prototype=Object.freeze(Object.create(null)),e})();window.$applyStyle=f;}`;
15
- var RENDER_ATTR_JS = `{var s=(l,n,r)=>{let t=l.parentElement;return t.tagName==="M-GROUP"&&(t=t.previousElementSibling),()=>{let e=r();e===!1||e===null||e===void 0?t.removeAttribute(n):typeof e=="object"&&e!==null?n==="class"?t.setAttribute(n,$cx(e)):n==="style"?$applyStyle(t,e):t.setAttribute(n,JSON.stringify(e)):n==="value"?t.value=String(e):t.setAttribute(n,e===!0?"":e)}};window.$renderAttr=s;}`;
16
- var RENDER_TOGGLE_JS = `{var r=(n,l)=>{let e;return()=>{if(!e){let t=n.firstElementChild;t&&t.tagName==="TEMPLATE"&&t.hasAttribute("m-slot")?e=[...t.content.childNodes]:e=[...n.childNodes]}n.replaceChildren(...l()?e:[])}};window.$renderToggle=r;}`;
17
- var RENDER_SWITCH_JS = `{var u=(r,d)=>{let s,i=r.getAttribute("value"),t,l,o=e=>t.get(e)??t.set(e,[]).get(e);return()=>{if(!t){t=new Map,l=[];for(let e of r.childNodes)if(e.nodeType===1&&e.tagName==="TEMPLATE"&&e.hasAttribute("m-slot")){for(let n of e.content.childNodes)n.nodeType===1&&n.hasAttribute("slot")?o(n.getAttribute("slot")).push(n):l.push(n);e.remove()}else i?o(i).push(e):l.push(e)}s=""+d(),r.replaceChildren(...t.has(s)?t.get(s):l)}};window.$renderSwitch=u;}`;
14
+ var STYLE_JS = `{var l=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;var u=e=>typeof e=="string",p=e=>typeof e=="object"&&e!==null,f=e=>e.replace(/[a-z][A-Z]/g,o=>o.charAt(0)+"-"+o.charAt(1).toLowerCase());var g=e=>{let o=[],n=[],r=new y;for(let[t,s]of Object.entries(e))switch(t.charCodeAt(0)){case 58:n.push(t.startsWith("::view-")?"":null,t+"{"+c(s)+"}");break;case 64:t.startsWith("@keyframes ")||t.startsWith("@view-")?p(s)&&n.push(t+"{"+Object.entries(s).map(([i,a])=>i+"{"+c(a)+"}").join("")+"}"):n.push(t+"{",null,"{"+c(s)+"}}");break;case 38:n.push(null,t.slice(1)+"{"+c(s)+"}");break;default:o.push([t,s])}return o.length>0&&(r.inline=c(o)),n.length>0&&(r.css=n),r},b=(e,o)=>{let{inline:n,css:r}=g(o);if(r){let t="data-css-",s="["+t+(Date.now()+Math.random()).toString(36).replace(".","")+"]";document.head.appendChild(document.createElement("style")).textContent=(n?s+"{"+n+"}":"")+r.map(i=>i===null?s:i).join(""),e.getAttributeNames().forEach(i=>i.startsWith(t)&&e.removeAttribute(i)),e.setAttribute(s.slice(1,-1),"")}else n&&e.setAttribute("style",n)},c=e=>{if(typeof e=="object"&&e!==null){let o="";for(let[n,r]of Array.isArray(e)?e:Object.entries(e))if(u(r)||typeof r=="number"){let t=f(n),s=typeof r=="number"?l.test(n)?""+r:r+"px":""+r;o+=(o?";":"")+t+":"+(t==="content"?JSON.stringify(s):s)}return o}return""},y=(()=>{function e(){}return e.prototype=Object.freeze(Object.create(null)),e})();window.$applyStyle=b;}`;
15
+ var RENDER_ATTR_JS = `{var s=(l,n,r)=>{let e=l.parentElement;return e.tagName==="M-GROUP"&&(e=e.previousElementSibling),()=>{let t=r();n==="value"?e.value=String(t):n==="checked"?e.checked=!!t:typeof t=="boolean"?e.toggleAttribute(n,t):t==null?e.removeAttribute(n):typeof t=="object"?n==="class"?e.setAttribute(n,$cx(t)):n==="style"?$applyStyle(e,t):e.setAttribute(n,JSON.stringify(t)):e.setAttribute(n,String(t))}};window.$renderAttr=s;}`;
16
+ var RENDER_TOGGLE_JS = `{var i=(e,s)=>{let t,l=()=>e.replaceChildren(...s()?t:[]);return()=>{if(!t){let n=e.firstElementChild;n&&n.tagName==="TEMPLATE"&&n.hasAttribute("m-slot")?t=[...n.content.childNodes]:t=[...e.childNodes]}e.hasAttribute("vt")&&document.startViewTransition?document.startViewTransition(l):l()}};window.$renderToggle=i;}`;
17
+ var RENDER_SWITCH_JS = `{var a=(l,u)=>{let s,r=l.getAttribute("value"),t,i,o=e=>t.get(e)??t.set(e,[]).get(e),d=()=>l.replaceChildren(...t.has(s)?t.get(s):i);return()=>{if(!t){t=new Map,i=[];for(let e of l.childNodes)if(e.nodeType===1&&e.tagName==="TEMPLATE"&&e.hasAttribute("m-slot")){for(let n of e.content.childNodes)n.nodeType===1&&n.hasAttribute("slot")?o(n.getAttribute("slot")).push(n):i.push(n);e.remove()}else r?o(r).push(e):i.push(e)}s=""+u(),l.hasAttribute("vt")&&document.startViewTransition?document.startViewTransition(d):d()}};window.$renderSwitch=a;}`;
18
18
  var SIGNALS_JS = `{let m;const h=window,b=new Map,k=new Map,l=n=>k.get(n)??k.set(n,M(n)).get(n),y=()=>Object.create(null),f=(n,e)=>n.getAttribute(e),M=n=>{const e=y(),t=(r,c)=>{e[r]=c},s=new Map,a=(r,c)=>{let o=s.get(r);return o||(o=new Set,s.set(r,o)),o.add(c),()=>{o.delete(c),o.size===0&&s.delete(r)}},i=new Proxy(y(),{get:(r,c)=>document.querySelector("[data-ref='"+n+":"+c+"']")});return new Proxy(e,{get:(r,c,o)=>{switch(c){case"$init":return t;case"$watch":return a;case"app":return l(0);case"refs":return i;default:return m?.(n,c),Reflect.get(r,c,o)}},set:(r,c,o,d)=>{if(o!==Reflect.get(r,c,d)){const u=s.get(c);return u&&queueMicrotask(()=>u.forEach(g=>g())),Reflect.set(r,c,o,d)}return!1}})},$=(n,e,t)=>{switch(e){case"toggle":return $renderToggle(n,t);case"switch":return $renderSwitch(n,t);case"html":return()=>n.innerHTML=""+t()}return e&&e.length>2&&e.startsWith("[")&&e.endsWith("]")?$renderAttr(n,e.slice(1,-1),t):()=>n.textContent=""+t()},E=n=>{const e=n.indexOf(":");return e>0?[Number(n.slice(0,e)),n.slice(e+1)]:null},p=async n=>{const e=n();return e!==void 0?e:(await new Promise(t=>setTimeout(t,0)),p(n))},S=n=>{typeof n=="function"&&n()},v=(n,e)=>customElements.define(n,class extends HTMLElement{disposes=[];connectedCallback(){e(this)}disconnectedCallback(){this.disposes.forEach(t=>t()),this.disposes.length=0}});v("m-signal",n=>{const e=Number(f(n,"scope")),t=l(e),s=f(n,"key");if(s)n.disposes.push(t.$watch(s,$(n,f(n,"mode"),()=>t[s])));else{const a=Number(f(n,"computed"));p(()=>b.get(e*1e9+a)).then(([i,r])=>{const c=$(n,f(n,"mode"),i.bind(t));r.forEach(o=>{const[d,u]=E(o);n.disposes.push(l(d).$watch(u,c))})})}}),v("m-effect",n=>{const{disposes:e}=n,t=Number(f(n,"scope")),s=Number(f(n,"n")),a=new Array(s);e.push(()=>{a.forEach(S),a.length=0});for(let i=0;i<s;i++){const r="$ME_"+t+"_"+i;p(()=>h[r]).then(c=>{const o=[],d=l(t),u=()=>{S(a[i]),a[i]=c.call(d)};m=(g,w)=>o.push([g,w]),u(),m=void 0;for(const[g,w]of o)e.push(l(g).$watch(w,u))},()=>{})}}),h.$MS=(n,e)=>{const[t,s]=E(n);l(t).$init(s,e)},h.$MC=(n,e,t,s)=>{b.set(n*1e9+e,[t,s])},h.$patch=(n,...e)=>{for(const[t,...s]of e){const a=s.pop();let i=n;for(const r of s)i=i[r];i[a]=t}return n},h.$signals=n=>n!==void 0?l(n):void 0;}`;
19
19
  var SUSPENSE_JS = `{const i=new Map,o=e=>e.getAttribute("chunk-id"),l=(e,t)=>customElements.define(e,class extends HTMLElement{connectedCallback(){t(this)}});l("m-portal",e=>{i.set(o(e),e)}),l("m-chunk",e=>{setTimeout(()=>{const t=o(e),n=i.get(t),s=e.firstChild?.content.childNodes;n&&(e.hasAttribute("next")?s&&n.before(...s):(e.hasAttribute("done")?n.remove():s&&n.replaceWith(...s),i.delete(t)),e.remove())})});}`;
20
- var LAZY_JS = `{const r=document,o=(t,s)=>t.getAttribute(s),i=(t,s=[])=>t.replaceChildren(...s);customElements.define("m-component",class extends HTMLElement{static observedAttributes=["name","props"];#t;#e;#i;#n;#s;async#r(){if(!this.#t){i(this);return}const t={"x-component":this.#t,"x-props":this.#e||"{}","x-flags":$FLAGS},s=new AbortController;this.#n?.abort(),this.#n=s,i(this,this.#i);const e=await fetch(location.href,{headers:t,signal:s.signal});if(!e.ok)throw i(this),new Error("Failed to fetch component '"+this.#t+"'");const[h,n]=await e.json();this.innerHTML=h,n&&(r.body.appendChild(r.createElement("script")).textContent=n)}get name(){return this.#t??null}set name(t){t&&t!==this.#t&&(this.#t=t,this.refresh())}get props(){return this.#e?JSON.parse(this.#e):void 0}set props(t){const s=typeof t=="string"?t:JSON.stringify(t);s&&s!==this.#e&&(this.#e=s,this.refresh())}connectedCallback(){setTimeout(()=>{if(!this.#i){const t=o(this,"props");this.#t=o(this,"name"),this.#e=t?.startsWith("base64,")?atob(t.slice(7)):void 0,this.#i=[...this.childNodes]}this.#r()})}disconnectedCallback(){i(this,this.#i),this.#n?.abort(),this.#n=void 0,this.#s&&clearTimeout(this.#s),this.#s=void 0}attributeChangedCallback(t,s,e){this.#t&&e&&(t==="name"?this.name=e:t==="props"&&(this.props=e))}refresh(){this.#s&&clearTimeout(this.#s),this.#s=setTimeout(()=>{this.#s=void 0,this.#r()},50)}});}`;
21
- var ROUTER_JS = `{const a=document,n=location,l=t=>t.split("#",1)[0],c=t=>l(t)===l(n.href);customElements.define("m-router",class extends HTMLElement{#t;#e;#s;#i;async#o(t){const s=new AbortController,e={"x-route":"true","x-flags":$FLAGS};this.#i?.abort(),this.#i=s;const i=await fetch(t,{headers:e,signal:s.signal});if(i.status===404)return this.replaceChildren(...this.#t),!0;if(!i.ok)throw this.replaceChildren(),new Error("Failed to fetch route: "+i.status+" "+i.statusText);const[o,r]=await i.json();this.innerHTML=o,r&&(a.body.appendChild(a.createElement("script")).textContent=r)}#n(){a.querySelectorAll("nav a").forEach(t=>{const{href:s,classList:e}=t,i=t.closest("nav")?.getAttribute("data-active-class")??"active";c(s)?e.add(i):e.remove(i)})}navigate(t,s){const e=new URL(t,n.href);if(e.origin!==n.origin){n.href=t;return}c(e.href)||this.#a(t,s)}async#a(t,s){const e=await this.#o(t);s?.replace?history.replaceState({},"",t):history.pushState({},"",t),e&&typeof $signals<"u"&&($signals(0).url=new URL(t)),this.#n(),window.scrollTo(0,0)}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:s,href:e,rel:i,target:o}=t.target;s||i==="external"||o==="_blank"||!e.startsWith(n.origin)||(t.preventDefault(),this.navigate(e))},this.#s=()=>this.#a(n.href),addEventListener("popstate",this.#s),a.addEventListener("click",this.#e),setTimeout(()=>this.#n())}disconnectedCallback(){removeEventListener("popstate",this.#s),a.removeEventListener("click",this.#e),this.#i?.abort(),this.#i=void 0,this.#e=void 0,this.#s=void 0}});}`;
20
+ var LAZY_JS = `{const e=document,a=(t,s)=>t.getAttribute(s);customElements.define("m-component",class extends HTMLElement{static observedAttributes=["name","props"];#t;#s;#r;#h;#i;#e=new Map;#a=!0;async#l(){if(!this.#t){this.#n("");return}const t=this.#s||"{}",s=this.#t+t,i={"x-component":this.#t,"x-props":t,"x-flags":$FLAGS},n=new AbortController;if(this.#h?.abort(),this.#h=n,this.#e.has(s)){this.#n(this.#e.get(s));return}this.#r?.length&&this.#n(this.#r);const r=await fetch(location.href,{headers:i,signal:n.signal});if(!r.ok)throw this.#n(""),new Error("Failed to fetch component '"+this.#t+"'");const[h,o]=await r.json();this.#e.set(s,h),this.#n(h),o&&(e.body.appendChild(e.createElement("script")).textContent=o)}#n(t){const s=()=>typeof t=="string"?this.innerHTML=t:this.replaceChildren(...t);this.hasAttribute("vt")&&e.startViewTransition&&!this.#a?e.startViewTransition(s):s(),this.#a=!1}get name(){return this.#t??null}set name(t){t&&t!==this.#t&&(this.#t=t,this.#o())}get props(){return this.#s?JSON.parse(this.#s):void 0}set props(t){const s=typeof t=="string"?t:JSON.stringify(t);s&&s!==this.#s&&(this.#s=s,this.#o())}attributeChangedCallback(t,s,i){this.#t&&i&&(t==="name"?this.name=i:t==="props"&&(this.props=i))}connectedCallback(){setTimeout(()=>{if(!this.#r){const t=a(this,"props");this.#t=a(this,"name"),this.#s=t?.startsWith("base64,")?atob(t.slice(7)):void 0,this.#r=[...this.childNodes]}this.#l()})}disconnectedCallback(){this.#e.clear(),this.#h?.abort(),this.#h=void 0,this.#i&&clearTimeout(this.#i),this.#i=void 0}#o(){this.#i&&clearTimeout(this.#i),this.#i=setTimeout(()=>{this.#i=void 0,this.#l()},50)}refresh(){this.#t&&this.#e.delete(this.#t+(this.#s||"{}")),this.#o()}});}`;
21
+ var ROUTER_JS = `{const n=document,a=location,l=t=>t.split("#",1)[0],c=t=>l(t)===l(a.href);customElements.define("m-router",class extends HTMLElement{#t;#e;#s;#i;#n=new Map;#r=!0;async#c(t){this.#n.has(t)&&this.#a(this.#n.get(t));const e=new AbortController,s={"x-route":"true","x-flags":$FLAGS};this.#i?.abort(),this.#i=e;const i=await fetch(t,{headers:s,signal:e.signal});if(i.status===404)return this.#a(this.#t??[]),404;if(!i.ok)throw this.replaceChildren(),new Error("Failed to fetch route: "+i.status+" "+i.statusText);const[r,o]=await i.json();this.#n.set(t,r),this.#a(r),o&&(n.body.appendChild(n.createElement("script")).textContent=o)}#a(t){const e=()=>typeof t=="string"?this.innerHTML=t:this.replaceChildren(...t);this.hasAttribute("vt")&&n.startViewTransition&&!this.#r?n.startViewTransition(e):e(),this.#r=!1}#o(){n.querySelectorAll("nav a").forEach(t=>{const{href:e,classList:s}=t,i=t.closest("nav")?.getAttribute("data-active-class")??"active";c(e)?s.add(i):s.remove(i)})}async#l(t,e){const s=await this.#c(t)===404;e?.replace?history.replaceState({},"",t):history.pushState({},"",t),s&&typeof $signals<"u"&&($signals(0).url=new URL(t)),this.#o(),window.scrollTo(0,0)}navigate(t,e){const s=new URL(t,a.href);if(s.origin!==a.origin){a.href=t;return}c(s.href)||this.#l(t,e)}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:e,href:s,rel:i,target:r}=t.target;e||i==="external"||r==="_blank"||!s.startsWith(a.origin)||(t.preventDefault(),this.navigate(s))},this.#s=()=>this.#l(a.href),addEventListener("popstate",this.#s),n.addEventListener("click",this.#e),setTimeout(()=>this.#o())}disconnectedCallback(){removeEventListener("popstate",this.#s),n.removeEventListener("click",this.#e),this.#i?.abort(),this.#i=void 0,this.#n.clear(),this.#e=void 0,this.#s=void 0}});}`;
22
22
 
23
23
  // runtime/utils.ts
24
24
  var regexpCssBareUnitProps = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;
@@ -46,11 +46,17 @@ var styleToCSS = (style) => {
46
46
  switch (k.charCodeAt(0)) {
47
47
  case /* ':' */
48
48
  58:
49
- css.push(null, k + "{" + renderStyle(v) + "}");
49
+ css.push(k.startsWith("::view-") ? "" : null, k + "{" + renderStyle(v) + "}");
50
50
  break;
51
51
  case /* '@' */
52
52
  64:
53
- css.push(k + "{", null, "{" + renderStyle(v) + "}}");
53
+ if (k.startsWith("@keyframes ") || k.startsWith("@view-")) {
54
+ if (isObject(v)) {
55
+ css.push(k + "{" + Object.entries(v).map(([k2, v2]) => k2 + "{" + renderStyle(v2) + "}").join("") + "}");
56
+ }
57
+ } else {
58
+ css.push(k + "{", null, "{" + renderStyle(v) + "}}");
59
+ }
54
60
  break;
55
61
  case /* '&' */
56
62
  38:
@@ -135,7 +141,7 @@ var $signal = Symbol.for("mono.signal");
135
141
  var $vnode = Symbol.for("jsx.vnode");
136
142
 
137
143
  // version.ts
138
- var VERSION = "0.6.9";
144
+ var VERSION = "0.6.11";
139
145
 
140
146
  // render.ts
141
147
  var cdn = "https://raw.esm.sh";
@@ -434,7 +440,7 @@ async function renderNode(rc, node, stripSlotProp) {
434
440
  case "object":
435
441
  if (node === null) {
436
442
  } else if (isSignal(node)) {
437
- renderSignal(rc, node, void 0, node[$signal].value);
443
+ rc.write(renderSignal(rc, node));
438
444
  } else if (isVNode(node)) {
439
445
  const [tag, props] = node;
440
446
  switch (tag) {
@@ -450,7 +456,7 @@ async function renderNode(rc, node, stripSlotProp) {
450
456
  const { innerHTML } = props;
451
457
  if (innerHTML) {
452
458
  if (isSignal(innerHTML)) {
453
- renderSignal(rc, innerHTML, "html", String(innerHTML[$signal].value), true);
459
+ rc.write(renderSignal(rc, innerHTML, "html"));
454
460
  } else {
455
461
  write(innerHTML);
456
462
  }
@@ -476,7 +482,7 @@ async function renderNode(rc, node, stripSlotProp) {
476
482
  }
477
483
  // `<toggle>` element
478
484
  case "toggle": {
479
- let { show, hidden, children } = props;
485
+ let { show, hidden, viewTransition, children } = props;
480
486
  if (children !== void 0) {
481
487
  if (show === void 0 && hidden !== void 0) {
482
488
  if (isSignal(hidden)) {
@@ -498,13 +504,8 @@ async function renderNode(rc, node, stripSlotProp) {
498
504
  }
499
505
  }
500
506
  if (isSignal(show)) {
501
- const { scope, key, value } = show[$signal];
502
- let buf = '<m-signal mode="toggle" scope="' + scope + '" ';
503
- if (isString(key)) {
504
- buf += "key=" + toAttrStringLit(key) + ">";
505
- } else {
506
- buf += 'computed="' + rc.mcs.gen(show, rc.fcCtx?.scopeId) + '">';
507
- }
507
+ const { value } = show[$signal];
508
+ let buf = renderSignal(rc, show, "toggle", false).slice(0, -1) + renderViewTransitionAttr(viewTransition) + ">";
508
509
  if (!value) {
509
510
  buf += "<template m-slot>";
510
511
  }
@@ -520,19 +521,14 @@ async function renderNode(rc, node, stripSlotProp) {
520
521
  }
521
522
  // `<switch>` element
522
523
  case "switch": {
523
- const { value: valueProp, children } = props;
524
+ const { value: valueProp, viewTransition, children } = props;
524
525
  if (children !== void 0) {
525
526
  let slots = Array.isArray(children) ? isVNode(children) ? [children] : children : [children];
526
- let stateful;
527
+ let signalHtml;
527
528
  let toSlotName;
528
529
  if (isSignal(valueProp)) {
529
- const { scope, key, value } = valueProp[$signal];
530
- stateful = '<m-signal mode="switch" scope="' + scope + '" ';
531
- if (isString(key)) {
532
- stateful += "key=" + toAttrStringLit(key) + ">";
533
- } else {
534
- stateful += 'computed="' + rc.mcs.gen(valueProp, rc.fcCtx?.scopeId) + '">';
535
- }
530
+ const { value } = valueProp[$signal];
531
+ signalHtml = renderSignal(rc, valueProp, "switch", false).slice(0, -1) + renderViewTransitionAttr(viewTransition) + ">";
536
532
  rc.flags.runtime |= RENDER_SWITCH;
537
533
  toSlotName = String(value);
538
534
  } else {
@@ -553,15 +549,15 @@ async function renderNode(rc, node, stripSlotProp) {
553
549
  namedSlots.push(slot);
554
550
  }
555
551
  }
556
- if (stateful) {
557
- write(matchedSlot ? stateful.slice(0, -1) + " match=" + toAttrStringLit(matchedSlot[0]) + ">" : stateful);
552
+ if (signalHtml) {
553
+ write(matchedSlot ? signalHtml.slice(0, -1) + " match=" + toAttrStringLit(matchedSlot[0]) + ">" : signalHtml);
558
554
  }
559
555
  if (matchedSlot) {
560
556
  await renderNode(rc, matchedSlot[1], true);
561
557
  } else if (unnamedSlots.length > 0) {
562
558
  await renderChildren(rc, unnamedSlots);
563
559
  }
564
- if (stateful) {
560
+ if (signalHtml) {
565
561
  if (namedSlots.length > 0 || matchedSlot && unnamedSlots.length > 0) {
566
562
  write("<template m-slot>");
567
563
  await renderChildren(rc, namedSlots);
@@ -577,22 +573,20 @@ async function renderNode(rc, node, stripSlotProp) {
577
573
  }
578
574
  // `<component>` element
579
575
  case "component": {
580
- let { placeholder } = props;
576
+ let { placeholder, viewTransition } = props;
581
577
  let attrs = "";
582
578
  let attrModifiers = "";
583
579
  for (const p of ["name", "props", "ref"]) {
584
580
  let propValue = props[p];
585
581
  let [attr, , attrSignal] = renderAttr(rc, p, propValue);
586
582
  if (attrSignal) {
587
- const write2 = (chunk) => {
588
- attrModifiers += chunk;
589
- };
590
- renderSignal({ ...rc, write: write2 }, attrSignal, [p]);
583
+ attrModifiers += renderSignal(rc, attrSignal, [p]);
591
584
  rc.flags.runtime |= RENDER_ATTR;
592
585
  propValue = attrSignal[$signal].value;
593
586
  }
594
587
  attrs += attr;
595
588
  }
589
+ attrs += renderViewTransitionAttr(viewTransition);
596
590
  let buf = "<m-component" + attrs + ">";
597
591
  if (placeholder) {
598
592
  const write2 = (chunk) => {
@@ -610,10 +604,9 @@ async function renderNode(rc, node, stripSlotProp) {
610
604
  }
611
605
  // `<router>` element
612
606
  case "router": {
607
+ const { children, viewTransition } = props;
613
608
  const { routeFC } = rc;
614
- const { children } = props;
615
- const status = routeFC ? 200 : 404;
616
- write('<m-router status="' + status + '">');
609
+ write('<m-router status="' + (routeFC ? 200 : 404) + '"' + renderViewTransitionAttr(viewTransition) + ">");
617
610
  if (routeFC) {
618
611
  await renderFC(rc, routeFC instanceof Promise ? (await routeFC).default : routeFC, {});
619
612
  }
@@ -651,15 +644,12 @@ async function renderNode(rc, node, stripSlotProp) {
651
644
  if (propName === "children") {
652
645
  continue;
653
646
  }
654
- const [attr, addonHtml, signalValue] = renderAttr(rc, propName, propValue, stripSlotProp);
647
+ const [attr, addonHtml, signalValue, binding] = renderAttr(rc, propName, propValue, stripSlotProp);
655
648
  if (addonHtml) {
656
649
  write(addonHtml);
657
650
  }
658
651
  if (signalValue) {
659
- const write2 = (chunk) => {
660
- attrModifiers += chunk;
661
- };
662
- renderSignal({ ...rc, write: write2 }, signalValue, [propName === "$value" ? "value" : propName]);
652
+ attrModifiers += renderSignal(rc, signalValue, [binding ? propName.slice(1) : propName]);
663
653
  rc.flags.runtime |= RENDER_ATTR;
664
654
  }
665
655
  buffer += attr;
@@ -702,6 +692,7 @@ function renderAttr(rc, attrName, attrValue, stripSlotProp) {
702
692
  let attr = "";
703
693
  let addonHtml = "";
704
694
  let signalValue;
695
+ let binding = false;
705
696
  let scopeId = rc.fcCtx?.scopeId;
706
697
  if (isObject(attrValue)) {
707
698
  let signal;
@@ -793,16 +784,23 @@ function renderAttr(rc, attrName, attrValue, stripSlotProp) {
793
784
  attr = " slot=" + toAttrStringLit(attrValue);
794
785
  }
795
786
  break;
787
+ case "$checked":
796
788
  case "$value":
797
- attr = " value=" + toAttrStringLit(String(attrValue));
789
+ if (!(attrValue === false || attrValue === null || attrValue === void 0)) {
790
+ attr = " " + attrName.slice(1);
791
+ if (attrValue !== true) {
792
+ attr += "=" + toAttrStringLit(String(attrValue));
793
+ }
794
+ }
798
795
  if (signalValue) {
799
796
  const { key } = signalValue[$signal];
800
797
  if (isString(key)) {
801
798
  const fn = () => {
802
799
  };
803
- fn.str = "e=>this[" + toAttrStringLit(key) + "]=e.target.value";
800
+ fn.str = "e=>this[" + toAttrStringLit(key) + "]=e.target." + attrName.slice(1);
804
801
  attr += ' oninput="$emit(event,$MF_' + (scopeId ?? 0) + "_" + rc.mfs.gen(fn, scopeId) + toStr(scopeId, (i) => "," + i) + ')"';
805
802
  }
803
+ binding = true;
806
804
  }
807
805
  break;
808
806
  default:
@@ -816,7 +814,15 @@ function renderAttr(rc, attrName, attrValue, stripSlotProp) {
816
814
  }
817
815
  }
818
816
  }
819
- return [attr, addonHtml, signalValue];
817
+ return [attr, addonHtml, signalValue, binding];
818
+ }
819
+ function renderViewTransitionAttr(viewTransition) {
820
+ if (viewTransition === true || viewTransition === "") {
821
+ return " vt";
822
+ } else if (isString(viewTransition)) {
823
+ return " style=" + toAttrStringLit("view-transition-name:" + viewTransition) + " vt";
824
+ }
825
+ return "";
820
826
  }
821
827
  async function renderFC(rc, fc, props, eager) {
822
828
  const { write } = rc;
@@ -904,17 +910,14 @@ async function renderFC(rc, fc, props, eager) {
904
910
  }
905
911
  }
906
912
  }
907
- function renderSignal(rc, signal, mode, content, html2) {
908
- const { scope, key } = signal[$signal];
913
+ function renderSignal(rc, signal, mode, close) {
914
+ const { scope, key, value } = signal[$signal];
909
915
  let buffer = "<m-signal";
910
916
  if (mode) {
911
- buffer += ' mode="';
912
- if (isString(mode)) {
913
- buffer += mode;
914
- } else {
915
- buffer += "[" + mode[0] + "]";
917
+ if (Array.isArray(mode)) {
918
+ mode = "[" + mode[0] + "]";
916
919
  }
917
- buffer += '"';
920
+ buffer += ' mode="' + mode + '"';
918
921
  }
919
922
  buffer += ' scope="' + scope + '"';
920
923
  if (isString(key)) {
@@ -922,9 +925,26 @@ function renderSignal(rc, signal, mode, content, html2) {
922
925
  } else {
923
926
  buffer += ' computed="' + rc.mcs.gen(signal, rc.fcCtx?.scopeId) + '"';
924
927
  }
925
- rc.write(buffer + ">" + (html2 ? content : escapeHTML(String(content ?? ""))) + "</m-signal>");
928
+ buffer += ">";
929
+ if (!mode || mode === "html") {
930
+ let text;
931
+ switch (typeof value) {
932
+ case "string":
933
+ text = value;
934
+ break;
935
+ case "number":
936
+ case "bigint": {
937
+ text = String(value);
938
+ break;
939
+ }
940
+ }
941
+ if (text) {
942
+ buffer += !mode ? escapeHTML(text) : text;
943
+ }
944
+ }
945
+ return buffer + (close !== false ? "</m-signal>" : "");
926
946
  }
927
- var collectDeps;
947
+ var collectDep;
928
948
  function Signal(scope, key, value) {
929
949
  const signal = { scope, key, value };
930
950
  return new Proxy(new NullProtoObj(), {
@@ -963,9 +983,9 @@ function createSignals(scopeId, appSignals, context = new NullProtoObj(), reques
963
983
  });
964
984
  const computed = (compute) => {
965
985
  const deps = /* @__PURE__ */ new Set();
966
- collectDeps = (scopeId2, key) => deps.add(scopeId2 + ":" + key);
986
+ collectDep = (scopeId2, key) => deps.add(scopeId2 + ":" + key);
967
987
  const value = compute.call(thisProxy);
968
- collectDeps = void 0;
988
+ collectDep = void 0;
969
989
  return Signal(scopeId, { compute, deps }, value);
970
990
  };
971
991
  const markEffect = (effect) => {
@@ -1009,7 +1029,7 @@ function createSignals(scopeId, appSignals, context = new NullProtoObj(), reques
1009
1029
  return mark;
1010
1030
  case "url":
1011
1031
  if (scopeId === 0) {
1012
- collectDeps?.(0, key);
1032
+ collectDep?.(0, key);
1013
1033
  return request ? request.URL ?? (request.URL = new URL(request.url)) : void 0;
1014
1034
  }
1015
1035
  // fallthrough
@@ -1021,8 +1041,8 @@ function createSignals(scopeId, appSignals, context = new NullProtoObj(), reques
1021
1041
  if (value === void 0 && !Reflect.has(target, key)) {
1022
1042
  Reflect.set(target, key, void 0, receiver);
1023
1043
  }
1024
- if (collectDeps) {
1025
- collectDeps(scopeId, key);
1044
+ if (collectDep) {
1045
+ collectDep(scopeId, key);
1026
1046
  return value;
1027
1047
  }
1028
1048
  let signal = signals.get(key);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mono-jsx",
3
- "version": "0.6.10",
3
+ "version": "0.6.12",
4
4
  "description": "`<html>` as a `Response`.",
5
5
  "type": "module",
6
6
  "module": "./index.mjs",
package/types/html.d.ts CHANGED
@@ -44,7 +44,9 @@ export namespace HTML {
44
44
 
45
45
  /** Global HTML attributes from https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes */
46
46
  interface GlobalAttributes<T extends EventTarget> extends EventAttributes<T>, Aria.Attributes, Mono.BaseAttributes, JSX.HtmlTag {
47
- // @mono-jsx
47
+ /** @mono-jsx
48
+ * A reference to the element.
49
+ */
48
50
  ref?: HTMLElement | ((el: T) => unknown);
49
51
  /** Defines a unique identifier (ID) which must be unique in the whole document. Its purpose is to identify the element when linking (using a fragment identifier), scripting, or styling (with CSS). */
50
52
  id?: string;
@@ -122,7 +124,8 @@ export namespace HTML {
122
124
  }
123
125
 
124
126
  interface NavAttributes<T extends EventTarget> extends GlobalAttributes<T> {
125
- /** @mono-jsx: This attribute is used to specify the class name for the active link. */
127
+ /** @mono-jsx
128
+ * This attribute is used to specify the class name for the active link. */
126
129
  "data-active-class"?: string;
127
130
  }
128
131
 
@@ -185,7 +188,7 @@ export namespace HTML {
185
188
  src?: string;
186
189
  step?: number | string;
187
190
  type?: InputType;
188
- value?: string | number | ReadonlyArray<string | number>;
191
+ value?: string | number;
189
192
  width?: number | string;
190
193
  /**
191
194
  * Turns a <button> or <input> element into a popover control button; takes the ID of the popover element to control as its value.
@@ -202,10 +205,15 @@ export namespace HTML {
202
205
  */
203
206
  onSearch?: EventHandler<Event, T>;
204
207
  /**
205
- * @mono-jsx: Two-way binding prop that automatically creates value and oninput attributes for signal binding
206
- * Similar to Vue's v-model
208
+ * @mono-jsx
209
+ * Two-way binding prop that automatically creates checked and oninput attributes for signal binding
207
210
  */
208
- $value?: string | number | ReadonlyArray<string | number>;
211
+ $checked?: boolean;
212
+ /**
213
+ * @mono-jsx
214
+ * Two-way binding prop that automatically creates value and oninput attributes for signal binding
215
+ */
216
+ $value?: string | number;
209
217
  }
210
218
 
211
219
  interface OptionAttributes<T extends EventTarget> extends GlobalAttributes<T> {
@@ -223,12 +231,12 @@ export namespace HTML {
223
231
  name?: string;
224
232
  required?: boolean;
225
233
  size?: number;
226
- value?: string | number | ReadonlyArray<string | number>;
234
+ value?: string | number;
227
235
  /**
228
- * @mono-jsx: Two-way binding prop that automatically creates value and oninput attributes for signal binding
229
- * Similar to Vue's v-model
236
+ * @mono-jsx
237
+ * Two-way binding prop that automatically creates value and oninput attributes for signal binding
230
238
  */
231
- $value?: string | number | ReadonlyArray<string | number>;
239
+ $value?: string | number;
232
240
  }
233
241
 
234
242
  interface TextareaAttributes<T extends EventTarget> extends GlobalAttributes<T> {
@@ -248,8 +256,8 @@ export namespace HTML {
248
256
  wrap?: string;
249
257
  onChange?: EventHandler<Event, T>;
250
258
  /**
251
- * @mono-jsx: Two-way binding prop that automatically creates value and oninput attributes for signal binding
252
- * Similar to Vue's v-model
259
+ * @mono-jsx
260
+ * Two-way binding prop that automatically creates value and oninput attributes for signal binding
253
261
  */
254
262
  $value?: string;
255
263
  }
@@ -319,7 +327,7 @@ export namespace HTML {
319
327
  }
320
328
 
321
329
  interface DataAttributes<T extends EventTarget> extends GlobalAttributes<T> {
322
- value?: string | ReadonlyArray<string> | number;
330
+ value?: string | number;
323
331
  }
324
332
 
325
333
  interface DetailsAttributes<T extends EventTarget> extends GlobalAttributes<T> {
@@ -379,7 +387,7 @@ export namespace HTML {
379
387
  }
380
388
 
381
389
  interface LiAttributes<T extends EventTarget> extends GlobalAttributes<T> {
382
- value?: string | ReadonlyArray<string> | number;
390
+ value?: string | number;
383
391
  }
384
392
 
385
393
  interface LinkAttributes<T extends EventTarget> extends GlobalAttributes<T>, LoaderElementAttributes<T> {
@@ -444,6 +452,7 @@ export namespace HTML {
444
452
  interface MetaAttributes<T extends EventTarget> extends GlobalAttributes<T> {
445
453
  charSet?: string;
446
454
  httpEquiv?: string;
455
+ property?: string;
447
456
  name?: string;
448
457
  content?: string;
449
458
  media?: string;
@@ -456,7 +465,7 @@ export namespace HTML {
456
465
  max?: number | string;
457
466
  min?: number | string;
458
467
  optimum?: number;
459
- value?: string | ReadonlyArray<string> | number;
468
+ value?: string | number;
460
469
  }
461
470
 
462
471
  interface QuoteAttributes<T extends EventTarget> extends GlobalAttributes<T> {
@@ -494,7 +503,7 @@ export namespace HTML {
494
503
 
495
504
  interface ProgressAttributes<T extends EventTarget> extends GlobalAttributes<T> {
496
505
  max?: number | string;
497
- value?: string | ReadonlyArray<string> | number;
506
+ value?: string | number;
498
507
  }
499
508
 
500
509
  interface SlotAttributes<T extends EventTarget> extends GlobalAttributes<T> {
@@ -2,7 +2,7 @@ import type { FC, VNode } from "./jsx.d.ts";
2
2
 
3
3
  export const html: JSX.Raw;
4
4
  export const JSX: typeof globalThis.JSX;
5
- export const Fragment: (props: Record<string, unknown>) => VNode;
5
+ export const Fragment: (props: {}) => VNode;
6
6
  export const jsx: (tag: string | FC, props: Record<string, unknown>, key?: string | number) => VNode;
7
7
 
8
8
  export { html as css, html as js, jsx as jsxDEV, jsx as jsxs };
package/types/mono.d.ts CHANGED
@@ -24,10 +24,10 @@ export interface BaseCSSProperties extends CSS.Properties<string | number> {
24
24
  export interface AtRuleCSSProperties {
25
25
  [key: `@container${" " | "("}${string}`]: BaseCSSProperties;
26
26
  [key: `@media${" " | "("}${string}`]: BaseCSSProperties;
27
+ [key: `@supports${" " | "("}${string}`]: BaseCSSProperties;
27
28
  [key: `@keyframes ${string}`]: {
28
29
  [key in "from" | "to" | `${D100}%`]?: BaseCSSProperties;
29
30
  };
30
- [key: `@supports${" " | "("}${string}`]: BaseCSSProperties;
31
31
  "@view-transition"?: {
32
32
  /**
33
33
  * Specifies the effect this at-rule will have on the document's view transition behavior.
@@ -118,6 +118,7 @@ export interface Elements {
118
118
  toggle: BaseAttributes & {
119
119
  show?: any;
120
120
  hidden?: any;
121
+ viewTransition?: string | boolean;
121
122
  };
122
123
  /**
123
124
  * The `switch` element is a built-in element that chooses one of its children based on the `slot` attribute to display.
@@ -125,6 +126,7 @@ export interface Elements {
125
126
  */
126
127
  switch: BaseAttributes & {
127
128
  value?: string | number | boolean | null;
129
+ viewTransition?: string | boolean;
128
130
  };
129
131
  /**
130
132
  * The `component` element is a built-in element that is used to load components lazily,
@@ -134,6 +136,7 @@ export interface Elements {
134
136
  name?: string;
135
137
  props?: Record<string, unknown>;
136
138
  ref?: ComponentElement | ((el: ComponentElement) => void);
139
+ viewTransition?: string | boolean;
137
140
  };
138
141
  /**
139
142
  * The `router` element is a built-in element that implements client-side routing.
@@ -144,6 +147,7 @@ export interface Elements {
144
147
  */
145
148
  base?: string;
146
149
  ref?: RouterElement | ((el: RouterElement) => void);
150
+ viewTransition?: string | boolean;
147
151
  };
148
152
  }
149
153