juststore 0.4.2 → 0.4.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/dist/form.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { FieldPath, FieldPathValue, FieldValues, IsEqual } from './path';
2
- import type { ArrayProxy, DerivedStateProps, IsNullable, MaybeNullable, ObjectMutationMethods, ValueState } from './types';
2
+ import type { ArrayProxy, DerivedStateProps, IsNullable, MaybeNullable, ObjectMutationMethods, Prettify, ValueState } from './types';
3
3
  export { createForm, 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.
@@ -13,7 +13,12 @@ type FormCommon = {
13
13
  setError: (error: string | undefined) => void;
14
14
  };
15
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 {
16
+ type FormReadOnlyState<T> = Prettify<Pick<FormValueState<Readonly<Required<T>>>, 'value' | 'use' | 'useCompute' | 'Render' | 'Show' | 'error' | 'setError'>>;
17
+ interface FormValueState<T> extends Omit<ValueState<T>, 'ensureArray' | 'ensureObject' | 'withDefault' | 'derived'>, FormCommon {
18
+ /** Ensure the value is an array. */
19
+ ensureArray(): NonNullable<T> extends (infer U)[] ? FormArrayState<U> : never;
20
+ /** Ensure the value is an object. */
21
+ ensureObject(): NonNullable<T> extends FieldValues ? FormObjectState<NonNullable<T>> : never;
17
22
  /** Return a new state with a default value, and make the type non-nullable */
18
23
  withDefault(defaultValue: T): FormState<NonNullable<T>>;
19
24
  /** Virtual state derived from the current value.
@@ -30,10 +35,17 @@ interface FormValueState<T> extends Omit<ValueState<T>, 'withDefault' | 'derived
30
35
  */
31
36
  derived: <R>({ from, to }: DerivedStateProps<T, R>) => FormState<R>;
32
37
  }
33
- type FormArrayState<T, Nullable extends boolean = false, TT = MaybeNullable<T, Nullable>> = IsEqual<T, unknown> extends true ? never : FormValueState<TT[]> & ArrayProxy<TT, FormState<TT>>;
34
- type FormObjectState<T extends FieldValues, Nullable extends boolean = false> = {
38
+ type FormObjectProxy<T extends FieldValues> = {
39
+ /** Virtual state for the object's keys.
40
+ *
41
+ * This does NOT read from a real `keys` property on the stored object; it results in a stable array of keys.
42
+ */
43
+ readonly keys: FormReadOnlyState<FieldPath<T>[]>;
44
+ } & {
35
45
  [K in keyof T]-?: FormState<T[K]>;
36
- } & FormValueState<MaybeNullable<T, Nullable>> & ObjectMutationMethods;
46
+ };
47
+ type FormArrayState<T, Nullable extends boolean = false> = IsEqual<T, unknown> extends true ? never : FormValueState<MaybeNullable<T[], Nullable>> & ArrayProxy<T, FormState<T>>;
48
+ type FormObjectState<T extends FieldValues, Nullable extends boolean = false> = FormObjectProxy<T> & FormValueState<MaybeNullable<T, Nullable>> & ObjectMutationMethods;
37
49
  /** Type for nested objects with proxy methods */
38
50
  type DeepNonNullable<T> = [NonNullable<T>] extends [readonly (infer U)[]] ? U[] : [NonNullable<T>] extends [FieldValues] ? {
39
51
  [K in keyof NonNullable<T>]-?: DeepNonNullable<NonNullable<T>[K]>;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { createAtom, type Atom } from './atom';
2
2
  export type * from './form';
3
3
  export { useForm } from './form';
4
+ export { isEqual } from './impl';
4
5
  export { createMemoryStore, useMemoryStore, type MemoryStore } from './memory';
5
6
  export { createMixedState } from './mixed_state';
6
7
  export type * from './path';
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export { createAtom } from './atom';
2
2
  export { useForm } from './form';
3
+ export { isEqual } from './impl';
3
4
  export { createMemoryStore, useMemoryStore } from './memory';
4
5
  export { createMixedState } from './mixed_state';
5
6
  export { createStore } from './store';
@@ -1,3 +1,5 @@
1
+ import { useCallback, useEffect, useState } from 'react';
2
+ import { isEqual } from './impl';
1
3
  export { createMixedState };
2
4
  /**
3
5
  * Creates a mixed state that combines multiple states into a tuple.
@@ -22,7 +24,19 @@ function createMixedState(...states) {
22
24
  },
23
25
  use,
24
26
  useCompute(fn) {
25
- return states.map(state => state.useCompute(value => fn(value)));
27
+ const [value, setValue] = useState(fn(this.value));
28
+ const recompute = useCallback(() => {
29
+ const newValue = fn(this.value);
30
+ // skip update if the new value is the same as the previous value
31
+ setValue(prev => (isEqual(prev, newValue) ? prev : newValue));
32
+ }, [fn]);
33
+ useEffect(() => {
34
+ const unsubscribeFns = states.map(state => state.subscribe(recompute));
35
+ return () => {
36
+ unsubscribeFns.forEach(unsubscribe => unsubscribe());
37
+ };
38
+ });
39
+ return value;
26
40
  },
27
41
  Render({ children }) {
28
42
  const value = use();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juststore",
3
- "version": "0.4.2",
3
+ "version": "0.4.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",