floppy-disk 3.0.0-experimental.1 → 3.0.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 (76) hide show
  1. package/README.md +237 -685
  2. package/esm/index.d.mts +1 -0
  3. package/esm/index.mjs +1 -0
  4. package/esm/react/create-mutation.d.mts +151 -0
  5. package/esm/react/create-query.d.mts +344 -0
  6. package/esm/react/create-store.d.mts +28 -0
  7. package/esm/react/create-stores.d.mts +39 -0
  8. package/esm/react/use-isomorphic-layout-effect.d.mts +6 -0
  9. package/esm/react/use-mutation.d.mts +82 -0
  10. package/esm/react/use-store.d.mts +28 -0
  11. package/esm/react.d.mts +7 -0
  12. package/esm/react.mjs +697 -0
  13. package/esm/vanilla/basic.d.mts +13 -0
  14. package/esm/vanilla/hash.d.mts +7 -0
  15. package/esm/vanilla/store.d.mts +89 -0
  16. package/esm/vanilla.d.mts +3 -0
  17. package/esm/vanilla.mjs +82 -0
  18. package/index.d.ts +1 -0
  19. package/index.js +12 -0
  20. package/package.json +47 -45
  21. package/react/create-mutation.d.ts +151 -0
  22. package/react/create-query.d.ts +344 -0
  23. package/react/create-store.d.ts +28 -0
  24. package/react/create-stores.d.ts +39 -0
  25. package/react/use-isomorphic-layout-effect.d.ts +6 -0
  26. package/react/use-mutation.d.ts +82 -0
  27. package/react/use-store.d.ts +28 -0
  28. package/react.d.ts +7 -0
  29. package/react.js +705 -0
  30. package/ts_version_4.5_and_above_is_required.d.ts +0 -0
  31. package/vanilla/basic.d.ts +13 -0
  32. package/vanilla/hash.d.ts +7 -0
  33. package/vanilla/store.d.ts +89 -0
  34. package/vanilla.d.ts +3 -0
  35. package/vanilla.js +89 -0
  36. package/esm/index.d.ts +0 -8
  37. package/esm/index.js +0 -8
  38. package/esm/react/create-bi-direction-query.d.ts +0 -166
  39. package/esm/react/create-bi-direction-query.js +0 -74
  40. package/esm/react/create-mutation.d.ts +0 -39
  41. package/esm/react/create-mutation.js +0 -56
  42. package/esm/react/create-query.d.ts +0 -319
  43. package/esm/react/create-query.js +0 -434
  44. package/esm/react/create-store.d.ts +0 -38
  45. package/esm/react/create-store.js +0 -38
  46. package/esm/react/create-stores.d.ts +0 -61
  47. package/esm/react/create-stores.js +0 -99
  48. package/esm/react/with-context.d.ts +0 -5
  49. package/esm/react/with-context.js +0 -14
  50. package/esm/utils.d.ts +0 -24
  51. package/esm/utils.js +0 -31
  52. package/esm/vanilla/fetcher.d.ts +0 -27
  53. package/esm/vanilla/fetcher.js +0 -95
  54. package/esm/vanilla/init-store.d.ts +0 -24
  55. package/esm/vanilla/init-store.js +0 -51
  56. package/lib/index.d.ts +0 -8
  57. package/lib/index.js +0 -11
  58. package/lib/react/create-bi-direction-query.d.ts +0 -166
  59. package/lib/react/create-bi-direction-query.js +0 -78
  60. package/lib/react/create-mutation.d.ts +0 -39
  61. package/lib/react/create-mutation.js +0 -60
  62. package/lib/react/create-query.d.ts +0 -319
  63. package/lib/react/create-query.js +0 -438
  64. package/lib/react/create-store.d.ts +0 -38
  65. package/lib/react/create-store.js +0 -42
  66. package/lib/react/create-stores.d.ts +0 -61
  67. package/lib/react/create-stores.js +0 -104
  68. package/lib/react/with-context.d.ts +0 -5
  69. package/lib/react/with-context.js +0 -18
  70. package/lib/utils.d.ts +0 -24
  71. package/lib/utils.js +0 -39
  72. package/lib/vanilla/fetcher.d.ts +0 -27
  73. package/lib/vanilla/fetcher.js +0 -99
  74. package/lib/vanilla/init-store.d.ts +0 -24
  75. package/lib/vanilla/init-store.js +0 -55
  76. package/utils/package.json +0 -6
