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 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={{ /* props for the component */ }} placeholder={<p>Loading...</p>} />
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
- Or 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.
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={{ /* props for the component */ }} placeholder={<p>Loading...</p>} />
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={{ /* props for the component */ }} placeholder={<p>Loading...</p>} />
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<{}, AppSignals>) {
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<{}, AppSignals>) {
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<{}, AppSignals>) {
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" onInput={({ target }) => this.app.themeColor = target.value}/>
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 = {}, AppSignals = {}, Context = {}, Refs = {}, AppRefs = {}> = {
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: HTMLInputElement }>) {
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: Refs<FC, {}, { h1: HTMLH1Element }>) {
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
- // re-render the component
929
+ // re-render the component
910
930
  this.refs.component.refresh();
911
931
  }, 1000);
912
932
  return () => clearInterval(timer); // cleanup