mono-jsx 0.7.5 → 0.8.0-beta.11
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 +39 -19
- package/dom/jsx-runtime.mjs +703 -0
- package/jsx-runtime.mjs +265 -250
- package/package.json +15 -3
- package/setup.mjs +101 -7
- package/types/dom/jsx-runtime.d.ts +22 -0
- package/types/dom/mono.d.ts +47 -0
- package/types/html.d.ts +89 -6
- package/types/htmx.d.ts +1 -3
- package/types/index.d.ts +2 -2
- package/types/jsx-runtime.d.ts +14 -2
- package/types/jsx.d.ts +114 -9
- package/types/mono.d.ts +66 -178
- package/types/render.d.ts +5 -3
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ mono-jsx is a JSX runtime that renders the `<html>` element to a `Response` obje
|
|
|
10
10
|
- ⚡️ Use web components, no virtual DOM
|
|
11
11
|
- 💡 Complete Web API TypeScript definitions
|
|
12
12
|
- ⏳ Streaming rendering
|
|
13
|
-
- 🗂️ Built-in router(SPA mode)
|
|
13
|
+
- 🗂️ Built-in router (SPA mode)
|
|
14
14
|
- 🔑 Session storage
|
|
15
15
|
- 🥷 [htmx](#using-htmx) integration
|
|
16
16
|
- 🌎 Universal, works in Node.js, Deno, Bun, Cloudflare Workers, etc.
|
|
@@ -40,6 +40,8 @@ To use mono-jsx as your JSX runtime, add the following configuration to your `ts
|
|
|
40
40
|
```jsonc
|
|
41
41
|
{
|
|
42
42
|
"compilerOptions": {
|
|
43
|
+
"module": "esnext",
|
|
44
|
+
"moduleResolution": "bundler",
|
|
43
45
|
"jsx": "react-jsx",
|
|
44
46
|
"jsxImportSource": "mono-jsx"
|
|
45
47
|
}
|
|
@@ -431,22 +433,38 @@ mono-jsx renders HTML on the server side and sends no hydration JavaScript to th
|
|
|
431
433
|
To render a component by name, you can use the `<component>` element with the `name` prop, and ensure the component is registered in the `components` prop of root `<html>` element.
|
|
432
434
|
|
|
433
435
|
```tsx
|
|
436
|
+
function Foo(props: { bar: string }) {
|
|
437
|
+
return <h1>{props.bar}</h1>;
|
|
438
|
+
}
|
|
439
|
+
|
|
434
440
|
export default {
|
|
435
441
|
fetch: (req) => (
|
|
436
|
-
<html components={{ Foo }}>
|
|
437
|
-
<component name="Foo" props={{
|
|
442
|
+
<html request={req} components={{ Foo }}>
|
|
443
|
+
<component name="Foo" props={{ bar: "baz" }} placeholder={<p>Loading...</p>} />
|
|
438
444
|
</html>
|
|
439
445
|
)
|
|
440
446
|
}
|
|
441
447
|
```
|
|
442
448
|
|
|
443
|
-
|
|
449
|
+
You can use the `<component>` element with the `is` prop to render a component by function reference without registering the component in the `components` prop of root `<html>` element.
|
|
444
450
|
|
|
445
451
|
```tsx
|
|
446
452
|
export default {
|
|
447
453
|
fetch: (req) => (
|
|
448
|
-
<html>
|
|
449
|
-
<component is={Foo} props={{
|
|
454
|
+
<html request={req}>
|
|
455
|
+
<component is={Foo} props={{ bar: "baz" }} placeholder={<p>Loading...</p>} />
|
|
456
|
+
</html>
|
|
457
|
+
)
|
|
458
|
+
}
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
Or you can use the `<component>` element with the `as` prop to render a component by JSX element.
|
|
462
|
+
|
|
463
|
+
```tsx
|
|
464
|
+
export default {
|
|
465
|
+
fetch: (req) => (
|
|
466
|
+
<html request={req}>
|
|
467
|
+
<component as={<Foo bar="baz" />} placeholder={<p>Loading...</p>} />
|
|
450
468
|
</html>
|
|
451
469
|
)
|
|
452
470
|
}
|
|
@@ -476,7 +494,7 @@ function Dash(this: FC<{ page: "Profile" | "Projects" | "Settings" }>) {
|
|
|
476
494
|
|
|
477
495
|
export default {
|
|
478
496
|
fetch: (req) => (
|
|
479
|
-
<html components={{ Profile, Projects, Settings }}>
|
|
497
|
+
<html request={req} components={{ Profile, Projects, Settings }}>
|
|
480
498
|
<Dash />
|
|
481
499
|
</html>
|
|
482
500
|
)
|
|
@@ -491,7 +509,7 @@ async function Lazy(this: FC<{ show: boolean }>, props: { url: string }) {
|
|
|
491
509
|
return (
|
|
492
510
|
<div>
|
|
493
511
|
<toggle show={this.show}>
|
|
494
|
-
<component name="Foo" props={{
|
|
512
|
+
<component name="Foo" props={{ bar: "baz" }} placeholder={<p>Loading...</p>} />
|
|
495
513
|
</toggle>
|
|
496
514
|
<button onClick={() => this.show = true }>Load `Foo` Component</button>
|
|
497
515
|
</div>
|
|
@@ -500,7 +518,7 @@ async function Lazy(this: FC<{ show: boolean }>, props: { url: string }) {
|
|
|
500
518
|
|
|
501
519
|
export default {
|
|
502
520
|
fetch: (req) => (
|
|
503
|
-
<html components={{ Foo }}>
|
|
521
|
+
<html request={req} components={{ Foo }}>
|
|
504
522
|
<Lazy />
|
|
505
523
|
</html>
|
|
506
524
|
)
|
|
@@ -545,7 +563,7 @@ interface AppSignals {
|
|
|
545
563
|
themeColor: string;
|
|
546
564
|
}
|
|
547
565
|
|
|
548
|
-
function Header(this: FC
|
|
566
|
+
function Header(this: App<FC, AppSignals>) {
|
|
549
567
|
return (
|
|
550
568
|
<header>
|
|
551
569
|
<h1 style={{ color: this.app.themeColor }}>Welcome to mono-jsx!</h1>
|
|
@@ -553,7 +571,7 @@ function Header(this: FC<{}, AppSignals>) {
|
|
|
553
571
|
)
|
|
554
572
|
}
|
|
555
573
|
|
|
556
|
-
function Footer(this: FC
|
|
574
|
+
function Footer(this: App<FC, AppSignals>) {
|
|
557
575
|
return (
|
|
558
576
|
<footer>
|
|
559
577
|
<p style={{ color: this.app.themeColor }}>(c) 2025 mono-jsx.</p>
|
|
@@ -561,12 +579,12 @@ function Footer(this: FC<{}, AppSignals>) {
|
|
|
561
579
|
)
|
|
562
580
|
}
|
|
563
581
|
|
|
564
|
-
function Main(this: FC
|
|
582
|
+
function Main(this: App<FC, AppSignals>) {
|
|
565
583
|
return (
|
|
566
584
|
<main>
|
|
567
585
|
<p>
|
|
568
586
|
<label>Theme Color: </label>
|
|
569
|
-
<input type="color"
|
|
587
|
+
<input type="color" $value={this.app.themeColor} />
|
|
570
588
|
</p>
|
|
571
589
|
</main>
|
|
572
590
|
)
|
|
@@ -574,7 +592,7 @@ function Main(this: FC<{}, AppSignals>) {
|
|
|
574
592
|
|
|
575
593
|
export default {
|
|
576
594
|
fetch: (req) => (
|
|
577
|
-
<html app={{ themeColor: "#232323" }}>
|
|
595
|
+
<html app={{ themeColor: "#232323" } satisfies AppSignals}>
|
|
578
596
|
<Header />
|
|
579
597
|
<Main />
|
|
580
598
|
<Footer />
|
|
@@ -696,7 +714,7 @@ function App(this: FC<{ lang: "en" | "zh" | "🙂" }>) {
|
|
|
696
714
|
<switch value={this.lang}>
|
|
697
715
|
<h1 slot="en">Hello, world!</h1>
|
|
698
716
|
<h1 slot="zh">你好,世界!</h1>
|
|
699
|
-
<h1>✋🌎❗️</h1>
|
|
717
|
+
<h1 slot="🙂">✋🌎❗️</h1>
|
|
700
718
|
</switch>
|
|
701
719
|
<p>
|
|
702
720
|
<button onClick={() => this.lang = "en"}>English</button>
|
|
@@ -837,7 +855,7 @@ The `this` object has the following built-in properties:
|
|
|
837
855
|
- `effect`: A method to create side effects.
|
|
838
856
|
|
|
839
857
|
```ts
|
|
840
|
-
type FC<Signals = {},
|
|
858
|
+
type FC<Signals = {}, Refs = {}, AppSignals = {}, AppRefs = {}, Context = {}> = {
|
|
841
859
|
readonly app: AppSignals & { refs: AppRefs; url: WithParams<URL> }
|
|
842
860
|
readonly context: Context;
|
|
843
861
|
readonly request: WithParams<Request>;
|
|
@@ -859,7 +877,7 @@ See the [Using Signals](#using-signals) section for more details on how to use s
|
|
|
859
877
|
You can use `this.refs` to access refs in your components. Refs are defined using the `ref` attribute in JSX, and they allow you to access DOM elements directly. The `refs` object is a map of ref names to DOM elements.
|
|
860
878
|
|
|
861
879
|
```tsx
|
|
862
|
-
function App(this: Refs<FC, { input
|
|
880
|
+
function App(this: Refs<FC, { input?: HTMLInputElement }>) {
|
|
863
881
|
this.effect(() => {
|
|
864
882
|
this.refs.input?.addEventListener("input", (evt) => {
|
|
865
883
|
console.log("Input changed:", evt.target.value);
|
|
@@ -878,7 +896,7 @@ function App(this: Refs<FC, { input: HTMLInputElement }>) {
|
|
|
878
896
|
You can also use `this.app.refs` to access app-level refs:
|
|
879
897
|
|
|
880
898
|
```tsx
|
|
881
|
-
function Layout(this:
|
|
899
|
+
function Layout(this: FC) {
|
|
882
900
|
return (
|
|
883
901
|
<>
|
|
884
902
|
<header>
|
|
@@ -899,6 +917,8 @@ The `<component>` element also supports the `ref` attribute, which allows you to
|
|
|
899
917
|
- `refresh`: A method to re-render the component with the current name and props.
|
|
900
918
|
|
|
901
919
|
```tsx
|
|
920
|
+
import type { ComponentElement } from "mono-jsx";
|
|
921
|
+
|
|
902
922
|
function App(this: Refs<FC, { component: ComponentElement }>) {
|
|
903
923
|
this.effect(() => {
|
|
904
924
|
// updating the component name and props will trigger a re-render of the component
|
|
@@ -906,7 +926,7 @@ function App(this: Refs<FC, { component: ComponentElement }>) {
|
|
|
906
926
|
this.refs.component.props = {};
|
|
907
927
|
|
|
908
928
|
const timer = setInterval(() => {
|
|
909
|
-
|
|
929
|
+
// re-render the component
|
|
910
930
|
this.refs.component.refresh();
|
|
911
931
|
}, 1000);
|
|
912
932
|
return () => clearInterval(timer); // cleanup
|