reactjs-signal 1.0.0 → 1.0.2

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 +1,382 @@
1
- # Template create npm package
1
+ <p align="center">
2
+ <a href="https://www.npmjs.com/package/reactjs-signal" target="_blank" rel="noopener noreferrer">
3
+ <img src="https://api.iconify.design/uil:comment-verify.svg?color=%23b3ff75" alt="logo" width='100'/></a>
4
+ </p>
5
+
6
+ <p align="center">
7
+ Share Store State with Signal Pattern
8
+ </p>
9
+
10
+ <p align="center">
11
+ <a href="https://www.npmjs.com/package/reactjs-signal" target="_blank" rel="noopener noreferrer"><img src="https://badge.fury.io/js/reactjs-signal.svg" alt="NPM Version" /></a>
12
+ <a href="https://www.npmjs.com/package/reactjs-signal" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/npm/dt/reactjs-signal.svg?logo=npm" alt="NPM Downloads" /></a>
13
+ <a href="https://bundlephobia.com/result?p=reactjs-signal" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/bundlephobia/minzip/reactjs-signal" alt="Minizip" /></a>
14
+ <a href="https://github.com/hunghg255/reactjs-signal/graphs/contributors" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/badge/all_contributors-1-orange.svg" alt="Contributors" /></a>
15
+ <a href="https://github.com/hunghg255/reactjs-signal/blob/main/LICENSE" target="_blank" rel="noopener noreferrer"><img src="https://badgen.net/github/license/hunghg255/reactjs-signal" alt="License" /></a>
16
+ </p>
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install reactjs-signal
22
+ ```
23
+
24
+
25
+ ## Usage
26
+
27
+ ```tsx
28
+ import React from 'react';
29
+ import { useSignal } from 'reactjs-signal';
30
+
31
+ const App = () => {
32
+ const [state, setState] = useSignal({ count: 0 });
33
+
34
+ return (
35
+ <div>
36
+ <h1>{state.count}</h1>
37
+ <button onClick={() => setState({ count: state.count + 1 })}>Increment</button>
38
+ </div>
39
+ );
40
+ };
41
+ ```
42
+
43
+ ## API Documentation
44
+
45
+ ### `createSignal`
46
+
47
+ Creates a writable Alien Signal.
48
+
49
+ #### Example
50
+
51
+ ```typescript
52
+ const countSignal = createSignal(0);
53
+ countSignal.set(10); // sets the value to 10
54
+ ```
55
+
56
+ #### Parameters
57
+
58
+ - `initialValue` (`T`): The initial value of the signal.
59
+
60
+ #### Returns
61
+
62
+ - `IWritableSignal<T>`: The created Alien Signal.
63
+
64
+ ### `createComputed`
65
+
66
+ Creates a computed Alien Signal based on a getter function.
67
+
68
+ #### Example
69
+
70
+ ```typescript
71
+ const countSignal = createSignal(1);
72
+ const doubleSignal = createComputed(() => countSignal.get() * 2);
73
+ ```
74
+
75
+ #### Parameters
76
+
77
+ - `fn` (`() => T`): A getter function returning a computed value.
78
+
79
+ #### Returns
80
+
81
+ - `ISignal<T>`: The created computed signal.
82
+
83
+ ### `createEffect`
84
+
85
+ Creates a side effect in Alien Signals.
86
+
87
+ #### Example
88
+
89
+ ```typescript
90
+ const countSignal = createSignal(1);
91
+ createEffect(() => {
92
+ console.log('Count is', countSignal.get());
93
+ });
94
+ ```
95
+
96
+ #### Parameters
97
+
98
+ - `fn` (`() => T`): A function that will run whenever its tracked signals update.
99
+
100
+ #### Returns
101
+
102
+ - `Effect<T>`: The created effect object.
103
+
104
+ ### `createSignalScope`
105
+
106
+ Creates an Alien Signals effect scope. This scope can manage multiple effects, allowing you to stop or start them together.
107
+
108
+ #### Example
109
+
110
+ ```typescript
111
+ const scope = createSignalScope();
112
+ scope.run(() => {
113
+ // create effects in here...
114
+ });
115
+ ```
116
+
117
+ #### Returns
118
+
119
+ - `EffectScope`: The created effect scope.
120
+
121
+ ### `unstable_createAsyncComputed`
122
+
123
+ Creates an async computed signal in Alien Signals. The getter is an async generator that yields dependencies and finally resolves to a computed value.
124
+
125
+ #### Example
126
+
127
+ ```typescript
128
+ const asyncComp = createAsyncComputed<number>(async function* () {
129
+ yield someDependency;
130
+ return 42;
131
+ });
132
+ ```
133
+
134
+ #### Parameters
135
+
136
+ - `getter` (`() => AsyncGenerator<Dependency, T>`): An async generator returning dependencies and ultimately a value.
137
+
138
+ #### Returns
139
+
140
+ - `AsyncComputed<T>`: The created async computed signal.
141
+
142
+ ### `unstable_createAsyncEffect`
143
+
144
+ Creates an async effect in Alien Signals. The function is an async generator that yields dependencies as they are discovered.
145
+
146
+ #### Example
147
+
148
+ ```typescript
149
+ createAsyncEffect(async function* () {
150
+ yield someDependency;
151
+ console.log('Async effect done!');
152
+ });
153
+ ```
154
+
155
+ #### Parameters
156
+
157
+ - `fn` (`() => AsyncGenerator<Dependency, T>`): An async generator returning dependencies.
158
+
159
+ #### Returns
160
+
161
+ - `Promise<T>`: The created async effect object.
162
+
163
+ ### `unstable_createComputedArray`
164
+
165
+ Creates a computed array signal in Alien Signals, deriving a reactive array from an original signal array.
166
+
167
+ #### Example
168
+
169
+ ```typescript
170
+ const numbersSignal = createSignal([1, 2, 3]);
171
+ const compArray = createComputedArray(numbersSignal, (itemSignal, i) => () => {
172
+ return itemSignal.get() * 2;
173
+ });
174
+ ```
175
+
176
+ #### Parameters
177
+
178
+ - `arr` (`ISignal<I[]>`): Signal containing an array.
179
+ - `getGetter` (`(itemSignal: ISignal<I>, index: number) => () => O`): A function returning a getter for each item signal.
180
+
181
+ #### Returns
182
+
183
+ - `Readonly<O[]>`: A proxied array signal.
184
+
185
+ ### `unstable_createComputedSet`
186
+
187
+ Creates a computed Set signal in Alien Signals that tracks changes to a source Set signal.
188
+
189
+ #### Example
190
+
191
+ ```typescript
192
+ const setSignal = createSignal(new Set([1, 2]));
193
+ const compSet = createComputedSet(setSignal);
194
+ ```
195
+
196
+ #### Parameters
197
+
198
+ - `source` (`IWritableSignal<Set<T>>`): A signal containing a Set.
199
+
200
+ #### Returns
201
+
202
+ - `ISignal<Set<T>>`: A computed signal referencing that Set.
203
+
204
+ ### `unstable_createEqualityComputed`
205
+
206
+ Creates an equality-based computed signal, only updating when the new value is not deeply equal to the old value.
207
+
208
+ #### Example
209
+
210
+ ```typescript
211
+ const eqComp = createEqualityComputed(() => {
212
+ return { foo: 'bar' };
213
+ });
214
+ ```
215
+
216
+ #### Parameters
217
+
218
+ - `getter` (`() => T`): A function returning the value to compare.
219
+
220
+ #### Returns
221
+
222
+ - `ISignal<T>`: An equality computed signal.
223
+
224
+ ### `useSignal`
225
+
226
+ React hook returning `[value, setValue]` for a given Alien Signal. Uses `useSyncExternalStore` for concurrency-safe re-renders.
227
+
228
+ #### Example
229
+
230
+ ```typescript
231
+ const countSignal = createSignal(0);
232
+ function Counter() {
233
+ const [count, setCount] = useSignal(countSignal);
234
+ return <button onClick={() => setCount(count + 1)}>{count}</button>;
235
+ }
236
+ ```
237
+
238
+ #### Parameters
239
+
240
+ - `alienSignal` (`IWritableSignal<T>`): The signal to read/write.
241
+
242
+ #### Returns
243
+
244
+ - `[T, (val: T | ((oldVal: T) => T)) => void]`: A tuple `[currentValue, setValue]`.
245
+
246
+ ### `useSignalValue`
247
+
248
+ React hook returning only the current value of an Alien Signal (or computed). No setter is provided.
249
+
250
+ #### Example
251
+
252
+ ```typescript
253
+ const countSignal = createSignal(0);
254
+ const doubleSignal = createComputed(() => countSignal.get() * 2);
255
+ function Display() {
256
+ const count = useSignalValue(countSignal);
257
+ const double = useSignalValue(doubleSignal);
258
+ return <div>{count}, {double}</div>;
259
+ }
260
+ ```
261
+
262
+ #### Parameters
263
+
264
+ - `alienSignal` (`IWritableSignal<T>`): The signal to read.
265
+
266
+ #### Returns
267
+
268
+ - `T`: The current value.
269
+
270
+ ### `useSetSignal`
271
+
272
+ React hook returning only a setter function for an Alien Signal. No current value is provided, similar to Jotai's `useSetAtom`.
273
+
274
+ #### Example
275
+
276
+ ```typescript
277
+ const countSignal = createSignal(0);
278
+ function Incrementor() {
279
+ const setCount = useSetSignal(countSignal);
280
+ return <button onClick={() => setCount((c) => c + 1)}>+1</button>;
281
+ }
282
+ ```
283
+
284
+ #### Parameters
285
+
286
+ - `alienSignal` (`IWritableSignal<T>`): The signal to write.
287
+
288
+ #### Returns
289
+
290
+ - `(val: T | ((oldVal: T) => T)) => void`: A setter function.
291
+
292
+ ### `useSignalEffect`
293
+
294
+ React hook for running a side effect whenever Alien Signals' dependencies used in `fn` change. The effect is cleaned up on component unmount.
295
+
296
+ #### Example
297
+
298
+ ```typescript
299
+ function Logger() {
300
+ useSignalEffect(() => {
301
+ console.log('Signal changed:', someSignal.get());
302
+ });
303
+ return null;
304
+ }
305
+ ```
306
+
307
+ #### Parameters
308
+
309
+ - `fn` (`() => void`): The effect function to run.
310
+
311
+ ### `useSignalScope`
312
+
313
+ React hook for managing an Alien Signals effect scope. All signals/effects created inside this scope run when the component mounts, and are stopped automatically when the component unmounts.
314
+
315
+ #### Example
316
+
317
+ ```typescript
318
+ function ScopedEffects() {
319
+ const scope = useSignalScope();
320
+ useEffect(() => {
321
+ scope.run(() => {
322
+ createEffect(() => {
323
+ console.log('Scoped effect:', someSignal.get());
324
+ });
325
+ });
326
+ }, [scope]);
327
+ return null;
328
+ }
329
+ ```
330
+
331
+ #### Returns
332
+
333
+ - `EffectScope`: The created effect scope.
334
+
335
+ ### `unstable_useAsyncComputedValue`
336
+
337
+ React hook to read from an async computed signal. The hook fetches the current value, subscribing to changes via `useSyncExternalStore`, and triggers a `get()` call to retrieve updated data. Maintains an internal state for the resolved value of the promise.
338
+
339
+ #### Example
340
+
341
+ ```typescript
342
+ const asyncSignal = createAsyncComputed<number>(async function*() {
343
+ const val = someSignal.get();
344
+ yield Promise.resolve(someSignal); // track async dep
345
+ return val * 2;
346
+ });
347
+
348
+ function AsyncDisplay() {
349
+ const value = useAsyncComputedValue(asyncSignal);
350
+ return <div>Value: {String(value)}</div>;
351
+ }
352
+ ```
353
+
354
+ #### Parameters
355
+
356
+ - `alienAsyncComp` (`AsyncComputed<T>`): The async computed signal to read.
357
+
358
+ #### Returns
359
+
360
+ - `T | undefined`: The resolved value (or undefined if not yet resolved).
361
+
362
+ ### `unstable_useAsyncEffect`
363
+
364
+ React hook to run an asynchronous effect whenever the component mounts, cleaning up when it unmounts.
365
+
366
+ #### Example
367
+
368
+ ```typescript
369
+ useAsyncEffect(async function* () {
370
+ yield someDependency;
371
+ console.log('Async side effect complete!');
372
+ });
373
+ ```
374
+
375
+ #### Parameters
376
+
377
+ - `fn` (`() => AsyncGenerator<Dependency, T>`): An async generator representing the effect logic.
378
+
379
+
380
+ ## Refer
381
+
382
+ React Alien Signals is a **TypeScript** library that provides hooks built on top of [Alien Signals](https://github.com/stackblitz/alien-signals).
@@ -1,4 +1,5 @@
1
- 'use client';
1
+ import { IWritableSignal, ISignal, Effect, EffectScope, Dependency, Computed } from 'alien-signals';
2
+
2
3
  /**
3
4
  *
4
5
  * React Alien Signals is a **TypeScript** library that provides hooks built on top of [Alien Signals](https://github.com/stackblitz/alien-signals).
@@ -7,27 +8,10 @@
7
8
  * @module reactjs-signal
8
9
  */
9
10
 
10
- import {
11
- computed as alienComputed,
12
- effect as alienEffect,
13
- effectScope as alienEffectScope,
14
- signal as alienSignal,
15
- unstable as alienUnstable,
16
- type Effect,
17
- type Computed,
18
- type Dependency,
19
- type EffectScope,
20
- type ISignal,
21
- type IWritableSignal,
22
- } from 'alien-signals';
23
- import { useEffect, useMemo, useState, useSyncExternalStore } from 'react';
24
-
25
11
  declare class AsyncComputed<T = any> extends Computed {
26
- get(): Promise<T>;
27
- //@ts-ignore
28
- update(): Promise<boolean>;
12
+ get(): Promise<T>;
13
+ update(): Promise<boolean>;
29
14
  }
30
-
31
15
  /**
32
16
  * Creates a writable Alien Signal.
33
17
  *
@@ -41,10 +25,7 @@ declare class AsyncComputed<T = any> extends Computed {
41
25
  * @param {T} initialValue - The initial value of the signal.
42
26
  * @returns {IWritableSignal<T>} The created Alien Signal.
43
27
  */
44
- export function createSignal<T>(initialValue: T): IWritableSignal<T> {
45
- return alienSignal<T>(initialValue);
46
- }
47
-
28
+ declare function createSignal<T>(initialValue: T): IWritableSignal<T>;
48
29
  /**
49
30
  * Creates a computed Alien Signal based on a getter function.
50
31
  *
@@ -58,10 +39,7 @@ export function createSignal<T>(initialValue: T): IWritableSignal<T> {
58
39
  * @param {() => T} fn - A getter function returning a computed value.
59
40
  * @returns {ISignal<T>} The created computed signal.
60
41
  */
61
- export function createComputed<T>(fn: () => T): ISignal<T> {
62
- return alienComputed<T>(fn);
63
- }
64
-
42
+ declare function createComputed<T>(fn: () => T): ISignal<T>;
65
43
  /**
66
44
  * Creates a side effect in Alien Signals.
67
45
  *
@@ -77,10 +55,7 @@ export function createComputed<T>(fn: () => T): ISignal<T> {
77
55
  * @param {() => T} fn - A function that will run whenever its tracked signals update.
78
56
  * @returns {Effect<T>} The created effect object.
79
57
  */
80
- export function createEffect<T>(fn: () => T): Effect<T> {
81
- return alienEffect(fn);
82
- }
83
-
58
+ declare function createEffect<T>(fn: () => T): Effect<T>;
84
59
  /**
85
60
  * Creates an Alien Signals effect scope. This scope can manage multiple effects,
86
61
  * allowing you to stop or start them together.
@@ -95,10 +70,7 @@ export function createEffect<T>(fn: () => T): Effect<T> {
95
70
  *
96
71
  * @returns {EffectScope} The created effect scope.
97
72
  */
98
- export function createSignalScope(): EffectScope {
99
- return alienEffectScope();
100
- }
101
-
73
+ declare function createSignalScope(): EffectScope;
102
74
  /**
103
75
  * Creates an async computed signal in Alien Signals. The getter is an async generator
104
76
  * that yields dependencies and finally resolves to a computed value.
@@ -116,12 +88,7 @@ export function createSignalScope(): EffectScope {
116
88
  * @returns {AsyncComputed<T>} The created async computed signal.
117
89
  * @experimental
118
90
  */
119
- export function unstable_createAsyncComputed<T>(
120
- getter: () => AsyncGenerator<Dependency, T>,
121
- ): AsyncComputed<T> {
122
- return alienUnstable.asyncComputed<T>(getter);
123
- }
124
-
91
+ declare function unstable_createAsyncComputed<T>(getter: () => AsyncGenerator<Dependency, T>): AsyncComputed<T>;
125
92
  /**
126
93
  * Creates an async effect in Alien Signals. The function is an async generator
127
94
  * that yields dependencies as they are discovered.
@@ -138,16 +105,7 @@ export function unstable_createAsyncComputed<T>(
138
105
  * @param {() => AsyncGenerator<Dependency, T>} fn - An async generator returning dependencies.
139
106
  * @returns {Promise<T>} The created async effect object.
140
107
  */
141
- export async function unstable_createAsyncEffect<T>(
142
- fn: () => AsyncGenerator<Dependency, T>,
143
- ): Promise<T> {
144
- const eff = alienUnstable.asyncEffect(fn);
145
-
146
- // Immediately run the effect and return its promise
147
- const final = await eff.run();
148
- return final;
149
- }
150
-
108
+ declare function unstable_createAsyncEffect<T>(fn: () => AsyncGenerator<Dependency, T>): Promise<T>;
151
109
  /**
152
110
  * Creates a computed array signal in Alien Signals, deriving a reactive
153
111
  * array from an original signal array.
@@ -167,13 +125,7 @@ export async function unstable_createAsyncEffect<T>(
167
125
  * @returns {Readonly<O[]>} A proxied array signal.
168
126
  * @experimental
169
127
  */
170
- export function unstable_createComputedArray<I, O>(
171
- arr: ISignal<I[]>,
172
- getGetter: (itemSignal: ISignal<I>, index: number) => () => O,
173
- ): Readonly<O[]> {
174
- return alienUnstable.computedArray<I, O>(arr, getGetter);
175
- }
176
-
128
+ declare function unstable_createComputedArray<I, O>(arr: ISignal<I[]>, getGetter: (itemSignal: ISignal<I>, index: number) => () => O): Readonly<O[]>;
177
129
  /**
178
130
  * Creates a computed Set signal in Alien Signals that tracks changes
179
131
  * to a source Set signal.
@@ -189,10 +141,7 @@ export function unstable_createComputedArray<I, O>(
189
141
  * @returns {ISignal<Set<T>>} A computed signal referencing that Set.
190
142
  * @experimental
191
143
  */
192
- export function unstable_createComputedSet<T>(source: IWritableSignal<Set<T>>): ISignal<Set<T>> {
193
- return alienUnstable.computedSet<T>(source);
194
- }
195
-
144
+ declare function unstable_createComputedSet<T>(source: IWritableSignal<Set<T>>): ISignal<Set<T>>;
196
145
  /**
197
146
  * Creates an equality-based computed signal, only updating when the new value
198
147
  * is not deeply equal to the old value.
@@ -209,10 +158,7 @@ export function unstable_createComputedSet<T>(source: IWritableSignal<Set<T>>):
209
158
  * @returns {ISignal<T>} An equality computed signal.
210
159
  * @experimental
211
160
  */
212
- export function unstable_createEqualityComputed<T>(getter: () => T): ISignal<T> {
213
- return alienUnstable.equalityComputed(getter);
214
- }
215
-
161
+ declare function unstable_createEqualityComputed<T>(getter: () => T): ISignal<T>;
216
162
  /**
217
163
  * React hook returning `[value, setValue]` for a given Alien Signal.
218
164
  * Uses useSyncExternalStore for concurrency-safe re-renders.
@@ -230,32 +176,7 @@ export function unstable_createEqualityComputed<T>(getter: () => T): ISignal<T>
230
176
  * @param {IWritableSignal<T>} alienSignal - The signal to read/write.
231
177
  * @returns {[T, (val: T | ((oldVal: T) => T)) => void]} A tuple [currentValue, setValue].
232
178
  */
233
- export function useSignal<T>(
234
- alienSignal: IWritableSignal<T>,
235
- ): [T, (val: T | ((oldVal: T) => T)) => void] {
236
- const value = useSyncExternalStore(
237
- (callback) => {
238
- const eff = alienEffect(() => {
239
- alienSignal.get(); // track
240
- callback();
241
- });
242
- return () => eff.stop();
243
- },
244
- () => alienSignal.get(),
245
- () => alienSignal.get(), // server snapshot
246
- );
247
-
248
- const setValue = (val: T | ((oldVal: T) => T)) => {
249
- if (typeof val === 'function') {
250
- alienSignal.set((val as (oldVal: T) => T)(alienSignal.get()));
251
- } else {
252
- alienSignal.set(val);
253
- }
254
- };
255
-
256
- return [value, setValue];
257
- }
258
-
179
+ declare function useSignal<T>(alienSignal: IWritableSignal<T>): [T, (val: T | ((oldVal: T) => T)) => void];
259
180
  /**
260
181
  * React hook returning only the current value of an Alien Signal (or computed).
261
182
  * No setter is provided.
@@ -275,19 +196,7 @@ export function useSignal<T>(
275
196
  * @param {IWritableSignal<T>} alienSignal - The signal to read.
276
197
  * @returns {T} The current value.
277
198
  */
278
- export function useSignalValue<T>(alienSignal: IWritableSignal<T>): T {
279
- return useSyncExternalStore(
280
- (callback) => {
281
- const eff = alienEffect(() => {
282
- alienSignal.get();
283
- callback();
284
- });
285
- return () => eff.stop();
286
- },
287
- () => alienSignal.get(),
288
- );
289
- }
290
-
199
+ declare function useSignalValue<T>(alienSignal: IWritableSignal<T>): T;
291
200
  /**
292
201
  * React hook returning only a setter function for an Alien Signal.
293
202
  * No current value is provided, similar to Jotai's useSetAtom.
@@ -305,18 +214,7 @@ export function useSignalValue<T>(alienSignal: IWritableSignal<T>): T {
305
214
  * @param {IWritableSignal<T>} alienSignal - The signal to write.
306
215
  * @returns {(val: T | ((oldVal: T) => T)) => void} A setter function.
307
216
  */
308
- export function useSetSignal<T>(
309
- alienSignal: IWritableSignal<T>,
310
- ): (val: T | ((oldVal: T) => T)) => void {
311
- return (val) => {
312
- if (typeof val === 'function') {
313
- alienSignal.set((val as (oldVal: T) => T)(alienSignal.get()));
314
- } else {
315
- alienSignal.set(val);
316
- }
317
- };
318
- }
319
-
217
+ declare function useSetSignal<T>(alienSignal: IWritableSignal<T>): (val: T | ((oldVal: T) => T)) => void;
320
218
  /**
321
219
  * React hook for running a side effect whenever Alien Signals' dependencies
322
220
  * used in `fn` change. The effect is cleaned up on component unmount.
@@ -333,13 +231,7 @@ export function useSetSignal<T>(
333
231
  *
334
232
  * @param {() => void} fn - The effect function to run.
335
233
  */
336
- export function useSignalEffect(fn: () => void): void {
337
- useEffect(() => {
338
- const eff = alienEffect(fn);
339
- return () => eff.stop();
340
- }, [fn]);
341
- }
342
-
234
+ declare function useSignalEffect(fn: () => void): void;
343
235
  /**
344
236
  * React hook for managing an Alien Signals effect scope.
345
237
  * All signals/effects created inside this scope run when the component mounts,
@@ -362,16 +254,7 @@ export function useSignalEffect(fn: () => void): void {
362
254
  *
363
255
  * @returns {EffectScope} The created effect scope.
364
256
  */
365
- export function useSignalScope(): EffectScope {
366
- const scope = useMemo(() => alienEffectScope(), []);
367
- useEffect(() => {
368
- return () => {
369
- scope.stop();
370
- };
371
- }, [scope]);
372
- return scope;
373
- }
374
-
257
+ declare function useSignalScope(): EffectScope;
375
258
  /**
376
259
  * React hook to read from an async computed signal.
377
260
  * The hook fetches the current value, subscribing to changes via useSyncExternalStore,
@@ -397,35 +280,7 @@ export function useSignalScope(): EffectScope {
397
280
  * @returns {T | undefined} The resolved value (or undefined if not yet resolved).
398
281
  * @experimental
399
282
  */
400
- export function unstable_useAsyncComputedValue<T>(alienAsyncComp: AsyncComputed<T>): T | undefined {
401
- const [value, setValue] = useState<T | undefined>(alienAsyncComp.currentValue);
402
-
403
- useSyncExternalStore(
404
- (callback) => {
405
- const eff = alienEffect(() => {
406
- alienAsyncComp.currentValue; // track
407
- callback();
408
- });
409
- return () => eff.stop();
410
- },
411
- () => alienAsyncComp.currentValue,
412
- );
413
-
414
- useEffect(() => {
415
- let active = true;
416
- const fetchValue = async () => {
417
- const val = await alienAsyncComp.get();
418
- if (active) setValue(val);
419
- };
420
- fetchValue();
421
- return () => {
422
- active = false;
423
- };
424
- }, [alienAsyncComp]);
425
-
426
- return value;
427
- }
428
-
283
+ declare function unstable_useAsyncComputedValue<T>(alienAsyncComp: AsyncComputed<T>): T | undefined;
429
284
  /**
430
285
  * React hook to run an asynchronous effect whenever the component mounts,
431
286
  * cleaning up when it unmounts.
@@ -442,9 +297,6 @@ export function unstable_useAsyncComputedValue<T>(alienAsyncComp: AsyncComputed<
442
297
  * @param {() => AsyncGenerator<Dependency, T>} fn - An async generator representing the effect logic.
443
298
  * @experimental
444
299
  */
445
- export function unstable_useAsyncEffect<T>(fn: () => AsyncGenerator<Dependency, T>): void {
446
- useEffect(() => {
447
- const eff = alienUnstable.asyncEffect(fn);
448
- return () => eff.stop();
449
- }, [fn]);
450
- }
300
+ declare function unstable_useAsyncEffect<T>(fn: () => AsyncGenerator<Dependency, T>): void;
301
+
302
+ export { createComputed, createEffect, createSignal, createSignalScope, unstable_createAsyncComputed, unstable_createAsyncEffect, unstable_createComputedArray, unstable_createComputedSet, unstable_createEqualityComputed, unstable_useAsyncComputedValue, unstable_useAsyncEffect, useSetSignal, useSignal, useSignalEffect, useSignalScope, useSignalValue };
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ import {signal,computed,effect,effectScope,unstable}from'alien-signals';import {useSyncExternalStore,useEffect,useMemo,useState}from'react';function g(e){return signal(e)}function m(e){return computed(e)}function x(e){return effect(e)}function b(){return effectScope()}function E(e){return unstable.asyncComputed(e)}async function I(e){return await unstable.asyncEffect(e).run()}function V(e,t){return unstable.computedArray(e,t)}function C(e){return unstable.computedSet(e)}function v(e){return unstable.equalityComputed(e)}function A(e){return [useSyncExternalStore(n=>{let c=effect(()=>{e.get(),n();});return ()=>c.stop()},()=>e.get(),()=>e.get()),n=>{typeof n=="function"?e.set(n(e.get())):e.set(n);}]}function _(e){return useSyncExternalStore(t=>{let o=effect(()=>{e.get(),t();});return ()=>o.stop()},()=>e.get())}function W(e){return t=>{typeof t=="function"?e.set(t(e.get())):e.set(t);}}function D(e){useEffect(()=>{let t=effect(e);return ()=>t.stop()},[e]);}function O(){let e=useMemo(()=>effectScope(),[]);return useEffect(()=>()=>{e.stop();},[e]),e}function G(e){let[t,o]=useState(e.currentValue);return useSyncExternalStore(n=>{let c=effect(()=>{e.currentValue,n();});return ()=>c.stop()},()=>e.currentValue),useEffect(()=>{let n=!0;return (async()=>{let l=await e.get();n&&o(l);})(),()=>{n=!1;}},[e]),t}function P(e){useEffect(()=>{let t=unstable.asyncEffect(e);return ()=>t.stop()},[e]);}export{m as createComputed,x as createEffect,g as createSignal,b as createSignalScope,E as unstable_createAsyncComputed,I as unstable_createAsyncEffect,V as unstable_createComputedArray,C as unstable_createComputedSet,v as unstable_createEqualityComputed,G as unstable_useAsyncComputedValue,P as unstable_useAsyncEffect,W as useSetSignal,A as useSignal,D as useSignalEffect,O as useSignalScope,_ as useSignalValue};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reactjs-signal",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
@@ -8,9 +8,13 @@
8
8
  "exports": {
9
9
  ".": {
10
10
  "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js"
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.js"
12
13
  }
13
14
  },
15
+ "files": [
16
+ "dist"
17
+ ],
14
18
  "scripts": {
15
19
  "build": "tsup",
16
20
  "watch": "npm run build -- --watch src",
@@ -40,5 +44,13 @@
40
44
  "peerDependencies": {
41
45
  "alien-signals": ">=0.4",
42
46
  "react": ">=18"
47
+ },
48
+ "bugs": {
49
+ "url": "https://github.com/hunghg255/reactjs-signal/issues"
50
+ },
51
+ "homepage": "https://github.com/hunghg255/reactjs-signal#readme",
52
+ "repository": {
53
+ "type": "git",
54
+ "url": "git+https://github.com/hunghg255/reactjs-signal.git"
43
55
  }
44
56
  }
@@ -1,95 +0,0 @@
1
- ## Git Commit Message Convention
2
-
3
- > This is adapted from [Commit convention](https://www.conventionalcommits.org/en/v1.0.0/).
4
-
5
- #### TL;DR:
6
-
7
- Messages must be matched by the following regex:
8
-
9
- ```js
10
- /^((feat|fix|docs|style|core|i18n|report|misc|cli|audits|refactor|perf|test|workflow|build|ci|chore|types|wip|release|deps?|merge|examples?|revert)(\(.+\))?(\:|\!\:)|(Merge|Revert|Version)) .{1,50}$/;
11
- ```
12
-
13
- #### Examples
14
-
15
- Appears under "Features" header, `compiler` subheader:
16
-
17
- ```
18
- feat(compiler): add 'comments' option
19
- ```
20
-
21
- Appears under "Bug Fixes" header, `v-model` subheader, with a link to issue #28:
22
-
23
- ```
24
- fix(v-model): handle events on blur
25
-
26
- close #28
27
- ```
28
-
29
- Appears under "Performance Improvements" header, and under "Breaking Changes" with the breaking change explanation:
30
-
31
- ```
32
- perf(core): improve vdom diffing by removing 'foo' option
33
-
34
- BREAKING CHANGE: The 'foo' option has been removed.
35
- ```
36
-
37
- The following commit and commit `667ecc1` do not appear in the changelog if they are under the same release. If not, the revert commit appears under the "Reverts" header.
38
-
39
- ```
40
- revert: feat(compiler): add 'comments' option
41
-
42
- This reverts commit 667ecc1654a317a13331b17617d973392f415f02.
43
- ```
44
-
45
- ### Full Message Format
46
-
47
- A commit message consists of a **header**, **body** and **footer**. The header has a **type**, **scope** and **subject**:
48
-
49
- ```
50
- <type>(<scope>): <subject>
51
- <BLANK LINE>
52
- <body>
53
- <BLANK LINE>
54
- <footer>
55
- ```
56
-
57
- The **header** is mandatory and the **scope** of the header is optional.
58
-
59
- ### Revert
60
-
61
- If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body, it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
62
-
63
- ### Type
64
-
65
- If the prefix is `feat`, `fix` or `perf`, it will appear in the changelog. However, if there is any [BREAKING CHANGE](#footer), the commit will always appear in the changelog.
66
-
67
- Other prefixes are up to your discretion. Suggested prefixes are `docs`, `chore`, `style`, `refactor`, and `test` for non-changelog related tasks.
68
-
69
- ### Scope
70
-
71
- The scope could be anything specifying the place of the commit change. For example `core`, `compiler`, `ssr`, `v-model`, `transition` etc...
72
-
73
- ### Subject
74
-
75
- The subject contains a succinct description of the change:
76
-
77
- - use the imperative, present tense: "change" not "changed" nor "changes"
78
- - don't capitalize the first letter
79
- - no dot (.) at the end
80
-
81
- ### Body
82
-
83
- Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes".
84
- The body should include the motivation for the change and contrast this with previous behavior.
85
-
86
- ### Footer
87
-
88
- The footer should contain any information about **Breaking Changes** and is also the place to
89
- reference GitHub issues that this commit **Closes**.
90
-
91
- **Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.
92
-
93
- ```
94
- feat!: breaking change / feat(scope)!: rework API
95
- ```
@@ -1,21 +0,0 @@
1
- name: CI
2
- on:
3
- push:
4
- branches:
5
- - master
6
-
7
- pull_request:
8
- branches:
9
- - master
10
-
11
- jobs:
12
- build:
13
- runs-on: ubuntu-latest
14
- steps:
15
- - uses: actions/checkout@v3
16
- - uses: actions/setup-node@v3
17
- with:
18
- node-version: 18.x
19
-
20
- - run: npm install
21
- - run: npm run lint && npm run build
@@ -1,29 +0,0 @@
1
- name: Release
2
-
3
- permissions:
4
- contents: write
5
-
6
- on:
7
- push:
8
- tags:
9
- - 'v*'
10
-
11
- jobs:
12
- release:
13
- runs-on: ubuntu-latest
14
- steps:
15
- - uses: actions/checkout@v3
16
- with:
17
- fetch-depth: 0
18
-
19
- - uses: actions/setup-node@v3
20
- with:
21
- node-version: 18.x
22
-
23
- - run: npx changeloggithub@latest
24
- env:
25
- GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
26
-
27
- - name: Publish
28
- run: |
29
- echo "Publishing"
package/tsconfig.json DELETED
@@ -1,26 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- // Enable latest features
4
- "lib": ["ESNext", "DOM"],
5
- "target": "ESNext",
6
- "module": "ESNext",
7
- "moduleDetection": "force",
8
- "allowJs": true,
9
-
10
- // Bundler mode
11
- "moduleResolution": "bundler",
12
- "allowImportingTsExtensions": true,
13
- "verbatimModuleSyntax": true,
14
- "noEmit": true,
15
-
16
- // Best practices
17
- "strict": true,
18
- "skipLibCheck": true,
19
- "noFallthroughCasesInSwitch": true,
20
-
21
- // Some stricter flags (disabled by default)
22
- "noUnusedLocals": false,
23
- "noUnusedParameters": false,
24
- "noPropertyAccessFromIndexSignature": false
25
- }
26
- }
package/tsup.config.ts DELETED
@@ -1,12 +0,0 @@
1
- import { defineConfig } from "tsup";
2
-
3
- export default defineConfig({
4
- entry: ["src/index.ts"],
5
- format: "esm",
6
- treeshake: true,
7
- clean: true,
8
- dts: true,
9
- platform: "browser",
10
- splitting: true,
11
- minify: true,
12
- });