@fozy-labs/rx-toolkit 0.4.17 → 0.5.0-rc.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.
Files changed (77) hide show
  1. package/README.md +20 -19
  2. package/dist/common/devtools/reduxDevtools.d.ts +17 -0
  3. package/dist/common/devtools/reduxDevtools.js +98 -17
  4. package/dist/common/devtools/types.d.ts +1 -0
  5. package/dist/common/options/DefaultOptions.d.ts +0 -2
  6. package/dist/common/options/DefaultOptions.js +0 -2
  7. package/dist/common/options/SharedOptions.d.ts +0 -2
  8. package/dist/common/options/SharedOptions.js +0 -1
  9. package/dist/query/api/resetAllQueriesCache.d.ts +1 -0
  10. package/dist/query/api/resetAllQueriesCache.js +4 -0
  11. package/dist/query/core/Opertation/Operation.js +10 -7
  12. package/dist/query/core/Opertation/OperationAgent.d.ts +0 -2
  13. package/dist/query/core/Opertation/OperationAgent.js +4 -21
  14. package/dist/query/core/QueriesCache.d.ts +1 -1
  15. package/dist/query/core/QueriesCache.js +2 -6
  16. package/dist/query/core/{CleanAllQueriesSignal.d.ts → ResetAllQueriesSignal.d.ts} +1 -1
  17. package/dist/query/core/ResetAllQueriesSignal.js +11 -0
  18. package/dist/query/core/Resource/Resource.js +7 -3
  19. package/dist/query/core/Resource/ResourceAgent.d.ts +2 -3
  20. package/dist/query/core/Resource/ResourceAgent.js +62 -29
  21. package/dist/query/index.d.ts +1 -1
  22. package/dist/query/index.js +1 -1
  23. package/dist/query/lib/IndirectMap.d.ts +1 -1
  24. package/dist/query/lib/IndirectMap.js +1 -1
  25. package/dist/query/lib/ReactiveCache.d.ts +1 -1
  26. package/dist/query/lib/ReactiveCache.js +2 -2
  27. package/dist/query/react/useOperationAgent.js +2 -5
  28. package/dist/query/react/useResourceAgent.js +1 -4
  29. package/dist/query/types/Operation.types.d.ts +1 -3
  30. package/dist/query/types/Resource.types.d.ts +1 -3
  31. package/dist/signals/base/Batcher.d.ts +1 -1
  32. package/dist/signals/base/Batcher.js +1 -1
  33. package/dist/signals/base/DependencyTracker.d.ts +18 -0
  34. package/dist/signals/base/DependencyTracker.js +13 -0
  35. package/dist/signals/base/Devtools.d.ts +1 -1
  36. package/dist/signals/base/Devtools.js +13 -1
  37. package/dist/signals/base/ReadonlySignal.d.ts +5 -7
  38. package/dist/signals/base/ReadonlySignal.js +20 -12
  39. package/dist/signals/base/index.d.ts +1 -2
  40. package/dist/signals/base/index.js +1 -2
  41. package/dist/signals/operators/index.d.ts +0 -2
  42. package/dist/signals/operators/index.js +0 -2
  43. package/dist/signals/operators/signalize.d.ts +2 -2
  44. package/dist/signals/operators/signalize.js +1 -1
  45. package/dist/signals/react/useSignal.d.ts +6 -2
  46. package/dist/signals/react/useSignal.js +2 -21
  47. package/dist/signals/signals/Computed.d.ts +13 -11
  48. package/dist/signals/signals/Computed.js +79 -26
  49. package/dist/signals/signals/Effect.d.ts +11 -7
  50. package/dist/signals/signals/Effect.js +60 -58
  51. package/dist/signals/signals/LocalSignal.d.ts +14 -7
  52. package/dist/signals/signals/LocalSignal.js +52 -33
  53. package/dist/signals/signals/Signal.d.ts +13 -37
  54. package/dist/signals/signals/Signal.js +44 -58
  55. package/dist/signals/types/index.d.ts +1 -0
  56. package/dist/signals/types/index.js +1 -0
  57. package/dist/signals/types/signals.types.d.ts +16 -0
  58. package/docs/CHANGELOG.md +32 -0
  59. package/docs/devtools/README.md +162 -29
  60. package/docs/migrations/0.5.0.md +73 -0
  61. package/docs/options/README.md +89 -0
  62. package/docs/query/README.md +425 -89
  63. package/docs/release/README.md +58 -6
  64. package/docs/signals/README.md +207 -34
  65. package/docs/usage/react/README.md +261 -49
  66. package/package.json +5 -5
  67. package/dist/query/api/cleanAllQueriesCache.d.ts +0 -1
  68. package/dist/query/api/cleanAllQueriesCache.js +0 -4
  69. package/dist/query/core/CleanAllQueriesSignal.js +0 -11
  70. package/dist/signals/base/Tracker.d.ts +0 -10
  71. package/dist/signals/base/Tracker.js +0 -7
  72. package/dist/signals/base/types.d.ts +0 -23
  73. package/dist/signals/operators/filterUpdates.d.ts +0 -5
  74. package/dist/signals/operators/filterUpdates.js +0 -18
  75. package/dist/signals/operators/mapSignals.d.ts +0 -3
  76. package/dist/signals/operators/mapSignals.js +0 -10
  77. /package/dist/signals/{base/types.js → types/signals.types.js} +0 -0
