mono-jsx 0.8.0-beta.13 → 0.8.0-beta.15
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 +27 -9
- package/jsx-runtime.mjs +11 -6
- package/package.json +1 -1
- package/types/jsx.d.ts +5 -0
- package/types/mono.d.ts +10 -2
package/README.md
CHANGED
|
@@ -1103,12 +1103,12 @@ async function Login(this: FC) {
|
|
|
1103
1103
|
You can also return regular HTML elements from the route form post response. The `formslot` element is used to
|
|
1104
1104
|
mark the position where the returned HTML elements will be inserted.
|
|
1105
1105
|
|
|
1106
|
-
- `<formslot mode="
|
|
1106
|
+
- `<formslot mode="replaceChildren" />`: Replace the `formslot` element's children with the HTML. This is the default mode.
|
|
1107
1107
|
- `<formslot mode="insertafter" />`: Insert HTML after the `formslot` element.
|
|
1108
|
-
- `<formslot mode="
|
|
1108
|
+
- `<formslot mode="insertbefore" />`: Insert HTML before the `formslot` element.
|
|
1109
1109
|
|
|
1110
1110
|
```tsx
|
|
1111
|
-
function
|
|
1111
|
+
function MyFormPage(this: FC) {
|
|
1112
1112
|
if (this.form) {
|
|
1113
1113
|
const message = this.form.get("message") as string | null;
|
|
1114
1114
|
if (!message) {
|
|
@@ -1117,12 +1117,30 @@ function FormSlot(this: FC) {
|
|
|
1117
1117
|
return <p>{message}</p>
|
|
1118
1118
|
}
|
|
1119
1119
|
return (
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1120
|
+
<form route>
|
|
1121
|
+
{/* <- new message will be inserted here */}
|
|
1122
|
+
<formslot mode="insertbefore" />
|
|
1123
|
+
<input type="text" name="message" placeholder="Type Message..." style={{ ":invalid": { borderColor: "red" } }} />
|
|
1124
|
+
<button type="submit">Send</button>
|
|
1125
|
+
</form>
|
|
1126
|
+
)
|
|
1127
|
+
}
|
|
1128
|
+
```
|
|
1129
|
+
|
|
1130
|
+
You can also use the `name` attribute to specify the name of the formslot element. And you can use the `slot` attribute to specify the name of the slot to insert the HTML into.
|
|
1131
|
+
|
|
1132
|
+
```tsx
|
|
1133
|
+
function MyFormPage(this: FC) {
|
|
1134
|
+
if (this.form) {
|
|
1135
|
+
return <p slot="message">Hello, world!</p>
|
|
1136
|
+
}
|
|
1137
|
+
return (
|
|
1138
|
+
<div>
|
|
1139
|
+
<formslot name="message" />
|
|
1140
|
+
<form route>
|
|
1141
|
+
<button type="submit">Send</button>
|
|
1142
|
+
</form>
|
|
1143
|
+
</div>
|
|
1126
1144
|
)
|
|
1127
1145
|
}
|
|
1128
1146
|
```
|
package/jsx-runtime.mjs
CHANGED
|
@@ -30,7 +30,7 @@ var SIGNALS_JS = `{let m;const w=window,p=document,y=new Map,k=new Map,l=n=>k.ge
|
|
|
30
30
|
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())})});}`;
|
|
31
31
|
var COMPONENT_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()}});}`;
|
|
32
32
|
var ROUTER_JS = `{const n=document,a=location,o=t=>t.split("#",1)[0],l=t=>o(t)===o(a.href);customElements.define("m-router",class extends HTMLElement{#t;#s;#i;#n;#e=new Map;#r=!0;async#c(t){const s=new AbortController,i={"x-route":"true","x-flags":$FLAGS};this.#n?.abort(),this.#n=s;const e=await fetch(t,{headers:i,signal:s.signal});if(e.status===404)return null;if(!e.ok)throw this.replaceChildren(),new Error("Failed to fetch route: "+e.status+" "+e.statusText);return e.json()}#a(t){const s=()=>typeof t=="string"?this.innerHTML=t:this.replaceChildren(...t);this.hasAttribute("vt")&&n.startViewTransition&&!this.#r?n.startViewTransition(s):s(),this.#r=!1}#o(){n.querySelectorAll("nav a").forEach(t=>{const{href:s,classList:i}=t,e=t.closest("nav")?.getAttribute("data-active-class")??"active";l(s)?i.add(e):i.remove(e)})}async#l(t,s){const i=this.#c(t).then(e=>{if(e){const[r,c]=e;return this.#e.set(t,r),this.#a(r),c}else this.#e.delete(t),this.#a(this.#t??[]),typeof $signals<"u"&&($signals(0).url=new URL(t))});this.#e.has(t)?this.#a(this.#e.get(t)):await i,history[s?.replace?"replaceState":"pushState"]({},"",t),this.#o(),window.scrollTo(0,0),i.then(e=>{e&&(n.body.appendChild(n.createElement("script")).textContent=e)})}navigate(t,s){const i=new URL(t,a.href);if(i.origin!==a.origin){a.href=t;return}l(i.href)||this.#l(t,s)}connectedCallback(){setTimeout(()=>{if(!this.#t)if(this.hasAttribute("fallback"))this.removeAttribute("fallback"),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.#s=t=>{if(t.defaultPrevented||t.altKey||t.ctrlKey||t.metaKey||t.shiftKey||!(t.target instanceof HTMLAnchorElement))return;const{download:s,href:i,rel:e,target:r}=t.target;s||e==="external"||r==="_blank"||!i.startsWith(a.origin)||(t.preventDefault(),this.navigate(i))},this.#i=()=>this.#l(a.href),addEventListener("popstate",this.#i),n.addEventListener("click",this.#s),setTimeout(()=>this.#o()),globalThis.$router=this}disconnectedCallback(){removeEventListener("popstate",this.#i),n.removeEventListener("click",this.#s),delete globalThis.$router,this.#n?.abort(),this.#n=void 0,this.#e.clear(),this.#s=void 0,this.#i=void 0}});}`;
|
|
33
|
-
var FORM_JS = `{
|
|
33
|
+
var FORM_JS = `{customElements.define("m-invalid",class extends HTMLElement{connectedCallback(){const s=this.getAttribute("for"),t=this.closest("form"),i=this.textContent;if(s&&t&&i)for(const l of s.split(",")){const o=t.elements.namedItem(l.trim());if(o){const r=()=>{o.removeEventListener("input",r),o.setCustomValidity("")};o.addEventListener("input",r),o.setCustomValidity(i),o.focus()}}this.remove()}}),window.$onrfs=async s=>{s.preventDefault();const t=s.target;if(!t.checkValidity())return;const i=new FormData(t),l=[...t.elements];for(const e of l)e._disabled=e.disabled,e.disabled=!0;const o=await fetch(location.href,{method:"POST",headers:{"x-route-form":"true","x-flags":$FLAGS},body:i}),[r,m]=await o.json(),f=document.createElement("template"),u=new Map;f.innerHTML=r;for(const e of l)e.disabled=e._disabled,delete e._disabled;for(const e of f.content.childNodes){if(e.nodeType===1){const n=e,a=n.getAttribute("formslot"),d=a?'m-formslot[name="'+a+'"]':"m-formslot",c=a?t.querySelector(d)??document.querySelector(d):t.querySelector(d);if(c){c.innerHTML="",u.set(n,c);continue}}t.appendChild(e)}for(const[e,n]of u)switch(n.getAttribute("mode")){case"insertbefore":n.before(e);break;case"insertafter":n.after(e);break;default:n.appendChild(e)}setTimeout(()=>{l.some(e=>!e.validity.valid)||t.reset()},0),m&&(document.body.appendChild(document.createElement("script")).textContent=m)};}`;
|
|
34
34
|
|
|
35
35
|
// runtime/utils.ts
|
|
36
36
|
var regexpIsNonDimensional = /^(-|f[lo].*[^se]$|g.{5,}[^ps]$|z|o[pr]|(W.{5})?[lL]i.*(t|mp)$|an|(bo|s).{4}Im|sca|m.{6}[ds]|ta|c.*[st]$|wido|ini)/;
|
|
@@ -176,7 +176,7 @@ var $vnode = Symbol.for("jsx.vnode");
|
|
|
176
176
|
var $setup = Symbol.for("mono.setup");
|
|
177
177
|
|
|
178
178
|
// version.ts
|
|
179
|
-
var VERSION = "0.8.0-beta.
|
|
179
|
+
var VERSION = "0.8.0-beta.15";
|
|
180
180
|
|
|
181
181
|
// render.ts
|
|
182
182
|
var cdn = "https://raw.esm.sh";
|
|
@@ -745,7 +745,9 @@ async function renderNode(rc, node, stripSlotProp) {
|
|
|
745
745
|
const now = Date.now();
|
|
746
746
|
const value = cache.get(key);
|
|
747
747
|
if (value && (!value.expires || value.expires > now)) {
|
|
748
|
+
write("<!-- cached -->");
|
|
748
749
|
write(value.html);
|
|
750
|
+
write("<!-- /cached -->");
|
|
749
751
|
} else {
|
|
750
752
|
let buf = "";
|
|
751
753
|
await renderChildren(
|
|
@@ -778,16 +780,19 @@ async function renderNode(rc, node, stripSlotProp) {
|
|
|
778
780
|
}
|
|
779
781
|
case "invalid":
|
|
780
782
|
case "formslot": {
|
|
781
|
-
const { children, for: forProp
|
|
783
|
+
const { children, name, mode, for: forProp } = props;
|
|
782
784
|
let buf = "<m-" + tag;
|
|
785
|
+
if (isString(name)) {
|
|
786
|
+
buf += " name=" + toAttrStringLit(name);
|
|
787
|
+
}
|
|
788
|
+
if (isString(mode)) {
|
|
789
|
+
buf += " mode=" + toAttrStringLit(mode);
|
|
790
|
+
}
|
|
783
791
|
if (isString(forProp)) {
|
|
784
792
|
buf += " for=" + toAttrStringLit(forProp) + " hidden";
|
|
785
793
|
} else if (tag === "invalid") {
|
|
786
794
|
break;
|
|
787
795
|
}
|
|
788
|
-
if (isString(mode)) {
|
|
789
|
-
buf += " mode=" + toAttrStringLit(mode);
|
|
790
|
-
}
|
|
791
796
|
buf += ">";
|
|
792
797
|
if (children) {
|
|
793
798
|
await renderChildren({
|
package/package.json
CHANGED
package/types/jsx.d.ts
CHANGED
|
@@ -18,6 +18,11 @@ export interface BaseAttributes {
|
|
|
18
18
|
* The `slot` attribute assigns a slot in a [shadow DOM](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM) shadow tree to an element: An element with a `slot` attribute is assigned to the slot created by the `<slot>` element whose name attribute's value matches that slot attribute's value.
|
|
19
19
|
*/
|
|
20
20
|
slot?: string;
|
|
21
|
+
/**
|
|
22
|
+
* The `formslot` attribute assigns a named formslot element to an element.
|
|
23
|
+
* @mono-jsx
|
|
24
|
+
*/
|
|
25
|
+
formslot?: string;
|
|
21
26
|
/**
|
|
22
27
|
* The `portal` attribute is used to mount the component to a specified DOM element.
|
|
23
28
|
* @mono-jsx
|
package/types/mono.d.ts
CHANGED
|
@@ -151,9 +151,17 @@ export interface Elements {
|
|
|
151
151
|
*/
|
|
152
152
|
formslot: BaseAttributes & {
|
|
153
153
|
/**
|
|
154
|
-
* The
|
|
154
|
+
* The name of the formslot element.
|
|
155
155
|
*/
|
|
156
|
-
|
|
156
|
+
name?: string;
|
|
157
|
+
/**
|
|
158
|
+
* The insert mode of the formslot.
|
|
159
|
+
* - "insertbefore": Insert HTML before the formslot element.
|
|
160
|
+
* - "insertafter": Insert HTML after the formslot element.
|
|
161
|
+
* - "replaceChildren": Replace the formslot element's children with the HTML.
|
|
162
|
+
* @default "replaceChildren"
|
|
163
|
+
*/
|
|
164
|
+
mode?: "insertbefore" | "insertafter" | "replaceChildren";
|
|
157
165
|
};
|
|
158
166
|
}
|
|
159
167
|
|