@tale-ui/utils 0.0.3
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/CHANGELOG.md +14 -0
- package/LICENSE +21 -0
- package/README.md +3 -0
- package/detectBrowser.d.ts +8 -0
- package/detectBrowser.js +64 -0
- package/empty.d.ts +3 -0
- package/empty.js +10 -0
- package/error.d.ts +2 -0
- package/error.js +23 -0
- package/esm/detectBrowser.d.ts +8 -0
- package/esm/detectBrowser.js +58 -0
- package/esm/empty.d.ts +3 -0
- package/esm/empty.js +3 -0
- package/esm/error.d.ts +2 -0
- package/esm/error.js +16 -0
- package/esm/fastHooks.d.ts +14 -0
- package/esm/fastHooks.js +43 -0
- package/esm/fastObjectShallowCompare.d.ts +1 -0
- package/esm/fastObjectShallowCompare.js +29 -0
- package/esm/formatErrorMessage.d.ts +18 -0
- package/esm/formatErrorMessage.js +26 -0
- package/esm/generateId.d.ts +1 -0
- package/esm/generateId.js +5 -0
- package/esm/getReactElementRef.d.ts +5 -0
- package/esm/getReactElementRef.js +14 -0
- package/esm/inertValue.d.ts +1 -0
- package/esm/inertValue.js +8 -0
- package/esm/isElementDisabled.d.ts +1 -0
- package/esm/isElementDisabled.js +3 -0
- package/esm/isMouseWithinBounds.d.ts +1 -0
- package/esm/isMouseWithinBounds.js +10 -0
- package/esm/mergeObjects.d.ts +1 -0
- package/esm/mergeObjects.js +15 -0
- package/esm/owner.d.ts +2 -0
- package/esm/owner.js +4 -0
- package/esm/package.json +1 -0
- package/esm/reactVersion.d.ts +3 -0
- package/esm/reactVersion.js +5 -0
- package/esm/safeReact.d.ts +2 -0
- package/esm/safeReact.js +6 -0
- package/esm/store/ReactStore.d.ts +91 -0
- package/esm/store/ReactStore.js +199 -0
- package/esm/store/Store.d.ts +58 -0
- package/esm/store/Store.js +111 -0
- package/esm/store/StoreInspector.d.ts +41 -0
- package/esm/store/StoreInspector.js +537 -0
- package/esm/store/createSelector.d.ts +30 -0
- package/esm/store/createSelector.js +148 -0
- package/esm/store/index.d.ts +5 -0
- package/esm/store/index.js +5 -0
- package/esm/store/useStore.d.ts +22 -0
- package/esm/store/useStore.js +107 -0
- package/esm/testUtils.d.ts +17 -0
- package/esm/testUtils.js +19 -0
- package/esm/useAnimationFrame.d.ts +18 -0
- package/esm/useAnimationFrame.js +106 -0
- package/esm/useControlled.d.ts +24 -0
- package/esm/useControlled.js +40 -0
- package/esm/useEnhancedClickHandler.d.ts +13 -0
- package/esm/useEnhancedClickHandler.js +38 -0
- package/esm/useForcedRerendering.d.ts +4 -0
- package/esm/useForcedRerendering.js +13 -0
- package/esm/useId.d.ts +7 -0
- package/esm/useId.js +41 -0
- package/esm/useInterval.d.ts +13 -0
- package/esm/useInterval.js +36 -0
- package/esm/useIsoLayoutEffect.d.ts +2 -0
- package/esm/useIsoLayoutEffect.js +5 -0
- package/esm/useMergedRefs.d.ts +21 -0
- package/esm/useMergedRefs.js +108 -0
- package/esm/useOnFirstRender.d.ts +1 -0
- package/esm/useOnFirstRender.js +10 -0
- package/esm/useOnMount.d.ts +5 -0
- package/esm/useOnMount.js +14 -0
- package/esm/usePreviousValue.d.ts +6 -0
- package/esm/usePreviousValue.js +22 -0
- package/esm/useRefWithInit.d.ts +10 -0
- package/esm/useRefWithInit.js +20 -0
- package/esm/useScrollLock.d.ts +7 -0
- package/esm/useScrollLock.js +244 -0
- package/esm/useStableCallback.d.ts +13 -0
- package/esm/useStableCallback.js +44 -0
- package/esm/useTimeout.d.ts +17 -0
- package/esm/useTimeout.js +43 -0
- package/esm/useValueAsRef.d.ts +10 -0
- package/esm/useValueAsRef.js +28 -0
- package/esm/visuallyHidden.d.ts +3 -0
- package/esm/visuallyHidden.js +20 -0
- package/esm/warn.d.ts +1 -0
- package/esm/warn.js +13 -0
- package/fastHooks.d.ts +14 -0
- package/fastHooks.js +54 -0
- package/fastObjectShallowCompare.d.ts +1 -0
- package/fastObjectShallowCompare.js +35 -0
- package/formatErrorMessage.d.ts +18 -0
- package/formatErrorMessage.js +33 -0
- package/generateId.d.ts +1 -0
- package/generateId.js +11 -0
- package/getReactElementRef.d.ts +5 -0
- package/getReactElementRef.js +20 -0
- package/inertValue.d.ts +1 -0
- package/inertValue.js +14 -0
- package/isElementDisabled.d.ts +1 -0
- package/isElementDisabled.js +9 -0
- package/isMouseWithinBounds.d.ts +1 -0
- package/isMouseWithinBounds.js +16 -0
- package/mergeObjects.d.ts +1 -0
- package/mergeObjects.js +21 -0
- package/owner.d.ts +2 -0
- package/owner.js +16 -0
- package/package.json +64 -0
- package/reactVersion.d.ts +3 -0
- package/reactVersion.js +12 -0
- package/safeReact.d.ts +2 -0
- package/safeReact.js +12 -0
- package/store/ReactStore.d.ts +91 -0
- package/store/ReactStore.js +205 -0
- package/store/Store.d.ts +58 -0
- package/store/Store.js +118 -0
- package/store/StoreInspector.d.ts +41 -0
- package/store/StoreInspector.js +544 -0
- package/store/createSelector.d.ts +30 -0
- package/store/createSelector.js +154 -0
- package/store/index.d.ts +5 -0
- package/store/index.js +60 -0
- package/store/useStore.d.ts +22 -0
- package/store/useStore.js +115 -0
- package/testUtils.d.ts +17 -0
- package/testUtils.js +26 -0
- package/useAnimationFrame.d.ts +18 -0
- package/useAnimationFrame.js +113 -0
- package/useControlled.d.ts +24 -0
- package/useControlled.js +46 -0
- package/useEnhancedClickHandler.d.ts +13 -0
- package/useEnhancedClickHandler.js +44 -0
- package/useForcedRerendering.d.ts +4 -0
- package/useForcedRerendering.js +18 -0
- package/useId.d.ts +7 -0
- package/useId.js +47 -0
- package/useInterval.d.ts +13 -0
- package/useInterval.js +43 -0
- package/useIsoLayoutEffect.d.ts +2 -0
- package/useIsoLayoutEffect.js +11 -0
- package/useMergedRefs.d.ts +21 -0
- package/useMergedRefs.js +114 -0
- package/useOnFirstRender.d.ts +1 -0
- package/useOnFirstRender.js +16 -0
- package/useOnMount.d.ts +5 -0
- package/useOnMount.js +20 -0
- package/usePreviousValue.d.ts +6 -0
- package/usePreviousValue.js +27 -0
- package/useRefWithInit.d.ts +10 -0
- package/useRefWithInit.js +26 -0
- package/useScrollLock.d.ts +7 -0
- package/useScrollLock.js +249 -0
- package/useStableCallback.d.ts +13 -0
- package/useStableCallback.js +49 -0
- package/useTimeout.d.ts +17 -0
- package/useTimeout.js +50 -0
- package/useValueAsRef.d.ts +10 -0
- package/useValueAsRef.js +32 -0
- package/visuallyHidden.d.ts +3 -0
- package/visuallyHidden.js +26 -0
- package/warn.d.ts +1 -0
- package/warn.js +19 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/* False positives - ESLint thinks we're calling a hook from a class component. */
|
|
2
|
+
/* eslint-disable react-hooks/rules-of-hooks */
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import { Store } from "./Store.js";
|
|
7
|
+
import { useStore } from "./useStore.js";
|
|
8
|
+
import { useStableCallback } from "../useStableCallback.js";
|
|
9
|
+
import { useIsoLayoutEffect } from "../useIsoLayoutEffect.js";
|
|
10
|
+
import { NOOP } from "../empty.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A Store that supports controlled state keys, non-reactive values and provides utility methods for React.
|
|
14
|
+
*/
|
|
15
|
+
export class ReactStore extends Store {
|
|
16
|
+
/**
|
|
17
|
+
* Creates a new ReactStore instance.
|
|
18
|
+
*
|
|
19
|
+
* @param state Initial state of the store.
|
|
20
|
+
* @param context Non-reactive context values.
|
|
21
|
+
* @param selectors Optional selectors for use with `useState`.
|
|
22
|
+
*/
|
|
23
|
+
constructor(state, context = {}, selectors) {
|
|
24
|
+
super(state);
|
|
25
|
+
this.context = context;
|
|
26
|
+
this.selectors = selectors;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Non-reactive values such as refs, callbacks, etc.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Synchronizes a single external value into the store.
|
|
35
|
+
*
|
|
36
|
+
* Note that the while the value in `state` is updated immediately, the value returned
|
|
37
|
+
* by `useState` is updated before the next render (similarly to React's `useState`).
|
|
38
|
+
*/
|
|
39
|
+
useSyncedValue(key, value) {
|
|
40
|
+
React.useDebugValue(key);
|
|
41
|
+
useIsoLayoutEffect(() => {
|
|
42
|
+
if (this.state[key] !== value) {
|
|
43
|
+
this.set(key, value);
|
|
44
|
+
}
|
|
45
|
+
}, [key, value]);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Synchronizes a single external value into the store and
|
|
50
|
+
* cleans it up (sets to `undefined`) on unmount.
|
|
51
|
+
*
|
|
52
|
+
* Note that the while the value in `state` is updated immediately, the value returned
|
|
53
|
+
* by `useState` is updated before the next render (similarly to React's `useState`).
|
|
54
|
+
*/
|
|
55
|
+
useSyncedValueWithCleanup(key, value) {
|
|
56
|
+
// eslint-disable-next-line consistent-this
|
|
57
|
+
const store = this;
|
|
58
|
+
useIsoLayoutEffect(() => {
|
|
59
|
+
if (store.state[key] !== value) {
|
|
60
|
+
store.set(key, value);
|
|
61
|
+
}
|
|
62
|
+
return () => {
|
|
63
|
+
store.set(key, undefined);
|
|
64
|
+
};
|
|
65
|
+
}, [store, key, value]);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Synchronizes multiple external values into the store.
|
|
70
|
+
*
|
|
71
|
+
* Note that the while the values in `state` are updated immediately, the values returned
|
|
72
|
+
* by `useState` are updated before the next render (similarly to React's `useState`).
|
|
73
|
+
*/
|
|
74
|
+
useSyncedValues(statePart) {
|
|
75
|
+
// eslint-disable-next-line consistent-this
|
|
76
|
+
const store = this;
|
|
77
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
78
|
+
// Check that an object with the same shape is passed on every render
|
|
79
|
+
React.useDebugValue(statePart, p => Object.keys(p));
|
|
80
|
+
const keys = React.useRef(Object.keys(statePart)).current;
|
|
81
|
+
const nextKeys = Object.keys(statePart);
|
|
82
|
+
if (keys.length !== nextKeys.length || keys.some((key, index) => key !== nextKeys[index])) {
|
|
83
|
+
console.error('ReactStore.useSyncedValues expects the same prop keys on every render. Keys should be stable.');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const dependencies = Object.values(statePart);
|
|
87
|
+
useIsoLayoutEffect(() => {
|
|
88
|
+
store.update(statePart);
|
|
89
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
90
|
+
}, [store, ...dependencies]);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Registers a controllable prop pair (`controlled`, `defaultValue`) for a specific key. If `controlled`
|
|
95
|
+
* is non-undefined, the store's state at `key` is updated to match `controlled`.
|
|
96
|
+
*/
|
|
97
|
+
useControlledProp(key, controlled) {
|
|
98
|
+
React.useDebugValue(key);
|
|
99
|
+
const isControlled = controlled !== undefined;
|
|
100
|
+
useIsoLayoutEffect(() => {
|
|
101
|
+
if (isControlled && !Object.is(this.state[key], controlled)) {
|
|
102
|
+
// Set the internal state to match the controlled value.
|
|
103
|
+
super.setState({
|
|
104
|
+
...this.state,
|
|
105
|
+
[key]: controlled
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}, [key, controlled, isControlled]);
|
|
109
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
110
|
+
// eslint-disable-next-line
|
|
111
|
+
const cache = this.controlledValues ??= new Map();
|
|
112
|
+
if (!cache.has(key)) {
|
|
113
|
+
cache.set(key, isControlled);
|
|
114
|
+
}
|
|
115
|
+
const previouslyControlled = cache.get(key);
|
|
116
|
+
if (previouslyControlled !== undefined && previouslyControlled !== isControlled) {
|
|
117
|
+
console.error(`A component is changing the ${isControlled ? '' : 'un'}controlled state of ${key.toString()} to be ${isControlled ? 'un' : ''}controlled. Elements should not switch from uncontrolled to controlled (or vice versa).`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Gets the current value from the store using a selector with the provided key.
|
|
123
|
+
*
|
|
124
|
+
* @param key Key of the selector to use.
|
|
125
|
+
*/
|
|
126
|
+
|
|
127
|
+
select(key, a1, a2, a3) {
|
|
128
|
+
const selector = this.selectors[key];
|
|
129
|
+
return selector(this.state, a1, a2, a3);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Returns a value from the store's state using a selector function.
|
|
134
|
+
* Used to subscribe to specific parts of the state.
|
|
135
|
+
* This methods causes a rerender whenever the selected state changes.
|
|
136
|
+
*
|
|
137
|
+
* @param key Key of the selector to use.
|
|
138
|
+
*/
|
|
139
|
+
|
|
140
|
+
useState(key, a1, a2, a3) {
|
|
141
|
+
React.useDebugValue(key);
|
|
142
|
+
return useStore(this, this.selectors[key], a1, a2, a3);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Wraps a function with `useStableCallback` to ensure it has a stable reference
|
|
147
|
+
* and assigns it to the context.
|
|
148
|
+
*
|
|
149
|
+
* @param key Key of the event callback. Must be a function in the context.
|
|
150
|
+
* @param fn Function to assign.
|
|
151
|
+
*/
|
|
152
|
+
useContextCallback(key, fn) {
|
|
153
|
+
React.useDebugValue(key);
|
|
154
|
+
const stableFunction = useStableCallback(fn ?? NOOP);
|
|
155
|
+
this.context[key] = stableFunction;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Returns a stable setter function for a specific key in the store's state.
|
|
160
|
+
* It's commonly used to pass as a ref callback to React elements.
|
|
161
|
+
*
|
|
162
|
+
* @param key Key of the state to set.
|
|
163
|
+
*/
|
|
164
|
+
useStateSetter(key) {
|
|
165
|
+
const ref = React.useRef(undefined);
|
|
166
|
+
if (ref.current === undefined) {
|
|
167
|
+
ref.current = value => {
|
|
168
|
+
this.set(key, value);
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
return ref.current;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Observes changes derived from the store's selectors and calls the listener when the selected value changes.
|
|
176
|
+
*
|
|
177
|
+
* @param key Key of the selector to observe.
|
|
178
|
+
* @param listener Listener function called when the selector result changes.
|
|
179
|
+
*/
|
|
180
|
+
|
|
181
|
+
observe(selector, listener) {
|
|
182
|
+
let selectFn;
|
|
183
|
+
if (typeof selector === 'function') {
|
|
184
|
+
selectFn = selector;
|
|
185
|
+
} else {
|
|
186
|
+
selectFn = this.selectors[selector];
|
|
187
|
+
}
|
|
188
|
+
let prevValue = selectFn(this.state);
|
|
189
|
+
listener(prevValue, prevValue, this);
|
|
190
|
+
return this.subscribe(nextState => {
|
|
191
|
+
const nextValue = selectFn(nextState);
|
|
192
|
+
if (!Object.is(prevValue, nextValue)) {
|
|
193
|
+
const oldValue = prevValue;
|
|
194
|
+
prevValue = nextValue;
|
|
195
|
+
listener(nextValue, oldValue, this);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
type Listener<T> = (state: T) => void;
|
|
2
|
+
/**
|
|
3
|
+
* A data store implementation that allows subscribing to state changes and updating the state.
|
|
4
|
+
* It uses an observer pattern to notify subscribers when the state changes.
|
|
5
|
+
*/
|
|
6
|
+
export declare class Store<State> {
|
|
7
|
+
/**
|
|
8
|
+
* The current state of the store.
|
|
9
|
+
* This property is updated immediately when the state changes as a result of calling {@link setState}, {@link update}, or {@link set}.
|
|
10
|
+
* To subscribe to state changes, use the {@link useState} method. The value returned by {@link useState} is updated after the component renders (similarly to React's useState).
|
|
11
|
+
* The values can be used directly (to avoid subscribing to the store) in effects or event handlers.
|
|
12
|
+
*
|
|
13
|
+
* Do not modify properties in state directly. Instead, use the provided methods to ensure proper state management and listener notification.
|
|
14
|
+
*/
|
|
15
|
+
state: State;
|
|
16
|
+
private listeners;
|
|
17
|
+
private updateTick;
|
|
18
|
+
constructor(state: State);
|
|
19
|
+
/**
|
|
20
|
+
* Registers a listener that will be called whenever the store's state changes.
|
|
21
|
+
*
|
|
22
|
+
* @param fn The listener function to be called on state changes.
|
|
23
|
+
* @returns A function to unsubscribe the listener.
|
|
24
|
+
*/
|
|
25
|
+
subscribe: (fn: Listener<State>) => () => void;
|
|
26
|
+
/**
|
|
27
|
+
* Returns the current state of the store.
|
|
28
|
+
*/
|
|
29
|
+
getSnapshot: () => State;
|
|
30
|
+
/**
|
|
31
|
+
* Updates the entire store's state and notifies all registered listeners.
|
|
32
|
+
*
|
|
33
|
+
* @param newState The new state to set for the store.
|
|
34
|
+
*/
|
|
35
|
+
setState(newState: State): void;
|
|
36
|
+
/**
|
|
37
|
+
* Merges the provided changes into the current state and notifies listeners if there are changes.
|
|
38
|
+
*
|
|
39
|
+
* @param changes An object containing the changes to apply to the current state.
|
|
40
|
+
*/
|
|
41
|
+
update(changes: Partial<State>): void;
|
|
42
|
+
/**
|
|
43
|
+
* Sets a specific key in the store's state to a new value and notifies listeners if the value has changed.
|
|
44
|
+
*
|
|
45
|
+
* @param key The key in the store's state to update.
|
|
46
|
+
* @param value The new value to set for the specified key.
|
|
47
|
+
*/
|
|
48
|
+
set<T>(key: keyof State, value: T): void;
|
|
49
|
+
/**
|
|
50
|
+
* Gives the state a new reference and updates all registered listeners.
|
|
51
|
+
*/
|
|
52
|
+
notifyAll(): void;
|
|
53
|
+
use<F extends (...args: any) => any>(selector: F, ...args: SelectorArgs<F>): ReturnType<F>;
|
|
54
|
+
}
|
|
55
|
+
export type ReadonlyStore<State> = Pick<Store<State>, 'getSnapshot' | 'subscribe' | 'state'>;
|
|
56
|
+
type SelectorArgs<Selector> = Selector extends ((...params: infer Params) => any) ? Tail<Params> : never;
|
|
57
|
+
type Tail<T extends readonly any[]> = T extends readonly [any, ...infer Rest] ? Rest : [];
|
|
58
|
+
export {};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { useStore } from "./useStore.js";
|
|
2
|
+
/**
|
|
3
|
+
* A data store implementation that allows subscribing to state changes and updating the state.
|
|
4
|
+
* It uses an observer pattern to notify subscribers when the state changes.
|
|
5
|
+
*/
|
|
6
|
+
export class Store {
|
|
7
|
+
/**
|
|
8
|
+
* The current state of the store.
|
|
9
|
+
* This property is updated immediately when the state changes as a result of calling {@link setState}, {@link update}, or {@link set}.
|
|
10
|
+
* To subscribe to state changes, use the {@link useState} method. The value returned by {@link useState} is updated after the component renders (similarly to React's useState).
|
|
11
|
+
* The values can be used directly (to avoid subscribing to the store) in effects or event handlers.
|
|
12
|
+
*
|
|
13
|
+
* Do not modify properties in state directly. Instead, use the provided methods to ensure proper state management and listener notification.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
// Internal state to handle recursive `setState()` calls
|
|
17
|
+
|
|
18
|
+
constructor(state) {
|
|
19
|
+
this.state = state;
|
|
20
|
+
this.listeners = new Set();
|
|
21
|
+
this.updateTick = 0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Registers a listener that will be called whenever the store's state changes.
|
|
26
|
+
*
|
|
27
|
+
* @param fn The listener function to be called on state changes.
|
|
28
|
+
* @returns A function to unsubscribe the listener.
|
|
29
|
+
*/
|
|
30
|
+
subscribe = fn => {
|
|
31
|
+
this.listeners.add(fn);
|
|
32
|
+
return () => {
|
|
33
|
+
this.listeners.delete(fn);
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Returns the current state of the store.
|
|
39
|
+
*/
|
|
40
|
+
getSnapshot = () => {
|
|
41
|
+
return this.state;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Updates the entire store's state and notifies all registered listeners.
|
|
46
|
+
*
|
|
47
|
+
* @param newState The new state to set for the store.
|
|
48
|
+
*/
|
|
49
|
+
setState(newState) {
|
|
50
|
+
if (this.state === newState) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
this.state = newState;
|
|
54
|
+
this.updateTick += 1;
|
|
55
|
+
const currentTick = this.updateTick;
|
|
56
|
+
for (const listener of this.listeners) {
|
|
57
|
+
if (currentTick !== this.updateTick) {
|
|
58
|
+
// If the tick has changed, a recursive `setState` call has been made,
|
|
59
|
+
// and it has already notified all listeners.
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
listener(newState);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Merges the provided changes into the current state and notifies listeners if there are changes.
|
|
68
|
+
*
|
|
69
|
+
* @param changes An object containing the changes to apply to the current state.
|
|
70
|
+
*/
|
|
71
|
+
update(changes) {
|
|
72
|
+
for (const key in changes) {
|
|
73
|
+
if (!Object.is(this.state[key], changes[key])) {
|
|
74
|
+
this.setState({
|
|
75
|
+
...this.state,
|
|
76
|
+
...changes
|
|
77
|
+
});
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Sets a specific key in the store's state to a new value and notifies listeners if the value has changed.
|
|
85
|
+
*
|
|
86
|
+
* @param key The key in the store's state to update.
|
|
87
|
+
* @param value The new value to set for the specified key.
|
|
88
|
+
*/
|
|
89
|
+
set(key, value) {
|
|
90
|
+
if (!Object.is(this.state[key], value)) {
|
|
91
|
+
this.setState({
|
|
92
|
+
...this.state,
|
|
93
|
+
[key]: value
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Gives the state a new reference and updates all registered listeners.
|
|
100
|
+
*/
|
|
101
|
+
notifyAll() {
|
|
102
|
+
const newState = {
|
|
103
|
+
...this.state
|
|
104
|
+
};
|
|
105
|
+
this.setState(newState);
|
|
106
|
+
}
|
|
107
|
+
use(selector, a1, a2, a3) {
|
|
108
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
109
|
+
return useStore(this, selector, a1, a2, a3);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Store } from "./Store.js";
|
|
3
|
+
export interface StoreInspectorProps {
|
|
4
|
+
/**
|
|
5
|
+
* Instance of the store to inspect.
|
|
6
|
+
*/
|
|
7
|
+
store: Store<any>;
|
|
8
|
+
/**
|
|
9
|
+
* Additional data to display in the inspector.
|
|
10
|
+
*/
|
|
11
|
+
additionalData?: any;
|
|
12
|
+
/**
|
|
13
|
+
* Title to display in the panel header.
|
|
14
|
+
*/
|
|
15
|
+
title?: string | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Whether the inspector panel should be open by default.
|
|
18
|
+
* @default false
|
|
19
|
+
*/
|
|
20
|
+
defaultOpen?: boolean | undefined;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* A tool to inspect the state of a Store in a floating panel.
|
|
24
|
+
* This is intended for development and debugging purposes.
|
|
25
|
+
*/
|
|
26
|
+
export declare function StoreInspector(props: StoreInspectorProps): import("react/jsx-runtime").JSX.Element;
|
|
27
|
+
interface PanelProps {
|
|
28
|
+
store: Store<any>;
|
|
29
|
+
title?: string | undefined;
|
|
30
|
+
additionalData?: any;
|
|
31
|
+
open: boolean;
|
|
32
|
+
onClose?: (() => void) | undefined;
|
|
33
|
+
}
|
|
34
|
+
export declare function StoreInspectorPanel({
|
|
35
|
+
store,
|
|
36
|
+
title,
|
|
37
|
+
additionalData,
|
|
38
|
+
open,
|
|
39
|
+
onClose
|
|
40
|
+
}: PanelProps): React.ReactPortal | null;
|
|
41
|
+
export {};
|