@@ -9,43 +9,47 @@ RxToolkit предоставляет набор React хуков для эффе
9
9
  Подписывается на изменения сигнала и возвращает текущее значение.
10
10
 
11
11
  ```tsx
12
- import { useSignal } from '@fozy-labs/rx-toolkit';
12
+ import { Signal, Computed, useSignal } from '@fozy-labs/rx-toolkit';
13
+
14
+ const counter$ = Signal.create(0);
15
+ const doubled$ = Signal.compute(() => counter$() * 2);
13
16
 
14
17
  function Counter() {
15
- const count = useSignal(countSignal);
16
-
17
- return (
18
- <div>
19
- <p>Count: {count}</p>
20
- <button onClick={() => countSignal.value++}>
21
- Increment
22
- </button>
23
- </div>
24
- );
18
+ const count = useSignal(counter$);
19
+ const doubled = useSignal(doubled$);
20
+
21
+ return (
22
+ <div>
23
+ <p>Count: {count}</p>
24
+ <p>Doubled: {doubled}</p>
25
+ <button onClick={() => counter$.set(counter$.peek() + 1)}>
26
+ Increment
27
+ </button>
28
+ </div>
29
+ );
25
30
  }
26
31
  ```
27
32
 
28
33
  **Особенности:**
29
- - Автоматическая подписка и отписка
30
- - Использует `useSyncExternalStore` для оптимальной производительности
34
+ - Автоматическая подписка и отписка при размонтировании
31
35
  - Не вызывает ре-рендер, если значение не изменилось
32
36
 
33
37
  ### useObservable
34
38
 
35
39
  Подписывается на RxJS Observable и возвращает текущее значение.
36
40
 
37
- ```typescript
41
+ ```tsx
38
42
  import { useObservable } from '@fozy-labs/rx-toolkit';
39
43
  import { interval, map } from 'rxjs';
40
44
 
41
45
  const timer$ = interval(1000).pipe(
42
- map(count => `Timer: ${count}`)
46
+ map(count => `Timer: ${count}`)
43
47
  );
44
48
 
45
49
  function Timer() {
46
- const timerValue = useObservable(timer$, 'Timer: 0');
47
-
48
- return <div>{timerValue}</div>;
50
+ const timerValue = useObservable(timer$, 'Timer: 0');
51
+
52
+ return <div>{timerValue}</div>;
49
53
  }
50
54
  ```
51
55
 
@@ -53,10 +57,13 @@ function Timer() {
53
57
  - `observable$` — RxJS Observable для подписки
54
58
  - `initialValue` — начальное значение до первой эмиссии
55
59
 
60
+ **Особенности:**
61
+ - Требует начальное значение, если Observable асинхронный
62
+ - Автоматическая переподписка при смене Observable
63
+
56
64
  ### useSyncObservable
57
65
 
58
66
  Синхронная версия `useObservable` для Observable, которые могут выдать значение немедленно.
59
- Если Observable не может выдать значение сразу, будет выброшена ошибка.
60
67
 
61
68
  ```tsx
62
69
  import { useSyncObservable } from '@fozy-labs/rx-toolkit';
@@ -65,68 +72,100 @@ import { BehaviorSubject } from 'rxjs';
65
72
  const data$ = new BehaviorSubject('initial data');
66
73
 
67
74
  function DataComponent() {
68
- const data = useSyncObservable(data$);
69
-
70
- return <div>Data: {data}</div>;
75
+ const data = useSyncObservable(data$);
76
+
77
+ return <div>Data: {data}</div>;
71
78
  }
