@react-navigation/core 8.0.0-alpha.30 → 8.0.0-alpha.32
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/lib/module/BaseNavigationContainer.js +132 -82
- package/lib/module/BaseNavigationContainer.js.map +1 -1
- package/lib/module/DataLoading.js +3 -1
- package/lib/module/DataLoading.js.map +1 -1
- package/lib/module/NavigationBuilderContext.js +2 -1
- package/lib/module/NavigationBuilderContext.js.map +1 -1
- package/lib/module/NavigationIndependentTree.js +21 -11
- package/lib/module/NavigationIndependentTree.js.map +1 -1
- package/lib/module/NavigationProvider.js +10 -1
- package/lib/module/NavigationProvider.js.map +1 -1
- package/lib/module/NavigationRootContext.js +8 -0
- package/lib/module/NavigationRootContext.js.map +1 -0
- package/lib/module/NavigationStateContext.js +3 -0
- package/lib/module/NavigationStateContext.js.map +1 -1
- package/lib/module/SceneView.js +3 -1
- package/lib/module/SceneView.js.map +1 -1
- package/lib/module/StaticNavigation.js +54 -19
- package/lib/module/StaticNavigation.js.map +1 -1
- package/lib/module/createNavigationContainerRef.js +1 -1
- package/lib/module/createNavigationContainerRef.js.map +1 -1
- package/lib/module/findFocusedRoute.js.map +1 -1
- package/lib/module/getActionFromState.js.map +1 -1
- package/lib/module/getStateFromPath.js +15 -16
- package/lib/module/getStateFromPath.js.map +1 -1
- package/lib/module/getStateFromRouteParams.js +0 -1
- package/lib/module/getStateFromRouteParams.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/internal.js +2 -0
- package/lib/module/internal.js.map +1 -0
- package/lib/module/types.js +0 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/useDescriptors.js +6 -4
- package/lib/module/useDescriptors.js.map +1 -1
- package/lib/module/useKeyedChildListeners.js +1 -0
- package/lib/module/useKeyedChildListeners.js.map +1 -1
- package/lib/module/useNavigation.js +2 -2
- package/lib/module/useNavigation.js.map +1 -1
- package/lib/module/useNavigationBuilder.js +14 -4
- package/lib/module/useNavigationBuilder.js.map +1 -1
- package/lib/module/useNavigationCache.js +23 -31
- package/lib/module/useNavigationCache.js.map +1 -1
- package/lib/module/useNavigationHelpers.js +18 -37
- package/lib/module/useNavigationHelpers.js.map +1 -1
- package/lib/module/useNavigationState.js +85 -33
- package/lib/module/useNavigationState.js.map +1 -1
- package/lib/module/useOnGetNavigation.js +26 -0
- package/lib/module/useOnGetNavigation.js.map +1 -0
- package/lib/module/useSyncState.js +25 -6
- package/lib/module/useSyncState.js.map +1 -1
- package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
- package/lib/typescript/src/DataLoading.d.ts.map +1 -1
- package/lib/typescript/src/NavigationBuilderContext.d.ts +4 -1
- package/lib/typescript/src/NavigationBuilderContext.d.ts.map +1 -1
- package/lib/typescript/src/NavigationIndependentTree.d.ts.map +1 -1
- package/lib/typescript/src/NavigationProvider.d.ts +9 -5
- package/lib/typescript/src/NavigationProvider.d.ts.map +1 -1
- package/lib/typescript/src/NavigationRootContext.d.ts +8 -0
- package/lib/typescript/src/NavigationRootContext.d.ts.map +1 -0
- package/lib/typescript/src/NavigationStateContext.d.ts +1 -0
- package/lib/typescript/src/NavigationStateContext.d.ts.map +1 -1
- package/lib/typescript/src/SceneView.d.ts +2 -1
- package/lib/typescript/src/SceneView.d.ts.map +1 -1
- package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
- package/lib/typescript/src/createNavigationContainerRef.d.ts.map +1 -1
- package/lib/typescript/src/findFocusedRoute.d.ts +3 -8
- package/lib/typescript/src/findFocusedRoute.d.ts.map +1 -1
- package/lib/typescript/src/getActionFromState.d.ts.map +1 -1
- package/lib/typescript/src/getStateFromPath.d.ts +1 -4
- package/lib/typescript/src/getStateFromPath.d.ts.map +1 -1
- package/lib/typescript/src/getStateFromRouteParams.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/internal.d.ts +3 -0
- package/lib/typescript/src/internal.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +3 -6
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/useDescriptors.d.ts +2 -1
- package/lib/typescript/src/useDescriptors.d.ts.map +1 -1
- package/lib/typescript/src/useKeyedChildListeners.d.ts +1 -0
- package/lib/typescript/src/useKeyedChildListeners.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationHelpers.d.ts +1 -2
- package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationState.d.ts +7 -2
- package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
- package/lib/typescript/src/useOnGetNavigation.d.ts +12 -0
- package/lib/typescript/src/useOnGetNavigation.d.ts.map +1 -0
- package/lib/typescript/src/useSyncState.d.ts +1 -0
- package/lib/typescript/src/useSyncState.d.ts.map +1 -1
- package/package.json +11 -5
- package/src/BaseNavigationContainer.tsx +194 -97
- package/src/DataLoading.tsx +4 -1
- package/src/NavigationBuilderContext.tsx +10 -1
- package/src/NavigationIndependentTree.tsx +27 -16
- package/src/NavigationProvider.tsx +13 -6
- package/src/NavigationRootContext.tsx +11 -0
- package/src/NavigationStateContext.tsx +4 -0
- package/src/SceneView.tsx +4 -0
- package/src/StaticNavigation.tsx +77 -19
- package/src/createNavigationContainerRef.tsx +0 -2
- package/src/findFocusedRoute.tsx +7 -12
- package/src/getActionFromState.tsx +2 -1
- package/src/getStateFromPath.tsx +31 -43
- package/src/getStateFromRouteParams.tsx +0 -1
- package/src/index.tsx +1 -0
- package/src/internal.tsx +2 -0
- package/src/types.tsx +3 -7
- package/src/useDescriptors.tsx +6 -3
- package/src/useKeyedChildListeners.tsx +1 -0
- package/src/useNavigation.tsx +2 -2
- package/src/useNavigationBuilder.tsx +14 -4
- package/src/useNavigationCache.tsx +24 -33
- package/src/useNavigationHelpers.tsx +19 -38
- package/src/useNavigationState.tsx +104 -31
- package/src/useOnGetNavigation.tsx +29 -0
- package/src/useSyncState.tsx +27 -6
- package/lib/module/checkSerializable.js +0 -51
- package/lib/module/checkSerializable.js.map +0 -1
- package/lib/typescript/src/checkSerializable.d.ts +0 -14
- package/lib/typescript/src/checkSerializable.d.ts.map +0 -1
- package/src/checkSerializable.tsx +0 -90
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from '@react-navigation/routers';
|
|
8
8
|
import * as React from 'react';
|
|
9
9
|
|
|
10
|
+
import { NavigationBuilderContext } from './NavigationBuilderContext';
|
|
10
11
|
import { NavigationContext } from './NavigationProvider';
|
|
11
12
|
import { type NavigationHelpers, PrivateValueStore } from './types';
|
|
12
13
|
import type { NavigationEventEmitter } from './useEventEmitter';
|
|
@@ -19,7 +20,6 @@ type Options<State extends NavigationState, Action extends NavigationAction> = {
|
|
|
19
20
|
onAction: (action: NavigationAction) => boolean;
|
|
20
21
|
onUnhandledAction: (action: NavigationAction) => void;
|
|
21
22
|
getState: () => State;
|
|
22
|
-
state: State;
|
|
23
23
|
emitter: NavigationEventEmitter<any>;
|
|
24
24
|
router: Router<State, Action>;
|
|
25
25
|
};
|
|
@@ -37,38 +37,23 @@ export function useNavigationHelpers<
|
|
|
37
37
|
onAction,
|
|
38
38
|
onUnhandledAction,
|
|
39
39
|
getState,
|
|
40
|
-
state,
|
|
41
40
|
emitter,
|
|
42
41
|
router,
|
|
43
42
|
}: Options<State, Action>) {
|
|
44
43
|
const parentNavigationHelpers = React.use(NavigationContext);
|
|
45
|
-
|
|
46
|
-
// In some cases (e.g. route names change), internal state might have changed
|
|
47
|
-
// But it hasn't been committed yet, so hasn't propagated to any listeners
|
|
48
|
-
// During this time, we need to return the internal state in `getState`
|
|
49
|
-
// Otherwise it can return an inconsistent state during render in children
|
|
50
|
-
// This may affect hooks like `useNavigationState` that need to read the state during render
|
|
51
|
-
// To avoid this, we use a ref for render phase, and immediately clear it on commit
|
|
52
|
-
// The ref won't be cleared if the render is discarded, e.g. when interrupted
|
|
53
|
-
// So we also track the stored state the render was based on
|
|
54
|
-
// Then ignore the ref once the stored state changes due to another dispatch
|
|
55
|
-
const stateRef = React.useRef<{ state: State; base: State } | null>(null);
|
|
56
|
-
|
|
57
|
-
stateRef.current = { state, base: getState() };
|
|
58
|
-
|
|
59
|
-
React.useInsertionEffect(() => {
|
|
60
|
-
stateRef.current = null;
|
|
61
|
-
});
|
|
44
|
+
const { withStackTrace } = React.use(NavigationBuilderContext);
|
|
62
45
|
|
|
63
46
|
return React.useMemo(() => {
|
|
64
47
|
const dispatch = (op: Action | ((state: State) => Action)) => {
|
|
65
|
-
|
|
48
|
+
withStackTrace(dispatch, () => {
|
|
49
|
+
const action = typeof op === 'function' ? op(getState()) : op;
|
|
66
50
|
|
|
67
|
-
|
|
51
|
+
const handled = onAction(action);
|
|
68
52
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
53
|
+
if (!handled) {
|
|
54
|
+
onUnhandledAction?.(action);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
72
57
|
};
|
|
73
58
|
|
|
74
59
|
const actions = {
|
|
@@ -77,8 +62,15 @@ export function useNavigationHelpers<
|
|
|
77
62
|
};
|
|
78
63
|
|
|
79
64
|
const helpers = Object.keys(actions).reduce((acc, name) => {
|
|
65
|
+
const helper = (...args: any) =>
|
|
66
|
+
withStackTrace(helper, () =>
|
|
67
|
+
// @ts-expect-error: name is a valid key, but TypeScript is dumb
|
|
68
|
+
dispatch(actions[name](...args))
|
|
69
|
+
);
|
|
70
|
+
|
|
80
71
|
// @ts-expect-error: name is a valid key, but TypeScript is dumb
|
|
81
|
-
acc[name] =
|
|
72
|
+
acc[name] = helper;
|
|
73
|
+
|
|
82
74
|
return acc;
|
|
83
75
|
}, {} as ActionHelpers);
|
|
84
76
|
|
|
@@ -103,18 +95,7 @@ export function useNavigationHelpers<
|
|
|
103
95
|
false
|
|
104
96
|
);
|
|
105
97
|
},
|
|
106
|
-
getState
|
|
107
|
-
const current = getState();
|
|
108
|
-
const pending = stateRef.current;
|
|
109
|
-
|
|
110
|
-
// FIXME: Workaround for when the state is read during render
|
|
111
|
-
// Apart from subscriptions, `getState` should never be called during render
|
|
112
|
-
if (pending != null && pending.base === current) {
|
|
113
|
-
return pending.state;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return current;
|
|
117
|
-
},
|
|
98
|
+
getState,
|
|
118
99
|
} as NavigationHelpers<ParamListBase, EventMap> & ActionHelpers;
|
|
119
100
|
|
|
120
101
|
return navigationHelpers;
|
|
@@ -125,6 +106,6 @@ export function useNavigationHelpers<
|
|
|
125
106
|
getState,
|
|
126
107
|
onAction,
|
|
127
108
|
onUnhandledAction,
|
|
128
|
-
|
|
109
|
+
withStackTrace,
|
|
129
110
|
]);
|
|
130
111
|
}
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
import type { NavigationState, ParamListBase } from '@react-navigation/routers';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import useLatestCallback from 'use-latest-callback';
|
|
4
3
|
|
|
5
4
|
import type { NavigationListForNested, RootNavigator } from './types';
|
|
6
5
|
|
|
6
|
+
type NavigationStateEvent = 'update' | 'commit';
|
|
7
|
+
|
|
7
8
|
type NavigationStateListener = {
|
|
8
9
|
getState: () => NavigationState<ParamListBase>;
|
|
9
|
-
|
|
10
|
+
getSnapshot: () => NavigationState<ParamListBase>;
|
|
11
|
+
subscribe: (callback: (event: NavigationStateEvent) => void) => () => void;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type NavigationStateEntry = {
|
|
15
|
+
listener: NavigationStateListener;
|
|
16
|
+
state: NavigationState<ParamListBase>;
|
|
10
17
|
};
|
|
11
18
|
|
|
12
19
|
type NavigationStateForNested<
|
|
@@ -74,68 +81,134 @@ export function useNavigationState(...args: unknown[]): unknown {
|
|
|
74
81
|
}
|
|
75
82
|
}
|
|
76
83
|
|
|
77
|
-
const { getState, subscribe } = listener;
|
|
84
|
+
const { getState, getSnapshot, subscribe } = listener;
|
|
85
|
+
|
|
86
|
+
// The store can contain state from a transition that hasn't committed yet.
|
|
87
|
+
// Reading it during render can show state that doesn't match the navigator in that render.
|
|
88
|
+
// The reducer lets React process state in the same render lane as the navigator.
|
|
89
|
+
const [entry, dispatch] = React.useReducer(
|
|
90
|
+
(previous: NavigationStateEntry, event: NavigationStateEvent) => {
|
|
91
|
+
// Navigation state can change between the dispatch and the reducer running.
|
|
92
|
+
// Reading here ensures the processed event uses the state for that render.
|
|
93
|
+
const state = event === 'update' ? getState() : getSnapshot();
|
|
94
|
+
|
|
95
|
+
if (
|
|
96
|
+
previous.listener === listener &&
|
|
97
|
+
(previous.state === state ||
|
|
98
|
+
(event === 'update' &&
|
|
99
|
+
Object.is(select(previous.state), select(state))))
|
|
100
|
+
) {
|
|
101
|
+
return previous;
|
|
102
|
+
}
|
|
78
103
|
|
|
79
|
-
|
|
104
|
+
return { listener, state };
|
|
105
|
+
},
|
|
106
|
+
undefined,
|
|
107
|
+
() => ({ listener, state: getState() })
|
|
108
|
+
);
|
|
80
109
|
|
|
81
|
-
|
|
110
|
+
let state = entry.state;
|
|
82
111
|
|
|
83
|
-
const
|
|
112
|
+
const committedRef = React.useRef<{
|
|
113
|
+
entry: NavigationStateEntry | null;
|
|
114
|
+
state: NavigationState<ParamListBase>;
|
|
115
|
+
select: (state: NavigationState<ParamListBase>) => unknown;
|
|
116
|
+
}>({ entry: null, state, select });
|
|
84
117
|
|
|
85
|
-
React.
|
|
86
|
-
|
|
118
|
+
React.useInsertionEffect(() => {
|
|
119
|
+
committedRef.current = { entry, state, select };
|
|
87
120
|
});
|
|
88
121
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
122
|
+
const snapshot = getSnapshot();
|
|
123
|
+
|
|
124
|
+
const behind =
|
|
125
|
+
state !== snapshot &&
|
|
126
|
+
// A different listener means the state belongs to another navigator.
|
|
127
|
+
// This can happen when the passed route name changes.
|
|
128
|
+
(entry.listener !== listener ||
|
|
129
|
+
// An entry that advanced past the last commit is at least as new as the snapshot.
|
|
130
|
+
// An entry that didn't advance while the committed state changed is older.
|
|
131
|
+
entry === committedRef.current.entry);
|
|
92
132
|
|
|
93
|
-
|
|
94
|
-
|
|
133
|
+
if (behind) {
|
|
134
|
+
state = snapshot;
|
|
135
|
+
dispatch('commit');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
React.useLayoutEffect(() => {
|
|
139
|
+
const check = (event: NavigationStateEvent) => {
|
|
140
|
+
const { state, select } = committedRef.current;
|
|
141
|
+
|
|
142
|
+
// An 'update' event follows the latest state in the lane the update was made in.
|
|
143
|
+
// A 'commit' event syncs the reducer to the state committed by the navigator.
|
|
144
|
+
const target = event === 'update' ? getState() : getSnapshot();
|
|
145
|
+
|
|
146
|
+
if (state !== target && !Object.is(select(state), select(target))) {
|
|
147
|
+
dispatch(event);
|
|
95
148
|
}
|
|
96
149
|
};
|
|
97
150
|
|
|
98
|
-
const unsubscribe = subscribe(
|
|
151
|
+
const unsubscribe = subscribe(check);
|
|
99
152
|
|
|
100
|
-
// The
|
|
101
|
-
|
|
153
|
+
// The reducer may not match the committed state when the subscription starts.
|
|
154
|
+
// This happens on mount during a transition or an update before subscribing.
|
|
155
|
+
check('commit');
|
|
102
156
|
|
|
103
157
|
return unsubscribe;
|
|
104
|
-
}, [getState, subscribe]);
|
|
158
|
+
}, [getState, getSnapshot, subscribe]);
|
|
105
159
|
|
|
106
|
-
return
|
|
160
|
+
return select(state);
|
|
107
161
|
}
|
|
108
162
|
|
|
109
163
|
export function NavigationStateListenerProvider({
|
|
164
|
+
isSynced,
|
|
110
165
|
state,
|
|
111
166
|
getState,
|
|
167
|
+
subscribe,
|
|
112
168
|
children,
|
|
113
169
|
}: {
|
|
170
|
+
isSynced: boolean;
|
|
114
171
|
state: NavigationState<ParamListBase>;
|
|
115
172
|
getState: () => NavigationState<ParamListBase>;
|
|
173
|
+
subscribe: (callback: () => void) => () => void;
|
|
116
174
|
children: React.ReactNode;
|
|
117
175
|
}) {
|
|
118
|
-
const listeners = React.
|
|
176
|
+
const [listeners] = React.useState(
|
|
177
|
+
() => new Set<(event: NavigationStateEvent) => void>()
|
|
178
|
+
);
|
|
119
179
|
|
|
120
|
-
|
|
121
|
-
listeners.
|
|
180
|
+
React.useLayoutEffect(() => {
|
|
181
|
+
listeners.forEach((listener) => listener('commit'));
|
|
182
|
+
}, [listeners, state]);
|
|
122
183
|
|
|
123
|
-
|
|
124
|
-
listeners.current = listeners.current.filter((cb) => cb !== callback);
|
|
125
|
-
};
|
|
126
|
-
});
|
|
184
|
+
const snapshotRef = React.useRef(state);
|
|
127
185
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
listeners.current.forEach((callback) => callback());
|
|
186
|
+
React.useInsertionEffect(() => {
|
|
187
|
+
snapshotRef.current = state;
|
|
131
188
|
}, [state]);
|
|
132
189
|
|
|
190
|
+
// Route config or nested params can produce new state during render.
|
|
191
|
+
// If the scheduled update hasn't synced that state to the store yet,
|
|
192
|
+
// We need to expose the rendered state so consumers match the navigator.
|
|
193
|
+
// We keep this `undefined` for other scenarios, so the context isn't recreated.
|
|
194
|
+
const nextState = isSynced ? undefined : state;
|
|
195
|
+
|
|
133
196
|
const context = React.useMemo(
|
|
134
197
|
() => ({
|
|
135
198
|
getState,
|
|
136
|
-
|
|
199
|
+
getSnapshot: () => nextState ?? snapshotRef.current,
|
|
200
|
+
subscribe: (callback: (event: NavigationStateEvent) => void) => {
|
|
201
|
+
const unsubscribe = subscribe(() => callback('update'));
|
|
202
|
+
|
|
203
|
+
listeners.add(callback);
|
|
204
|
+
|
|
205
|
+
return () => {
|
|
206
|
+
listeners.delete(callback);
|
|
207
|
+
unsubscribe();
|
|
208
|
+
};
|
|
209
|
+
},
|
|
137
210
|
}),
|
|
138
|
-
[getState, subscribe]
|
|
211
|
+
[getState, listeners, nextState, subscribe]
|
|
139
212
|
);
|
|
140
213
|
|
|
141
214
|
return (
|
|
@@ -177,7 +250,7 @@ export function NamedNavigationStateListenerProvider({
|
|
|
177
250
|
);
|
|
178
251
|
}
|
|
179
252
|
|
|
180
|
-
const NavigationStateListenerContext = React.createContext<
|
|
253
|
+
export const NavigationStateListenerContext = React.createContext<
|
|
181
254
|
NavigationStateListener | undefined
|
|
182
255
|
>(undefined);
|
|
183
256
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ParamListBase } from '@react-navigation/routers';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import { NavigationBuilderContext } from './NavigationBuilderContext';
|
|
5
|
+
import { NavigationRouteContext } from './NavigationProvider';
|
|
6
|
+
import type { NavigationHelpers } from './types';
|
|
7
|
+
|
|
8
|
+
type Options = {
|
|
9
|
+
navigation: NavigationHelpers<ParamListBase>;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Hook which lets the container access the navigation object of the root navigator.
|
|
14
|
+
* It's used for the navigation object returned by `useNavigation` outside a screen.
|
|
15
|
+
*/
|
|
16
|
+
export function useOnGetNavigation({ navigation }: Options) {
|
|
17
|
+
const { addKeyedListener } = React.use(NavigationBuilderContext);
|
|
18
|
+
const route = React.use(NavigationRouteContext);
|
|
19
|
+
|
|
20
|
+
React.useInsertionEffect(() => {
|
|
21
|
+
// We only register if this is the root navigator
|
|
22
|
+
// i.e. there is no parent route
|
|
23
|
+
if (route != null) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return addKeyedListener?.('getNavigation', 'root', () => navigation);
|
|
28
|
+
}, [addKeyedListener, navigation, route]);
|
|
29
|
+
}
|
package/src/useSyncState.tsx
CHANGED
|
@@ -24,13 +24,29 @@ const createStore = <T,>(getInitialState: () => T) => {
|
|
|
24
24
|
let isBatching = false;
|
|
25
25
|
let didUpdate = false;
|
|
26
26
|
|
|
27
|
+
const notify = () => {
|
|
28
|
+
let error: { value: unknown } | undefined;
|
|
29
|
+
|
|
30
|
+
listeners.forEach((listener) => {
|
|
31
|
+
try {
|
|
32
|
+
listener();
|
|
33
|
+
} catch (e) {
|
|
34
|
+
error = error ?? { value: e };
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
if (error) {
|
|
39
|
+
throw error.value;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
27
43
|
const setState = (newState: T) => {
|
|
28
44
|
state = deepFreeze(newState);
|
|
29
45
|
|
|
30
46
|
if (isBatching) {
|
|
31
47
|
didUpdate = true;
|
|
32
48
|
} else {
|
|
33
|
-
|
|
49
|
+
notify();
|
|
34
50
|
}
|
|
35
51
|
};
|
|
36
52
|
|
|
@@ -44,12 +60,16 @@ const createStore = <T,>(getInitialState: () => T) => {
|
|
|
44
60
|
|
|
45
61
|
const batchUpdates = (callback: () => void) => {
|
|
46
62
|
isBatching = true;
|
|
47
|
-
callback();
|
|
48
|
-
isBatching = false;
|
|
49
63
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
64
|
+
try {
|
|
65
|
+
callback();
|
|
66
|
+
} finally {
|
|
67
|
+
isBatching = false;
|
|
68
|
+
|
|
69
|
+
if (didUpdate) {
|
|
70
|
+
didUpdate = false;
|
|
71
|
+
notify();
|
|
72
|
+
}
|
|
53
73
|
}
|
|
54
74
|
};
|
|
55
75
|
|
|
@@ -119,6 +139,7 @@ export function useSyncState<T>(getInitialState: () => T) {
|
|
|
119
139
|
state,
|
|
120
140
|
getState: store.getState,
|
|
121
141
|
setState: store.setState,
|
|
142
|
+
subscribe: store.subscribe,
|
|
122
143
|
scheduleUpdate,
|
|
123
144
|
flushUpdates,
|
|
124
145
|
} as const;
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const checkSerializableWithoutCircularReference = (o, seen, location) => {
|
|
4
|
-
if (o === undefined || o === null || typeof o === 'boolean' || typeof o === 'number' || typeof o === 'string') {
|
|
5
|
-
return undefined;
|
|
6
|
-
}
|
|
7
|
-
if (Object.prototype.toString.call(o) !== '[object Object]' && !Array.isArray(o)) {
|
|
8
|
-
return {
|
|
9
|
-
serializable: false,
|
|
10
|
-
location: location.slice(),
|
|
11
|
-
reason: typeof o === 'function' ? 'Function' : String(o)
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
if (seen.has(o)) {
|
|
15
|
-
return {
|
|
16
|
-
serializable: false,
|
|
17
|
-
reason: 'Circular reference',
|
|
18
|
-
location: location.slice()
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
seen.add(o);
|
|
22
|
-
if (Array.isArray(o)) {
|
|
23
|
-
for (let i = 0; i < o.length; i++) {
|
|
24
|
-
location.push(i);
|
|
25
|
-
const childResult = checkSerializableWithoutCircularReference(o[i], seen, location);
|
|
26
|
-
location.pop();
|
|
27
|
-
if (childResult) {
|
|
28
|
-
seen.delete(o);
|
|
29
|
-
return childResult;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
} else {
|
|
33
|
-
for (const key in o) {
|
|
34
|
-
location.push(key);
|
|
35
|
-
const childResult = checkSerializableWithoutCircularReference(o[key], seen, location);
|
|
36
|
-
location.pop();
|
|
37
|
-
if (childResult) {
|
|
38
|
-
seen.delete(o);
|
|
39
|
-
return childResult;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
seen.delete(o);
|
|
44
|
-
return undefined;
|
|
45
|
-
};
|
|
46
|
-
export function checkSerializable(o) {
|
|
47
|
-
return checkSerializableWithoutCircularReference(o, new Set(), []) ?? {
|
|
48
|
-
serializable: true
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
//# sourceMappingURL=checkSerializable.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["checkSerializableWithoutCircularReference","o","seen","location","undefined","Object","prototype","toString","call","Array","isArray","serializable","slice","reason","String","has","add","i","length","push","childResult","pop","delete","key","checkSerializable","Set"],"sourceRoot":"../../src","sources":["checkSerializable.tsx"],"mappings":";;AAUA,MAAMA,yCAAyC,GAAGA,CAChDC,CAAyB,EACzBC,IAAc,EACdC,QAA6B,KACL;EACxB,IACEF,CAAC,KAAKG,SAAS,IACfH,CAAC,KAAK,IAAI,IACV,OAAOA,CAAC,KAAK,SAAS,IACtB,OAAOA,CAAC,KAAK,QAAQ,IACrB,OAAOA,CAAC,KAAK,QAAQ,EACrB;IACA,OAAOG,SAAS;EAClB;EAEA,IACEC,MAAM,CAACC,SAAS,CAACC,QAAQ,CAACC,IAAI,CAACP,CAAC,CAAC,KAAK,iBAAiB,IACvD,CAACQ,KAAK,CAACC,OAAO,CAACT,CAAC,CAAC,EACjB;IACA,OAAO;MACLU,YAAY,EAAE,KAAK;MACnBR,QAAQ,EAAEA,QAAQ,CAACS,KAAK,CAAC,CAAC;MAC1BC,MAAM,EAAE,OAAOZ,CAAC,KAAK,UAAU,GAAG,UAAU,GAAGa,MAAM,CAACb,CAAC;IACzD,CAAC;EACH;EAEA,IAAIC,IAAI,CAACa,GAAG,CAACd,CAAC,CAAC,EAAE;IACf,OAAO;MACLU,YAAY,EAAE,KAAK;MACnBE,MAAM,EAAE,oBAAoB;MAC5BV,QAAQ,EAAEA,QAAQ,CAACS,KAAK,CAAC;IAC3B,CAAC;EACH;EAEAV,IAAI,CAACc,GAAG,CAACf,CAAC,CAAC;EAEX,IAAIQ,KAAK,CAACC,OAAO,CAACT,CAAC,CAAC,EAAE;IACpB,KAAK,IAAIgB,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGhB,CAAC,CAACiB,MAAM,EAAED,CAAC,EAAE,EAAE;MACjCd,QAAQ,CAACgB,IAAI,CAACF,CAAC,CAAC;MAChB,MAAMG,WAAW,GAAGpB,yCAAyC,CAC3DC,CAAC,CAACgB,CAAC,CAAC,EACJf,IAAI,EACJC,QACF,CAAC;MACDA,QAAQ,CAACkB,GAAG,CAAC,CAAC;MAEd,IAAID,WAAW,EAAE;QACflB,IAAI,CAACoB,MAAM,CAACrB,CAAC,CAAC;QACd,OAAOmB,WAAW;MACpB;IACF;EACF,CAAC,MAAM;IACL,KAAK,MAAMG,GAAG,IAAItB,CAAC,EAAE;MACnBE,QAAQ,CAACgB,IAAI,CAACI,GAAG,CAAC;MAClB,MAAMH,WAAW,GAAGpB,yCAAyC,CAC3DC,CAAC,CAACsB,GAAG,CAAC,EACNrB,IAAI,EACJC,QACF,CAAC;MACDA,QAAQ,CAACkB,GAAG,CAAC,CAAC;MAEd,IAAID,WAAW,EAAE;QACflB,IAAI,CAACoB,MAAM,CAACrB,CAAC,CAAC;QACd,OAAOmB,WAAW;MACpB;IACF;EACF;EAEAlB,IAAI,CAACoB,MAAM,CAACrB,CAAC,CAAC;EAEd,OAAOG,SAAS;AAClB,CAAC;AAED,OAAO,SAASoB,iBAAiBA,CAACvB,CAAyB,EAAU;EACnE,OACED,yCAAyC,CAACC,CAAC,EAAE,IAAIwB,GAAG,CAAM,CAAC,EAAE,EAAE,CAAC,IAAI;IAClEd,YAAY,EAAE;EAChB,CAAC;AAEL","ignoreList":[]}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
type Success = {
|
|
2
|
-
serializable: true;
|
|
3
|
-
};
|
|
4
|
-
type Failure = {
|
|
5
|
-
serializable: false;
|
|
6
|
-
location: (string | number)[];
|
|
7
|
-
reason: string;
|
|
8
|
-
};
|
|
9
|
-
type Result = Success | Failure;
|
|
10
|
-
export declare function checkSerializable(o: {
|
|
11
|
-
[key: string]: any;
|
|
12
|
-
}): Result;
|
|
13
|
-
export {};
|
|
14
|
-
//# sourceMappingURL=checkSerializable.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"checkSerializable.d.ts","sourceRoot":"","sources":["../../../src/checkSerializable.tsx"],"names":[],"mappings":"AAAA,KAAK,OAAO,GAAG;IAAE,YAAY,EAAE,IAAI,CAAA;CAAE,CAAC;AAEtC,KAAK,OAAO,GAAG;IACb,YAAY,EAAE,KAAK,CAAC;IACpB,QAAQ,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,KAAK,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AA2EhC,wBAAgB,iBAAiB,CAAC,CAAC,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,GAAG,MAAM,CAMnE"}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
type Success = { serializable: true };
|
|
2
|
-
|
|
3
|
-
type Failure = {
|
|
4
|
-
serializable: false;
|
|
5
|
-
location: (string | number)[];
|
|
6
|
-
reason: string;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
type Result = Success | Failure;
|
|
10
|
-
|
|
11
|
-
const checkSerializableWithoutCircularReference = (
|
|
12
|
-
o: { [key: string]: any },
|
|
13
|
-
seen: Set<any>,
|
|
14
|
-
location: (string | number)[]
|
|
15
|
-
): Failure | undefined => {
|
|
16
|
-
if (
|
|
17
|
-
o === undefined ||
|
|
18
|
-
o === null ||
|
|
19
|
-
typeof o === 'boolean' ||
|
|
20
|
-
typeof o === 'number' ||
|
|
21
|
-
typeof o === 'string'
|
|
22
|
-
) {
|
|
23
|
-
return undefined;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (
|
|
27
|
-
Object.prototype.toString.call(o) !== '[object Object]' &&
|
|
28
|
-
!Array.isArray(o)
|
|
29
|
-
) {
|
|
30
|
-
return {
|
|
31
|
-
serializable: false,
|
|
32
|
-
location: location.slice(),
|
|
33
|
-
reason: typeof o === 'function' ? 'Function' : String(o),
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (seen.has(o)) {
|
|
38
|
-
return {
|
|
39
|
-
serializable: false,
|
|
40
|
-
reason: 'Circular reference',
|
|
41
|
-
location: location.slice(),
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
seen.add(o);
|
|
46
|
-
|
|
47
|
-
if (Array.isArray(o)) {
|
|
48
|
-
for (let i = 0; i < o.length; i++) {
|
|
49
|
-
location.push(i);
|
|
50
|
-
const childResult = checkSerializableWithoutCircularReference(
|
|
51
|
-
o[i],
|
|
52
|
-
seen,
|
|
53
|
-
location
|
|
54
|
-
);
|
|
55
|
-
location.pop();
|
|
56
|
-
|
|
57
|
-
if (childResult) {
|
|
58
|
-
seen.delete(o);
|
|
59
|
-
return childResult;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
} else {
|
|
63
|
-
for (const key in o) {
|
|
64
|
-
location.push(key);
|
|
65
|
-
const childResult = checkSerializableWithoutCircularReference(
|
|
66
|
-
o[key],
|
|
67
|
-
seen,
|
|
68
|
-
location
|
|
69
|
-
);
|
|
70
|
-
location.pop();
|
|
71
|
-
|
|
72
|
-
if (childResult) {
|
|
73
|
-
seen.delete(o);
|
|
74
|
-
return childResult;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
seen.delete(o);
|
|
80
|
-
|
|
81
|
-
return undefined;
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
export function checkSerializable(o: { [key: string]: any }): Result {
|
|
85
|
-
return (
|
|
86
|
-
checkSerializableWithoutCircularReference(o, new Set<any>(), []) ?? {
|
|
87
|
-
serializable: true,
|
|
88
|
-
}
|
|
89
|
-
);
|
|
90
|
-
}
|