juststore 0.3.0 → 0.3.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/README.md +19 -16
- package/dist/form.d.ts +28 -12
- package/dist/index.d.ts +1 -1
- package/dist/memory.d.ts +2 -2
- package/dist/mixed_state.d.ts +2 -2
- package/dist/node.js +26 -15
- package/dist/root.js +24 -16
- package/dist/types.d.ts +14 -13
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -473,22 +473,25 @@ The store root provides path-based methods for dynamic access:
|
|
|
473
473
|
|
|
474
474
|
### State Methods
|
|
475
475
|
|
|
476
|
-
| Method | Description
|
|
477
|
-
| ---------------------------------------- |
|
|
478
|
-
| `.use()` | Subscribe and read value (triggers re-render on change)
|
|
479
|
-
| `.useDebounce(ms)` | Subscribe with debounced updates
|
|
480
|
-
| `.useState()` | Returns `[value, setValue]` tuple
|
|
481
|
-
| `.value` | Read without subscribing
|
|
482
|
-
| `.set(value)` | Update value
|
|
483
|
-
| `.set(fn)` | Functional update
|
|
484
|
-
| `.reset()` | Delete value at path
|
|
485
|
-
| `.subscribe(fn)` | Subscribe to changes (for effects)
|
|
486
|
-
| `.rename(oldKey, newKey, notifyObject?)` | Rename a key in an object
|
|
487
|
-
| `.notify()` | Manually trigger subscribers
|
|
488
|
-
| `.useCompute(fn)` | Derive a computed value
|
|
489
|
-
| `.derived({ from, to })` | Create bidirectional transform
|
|
490
|
-
| `.
|
|
491
|
-
| `.
|
|
476
|
+
| Method | Description |
|
|
477
|
+
| ---------------------------------------- | ----------------------------------------------------------------------- |
|
|
478
|
+
| `.use()` | Subscribe and read value (triggers re-render on change) |
|
|
479
|
+
| `.useDebounce(ms)` | Subscribe with debounced updates |
|
|
480
|
+
| `.useState()` | Returns `[value, setValue]` tuple |
|
|
481
|
+
| `.value` | Read without subscribing |
|
|
482
|
+
| `.set(value)` | Update value |
|
|
483
|
+
| `.set(fn)` | Functional update |
|
|
484
|
+
| `.reset()` | Delete value at path |
|
|
485
|
+
| `.subscribe(fn)` | Subscribe to changes (for effects) |
|
|
486
|
+
| `.rename(oldKey, newKey, notifyObject?)` | Rename a key in an object |
|
|
487
|
+
| `.notify()` | Manually trigger subscribers |
|
|
488
|
+
| `.useCompute(fn)` | Derive a computed value |
|
|
489
|
+
| `.derived({ from, to })` | Create bidirectional transform |
|
|
490
|
+
| `.ensureArray()` | Ensure the value is an array |
|
|
491
|
+
| `.ensureObject()` | Ensure the value is an object |
|
|
492
|
+
| `.withDefault(defaultValue)` | Return a new state with a default value, and make the type non-nullable |
|
|
493
|
+
| `.Render({ children })` | Render prop component |
|
|
494
|
+
| `.Show({ children, on })` | Conditional render component |
|
|
492
495
|
|
|
493
496
|
## License
|
|
494
497
|
|
package/dist/form.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { FieldPath, FieldPathValue, FieldValues,
|
|
2
|
-
import type { ArrayProxy,
|
|
1
|
+
import type { FieldPath, FieldPathValue, FieldValues, IsEqual } from './path';
|
|
2
|
+
import type { ArrayProxy, IsNullable, MaybeNullable, ObjectMutationMethods, ValueState } from './types';
|
|
3
3
|
export { useForm, type CreateFormOptions, type DeepNonNullable, type FormArrayState, type FormObjectState, type FormState, type FormStore, type FormValueState };
|
|
4
4
|
/**
|
|
5
5
|
* Common form field methods available on every form state node.
|
|
@@ -12,19 +12,35 @@ type FormCommon = {
|
|
|
12
12
|
/** Manually set a validation error. */
|
|
13
13
|
setError: (error: string | undefined) => void;
|
|
14
14
|
};
|
|
15
|
-
type FormState<T> = [
|
|
16
|
-
interface FormValueState<T> extends ValueState<T>, FormCommon {
|
|
15
|
+
type FormState<T> = IsEqual<T, unknown> extends true ? never : [NonNullable<T>] extends [readonly (infer U)[]] ? FormArrayState<U, IsNullable<T>> : [NonNullable<T>] extends [FieldValues] ? FormObjectState<NonNullable<T>, IsNullable<T>> : FormValueState<T>;
|
|
16
|
+
interface FormValueState<T> extends Omit<ValueState<T>, 'withDefault' | 'derived'>, FormCommon {
|
|
17
|
+
/** Return a new state with a default value, and make the type non-nullable */
|
|
18
|
+
withDefault(defaultValue: T): FormState<NonNullable<T>>;
|
|
19
|
+
/** Virtual state derived from the current value.
|
|
20
|
+
*
|
|
21
|
+
* @returns ArrayState if the derived value is an array, ObjectState if the derived value is an object, otherwise State.
|
|
22
|
+
* @example
|
|
23
|
+
* const state = store.a.b.c.derived({
|
|
24
|
+
* from: value => value + 1,
|
|
25
|
+
* to: value => value - 1
|
|
26
|
+
* })
|
|
27
|
+
* state.use() // returns the derived value
|
|
28
|
+
* state.set(10) // sets the derived value
|
|
29
|
+
* state.reset() // resets the derived value
|
|
30
|
+
*/
|
|
31
|
+
derived: <R>({ from, to }: {
|
|
32
|
+
from?: (value: T | undefined) => R;
|
|
33
|
+
to?: (value: R) => T | undefined;
|
|
34
|
+
}) => FormState<R>;
|
|
17
35
|
}
|
|
18
|
-
type
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
type FormObjectState<T extends FieldValues> = {
|
|
36
|
+
type FormArrayState<T, Nullable extends boolean = false, TT = MaybeNullable<T[], Nullable>> = IsEqual<T, unknown> extends true ? never : FormValueState<TT[]> & ArrayProxy<TT, FormState<TT>>;
|
|
37
|
+
type FormObjectState<T extends FieldValues, Nullable extends boolean = false> = {
|
|
22
38
|
[K in keyof T]-?: FormState<T[K]>;
|
|
23
|
-
} & FormValueState<T
|
|
39
|
+
} & FormValueState<MaybeNullable<T, Nullable>> & ObjectMutationMethods;
|
|
24
40
|
/** Type for nested objects with proxy methods */
|
|
25
|
-
type DeepNonNullable<T> = [
|
|
26
|
-
[K in keyof
|
|
27
|
-
} :
|
|
41
|
+
type DeepNonNullable<T> = [NonNullable<T>] extends [readonly (infer U)[]] ? U[] : [NonNullable<T>] extends [FieldValues] ? {
|
|
42
|
+
[K in keyof NonNullable<T>]-?: DeepNonNullable<NonNullable<T>[K]>;
|
|
43
|
+
} : NonNullable<T>;
|
|
28
44
|
/**
|
|
29
45
|
* The form store type, combining form state with validation and submission handling.
|
|
30
46
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
export type * from './form';
|
|
1
2
|
export { useForm } from './form';
|
|
2
|
-
export type { CreateFormOptions, FormState, FormStore } from './form';
|
|
3
3
|
export { useMemoryStore, type MemoryStore } from './memory';
|
|
4
4
|
export { createMixedState, type MixedState } from './mixed_state';
|
|
5
5
|
export type * from './path';
|
package/dist/memory.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { FieldValues } from './path';
|
|
2
|
-
import type { State } from './types';
|
|
2
|
+
import type { State, ValueState } from './types';
|
|
3
3
|
export { useMemoryStore, type MemoryStore };
|
|
4
4
|
/**
|
|
5
5
|
* A component local store with React bindings.
|
|
@@ -10,7 +10,7 @@ export { useMemoryStore, type MemoryStore };
|
|
|
10
10
|
* - Type-safe paths using FieldPath.
|
|
11
11
|
* - Dynamic deep access via Proxy for ergonomic usage like `state.a.b.c.use()` and `state.a.b.c.set(v)`.
|
|
12
12
|
*/
|
|
13
|
-
type MemoryStore<T extends FieldValues> =
|
|
13
|
+
type MemoryStore<T extends FieldValues> = ValueState<T> & {
|
|
14
14
|
[K in keyof T]-?: State<T[K]>;
|
|
15
15
|
};
|
|
16
16
|
/**
|
package/dist/mixed_state.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Prettify,
|
|
1
|
+
import type { Prettify, ValueState } from './types';
|
|
2
2
|
export { createMixedState, type MixedState };
|
|
3
3
|
/**
|
|
4
4
|
* A combined state that aggregates multiple independent states into a tuple.
|
|
@@ -21,5 +21,5 @@ type MixedState<T extends readonly unknown[]> = Prettify<Pick<ValueState<Readonl
|
|
|
21
21
|
* </mixedState.Render>
|
|
22
22
|
*/
|
|
23
23
|
declare function createMixedState<T extends readonly unknown[]>(...states: {
|
|
24
|
-
[K in keyof T]-?:
|
|
24
|
+
[K in keyof T]-?: ValueState<T[K]>;
|
|
25
25
|
}): MixedState<T>;
|
package/dist/node.js
CHANGED
|
@@ -87,10 +87,13 @@ function createNode(storeApi, path, cache, extensions, from = unchanged, to = un
|
|
|
87
87
|
return () => storeApi.notify(path);
|
|
88
88
|
}
|
|
89
89
|
if (prop === 'ensureArray') {
|
|
90
|
-
return () => createNode(storeApi, path, cache, extensions, ensureArray, unchanged);
|
|
90
|
+
return () => createNode(storeApi, path, cache, extensions, value => ensureArray(value, from), unchanged);
|
|
91
91
|
}
|
|
92
92
|
if (prop === 'ensureObject') {
|
|
93
|
-
return () => createNode(storeApi, path, cache, extensions, ensureObject,
|
|
93
|
+
return () => createNode(storeApi, path, cache, extensions, value => ensureObject(value, from), to);
|
|
94
|
+
}
|
|
95
|
+
if (prop === 'withDefault') {
|
|
96
|
+
return (defaultValue) => createNode(storeApi, path, cache, extensions, value => withDefault(value, defaultValue, from), to);
|
|
94
97
|
}
|
|
95
98
|
if (isObjectMethod(prop)) {
|
|
96
99
|
const derivedValue = from(storeApi.value(path));
|
|
@@ -112,7 +115,7 @@ function createNode(storeApi, path, cache, extensions, from = unchanged, to = un
|
|
|
112
115
|
if (prop === 'at') {
|
|
113
116
|
return (index) => {
|
|
114
117
|
const nextPath = path ? `${path}.${index}` : String(index);
|
|
115
|
-
return createNode(storeApi, nextPath, cache, extensions
|
|
118
|
+
return createNode(storeApi, nextPath, cache, extensions);
|
|
116
119
|
};
|
|
117
120
|
}
|
|
118
121
|
if (prop === 'length') {
|
|
@@ -221,8 +224,7 @@ function createNode(storeApi, path, cache, extensions, from = unchanged, to = un
|
|
|
221
224
|
}
|
|
222
225
|
if (typeof prop === 'string' || typeof prop === 'number') {
|
|
223
226
|
const nextPath = path ? `${path}.${prop}` : String(prop);
|
|
224
|
-
|
|
225
|
-
return createNode(storeApi, nextPath, cache, extensions, from, to);
|
|
227
|
+
return createNode(storeApi, nextPath, cache, extensions);
|
|
226
228
|
}
|
|
227
229
|
return undefined;
|
|
228
230
|
},
|
|
@@ -263,17 +265,26 @@ function isObjectMethod(prop) {
|
|
|
263
265
|
function unchanged(value) {
|
|
264
266
|
return value;
|
|
265
267
|
}
|
|
266
|
-
|
|
268
|
+
const EMPTY_ARRAY = [];
|
|
269
|
+
const EMPTY_OBJECT = {};
|
|
270
|
+
function ensureArray(value, from) {
|
|
271
|
+
if (value === undefined || value === null)
|
|
272
|
+
return EMPTY_ARRAY;
|
|
273
|
+
const array = from(value);
|
|
274
|
+
if (Array.isArray(array))
|
|
275
|
+
return array;
|
|
276
|
+
return EMPTY_ARRAY;
|
|
277
|
+
}
|
|
278
|
+
function ensureObject(value, from) {
|
|
267
279
|
if (value === undefined || value === null)
|
|
268
|
-
return
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
280
|
+
return EMPTY_OBJECT;
|
|
281
|
+
const obj = from(value);
|
|
282
|
+
if (typeof obj === 'object')
|
|
283
|
+
return obj;
|
|
284
|
+
return EMPTY_OBJECT;
|
|
272
285
|
}
|
|
273
|
-
function
|
|
286
|
+
function withDefault(value, defaultValue, from) {
|
|
274
287
|
if (value === undefined || value === null)
|
|
275
|
-
return
|
|
276
|
-
|
|
277
|
-
return value;
|
|
278
|
-
return {};
|
|
288
|
+
return defaultValue; // defaultValue should've already matched the type
|
|
289
|
+
return from(value);
|
|
279
290
|
}
|
package/dist/root.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCallback, useRef, useSyncExternalStore } from 'react';
|
|
2
|
-
import { getNestedValue, getSnapshot, joinPath, notifyListeners, produce, rename, setLeaf, subscribe, useDebounce, useObject, useSubscribe } from './impl';
|
|
2
|
+
import { getNestedValue, getSnapshot, isEqual, joinPath, notifyListeners, produce, rename, setLeaf, subscribe, useDebounce, useObject, useSubscribe } from './impl';
|
|
3
3
|
import { createRootNode } from './node';
|
|
4
4
|
export { createStoreRoot };
|
|
5
5
|
/**
|
|
@@ -41,19 +41,27 @@ function createStoreRoot(namespace, defaultValue, options = {}) {
|
|
|
41
41
|
const fullPath = joinPath(namespace, path);
|
|
42
42
|
const fnRef = useRef(fn);
|
|
43
43
|
fnRef.current = fn;
|
|
44
|
-
// Cache to avoid infinite loops - only recompute when store value changes
|
|
45
44
|
const cacheRef = useRef(null);
|
|
46
45
|
const subscribeToPath = useCallback((onStoreChange) => subscribe(fullPath, onStoreChange), [fullPath]);
|
|
47
46
|
const getComputedSnapshot = useCallback(() => {
|
|
47
|
+
if (cacheRef.current && cacheRef.current.path !== fullPath) {
|
|
48
|
+
cacheRef.current = null;
|
|
49
|
+
}
|
|
48
50
|
const storeValue = getSnapshot(fullPath);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
if (cacheRef.current && isEqual(cacheRef.current.storeValue, storeValue)) {
|
|
52
|
+
// same store value, return the same computed value
|
|
53
|
+
return cacheRef.current.computed;
|
|
54
|
+
}
|
|
55
|
+
const computedNext = fnRef.current(storeValue);
|
|
56
|
+
// Important: even if storeValue changed, we should avoid forcing a re-render
|
|
57
|
+
// when the computed result is logically unchanged. `useSyncExternalStore`
|
|
58
|
+
// uses `Object.is` on the snapshot; returning the same reference will bail out.
|
|
59
|
+
if (cacheRef.current && isEqual(cacheRef.current.computed, computedNext)) {
|
|
60
|
+
cacheRef.current.storeValue = storeValue;
|
|
51
61
|
return cacheRef.current.computed;
|
|
52
62
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
cacheRef.current = { storeValue, computed };
|
|
56
|
-
return computed;
|
|
63
|
+
cacheRef.current = { path: fullPath, storeValue, computed: computedNext };
|
|
64
|
+
return computedNext;
|
|
57
65
|
}, [fullPath]);
|
|
58
66
|
return useSyncExternalStore(subscribeToPath, getComputedSnapshot, getComputedSnapshot);
|
|
59
67
|
},
|
|
@@ -66,28 +74,28 @@ function createStoreRoot(namespace, defaultValue, options = {}) {
|
|
|
66
74
|
});
|
|
67
75
|
},
|
|
68
76
|
useState: (path) => {
|
|
69
|
-
const
|
|
77
|
+
const fullPath = joinPath(namespace, path);
|
|
70
78
|
const setValue = useCallback((value) => {
|
|
71
79
|
if (typeof value === 'function') {
|
|
72
|
-
const currentValue = getSnapshot(
|
|
80
|
+
const currentValue = getSnapshot(fullPath);
|
|
73
81
|
const newValue = value(currentValue);
|
|
74
82
|
return setLeaf(namespace, path, newValue, false, memoryOnly);
|
|
75
83
|
}
|
|
76
84
|
return setLeaf(namespace, path, value, false, memoryOnly);
|
|
77
|
-
}, [path]);
|
|
78
|
-
return [useObject(
|
|
85
|
+
}, [fullPath, path]);
|
|
86
|
+
return [useObject(namespace, path), setValue];
|
|
79
87
|
},
|
|
80
88
|
Render: ({ path, children }) => {
|
|
81
|
-
const
|
|
82
|
-
const value = useObject(
|
|
89
|
+
const fullPath = joinPath(namespace, path);
|
|
90
|
+
const value = useObject(namespace, path);
|
|
83
91
|
const update = useCallback((value) => {
|
|
84
92
|
if (typeof value === 'function') {
|
|
85
|
-
const currentValue = getSnapshot(
|
|
93
|
+
const currentValue = getSnapshot(fullPath);
|
|
86
94
|
const newValue = value(currentValue);
|
|
87
95
|
return setLeaf(namespace, path, newValue, false, memoryOnly);
|
|
88
96
|
}
|
|
89
97
|
return setLeaf(namespace, path, value, false, memoryOnly);
|
|
90
|
-
}, [path]);
|
|
98
|
+
}, [fullPath, path]);
|
|
91
99
|
return children(value, update);
|
|
92
100
|
},
|
|
93
101
|
Show: ({ path, children, on }) => {
|
package/dist/types.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import type { FieldPath, FieldPathValue, FieldValues,
|
|
2
|
-
export type { AllowedKeys,
|
|
1
|
+
import type { FieldPath, FieldPathValue, FieldValues, IsEqual } from './path';
|
|
2
|
+
export type { AllowedKeys, ArrayProxy, ArrayState, DerivedStateProps, IsNullable, MaybeNullable, ObjectMutationMethods, ObjectState, Prettify, State, StoreRenderProps, StoreRoot, StoreSetStateAction, StoreShowProps, StoreUse, ValueState };
|
|
3
3
|
type Prettify<T> = {
|
|
4
4
|
[K in keyof T]: T[K];
|
|
5
5
|
} & {};
|
|
6
6
|
type AllowedKeys<T> = Exclude<keyof T, keyof ValueState<unknown> | keyof ObjectMutationMethods>;
|
|
7
|
-
type ArrayMutationMethods<T> = Pick<Array<T>, 'push' | 'pop' | 'shift' | 'unshift' | 'splice' | 'reverse' | 'sort' | 'fill' | 'copyWithin'
|
|
7
|
+
type ArrayMutationMethods<T> = Prettify<Pick<Array<T>, 'push' | 'pop' | 'shift' | 'unshift' | 'splice' | 'reverse' | 'sort' | 'fill' | 'copyWithin'>>;
|
|
8
8
|
/** Type for array proxy with index access */
|
|
9
|
-
type ArrayProxy<T, ElementState =
|
|
9
|
+
type ArrayProxy<T, ElementState = State<T>> = ArrayMutationMethods<T> & {
|
|
10
10
|
/** Read without subscribing. Returns array or undefined for missing paths. */
|
|
11
11
|
readonly value: T[];
|
|
12
12
|
/**
|
|
@@ -80,9 +80,11 @@ type ValueState<T> = {
|
|
|
80
80
|
/** Compute a derived value from the current value, similar to useState + useMemo */
|
|
81
81
|
useCompute: <R>(fn: (value: T) => R) => R;
|
|
82
82
|
/** Ensure the value is an array. */
|
|
83
|
-
ensureArray<
|
|
83
|
+
ensureArray(): NonNullable<T> extends (infer U)[] ? ArrayState<U> : never;
|
|
84
84
|
/** Ensure the value is an object. */
|
|
85
|
-
ensureObject<
|
|
85
|
+
ensureObject(): NonNullable<T> extends FieldValues ? ObjectState<NonNullable<T>> : never;
|
|
86
|
+
/** Return a new state with a default value, and make the type non-nullable */
|
|
87
|
+
withDefault(defaultValue: T): State<NonNullable<T>>;
|
|
86
88
|
/** Virtual state derived from the current value.
|
|
87
89
|
*
|
|
88
90
|
* @returns ArrayState if the derived value is an array, ObjectState if the derived value is an object, otherwise State.
|
|
@@ -123,14 +125,13 @@ type ValueState<T> = {
|
|
|
123
125
|
on: (value: T) => boolean;
|
|
124
126
|
}) => React.ReactNode;
|
|
125
127
|
};
|
|
126
|
-
type
|
|
127
|
-
type
|
|
128
|
-
type State<T> = [
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
type ObjectState<T extends FieldValues> = {
|
|
128
|
+
type MaybeNullable<T, Nullable extends boolean = false> = Nullable extends true ? T | undefined : T;
|
|
129
|
+
type IsNullable<T> = T extends undefined | null ? true : false;
|
|
130
|
+
type State<T> = IsEqual<T, unknown> extends true ? never : [NonNullable<T>] extends [readonly (infer U)[]] ? ArrayState<U, IsNullable<T>> : [NonNullable<T>] extends [FieldValues] ? ObjectState<NonNullable<T>, IsNullable<T>> : ValueState<T>;
|
|
131
|
+
type ArrayState<T, Nullable extends boolean = false> = IsEqual<T, unknown> extends true ? never : ValueState<MaybeNullable<T[], Nullable>> & ArrayProxy<T>;
|
|
132
|
+
type ObjectState<T extends FieldValues, Nullable extends boolean = false> = {
|
|
132
133
|
[K in keyof T]-?: State<T[K]>;
|
|
133
|
-
} & ValueState<T
|
|
134
|
+
} & ValueState<MaybeNullable<T, Nullable>> & ObjectMutationMethods;
|
|
134
135
|
/** Props for Store.Render helper. */
|
|
135
136
|
type StoreRenderProps<T extends FieldValues, P extends FieldPath<T>> = {
|
|
136
137
|
path: P;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "juststore",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "A small, expressive, and type-safe state management library for React.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -52,19 +52,19 @@
|
|
|
52
52
|
"react-fast-compare": "^3.2.2"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@eslint/js": "^9.39.
|
|
56
|
-
"@types/node": "^24.10.
|
|
57
|
-
"@types/react": "^19.2.
|
|
58
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
59
|
-
"@typescript-eslint/parser": "^8.
|
|
60
|
-
"eslint": "^9.39.
|
|
55
|
+
"@eslint/js": "^9.39.2",
|
|
56
|
+
"@types/node": "^24.10.4",
|
|
57
|
+
"@types/react": "^19.2.7",
|
|
58
|
+
"@typescript-eslint/eslint-plugin": "^8.50.1",
|
|
59
|
+
"@typescript-eslint/parser": "^8.50.1",
|
|
60
|
+
"eslint": "^9.39.2",
|
|
61
61
|
"eslint-plugin-prettier": "^5.5.4",
|
|
62
62
|
"eslint-plugin-react": "^7.37.5",
|
|
63
63
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
64
|
-
"eslint-plugin-react-refresh": "^0.4.
|
|
64
|
+
"eslint-plugin-react-refresh": "^0.4.26",
|
|
65
65
|
"husky": "^9.1.7",
|
|
66
66
|
"prettier": "^3.7.4",
|
|
67
|
-
"react": "^19.2.
|
|
67
|
+
"react": "^19.2.3",
|
|
68
68
|
"typescript": "^5.9.3"
|
|
69
69
|
}
|
|
70
70
|
}
|