72
79
  ```
73
80
 
74
81
  **Отличия от useObservable:**
75
82
  - Не требует начального значения
76
- - Получает значение синхронно при первом рендере
77
- - Подходит для BehaviorSubject и других синхронных Observable
83
+ - Подходит для BehaviorSubject, ReplaySubject и сигналов
84
+ - Выбросит ошибку, если Observable не эмитит значение синхронно
85
+
86
+ ---
78
87
 
79
88
  ## RxQuery хуки
80
89
 
81
90
  ### useResourceAgent
82
91
 
83
- Подписывается на состояние ресурса и автоматически инициирует запрос.
92
+ Подписывается на состояние ресурса и автоматически инициирует запрос при монтировании или изменении аргументов.
84
93
 
85
94
  ```tsx
86
95
  import { useResourceAgent, SKIP } from '@fozy-labs/rx-toolkit';
87
- import { userResource } from '../api/userResource.ts';
96
+ import { userResource } from '../api/userResource';
88
97
 
89
- // Автоматическая инициация
90
98
  function UserProfile({ userId }: { userId: string | null }) {
91
- const userState = useResourceAgent(userResource, userId ? { id: userId } : SKIP);
92
-
93
- if (userState.isLoading || !userId) return <div>Загрузка...</div>;
94
- if (userState.isError) return <div>Ошибка: {userState.error?.message}</div>;
95
-
96
- return (
97
- <div>
98
- <h1>{userState.data?.name}</h1>
99
- <p>{userState.data?.email}</p>
100
- </div>
101
- );
99
+ const userQuery = useResourceAgent(
100
+ userResource,
101
+ userId ? { id: userId } : SKIP
102
+ );
103
+
104
+ if (userQuery.isInitialLoading) {
105
+ return <div>Загрузка...</div>;
106
+ }
107
+
108
+ if (userQuery.isError) {
109
+ return <div>Ошибка: {String(userQuery.error)}</div>;
110
+ }
111
+
112
+ if (userQuery.isReloading) {
113
+ // Показываем данные + индикатор перезагрузки
114
+ }
115
+
116
+ return (
117
+ <div>
118
+ <h1>{userQuery.data?.name}</h1>
119
+ <p>{userQuery.data?.email}</p>
120
+ </div>
121
+ );
102
122
  }
103
123
  ```
104
124
 
125
+ **Возвращаемое значение (ResourceQueryState):**
126
+
127
+ | Поле | Тип | Описание |
128
+ |--------------------|-------------|---------------------------------------|
129
+ | `isLoading` | `boolean` | Любая загрузка (первая или повторная) |
130
+ | `isInitialLoading` | `boolean` | Первая загрузка (данных еще нет) |
131
+ | `isReloading` | `boolean` | Перезагрузка (данные уже есть) |
132
+ | `isDone` | `boolean` | Завершен ли запрос |
133
+ | `isSuccess` | `boolean` | Успешно ли завершен последний запрос |
134
+ | `isError` | `boolean` | Произошла ли ошибка |
135
+ | `isLocked` | `boolean` | Заблокирован ли ресурс для операцией |
136
+ | `error` | `unknown` | Объект ошибки |
137
+ | `data` | `D["Data"]` | Данные ресурса |
138
+ | `args` | `D["Args"]` | Аргументы последнего запроса |
139
+
105
140
  **Особенности:**
106
141
  - Автоматическая подписка на состояние ресурса
107
142
  - Умная инициация: не повторяет запрос для тех же аргументов
108
- - Поддержка SKIP токена для ручного управления
143
+ - Поддержка `SKIP` токена для условного пропуска запроса
144
+ - При смене аргументов показывает предыдущие данные во время загрузки новых
109
145
 
110
146
  ### useOperationAgent
111
147
 
112
- Подписывается на состояние операции для отслеживания выполнения мутаций.
148
+ Создает агент операции и возвращает кортеж `[trigger, state]`.
113
149
 
114
150
  ```tsx
115
151
  import { useOperationAgent } from '@fozy-labs/rx-toolkit';
116
- import { updateUserOperation } from '../api/updateUserOperation.ts';
117
- import { User } from '../types/user.ts';
152
+ import { updateUserOperation } from '../api/updateUserOperation';
118
153
 
