muya 1.0.3 → 2.0.0-beta.1

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.
Files changed (89) hide show
  1. package/README.md +194 -216
  2. package/cjs/index.js +1 -1
  3. package/esm/__tests__/create-async.test.js +1 -0
  4. package/esm/create.js +1 -1
  5. package/esm/index.js +1 -1
  6. package/esm/subscriber.js +1 -0
  7. package/esm/types.js +1 -1
  8. package/esm/use.js +1 -0
  9. package/esm/utils/__tests__/context.test.js +1 -0
  10. package/esm/utils/__tests__/is.test.js +1 -0
  11. package/esm/utils/__tests__/sub-memo.test.js +1 -0
  12. package/esm/utils/common.js +1 -0
  13. package/esm/utils/create-context.js +1 -0
  14. package/esm/utils/create-emitter.js +1 -0
  15. package/esm/utils/is.js +1 -0
  16. package/esm/utils/scheduler.js +1 -0
  17. package/esm/utils/shallow.js +1 -0
  18. package/esm/utils/sub-memo.js +1 -0
  19. package/package.json +1 -4
  20. package/packages/core/__tests__/bench.test.tsx +261 -0
  21. package/packages/core/__tests__/create-async.test.ts +88 -0
  22. package/packages/core/__tests__/create.test.tsx +107 -0
  23. package/packages/core/__tests__/use-async.test.tsx +44 -0
  24. package/packages/core/__tests__/use.test.tsx +76 -0
  25. package/packages/core/create.ts +67 -0
  26. package/packages/core/index.ts +4 -0
  27. package/packages/core/subscriber.ts +121 -0
  28. package/packages/core/types.ts +15 -0
  29. package/packages/core/use.ts +59 -0
  30. package/packages/core/utils/__tests__/context.test.ts +198 -0
  31. package/{src → packages/core/utils}/__tests__/is.test.ts +1 -30
  32. package/packages/core/utils/__tests__/sub-memo.test.ts +13 -0
  33. package/packages/core/utils/common.ts +48 -0
  34. package/packages/core/utils/create-context.ts +60 -0
  35. package/packages/core/utils/create-emitter.ts +53 -0
  36. package/{src → packages/core/utils}/is.ts +11 -13
  37. package/packages/core/utils/scheduler.ts +59 -0
  38. package/{src → packages/core/utils}/shallow.ts +3 -3
  39. package/packages/core/utils/sub-memo.ts +37 -0
  40. package/types/create.d.ts +14 -21
  41. package/types/index.d.ts +2 -4
  42. package/types/subscriber.d.ts +25 -0
  43. package/types/types.d.ts +9 -65
  44. package/types/use.d.ts +2 -0
  45. package/types/utils/common.d.ts +15 -0
  46. package/types/utils/create-context.d.ts +5 -0
  47. package/types/utils/create-emitter.d.ts +20 -0
  48. package/types/{is.d.ts → utils/is.d.ts} +5 -6
  49. package/types/utils/scheduler.d.ts +6 -0
  50. package/types/utils/sub-memo.d.ts +6 -0
  51. package/esm/__tests__/common.test.js +0 -1
  52. package/esm/__tests__/is.test.js +0 -1
  53. package/esm/__tests__/merge.test.js +0 -1
  54. package/esm/__tests__/types.test.js +0 -1
  55. package/esm/common.js +0 -1
  56. package/esm/create-base-state.js +0 -1
  57. package/esm/create-emitter.js +0 -1
  58. package/esm/create-getter-state.js +0 -1
  59. package/esm/is.js +0 -1
  60. package/esm/merge.js +0 -1
  61. package/esm/select.js +0 -1
  62. package/esm/shallow.js +0 -1
  63. package/esm/use-state-value.js +0 -1
  64. package/src/__tests__/common.test.ts +0 -63
  65. package/src/__tests__/create.test.tsx +0 -84
  66. package/src/__tests__/merge.test.ts +0 -78
  67. package/src/__tests__/state.test.tsx +0 -619
  68. package/src/__tests__/types.test.ts +0 -17
  69. package/src/common.ts +0 -60
  70. package/src/create-base-state.ts +0 -31
  71. package/src/create-emitter.ts +0 -24
  72. package/src/create-getter-state.ts +0 -18
  73. package/src/create.ts +0 -127
  74. package/src/index.ts +0 -6
  75. package/src/merge.ts +0 -38
  76. package/src/select.ts +0 -33
  77. package/src/types.ts +0 -94
  78. package/src/use-state-value.ts +0 -32
  79. package/types/common.d.ts +0 -17
  80. package/types/create-base-state.d.ts +0 -10
  81. package/types/create-emitter.d.ts +0 -7
  82. package/types/create-getter-state.d.ts +0 -6
  83. package/types/merge.d.ts +0 -4
  84. package/types/select.d.ts +0 -2
  85. package/types/use-state-value.d.ts +0 -10
  86. /package/esm/{__tests__ → utils/__tests__}/shallow.test.js +0 -0
  87. /package/{src → packages/core}/__tests__/test-utils.ts +0 -0
  88. /package/{src → packages/core/utils}/__tests__/shallow.test.ts +0 -0
  89. /package/types/{shallow.d.ts → utils/shallow.d.ts} +0 -0
