mono-jsx 0.2.0 → 0.3.1

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/jsx-runtime.mjs CHANGED
@@ -6,19 +6,21 @@ var $state = Symbol.for("mono.state");
6
6
  var $computed = Symbol.for("mono.computed");
7
7
 
8
8
  // state.ts
9
- function createState(context, request) {
10
- let collectDeps;
9
+ var collectDeps;
10
+ function createState(fc, appState, context, request) {
11
11
  const computed = (fn) => {
12
12
  const deps = /* @__PURE__ */ Object.create(null);
13
- collectDeps = (key, value2) => deps[key] = value2;
14
- const value = fn();
13
+ collectDeps = (fc2, key, value2) => deps[fc2 + ":" + key] = value2;
14
+ const value = fn.call(proxy);
15
15
  collectDeps = void 0;
16
- if (deps.size === 0) return value;
17
- return [$computed, { value, deps, fn: fn.toString() }, $vnode];
16
+ if (value instanceof Promise || deps.size === 0) return value;
17
+ return [$computed, { value, deps, fn: fn.toString(), fc }, $vnode];
18
18
  };
19
- return new Proxy(/* @__PURE__ */ Object.create(null), {
19
+ const proxy = new Proxy(/* @__PURE__ */ Object.create(null), {
20
20
  get(target, key, receiver) {
21
21
  switch (key) {
22
+ case "app":
23
+ return appState;
22
24
  case "context":
23
25
  return context ?? {};
24
26
  case "request":
@@ -34,31 +36,30 @@ function createState(context, request) {
34
36
  return value;
35
37
  }
36
38
  if (collectDeps) {
37
- collectDeps(key, value);
39
+ collectDeps(fc, key, value);
38
40
  return value;
39
41
  }
40
- return [$state, { key, value }, $vnode];
42
+ return [$state, { key, value, fc }, $vnode];
41
43
  }
42
44
  }
43
45
  },
44
46
  set(target, key, value, receiver) {
45
- const vt = typeof value;
46
- value = vt === "boolean" || vt === "number" || vt === "bigint" ? value : structuredClone(value);
47
47
  return Reflect.set(target, key, value, receiver);
48
48
  }
49
49
  });
50
+ return proxy;
50
51
  }
51
52
 
52
53
  // runtime/index.ts
53
- var RUNTIME_STATE_JS = `const p=(e,i)=>e.getAttribute(i),m=(e,i)=>e.hasAttribute(i),M=new Map,T=e=>M.get(e)??M.set(e,L()).get(e);function L(){const e=Object.create(null),i=new Map;function f(n,o){let a=o;Object.defineProperty(e,n,{get:()=>a,set:u=>{if(u!==a){const r=i.get(n);r&&queueMicrotask(()=>r.forEach(s=>s())),a=u}}})}function d(n,o,a,u){let r;if(o==="toggle"){let s;r=()=>{if(!s){const t=n.firstElementChild;t&&t.tagName==="TEMPLATE"&&m(t,"m-slot")?(s=t.content.childNodes,n.innerHTML=""):s=n.childNodes}a()?n.append(...s):n.innerHTML=""}}else if(o==="switch"){let s=p(n,"match"),t,l,E=c=>t.get(c)??t.set(c,[]).get(c),h;r=()=>{if(!t){t=new Map,l=[];for(const c of n.childNodes)if(c.nodeType===1&&c.tagName==="TEMPLATE"&&m(c,"m-slot")){for(const g of c.content.childNodes)g.nodeType===1&&m(g,"slot")?E(p(g,"slot")).push(g):l.push(g);c.remove()}else s?E(s).push(c):l.push(c)}h=a(),n.innerHTML="",n.append(...t.has(h)?t.get(h):l)}}else if(o&&o.length>2&&o.startsWith("[")&&o.endsWith("]")){let s=o.slice(1,-1),t=n.parentElement;t.tagName==="M-GROUP"&&(t=t.previousElementSibling),r=()=>{const l=a();l===!1?t.removeAttribute(s):(s==="class"||s==="style")&&l&&typeof l=="object"?t.setAttribute(s,s==="class"?cx(l):styleToCSS(l)):t.setAttribute(s,l===!0?"":""+l)}}else r=()=>n.textContent=""+a();if(r)for(const s of u){let t=i.get(s);t||(t=[],i.set(s,t)),t.push(r)}}return{store:e,define:f,createEffect:d}}customElements.define("m-state",class extends HTMLElement{connectedCallback(){const e=this,i=p(e,"mode"),f=p(e,"key"),d=T(p(e,"fc"));f?d.createEffect(e,i,()=>d.store[f],[f]):m(e,"computed")&&setTimeout(()=>{const n=e.firstChild;if(n&&n.nodeType===1&&n.type==="computed"){const o=n.textContent;o&&new Function("$",o).call(d.store,(a,u)=>d.createEffect(e,i,a,u))}})}}),Object.assign(globalThis,{$state:e=>T(e).store,$defineState:(e,i)=>{const f=e.indexOf(":");f>0&&T(e.slice(0,f)).define(e.slice(f+1),i)}});`;
54
- var RUNTIME_SUSPENSE_JS = `const n={},o=e=>e.getAttribute("chunk-id");c("m-portal",e=>{n[o(e)]=e}),c("m-chunk",e=>{const t=o(e),s=n[t];s&&setTimeout(()=>{s.replaceWith(...e.firstChild.content.childNodes),delete n[t],e.remove()})});function c(e,t){customElements.define(e,class extends HTMLElement{connectedCallback(){t(this)}})}`;
55
- var RUNTIME_COMPONENTS_JS = {
54
+ var STATE_JS = `const p=new Map,f=e=>p.get(e)??p.set(e,E(e)).get(e),u=(e,t)=>e.getAttribute(t),d=(e,t)=>e.hasAttribute(t),E=e=>{const t=Object.create(null),l=new Map,s=(i,c)=>{let r=c;Object.defineProperty(t,i,{get:()=>r,set:o=>{if(o!==r){const a=l.get(i);a&&queueMicrotask(()=>a.forEach(m=>m())),r=o}}})},n=(i,c)=>{let r=l.get(i);r||(r=[],l.set(i,r)),r.push(c)};return e>0&&Object.defineProperty(t,"app",{get:()=>f(0).store,enumerable:!1,configurable:!1}),{store:t,define:s,watch:n}},g=(e,t,l)=>{if(t==="toggle"){let s;return()=>{if(!s){const n=e.firstElementChild;n&&n.tagName==="TEMPLATE"&&d(n,"m-slot")?(s=n.content.childNodes,e.innerHTML=""):s=e.childNodes}l()?e.append(...s):e.innerHTML=""}}if(t==="switch"){let s=u(e,"match"),n,i,c=o=>n.get(o)??n.set(o,[]).get(o),r;return()=>{if(!n){n=new Map,i=[];for(const o of e.childNodes)if(o.nodeType===1&&o.tagName==="TEMPLATE"&&d(o,"m-slot")){for(const a of o.content.childNodes)a.nodeType===1&&d(a,"slot")?c(u(a,"slot")).push(a):i.push(a);o.remove()}else s?c(s).push(o):i.push(o)}r=l(),e.innerHTML="",e.append(...n.has(r)?n.get(r):i)}}if(t&&t.length>2&&t.startsWith("[")&&t.endsWith("]")){let s=t.slice(1,-1),n=e.parentElement;return n.tagName==="M-GROUP"&&(n=n.previousElementSibling),()=>{const i=l();i===!1?n.removeAttribute(s):(s==="class"||s==="style")&&i&&typeof i=="object"?n.setAttribute(s,s==="class"?cx(i):styleToCSS(i)):n.setAttribute(s,i===!0?"":""+i)}}return()=>e.textContent=""+l()},h=e=>{const t=e.indexOf(":");if(t>0)return[Number(e.slice(0,t)),e.slice(t+1)];throw new Error("Invalid state key")};customElements.define("m-state",class extends HTMLElement{connectedCallback(){const e=this,t=f(Number(u(e,"fc"))),l=u(e,"mode"),s=u(e,"key");s?t.watch(s,g(e,l,()=>t.store[s])):d(e,"computed")&&setTimeout(()=>{const n=e.firstChild;if(n&&n.nodeType===1&&n.type==="computed"){const i=n.textContent;i&&new Function("$",i).call(t.store,(c,r)=>{const o=g(e,l,c);for(const a of r){const[m,T]=h(a);f(m).watch(T,o)}})}})}}),Object.assign(globalThis,{$state:e=>e!==void 0?f(e).store:void 0,$defineState:(e,t)=>{const[l,s]=h(e);f(l).define(s,t)}});`;
55
+ var SUSPENSE_JS = `const n={},o=e=>e.getAttribute("chunk-id");c("m-portal",e=>{n[o(e)]=e}),c("m-chunk",e=>{const t=o(e),s=n[t];s&&setTimeout(()=>{s.replaceWith(...e.firstChild.content.childNodes),delete n[t],e.remove()})});function c(e,t){customElements.define(e,class extends HTMLElement{connectedCallback(){t(this)}})}`;
56
+ var UTILS_JS = {
56
57
  /** cx.js (239 bytes) */
57
- cx: `var cx=(()=>{var n=e=>typeof e=="string",o=e=>typeof e=="object"&&e!==null;function t(e){return n(e)?e:o(e)?Array.isArray(e)?e.map(t).filter(Boolean).join(" "):Object.entries(e).filter(([,r])=>!!r).map(([r])=>r).join(" "):""}return t;})();`,
58
+ cx: `let cx=(()=>{var n=e=>typeof e=="string",o=e=>typeof e=="object"&&e!==null;function t(e){return n(e)?e:o(e)?Array.isArray(e)?e.map(t).filter(Boolean).join(" "):Object.entries(e).filter(([,r])=>!!r).map(([r])=>r).join(" "):""}return t;})();`,
58
59
  /** styleToCSS.js (1203 bytes) */
59
- styleToCSS: `var styleToCSS=(()=>{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"]),s=e=>typeof e=="string",u=e=>typeof e=="object"&&e!==null,f=e=>e.replace(/[a-z][A-Z]/g,r=>r.charAt(0)+"-"+r.charAt(1).toLowerCase());function l(e){if(s(e))return e;if(u(e)){let r="";for(let[o,t]of Array.isArray(e)?e:Object.entries(e)){if(t==null||t===!1||Number.isNaN(t)||!s(o))return"";let n=f(o),i=typeof t=="number"?c.has(n)?""+t:t+"px":a(""+t);r+=(r!==""?";":"")+a(n)+":"+(n==="content"?JSON.stringify(i):i)}return r}return""}function a(e){return e.replace(/["<>]/g,r=>r==="<"?"&lt;":r===">"?"&gt;":"'")}return l;})();`,
60
- /** event.js (176 bytes) */
61
- event: `window.$emit=(evt,el,fn,fc)=>fn.call(window.$state?.(fc)??el,evt);window.$onsubmit=(evt,el,fn,fc)=>{evt.preventDefault();fn.call(window.$state?.(fc)??el,new FormData(el),evt)};`
60
+ styleToCSS: `let styleToCSS=(()=>{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"]),s=e=>typeof e=="string",u=e=>typeof e=="object"&&e!==null,f=e=>e.replace(/[a-z][A-Z]/g,r=>r.charAt(0)+"-"+r.charAt(1).toLowerCase());function l(e){if(s(e))return e;if(u(e)){let r="";for(let[o,t]of Array.isArray(e)?e:Object.entries(e)){if(t==null||t===!1||Number.isNaN(t)||!s(o))return"";let n=f(o),i=typeof t=="number"?c.has(n)?""+t:t+"px":a(""+t);r+=(r!==""?";":"")+a(n)+":"+(n==="content"?JSON.stringify(i):i)}return r}return""}function a(e){return e.replace(/["<>]/g,r=>r==="<"?"&lt;":r===">"?"&gt;":"'")}return l;})();`,
61
+ /** event.js (169 bytes) */
62
+ event: `let w=window;w.$emit=(evt,el,fn,fc)=>fn.call(w.$state?.(fc)??el,evt);w.$onsubmit=(evt,el,fn,fc)=>{evt.preventDefault();fn.call(w.$state?.(fc)??el,new FormData(el),evt)};`
62
63
  };
63
64
 
64
65
  // runtime/utils.ts
@@ -191,9 +192,9 @@ var regexpHtmlTag = /^[a-z][\w\-$]*$/;
191
192
  var selfClosingTags = new Set("area,base,br,col,embed,hr,img,input,keygen,link,meta,param,source,track,wbr".split(","));
192
193
  var isVNode = (v) => Array.isArray(v) && v.length === 3 && v[2] === $vnode;
193
194
  var hashCode = (s) => [...s].reduce((hash, c) => Math.imul(31, hash) + c.charCodeAt(0) | 0, 0);
194
- var toAttrStringLit = (str) => '"' + escapeHTML(str).replaceAll('"', '\\"') + '"';
195
- async function renderNode(ctx, node, stripSlotProp) {
196
- const { write, stateStore } = ctx;
195
+ var toAttrStringLit = (str) => '"' + escapeHTML(str) + '"';
196
+ async function renderNode(rc, node, stripSlotProp) {
197
+ const { write } = rc;
197
198
  switch (typeof node) {
198
199
  case "string":
199
200
  write(escapeHTML(node));
@@ -204,11 +205,11 @@ async function renderNode(ctx, node, stripSlotProp) {
204
205
  break;
205
206
  case "object":
206
207
  if (isVNode(node)) {
207
- let [tag, props] = node;
208
- let children = props.children;
209
- if (tag === $fragment) {
210
- if (children !== void 0) {
211
- await renderChildren(ctx, children);
208
+ const [tag, props] = node;
209
+ const { stateStore } = rc;
210
+ if (tag === $fragment || tag === "htmx") {
211
+ if (props.children !== void 0) {
212
+ await renderChildren(rc, props.children);
212
213
  }
213
214
  break;
214
215
  }
@@ -218,114 +219,98 @@ async function renderNode(ctx, node, stripSlotProp) {
218
219
  }
219
220
  break;
220
221
  }
221
- if (tag === "slot") {
222
- const ctxSlots = ctx.slots;
223
- let slots;
224
- if (ctxSlots !== void 0) {
225
- if (Array.isArray(ctxSlots)) {
226
- if (isVNode(ctxSlots)) {
227
- slots = [ctxSlots];
228
- } else {
229
- slots = ctxSlots;
230
- }
231
- } else {
232
- slots = [ctxSlots];
233
- }
234
- }
235
- if (props.name) {
236
- children = slots?.filter((v) => isVNode(v) && v[1].slot === props.name);
237
- } else {
238
- children = slots?.filter((v) => !isVNode(v) || !v[1].slot);
239
- }
240
- if (children === void 0 || Array(children) && children.length === 0) {
241
- children = node[1].children;
242
- }
243
- if (children !== void 0) {
244
- await renderChildren(ctx, children, true);
245
- }
246
- break;
247
- }
248
- const fcIndex = ctx.index.fc.toString(36);
249
222
  if (tag === $state) {
250
- const { key, value } = props;
251
- write('<m-state fc="' + fcIndex + '" key=' + toAttrStringLit(key) + ">");
223
+ const { key, value, fc } = props;
224
+ write('<m-state fc="' + fc + '" key=' + toAttrStringLit(key) + ">");
252
225
  if (value !== void 0 && value !== null) {
253
226
  write(escapeHTML("" + value));
254
227
  }
255
228
  write("</m-state>");
256
- stateStore.set(fcIndex + ":" + key, value);
229
+ stateStore.set(fc + ":" + key, value);
257
230
  break;
258
231
  }
259
232
  if (tag === $computed) {
260
- const { deps, value, fn } = props;
233
+ const { deps, value, fn, fc } = props;
261
234
  write(
262
- '<m-state fc="' + fcIndex + '" computed><script type="computed">$(' + fn + ", " + JSON.stringify(Object.keys(deps)) + ")<\/script>"
235
+ '<m-state fc="' + fc + '" computed><script type="computed">$(' + fn + ", " + JSON.stringify(Object.keys(deps)) + ")<\/script>"
263
236
  );
264
237
  if (value !== void 0) {
265
238
  write(escapeHTML("" + value));
266
239
  }
267
240
  write("</m-state>");
268
241
  for (const [key, value2] of Object.entries(deps)) {
269
- const stateKey = fcIndex + ":" + key;
270
- if (!stateStore.has(stateKey)) {
271
- stateStore.set(stateKey, value2);
242
+ if (!stateStore.has(key)) {
243
+ stateStore.set(key, value2);
272
244
  }
273
245
  }
274
246
  break;
275
247
  }
248
+ if (tag === "slot") {
249
+ const { fcSlots } = rc;
250
+ if (fcSlots) {
251
+ let slots;
252
+ if (props.name) {
253
+ slots = fcSlots.filter((v) => isVNode(v) && v[1].slot === props.name);
254
+ } else {
255
+ slots = fcSlots.filter((v) => !isVNode(v) || !v[1].slot);
256
+ }
257
+ if (slots.length === 0) {
258
+ slots = props.children;
259
+ }
260
+ await renderChildren(rc, slots, true);
261
+ }
262
+ break;
263
+ }
276
264
  if (tag === "toggle") {
265
+ const { value: valueProp, children } = props;
277
266
  if (children !== void 0) {
278
- const valueProp = props.value;
279
267
  if (isVNode(valueProp) && valueProp[0] === $state || valueProp[0] === $computed) {
280
- const { key, deps, value, fn } = valueProp[1];
281
- write('<m-state mode="toggle" fc="' + fcIndex + '" ');
268
+ const { key, deps, value, fn, fc } = valueProp[1];
269
+ write('<m-state mode="toggle" fc="' + fc + '" ');
282
270
  if (key) {
283
271
  write("key=" + toAttrStringLit(key) + ">");
284
- stateStore.set(fcIndex + ":" + key, !!value);
272
+ stateStore.set(fc + ":" + key, !!value);
285
273
  } else {
286
274
  write('computed><script type="computed">$(' + fn + ", " + JSON.stringify(Object.keys(deps)) + ")<\/script>");
287
275
  for (const [key2, value2] of Object.entries(deps)) {
288
- const stateKey = fcIndex + ":" + key2;
289
- if (!stateStore.has(stateKey)) {
290
- stateStore.set(stateKey, value2);
276
+ if (!stateStore.has(key2)) {
277
+ stateStore.set(key2, value2);
291
278
  }
292
279
  }
293
280
  }
294
281
  if (!value) {
295
282
  write("<template m-slot>");
296
283
  }
297
- await renderChildren(ctx, children);
284
+ await renderChildren(rc, children);
298
285
  if (!value) {
299
286
  write("</template>");
300
287
  }
301
288
  write("</m-state>");
302
289
  } else if (valueProp) {
303
- await renderChildren(ctx, children);
290
+ await renderChildren(rc, children);
304
291
  }
305
292
  }
306
293
  break;
307
294
  }
308
295
  if (tag === "switch") {
296
+ const { value: valueProp, defaultValue, children } = props;
309
297
  if (children !== void 0) {
310
298
  let slots = Array.isArray(children) ? isVNode(children) ? [children] : children : [children];
311
- let valueProp = props.value;
312
- let defaultValue = props.defaultValue;
313
299
  let stateful;
314
300
  let computed;
315
301
  let valueOrDefault;
316
302
  if (isVNode(valueProp) && (valueProp[0] === $state || valueProp[0] === $computed)) {
317
- const { key, deps, value, fn } = valueProp[1];
303
+ const { key, deps, value, fn, fc } = valueProp[1];
318
304
  valueOrDefault = value ?? defaultValue;
319
- stateful = '<m-state mode="switch" fc="' + fcIndex + '" ';
305
+ stateful = '<m-state mode="switch" fc="' + fc + '" ';
320
306
  if (key) {
321
307
  stateful += "key=" + toAttrStringLit(key) + ">";
322
- stateStore.set(fcIndex + ":" + key, valueOrDefault);
308
+ stateStore.set(fc + ":" + key, valueOrDefault);
323
309
  } else {
324
310
  stateful += 'computed><script type="computed">$(' + fn + ", " + JSON.stringify(Object.keys(deps)) + ")<\/script>";
325
311
  for (const [key2, value2] of Object.entries(deps)) {
326
- const stateKey = fcIndex + ":" + key2;
327
- if (!stateStore.has(stateKey)) {
328
- stateStore.set(stateKey, value2);
312
+ if (!stateStore.has(key2)) {
313
+ stateStore.set(key2, value2);
329
314
  }
330
315
  }
331
316
  }
@@ -354,16 +339,16 @@ async function renderNode(ctx, node, stripSlotProp) {
354
339
  }
355
340
  }
356
341
  if (matchedSlot) {
357
- await renderNode(ctx, matchedSlot[1], true);
342
+ await renderNode(rc, matchedSlot[1], true);
358
343
  } else if (unnamedSlots.length > 0) {
359
- await renderChildren(ctx, unnamedSlots);
344
+ await renderChildren(rc, unnamedSlots);
360
345
  }
361
346
  if (stateful) {
362
347
  if (namedSlots.length > 0 || matchedSlot && unnamedSlots.length > 0) {
363
348
  write("<template m-slot>");
364
- await renderChildren(ctx, namedSlots);
349
+ await renderChildren(rc, namedSlots);
365
350
  if (matchedSlot && unnamedSlots.length > 0) {
366
- await renderChildren(ctx, unnamedSlots);
351
+ await renderChildren(rc, unnamedSlots);
367
352
  }
368
353
  write("</template>");
369
354
  }
@@ -373,48 +358,47 @@ async function renderNode(ctx, node, stripSlotProp) {
373
358
  break;
374
359
  }
375
360
  if (typeof tag === "function") {
361
+ const fcIndex = ++rc.index.fc;
376
362
  const { rendering, placeholder, catch: catchFC, ...fcProps } = props ?? /* @__PURE__ */ Object.create(null);
377
- let eager = ctx.eager;
378
- if ((rendering ?? tag.rendering) === "eager") {
379
- eager = true;
380
- }
381
363
  try {
382
- const v = tag.call(createState(ctx.context, ctx.request), fcProps);
383
- ctx.index.fc++;
364
+ const v = tag.call(createState(fcIndex, rc.appState, rc.context, rc.request), fcProps);
365
+ const { children } = fcProps;
366
+ const fcSlots = children !== void 0 ? Array.isArray(children) ? isVNode(children) ? [children] : children : [children] : void 0;
367
+ const eager = (rendering ?? tag.rendering) === "eager" || rc.eager;
384
368
  if (v instanceof Promise) {
385
369
  if (eager) {
386
- await renderNode({ ...ctx, eager: true, slots: children }, await v);
370
+ await renderNode({ ...rc, fcIndex, eager: true, fcSlots }, await v);
387
371
  } else {
388
- const chunkId = (ctx.suspenses.length + 1).toString(36);
389
- ctx.suspenses.push(v.then(async (c) => {
372
+ const chunkId = (rc.suspenses.length + 1).toString(36);
373
+ rc.suspenses.push(v.then(async (c) => {
390
374
  write('<m-chunk chunk-id="' + chunkId + '"><template>');
391
- await renderNode({ ...ctx, eager, slots: children }, c);
375
+ await renderNode({ ...rc, fcIndex, eager, fcSlots }, c);
392
376
  write("</template></m-chunk>");
393
377
  }));
394
378
  write('<m-portal chunk-id="' + chunkId + '">');
395
379
  if (placeholder) {
396
- await renderNode({ ...ctx, eager: true }, placeholder);
380
+ await renderNode({ ...rc, fcIndex, eager: true }, placeholder);
397
381
  }
398
382
  write("</m-portal>");
399
383
  }
400
384
  } else if (isObject(v) && Symbol.iterator in v && !isVNode(v)) {
401
385
  for (const c of v) {
402
- await renderNode({ ...ctx, eager, slots: children }, c);
386
+ await renderNode({ ...rc, fcIndex, eager, fcSlots }, c);
403
387
  }
404
388
  } else if (isObject(v) && Symbol.asyncIterator in v) {
405
389
  if (eager) {
406
390
  for await (const c of v) {
407
- await renderNode({ ...ctx, eager: true, slots: children }, c);
391
+ await renderNode({ ...rc, fcIndex, eager: true, fcSlots }, c);
408
392
  }
409
393
  } else {
410
394
  }
411
395
  } else {
412
- await renderNode({ ...ctx, eager, slots: children }, v);
396
+ await renderNode({ ...rc, fcIndex, eager, fcSlots }, v);
413
397
  }
414
398
  } catch (err) {
415
399
  if (err instanceof Error) {
416
400
  if (typeof catchFC === "function") {
417
- await renderNode({ ...ctx, eager: true }, catchFC(err));
401
+ await renderNode({ ...rc, fcIndex, eager: true }, catchFC(err));
418
402
  } else {
419
403
  write('<pre style="color:red;font-size:1rem"><code>' + escapeHTML(err.stack ?? err.message) + "</code></pre>");
420
404
  }
@@ -431,22 +415,21 @@ async function renderNode(ctx, node, stripSlotProp) {
431
415
  continue;
432
416
  }
433
417
  if (isVNode(propValue) && (propValue[0] === $state || propValue[0] === $computed)) {
434
- const { key, deps, fn, value } = propValue[1];
418
+ const { key, value, deps, fn, fc } = propValue[1];
435
419
  if (propName === "class") {
436
- ctx.rtComponents.cx = true;
420
+ rc.runtimeUtils.cx = true;
437
421
  } else if (propName === "style") {
438
- ctx.rtComponents.styleToCSS = true;
422
+ rc.runtimeUtils.styleToCSS = true;
439
423
  }
440
- propEffects.push("<m-state mode=" + toAttrStringLit("[" + propName + "]") + ' fc="' + fcIndex + '" ');
424
+ propEffects.push("<m-state mode=" + toAttrStringLit("[" + propName + "]") + ' fc="' + fc + '" ');
441
425
  if (key) {
442
426
  propEffects.push("key=" + toAttrStringLit(key) + ">");
443
- stateStore.set(fcIndex + ":" + key, value);
427
+ stateStore.set(fc + ":" + key, value);
444
428
  } else {
445
429
  propEffects.push('computed><script type="computed">$(' + fn + ", " + JSON.stringify(Object.keys(deps)) + ")<\/script>");
446
430
  for (const [key2, value2] of Object.entries(deps)) {
447
- const stateKey = fcIndex + ":" + key2;
448
- if (!stateStore.has(stateKey)) {
449
- stateStore.set(stateKey, value2);
431
+ if (!stateStore.has(key2)) {
432
+ stateStore.set(key2, value2);
450
433
  }
451
434
  }
452
435
  }
@@ -494,7 +477,7 @@ async function renderNode(ctx, node, stripSlotProp) {
494
477
  raw += css + "|";
495
478
  }
496
479
  raw += [pseudoStyles, atRuleStyles, nestingStyles].flat(1).map(([k, v]) => k + ">" + v).join("|");
497
- styleIds = ctx.styleIds ?? (ctx.styleIds = /* @__PURE__ */ new Set());
480
+ styleIds = rc.styleIds ?? (rc.styleIds = /* @__PURE__ */ new Set());
498
481
  id = hashCode(raw).toString(36);
499
482
  cssSelector = "[data-css-" + id + "]";
500
483
  if (!styleIds.has(id)) {
@@ -526,9 +509,9 @@ async function renderNode(ctx, node, stripSlotProp) {
526
509
  break;
527
510
  case "action":
528
511
  if (typeof propValue === "function" && tag === "form") {
529
- const id = "$MF_" + (ctx.index.mf++).toString(36);
530
- write("<script>function " + id + "(fd){(" + propValue.toString() + ")(fd)}<\/script>");
531
- buffer += ' onsubmit="$onsubmit(event,this,' + id + ",'" + fcIndex + `')"`;
512
+ const fn = "$MF_" + (rc.index.mf++).toString(36);
513
+ write("<script>function " + fn + "(fd){(" + propValue.toString() + ")(fd)}<\/script>");
514
+ buffer += ' onsubmit="$onsubmit(event,this,' + fn + (rc.fcIndex !== void 0 ? "," + rc.fcIndex : "") + ')"';
532
515
  } else if (isString(propValue)) {
533
516
  buffer += " action=" + toAttrStringLit(propValue);
534
517
  }
@@ -542,16 +525,16 @@ async function renderNode(ctx, node, stripSlotProp) {
542
525
  if (regexpHtmlTag.test(propName) && propValue !== void 0) {
543
526
  if (propName.startsWith("on")) {
544
527
  if (typeof propValue === "function") {
545
- const id = "$MF_" + (ctx.index.mf++).toString(36);
546
- write("<script>function " + id + "(e){(" + propValue.toString() + ")(e)}<\/script>");
547
- buffer += " " + propName.toLowerCase() + '="$emit(event,this,' + id + ",'" + fcIndex + `')"`;
528
+ const fn = "$MF_" + (rc.index.mf++).toString(36);
529
+ write("<script>function " + fn + "(e){(" + propValue.toString() + ")(e)}<\/script>");
530
+ buffer += " " + propName.toLowerCase() + '="$emit(event,this,' + fn + (rc.fcIndex !== void 0 ? "," + rc.fcIndex : "") + ')"';
548
531
  }
549
532
  } else if (typeof propValue === "boolean") {
550
533
  if (propValue) {
551
534
  buffer += " " + propName;
552
535
  }
553
536
  } else {
554
- buffer += " " + (propValue === true ? escapeHTML(propName) : escapeHTML(propName) + "=" + toAttrStringLit("" + propValue));
537
+ buffer += " " + escapeHTML(propName) + (propValue === true ? "" : "=" + toAttrStringLit("" + propValue));
555
538
  }
556
539
  }
557
540
  }
@@ -563,19 +546,17 @@ async function renderNode(ctx, node, stripSlotProp) {
563
546
  }
564
547
  if (props.innerHTML) {
565
548
  write(props.innerHTML);
566
- } else if (children !== void 0) {
567
- await renderChildren(ctx, children);
549
+ } else if (props.children !== void 0) {
550
+ await renderChildren(rc, props.children);
568
551
  }
569
552
  write("</" + tag + ">");
570
553
  } else if (propEffects.length > 0) {
571
- write("<m-group>");
572
- write(propEffects.join(""));
573
- write("</m-group>");
554
+ write("<m-group>" + propEffects.join("") + "</m-group>");
574
555
  }
575
556
  if (onMountHandler) {
576
- ctx.index.mf++;
557
+ rc.index.mf++;
577
558
  write(
578
- '<script>{const target=document.currentScript.previousElementSibling;addEventListener("load",()=>$emit({type:"mount",currentTarget:target,target},target,' + onMountHandler.toString() + ',"' + fcIndex + '"))}<\/script>'
559
+ '<script>{const target=document.currentScript.previousElementSibling;addEventListener("load",()=>$emit({type:"mount",currentTarget:target,target},target,' + onMountHandler.toString() + (rc.fcIndex !== void 0 ? "," + rc.fcIndex : "") + "))}<\/script>"
579
560
  );
580
561
  }
581
562
  }
@@ -583,17 +564,17 @@ async function renderNode(ctx, node, stripSlotProp) {
583
564
  break;
584
565
  }
585
566
  }
586
- async function renderChildren(ctx, children, stripSlotProp) {
567
+ async function renderChildren(rc, children, stripSlotProp) {
587
568
  if (Array.isArray(children) && !isVNode(children)) {
588
569
  for (const child of children) {
589
- await renderNode(ctx, child, stripSlotProp);
570
+ await renderNode(rc, child, stripSlotProp);
590
571
  }
591
572
  } else {
592
- await renderNode(ctx, children, stripSlotProp);
573
+ await renderNode(rc, children, stripSlotProp);
593
574
  }
594
575
  }
595
576
  function render(node, renderOptions = {}) {
596
- const { context, request, status, headers: headersInit, rendering } = renderOptions;
577
+ const { request, status, headers: headersInit } = renderOptions;
597
578
  const headers = new Headers();
598
579
  if (headersInit) {
599
580
  for (const [key, value] of Object.entries(headersInit)) {
@@ -615,43 +596,61 @@ function render(node, renderOptions = {}) {
615
596
  return new Response(
616
597
  new ReadableStream({
617
598
  async start(controller) {
599
+ const { appState: appStateInit, context, rendering, htmx } = renderOptions;
618
600
  const write = (chunk) => controller.enqueue(encoder.encode(chunk));
601
+ const appState = createState(0, null, context, request);
619
602
  const stateStore = /* @__PURE__ */ new Map();
620
603
  const suspenses = [];
621
604
  const rtComponents = { cx: false, styleToCSS: false };
622
- const ctx = {
605
+ const rc = {
623
606
  write,
624
607
  context,
625
608
  request,
609
+ appState,
626
610
  stateStore,
627
611
  suspenses,
628
- rtComponents,
612
+ runtimeUtils: rtComponents,
629
613
  index: { fc: 0, mf: 0 },
630
614
  eager: rendering === "eager"
631
615
  };
616
+ if (appStateInit) {
617
+ for (const [key, value] of Object.entries(appStateInit)) {
618
+ if (value !== void 0) {
619
+ appState[key] = value;
620
+ }
621
+ }
622
+ }
632
623
  try {
633
624
  write("<!DOCTYPE html>");
634
- await renderNode(ctx, node);
625
+ await renderNode(rc, node);
635
626
  let js = "";
627
+ if (rc.index.mf > 0) {
628
+ js += UTILS_JS.event;
629
+ }
636
630
  if (stateStore.size > 0) {
637
631
  if (rtComponents.cx) {
638
- js += RUNTIME_COMPONENTS_JS.cx;
632
+ js += UTILS_JS.cx;
639
633
  }
640
634
  if (rtComponents.styleToCSS) {
641
- js += RUNTIME_COMPONENTS_JS.styleToCSS;
635
+ js += UTILS_JS.styleToCSS;
642
636
  }
643
- js += RUNTIME_STATE_JS;
637
+ js += STATE_JS;
644
638
  js += "for(let[k,v]of" + JSON.stringify(Array.from(stateStore.entries()).map((e) => e[1] === void 0 ? [e[0]] : e)) + ")$defineState(k,v);";
645
639
  }
646
- if (ctx.index.mf > 0) {
647
- js += RUNTIME_COMPONENTS_JS.event;
648
- }
649
640
  if (suspenses.length > 0) {
650
- js += RUNTIME_SUSPENSE_JS;
641
+ js += SUSPENSE_JS;
651
642
  }
652
643
  if (js) {
653
644
  write("<script>(()=>{" + js + "})()<\/script>");
654
645
  }
646
+ if (htmx) {
647
+ write(`<script src="https://raw.esm.sh/htmx.org${htmx === true ? "" : "@" + htmx}/dist/htmx.min.js"><\/script>`);
648
+ for (const [name, version] of Object.entries(renderOptions)) {
649
+ if (name.startsWith("html-ext-")) {
650
+ write(`<script src="https://raw.esm.sh/${name}${version === true ? "" : "@" + version}"><\/script>`);
651
+ }
652
+ }
653
+ }
655
654
  if (suspenses.length > 0) {
656
655
  await Promise.all(suspenses);
657
656
  }
@@ -675,9 +674,10 @@ var jsx = (tag, props = /* @__PURE__ */ Object.create(null), key) => {
675
674
  }
676
675
  if (tag === "html") {
677
676
  const renderOptions = /* @__PURE__ */ Object.create(null);
678
- for (const key2 of ["context", "request", "status", "headers", "rendering"]) {
679
- if (Object.hasOwn(props, key2)) {
680
- renderOptions[key2] = props[key2];
677
+ const optionsKeys = /* @__PURE__ */ new Set(["appState", "context", "request", "status", "headers", "rendering", "htmx"]);
678
+ for (const [key2, value] of Object.entries(props)) {
679
+ if (optionsKeys.has(key2) || key2.startsWith("html-ext-")) {
680
+ renderOptions[key2] = value;
681
681
  delete props[key2];
682
682
  }
683
683
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mono-jsx",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "`<html>` as a `Response`.",
5
5
  "type": "module",
6
6
  "module": "./index.mjs",
package/setup.mjs ADDED
@@ -0,0 +1,44 @@
1
+ // setup.ts
2
+ import { existsSync } from "node:fs";
3
+ import { readFile, writeFile } from "node:fs/promises";
4
+ async function setup() {
5
+ if (globalThis.Deno && existsSync("deno.jsonc")) {
6
+ console.log("Please add the following options to your deno.jsonc file:");
7
+ console.log(
8
+ [
9
+ `{`,
10
+ ` "compilerOptions": {`,
11
+ ` %c"jsx": "react-jsx",`,
12
+ ` "jsxImportSource": "mono-jsx",%c`,
13
+ ` }`,
14
+ `}`
15
+ ].join("\n"),
16
+ "color:green",
17
+ ""
18
+ );
19
+ return;
20
+ }
21
+ let tsConfigFilename = globalThis.Deno ? "deno.json" : "tsconfig.json";
22
+ let tsConfig = /* @__PURE__ */ Object.create(null);
23
+ try {
24
+ const data = await readFile(tsConfigFilename, "utf8");
25
+ tsConfig = JSON.parse(data);
26
+ } catch {
27
+ }
28
+ const compilerOptions = tsConfig.compilerOptions ?? (tsConfig.compilerOptions = {});
29
+ if (compilerOptions.jsx === "react-jsx" && compilerOptions.jsxImportSource === "mono-jsx") {
30
+ console.log("%cmono-jsx already setup.", "color:grey");
31
+ return;
32
+ }
33
+ if (!globalThis.Deno) {
34
+ compilerOptions.module ??= "es2022";
35
+ compilerOptions.moduleResolution ??= "bundler";
36
+ }
37
+ compilerOptions.jsx = "react-jsx";
38
+ compilerOptions.jsxImportSource = "mono-jsx";
39
+ await writeFile(tsConfigFilename, JSON.stringify(tsConfig, null, 2));
40
+ console.log("\u2705 mono-jsx setup complete.");
41
+ }
42
+ export {
43
+ setup
44
+ };
package/types/css.d.ts CHANGED
@@ -6671,7 +6671,7 @@ export interface VendorLonghandProperties<TLength = (string & {}) | 0, TTime = s
6671
6671
  */
6672
6672
  msHyphens?: Property.Hyphens | undefined;
6673
6673
  /**
6674
- * The **`-ms-ime-align`** CSS property is a Microsoft extension aligning the Input Method Editor (IME) candidate window box relative to the element on which the IME composition is active. The extension is implemented in Microsoft Edge and Internet Explorer 11.
6674
+ * The **`-ms-ime-align`** CSS property is a Microsoft extension aligning the Input Method Editor (IME) candidate window box relative to the element on which the IME composition is active. The extension is implemented in Microsoft Edge and Internet Explorer 11.
6675
6675
  *
6676
6676
  * **Syntax**: `auto | after`
6677
6677
  *