119
154
  function EditUserForm({ user }: { user: User }) {
120
- const [updateUser, updateUserQuery] = useOperationAgent(updateUserOperation);
155
+ const [updateUser, updateState] = useOperationAgent(updateUserOperation);
121
156
 
122
157
  const handleSubmit = async (event: React.FormEvent) => {
123
158
  event.preventDefault();
124
159
  const formData = new FormData(event.target as HTMLFormElement);
160
+
125
161
  try {
126
- await agent.initiate({ id: user.id, data: formData });
127
- alert('Пользователь обновлен');
162
+ const result = await updateUser({
163
+ id: user.id,
164
+ data: Object.fromEntries(formData)
165
+ });
166
+ console.log('Обновлено:', result);
128
167
  } catch (error) {
129
- alert('Ошибка при обновлении пользователя');
168
+ console.error('Ошибка:', error);
130
169
  }
131
170
  };
132
171
 
@@ -134,11 +173,184 @@ function EditUserForm({ user }: { user: User }) {
134
173
  <form onSubmit={handleSubmit}>
135
174
  <input name="name" defaultValue={user.name} />
136
175
  <input name="email" defaultValue={user.email} />
137
- <button type="submit" disabled={updateUserQuery.isLoading}>
138
- {updateUserQuery.isLoading ? 'Обновление...' : 'Обновить'}
176
+
177
+ <button type="submit" disabled={updateState.isLoading}>
178
+ {updateState.isLoading ? 'Сохранение...' : 'Сохранить'}
139
179
  </button>
140
- {updateUserQuery.isError && <p>Ошибка: {updateUserQuery.error?.message}</p>}
180
+
181
+ {updateState.isError && (
182
+ <p className="error">Ошибка: {String(updateState.error)}</p>
183
+ )}
141
184
  </form>
142
185
  );
143
186
  }
