mono-jsx 0.3.0 → 0.3.2

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
@@ -109,6 +109,9 @@ You'll need [tsx](https://www.npmjs.com/package/tsx) to start the app without a
109
109
  npx tsx app.tsx
110
110
  ```
111
111
 
112
+ > [!NOTE]
113
+ > Only root `<html>` element will be rendered as a `Response` object. You cannot return a `<div>` or any other element directly from the `fetch` handler. This is a limitation of the mono-jsx runtime.
114
+
112
115
  ## Using JSX
113
116
 
114
117
  mono-jsx uses [**JSX**](https://react.dev/learn/describing-the-ui) to describe the user interface, similar to React but with key differences.
@@ -336,7 +339,7 @@ function Main(this: FC<{}, { title: string }>) {
336
339
  <h1>{this.app.title}</h1>
337
340
  <h2>Changing the title</h2>
338
341
  <input
339
- onInput={(evt) => this.app.title = evt.target.value }
342
+ onInput={(evt) => this.app.title = evt.target.value}
340
343
  placeholder="Enter a new title"
341
344
  />
342
345
  </main>
@@ -604,6 +607,88 @@ export default {
604
607
  };
605
608
  ```
606
609
 
610
+ ## Using htmx
611
+
612
+ mono-jsx integrates with [htmx](https://htmx.org/) and [typed-htmx](https://github.com/Desdaemon/typed-htmx). To use htmx, add the `htmx` attribute to the root `<html>` element:
613
+
614
+ ```jsx
615
+ export default {
616
+ fetch: (req) => {
617
+ const url = new URL(req.url);
618
+
619
+ if (url.pathname === "/clicked") {
620
+ return (
621
+ <html>
622
+ <span>Clicked!</span>
623
+ </html>
624
+ );
625
+ }
626
+
627
+ return (
628
+ <html htmx>
629
+ <button hx-get="/clicked" hx-swap="outerHTML">
630
+ Click Me
631
+ </button>
632
+ </html>
633
+ );
634
+ },
635
+ };
636
+ ```
637
+
638
+ ### Adding htmx Extensions
639
+
640
+ You can add htmx [extensions](https://htmx.org/docs/#extensions) by adding the `htmx-ext-*` attribute to the root `<html>` element:
641
+
642
+ ```jsx
643
+ export default {
644
+ fetch: (req) => (
645
+ <html htmx htmx-ext-response-targets htmx-ext-ws>
646
+ <button hx-get="/clicked" hx-swap="outerHTML">
647
+ Click Me
648
+ </button>
649
+ </html>
650
+ ),
651
+ };
652
+ ```
653
+
654
+ ### Specifying htmx Version
655
+
656
+ You can specify the htmx version by setting the `htmx` attribute to a specific version:
657
+
658
+ ```jsx
659
+ export default {
660
+ fetch: (req) => (
661
+ <html htmx="2.0.4" htmx-ext-response-targets="2.0.2" htmx-ext-ws="2.0.2">
662
+ <button hx-get="/clicked" hx-swap="outerHTML">
663
+ Click Me
664
+ </button>
665
+ </html>
666
+ ),
667
+ };
668
+ ```
669
+
670
+ ### Installing htmx Manually
671
+
672
+ By default, mono-jsx installs htmx from [esm.sh](https://esm.sh/) CDN when you set the `htmx` attribute. You can also install htmx manually with your own CDN or local copy:
673
+
674
+ ```jsx
675
+ export default {
676
+ fetch: (req) => (
677
+ <html>
678
+ <head>
679
+ <script src="https://unpkg.com/htmx.org@2.0.4" integrity="sha384-HGfztofotfshcF7+8n44JQL2oJmowVChPTg48S+jvZoztPfvwD79OC/LTtG6dMp+" crossorigin="anonymous"></script>
680
+ <script src="https://unpkg.com/htmx-ext-ws@2.0.2" integrity="sha384-vuKxTKv5TX/b3lLzDKP2U363sOAoRo5wSvzzc3LJsbaQRSBSS+3rKKHcOx5J8doU" crossorigin="anonymous"></script>
681
+ </head>
682
+ <body>
683
+ <button hx-get="/clicked" hx-swap="outerHTML">
684
+ Click Me
685
+ </button>
686
+ </body>
687
+ </html>
688
+ ),
689
+ };
690
+ ```
691
+
607
692
  ## License
608
693
 
609
694
  [MIT](LICENSE)
package/jsx-runtime.mjs CHANGED
@@ -11,12 +11,12 @@ function createState(fc, appState, context, request) {
11
11
  const computed = (fn) => {
12
12
  const deps = /* @__PURE__ */ Object.create(null);
13
13
  collectDeps = (fc2, key, value2) => deps[fc2 + ":" + key] = value2;
14
- const value = fn();
14
+ const value = fn.call(proxy);
15
15
  collectDeps = void 0;
16
16
  if (value instanceof Promise || deps.size === 0) return value;
17
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
22
  case "app":
@@ -47,6 +47,7 @@ function createState(fc, appState, context, request) {
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
@@ -643,10 +644,10 @@ function render(node, renderOptions = {}) {
643
644
  write("<script>(()=>{" + js + "})()<\/script>");
644
645
  }
645
646
  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>`);
647
+ write(`<script src="https://raw.esm.sh/htmx.org${htmx === true ? "" : escapeHTML("@" + htmx)}/dist/htmx.min.js"><\/script>`);
648
+ for (const [key, value] of Object.entries(renderOptions)) {
649
+ if (key.startsWith("htmx-ext-") && value) {
650
+ write(`<script src="https://raw.esm.sh/${key}${value === true ? "" : escapeHTML("@" + value)}"><\/script>`);
650
651
  }
651
652
  }
652
653
  }
@@ -675,7 +676,7 @@ var jsx = (tag, props = /* @__PURE__ */ Object.create(null), key) => {
675
676
  const renderOptions = /* @__PURE__ */ Object.create(null);
676
677
  const optionsKeys = /* @__PURE__ */ new Set(["appState", "context", "request", "status", "headers", "rendering", "htmx"]);
677
678
  for (const [key2, value] of Object.entries(props)) {
678
- if (optionsKeys.has(key2) || key2.startsWith("html-ext-")) {
679
+ if (optionsKeys.has(key2) || key2.startsWith("htmx-ext-")) {
679
680
  renderOptions[key2] = value;
680
681
  delete props[key2];
681
682
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mono-jsx",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "`<html>` as a `Response`.",
5
5
  "type": "module",
6
6
  "module": "./index.mjs",
@@ -26,8 +26,7 @@
26
26
  }
27
27
  },
28
28
  "scripts": {
29
- "prepublishOnly": "deno task build",
30
- "postinstall": "node setup.mjs"
29
+ "prepublishOnly": "deno task build"
31
30
  },
32
31
  "files": [
33
32
  "*.mjs",
package/setup.mjs CHANGED
@@ -1,8 +1,6 @@
1
1
  // setup.ts
2
2
  import { existsSync } from "node:fs";
3
3
  import { readFile, writeFile } from "node:fs/promises";
4
- import { fileURLToPath } from "node:url";
5
- import { argv } from "node:process";
6
4
  async function setup() {
7
5
  if (globalThis.Deno && existsSync("deno.jsonc")) {
8
6
  console.log("Please add the following options to your deno.jsonc file:");
@@ -41,18 +39,6 @@ async function setup() {
41
39
  await writeFile(tsConfigFilename, JSON.stringify(tsConfig, null, 2));
42
40
  console.log("\u2705 mono-jsx setup complete.");
43
41
  }
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
42
  export {
57
43
  setup
58
44
  };
package/types/render.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * @see https://htmx.org/docs/#extensions
4
4
  */
5
5
  type HtmxExts = {
6
- [key in `html-ext-${JSX.HtmxExtensions[keyof JSX.HtmxExtensions]}`]:
6
+ [key in `htmx-ext-${JSX.HtmxExtensions[keyof JSX.HtmxExtensions]}`]:
7
7
  | number
8
8
  | string
9
9
  | boolean;