@legendapp/state 2.2.0-next.8 → 2.2.0-next.80
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 +4 -2
- package/babel.js.map +1 -1
- package/config/enable$get.d.ts +8 -0
- package/config/enable$get.js +24 -0
- package/config/enable$get.js.map +1 -0
- package/config/enable$get.mjs +21 -0
- package/config/enable$get.mjs.map +1 -0
- package/config/enableReactComponents.js.map +1 -1
- package/config/enableReactComponents.mjs.map +1 -1
- package/config/enableReactNativeComponents.js.map +1 -1
- package/config/enableReactNativeComponents.mjs.map +1 -1
- package/config/enableReactTracking.d.ts +0 -9
- package/config/enableReactTracking.js +34 -32
- package/config/enableReactTracking.js.map +1 -1
- package/config/enableReactTracking.mjs +35 -33
- package/config/enableReactTracking.mjs.map +1 -1
- package/config/enableReactUse.d.ts +1 -1
- package/config/enableReactUse.js +9 -1
- package/config/enableReactUse.js.map +1 -1
- package/config/enableReactUse.mjs +9 -1
- package/config/enableReactUse.mjs.map +1 -1
- package/config/enable_peek.d.ts +8 -0
- package/config/{enableDirectPeek.js → enable_peek.js} +6 -3
- package/config/enable_peek.js.map +1 -0
- package/config/{enableDirectPeek.mjs → enable_peek.mjs} +5 -3
- package/config/enable_peek.mjs.map +1 -0
- package/helpers/fetch.d.ts +4 -3
- package/helpers/fetch.js.map +1 -1
- package/helpers/fetch.mjs.map +1 -1
- package/helpers/pageHash.js.map +1 -1
- package/helpers/pageHash.mjs.map +1 -1
- package/helpers/pageHashParams.js.map +1 -1
- package/helpers/pageHashParams.mjs.map +1 -1
- package/helpers/time.d.ts +2 -2
- package/helpers/time.js.map +1 -1
- package/helpers/time.mjs.map +1 -1
- package/history.js +2 -2
- package/history.js.map +1 -1
- package/history.mjs +3 -3
- package/history.mjs.map +1 -1
- package/index.d.ts +29 -9
- package/index.js +964 -671
- package/index.js.map +1 -1
- package/index.mjs +959 -668
- package/index.mjs.map +1 -1
- package/package.json +37 -25
- package/persist-plugins/async-storage.d.ts +4 -3
- package/persist-plugins/async-storage.js +8 -7
- package/persist-plugins/async-storage.js.map +1 -1
- package/persist-plugins/async-storage.mjs +9 -8
- package/persist-plugins/async-storage.mjs.map +1 -1
- package/persist-plugins/fetch.d.ts +1 -1
- package/persist-plugins/fetch.js.map +1 -1
- package/persist-plugins/fetch.mjs.map +1 -1
- package/persist-plugins/firebase.d.ts +2 -2
- package/persist-plugins/firebase.js +12 -11
- package/persist-plugins/firebase.js.map +1 -1
- package/persist-plugins/firebase.mjs +13 -12
- package/persist-plugins/firebase.mjs.map +1 -1
- package/persist-plugins/indexeddb.d.ts +11 -10
- package/persist-plugins/indexeddb.js +2 -2
- package/persist-plugins/indexeddb.js.map +1 -1
- package/persist-plugins/indexeddb.mjs +2 -2
- package/persist-plugins/indexeddb.mjs.map +1 -1
- package/persist-plugins/local-storage.d.ts +4 -4
- package/persist-plugins/local-storage.js +19 -7
- package/persist-plugins/local-storage.js.map +1 -1
- package/persist-plugins/local-storage.mjs +20 -9
- package/persist-plugins/local-storage.mjs.map +1 -1
- package/persist-plugins/mmkv.d.ts +9 -8
- package/persist-plugins/mmkv.js +5 -4
- package/persist-plugins/mmkv.js.map +1 -1
- package/persist-plugins/mmkv.mjs +6 -5
- package/persist-plugins/mmkv.mjs.map +1 -1
- package/persist-plugins/query.d.ts +1 -1
- package/persist-plugins/query.js.map +1 -1
- package/persist-plugins/query.mjs.map +1 -1
- package/persist.d.ts +2 -14
- package/persist.js +1270 -269
- package/persist.js.map +1 -1
- package/persist.mjs +1270 -270
- package/persist.mjs.map +1 -1
- package/react-hooks/createObservableHook.js +1 -1
- package/react-hooks/createObservableHook.js.map +1 -1
- package/react-hooks/createObservableHook.mjs +1 -1
- package/react-hooks/createObservableHook.mjs.map +1 -1
- package/react-hooks/useFetch.d.ts +4 -3
- package/react-hooks/useFetch.js.map +1 -1
- package/react-hooks/useFetch.mjs.map +1 -1
- package/react-hooks/useHover.js.map +1 -1
- package/react-hooks/useHover.mjs.map +1 -1
- package/react-hooks/useMeasure.js.map +1 -1
- package/react-hooks/useMeasure.mjs.map +1 -1
- package/react-hooks/useObservableNextRouter.js.map +1 -1
- package/react-hooks/useObservableNextRouter.mjs.map +1 -1
- package/react-hooks/useObservableQuery.js.map +1 -1
- package/react-hooks/useObservableQuery.mjs.map +1 -1
- package/react-hooks/usePersistedObservable.d.ts +6 -3
- package/react-hooks/usePersistedObservable.js +5 -2
- package/react-hooks/usePersistedObservable.js.map +1 -1
- package/react-hooks/usePersistedObservable.mjs +5 -2
- package/react-hooks/usePersistedObservable.mjs.map +1 -1
- package/react.js +73 -93
- package/react.js.map +1 -1
- package/react.mjs +73 -93
- package/react.mjs.map +1 -1
- package/src/ObservableObject.ts +1217 -0
- package/src/ObservablePrimitive.ts +62 -0
- package/src/babel/index.ts +70 -0
- package/src/batching.ts +378 -0
- package/src/computed.ts +18 -0
- package/src/config/enable$get.ts +30 -0
- package/src/config/enableReactComponents.ts +26 -0
- package/src/config/enableReactNativeComponents.ts +102 -0
- package/src/config/enableReactTracking.ts +62 -0
- package/src/config/enableReactUse.ts +32 -0
- package/src/config/enable_peek.ts +31 -0
- package/src/config.ts +47 -0
- package/src/createObservable.ts +46 -0
- package/src/event.ts +26 -0
- package/src/globals.ts +234 -0
- package/src/helpers/fetch.ts +26 -0
- package/src/helpers/pageHash.ts +41 -0
- package/src/helpers/pageHashParams.ts +55 -0
- package/src/helpers/time.ts +30 -0
- package/src/helpers.ts +224 -0
- package/src/history/trackHistory.ts +29 -0
- package/src/history/undoRedo.ts +111 -0
- package/src/is.ts +63 -0
- package/src/linked.ts +6 -0
- package/src/observable.ts +32 -0
- package/src/observableInterfaces.ts +148 -0
- package/src/observableTypes.ts +226 -0
- package/src/observe.ts +89 -0
- package/src/onChange.ts +136 -0
- package/src/persist/configureObservablePersistence.ts +7 -0
- package/src/persist/fieldTransformer.ts +149 -0
- package/src/persist/observablePersistRemoteFunctionsAdapter.ts +39 -0
- package/src/persist/persistObservable.ts +1031 -0
- package/src/persist-plugins/async-storage.ts +102 -0
- package/src/persist-plugins/fetch.ts +34 -0
- package/src/persist-plugins/firebase.ts +1052 -0
- package/src/persist-plugins/indexeddb.ts +432 -0
- package/src/persist-plugins/local-storage.ts +91 -0
- package/src/persist-plugins/mmkv.ts +91 -0
- package/src/persist-plugins/query.ts +129 -0
- package/src/proxy.ts +28 -0
- package/src/react/Computed.tsx +7 -0
- package/src/react/For.tsx +116 -0
- package/src/react/Memo.tsx +4 -0
- package/src/react/Reactive.tsx +53 -0
- package/src/react/Show.tsx +33 -0
- package/src/react/Switch.tsx +43 -0
- package/src/react/react-globals.ts +3 -0
- package/src/react/{reactInterfaces.d.ts → reactInterfaces.ts} +15 -7
- package/src/react/reactive-observer.tsx +210 -0
- package/src/react/useComputed.ts +36 -0
- package/src/react/useEffectOnce.ts +41 -0
- package/src/react/useIsMounted.ts +16 -0
- package/src/react/useMount.ts +15 -0
- package/src/react/useObservable.ts +24 -0
- package/src/react/useObservableReducer.ts +52 -0
- package/src/react/useObservableState.ts +30 -0
- package/src/react/useObserve.ts +54 -0
- package/src/react/useObserveEffect.ts +40 -0
- package/src/react/usePauseProvider.tsx +13 -0
- package/src/react/useSelector.ts +167 -0
- package/src/react/useUnmount.ts +8 -0
- package/src/react/useWhen.ts +9 -0
- package/src/react-hooks/createObservableHook.ts +53 -0
- package/src/react-hooks/useFetch.ts +16 -0
- package/src/react-hooks/useHover.ts +40 -0
- package/src/react-hooks/useMeasure.ts +48 -0
- package/src/react-hooks/useObservableNextRouter.ts +137 -0
- package/src/react-hooks/useObservableQuery.ts +205 -0
- package/src/react-hooks/usePersistedObservable.ts +25 -0
- package/src/retry.ts +71 -0
- package/src/setupTracking.ts +26 -0
- package/src/sync/activateSyncedNode.ts +128 -0
- package/src/sync/configureObservableSync.ts +7 -0
- package/src/sync/persistTypes.ts +226 -0
- package/src/sync/syncHelpers.ts +56 -0
- package/src/sync/syncObservable.ts +1040 -0
- package/src/sync/syncObservableAdapter.ts +31 -0
- package/src/sync/syncTypes.ts +188 -0
- package/src/sync/synced.ts +20 -0
- package/src/sync-plugins/crud.ts +404 -0
- package/src/sync-plugins/fetch.ts +72 -0
- package/src/sync-plugins/keel.ts +452 -0
- package/src/sync-plugins/supabase.ts +261 -0
- package/src/trace/traceHelpers.ts +11 -0
- package/src/trace/useTraceListeners.ts +34 -0
- package/src/trace/useTraceUpdates.ts +24 -0
- package/src/trace/useVerifyNotTracking.ts +33 -0
- package/src/trace/useVerifyOneRender.ts +10 -0
- package/src/trackSelector.ts +52 -0
- package/src/tracking.ts +43 -0
- package/src/types/babel.d.ts +12 -0
- package/src/when.ts +75 -0
- package/sync-plugins/crud.d.ts +41 -0
- package/sync-plugins/crud.js +290 -0
- package/sync-plugins/crud.js.map +1 -0
- package/sync-plugins/crud.mjs +286 -0
- package/sync-plugins/crud.mjs.map +1 -0
- package/sync-plugins/fetch.d.ts +13 -0
- package/sync-plugins/fetch.js +46 -0
- package/sync-plugins/fetch.js.map +1 -0
- package/sync-plugins/fetch.mjs +44 -0
- package/sync-plugins/fetch.mjs.map +1 -0
- package/sync-plugins/keel.d.ts +91 -0
- package/sync-plugins/keel.js +277 -0
- package/sync-plugins/keel.js.map +1 -0
- package/sync-plugins/keel.mjs +273 -0
- package/sync-plugins/keel.mjs.map +1 -0
- package/sync-plugins/supabase.d.ts +36 -0
- package/sync-plugins/supabase.js +152 -0
- package/sync-plugins/supabase.js.map +1 -0
- package/sync-plugins/supabase.mjs +149 -0
- package/sync-plugins/supabase.mjs.map +1 -0
- package/sync.d.ts +11 -0
- package/sync.js +976 -0
- package/sync.js.map +1 -0
- package/sync.mjs +966 -0
- package/sync.mjs.map +1 -0
- package/trace.js +13 -10
- package/trace.js.map +1 -1
- package/trace.mjs +11 -8
- package/trace.mjs.map +1 -1
- package/types/babel.d.ts +3 -3
- package/config/enableDirectAccess.d.ts +0 -7
- package/config/enableDirectAccess.js +0 -25
- package/config/enableDirectAccess.js.map +0 -1
- package/config/enableDirectAccess.mjs +0 -23
- package/config/enableDirectAccess.mjs.map +0 -1
- package/config/enableDirectPeek.d.ts +0 -7
- package/config/enableDirectPeek.js.map +0 -1
- package/config/enableDirectPeek.mjs.map +0 -1
- package/config/enableReactDirectRender.d.ts +0 -2
- package/config/enableReactDirectRender.js +0 -78
- package/config/enableReactDirectRender.js.map +0 -1
- package/config/enableReactDirectRender.mjs +0 -75
- package/config/enableReactDirectRender.mjs.map +0 -1
- package/src/ObservableObject.d.ts +0 -14
- package/src/ObservablePrimitive.d.ts +0 -7
- package/src/babel/index.d.ts +0 -17
- package/src/batching.d.ts +0 -6
- package/src/computed.d.ts +0 -4
- package/src/config/enableDirectAccess.d.ts +0 -7
- package/src/config/enableDirectPeek.d.ts +0 -7
- package/src/config/enableReactComponents.d.ts +0 -7
- package/src/config/enableReactDirectRender.d.ts +0 -2
- package/src/config/enableReactNativeComponents.d.ts +0 -20
- package/src/config/enableReactTracking.d.ts +0 -15
- package/src/config/enableReactUse.d.ts +0 -7
- package/src/config.d.ts +0 -8
- package/src/createObservable.d.ts +0 -2
- package/src/event.d.ts +0 -2
- package/src/globals.d.ts +0 -32
- package/src/helpers/fetch.d.ts +0 -6
- package/src/helpers/pageHash.d.ts +0 -7
- package/src/helpers/pageHashParams.d.ts +0 -7
- package/src/helpers/time.d.ts +0 -3
- package/src/helpers.d.ts +0 -13
- package/src/history/trackHistory.d.ts +0 -4
- package/src/is.d.ts +0 -10
- package/src/observable.d.ts +0 -16
- package/src/observableInterfaces.d.ts +0 -458
- package/src/observe.d.ts +0 -6
- package/src/onChange.d.ts +0 -7
- package/src/persist/configureObservablePersistence.d.ts +0 -3
- package/src/persist/fieldTransformer.d.ts +0 -8
- package/src/persist/observablePersistRemoteFunctionsAdapter.d.ts +0 -2
- package/src/persist/persistActivateNode.d.ts +0 -1
- package/src/persist/persistHelpers.d.ts +0 -1
- package/src/persist/persistObservable.d.ts +0 -25
- package/src/persist-plugins/async-storage.d.ts +0 -14
- package/src/persist-plugins/fetch.d.ts +0 -10
- package/src/persist-plugins/firebase.d.ts +0 -51
- package/src/persist-plugins/indexeddb.d.ts +0 -25
- package/src/persist-plugins/local-storage.d.ts +0 -21
- package/src/persist-plugins/mmkv.d.ts +0 -14
- package/src/persist-plugins/query.d.ts +0 -18
- package/src/proxy.d.ts +0 -5
- package/src/react/Computed.d.ts +0 -5
- package/src/react/For.d.ts +0 -15
- package/src/react/Memo.d.ts +0 -3
- package/src/react/Reactive.d.ts +0 -9
- package/src/react/Show.d.ts +0 -18
- package/src/react/Switch.d.ts +0 -14
- package/src/react/react-globals.d.ts +0 -3
- package/src/react/reactive-observer.d.ts +0 -14
- package/src/react/useComputed.d.ts +0 -5
- package/src/react/useEffectOnce.d.ts +0 -1
- package/src/react/useIsMounted.d.ts +0 -2
- package/src/react/useMount.d.ts +0 -2
- package/src/react/useObservable.d.ts +0 -9
- package/src/react/useObservableReducer.d.ts +0 -7
- package/src/react/useObservableState.d.ts +0 -2
- package/src/react/useObserve.d.ts +0 -4
- package/src/react/useObserveEffect.d.ts +0 -4
- package/src/react/usePauseProvider.d.ts +0 -8
- package/src/react/useSelector.d.ts +0 -3
- package/src/react/useUnmount.d.ts +0 -2
- package/src/react/useWhen.d.ts +0 -3
- package/src/react-hooks/createObservableHook.d.ts +0 -2
- package/src/react-hooks/useFetch.d.ts +0 -6
- package/src/react-hooks/useHover.d.ts +0 -3
- package/src/react-hooks/useMeasure.d.ts +0 -6
- package/src/react-hooks/useObservableNextRouter.d.ts +0 -33
- package/src/react-hooks/useObservableQuery.d.ts +0 -6
- package/src/react-hooks/usePersistedObservable.d.ts +0 -11
- package/src/retry.d.ts +0 -9
- package/src/setupTracking.d.ts +0 -2
- package/src/trace/traceHelpers.d.ts +0 -2
- package/src/trace/useTraceListeners.d.ts +0 -1
- package/src/trace/useTraceUpdates.d.ts +0 -1
- package/src/trace/useVerifyNotTracking.d.ts +0 -1
- package/src/trace/useVerifyOneRender.d.ts +0 -1
- package/src/trackSelector.d.ts +0 -7
- package/src/tracking.d.ts +0 -13
- package/src/when.d.ts +0 -3
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { isFunction, observe } from '@legendapp/state';
|
|
2
|
+
import { ObservablePersistRemoteFunctions, type ObservablePersistRemoteSetParams } from '@legendapp/state/sync';
|
|
3
|
+
import {
|
|
4
|
+
InfiniteQueryObserver,
|
|
5
|
+
MutationObserver,
|
|
6
|
+
QueryClient,
|
|
7
|
+
QueryKey,
|
|
8
|
+
QueryObserver,
|
|
9
|
+
UseBaseQueryOptions,
|
|
10
|
+
UseMutationOptions,
|
|
11
|
+
notifyManager,
|
|
12
|
+
useQueryClient,
|
|
13
|
+
} from '@tanstack/react-query';
|
|
14
|
+
|
|
15
|
+
type ObservableQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey extends QueryKey> = Omit<
|
|
16
|
+
UseBaseQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>,
|
|
17
|
+
'queryKey'
|
|
18
|
+
> & { queryKey?: TQueryKey | (() => TQueryKey) };
|
|
19
|
+
|
|
20
|
+
type Params<TQueryFnData, TError, TData, TQueryData, TQueryKey extends QueryKey> = {
|
|
21
|
+
query: ObservableQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>;
|
|
22
|
+
mutation?: UseMutationOptions<TData, TError, void>;
|
|
23
|
+
type?: 'Query' | 'Infinite';
|
|
24
|
+
} & (
|
|
25
|
+
| {
|
|
26
|
+
queryClient: QueryClient;
|
|
27
|
+
useContext?: false | undefined | never;
|
|
28
|
+
}
|
|
29
|
+
| {
|
|
30
|
+
queryClient?: QueryClient;
|
|
31
|
+
useContext?: true;
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
export function persistPluginQuery<TObs, TQueryFnData, TError, TData, TQueryData, TQueryKey extends QueryKey>({
|
|
36
|
+
query: options,
|
|
37
|
+
mutation: mutationOptions,
|
|
38
|
+
type = 'Query',
|
|
39
|
+
queryClient,
|
|
40
|
+
useContext,
|
|
41
|
+
}: Params<TQueryFnData, TError, TData, TQueryData, TQueryKey>): ObservablePersistRemoteFunctions<TObs> {
|
|
42
|
+
if (useContext) {
|
|
43
|
+
queryClient = queryClient || useQueryClient();
|
|
44
|
+
}
|
|
45
|
+
// Set up the defaults like useBaseQuery does
|
|
46
|
+
const defaultedOptions = queryClient!.defaultQueryOptions(
|
|
47
|
+
options as UseBaseQueryOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>,
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
// Include callbacks in batch renders
|
|
51
|
+
if (defaultedOptions.onError) {
|
|
52
|
+
defaultedOptions.onError = notifyManager.batchCalls(defaultedOptions.onError);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (defaultedOptions.onSuccess) {
|
|
56
|
+
defaultedOptions.onSuccess = notifyManager.batchCalls(defaultedOptions.onSuccess);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (defaultedOptions.onSettled) {
|
|
60
|
+
defaultedOptions.onSettled = notifyManager.batchCalls(defaultedOptions.onSettled);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const Observer = type === 'Query' ? QueryObserver : (InfiniteQueryObserver as typeof QueryObserver);
|
|
64
|
+
|
|
65
|
+
const ret: ObservablePersistRemoteFunctions<unknown> = {
|
|
66
|
+
get({ onChange }) {
|
|
67
|
+
let observer: QueryObserver<TQueryFnData, TError, TData, TQueryData, TQueryKey> | undefined = undefined;
|
|
68
|
+
let latestOptions = defaultedOptions;
|
|
69
|
+
let queryKeyFromFn: TQueryKey;
|
|
70
|
+
|
|
71
|
+
const origQueryKey = options.queryKey!;
|
|
72
|
+
|
|
73
|
+
// If the queryKey is a function, observe it and extract the raw value
|
|
74
|
+
const isKeyFunction = isFunction(origQueryKey);
|
|
75
|
+
if (isKeyFunction) {
|
|
76
|
+
observe(({ num }) => {
|
|
77
|
+
queryKeyFromFn = origQueryKey();
|
|
78
|
+
if (num > 0) {
|
|
79
|
+
updateQueryOptions(latestOptions);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const updateQueryOptions = (obj: any) => {
|
|
85
|
+
// Since legend-state mutates the query options, we need to clone it to make Query
|
|
86
|
+
// see it as changed
|
|
87
|
+
const options = Object.assign({}, obj);
|
|
88
|
+
|
|
89
|
+
// Use the latest value from the observed queryKey function
|
|
90
|
+
if (isKeyFunction) {
|
|
91
|
+
options.queryKey = queryKeyFromFn;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
latestOptions = options;
|
|
95
|
+
|
|
96
|
+
// Update the Query options
|
|
97
|
+
if (observer) {
|
|
98
|
+
observer.setOptions(options, { listeners: false });
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
updateQueryOptions(defaultedOptions);
|
|
102
|
+
|
|
103
|
+
// Create the observer
|
|
104
|
+
observer = new Observer!<TQueryFnData, TError, TData, TQueryData, TQueryKey>(queryClient!, latestOptions);
|
|
105
|
+
|
|
106
|
+
// Get the initial optimistic results if it's already cached
|
|
107
|
+
const result = observer!.getOptimisticResult(latestOptions);
|
|
108
|
+
// Subscribe to Query's observer and update the observable
|
|
109
|
+
observer!.subscribe((result) => {
|
|
110
|
+
onChange({ value: result.data });
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Return the initial data
|
|
114
|
+
if (result) {
|
|
115
|
+
return result.data;
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
if (mutationOptions) {
|
|
121
|
+
const mutator = new MutationObserver(queryClient!, mutationOptions);
|
|
122
|
+
// When the observable changes call the mutator function
|
|
123
|
+
ret.set = async ({ value }: ObservablePersistRemoteSetParams<any>) => {
|
|
124
|
+
mutator.mutate(value);
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return ret as any;
|
|
129
|
+
}
|
package/src/proxy.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { linked } from './linked';
|
|
2
|
+
import { observable } from './observable';
|
|
3
|
+
import { Observable, ObservableParam } from './observableTypes';
|
|
4
|
+
|
|
5
|
+
// Deprecated. Remove in v4
|
|
6
|
+
|
|
7
|
+
export function proxy<T, T2 = T>(
|
|
8
|
+
get: (key: string) => T,
|
|
9
|
+
set: (key: string, value: T2) => void,
|
|
10
|
+
): Observable<Record<string, T>>;
|
|
11
|
+
export function proxy<T extends Record<string, any>>(
|
|
12
|
+
get: <K extends keyof T>(key: K) => ObservableParam<T[K]>,
|
|
13
|
+
): Observable<T>;
|
|
14
|
+
export function proxy<T>(get: (key: string) => ObservableParam<T>): Observable<Record<string, T>>;
|
|
15
|
+
export function proxy<T>(get: (key: string) => T): Observable<Record<string, T>>;
|
|
16
|
+
export function proxy<T extends Record<string, any>, T2 = T>(
|
|
17
|
+
get: (key: any) => ObservableParam<any>,
|
|
18
|
+
set?: (key: any, value: T2) => void,
|
|
19
|
+
): any {
|
|
20
|
+
return observable((key: string) =>
|
|
21
|
+
set
|
|
22
|
+
? linked({
|
|
23
|
+
get: () => get(key),
|
|
24
|
+
set: ({ value }) => set(key, value as any),
|
|
25
|
+
})
|
|
26
|
+
: get(key),
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import type { ObservableParam } from '../observableTypes';
|
|
3
|
+
import { useSelector } from './useSelector';
|
|
4
|
+
|
|
5
|
+
export function Computed({ children }: { children: ObservableParam | (() => ReactNode) }): ReactElement {
|
|
6
|
+
return useSelector(children, { skipCheck: true }) as ReactElement;
|
|
7
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { Observable, ObservableObject, ObservableParam } from '@legendapp/state';
|
|
2
|
+
import { internal, isArray, isFunction, isMap } from '@legendapp/state';
|
|
3
|
+
import { FC, ReactElement, createElement, memo, useMemo, useRef } from 'react';
|
|
4
|
+
import { observer } from './reactive-observer';
|
|
5
|
+
import { useSelector } from './useSelector';
|
|
6
|
+
const { findIDKey, getNode, optimized } = internal;
|
|
7
|
+
|
|
8
|
+
const autoMemoCache = new Map<FC<any>, FC<any>>();
|
|
9
|
+
|
|
10
|
+
type ForItemProps<T, TProps = {}> = {
|
|
11
|
+
item$: Observable<T>;
|
|
12
|
+
id?: string;
|
|
13
|
+
} & TProps;
|
|
14
|
+
|
|
15
|
+
export function For<T, TProps>({
|
|
16
|
+
each,
|
|
17
|
+
optimized: isOptimized,
|
|
18
|
+
item,
|
|
19
|
+
itemProps,
|
|
20
|
+
sortValues,
|
|
21
|
+
children,
|
|
22
|
+
}: {
|
|
23
|
+
each?: ObservableParam<T[] | Record<any, T> | Map<any, T>>;
|
|
24
|
+
optimized?: boolean;
|
|
25
|
+
item?: FC<ForItemProps<T, TProps>>;
|
|
26
|
+
itemProps?: TProps;
|
|
27
|
+
sortValues?: (A: T, B: T, AKey: string, BKey: string) => number;
|
|
28
|
+
children?: (value: Observable<T>, id: string | undefined) => ReactElement;
|
|
29
|
+
}): ReactElement | null {
|
|
30
|
+
if (!each) return null;
|
|
31
|
+
|
|
32
|
+
// Get the raw value with a shallow listener so this list only re-renders
|
|
33
|
+
// when the array length changes
|
|
34
|
+
const value = useSelector(() => each!.get(isOptimized ? optimized : true));
|
|
35
|
+
|
|
36
|
+
// The child function gets wrapped in a memoized observer component
|
|
37
|
+
if (!item && children) {
|
|
38
|
+
// Update the ref so the generated component uses the latest function
|
|
39
|
+
const refChildren = useRef<(value: Observable<T>, id: string | undefined) => ReactElement>();
|
|
40
|
+
refChildren.current = children;
|
|
41
|
+
|
|
42
|
+
item = useMemo(() => observer(({ item$, id }) => refChildren.current!(item$, id)), []);
|
|
43
|
+
} else {
|
|
44
|
+
// @ts-expect-error $$typeof is private
|
|
45
|
+
if (item.$$typeof !== Symbol.for('react.memo')) {
|
|
46
|
+
let memod = autoMemoCache.get(item!);
|
|
47
|
+
if (!memod) {
|
|
48
|
+
memod = memo(item!);
|
|
49
|
+
autoMemoCache.set(item!, memod);
|
|
50
|
+
}
|
|
51
|
+
item = memod;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// This early out needs to be after any hooks
|
|
56
|
+
if (!value) return null;
|
|
57
|
+
|
|
58
|
+
// Create the child elements
|
|
59
|
+
const out: ReactElement[] = [];
|
|
60
|
+
|
|
61
|
+
const isArr = isArray(value);
|
|
62
|
+
|
|
63
|
+
if (isArr) {
|
|
64
|
+
// Get the appropriate id field
|
|
65
|
+
const v0 = value[0] as any;
|
|
66
|
+
const node = getNode(each!);
|
|
67
|
+
const length = (value as any[]).length;
|
|
68
|
+
|
|
69
|
+
const idField =
|
|
70
|
+
length > 0
|
|
71
|
+
? (node && findIDKey(v0, node)) ||
|
|
72
|
+
(v0.id !== undefined ? 'id' : v0.key !== undefined ? 'key' : undefined)
|
|
73
|
+
: undefined;
|
|
74
|
+
|
|
75
|
+
const isIdFieldFunction = isFunction(idField);
|
|
76
|
+
|
|
77
|
+
for (let i = 0; i < length; i++) {
|
|
78
|
+
if (value[i]) {
|
|
79
|
+
const val = value[i];
|
|
80
|
+
const key = (isIdFieldFunction ? idField(val) : (val as Record<string, any>)[idField as string]) ?? i;
|
|
81
|
+
const item$ = (each as Observable<any[]>)[i];
|
|
82
|
+
// TODOV3 Remove item
|
|
83
|
+
const props: ForItemProps<any> & { key: string; item: Observable<any> } = {
|
|
84
|
+
key,
|
|
85
|
+
id: key,
|
|
86
|
+
item$,
|
|
87
|
+
item: item$,
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
out.push(createElement(item as FC, itemProps ? Object.assign(props, itemProps) : props));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
// Render the values of the object / Map
|
|
95
|
+
const asMap = isMap(value);
|
|
96
|
+
const keys = asMap ? Array.from(value.keys()) : Object.keys(value);
|
|
97
|
+
if (sortValues) {
|
|
98
|
+
keys.sort((A, B) => sortValues(asMap ? value.get(A)! : value[A], asMap ? value.get(B)! : value[B], A, B));
|
|
99
|
+
}
|
|
100
|
+
for (let i = 0; i < keys.length; i++) {
|
|
101
|
+
const key = keys[i];
|
|
102
|
+
if (asMap ? value.get(key) : value[key]) {
|
|
103
|
+
const item$ = asMap ? each!.get(key) : (each as ObservableObject<Record<string, any>>)[key];
|
|
104
|
+
const props: ForItemProps<any> & { key: string; item: Observable<any> } = {
|
|
105
|
+
key,
|
|
106
|
+
id: key,
|
|
107
|
+
item$,
|
|
108
|
+
item: item$,
|
|
109
|
+
};
|
|
110
|
+
out.push(createElement(item as FC, itemProps ? Object.assign(props, itemProps) : props));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return out as unknown as ReactElement;
|
|
116
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { isEmpty, isFunction } from '@legendapp/state';
|
|
2
|
+
import { ComponentClass, FC, createElement, forwardRef } from 'react';
|
|
3
|
+
import { BindKeys } from './reactInterfaces';
|
|
4
|
+
import { reactive } from './reactive-observer';
|
|
5
|
+
|
|
6
|
+
const ReactiveFns = new Map<string, FC | ComponentClass>();
|
|
7
|
+
const ReactiveFnBinders = new Map<string, BindKeys>();
|
|
8
|
+
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
10
|
+
export interface IReactive {}
|
|
11
|
+
|
|
12
|
+
export const Reactive: IReactive = new Proxy(
|
|
13
|
+
{},
|
|
14
|
+
{
|
|
15
|
+
get(target: Record<string, FC>, p: string) {
|
|
16
|
+
if (!target[p]) {
|
|
17
|
+
const Component = ReactiveFns.get(p) || p;
|
|
18
|
+
|
|
19
|
+
// Create a wrapper around createElement with the string so we can proxy it
|
|
20
|
+
// eslint-disable-next-line react/display-name
|
|
21
|
+
const render = forwardRef((props, ref) => {
|
|
22
|
+
const propsOut = { ...props } as any;
|
|
23
|
+
if (ref && (isFunction(ref) || !isEmpty(ref))) {
|
|
24
|
+
propsOut.ref = ref;
|
|
25
|
+
}
|
|
26
|
+
return createElement(Component, propsOut);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
target[p] = reactive(render, ReactiveFnBinders.get(p));
|
|
30
|
+
}
|
|
31
|
+
return target[p];
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
) as unknown as IReactive;
|
|
35
|
+
|
|
36
|
+
export function configureReactive({
|
|
37
|
+
components,
|
|
38
|
+
binders,
|
|
39
|
+
}: {
|
|
40
|
+
components?: Record<string, FC | ComponentClass<any>>;
|
|
41
|
+
binders?: Record<string, BindKeys>;
|
|
42
|
+
}) {
|
|
43
|
+
if (components) {
|
|
44
|
+
for (const key in components) {
|
|
45
|
+
ReactiveFns.set(key, components[key]);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (binders) {
|
|
49
|
+
for (const key in binders) {
|
|
50
|
+
ReactiveFnBinders.set(key, binders[key]);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Selector } from '@legendapp/state';
|
|
2
|
+
import { isFunction, isObservableValueReady } from '@legendapp/state';
|
|
3
|
+
import { FC, ReactElement, ReactNode, createElement } from 'react';
|
|
4
|
+
import { useSelector } from './useSelector';
|
|
5
|
+
|
|
6
|
+
interface PropsIf<T> {
|
|
7
|
+
if: Selector<T>;
|
|
8
|
+
ifReady?: never;
|
|
9
|
+
}
|
|
10
|
+
interface PropsIfReady<T> {
|
|
11
|
+
if?: never;
|
|
12
|
+
ifReady: Selector<T>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface PropsBase<T> {
|
|
16
|
+
else?: ReactNode | (() => ReactNode);
|
|
17
|
+
wrap?: FC;
|
|
18
|
+
children: ReactNode | ((value?: T) => ReactNode);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type Props<T> = PropsBase<T> & (PropsIf<T> | PropsIfReady<T>);
|
|
22
|
+
|
|
23
|
+
export function Show<T>(props: Props<T>): ReactElement;
|
|
24
|
+
export function Show<T>({ if: if_, ifReady, else: else_, wrap, children }: Props<T>): ReactElement {
|
|
25
|
+
const value = useSelector(if_ ?? ifReady);
|
|
26
|
+
const show = ifReady !== undefined ? isObservableValueReady(value) : value;
|
|
27
|
+
const child = useSelector(
|
|
28
|
+
show ? (isFunction(children) ? () => children(value) : (children as any)) : else_ ?? null,
|
|
29
|
+
{ skipCheck: true },
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
return wrap ? createElement(wrap, undefined, child) : child;
|
|
33
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Selector } from '@legendapp/state';
|
|
2
|
+
import { ReactElement, ReactNode } from 'react';
|
|
3
|
+
import { useSelector } from './useSelector';
|
|
4
|
+
|
|
5
|
+
export function Switch<T extends object>({
|
|
6
|
+
value,
|
|
7
|
+
children,
|
|
8
|
+
}: {
|
|
9
|
+
value?: Selector<T>;
|
|
10
|
+
children: Partial<Record<keyof T | 'null' | 'undefined' | 'default', () => ReactNode>>;
|
|
11
|
+
}): ReactElement | null;
|
|
12
|
+
export function Switch<T extends string | number | symbol>({
|
|
13
|
+
value,
|
|
14
|
+
children,
|
|
15
|
+
}: {
|
|
16
|
+
value?: Selector<T>;
|
|
17
|
+
children: Partial<Record<T | 'null' | 'undefined' | 'default', () => ReactNode>>;
|
|
18
|
+
}): ReactElement | null;
|
|
19
|
+
export function Switch<T extends boolean>({
|
|
20
|
+
value,
|
|
21
|
+
children,
|
|
22
|
+
}: {
|
|
23
|
+
value?: Selector<T>;
|
|
24
|
+
children: Partial<Record<'false' | 'true' | 'null' | 'undefined' | 'default', () => ReactNode>>;
|
|
25
|
+
}): ReactElement | null;
|
|
26
|
+
export function Switch<T>({
|
|
27
|
+
value,
|
|
28
|
+
children,
|
|
29
|
+
}: {
|
|
30
|
+
value?: Selector<T>;
|
|
31
|
+
children: Partial<Record<'undefined' | 'default', () => ReactNode>>;
|
|
32
|
+
}): ReactElement | null;
|
|
33
|
+
export function Switch<T>({
|
|
34
|
+
value,
|
|
35
|
+
children,
|
|
36
|
+
}: {
|
|
37
|
+
value?: Selector<T>;
|
|
38
|
+
children: Partial<Record<any, () => ReactNode>>;
|
|
39
|
+
}): ReactNode {
|
|
40
|
+
// Select from an object of cases
|
|
41
|
+
const child = children[useSelector(value)!];
|
|
42
|
+
return (child ? child() : children['default']?.()) ?? null;
|
|
43
|
+
}
|
|
@@ -1,23 +1,31 @@
|
|
|
1
1
|
import type { FC, LegacyRef, ReactNode } from 'react';
|
|
2
|
-
import type { Observable
|
|
2
|
+
import type { Observable } from '../observableTypes';
|
|
3
|
+
import type { Selector } from '../observableInterfaces';
|
|
4
|
+
|
|
3
5
|
export type ShapeWithNew$<T> = Partial<Omit<T, 'children'>> & {
|
|
4
6
|
[K in keyof T as K extends `$${string & K}` ? K : `$${string & K}`]?: Selector<T[K]>;
|
|
5
|
-
} & {
|
|
6
|
-
|
|
7
|
-
};
|
|
7
|
+
} & { children?: Selector<ReactNode> };
|
|
8
|
+
|
|
8
9
|
export interface BindKey<P> {
|
|
9
10
|
handler?: keyof P;
|
|
10
11
|
getValue?: (e: any) => any;
|
|
11
12
|
defaultValue?: any;
|
|
12
13
|
selector?: (propsOut: Record<string, any>, p: Observable<any>) => any;
|
|
13
14
|
}
|
|
15
|
+
|
|
14
16
|
export type BindKeys<P = any> = Record<keyof P, BindKey<P>>;
|
|
17
|
+
|
|
15
18
|
export type FCReactiveObject<T> = {
|
|
16
19
|
[K in keyof T]: FC<ShapeWithNew$<T[K]>>;
|
|
17
20
|
};
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
|
|
22
|
+
export type FCReactive<P, P2> = P &
|
|
23
|
+
FC<
|
|
24
|
+
ShapeWithNew$<P2> & {
|
|
25
|
+
ref?: LegacyRef<P> | undefined;
|
|
26
|
+
}
|
|
27
|
+
>;
|
|
28
|
+
|
|
21
29
|
export interface UseSelectorOptions {
|
|
22
30
|
suspense?: boolean;
|
|
23
31
|
skipCheck?: boolean;
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { isFunction, isObservable, Selector } from '@legendapp/state';
|
|
2
|
+
import { ChangeEvent, FC, forwardRef, memo, useCallback } from 'react';
|
|
3
|
+
import { reactGlobals } from './react-globals';
|
|
4
|
+
import type { BindKeys } from './reactInterfaces';
|
|
5
|
+
import { useSelector } from './useSelector';
|
|
6
|
+
|
|
7
|
+
export type ShapeWithPick$<T, T2 extends keyof T = keyof T> = Partial<T> & {
|
|
8
|
+
[K in T2 as K extends `$${string & K}` ? K : `$${string & K}`]?: Selector<T[K]>;
|
|
9
|
+
};
|
|
10
|
+
export type ShapeWith$<T> = Partial<T> & {
|
|
11
|
+
[K in keyof T as K extends `$${string & K}` ? K : `$${string & K}`]?: Selector<T[K]>;
|
|
12
|
+
};
|
|
13
|
+
export type ObjectShapeWith$<T> = {
|
|
14
|
+
[K in keyof T]: T[K] extends FC<infer P> ? FC<ShapeWith$<P>> : T[K];
|
|
15
|
+
};
|
|
16
|
+
export type ExtractFCPropsType<T> = T extends FC<infer P> ? P : never;
|
|
17
|
+
|
|
18
|
+
// Extracting the forwardRef inspired by https://github.com/mobxjs/mobx/blob/main/packages/mobx-react-lite/src/observer.ts
|
|
19
|
+
export const hasSymbol = /* @__PURE__ */ typeof Symbol === 'function' && Symbol.for;
|
|
20
|
+
|
|
21
|
+
let didWarnProps = false;
|
|
22
|
+
|
|
23
|
+
// TODOV2: Change bindKeys to an options object, where one of the options is "convertChildren" so that behavior can be optional
|
|
24
|
+
function createReactiveComponent<P = object>(
|
|
25
|
+
component: FC<P>,
|
|
26
|
+
observe: boolean,
|
|
27
|
+
reactive?: boolean,
|
|
28
|
+
bindKeys?: BindKeys<P>,
|
|
29
|
+
) {
|
|
30
|
+
const ReactForwardRefSymbol = hasSymbol
|
|
31
|
+
? Symbol.for('react.forward_ref')
|
|
32
|
+
: // eslint-disable-next-line react/display-name, @typescript-eslint/no-unused-vars
|
|
33
|
+
typeof forwardRef === 'function' && forwardRef((props: any) => null)['$$typeof'];
|
|
34
|
+
|
|
35
|
+
const ReactMemoSymbol = hasSymbol
|
|
36
|
+
? Symbol.for('react.memo')
|
|
37
|
+
: // eslint-disable-next-line react/display-name, @typescript-eslint/no-unused-vars
|
|
38
|
+
typeof forwardRef === 'function' && memo((props) => null)['$$typeof'];
|
|
39
|
+
|
|
40
|
+
// If this component is already reactive bail out early
|
|
41
|
+
// This can happen with Fast Refresh.
|
|
42
|
+
if ((component as any)['__legend_proxied']) return component;
|
|
43
|
+
|
|
44
|
+
let useForwardRef = false;
|
|
45
|
+
let useMemo = false;
|
|
46
|
+
let render = component;
|
|
47
|
+
|
|
48
|
+
// Unwrap memo on the component
|
|
49
|
+
if (ReactMemoSymbol && (render as any)['$$typeof'] === ReactMemoSymbol && (render as any)['type']) {
|
|
50
|
+
useMemo = true;
|
|
51
|
+
render = (render as any)['type'];
|
|
52
|
+
}
|
|
53
|
+
// Unwrap forwardRef on the component
|
|
54
|
+
if (ReactForwardRefSymbol && (render as any)['$$typeof'] === ReactForwardRefSymbol) {
|
|
55
|
+
useForwardRef = true;
|
|
56
|
+
render = (render as any)['render'];
|
|
57
|
+
if (process.env.NODE_ENV === 'development' && typeof render !== 'function') {
|
|
58
|
+
throw new Error(`[legend-state] \`render\` property of ForwardRef was not a function`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const proxyHandler: ProxyHandler<any> = {
|
|
63
|
+
apply(target, thisArg, argArray) {
|
|
64
|
+
// If this is a reactive component, convert all props ending in $
|
|
65
|
+
// to regular props and set up a useSelector listener
|
|
66
|
+
if (reactive) {
|
|
67
|
+
const props = argArray[0];
|
|
68
|
+
const propsOut = {} as Record<string, any>;
|
|
69
|
+
const keys = Object.keys(props);
|
|
70
|
+
for (let i = 0; i < keys.length; i++) {
|
|
71
|
+
const key = keys[i];
|
|
72
|
+
const p = props[key];
|
|
73
|
+
|
|
74
|
+
// Convert children if it's a function
|
|
75
|
+
if (key === 'children' && (isFunction(p) || isObservable(p))) {
|
|
76
|
+
props[key] = useSelector(p, { skipCheck: true });
|
|
77
|
+
}
|
|
78
|
+
// Convert reactive props
|
|
79
|
+
else if (key.startsWith('$') || key.endsWith('$')) {
|
|
80
|
+
// TODOV3 Add this warning
|
|
81
|
+
// TODOV4 Remove the deprecated endsWith option
|
|
82
|
+
if (process.env.NODE_ENV === 'development' && !didWarnProps && key.endsWith('$')) {
|
|
83
|
+
didWarnProps = true;
|
|
84
|
+
console.warn(
|
|
85
|
+
`[legend-state] Reactive props were changed to start with $ instead of end with $ in version 2.0. So please change ${key} to $${key.replace(
|
|
86
|
+
'$',
|
|
87
|
+
'',
|
|
88
|
+
)}. See https://legendapp.com/open-source/state/migrating for more details.`,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
const k = key.endsWith('$') ? key.slice(0, -1) : key.slice(1);
|
|
92
|
+
// Return raw value and listen to the selector for changes
|
|
93
|
+
|
|
94
|
+
const bind = bindKeys?.[k as keyof P];
|
|
95
|
+
const shouldBind = bind && isObservable(p);
|
|
96
|
+
|
|
97
|
+
propsOut[k] = shouldBind && bind?.selector ? bind.selector(propsOut, p) : useSelector(p);
|
|
98
|
+
|
|
99
|
+
// If this key is one of the bind keys set up a two-way binding
|
|
100
|
+
if (shouldBind) {
|
|
101
|
+
// Use the bind's defaultValue if value is undefined
|
|
102
|
+
if (bind.defaultValue !== undefined && propsOut[k] === undefined) {
|
|
103
|
+
propsOut[k] = bind.defaultValue;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (bind.handler && bind.getValue) {
|
|
107
|
+
// Hook up the change lander
|
|
108
|
+
const handlerFn = (e: ChangeEvent) => {
|
|
109
|
+
p.set(bind.getValue!(e));
|
|
110
|
+
props[bind.handler!]?.(e);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
(propsOut[bind.handler as string] as any) =
|
|
114
|
+
// If in development mode, don't memoize the handler. fix fast refresh bug
|
|
115
|
+
process.env.NODE_ENV === 'development'
|
|
116
|
+
? handlerFn
|
|
117
|
+
: useCallback(handlerFn, [props[bind.handler], bindKeys]);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Delete the reactive key
|
|
122
|
+
delete propsOut[key];
|
|
123
|
+
} else if (propsOut[key] === undefined) {
|
|
124
|
+
propsOut[key] = p;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
argArray[0] = propsOut;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// If observing wrap the whole render in a useSelector to listen to it
|
|
131
|
+
if (observe) {
|
|
132
|
+
return useSelector(
|
|
133
|
+
() => {
|
|
134
|
+
reactGlobals.inObserver = true;
|
|
135
|
+
try {
|
|
136
|
+
return Reflect.apply(target, thisArg, argArray);
|
|
137
|
+
} finally {
|
|
138
|
+
reactGlobals.inObserver = false;
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
{ skipCheck: true },
|
|
142
|
+
);
|
|
143
|
+
} else {
|
|
144
|
+
return Reflect.apply(target, thisArg, argArray);
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
const proxy = new Proxy(render, proxyHandler);
|
|
150
|
+
|
|
151
|
+
let ret;
|
|
152
|
+
|
|
153
|
+
if (useForwardRef) {
|
|
154
|
+
ret = forwardRef(proxy);
|
|
155
|
+
(ret as any)['__legend_proxied'] = true;
|
|
156
|
+
} else {
|
|
157
|
+
ret = proxy;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return observe || useMemo ? memo(ret) : ret;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function observer<P extends FC<any>>(component: P): P {
|
|
164
|
+
return createReactiveComponent(component, true);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function reactive<T extends FC<any>>(
|
|
168
|
+
component: T,
|
|
169
|
+
bindKeys?: BindKeys<ExtractFCPropsType<T>>,
|
|
170
|
+
): T | FC<ShapeWith$<ExtractFCPropsType<T>>>;
|
|
171
|
+
export function reactive<T extends FC<any>, T2 extends keyof ExtractFCPropsType<T>>(
|
|
172
|
+
component: T,
|
|
173
|
+
bindKeys?: BindKeys<ExtractFCPropsType<T>>,
|
|
174
|
+
): T | FC<ShapeWithPick$<ExtractFCPropsType<T>, T2>>;
|
|
175
|
+
export function reactive<T extends FC<any>>(
|
|
176
|
+
component: T,
|
|
177
|
+
bindKeys?: BindKeys<ExtractFCPropsType<T>>,
|
|
178
|
+
): T | FC<ShapeWith$<ExtractFCPropsType<T>>> {
|
|
179
|
+
return createReactiveComponent(component, false, true, bindKeys);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function reactiveObserver<T extends FC<any>>(
|
|
183
|
+
component: T,
|
|
184
|
+
bindKeys?: BindKeys<ExtractFCPropsType<T>>,
|
|
185
|
+
): T | FC<ShapeWith$<ExtractFCPropsType<T>>>;
|
|
186
|
+
export function reactiveObserver<T extends FC<any>, T2 extends keyof ExtractFCPropsType<T>>(
|
|
187
|
+
component: T,
|
|
188
|
+
bindKeys?: BindKeys<ExtractFCPropsType<T>>,
|
|
189
|
+
): T | FC<ShapeWithPick$<ExtractFCPropsType<T>, T2>>;
|
|
190
|
+
export function reactiveObserver<T extends FC<any>>(
|
|
191
|
+
component: T,
|
|
192
|
+
bindKeys?: BindKeys<ExtractFCPropsType<T>>,
|
|
193
|
+
): T | FC<ShapeWith$<ExtractFCPropsType<T>>> {
|
|
194
|
+
return createReactiveComponent(component, true, true, bindKeys);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export function reactiveComponents<P extends Record<string, FC>>(components: P): ObjectShapeWith$<P> {
|
|
198
|
+
return new Proxy(
|
|
199
|
+
{},
|
|
200
|
+
{
|
|
201
|
+
get(target: Record<string, any>, p: string) {
|
|
202
|
+
if (!target[p] && components[p]) {
|
|
203
|
+
target[p] = createReactiveComponent(components[p], false, true) as FC<ShapeWith$<P>>;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return target[p];
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
) as ObjectShapeWith$<P>;
|
|
210
|
+
}
|