144
187
  ```
188
+
189
+ **Возвращаемое значение:**
190
+ ```typescript
191
+ [
192
+ trigger: (args: Args) => Promise<Data>, // Функция запуска операции
193
+ state: OperationQueryState // Текущее состояние
194
+ ]
195
+ ```
196
+
197
+ **trigger функция:**
198
+ - Возвращает Promise с результатом операции
199
+ - При ошибке Promise реджектится
200
+ - Функция стабильна (не меняется между рендерами)
201
+
202
+ **state объект:**
203
+
204
+ | Поле | Тип | Описание |
205
+ |---------------|-------------|---------------------------|
206
+ | `isInitiated` | `boolean` | Была ли операция запущена |
207
+ | `isLoading` | `boolean` | Выполняется ли операция |
208
+ | `isDone` | `boolean` | Завершена ли операция |
209
+ | `isSuccess` | `boolean` | Успешно ли завершена |
210
+ | `isError` | `boolean` | Произошла ли ошибка |
211
+ | `error` | `unknown` | Объект ошибки |
212
+ | `data` | `D["Data"]` | Результат операции |
213
+
214
+ ### useResourceRef
215
+
216
+ Возвращает ссылку на элемент кэша ресурса для низкоуровневых операций.
217
+
218
+ ```tsx
219
+ import { useResourceRef, useResourceAgent } from '@fozy-labs/rx-toolkit';
220
+ import { todoResource } from '../api/todoResource';
221
+
222
+ function TodoItem({ todo }: { todo: Todo }) {
223
+ const todoQuery = useResourceAgent(todoResource, undefined);
224
+ const todoRef = useResourceRef(todoResource, undefined);
225
+
226
+ const [pendingTransaction, setPendingTransaction] = useState(null);
227
+
228
+ const handleToggle = () => {
229
+ // Создаем транзакцию для изменения
230
+ const transaction = todoRef.patch((draft) => {
231
+ const item = draft.items.find(i => i.id === todo.id);
232
+ if (item) item.completed = !item.completed;
233
+ });
234
+
235
+ if (transaction) {
236
+ setPendingTransaction(transaction);
237
+ }
238
+ };
239
+
240
+ const handleSave = async () => {
241
+ try {
242
+ await saveToServer(todo.id, !todo.completed);
243
+ pendingTransaction?.commit();
244
+ } catch {
245
+ pendingTransaction?.abort(); // Откатить изменения
246
+ }
247
+ setPendingTransaction(null);
248
+ };
249
+
250
+ return (
251
+ <div>
252
+ <input
253
+ type="checkbox"
254
+ checked={todo.completed}
255
+ onChange={handleToggle}
256
+ />
257
+ {pendingTransaction && (
258
+ <>
259
+ <button onClick={handleSave}>Сохранить</button>
260
+ <button onClick={() => {
261
+ pendingTransaction.abort();
262
+ setPendingTransaction(null);
263
+ }}>
264
+ Отмена
265
+ </button>
266
+ </>
267
+ )}
268
+ </div>
269
+ );
270
+ }
271
+ ```
272
+
273
+ **Возвращаемое значение (ResourceRefInstanse):**
274
+
275
+ | Метод | Описание |
276
+ |-------|----------|
277
+ | `has` | Проверка наличия элемента в кэше |
278
+ | `lock()` | Блокировка ресурса, возвращает `{ unlock }` |
279
+ | `unlockOne()` | Снятие одной блокировки |
280
+ | `patch(fn)` | Создание patch-транзакции |
281
+ | `invalidate()` | Инвалидация кэша |
282
+ | `create(data)` | Создание элемента в кэше |
283
+
284
+
285
+ ---
286
+
287
+ ## Паттерны использования
288
+
289
+ ### Store класс
290
+
291
+ ```tsx
292
+ import { Signal, useSignal } from '@fozy-labs/rx-toolkit';
293
+
294
+ class CounterStore {
295
+ count$ = Signal.create(0, 'counter');
296
+ doubled$ = Signal.compute(() => this.count$() * 2);
297
+
298
+ increment = () => this.count$.set(this.count$.peek() + 1);
299
+ decrement = () => this.count$.set(this.count$.peek() - 1);
300
+ reset = () => this.count$.set(0);
301
+ }
302
+
303
+ // Singleton
304
+ const counterStore = new CounterStore();
305
+
306
+ function Counter() {
307
+ const count = useSignal(counterStore.count$);
308
+ const doubled = useSignal(counterStore.doubled$);
309
+
310
+ return (
311
+ <div>
312
+ <p>{count} × 2 = {doubled}</p>
313
+ <button onClick={counterStore.increment}>+</button>
314
+ <button onClick={counterStore.decrement}>-</button>
315
+ <button onClick={counterStore.reset}>Reset</button>
316
+ </div>
317
+ );
318
+ }
319
+ ```
320
+
321
+ ### Условные запросы
322
+
323
+ ```tsx
324
+ function UserStats({ userId, showStats }) {
325
+ const statsQuery = useResourceAgent(
326
+ statsResource,
327
+ showStats && userId ? { userId } : SKIP
328
+ );
329
+
330
+ if (!showStats) return null;
331
+
332
+ return <StatsDisplay data={statsQuery.data} />;
333
+ }
334
+ ```
335
+
336
+ ### Комбинирование ресурсов
337
+
338
+ ```tsx
339
+ function Dashboard() {
340
+ const userQuery = useResourceAgent(userResource, { id: currentUserId });
341
+ const settingsQuery = useResourceAgent(settingsResource, undefined);
342
+
343
+ const isLoading = userQuery.isLoading || settingsQuery.isLoading;
344
+ const isError = userQuery.isError || settingsQuery.isError;
345
+
346
+ if (isLoading) return <Loader />;
347
+ if (isError) return <Error />;
348
+
349
+ return (
350
+ <div>
351
+ <UserInfo user={userQuery.data} />
352
+ <Settings settings={settingsQuery.data} />
353
+ </div>
354
+ );
355
+ }
356
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fozy-labs/rx-toolkit",
3
- "version": "0.4.17",
3
+ "version": "0.5.0-rc.0",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "type": "module",
@@ -11,16 +11,16 @@
11
11
  },
12
12
  "devDependencies": {
13
13
  "concurrently": "9.2.0",
14
- "rimraf": "6.0.1",
14
+ "rimraf": "6.1.2",
15
15
  "tsc-alias": "^1.8.16",
16
16
  "tsconfig-paths": "4.2.0",
17
17
  "typescript": "5.9.2",
18
18
  "zod": "4.1.11"
19
19
  },
20
20
  "peerDependencies": {
21
- "react": "19.1.1",
22
- "rxjs": "7.8.2",
23
- "zod": "4.1.11"
21
+ "react": "^19.0.0",
22
+ "rxjs": "^7.0.0",
23
+ "zod": "^4.0.0"
24
24
  },
25
25
  "description": "Набор инструментов для реактивного управления состоянием, построенный поверх RxJS.",
26
26
  "author": "Vladimir Panev <vova6255@gmail.com>",
