@sigrea/react 0.2.0 → 0.3.0

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
@@ -1,24 +1,24 @@
1
1
  # @sigrea/react
2
2
 
3
- `@sigrea/react` adapts [@sigrea/core](https://www.npmjs.com/package/@sigrea/core) logic modules and signals for use in React components. It binds scope-aware lifecycles to `useEffect`, synchronizes signal subscriptions with React rendering, and provides hooks for both shallow and deep reactivity.
3
+ `@sigrea/react` adapts [@sigrea/core](https://www.npmjs.com/package/@sigrea/core) molecule modules and signals for use in React components. It binds scope-aware lifecycles to `useEffect`, synchronizes signal subscriptions with React rendering, and provides hooks for both shallow and deep reactivity.
4
4
 
5
5
  - **Signal subscriptions.** `useSignal` subscribes to signals and computed values, triggering re-renders when they change.
6
6
  - **Computed subscriptions.** `useComputed` subscribes to computed values and memoizes them per component instance.
7
7
  - **Deep signal subscriptions.** `useDeepSignal` subscribes to deep signal objects and exposes them for direct mutation.
8
- - **Logic lifecycles.** `useLogic` mounts logic factories and binds their lifecycles to React components.
8
+ - **Molecule lifecycles.** `useMolcule` mounts molecule factories and binds their lifecycles to React components.
9
9
 
10
10
  ## Table of Contents
11
11
 
12
12
  - [Install](#install)
13
13
  - [Quick Start](#quick-start)
14
14
  - [Consume a Signal](#consume-a-signal)
15
- - [Bridge Framework-Agnostic Logic](#bridge-framework-agnostic-logic)
15
+ - [Bridge Framework-Agnostic Molecules](#bridge-framework-agnostic-molecules)
16
16
  - [Work with Deep Signals](#work-with-deep-signals)
17
17
  - [API Reference](#api-reference)
18
18
  - [useSignal](#usesignal)
19
19
  - [useComputed](#usecomputed)
20
20
  - [useDeepSignal](#usedeepsignal)
21
- - [useLogic](#uselogic)
21
+ - [useMolcule](#usemolcule)
22
22
  - [Testing](#testing)
23
23
  - [Development](#development)
24
24
  - [License](#license)
@@ -47,13 +47,13 @@ export function CounterLabel() {
47
47
  }
48
48
  ```
49
49
 
50
- ### Bridge Framework-Agnostic Logic
50
+ ### Bridge Framework-Agnostic Molecules
51
51
 
52
52
  ```tsx
53
- import { defineLogic, signal } from "@sigrea/core";
54
- import { useLogic, useSignal } from "@sigrea/react";
53
+ import { molecule, signal } from "@sigrea/core";
54
+ import { useMolcule, useSignal } from "@sigrea/react";
55
55
 
56
- const CounterLogic = defineLogic<{ initialCount: number }>()((props) => {
56
+ const CounterMolecule = molecule((props: { initialCount: number }) => {
57
57
  const count = signal(props.initialCount);
58
58
 
59
59
  const increment = () => {
@@ -68,7 +68,7 @@ const CounterLogic = defineLogic<{ initialCount: number }>()((props) => {
68
68
  });
69
69
 
70
70
  export function Counter(props: { initialCount: number }) {
71
- const counter = useLogic(CounterLogic, props);
71
+ const counter = useMolcule(CounterMolcule, props);
72
72
  const value = useSignal(counter.count);
73
73
 
74
74
  return (
@@ -132,27 +132,24 @@ function useDeepSignal<T extends object>(signal: DeepSignal<T>): T
132
132
 
133
133
  Exposes a deep signal object for direct mutation within the component. Updates to nested properties trigger re-renders, and the subscription is cleaned up when the component unmounts.
134
134
 
135
- ### useLogic
135
+ ### useMolcule
136
136
 
137
137
  ```tsx
138
- function useLogic<TProps, TReturn>(
139
- logic: LogicFunction<TProps, TReturn>,
138
+ function useMolcule<TProps, TReturn>(
139
+ molecule: MoleculeFactory<TProps, TReturn>,
140
140
  props?: TProps
141
141
  ): TReturn
142
142
  ```
143
143
 
144
- Mounts a logic factory and returns its public API. The logic's scope is bound to the component lifecycle: `onMount` callbacks run after the component mounts, and `onUnmount` callbacks run before it unmounts.
144
+ Mounts a molecule factory and returns its public API. The molecule's scope is bound to the component lifecycle: `onMount` callbacks run after the component mounts, and `onUnmount` callbacks run before it unmounts.
145
145
 
146
146
  ## Testing
147
147
 
148
148
  ```tsx
149
149
  // tests/Counter.test.tsx
150
150
  import { render, screen, fireEvent } from "@testing-library/react";
151
- import { cleanupLogics } from "@sigrea/core";
152
151
  import { Counter } from "../components/Counter";
153
152
 
154
- afterEach(() => cleanupLogics());
155
-
156
153
  it("increments and displays the updated count", () => {
157
154
  render(<Counter initialCount={10} />);
158
155
 
package/dist/index.cjs CHANGED
@@ -3,21 +3,23 @@
3
3
  const react = require('react');
4
4
  const core = require('@sigrea/core');
5
5
 
6
- function useLogic(logic, ...args) {
6
+ function useMolcule(molecule, ...args) {
7
7
  const props = args.length === 0 ? void 0 : args[0];
8
- const stateRef = react.useRef(void 0);
8
+ const stateRef = react.useRef(
9
+ void 0
10
+ );
9
11
  const currentState = stateRef.current;
10
- const shouldRemount = currentState === void 0 || currentState.logic !== logic || !Object.is(currentState.props, props);
12
+ const shouldRemount = currentState === void 0 || currentState.molecule !== molecule || !Object.is(currentState.props, props);
11
13
  if (shouldRemount) {
12
14
  if (currentState !== void 0) {
13
15
  currentState.pendingDisposeToken = null;
14
- core.cleanupLogic(currentState.instance);
16
+ core.disposeMolecule(currentState.instance);
15
17
  stateRef.current = void 0;
16
18
  }
17
- const logicArgs = props === void 0 ? [] : [props];
19
+ const moleculeArgs = props === void 0 ? [] : [props];
18
20
  stateRef.current = {
19
- instance: core.mountLogic(logic, ...logicArgs),
20
- logic,
21
+ instance: molecule(...moleculeArgs),
22
+ molecule,
21
23
  props,
22
24
  subscribers: 0,
23
25
  disposed: false,
@@ -26,7 +28,9 @@ function useLogic(logic, ...args) {
26
28
  }
27
29
  const state = stateRef.current;
28
30
  if (state === void 0) {
29
- throw new Error("useLogic failed to mount the requested logic instance.");
31
+ throw new Error(
32
+ "useMolcule failed to mount the requested molecule instance."
33
+ );
30
34
  }
31
35
  const instance = state.instance;
32
36
  react.useEffect(() => {
@@ -42,7 +46,7 @@ function useLogic(logic, ...args) {
42
46
  return () => {
43
47
  const latest = stateRef.current;
44
48
  if (latest === void 0 || latest.instance !== instance) {
45
- core.cleanupLogic(instance);
49
+ core.disposeMolecule(instance);
46
50
  return;
47
51
  }
48
52
  latest.subscribers -= 1;
@@ -60,7 +64,7 @@ function useLogic(logic, ...args) {
60
64
  current.disposed = true;
61
65
  current.pendingDisposeToken = null;
62
66
  stateRef.current = void 0;
63
- core.cleanupLogic(instance);
67
+ core.disposeMolecule(instance);
64
68
  });
65
69
  }
66
70
  };
@@ -102,6 +106,6 @@ function useDeepSignal(source) {
102
106
 
103
107
  exports.useComputed = useComputed;
104
108
  exports.useDeepSignal = useDeepSignal;
105
- exports.useLogic = useLogic;
109
+ exports.useMolcule = useMolcule;
106
110
  exports.useSignal = useSignal;
107
111
  exports.useSnapshot = useSnapshot;
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
- import { LogicFunction, LogicArgs, LogicInstance, Signal, ReadonlySignal, Computed, DeepSignal, SnapshotHandler } from '@sigrea/core';
1
+ import { MoleculeFactory, MoleculeArgs, MoleculeInstance, Signal, ReadonlySignal, Computed, DeepSignal, SnapshotHandler } from '@sigrea/core';
2
2
 
3
- declare function useLogic<TReturn extends object, TProps = void>(logic: LogicFunction<TReturn, TProps>, ...args: LogicArgs<TProps>): LogicInstance<TReturn>;
3
+ declare function useMolcule<TReturn extends object, TProps = void>(molecule: MoleculeFactory<TReturn, TProps>, ...args: MoleculeArgs<TProps>): MoleculeInstance<TReturn>;
4
4
 
5
5
  type ReadableSignal<T> = Signal<T> | ReadonlySignal<T>;
6
6
  declare function useSignal<T>(source: ReadableSignal<T>): T;
@@ -11,4 +11,4 @@ declare function useDeepSignal<T extends object>(source: DeepSignal<T>): T;
11
11
 
12
12
  declare function useSnapshot<T>(handler: SnapshotHandler<T>): T;
13
13
 
14
- export { useComputed, useDeepSignal, useLogic, useSignal, useSnapshot };
14
+ export { useComputed, useDeepSignal, useMolcule, useSignal, useSnapshot };
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
- import { LogicFunction, LogicArgs, LogicInstance, Signal, ReadonlySignal, Computed, DeepSignal, SnapshotHandler } from '@sigrea/core';
1
+ import { MoleculeFactory, MoleculeArgs, MoleculeInstance, Signal, ReadonlySignal, Computed, DeepSignal, SnapshotHandler } from '@sigrea/core';
2
2
 
3
- declare function useLogic<TReturn extends object, TProps = void>(logic: LogicFunction<TReturn, TProps>, ...args: LogicArgs<TProps>): LogicInstance<TReturn>;
3
+ declare function useMolcule<TReturn extends object, TProps = void>(molecule: MoleculeFactory<TReturn, TProps>, ...args: MoleculeArgs<TProps>): MoleculeInstance<TReturn>;
4
4
 
5
5
  type ReadableSignal<T> = Signal<T> | ReadonlySignal<T>;
6
6
  declare function useSignal<T>(source: ReadableSignal<T>): T;
@@ -11,4 +11,4 @@ declare function useDeepSignal<T extends object>(source: DeepSignal<T>): T;
11
11
 
12
12
  declare function useSnapshot<T>(handler: SnapshotHandler<T>): T;
13
13
 
14
- export { useComputed, useDeepSignal, useLogic, useSignal, useSnapshot };
14
+ export { useComputed, useDeepSignal, useMolcule, useSignal, useSnapshot };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { LogicFunction, LogicArgs, LogicInstance, Signal, ReadonlySignal, Computed, DeepSignal, SnapshotHandler } from '@sigrea/core';
1
+ import { MoleculeFactory, MoleculeArgs, MoleculeInstance, Signal, ReadonlySignal, Computed, DeepSignal, SnapshotHandler } from '@sigrea/core';
2
2
 
3
- declare function useLogic<TReturn extends object, TProps = void>(logic: LogicFunction<TReturn, TProps>, ...args: LogicArgs<TProps>): LogicInstance<TReturn>;
3
+ declare function useMolcule<TReturn extends object, TProps = void>(molecule: MoleculeFactory<TReturn, TProps>, ...args: MoleculeArgs<TProps>): MoleculeInstance<TReturn>;
4
4
 
5
5
  type ReadableSignal<T> = Signal<T> | ReadonlySignal<T>;
6
6
  declare function useSignal<T>(source: ReadableSignal<T>): T;
@@ -11,4 +11,4 @@ declare function useDeepSignal<T extends object>(source: DeepSignal<T>): T;
11
11
 
12
12
  declare function useSnapshot<T>(handler: SnapshotHandler<T>): T;
13
13
 
14
- export { useComputed, useDeepSignal, useLogic, useSignal, useSnapshot };
14
+ export { useComputed, useDeepSignal, useMolcule, useSignal, useSnapshot };
package/dist/index.mjs CHANGED
@@ -1,21 +1,23 @@
1
1
  import { useRef, useEffect, useCallback, useSyncExternalStore, useMemo } from 'react';
2
- import { cleanupLogic, mountLogic, createSignalHandler, createComputedHandler, createDeepSignalHandler } from '@sigrea/core';
2
+ import { disposeMolecule, createSignalHandler, createComputedHandler, createDeepSignalHandler } from '@sigrea/core';
3
3
 
4
- function useLogic(logic, ...args) {
4
+ function useMolcule(molecule, ...args) {
5
5
  const props = args.length === 0 ? void 0 : args[0];
6
- const stateRef = useRef(void 0);
6
+ const stateRef = useRef(
7
+ void 0
8
+ );
7
9
  const currentState = stateRef.current;
8
- const shouldRemount = currentState === void 0 || currentState.logic !== logic || !Object.is(currentState.props, props);
10
+ const shouldRemount = currentState === void 0 || currentState.molecule !== molecule || !Object.is(currentState.props, props);
9
11
  if (shouldRemount) {
10
12
  if (currentState !== void 0) {
11
13
  currentState.pendingDisposeToken = null;
12
- cleanupLogic(currentState.instance);
14
+ disposeMolecule(currentState.instance);
13
15
  stateRef.current = void 0;
14
16
  }
15
- const logicArgs = props === void 0 ? [] : [props];
17
+ const moleculeArgs = props === void 0 ? [] : [props];
16
18
  stateRef.current = {
17
- instance: mountLogic(logic, ...logicArgs),
18
- logic,
19
+ instance: molecule(...moleculeArgs),
20
+ molecule,
19
21
  props,
20
22
  subscribers: 0,
21
23
  disposed: false,
@@ -24,7 +26,9 @@ function useLogic(logic, ...args) {
24
26
  }
25
27
  const state = stateRef.current;
26
28
  if (state === void 0) {
27
- throw new Error("useLogic failed to mount the requested logic instance.");
29
+ throw new Error(
30
+ "useMolcule failed to mount the requested molecule instance."
31
+ );
28
32
  }
29
33
  const instance = state.instance;
30
34
  useEffect(() => {
@@ -40,7 +44,7 @@ function useLogic(logic, ...args) {
40
44
  return () => {
41
45
  const latest = stateRef.current;
42
46
  if (latest === void 0 || latest.instance !== instance) {
43
- cleanupLogic(instance);
47
+ disposeMolecule(instance);
44
48
  return;
45
49
  }
46
50
  latest.subscribers -= 1;
@@ -58,7 +62,7 @@ function useLogic(logic, ...args) {
58
62
  current.disposed = true;
59
63
  current.pendingDisposeToken = null;
60
64
  stateRef.current = void 0;
61
- cleanupLogic(instance);
65
+ disposeMolecule(instance);
62
66
  });
63
67
  }
64
68
  };
@@ -98,4 +102,4 @@ function useDeepSignal(source) {
98
102
  return useSnapshot(handler);
99
103
  }
100
104
 
101
- export { useComputed, useDeepSignal, useLogic, useSignal, useSnapshot };
105
+ export { useComputed, useDeepSignal, useMolcule, useSignal, useSnapshot };
package/package.json CHANGED
@@ -1,74 +1,82 @@
1
1
  {
2
- "name": "@sigrea/react",
3
- "version": "0.2.0",
4
- "description": "React adapter bindings for Sigrea logic modules.",
5
- "license": "MIT",
6
- "type": "module",
7
- "publishConfig": {
8
- "access": "public"
9
- },
10
- "repository": {
11
- "type": "git",
12
- "url": "git+https://github.com/sigrea/react.git"
13
- },
14
- "homepage": "https://github.com/sigrea/react#readme",
15
- "bugs": {
16
- "url": "https://github.com/sigrea/react/issues"
17
- },
18
- "engines": {
19
- "node": ">=20"
20
- },
21
- "sideEffects": false,
22
- "exports": {
23
- ".": {
24
- "types": "./dist/index.d.ts",
25
- "import": "./dist/index.mjs",
26
- "require": "./dist/index.cjs"
27
- }
28
- },
29
- "main": "./dist/index.cjs",
30
- "types": "./dist/index.d.ts",
31
- "files": [
32
- "dist"
33
- ],
34
- "keywords": [
35
- "signals",
36
- "reactivity",
37
- "react",
38
- "logic",
39
- "typescript"
40
- ],
41
- "peerDependencies": {
42
- "@sigrea/core": "^0.3.1",
43
- "react": "^18.0.0 || ^19.0.0",
44
- "react-dom": "^18.0.0 || ^19.0.0"
45
- },
46
- "devDependencies": {
47
- "@biomejs/biome": "1.9.4",
48
- "@vitejs/plugin-react": "^4.3.3",
49
- "@types/react": "^19.0.0",
50
- "@types/react-dom": "^19.0.0",
51
- "changelogen": "^0.6.2",
52
- "@vitest/coverage-v8": "^3.2.4",
53
- "lefthook": "1.13.6",
54
- "react": "^19.0.0",
55
- "react-dom": "^19.0.0",
56
- "tsx": "^4.20.5",
57
- "typescript": "5.9.3",
58
- "unbuild": "3.6.1",
59
- "vite": "^5.4.6",
60
- "vitest": "^3.2.4",
61
- "jsdom": "^24.1.3"
62
- },
63
- "scripts": {
64
- "dev": "vite --config playground/vite.config.ts",
65
- "build": "unbuild",
66
- "changelog": "changelogen",
67
- "release": "pnpm test && pnpm build && changelogen --release",
68
- "test": "vitest run",
69
- "test:coverage": "vitest --coverage",
70
- "typecheck": "tsc -p tsconfig.json --noEmit",
71
- "format": "biome check .",
72
- "format:fix": "biome check --write ."
73
- }
74
- }
2
+ "name": "@sigrea/react",
3
+ "version": "0.3.0",
4
+ "description": "React adapter bindings for Sigrea molecule modules.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "packageManager": "pnpm@10.0.0",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/sigrea/react.git"
14
+ },
15
+ "homepage": "https://github.com/sigrea/react#readme",
16
+ "bugs": {
17
+ "url": "https://github.com/sigrea/react/issues"
18
+ },
19
+ "engines": {
20
+ "node": ">=20"
21
+ },
22
+ "sideEffects": false,
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "import": "./dist/index.mjs",
27
+ "require": "./dist/index.cjs"
28
+ }
29
+ },
30
+ "main": "./dist/index.cjs",
31
+ "types": "./dist/index.d.ts",
32
+ "files": [
33
+ "dist"
34
+ ],
35
+ "keywords": [
36
+ "signals",
37
+ "reactivity",
38
+ "react",
39
+ "molecule",
40
+ "typescript"
41
+ ],
42
+ "scripts": {
43
+ "dev": "vite --config playground/vite.config.ts",
44
+ "build": "unbuild",
45
+ "prepack": "unbuild",
46
+ "changelog": "changelogen",
47
+ "release": "pnpm test && pnpm build && changelogen --release",
48
+ "test": "vitest run",
49
+ "test:coverage": "vitest --coverage",
50
+ "typecheck": "tsc -p tsconfig.json --noEmit",
51
+ "format": "biome check .",
52
+ "format:fix": "biome check --write ."
53
+ },
54
+ "peerDependencies": {
55
+ "@sigrea/core": "^0.4.0",
56
+ "react": "^18.0.0 || ^19.0.0",
57
+ "react-dom": "^18.0.0 || ^19.0.0"
58
+ },
59
+ "devDependencies": {
60
+ "@biomejs/biome": "1.9.4",
61
+ "@vitejs/plugin-react": "^4.3.3",
62
+ "@types/react": "^19.0.0",
63
+ "@types/react-dom": "^19.0.0",
64
+ "changelogen": "^0.6.2",
65
+ "@vitest/coverage-v8": "^3.2.4",
66
+ "lefthook": "1.13.6",
67
+ "react": "^19.0.0",
68
+ "react-dom": "^19.0.0",
69
+ "tsx": "^4.20.5",
70
+ "typescript": "5.9.3",
71
+ "unbuild": "3.6.1",
72
+ "vite": "^5.4.6",
73
+ "vitest": "^3.2.4",
74
+ "jsdom": "^24.1.3"
75
+ },
76
+ "pnpm": {
77
+ "onlyBuiltDependencies": [
78
+ "lefthook",
79
+ "@biomejs/biome"
80
+ ]
81
+ }
82
+ }