@@ -1,438 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createQuery = void 0;
4
- const react_1 = require("react");
5
- const utils_1 = require("../utils");
6
- const create_stores_1 = require("./create-stores");
7
- const INITIAL_QUERY_STATE = {
8
- isWaiting: false,
9
- isWaitingNextPage: false,
10
- status: 'loading',
11
- isLoading: true,
12
- isSuccess: false,
13
- isError: false,
14
- isRefetching: false,
15
- isRefetchError: false,
16
- isPreviousData: false,
17
- isOptimisticData: false,
18
- data: undefined,
19
- response: undefined,
20
- responseUpdatedAt: undefined,
21
- error: undefined,
22
- errorUpdatedAt: undefined,
23
- retryCount: 0,
24
- isGoingToRetry: false,
25
- pageParam: undefined,
26
- pageParams: [undefined],
27
- hasNextPage: false,
28
- retryNextPageCount: 0,
29
- isGoingToRetryNextPage: false,
30
- };
31
- const useQueryDefaultDeps = (state) => [
32
- state.data,
33
- state.error,
34
- state.isWaitingNextPage,
35
- state.hasNextPage,
36
- ];
37
- const fallbackComponent = () => null;
38
- /**
39
- * @see https://floppy-disk.vercel.app/docs/api#createquery
40
- */
41
- const createQuery = (queryFn, options = {}) => {
42
- const defaultFetchOnWindowFocus = options.fetchOnMount ?? true;
43
- const defaultFetchOnReconnect = options.fetchOnMount ?? true;
44
- const { onFirstSubscribe = utils_1.noop, onSubscribe = utils_1.noop, onLastUnsubscribe = utils_1.noop, onBeforeChangeKey = utils_1.noop, defaultDeps = useQueryDefaultDeps, select = utils_1.identityFn, staleTime = 3000, // 3 seconds
45
- fetchOnMount = true, fetchOnWindowFocus = defaultFetchOnWindowFocus, fetchOnReconnect = defaultFetchOnReconnect, enabled = true, retry = 1, retryDelay = 2000, // 2 seconds
46
- keepPreviousData, getNextPageParam = () => undefined, onSuccess = utils_1.noop, onError, onSettled = utils_1.noop, cacheTime = 5 * 60 * 1000, refetchInterval = false, ...createStoresOptions } = options;
47
- const retryTimeoutId = new Map();
48
- const retryNextPageTimeoutId = new Map();
49
- const resetTimeoutId = new Map();
50
- const refetchIntervalTimeoutId = new Map();
51
- const preventReplaceResponse = new Map(); // Prevent optimistic data to be replaced
52
- const useQuery = (0, create_stores_1.createStores)(({ get, set, key: _key, keyHash }) => {
53
- const key = _key;
54
- const getRetryProps = (error, retryCount) => {
55
- const prevState = get();
56
- const maxRetryCount = (0, utils_1.getValue)(retry, error, prevState) || 0;
57
- const delay = (0, utils_1.getValue)(retryDelay, error, prevState) || 0;
58
- return { shouldRetry: retryCount < maxRetryCount, delay };
59
- };
60
- const forceFetch = () => new Promise((resolve) => {
61
- const state = get();
62
- const { isWaiting, isLoading, pageParams } = state;
63
- const responseAllPages = [];
64
- const newPageParams = [pageParams[0]];
65
- let pageParam = pageParams[0];
66
- clearTimeout(refetchIntervalTimeoutId.get(keyHash));
67
- if (isWaiting || !(0, utils_1.getValue)(enabled, key))
68
- return resolve(state);
69
- if (isLoading)
70
- set({ isWaiting: true });
71
- else
72
- set({ isWaiting: true, isRefetching: true });
73
- const callQuery = (innerResolve = resolve) => {
74
- if (get().isGoingToRetry) {
75
- if (isLoading)
76
- set({ isGoingToRetry: false, isWaiting: true });
77
- else
78
- set({ isGoingToRetry: false, isWaiting: true, isRefetching: true });
79
- clearTimeout(retryTimeoutId.get(keyHash));
80
- }
81
- preventReplaceResponse.set(keyHash, false);
82
- const stateBeforeCallQuery = { ...get(), pageParam };
83
- queryFn(key, stateBeforeCallQuery)
84
- .then((response) => {
85
- if (preventReplaceResponse.get(keyHash)) {
86
- set({ isWaiting: false, isRefetching: false });
87
- return innerResolve(get());
88
- }
89
- responseAllPages.push(response);
90
- const newPageParam = getNextPageParam(response, responseAllPages.length, stateBeforeCallQuery);
91
- newPageParams.push(newPageParam);
92
- if ((0, utils_1.hasValue)(newPageParam) && newPageParams.length < pageParams.length) {
93
- pageParam = newPageParam;
94
- callQuery();
95
- return;
96
- }
97
- const nextState = {
98
- isWaiting: false,
99
- status: 'success',
100
- isLoading: false,
101
- isSuccess: true,
102
- isError: false,
103
- isRefetching: false,
104
- isRefetchError: false,
105
- isPreviousData: false,
106
- isOptimisticData: false,
107
- data: responseAllPages.reduce((prev, responseCurrentPage) => {
108
- return select(responseCurrentPage, { key, data: prev });
109
- }, undefined),
110
- response,
111
- responseUpdatedAt: Date.now(),
112
- error: undefined,
113
- errorUpdatedAt: undefined,
114
- retryCount: 0,
115
- pageParam: newPageParam,
116
- pageParams: newPageParams,
117
- hasNextPage: (0, utils_1.hasValue)(newPageParam),
118
- };
119
- const refetchIntervalValue = utils_1.isClient && (0, utils_1.getValue)(refetchInterval, { ...get(), ...nextState });
120
- if (refetchIntervalValue) {
121
- refetchIntervalTimeoutId.set(keyHash, window.setTimeout(() => {
122
- forceFetch();
123
- }, refetchIntervalValue));
124
- }
125
- set(nextState);
126
- onSuccess(response, stateBeforeCallQuery);
127
- onSettled(stateBeforeCallQuery);
128
- innerResolve(get());
129
- })
130
- .catch((error) => {
131
- const prevState = get();
132
- const errorUpdatedAt = Date.now();
133
- const { shouldRetry, delay } = getRetryProps(error, prevState.retryCount);
134
- if (shouldRetry) {
135
- set({
136
- isWaiting: false,
137
- isGoingToRetry: true,
138
- });
139
- if (utils_1.isClient) {
140
- retryTimeoutId.set(keyHash, window.setTimeout(() => {
141
- set({ retryCount: prevState.retryCount + 1 });
142
- callQuery(innerResolve);
143
- }, delay));
144
- }
145
- return;
146
- }
147
- set(prevState.isSuccess && !prevState.isPreviousData
148
- ? {
149
- isWaiting: false,
150
- isRefetching: false,
151
- isRefetchError: true,
152
- data: responseAllPages.length
153
- ? responseAllPages.reduce((prev, response) => {
154
- return select(response, { key, data: prev });
155
- }, undefined)
156
- : prevState.data,
157
- error,
158
- errorUpdatedAt,
159
- pageParam,
160
- hasNextPage: (0, utils_1.hasValue)(pageParam),
161
- }
162
- : {
163
- isWaiting: false,
164
- status: 'error',
165
- isLoading: false,
166
- isError: true,
167
- data: undefined,
168
- error,
169
- errorUpdatedAt,
170
- pageParam,
171
- hasNextPage: (0, utils_1.hasValue)(pageParam),
172
- });
173
- if (onError)
174
- onError(error, stateBeforeCallQuery);
175
- else
176
- console.error(error, get());
177
- onSettled(stateBeforeCallQuery);
178
- innerResolve(get());
179
- });
180
- };
181
- callQuery();
182
- });
183
- const fetch = () => {
184
- const { responseUpdatedAt } = get();
185
- const isStale = !responseUpdatedAt || Date.now() > responseUpdatedAt + staleTime;
186
- if (!isStale)
187
- return;
188
- forceFetch();
189
- };
190
- const fetchNextPage = () => new Promise((resolve) => {
191
- const state = get();
192
- if (typeof options.getNextPageParam !== 'function') {
193
- console.warn('fetchNextPage with invalid getNextPageParam option');
194
- return resolve(state);
195
- }
196
- const { isLoading, isWaitingNextPage, data, hasNextPage, pageParam, pageParams } = state;
197
- if (isLoading)
198
- return resolve(forceFetch());
199
- if (isWaitingNextPage || !hasNextPage || !(0, utils_1.getValue)(enabled, key))
200
- return resolve(state);
201
- set({ isWaitingNextPage: true, isGoingToRetryNextPage: false });
202
- clearTimeout(retryNextPageTimeoutId.get(keyHash));
203
- const stateBeforeCallQuery = get();
204
- queryFn(key, { ...state, pageParam })
205
- .then((response) => {
206
- if (preventReplaceResponse.get(keyHash)) {
207
- set({ isWaitingNextPage: false });
208
- return resolve(get());
209
- }
210
- const newPageParam = getNextPageParam(response, pageParams.length, stateBeforeCallQuery);
211
- set({
212
- isWaitingNextPage: false,
213
- response,
214
- responseUpdatedAt: Date.now(),
215
- data: select(response, { key, data }),
216
- pageParam: newPageParam,
217
- pageParams: pageParams.concat(newPageParam),
218
- hasNextPage: (0, utils_1.hasValue)(newPageParam),
219
- });
220
- onSuccess(response, stateBeforeCallQuery);
221
- onSettled(stateBeforeCallQuery);
222
- resolve(get());
223
- })
224
- .catch((error) => {
225
- const prevState = get();
226
- const { shouldRetry, delay } = getRetryProps(error, prevState.retryNextPageCount);
227
- if (shouldRetry) {
228
- set({
229
- isWaitingNextPage: false,
230
- isGoingToRetryNextPage: true,
231
- });
232
- retryNextPageTimeoutId.set(keyHash, window.setTimeout(() => {
233
- set({ retryNextPageCount: prevState.retryNextPageCount + 1 });
234
- resolve(fetchNextPage());
235
- }, delay));
236
- return;
237
- }
238
- set({
239
- isWaitingNextPage: false,
240
- isError: true,
241
- error,
242
- errorUpdatedAt: Date.now(),
243
- });
244
- if (onError)
245
- onError(error, stateBeforeCallQuery);
246
- else
247
- console.error(error, get());
248
- onSettled(stateBeforeCallQuery);
249
- resolve(get());
250
- });
251
- });
252
- return {
253
- ...INITIAL_QUERY_STATE,
254
- key,
255
- keyHash,
256
- fetch,
257
- forceFetch,
258
- fetchNextPage,
259
- reset: () => {
260
- preventReplaceResponse.set(keyHash, true);
261
- clearTimeout(retryTimeoutId.get(keyHash));
262
- clearTimeout(retryNextPageTimeoutId.get(keyHash));
263
- set(INITIAL_QUERY_STATE);
264
- },
265
- optimisticUpdate: (response) => useQuery.optimisticUpdate({ key, response }),
266
- };
267
- }, (() => {
268
- const windowFocusHandler = () => {
269
- useQuery.getAllWithSubscriber().forEach((state) => {
270
- const result = (0, utils_1.getValue)(fetchOnWindowFocus, state.key);
271
- if (result === 'always')
272
- state.forceFetch();
273
- else if (result)
274
- state.fetch();
275
- });
276
- };
277
- const reconnectHandler = () => {
278
- useQuery.getAllWithSubscriber().forEach((state) => {
279
- const result = (0, utils_1.getValue)(fetchOnReconnect, state.key);
280
- if (result === 'always')
281
- state.forceFetch();
282
- else if (result)
283
- state.fetch();
284
- });
285
- };
286
- return {
287
- ...createStoresOptions,
288
- defaultDeps,
289
- onFirstSubscribe: (state) => {
290
- if (state.isSuccess) {
291
- const refetchIntervalValue = utils_1.isClient && (0, utils_1.getValue)(refetchInterval, state);
292
- if (refetchIntervalValue) {
293
- refetchIntervalTimeoutId.set(state.keyHash, window.setTimeout(() => {
294
- state.forceFetch();
295
- }, refetchIntervalValue));
296
- }
297
- }
298
- if (utils_1.isClient) {
299
- if (fetchOnWindowFocus)
300
- window.addEventListener('focus', windowFocusHandler);
301
- if (fetchOnReconnect)
302
- window.addEventListener('online', reconnectHandler);
303
- }
304
- clearTimeout(resetTimeoutId.get(state.keyHash));
305
- onFirstSubscribe(state);
306
- },
307
- onSubscribe: (state) => {
308
- const result = (0, utils_1.getValue)(fetchOnMount, state.key);
309
- if (result === 'always')
310
- state.forceFetch();
311
- else if (result)
312
- state.fetch();
313
- onSubscribe(state);
314
- },
315
- onLastUnsubscribe: (state) => {
316
- const totalSubs = useQuery.getAllWithSubscriber().length;
317
- if (utils_1.isClient && totalSubs === 0) {
318
- if (fetchOnWindowFocus)
319
- window.removeEventListener('focus', windowFocusHandler);
320
- if (fetchOnReconnect)
321
- window.removeEventListener('online', reconnectHandler);
322
- }
323
- useQuery.set(state.key, { retryCount: 0, retryNextPageCount: 0 }, true);
324
- clearTimeout(retryTimeoutId.get(state.keyHash));
325
- clearTimeout(retryNextPageTimeoutId.get(state.keyHash));
326
- clearTimeout(refetchIntervalTimeoutId.get(state.keyHash));
327
- if (utils_1.isClient && cacheTime !== Infinity) {
328
- resetTimeoutId.set(state.keyHash, window.setTimeout(() => {
329
- useQuery.set(state.key, INITIAL_QUERY_STATE);
330
- }, cacheTime));
331
- }
332
- onLastUnsubscribe(state);
333
- },
334
- onBeforeChangeKey: (nextKey, prevKey) => {
335
- if (keepPreviousData) {
336
- const nextData = useQuery.get(nextKey);
337
- if (!nextData.data) {
338
- const prevData = useQuery.get(prevKey);
339
- if (prevData.data) {
340
- useQuery.set(nextKey, {
341
- status: 'success',
342
- isLoading: false,
343
- isSuccess: true,
344
- isError: false,
345
- data: prevData.data,
346
- response: prevData.response,
347
- isPreviousData: true,
348
- }, true);
349
- }
350
- }
351
- }
352
- onBeforeChangeKey(nextKey, prevKey);
353
- },
354
- };
355
- })());
356
- useQuery.setInitialResponse = ({ key, response, skipRevalidation }) => {
357
- // eslint-disable-next-line react-hooks/rules-of-hooks
358
- (0, react_1.useState)(() => {
359
- const state = useQuery.get(key);
360
- if (response === undefined || state.isSuccess)
361
- return;
362
- const newPageParam = getNextPageParam(response, 1, state);
363
- useQuery.set(key, {
364
- status: 'success',
365
- isLoading: false,
366
- isSuccess: true,
367
- isError: false,
368
- response,
369
- responseUpdatedAt: skipRevalidation ? Date.now() : undefined,
370
- data: select(response, { key: key, data: undefined }),
371
- pageParam: newPageParam,
372
- pageParams: [undefined, newPageParam],
373
- hasNextPage: (0, utils_1.hasValue)(newPageParam),
374
- });
375
- });
376
- };
377
- useQuery.reset = () => {
378
- useQuery.getStores().forEach((store, keyHash) => {
379
- preventReplaceResponse.set(keyHash, true);
380
- clearTimeout(retryTimeoutId.get(keyHash));
381
- clearTimeout(retryNextPageTimeoutId.get(keyHash));
382
- store.set(INITIAL_QUERY_STATE);
383
- });
384
- };
385
- useQuery.resetSpecificKey = (key) => useQuery.get(key).reset();
386
- useQuery.invalidate = () => {
387
- useQuery.getStores().forEach((store) => {
388
- const { get, set, getSubscribers } = store;
389
- set({ responseUpdatedAt: undefined });
390
- if (getSubscribers().size > 0)
391
- get().forceFetch();
392
- });
393
- };
394
- useQuery.invalidateSpecificKey = (key) => {
395
- const { get, set, getSubscribers } = useQuery.getStore(key);
396
- set({ responseUpdatedAt: undefined });
397
- if (getSubscribers().size > 0)
398
- get().forceFetch();
399
- };
400
- useQuery.optimisticUpdate = ({ key, response }) => {
401
- const prevState = useQuery.get(key);
402
- const optimisticResponse = (0, utils_1.getValue)(response, prevState);
403
- useQuery.set(key, {
404
- isOptimisticData: true,
405
- response: optimisticResponse,
406
- data: select(optimisticResponse, { key: key, data: undefined }),
407
- });
408
- preventReplaceResponse.set(prevState.keyHash, true);
409
- const revert = () => {
410
- useQuery.set(key, {
411
- isOptimisticData: false,
412
- response: prevState.response,
413
- data: prevState.data,
414
- });
415
- };
416
- const invalidate = () => useQuery.invalidateSpecificKey(key);
417
- return { revert, invalidate };
418
- };
419
- useQuery.suspend = (key) => {
420
- // eslint-disable-next-line react-hooks/rules-of-hooks
421
- const state = useQuery(key);
422
- if (state.isLoading)
423
- throw state.forceFetch();
424
- if (state.isError)
425
- throw state.error;
426
- return state;
427
- };
428
- useQuery.Render = (props) => {
429
- const { queryKey, loading = fallbackComponent, success = fallbackComponent, error = fallbackComponent, } = props;
430
- // eslint-disable-next-line react-hooks/rules-of-hooks
431
- const state = useQuery(queryKey);
432
- if (state.data)
433
- return (0, react_1.createElement)(success, state);
434
- return (0, react_1.createElement)(state.isLoading ? loading : error, state);
435
- };
436
- return useQuery;
437
- };
438
- exports.createQuery = createQuery;
@@ -1,38 +0,0 @@
1
- import { InitStoreOptions, SelectDeps, SetStoreState, StoreInitializer, StoreState, Subscribers } from '../vanilla/init-store';
2
- export type WatchProps<T> = {
3
- selectDeps?: SelectDeps<T>;
4
- render: (state: T) => any;
5
- };
6
- export type UseStore<T extends StoreState> = {
7
- /**
8
- * @param selectDeps A function that return the dependency array (just like in `useEffect`), to trigger reactivity.
9
- *
10
- * Defaults to `undefined` (reactive to all state change) if you didn't set `defaultDeps` on `createStore`.
11
- *
12
- * Value of `null` will also make it reactive to all state change.
13
- *
14
- * **IMPORTANT NOTE:** `selectDeps` must not be changed after initialization.
15
- */
16
- (selectDeps?: SelectDeps<T>): T;
17
- get: () => T;
18
- set: (value: SetStoreState<T>, silent?: boolean) => void;
19
- subscribe: (fn: (state: T) => void, selectDeps?: SelectDeps<T>) => () => void;
20
- getSubscribers: () => Subscribers<T>;
21
- /**
22
- * ⚛️ (**_Hook_**)
23
- *
24
- * Set default values **inside of a component**.
25
- *
26
- * **IMPORTANT NOTE:**
27
- * - This is a hook, put it inside of a React component
28
- * - Put this on the root component or parent component, before any component subscribed!
29
- */
30
- setDefaultValues: (values: SetStoreState<T>) => void;
31
- Watch: (props: WatchProps<T>) => any;
32
- };
33
- /**
34
- * @see https://floppy-disk.vercel.app/docs/api#createstore
35
- */
36
- export declare const createStore: <T extends StoreState>(initializer: StoreInitializer<T>, options?: InitStoreOptions<T> & {
37
- defaultDeps?: SelectDeps<T>;
38
- }) => UseStore<T>;
@@ -1,42 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createStore = void 0;
4
- const react_1 = require("react");
5
- const init_store_1 = require("../vanilla/init-store");
6
- /**
7
- * @see https://floppy-disk.vercel.app/docs/api#createstore
8
- */
9
- const createStore = (initializer, options = {}) => {
10
- const { get, set, subscribe, getSubscribers } = (0, init_store_1.initStore)(initializer, options);
11
- const { defaultDeps } = options;
12
- /**
13
- * **IMPORTANT NOTE:** `selectDeps` function must not be changed after initialization.
14
- */
15
- const useStore = (selectDeps = defaultDeps) => {
16
- const [state, setState] = (0, react_1.useState)(get);
17
- // eslint-disable-next-line react-hooks/exhaustive-deps
18
- (0, react_1.useEffect)(() => subscribe(setState, selectDeps), []);
19
- return state;
20
- };
21
- useStore.get = get;
22
- useStore.set = set;
23
- useStore.subscribe = subscribe;
24
- useStore.getSubscribers = getSubscribers;
25
- useStore.setDefaultValues = (value) => {
26
- // eslint-disable-next-line react-hooks/rules-of-hooks
27
- (0, react_1.useState)(() => {
28
- const subscribers = getSubscribers();
29
- if (subscribers.size > 0) {
30
- console.warn('Put setDefaultValues on the root component or parent component, before any component subscribed!');
31
- }
32
- set(value);
33
- });
34
- };
35
- const Watch = ({ selectDeps = defaultDeps, render }) => {
36
- const store = useStore(selectDeps);
37
- return render(store);
38
- };
39
- useStore.Watch = Watch;
40
- return useStore;
41
- };
42
- exports.createStore = createStore;
@@ -1,61 +0,0 @@
1
- import { Maybe } from '../utils';
2
- import { InitStoreOptions, InitStoreReturn, SelectDeps, SetStoreState, StoreState, Subscribers } from '../vanilla/init-store';
3
- import { WatchProps } from './create-store';
4
- export type StoreKey = Record<string, any> | undefined;
5
- export type StoresInitializer<TKey extends StoreKey = StoreKey, T extends StoreState = StoreState> = T | ((api: {
6
- get: () => T;
7
- set: (value: SetStoreState<T>, silent?: boolean) => void;
8
- key: TKey;
9
- keyHash: string;
10
- }) => T);
11
- export type UseStores<TKey extends StoreKey = StoreKey, T extends StoreState = StoreState> = {
12
- /**
13
- * @param key (Optional) Store key, an object that will be hashed into a string as a store identifier.
14
- * No need to memoize the store key.
15
- *
16
- * @param selectDeps (Optional) A function that return the dependency array (just like in `useEffect`), to trigger reactivity.
17
- *
18
- * Defaults to `undefined` (reactive to all state change) if you didn't set `defaultDeps` on `createStores`.
19
- *
20
- * Value of `null` will also make it reactive to all state change.
21
- *
22
- * **IMPORTANT NOTE:** `selectDeps` must not be changed after initialization.
23
- */
24
- (...args: [Maybe<TKey>, SelectDeps<T>?] | [SelectDeps<T>?]): T;
25
- get: (key?: Maybe<TKey>) => T;
26
- getAll: () => T[];
27
- getAllWithSubscriber: () => T[];
28
- set: (key: Maybe<TKey>, value: SetStoreState<T>, silent?: boolean) => void;
29
- setAll: (value: SetStoreState<T>, silent?: boolean) => void;
30
- subscribe: (key: Maybe<TKey>, fn: (state: T) => void, selectDeps?: SelectDeps<T>) => () => void;
31
- getSubscribers: (key: Maybe<TKey>) => Subscribers<T>;
32
- getStore: (key?: Maybe<TKey>) => InitStoreReturn<T>;
33
- getStores: () => Map<string, InitStoreReturn<T>>;
34
- /**
35
- * ⚛️ (**_Hook_**)
36
- *
37
- * Set default values **inside of a component**.
38
- *
39
- * **IMPORTANT NOTE:**
40
- * - This is a hook, put it inside of a React component
41
- * - Put this on the root component or parent component, before any component subscribed!
42
- */
43
- setDefaultValues: (key: Maybe<TKey>, values: SetStoreState<T>) => void;
44
- Watch: (props: WatchProps<T> & {
45
- storeKey?: Maybe<TKey>;
46
- }) => any;
47
- };
48
- export type CreateStoresOptions<TKey extends StoreKey = StoreKey, T extends StoreState = StoreState> = InitStoreOptions<T> & {
49
- onBeforeChangeKey?: (nextKey: TKey, prevKey: TKey) => void;
50
- /**
51
- * Will be triggered when a single store with a specific key was initialized.
52
- */
53
- onStoreInitialized?: (key: TKey, keyHash: string) => void;
54
- defaultDeps?: SelectDeps<T>;
55
- hashKeyFn?: (obj: TKey) => string;
56
- };
57
- export declare const hashStoreKey: (obj?: any) => string;
58
- /**
59
- * @see https://floppy-disk.vercel.app/docs/api#createstores
60
- */
61
- export declare const createStores: <TKey extends StoreKey = StoreKey, T extends StoreState = StoreState>(initializer: StoresInitializer<TKey, T>, options?: CreateStoresOptions<TKey, T>) => UseStores<TKey, T>;
@@ -1,104 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createStores = exports.hashStoreKey = void 0;
4
- const react_1 = require("react");
5
- const utils_1 = require("../utils");
6
- const init_store_1 = require("../vanilla/init-store");
7
- const hashStoreKey = (obj) => JSON.stringify(obj, Object.keys(obj).sort());
8
- exports.hashStoreKey = hashStoreKey;
9
- /**
10
- * @see https://floppy-disk.vercel.app/docs/api#createstores
11
- */
12
- const createStores = (initializer, options = {}) => {
13
- const { onBeforeChangeKey = utils_1.noop, onStoreInitialized = utils_1.noop, defaultDeps, hashKeyFn = exports.hashStoreKey, } = options;
14
- const stores = new Map();
15
- const getStore = (_key) => {
16
- const key = _key || {};
17
- const keyHash = hashKeyFn(key);
18
- if (!stores.has(keyHash)) {
19
- stores.set(keyHash, (0, init_store_1.initStore)((api) => (0, utils_1.getValue)(initializer, { key, keyHash, ...api }), options));
20
- onStoreInitialized(key, keyHash);
21
- }
22
- return stores.get(keyHash);
23
- };
24
- /**
25
- * **IMPORTANT NOTE:** `selectDeps` function must not be changed after initialization.
26
- */
27
- const useStores = (...args) => {
28
- const [_key, selectDeps = defaultDeps] = (typeof args[0] === 'function' ? [{}, args[0]] : args);
29
- const key = _key || {};
30
- const keyHash = hashKeyFn(key);
31
- // eslint-disable-next-line react-hooks/exhaustive-deps
32
- const { get, subscribe } = (0, react_1.useMemo)(() => getStore(key), [keyHash]);
33
- const [, setState] = (0, react_1.useState)(get);
34
- const prevKey = (0, react_1.useRef)(key);
35
- const prevKeyHash = (0, react_1.useRef)(keyHash);
36
- (0, react_1.useEffect)(() => {
37
- prevKey.current = key;
38
- prevKeyHash.current = keyHash;
39
- const unsubs = subscribe(setState, selectDeps);
40
- return unsubs;
41
- // eslint-disable-next-line react-hooks/exhaustive-deps
42
- }, [keyHash]);
43
- if (keyHash !== prevKeyHash.current)
44
- onBeforeChangeKey(key, prevKey.current);
45
- return get();
46
- };
47
- useStores.get = (key) => {
48
- const store = getStore(key);
49
- return store.get();
50
- };
51
- useStores.getAll = () => {
52
- const allStores = [];
53
- stores.forEach((store) => {
54
- allStores.push(store.get());
55
- });
56
- return allStores;
57
- };
58
- useStores.getAllWithSubscriber = () => {
59
- const allStores = [];
60
- stores.forEach((store) => {
61
- const subscribers = store.getSubscribers();
62
- if (subscribers.size > 0)
63
- allStores.push(store.get());
64
- });
65
- return allStores;
66
- };
67
- useStores.set = (key, value, silent) => {
68
- const store = getStore(key);
69
- store.set(value, silent);
70
- };
71
- useStores.setAll = (value, silent) => {
72
- stores.forEach((store) => {
73
- store.set(value, silent);
74
- });
75
- };
76
- useStores.subscribe = (key, fn, selectDeps = defaultDeps) => {
77
- const store = getStore(key);
78
- return store.subscribe(fn, selectDeps);
79
- };
80
- useStores.getSubscribers = (key) => {
81
- const store = getStore(key);
82
- return store.getSubscribers();
83
- };
84
- useStores.getStore = (key) => getStore(key);
85
- useStores.getStores = () => stores;
86
- useStores.setDefaultValues = (key, value) => {
87
- // eslint-disable-next-line react-hooks/rules-of-hooks
88
- (0, react_1.useState)(() => {
89
- const store = getStore(key);
90
- const subscribers = store.getSubscribers();
91
- if (subscribers.size > 0) {
92
- console.warn('Put setDefaultValues on the root component or parent component, before any component subscribed!');
93
- }
94
- store.set(value);
95
- });
96
- };
97
- const Watch = ({ storeKey, selectDeps = defaultDeps, render, }) => {
98
- const store = useStores(storeKey, selectDeps);
99
- return render(store);
100
- };
101
- useStores.Watch = Watch;
102
- return useStores;
103
- };
104
- exports.createStores = createStores;