@wirestate/react-signals 0.6.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/CHANGELOG.md ADDED
@@ -0,0 +1,51 @@
1
+ ## 0.6.0
2
+
3
+ - Split wirestate as separate @wirestate packages
4
+
5
+ ## 0.5.0
6
+
7
+ - Add default initial state param on creation of containers
8
+ - Explicit typing for query callers, export new types
9
+ - For wire-scope add missing optional query/command/resolve methods
10
+ - Add sourcemaps in lib bundles
11
+ - Add `signals` entry for variants of storage usage without mobx
12
+
13
+ ## 0.4.0
14
+
15
+ - Add `OnActivated` decorator
16
+ - Add `OnDeactivated` decorator
17
+ - `initialState` -> `seed`
18
+ - `type` -> `bindingType`
19
+ - `scopeType` -> `bindingScopeType`
20
+ - Emit events with two params instead of manually composed object, signal `from`
21
+ - Add commands module
22
+ - Add WireScope shared class for managing of wirestate events, queries and commands
23
+ - Remove abstract service in favor of WireScope usage
24
+ - Signals -> events
25
+ - `useOptionalInjection` -> add fallback handler
26
+
27
+ ## 0.3.0
28
+
29
+ - Rename `createServicesProvider` to `createInjectablesProvider`
30
+ - Add `useSignals`, `useSignalHandler` hooks for better signal handling ergonomics
31
+ - Add `useOptionalInjection` hook for safe resolution of optional dependencies
32
+ - Support optional queries via `queryOptional`, `useOptionalQueryCaller`, and `useOptionalSyncQueryCaller`
33
+ - Support merging of initial states when multiple providers co-exist
34
+ - Add more re-exports from `mobx` and `inversify` for easier consumer usage
35
+ - Improve test coverage, extend test utilities
36
+ - Correctly notify about `IS_DISPOSED` after deactivation of services
37
+
38
+ ## 0.2.0
39
+
40
+ - Activate and deactivate services in stack ordering
41
+ - Portable libs will not fail with react compiler builds
42
+ - Extend test-utils
43
+ - Increasing test coverage
44
+ - Error handling / custom error class
45
+ - Allow addition of constant bindings in the IOC container
46
+ - useService -> useInjection
47
+ - AbstractService::getService -> AbstractService::resolve
48
+
49
+ ## 0.1.1
50
+
51
+ - Initial release
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Syrotenko Igor
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,319 @@
1
+ # <a href='https://www.npmjs.com/package/wirestate'> ⚡ wirestate </a>
2
+
3
+ [![npm version](https://img.shields.io/npm/v/wirestate.svg?style=flat-square)](https://www.npmjs.com/package/wirestate)
4
+ [![language-ts](https://img.shields.io/badge/language-typescript-blue.svg?style=flat)](https://github.com/Neloreck/wirestate/search?l=typescript)
5
+ [![license](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/Neloreck/wirestate/blob/master/LICENSE)
6
+
7
+ `wirestate` is a reactivity-independent state management framework for React. It integrates **InversifyJS** for robust Dependency Injection,
8
+ providing IOC/DI/indirection based architecture based on concepts of Services, Events, Commands, and Queries.
9
+
10
+ It optionally works with **MobX**, **Signals**, or other custom reactivity implementations.
11
+
12
+ ## Architecture & Core Concepts
13
+
14
+ Designed for complex applications, `wirestate` enforces a clear separation of concerns:
15
+
16
+ - **Services**: Singleton-scoped logic units that hold state and business logic.
17
+ - **Dependency Injection**: First-class InversifyJS integration for decoupled, testable code.
18
+ - **Reactivity**: Independent state tracking (optional integration with MobX, Signals, etc.).
19
+ - **Events**: Fire-and-forget communication for cross-service side effects.
20
+ - **Commands**: Encapsulated write operations with standardized execution status (pending, settled, error).
21
+ - **Queries**: Synchronous or asynchronous request-response patterns for data retrieval.
22
+ - **Lifecycle Management**: Automated services provision within react tree, activation/deactivation lifecycle.
23
+
24
+ ## Requirements
25
+
26
+ - `react >= 16.8.0`
27
+ - `reflect-metadata` (must be imported at application entry)
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ npm install --save @wirestate/core reflect-metadata
33
+ ```
34
+
35
+ ### For react-mobx
36
+
37
+ ```bash
38
+ npm install --save @wirestate/react @wirestate/react-mobx mobx mobx-react-lite
39
+ ```
40
+
41
+ ### For signals
42
+
43
+ ```bash
44
+ npm install --save @wirestate/react @wirestate/react-signals @preact/signals-react
45
+ npm install --save-dev @preact/signals-react-transform
46
+ ```
47
+
48
+ ## Quick Start with mobx
49
+
50
+ ### 1. Define a Service
51
+
52
+ Services are standard classes decorated with `@Injectable`. Use `WireScope` to interact with the framework.
53
+
54
+ ```typescript
55
+ import { Injectable, Inject, WireScope, OnEvent, OnCommand, OnQuery } from '@wirestate/core';
56
+ import { makeObservable, Observable, Action } from '@wirestate/react-mobx';
57
+
58
+ @Injectable()
59
+ export class CounterService {
60
+ @Observable()
61
+ public count: number = 0;
62
+
63
+ public constructor(
64
+ @Inject(WireScope)
65
+ private scope: WireScope
66
+ ) {
67
+ makeObservable(this);
68
+ }
69
+
70
+ @Action()
71
+ public increment(amount: number = 1): void {
72
+ this.count += amount;
73
+ }
74
+
75
+ @Action()
76
+ public reset(): void {
77
+ this.count = 0;
78
+ }
79
+
80
+ @OnCommand('INCREMENT')
81
+ public onIncrementCommand(amount: number = 1): void {
82
+ this.increment(amount);
83
+ }
84
+
85
+ @OnQuery('GET_TOTAL')
86
+ public onGetTotal(): number {
87
+ return this.count;
88
+ }
89
+
90
+ @OnEvent('RESET')
91
+ public onResetEvent(): void {
92
+ this.reset();
93
+ }
94
+ }
95
+ ```
96
+
97
+ ### 2. Configure the Provider
98
+
99
+ Bind services at any level of the component tree.
100
+ Lifetimes are managed automatically.
101
+
102
+ ```tsx
103
+ import { IocProvider, createInjectablesProvider } from '@wirestate/react';
104
+ import { CounterService } from './CounterService';
105
+
106
+ const MainProvider = createInjectablesProvider([CounterService]);
107
+
108
+ export function Application() {
109
+ return (
110
+ <IocProvider>
111
+ <MainProvider>
112
+ <CounterView />
113
+ </MainProvider>
114
+ </IocProvider>
115
+ );
116
+ }
117
+ ```
118
+
119
+ ### 3. Consume in Components
120
+
121
+ Directly use services and rely on mobx reactivity.
122
+ Or use specialized hooks for communication without direct references.
123
+
124
+ ```tsx
125
+ import { useInjection, useCommandCaller, useEventEmitter } from '@wirestate/react';
126
+ import { observer } from '@wirestate/react-mobx';
127
+ import { CounterService } from './CounterService';
128
+
129
+ export const CounterView = observer(() => {
130
+ const service = useInjection(CounterService);
131
+ const call = useCommandCaller();
132
+ const emit = useEventEmitter();
133
+
134
+ return (
135
+ <div>
136
+ <p>Count: {service.count}</p>
137
+ <button onClick={() => service.increment(5)}>Add 1 (Method)</button>
138
+ <button onClick={() => call('INCREMENT', 5)}>Add 5 (Command)</button>
139
+ <button onClick={() => service.reset()}>Reset (Method)</button>
140
+ <button onClick={() => emit('RESET')}>Reset (Event)</button>
141
+ </div>
142
+ );
143
+ });
144
+ ```
145
+
146
+ ## Quick Start with signals
147
+
148
+ ### 1. Define a Service
149
+
150
+ Services use `signal` and `computed` for state management.
151
+
152
+ ```typescript
153
+ import { Injectable, Inject, WireScope, OnEvent, OnCommand, OnQuery } from '@wirestate/core';
154
+ import { signal, computed, Signal, ReadonlySignal } from '@wirestate/react-signals';
155
+
156
+ @Injectable()
157
+ export class CounterService {
158
+ public readonly count: Signal<number> = signal(0);
159
+ public readonly isEven: ReadonlySignal<boolean> = computed(() => this.count.value % 2 === 0);
160
+
161
+ public constructor(
162
+ @Inject(WireScope)
163
+ private scope: WireScope
164
+ ) {}
165
+
166
+ public increment(amount: number = 1): void {
167
+ this.count.value += amount;
168
+ }
169
+
170
+ public reset(): void {
171
+ this.count.value = 0;
172
+ }
173
+
174
+ @OnCommand('INCREMENT')
175
+ public onIncrementCommand(amount: number = 1): void {
176
+ this.increment(amount);
177
+ }
178
+
179
+ @OnQuery('GET_TOTAL')
180
+ public onGetTotal(): number {
181
+ return this.count.value;
182
+ }
183
+
184
+ @OnEvent('RESET')
185
+ public onResetEvent(): void {
186
+ this.reset();
187
+ }
188
+ }
189
+ ```
190
+
191
+ ### 2. Configure the Provider
192
+
193
+ The provider configuration remains the same regardless of the reactivity implementation.
194
+
195
+ ```tsx
196
+ import { IocProvider, createInjectablesProvider } from '@wirestate/react';
197
+ import { CounterService } from './CounterService';
198
+
199
+ const MainProvider = createInjectablesProvider([CounterService]);
200
+
201
+ export function Application() {
202
+ return (
203
+ <IocProvider>
204
+ <MainProvider>
205
+ <CounterView />
206
+ </MainProvider>
207
+ </IocProvider>
208
+ );
209
+ }
210
+ ```
211
+
212
+ ### 3. Consume in Components
213
+
214
+ Access signals directly in components. Reactivity is handled by the signals transform or manual subscription.
215
+
216
+ ```tsx
217
+ import { useInjection, useCommandCaller, useEventEmitter } from '@wirestate/react';
218
+ import { CounterService } from './CounterService';
219
+
220
+ export function CounterView() {
221
+ const service = useInjection(CounterService);
222
+ const call = useCommandCaller();
223
+ const emit = useEventEmitter();
224
+
225
+ return (
226
+ <div>
227
+ <p>Count: {service.count}</p>
228
+ <p>Even: {service.isEven.value ? 'Yes' : 'No'}</p>
229
+ <button onClick={() => service.increment(5)}>Add 1 (Method)</button>
230
+ <button onClick={() => call('INCREMENT', 5)}>Add 5 (Command)</button>
231
+ <button onClick={() => service.reset()}>Reset (Method)</button>
232
+ <button onClick={() => emit('RESET')}>Reset (Event)</button>
233
+ </div>
234
+ );
235
+ }
236
+ ```
237
+
238
+ ## Advanced Usage
239
+
240
+ ### Seeding Shared Initial State
241
+
242
+ `wirestate` supports providing initial data (seeds) to services during activation.
243
+
244
+ ```tsx
245
+ const MainProvider = createInjectablesProvider([CounterService]);
246
+
247
+ <IocProvider>
248
+ <MainProvider seed={{ initialCount: 100 }}>
249
+ <CounterView />
250
+ </MainProvider>
251
+ </IocProvider>
252
+ ```
253
+
254
+ In the service:
255
+
256
+ ```typescript
257
+ import { Injectable, Inject, SEED } from 'wirestate';
258
+
259
+ @Injectable()
260
+ export class CounterService {
261
+ // ...
262
+ public constructor(
263
+ @Inject(SEED)
264
+ initialState: { initialCount: number }
265
+ ) {
266
+ this.count = seed.initialCount;
267
+ }
268
+ }
269
+ ```
270
+
271
+ ### Seeding Bound Initial State
272
+
273
+ `wirestate` supports providing initial data (seeds) to services during activation.
274
+
275
+ ```tsx
276
+ const MainProvider = createInjectablesProvider([CounterService]);
277
+
278
+ <IocProvider>
279
+ <MainProvider seeds={[[CounterService, { count: 10 }]]}>
280
+ <CounterView />
281
+ </MainProvider>
282
+ </IocProvider>
283
+ ```
284
+
285
+ In the service:
286
+
287
+ ```typescript
288
+ import { Injectable, Inject, WireScope } from 'wirestate';
289
+
290
+ @Injectable()
291
+ export class CounterService {
292
+ // ...
293
+ public constructor(@Inject(WireScope) scope: WireScope) {
294
+ this.count = scope.getSeed(CounterService).count;
295
+ }
296
+ }
297
+ ```
298
+
299
+ ### Service Lifecycle
300
+
301
+ Use decorators to handle initialization and cleanup.
302
+
303
+ ```typescript
304
+ import { OnActivated, OnDeactivation } from 'wirestate';
305
+
306
+ @OnActivated()
307
+ public onActivated(): void {
308
+ // Start polling, fetch initial data, etc.
309
+ }
310
+
311
+ @OnDeactivation()
312
+ public onDeactivation(): void {
313
+ // Cleanup subscriptions
314
+ }
315
+ ```
316
+
317
+ ## License
318
+
319
+ MIT
@@ -0,0 +1,55 @@
1
+ 'use strict';
2
+
3
+ var signalsReact = require('@preact/signals-react');
4
+
5
+
6
+
7
+ Object.defineProperty(exports, "Signal", {
8
+ enumerable: true,
9
+ get: function () { return signalsReact.Signal; }
10
+ });
11
+ Object.defineProperty(exports, "action", {
12
+ enumerable: true,
13
+ get: function () { return signalsReact.action; }
14
+ });
15
+ Object.defineProperty(exports, "batch", {
16
+ enumerable: true,
17
+ get: function () { return signalsReact.batch; }
18
+ });
19
+ Object.defineProperty(exports, "computed", {
20
+ enumerable: true,
21
+ get: function () { return signalsReact.computed; }
22
+ });
23
+ Object.defineProperty(exports, "createModel", {
24
+ enumerable: true,
25
+ get: function () { return signalsReact.createModel; }
26
+ });
27
+ Object.defineProperty(exports, "effect", {
28
+ enumerable: true,
29
+ get: function () { return signalsReact.effect; }
30
+ });
31
+ Object.defineProperty(exports, "signal", {
32
+ enumerable: true,
33
+ get: function () { return signalsReact.signal; }
34
+ });
35
+ Object.defineProperty(exports, "untracked", {
36
+ enumerable: true,
37
+ get: function () { return signalsReact.untracked; }
38
+ });
39
+ Object.defineProperty(exports, "useComputed", {
40
+ enumerable: true,
41
+ get: function () { return signalsReact.useComputed; }
42
+ });
43
+ Object.defineProperty(exports, "useModel", {
44
+ enumerable: true,
45
+ get: function () { return signalsReact.useModel; }
46
+ });
47
+ Object.defineProperty(exports, "useSignal", {
48
+ enumerable: true,
49
+ get: function () { return signalsReact.useSignal; }
50
+ });
51
+ Object.defineProperty(exports, "useSignalEffect", {
52
+ enumerable: true,
53
+ get: function () { return signalsReact.useSignalEffect; }
54
+ });
55
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1 @@
1
+ "use strict";var e=require("@preact/signals-react");Object.defineProperty(exports,"Signal",{enumerable:!0,get:function(){return e.Signal}}),Object.defineProperty(exports,"action",{enumerable:!0,get:function(){return e.action}}),Object.defineProperty(exports,"batch",{enumerable:!0,get:function(){return e.batch}}),Object.defineProperty(exports,"computed",{enumerable:!0,get:function(){return e.computed}}),Object.defineProperty(exports,"createModel",{enumerable:!0,get:function(){return e.createModel}}),Object.defineProperty(exports,"effect",{enumerable:!0,get:function(){return e.effect}}),Object.defineProperty(exports,"signal",{enumerable:!0,get:function(){return e.signal}}),Object.defineProperty(exports,"untracked",{enumerable:!0,get:function(){return e.untracked}}),Object.defineProperty(exports,"useComputed",{enumerable:!0,get:function(){return e.useComputed}}),Object.defineProperty(exports,"useModel",{enumerable:!0,get:function(){return e.useModel}}),Object.defineProperty(exports,"useSignal",{enumerable:!0,get:function(){return e.useSignal}}),Object.defineProperty(exports,"useSignalEffect",{enumerable:!0,get:function(){return e.useSignalEffect}});//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export { Signal, action, batch, computed, createModel, effect, signal, untracked, useComputed, useModel, useSignal, useSignalEffect } from '@preact/signals-react';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ export{Signal,action,batch,computed,createModel,effect,signal,untracked,useComputed,useModel,useSignal,useSignalEffect}from"@preact/signals-react";//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
package/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { Model, ModelConstructor, ReadonlySignal, Signal, action, batch, computed, createModel, effect, signal, untracked, useComputed, useModel, useSignal, useSignalEffect } from '@preact/signals-react';
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@wirestate/react-signals",
3
+ "version": "0.6.0",
4
+ "description": "Preact signals alias and adapters for wirestate",
5
+ "sideEffects": false,
6
+ "author": "Syrotenko Igor",
7
+ "homepage": "https://github.com/neloreck/wirestate#readme",
8
+ "license": "MIT",
9
+ "main": "./cjs/development/index.js",
10
+ "module": "./esm/development/index.js",
11
+ "types": "./index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./index.d.ts",
15
+ "import": {
16
+ "production": "./esm/production/index.js",
17
+ "default": "./esm/development/index.js"
18
+ },
19
+ "require": {
20
+ "production": "./cjs/production/index.js",
21
+ "default": "./cjs/development/index.js"
22
+ }
23
+ }
24
+ },
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/neloreck/wirestate.git"
28
+ },
29
+ "bugs": {
30
+ "url": "https://github.com/neloreck/wirestate/issues"
31
+ },
32
+ "keywords": [
33
+ "class-based",
34
+ "context",
35
+ "declarative",
36
+ "management",
37
+ "manager",
38
+ "signals",
39
+ "react",
40
+ "inversify",
41
+ "ioc",
42
+ "di",
43
+ "dependency-injection",
44
+ "state",
45
+ "store",
46
+ "typescript"
47
+ ],
48
+ "dependencies": {},
49
+ "peerDependencies": {
50
+ "@preact/signals-react": ">=3.0.0"
51
+ },
52
+ "optionalDependencies": {}
53
+ }