@@ -1 +0,0 @@
1
- export declare function cleanAllQueriesCache(): void;
@@ -1,4 +0,0 @@
1
- import { CleanAllQueriesSignal } from "../core/CleanAllQueriesSignal";
2
- export function cleanAllQueriesCache() {
3
- CleanAllQueriesSignal.clean();
4
- }
@@ -1,11 +0,0 @@
1
- import { Subject } from "rxjs";
2
- import { Batcher } from "../../signals";
3
- export class CleanAllQueriesSignal {
4
- static subject$ = new Subject();
5
- static clean$ = CleanAllQueriesSignal.subject$;
6
- static clean() {
7
- Batcher.batch(() => {
8
- CleanAllQueriesSignal.subject$.next();
9
- });
10
- }
11
- }
@@ -1,10 +0,0 @@
1
- import { type Observable, Subject } from "rxjs";
2
- type TrackedValue = {
3
- rang: number;
4
- obsv$: Observable<unknown>;
5
- };
6
- export declare const Tracker: {
7
- tracked$: Subject<TrackedValue>;
8
- next(rang: number, observable: Observable<unknown>): void;
9
- };
10
- export {};
@@ -1,7 +0,0 @@
1
- import { Subject } from "rxjs";
2
- export const Tracker = {
3
- tracked$: new Subject(),
4
- next(rang, observable) {
5
- Tracker.tracked$.next({ rang, obsv$: observable, });
6
- }
7
- };
@@ -1,23 +0,0 @@
1
- import type { Observable } from "rxjs";
2
- export interface ReadableSignalLike<T = unknown> extends Observable<T> {
3
- get value(): T;
4
- peek(): T;
5
- /**
6
- * @deprecated use `value` instead.
7
- */
8
- get(): T;
9
- }
10
- export interface SignalLike<T = unknown> extends ReadableSignalLike<T> {
11
- set value(value: T);
12
- next(value: T): void;
13
- asReadonly(): ReadableSignalLike<T>;
14
- /**
15
- * @deprecated use `value` instead.
16
- */
17
- set(value: T): void;
18
- }
19
- export interface UnaryFunction<T, R> {
20
- (source: T): R;
21
- }
22
- export type SignalOperatorFn<T, R> = UnaryFunction<ReadableSignalLike<T>, ReadableSignalLike<R>>;
23
- export type MonoTypeSignalOperatorFn<T> = SignalOperatorFn<T, T>;
@@ -1,5 +0,0 @@
1
- import { type TruthyTypesOf } from "rxjs";
2
- import type { MonoTypeSignalOperatorFn, SignalOperatorFn } from "../base";
3
- export declare function filterUpdates<T, S extends T>(predicate: (value: T, index: number) => value is S): SignalOperatorFn<T, S>;
4
- export declare function filterUpdates<T>(predicate: BooleanConstructor): SignalOperatorFn<T, TruthyTypesOf<T>>;
5
- export declare function filterUpdates<T>(predicate: (value: T, index: number) => boolean): MonoTypeSignalOperatorFn<T>;
@@ -1,18 +0,0 @@
1
- import { createOperatorSubscriber } from "rxjs/internal/operators/OperatorSubscriber";
2
- import { ReadonlySignal } from "../base";
3
- export function filterUpdates(predicate, thisArg) {
4
- return (source) => new ReadonlySignal((destination) => {
5
- let index = 0;
6
- let isFirst = true;
7
- source.subscribe(createOperatorSubscriber(destination, (value) => {
8
- if (isFirst) {
9
- isFirst = false;
10
- destination.next(value);
11
- return;
12
- }
13
- const result = predicate.call(thisArg, value, index++);
14
- if (result)
15
- destination.next(value);
16
- }));
17
- });
18
- }
@@ -1,3 +0,0 @@
1
- import type { SignalOperatorFn } from "../base";
2
- export declare function mapSignals<T, R, A>(project: (this: A, value: T, index: number) => R): SignalOperatorFn<T, R>;
3
- export declare function mapSignals<T, R, A>(project: (this: A, value: T, index: number) => R, thisArg: A): SignalOperatorFn<T, R>;
@@ -1,10 +0,0 @@
1
- import { createOperatorSubscriber } from "rxjs/internal/operators/OperatorSubscriber";
2
- import { ReadonlySignal } from "../base";
3
- export function mapSignals(project, thisArg) {
4
- return (source) => new ReadonlySignal((destination) => {
5
- let index = 0;
6
- source.subscribe(createOperatorSubscriber(destination, (value) => {
7
- destination.next(project.call(thisArg, value, index++));
8
- }));
9
- });
10
- }