muya 1.0.1 → 1.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/src/create.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import { createEmitter } from './create-emitter'
2
2
  import type { SetValue, SetterState, StateDataInternal, DefaultValue, GetterState, IsEqual, UpdateValue } from './types'
3
3
  import { getDefaultValue } from './types'
4
- import { isEqualBase, isObject, isPromise, isSetValueFunction } from './is'
4
+ import { isAbortError, isEqualBase, isObject, isPromise, isSetValueFunction } from './is'
5
5
  import { createBaseState } from './create-base-state'
6
6
  import { createGetterState } from './create-getter-state'
7
+ import { cancelablePromise } from './common'
7
8
 
8
9
  /**
9
10
  * Creates a basic atom state.
@@ -44,19 +45,34 @@ export function create<T>(defaultValue: DefaultValue<T>, isEqual: IsEqual<T> = i
44
45
  }
45
46
  return stateData.value
46
47
  }
48
+
47
49
  function get(): T {
48
50
  const stateValue = getValue()
49
51
  if (isPromise(stateValue)) {
50
- stateValue.then((data) => {
51
- stateData.value = data as Awaited<T>
52
- emitter.emit()
53
- })
52
+ const { controller, promise } = cancelablePromise(stateValue, stateData.abortController)
53
+ stateData.abortController = controller
54
+ promise
55
+ .then((data) => {
56
+ stateData.value = data as Awaited<T>
57
+ emitter.emit()
58
+ })
59
+ .catch((error) => {
60
+ if (isAbortError(error)) {
61
+ return
62
+ }
63
+ stateData.value = new Error(error) as T
64
+ })
54
65
  }
55
66
  return stateValue
56
67
  }
57
68
 
58
69
  function set(stateValue: SetValue<T>) {
59
70
  const stateValueData = getValue()
71
+ if (stateData.abortController) {
72
+ stateData.abortController.abort()
73
+ stateData.abortController = undefined
74
+ }
75
+
60
76
  const newState = resolveSetter(stateValueData, stateValue)
61
77
  const isEqualResult = isEqual?.(stateValueData, newState)
62
78
  if (isEqualResult || newState === stateValueData) {
@@ -85,9 +101,18 @@ export function create<T>(defaultValue: DefaultValue<T>, isEqual: IsEqual<T> = i
85
101
  reset() {
86
102
  const value = getDefaultValue(defaultValue)
87
103
  if (isPromise(value)) {
88
- value.then((data) => {
89
- set(data as T)
90
- })
104
+ const { controller, promise } = cancelablePromise(value, stateData.abortController)
105
+ stateData.abortController = controller
106
+ promise
107
+ .then((data) => {
108
+ set(data as T)
109
+ })
110
+ .catch((error) => {
111
+ if (isAbortError(error)) {
112
+ return
113
+ }
114
+ stateData.value = new Error(error) as T
115
+ })
91
116
  return
92
117
  }
93
118
  set(value)
package/src/is.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { Abort } from './common'
1
2
  import type { Ref, Setter, SetValue } from './types'
2
3
 
3
4
  export function isPromise(value: unknown): value is Promise<unknown> {
@@ -34,3 +35,11 @@ export function isEqualBase<T>(valueA: T, valueB: T): boolean {
34
35
  }
35
36
  return !!Object.is(valueA, valueB)
36
37
  }
38
+
39
+ export function isAbortError(value: unknown): value is DOMException {
40
+ return value instanceof DOMException && value.name === Abort.Error
41
+ }
42
+
43
+ export function isAnyOtherError(value: unknown): value is Error {
44
+ return value instanceof Error && value.name !== Abort.Error
45
+ }
package/src/merge.ts CHANGED
@@ -4,35 +4,32 @@ import { createGetterState } from './create-getter-state'
4
4
  import { isEqualBase } from './is'
5
5
  import type { IsEqual, GetterState } from './types'
6
6
 
7
- export function merge<T1, T2, S>(
8
- state1: GetterState<T1>,
9
- state2: GetterState<T2>,
10
- selector: (value1: T1, value2: T2) => S,
7
+ export function merge<T extends unknown[], S>(
8
+ states: { [K in keyof T]: GetterState<T[K]> },
9
+ selector: (...values: T) => S,
11
10
  isEqual: IsEqual<S> = isEqualBase,
12
11
  ): GetterState<S> {
13
12
  let previousData: S | undefined
14
13
  const emitter = createEmitter(() => {
15
- const data = selector(state1.getState(), state2.getState())
14
+ const data = selector(...(states.map((state) => state.getState()) as T))
16
15
  if (previousData !== undefined && isEqual(previousData, data)) {
17
16
  return previousData
18
17
  }
19
18
  previousData = data
20
19
  return data
21
20
  })
22
- state1.__internal.emitter.subscribe(() => {
23
- emitter.emit()
24
- })
25
- state2.__internal.emitter.subscribe(() => {
26
- emitter.emit()
27
- })
21
+ for (const state of states) {
22
+ state.__internal.emitter.subscribe(() => {
23
+ emitter.emit()
24
+ })
25
+ }
28
26
 
29
27
  const baseState = createBaseState<S>({
30
28
  emitter,
31
29
  getGetterState: () => getterState,
32
- getState: () => selector(state1.getState(), state2.getState()),
30
+ getState: () => selector(...(states.map((state) => state.getState()) as T)),
33
31
  reset() {
34
- state1.reset()
35
- state2.reset()
32
+ for (const state of states) state.reset()
36
33
  },
37
34
  })
38
35
 
package/src/shallow.ts CHANGED
@@ -5,9 +5,6 @@ export function shallow<T>(valueA: T, valueB: T): boolean {
5
5
  if (valueA == valueB) {
6
6
  return true
7
7
  }
8
- if (Object.is(valueA, valueB)) {
9
- return true
10
- }
11
8
 
12
9
  if (typeof valueA !== 'object' || valueA == null || typeof valueB !== 'object' || valueB == null) {
13
10
  return false
package/src/types.ts CHANGED
@@ -27,6 +27,7 @@ export type GetState<T> = () => T
27
27
  export interface StateDataInternal<T = unknown> {
28
28
  value?: T
29
29
  updateVersion: number
30
+ abortController?: AbortController
30
31
  }
31
32
 
32
33
  // eslint-disable-next-line no-shadow
@@ -46,7 +47,6 @@ export interface BaseState<T> {
46
47
  getState: GetState<T>
47
48
 
48
49
  select: <S>(selector: (value: T) => S, isEqual?: IsEqual<S>) => GetterState<S>
49
- merge: <T2, S>(state2: GetterState<T2>, selector: (value1: T, value2: T2) => S, isEqual?: IsEqual<S>) => GetterState<S>
50
50
 
51
51
  /**
52
52
  * Internal state data
@@ -1,6 +1,6 @@
1
1
  import type { IsEqual, State } from './types'
2
2
  import { useSyncExternalStore, toType } from './common'
3
- import { isPromise } from './is'
3
+ import { isAnyOtherError, isPromise } from './is'
4
4
 
5
5
  /**
6
6
  * useCachedStateValue Hook.
@@ -25,5 +25,8 @@ export function useStateValue<T, S>(
25
25
  if (isPromise(data)) {
26
26
  throw data
27
27
  }
28
+ if (isAnyOtherError(data)) {
29
+ throw data
30
+ }
28
31
  return data
29
32
  }
@@ -0,0 +1,20 @@
1
+ import { Component } from 'react';
2
+ export declare function longPromise(time?: number): Promise<number>;
3
+ export declare class ErrorBoundary extends Component<{
4
+ fallback: React.ReactNode;
5
+ children: React.ReactNode;
6
+ }, {
7
+ hasError: boolean;
8
+ error: Error | null;
9
+ }> {
10
+ constructor(props: {
11
+ fallback: React.ReactNode;
12
+ children: React.ReactNode;
13
+ });
14
+ static getDerivedStateFromError(error: Error): {
15
+ hasError: boolean;
16
+ error: Error;
17
+ };
18
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void;
19
+ render(): import("react").ReactNode;
20
+ }
package/types/common.d.ts CHANGED
@@ -5,3 +5,13 @@ import type { IsEqual } from './types';
5
5
  */
