mono-jsx-dom 0.1.12 → 0.1.13

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
@@ -382,84 +382,129 @@ function Counter(this: FC<{ count: number }>, props: { initialCount?: number })
382
382
  }
383
383
  ```
384
384
 
385
- You can use `this.store` to create a signal store. You can use getters to create derived (computed) signals.
385
+ ### Atom signals
386
+
387
+ Call `this.atom(initialValue)` inside a component to get a reactive atom tied to that instance. It updates the view when you call `set`, and you can read the current value with `get` (for example in `effect` callbacks).
386
388
 
387
389
  ```tsx
388
- function App(this: FC<{ count: number }>) {
389
- const counter = this.store({
390
- value: 0,
391
- // double is a derived(computed) signal
392
- get double() {
393
- return this.value * 2;
394
- }
390
+ function Counter(this: FC) {
391
+ const count = this.atom(0);
392
+ this.effect(() => {
393
+ console.log("count changed:", count.get());
395
394
  });
396
-
397
395
  return (
398
396
  <div>
399
- <span>count:{counter.value}</span>
400
- <span>double: {counter.double}</span>
401
- <button onClick={() => counter.value++}>+</button>
397
+ <span>{count}</span>
398
+ <button onClick={() => count.set((prev) => prev + 1)}>Increment</button>
402
399
  </div>
403
- )
400
+ );
404
401
  }
405
402
  ```
406
403
 
407
- ### Using `atom` and `store`
404
+ For state shared across the whole app (or a module), import `atom` and define it at the top level. Any component that reads that atom in JSX or effects stays in sync.
408
405
 
409
- mono-jsx-dom provides two functions that allow you to define shared global signals. You can use them to share signals between components.
406
+ ```tsx
407
+ import { atom } from "mono-jsx-dom";
410
408
 
411
- - `atom(initValue)`: Creates an atom signal.
412
- - `store(initValue)`: Creates a signal store.
409
+ const count = atom(0);
410
+ const double = count.ref((value) => value * 2);
411
+
412
+ function Counter(this: FC) {
413
+ this.effect(() => {
414
+ console.log("count changed:", count.get());
415
+ });
416
+ return (
417
+ <div>
418
+ <p>count: {count}</p>
419
+ <p>double: {double}</p>
420
+ </div>
421
+ );
422
+ }
423
+
424
+ function App(this: FC) {
425
+ return (
426
+ <div>
427
+ <Counter />
428
+ <button onClick={() => count.set((prev) => prev + 1)}>Increment</button>
429
+ </div>
430
+ );
431
+ }
432
+ ```
433
+
434
+ The type of atom signals is defined as follows:
413
435
 
414
436
  ```ts
415
437
  export interface Atom<T> {
438
+ /** Read the current value. */
416
439
  get(): T;
417
- set(value: T | ((prev: T) => T)): void;
418
- map(callback: (value: T extends (infer V)[] ? V : T, index: number) => JSX.ChildPrimitiveType): JSX.ChildPrimitiveType[];
440
+ /** Assign a new value or compute one from the previous value. */
441
+ set(value: T): void;
442
+ set(fn: (value: T) => T): void;
443
+ /** When `T` is an array, map each item to a child for list rendering. */
444
+ map(
445
+ callback: (value: T extends (infer V)[] ? V : T, index: number) => ChildPrimitiveType,
446
+ ): ChildPrimitiveType[];
447
+ /** Create signal ref to the atom. */
419
448
  ref(): T;
449
+ /** Derived reactive value from the atom. */
420
450
  ref<V>(callback: (value: T) => V): V;
451
+ /** Run `callback` when the atom changes; pass `signal` to tie lifetime to an `AbortSignal`. */
452
+ watch(callback: () => void, signal?: AbortSignal): void;
421
453
  }
422
-
423
- export const atom: <T>(initValue: T) => Atom<T>;
424
- export const store: <T extends Record<string, unknown>>(initValue: T) => T;
425
454
  ```
426
455
 
427
- Example:
456
+ ### Signal stores
428
457
 
429
- ```tsx
430
- import { atom, store } from "mono-jsx-dom";
431
-
432
- const count = atom(0);
433
- const store = store({ text: 'Count:' });
458
+ The `this.store({ ... })` method in a component builds a reactive object: plain fields are signals, and getters become derived signals.
434
459
 
435
- function Counter(this: FC) {
436
- this.effect(() => {
437
- console.log("count changed:", count.get());
460
+ ```tsx
461
+ function App(this: FC) {
462
+ const counter = this.store({
463
+ value: 0,
464
+ get double() {
465
+ return this.value * 2;
466
+ },
438
467
  });
468
+
439
469
  return (
440
- <span>{store.text}{count}</span>
441
- )
470
+ <div>
471
+ <span>count: {counter.value}</span>
472
+ <span>double: {counter.double}</span>
473
+ <button onClick={() => counter.value++}>+</button>
474
+ </div>
475
+ );
442
476
  }
477
+ ```
478
+
479
+ You can also use the `store` function to create a global signal store. Like `atom` function, the global signals store is shared between all components.
443
480
 
444
- function Buttons(this: FC) {
481
+ ```tsx
482
+ import { store } from "mono-jsx-dom";
483
+
484
+ const counter = store({
485
+ value: 0,
486
+ get double() {
487
+ return this.value * 2;
488
+ },
489
+ });
490
+
491
+ function Counter(this: FC) {
445
492
  return (
446
- <>
447
- <button onClick={() => count.set(prev => prev+1)}>+</button>
448
- <button onClick={() => store.text = store.text === 'Count:' ? 'Count:' : '计数:'}>English/中文</button>
449
- </>
450
- )
493
+ <div>
494
+ <span>{counter.value}</span>
495
+ <span>{counter.double}</span>
496
+ </div>
497
+ );
451
498
  }
452
499
 
453
500
  function App(this: FC) {
454
501
  return (
455
- <>
502
+ <div>
456
503
  <Counter />
457
- <Buttons />
458
- </>
459
- )
504
+ <button onClick={() => counter.value++}>Increment</button>
505
+ </div>
506
+ );
460
507
  }
461
-
462
- document.body.mount(<App />);
463
508
  ```
464
509
 
465
510
  ### Using Computed Signals
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mono-jsx-dom",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "description": "A JSX runtime for browsers.",
5
5
  "keywords": [
6
6
  "jsx",
@@ -4,7 +4,7 @@ export const html: JSX.Raw;
4
4
  export const JSX: typeof globalThis.JSX;
5
5
  export const Fragment: (props: {}) => VNode;
6
6
  export const jsx: (tag: string | ComponentType, props: Record<string, unknown>, key?: string | number) => VNode;
7
- export const render: (scope: null, node: VNode, container: HTMLElement, aboutSignal?: AbortSignal) => void;
7
+ export const render: (scope: null, node: VNode, container: HTMLElement | DocumentFragment | ShadowRoot, aboutSignal?: AbortSignal) => void;
8
8
 
9
9
  // aliases
10
10
  export { html as css, html as js, jsx as jsxDEV, jsx as jsxs };
package/types/jsx.d.ts CHANGED
@@ -97,11 +97,21 @@ export interface MonoBuiltinElements {
97
97
  }
98
98
 
99
99
  export interface Atom<T> {
100
+ /** Read the current value. */
100
101
  get(): T;
101
- set(value: T | ((prev: T) => T)): void;
102
- map(callback: (value: T extends (infer V)[] ? V : T, index: number) => ChildPrimitiveType): ChildPrimitiveType[];
102
+ /** Assign a new value or compute one from the previous value. */
103
+ set(value: T): void;
104
+ set(fn: (value: T) => T): void;
105
+ /** When `T` is an array, map each item to a child for list rendering. */
106
+ map(
107
+ callback: (value: T extends (infer V)[] ? V : T, index: number) => ChildPrimitiveType,
108
+ ): ChildPrimitiveType[];
109
+ /** Create signal ref to the atom. */
103
110
  ref(): T;
111
+ /** Derived reactive value from the atom. */
104
112
  ref<V>(callback: (value: T) => V): V;
113
+ /** Run `callback` when the atom changes; pass `signal` to tie lifetime to an `AbortSignal`. */
114
+ watch(callback: () => void, signal?: AbortSignal): void;
105
115
  }
106
116
 
107
117
  declare global {