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 +86 -1
- package/jsx-runtime.mjs +8 -7
- package/package.json +2 -3
- package/setup.mjs +0 -14
- package/types/render.d.ts +1 -1
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
|
-
|
|
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 [
|
|
648
|
-
if (
|
|
649
|
-
write(`<script src="https://raw.esm.sh/${
|
|
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("
|
|
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.
|
|
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