6
6
  export declare function toType<T>(object?: unknown): T;
7
7
  export declare function useSyncExternalStore<T, S>(emitter: Emitter<T>, selector: (stateValue: T) => S, isEqual?: IsEqual<S>): undefined extends S ? T : S;
8
+ export declare enum Abort {
9
+ Error = "StateAbortError"
10
+ }
11
+ /**
12
+ * Cancelable promise function, return promise and controller
13
+ */
14
+ export declare function cancelablePromise<T>(promise: Promise<T>, previousController?: AbortController): {
15
+ promise: Promise<T>;
16
+ controller: AbortController;
17
+ };
package/types/is.d.ts CHANGED
@@ -8,3 +8,5 @@ export declare function isMap(value: unknown): value is Map<unknown, unknown>;
8
8
  export declare function isSet(value: unknown): value is Set<unknown>;
9
9
  export declare function isArray(value: unknown): value is Array<unknown>;
10
10
  export declare function isEqualBase<T>(valueA: T, valueB: T): boolean;
11
+ export declare function isAbortError(value: unknown): value is DOMException;
12
+ export declare function isAnyOtherError(value: unknown): value is Error;
package/types/merge.d.ts CHANGED
@@ -1,2 +1,4 @@
1
1
  import type { IsEqual, GetterState } from './types';
2
- export declare function merge<T1, T2, S>(state1: GetterState<T1>, state2: GetterState<T2>, selector: (value1: T1, value2: T2) => S, isEqual?: IsEqual<S>): GetterState<S>;
2
+ export declare function merge<T extends unknown[], S>(states: {
3
+ [K in keyof T]: GetterState<T[K]>;
4
+ }, selector: (...values: T) => S, isEqual?: IsEqual<S>): GetterState<S>;
package/types/types.d.ts CHANGED
@@ -22,6 +22,7 @@ export type GetState<T> = () => T;
22
22
  export interface StateDataInternal<T = unknown> {
23
23
  value?: T;
24
24
  updateVersion: number;
25
+ abortController?: AbortController;
25
26
  }
26
27
  export declare enum StateKeys {
27
28
  IS_STATE = "isState",
@@ -37,7 +38,6 @@ export interface BaseState<T> {
37
38
  */
38
39
  getState: GetState<T>;
39
40
  select: <S>(selector: (value: T) => S, isEqual?: IsEqual<S>) => GetterState<S>;
40
- merge: <T2, S>(state2: GetterState<T2>, selector: (value1: T, value2: T2) => S, isEqual?: IsEqual<S>) => GetterState<S>;
41
41
  /**
42
42
  * Internal state data
43
43
  */