mono-jsx 0.2.0 → 0.3.0

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