@@ -1,31 +0,0 @@
1
- import type { Emitter } from './create-emitter'
2
- import { select } from './select'
3
- import type { BaseState, GetterState } from './types'
4
-
5
- interface Options<T> {
6
- readonly emitter: Emitter<T>
7
- readonly reset: () => void
8
- readonly getState: () => T
9
- readonly getGetterState: () => GetterState<T>
10
- }
11
- export function createBaseState<T>(options: Options<T>): BaseState<T> {
12
- const { emitter, getGetterState, reset, getState } = options
13
- return {
14
- getState,
15
- reset,
16
- select(selector, isSame) {
17
- const state = getGetterState()
18
- return select(state, selector, isSame)
19
- },
20
-
21
- __internal: {
22
- emitter,
23
- },
24
- subscribe(listener) {
25
- listener(getState())
26
- return emitter.subscribe(() => {
27
- listener(getState())
28
- })
29
- },
30
- }
31
- }
@@ -1,24 +0,0 @@
1
- export type EmitterSubscribe<P = undefined> = (listener: (...params: P[]) => void) => () => void
2
- export interface Emitter<T, R = T, P = undefined> {
3
- subscribe: EmitterSubscribe<P>
4
- getSnapshot: () => R
5
- emit: (...params: P[]) => void
6
- }
7
-
8
- export function createEmitter<T, R = T, P = undefined>(getSnapshot: () => R): Emitter<T, R, P> {
9
- const listeners = new Set<(...params: P[]) => void>()
10
- return {
11
- subscribe: (listener) => {
12
- listeners.add(listener)
13
- return () => {
14
- listeners.delete(listener)
15
- }
16
- },
17
- emit: (...params) => {
18
- for (const listener of listeners) {
19
- listener(...params)
20
- }
21
- },
22
- getSnapshot,
23
- }
24
- }
@@ -1,18 +0,0 @@
1
- import type { BaseState, GetterState } from './types'
2
- import { useStateValue } from './use-state-value'
3
-
4
- interface Options<T> {
5
- readonly baseState: BaseState<T>
6
- }
7
- export function createGetterState<T>(options: Options<T>): GetterState<T> {
8
- const { baseState } = options
9
- const useSliceState: GetterState<T> = (useSelector, isEqualHook) => {
10
- return useStateValue(useSliceState, useSelector, isEqualHook)
11
- }
12
- useSliceState.__internal = baseState.__internal
13
- useSliceState.getState = baseState.getState
14
- useSliceState.reset = baseState.reset
15
- useSliceState.select = baseState.select
16
- useSliceState.subscribe = baseState.subscribe
17
- return useSliceState
18
- }
package/src/create.ts DELETED
@@ -1,127 +0,0 @@
1
- import { createEmitter } from './create-emitter'
2
- import type { SetValue, SetterState, StateDataInternal, DefaultValue, GetterState, IsEqual, UpdateValue } from './types'
3
- import { getDefaultValue } from './types'
4
- import { isAbortError, isEqualBase, isObject, isPromise, isSetValueFunction } from './is'
5
- import { createBaseState } from './create-base-state'
6
- import { createGetterState } from './create-getter-state'
7
- import { cancelablePromise } from './common'
8
-
9
- /**
10
- * Creates a basic atom state.
11
- * @param defaultValue - The initial state value.
12
- * @param options - Optional settings for the state (e.g., isEqual, onSet).
13
- * @returns A state object that can be used as a hook and provides state management methods.
14
- * @example
15
- * ```typescript
16
- * // Global scope
17
- * const counterState = state(0);
18
- * const userState = state({ name: 'John', age: 20 });
19
- *
20
- * // React component
21
- * const counter = counterState(); // Use as a hook
22
- * const user = userState();
23
- *
24
- * // Access partial data from the state using slice
25
- * const userAge = userState.slice((state) => state.age)();
26
- * ```
27
- */
28
-
29
- export function create<T>(defaultValue: DefaultValue<T>, isEqual: IsEqual<T> = isEqualBase): SetterState<Awaited<T>> {
30
- function resolveSetter(value: T, stateSetter: SetValue<T>): T {
31
- if (isSetValueFunction(stateSetter)) {
32
- return stateSetter(value)
33
- }
34
- return stateSetter
35
- }
36
-
37
- const stateData: StateDataInternal<T> = {
38
- updateVersion: 0,
39
- value: undefined,
40
- }
41
-
42
- function getValue(): T {
43
- if (stateData.value === undefined) {
44
- stateData.value = getDefaultValue(defaultValue)
45
- }
46
- return stateData.value
47
- }
48
-
49
- function get(): T {
50
- const stateValue = getValue()
51
- if (isPromise(stateValue)) {
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
- })
65
- }
66
- return stateValue
67
- }
68
-
69
- function set(stateValue: SetValue<T>) {
70
- const stateValueData = getValue()
71
- if (stateData.abortController) {
72
- stateData.abortController.abort()
73
- stateData.abortController = undefined
74
- }
75
-
76
- const newState = resolveSetter(stateValueData, stateValue)
77
- const isEqualResult = isEqual?.(stateValueData, newState)
78
- if (isEqualResult || newState === stateValueData) {
79
- return
80
- }
81
- stateData.updateVersion++
82
- stateData.value = newState
83
- emitter.emit()
84
- }
85
-
86
- function update(stateValue: UpdateValue<T>) {
87
- if (isObject(stateValue)) {
88
- return set((previousState) => {
89
- return { ...previousState, ...stateValue }
90
- })
91
- }
92
- set(stateValue as T)
93
- }
94
-
95
- const emitter = createEmitter<T>(get)
96
-
97
- const baseState = createBaseState({
98
- emitter,
99
- getGetterState: () => setterState,
100
- getState: get,
101
- reset() {
102
- const value = getDefaultValue(defaultValue)
103
- if (isPromise(value)) {
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
- })
116
- return
117
- }
118
- set(value)
119
- },
120
- })
121
-
122
- const getterState: GetterState<T> = createGetterState<T>({ baseState })
123
- const setterState: SetterState<T> = getterState as SetterState<T>
124
- setterState.setState = set
125
- setterState.updateState = update
126
- return setterState as SetterState<Awaited<T>>
127
- }
package/src/index.ts DELETED
@@ -1,6 +0,0 @@
1
- export * from './types'
2
- export { create } from './create'
3
- export { select } from './select'
4
- export { merge } from './merge'
5
- export { useStateValue } from './use-state-value'
6
- export { shallow } from './shallow'
package/src/merge.ts DELETED
@@ -1,38 +0,0 @@
1
- import { createBaseState } from './create-base-state'
2
- import { createEmitter } from './create-emitter'
3
- import { createGetterState } from './create-getter-state'
4
- import { isEqualBase } from './is'
5
- import type { IsEqual, GetterState } from './types'
6
-
7
- export function merge<T extends unknown[], S>(
8
- states: { [K in keyof T]: GetterState<T[K]> },
9
- selector: (...values: T) => S,
10
- isEqual: IsEqual<S> = isEqualBase,
11
- ): GetterState<S> {
12
- let previousData: S | undefined
13
- const emitter = createEmitter(() => {
14
- const data = selector(...(states.map((state) => state.getState()) as T))
15
- if (previousData !== undefined && isEqual(previousData, data)) {
16
- return previousData
17
- }
18
- previousData = data
19
- return data
20
- })
21
- for (const state of states) {
22
- state.__internal.emitter.subscribe(() => {
23
- emitter.emit()
24
- })
25
- }
26
-
27
- const baseState = createBaseState<S>({
28
- emitter,
29
- getGetterState: () => getterState,
30
- getState: () => selector(...(states.map((state) => state.getState()) as T)),
31
- reset() {
32
- for (const state of states) state.reset()
33
- },
34
- })
35
-
36
- const getterState: GetterState<S> = createGetterState<S>({ baseState })
37
- return getterState
38
- }
package/src/select.ts DELETED
@@ -1,33 +0,0 @@
1
- import { createBaseState } from './create-base-state'
2
- import { createEmitter } from './create-emitter'
3
- import { createGetterState } from './create-getter-state'
4
- import { isEqualBase } from './is'
5
- import type { IsEqual, GetterState } from './types'
6
-
7
- export function select<T, S>(
8
- state: GetterState<T>,
9
- selector: (value: T) => S,
10
- isEqual: IsEqual<S> = isEqualBase,
11
- ): GetterState<S> {
12
- let previousData: S | undefined
13
- const emitter = createEmitter(() => {
14
- const data = selector(state.getState())
15
- if (previousData !== undefined && isEqual(previousData, data)) {
16
- return previousData
17
- }
18
- previousData = data
19
- return data
20
- })
21
- state.__internal.emitter.subscribe(() => {
22
- emitter.emit()
23
- })
24
-
25
- const baseState = createBaseState<S>({
26
- emitter,
27
- getGetterState: () => getterState,
28
- getState: () => selector(state.getState()),
29
- reset: state.reset,
30
- })
31
- const getterState: GetterState<S> = createGetterState<S>({ baseState })
32
- return getterState
33
- }
package/src/types.ts DELETED
@@ -1,94 +0,0 @@
1
- import type { Emitter } from './create-emitter'
2
- import { isFunction, isPromise } from './is'
3
-
4
- /**
5
- * Equality check function.
6
- */
7
- export type IsEqual<T = unknown> = (a: T, b: T) => boolean
8
-
9
- export type Setter<T> = (value: T) => T
10
- /**
11
- * Set new state value function.
12
- */
13
- export type SetValue<T> = T | Setter<T>
14
- export type UpdateValue<T> = T extends object ? Partial<T> : T
15
-
16
- /**
17
- * Set new state function
18
- */
19
- export type StateValue<T, S> = undefined extends S ? T : S
20
- export type Set<T> = (value: SetValue<T>) => void
21
- export type Update<T> = (value: UpdateValue<T>) => void
22
-
23
- /**
24
- * Getting state value function.
25
- */
26
- export type GetState<T> = () => T
27
- export interface StateDataInternal<T = unknown> {
28
- value?: T
29
- updateVersion: number
30
- abortController?: AbortController
31
- }
32
-
33
- // eslint-disable-next-line no-shadow
34
- export enum StateKeys {
35
- IS_STATE = 'isState',
36
- IS_SLICE = 'isSlice',
37
- }
38
-
39
- export interface BaseState<T> {
40
- /**
41
- * Reset state to default value if it's basic atom - if it's family - it will clear all family members
42
- */
43
- reset: () => void
44
- /**
45
- * Get current state value
46
- */
47
- getState: GetState<T>
48
-
49
- select: <S>(selector: (value: T) => S, isEqual?: IsEqual<S>) => GetterState<S>
50
-
51
- /**
52
- * Internal state data
53
- */
54
- __internal: {
55
- emitter: Emitter<T>
56
- }
57
-
58
- subscribe: (listener: (value: T) => void) => () => void
59
- }
60
-
61
- export interface GetterState<T> extends BaseState<T> {
62
- // use use as the function call here
63
- <S>(selector?: (state: T) => S, isEqual?: IsEqual<S>): StateValue<T, S>
64
- }
65
- export interface SetterState<T> extends GetterState<T> {
66
- /**
67
- * Set new state value
68
- */
69
- setState: Set<T>
70
-
71
- /**
72
- * Set new state value
73
- */
74
- updateState: Update<T>
75
- }
76
-
77
- export type State<T> = SetterState<T> | GetterState<T>
78
-
79
- export type DefaultValue<T> = T | (() => T)
80
-
81
- export function getDefaultValue<T>(initValue: DefaultValue<T>): T {
82
- if (isPromise(initValue)) {
83
- return initValue
84
- }
85
- if (isFunction(initValue)) {
86
- return (initValue as () => T)()
87
- }
88
- return initValue
89
- }
90
-
91
- export interface Ref<T> {
92
- current: T | undefined
93
- readonly isRef: true
94
- }
@@ -1,32 +0,0 @@
1
- import type { IsEqual, State } from './types'
2
- import { useSyncExternalStore, toType } from './common'
3
- import { isAnyOtherError, isPromise } from './is'
4
-
5
- /**
6
- * useCachedStateValue Hook.
7
- * Hook for use state inside react scope. If the state is async - component need to be wrapped with Suspense.
8
- * @param state - state value
9
- * @param selector - selector function (useStateValue(state, (state) => state.value)) - it return only selected value, selector don't need to be memoized.
10
- * @param isEqual - equality check function for selector
11
- * @returns StateValue from selector if provided, otherwise whole state
12
- */
13
- export function useStateValue<T, S>(
14
- state: State<T>,
15
- selector: (stateValue: T) => S = (stateValue) => toType<S>(stateValue),
16
- isEqual?: IsEqual<S>,
17
- ): undefined extends S ? T : S {
18
- const data = useSyncExternalStore(
19
- state.__internal.emitter,
20
- (stateValue) => {
21
- return selector(stateValue)
22
- },
23
- isEqual,
24
- )
25
- if (isPromise(data)) {
26
- throw data
27
- }
28
- if (isAnyOtherError(data)) {
29
- throw data
30
- }
31
- return data
32
- }
package/types/common.d.ts DELETED
@@ -1,17 +0,0 @@
1
- import type { Emitter } from './create-emitter';
2
- import type { IsEqual } from './types';
3
- /**
4
- * Todo need to remove this
5
- */
6
- export declare function toType<T>(object?: unknown): T;
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
- };
@@ -1,10 +0,0 @@
1
- import type { Emitter } from './create-emitter';
2
- import type { BaseState, GetterState } from './types';
3
- interface Options<T> {
4
- readonly emitter: Emitter<T>;
5
- readonly reset: () => void;
6
- readonly getState: () => T;
7
- readonly getGetterState: () => GetterState<T>;
8
- }
9
- export declare function createBaseState<T>(options: Options<T>): BaseState<T>;
10
- export {};
@@ -1,7 +0,0 @@
1
- export type EmitterSubscribe<P = undefined> = (listener: (...params: P[]) => void) => () => void;
2
- export interface Emitter<T, R = T, P = undefined> {
3
- subscribe: EmitterSubscribe<P>;
4
- getSnapshot: () => R;
5
- emit: (...params: P[]) => void;
6
- }
7
- export declare function createEmitter<T, R = T, P = undefined>(getSnapshot: () => R): Emitter<T, R, P>;
@@ -1,6 +0,0 @@
1
- import type { BaseState, GetterState } from './types';
2
- interface Options<T> {
3
- readonly baseState: BaseState<T>;
4
- }
5
- export declare function createGetterState<T>(options: Options<T>): GetterState<T>;
6
- export {};
package/types/merge.d.ts DELETED
@@ -1,4 +0,0 @@
1
- import type { IsEqual, GetterState } from './types';
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/select.d.ts DELETED
@@ -1,2 +0,0 @@
1
- import type { IsEqual, GetterState } from './types';
2
- export declare function select<T, S>(state: GetterState<T>, selector: (value: T) => S, isEqual?: IsEqual<S>): GetterState<S>;
@@ -1,10 +0,0 @@
1
- import type { IsEqual, State } from './types';
2
- /**
3
- * useCachedStateValue Hook.
4
- * Hook for use state inside react scope. If the state is async - component need to be wrapped with Suspense.
5
- * @param state - state value
6
- * @param selector - selector function (useStateValue(state, (state) => state.value)) - it return only selected value, selector don't need to be memoized.
7
- * @param isEqual - equality check function for selector
8
- * @returns StateValue from selector if provided, otherwise whole state
9
- */
10
- export declare function useStateValue<T, S>(state: State<T>, selector?: (stateValue: T) => S, isEqual?: IsEqual<S>): undefined extends S ? T : S;
File without changes
File without changes