@yaasl/core 0.8.0 → 0.9.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.
- package/dist/@types/base/createActions.d.ts +31 -0
- package/dist/@types/base/createAtom.d.ts +42 -0
- package/dist/@types/base/{derive.d.ts → createDerived.d.ts} +4 -4
- package/dist/@types/base/createSelector.d.ts +33 -0
- package/dist/@types/base/index.d.ts +3 -3
- package/dist/@types/effects/EffectDispatcher.d.ts +15 -0
- package/dist/@types/effects/createEffect.d.ts +39 -0
- package/dist/@types/{middleware → effects}/expiration.d.ts +3 -3
- package/dist/@types/{middleware → effects}/index.d.ts +2 -2
- package/dist/@types/{middleware → effects}/indexedDb.d.ts +2 -2
- package/dist/@types/{middleware → effects}/localStorage.d.ts +2 -2
- package/dist/@types/{middleware → effects}/migration.d.ts +19 -3
- package/dist/@types/index.d.ts +1 -1
- package/dist/cjs/base/createActions.js +28 -0
- package/dist/cjs/base/createAtom.js +48 -0
- package/dist/cjs/base/{derive.js → createDerived.js} +3 -3
- package/dist/cjs/base/createSelector.js +46 -0
- package/dist/cjs/base/index.js +3 -3
- package/dist/cjs/{middleware/MiddlewareDispatcher.js → effects/EffectDispatcher.js} +11 -11
- package/dist/cjs/effects/createEffect.js +27 -0
- package/dist/cjs/{middleware → effects}/expiration.js +4 -4
- package/dist/cjs/{middleware → effects}/index.js +3 -3
- package/dist/cjs/{middleware → effects}/indexedDb.js +3 -3
- package/dist/cjs/{middleware → effects}/localStorage.js +3 -3
- package/dist/cjs/{middleware → effects}/migration.js +18 -2
- package/dist/cjs/index.js +1 -1
- package/dist/mjs/base/createActions.js +24 -0
- package/dist/mjs/base/createAtom.js +43 -0
- package/dist/mjs/base/{derive.js → createDerived.js} +1 -1
- package/dist/mjs/base/createSelector.js +40 -0
- package/dist/mjs/base/index.js +3 -3
- package/dist/mjs/{middleware/MiddlewareDispatcher.js → effects/EffectDispatcher.js} +9 -9
- package/dist/mjs/effects/createEffect.js +23 -0
- package/dist/mjs/{middleware → effects}/expiration.js +4 -4
- package/dist/mjs/{middleware → effects}/index.js +1 -1
- package/dist/mjs/{middleware → effects}/indexedDb.js +3 -3
- package/dist/mjs/{middleware → effects}/localStorage.js +3 -3
- package/dist/mjs/{middleware → effects}/migration.js +18 -2
- package/dist/mjs/index.js +1 -1
- package/package.json +2 -2
- package/dist/@types/base/atom.d.ts +0 -33
- package/dist/@types/base/select.d.ts +0 -20
- package/dist/@types/middleware/MiddlewareDispatcher.d.ts +0 -15
- package/dist/@types/middleware/middleware.d.ts +0 -31
- package/dist/cjs/base/atom.js +0 -47
- package/dist/cjs/base/select.js +0 -26
- package/dist/cjs/middleware/middleware.js +0 -19
- package/dist/mjs/base/atom.js +0 -42
- package/dist/mjs/base/select.js +0 -21
- package/dist/mjs/middleware/middleware.js +0 -15
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Atom } from "./createAtom";
|
|
2
|
+
import { SettableDerive } from "./createDerived";
|
|
3
|
+
type Reducer<State> = (state: State, ...payloadArgs: any[]) => State;
|
|
4
|
+
export type Reducers<State> = Record<string, Reducer<State>>;
|
|
5
|
+
type Payload<R extends Reducer<any>> = Parameters<R> extends [
|
|
6
|
+
any,
|
|
7
|
+
...infer PayloadArgs
|
|
8
|
+
] ? PayloadArgs : [];
|
|
9
|
+
export type Actions<State, R extends Reducers<State>> = {
|
|
10
|
+
[K in keyof R]: (...payloadArgs: Payload<R[K]>) => void;
|
|
11
|
+
};
|
|
12
|
+
/** Create actions to change the state of an atom.
|
|
13
|
+
*
|
|
14
|
+
* @param atom Atom to be used.
|
|
15
|
+
* @param reducers Reducers for custom actions to set the atoms value.
|
|
16
|
+
*
|
|
17
|
+
* @returns Actions to change the state of the atom.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* const counter = createAtom({ defaultValue: 0 })
|
|
21
|
+
* const actions = createActions(counter, {
|
|
22
|
+
* increment: (state) => state + 1,
|
|
23
|
+
* decrement: (state) => state - 1,
|
|
24
|
+
* add: (state, value: number) => state + value,
|
|
25
|
+
* subtract: (state, value: number) => state - value,
|
|
26
|
+
* })
|
|
27
|
+
* actions.increment()
|
|
28
|
+
* actions.add(5)
|
|
29
|
+
**/
|
|
30
|
+
export declare const createActions: <State, R extends Reducers<State>>(atom: Atom<State> | SettableDerive<State>, reducers: R) => Actions<State, R>;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { SetStateAction } from "@yaasl/utils";
|
|
2
|
+
import { Actions, Reducers } from "./createActions";
|
|
3
|
+
import { Stateful } from "./Stateful";
|
|
4
|
+
import { EffectAtomCallback } from "../effects/createEffect";
|
|
5
|
+
export interface AtomConfig<Value, R extends Reducers<Value> = Reducers<Value>> {
|
|
6
|
+
/** Value that will be used initially. */
|
|
7
|
+
defaultValue: Value;
|
|
8
|
+
/** Name of the atom. Must be unique among all atoms. Defaults to "atom-{number}". */
|
|
9
|
+
name?: string;
|
|
10
|
+
/** Effects that will be applied on the atom. */
|
|
11
|
+
effects?: EffectAtomCallback<any>[];
|
|
12
|
+
/** Reducers for custom actions to set the atom's value. */
|
|
13
|
+
reducers?: R;
|
|
14
|
+
}
|
|
15
|
+
export declare class Atom<Value = unknown, R extends Reducers<Value> = Reducers<Value>> extends Stateful<Value> {
|
|
16
|
+
readonly defaultValue: Value;
|
|
17
|
+
readonly name: string;
|
|
18
|
+
readonly actions: Actions<Value, R>;
|
|
19
|
+
constructor({ defaultValue, name, effects, reducers, }: AtomConfig<Value, R>);
|
|
20
|
+
/** Set the value of the atom.
|
|
21
|
+
*
|
|
22
|
+
* @param next New value or function to create the
|
|
23
|
+
* new value based off the previous value.
|
|
24
|
+
*/
|
|
25
|
+
set(next: SetStateAction<Value>): void;
|
|
26
|
+
}
|
|
27
|
+
/** Creates an atom store.
|
|
28
|
+
*
|
|
29
|
+
* @param config.defaultValue Value that will be used initially.
|
|
30
|
+
* @param config.name Name of the atom. Must be unique among all atoms. Defaults to "atom-{number}".
|
|
31
|
+
* @param config.effects Effects that will be applied on the atom.
|
|
32
|
+
* @param config.reducers Reducers for custom actions to set the atom's value.
|
|
33
|
+
*
|
|
34
|
+
* @returns An atom instance.
|
|
35
|
+
* - `result.get`: Read the value of state.
|
|
36
|
+
* - `result.subscribe`: Subscribe to value changes.
|
|
37
|
+
* - `result.set`: Set the value of the atom.
|
|
38
|
+
* - `result.actions`: All actions that were created with reducers.
|
|
39
|
+
* - `result.didInit`: State of the atom's effects initialization process.
|
|
40
|
+
* Will be a promise if the initialization is pending and `true` if finished.
|
|
41
|
+
**/
|
|
42
|
+
export declare const createAtom: <Value, R extends Reducers<Value> = Reducers<Value>>(config: AtomConfig<Value, R>) => Atom<Value, R>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SetStateAction } from "@yaasl/utils";
|
|
2
|
-
import { Atom } from "./
|
|
2
|
+
import { Atom } from "./createAtom";
|
|
3
3
|
import { Stateful } from "./Stateful";
|
|
4
4
|
type GetterFn<Value> = (context: {
|
|
5
5
|
get: <V>(dep: Stateful<V>) => V;
|
|
@@ -17,7 +17,7 @@ export declare class Derive<Value> extends Stateful<Value> {
|
|
|
17
17
|
}
|
|
18
18
|
export declare class SettableDerive<Value = unknown> extends Derive<Value> {
|
|
19
19
|
private readonly setter;
|
|
20
|
-
protected readonly setterDependencies: Set<Atom<any
|
|
20
|
+
protected readonly setterDependencies: Set<Atom<any, import("./createActions").Reducers<any>> | SettableDerive<any>>;
|
|
21
21
|
constructor(getter: GetterFn<Value>, setter: SetterFn<Value>);
|
|
22
22
|
/** Set the value of the derived atom.
|
|
23
23
|
*
|
|
@@ -40,6 +40,6 @@ export declare class SettableDerive<Value = unknown> extends Derive<Value> {
|
|
|
40
40
|
*
|
|
41
41
|
* @returns A derive instance.
|
|
42
42
|
**/
|
|
43
|
-
export declare function
|
|
44
|
-
export declare function
|
|
43
|
+
export declare function createDerived<Value>(getter: GetterFn<Value>): Derive<Value>;
|
|
44
|
+
export declare function createDerived<Value>(getter: GetterFn<Value>, setter: SetterFn<Value>): SettableDerive<Value>;
|
|
45
45
|
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Stateful } from "./Stateful";
|
|
2
|
+
type PathableState = Record<string | number, unknown>;
|
|
3
|
+
type DeepKeys<State> = State extends PathableState ? {
|
|
4
|
+
[K in keyof State]: `${Exclude<K, symbol>}${"" | `.${DeepKeys<State[K]>}`}`;
|
|
5
|
+
}[keyof State] : never;
|
|
6
|
+
type DeepValue<State, Path> = State extends PathableState ? Path extends `${infer Current}.${infer Next}` ? DeepValue<State[Current], Next> : State[Path & string] : never;
|
|
7
|
+
export declare class PathSelector<State, Path extends DeepKeys<State>> extends Stateful<DeepValue<State, Path>> {
|
|
8
|
+
constructor(atom: Stateful<State>, path: Path);
|
|
9
|
+
}
|
|
10
|
+
type InferValuesFromAtoms<Atoms extends readonly unknown[], States extends unknown[] = []> = Atoms extends [Stateful<infer Value>, ...infer Rest] ? InferValuesFromAtoms<Rest, [...States, Value]> : States;
|
|
11
|
+
export declare class CombinerSelector<State, Atoms extends [Stateful<any>, ...Stateful<any>[]]> extends Stateful<State> {
|
|
12
|
+
constructor(atoms: Atoms, combiner: (...res: InferValuesFromAtoms<Atoms>) => State);
|
|
13
|
+
}
|
|
14
|
+
interface CreateSelectorOverloads {
|
|
15
|
+
/** Creates a value, selected from one atom with an object value by using a key path.
|
|
16
|
+
*
|
|
17
|
+
* @param atom The atom to select a value from. The internal state must be an object.
|
|
18
|
+
* @param path The path to the value you want to select.
|
|
19
|
+
*
|
|
20
|
+
* @returns A PathSelector instance.
|
|
21
|
+
**/
|
|
22
|
+
<State, Path extends DeepKeys<State>>(atom: Stateful<State>, path: Path): PathSelector<State, Path>;
|
|
23
|
+
/** Creates a value, selected from one atom with an object value by using a key path.
|
|
24
|
+
*
|
|
25
|
+
* @param atoms Atoms you need to combine to receive the new value.
|
|
26
|
+
* @param combiner Combiner function to use the atom values and create a new value.
|
|
27
|
+
*
|
|
28
|
+
* @returns A CombinerSelector instance.
|
|
29
|
+
**/
|
|
30
|
+
<Atoms extends [Stateful<any>, ...Stateful<any>[]], CombinedState>(states: Atoms, combiner: (...res: InferValuesFromAtoms<Atoms>) => CombinedState): CombinerSelector<CombinedState, Atoms>;
|
|
31
|
+
}
|
|
32
|
+
export declare const createSelector: CreateSelectorOverloads;
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { EffectAtomCallback } from "./createEffect";
|
|
2
|
+
import { Atom } from "../base/createAtom";
|
|
3
|
+
interface EffectDispatcherConstructor {
|
|
4
|
+
atom: Atom<any>;
|
|
5
|
+
effects: EffectAtomCallback<any>[];
|
|
6
|
+
}
|
|
7
|
+
export declare class EffectDispatcher {
|
|
8
|
+
didInit: PromiseLike<void> | boolean;
|
|
9
|
+
private effects;
|
|
10
|
+
private scheduler;
|
|
11
|
+
constructor({ atom, effects }: EffectDispatcherConstructor);
|
|
12
|
+
private subscribeSetters;
|
|
13
|
+
private callEffectAction;
|
|
14
|
+
}
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Atom } from "../base";
|
|
2
|
+
export type ActionType = "init" | "didInit" | "set";
|
|
3
|
+
interface EffectPayload<Options, AtomValue> {
|
|
4
|
+
value: AtomValue;
|
|
5
|
+
atom: Atom<AtomValue>;
|
|
6
|
+
options: Options;
|
|
7
|
+
}
|
|
8
|
+
interface EffectActions<Options, AtomValue> {
|
|
9
|
+
init?: (payload: EffectPayload<Options, AtomValue>) => Promise<any> | void;
|
|
10
|
+
didInit?: (payload: EffectPayload<Options, AtomValue>) => Promise<any> | void;
|
|
11
|
+
set?: (payload: EffectPayload<Options, AtomValue>) => void;
|
|
12
|
+
}
|
|
13
|
+
interface EffectSetupProps<Options, AtomValue> {
|
|
14
|
+
atom: Atom<AtomValue>;
|
|
15
|
+
options: Options;
|
|
16
|
+
}
|
|
17
|
+
export type EffectAtomCallback<Options = unknown, AtomValue = unknown> = (atom: Atom<AtomValue>) => Effect<Options, AtomValue>;
|
|
18
|
+
type EffectSetup<Options, AtomValue> = EffectActions<Options, AtomValue> | ((props: EffectSetupProps<Options, AtomValue>) => EffectActions<Options, AtomValue>);
|
|
19
|
+
export interface Effect<Options = unknown, AtomValue = unknown> {
|
|
20
|
+
options: Options;
|
|
21
|
+
actions: EffectActions<Options, AtomValue>;
|
|
22
|
+
}
|
|
23
|
+
/** Create effects to be used in combination with atoms.
|
|
24
|
+
*
|
|
25
|
+
* Effects can be used to interact with an atom by using the following lifecycle actions:
|
|
26
|
+
*
|
|
27
|
+
* - `init`: Action to be called when the atom is created, but before subscribing to `set` events.
|
|
28
|
+
* May return a promise that can be awaited by using `atom.didInit`.
|
|
29
|
+
* - `didInit`: Action to be called when the atom is created, but after subscribing to `set` events.
|
|
30
|
+
* May return a promise that can be awaited by using `atom.didInit`.
|
|
31
|
+
* - `set`: Action to be called when the atom's `set` function is called.
|
|
32
|
+
*
|
|
33
|
+
* @param setup Effect actions or function to create effect actions.
|
|
34
|
+
* Effect actions are fired in the atom lifecycle, alongside to the subscriptions.
|
|
35
|
+
*
|
|
36
|
+
* @returns The effect to be used on atoms.
|
|
37
|
+
**/
|
|
38
|
+
export declare const createEffect: <Options = undefined, AtomValue = any>(setup: EffectSetup<Options, AtomValue>) => (...[optionsArg]: Options extends undefined ? [Options] | [] : [Options]) => EffectAtomCallback<Options, AtomValue>;
|
|
39
|
+
export {};
|
|
@@ -4,7 +4,7 @@ export interface ExpirationOptions {
|
|
|
4
4
|
/** Milliseconds in which the value expires. Will be ignored if expiresAt is set. */
|
|
5
5
|
expiresIn?: number | (() => number);
|
|
6
6
|
}
|
|
7
|
-
/**
|
|
7
|
+
/** Effect to make an atom value expirable and reset to its defaulValue.
|
|
8
8
|
*
|
|
9
9
|
* __Note:__ When using `expiresAt`, a function returning the date should be prefered since using a static date might end in an infinite loop.
|
|
10
10
|
*
|
|
@@ -12,6 +12,6 @@ export interface ExpirationOptions {
|
|
|
12
12
|
* @param options.expiresAt Date at which the value expires
|
|
13
13
|
* @param options.expiresIn Milliseconds in which the value expires. Will be ignored if expiresAt is set.
|
|
14
14
|
*
|
|
15
|
-
* @returns The
|
|
15
|
+
* @returns The effect to be used on atoms.
|
|
16
16
|
**/
|
|
17
|
-
export declare const expiration: (__0_0: ExpirationOptions) => import("./
|
|
17
|
+
export declare const expiration: (__0_0: ExpirationOptions) => import("./createEffect").EffectAtomCallback<ExpirationOptions, any>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export type {
|
|
1
|
+
export { createEffect } from "./createEffect";
|
|
2
|
+
export type { Effect } from "./createEffect";
|
|
3
3
|
export { localStorage } from "./localStorage";
|
|
4
4
|
export type { LocalStorageOptions, LocalStorageParser } from "./localStorage";
|
|
5
5
|
export { indexedDb } from "./indexedDb";
|
|
@@ -10,6 +10,6 @@ export interface IndexedDbOptions {
|
|
|
10
10
|
* @param {IndexedDbOptions | undefined} options
|
|
11
11
|
* @param options.key Use your own store key. Will be `atom.name` by default.
|
|
12
12
|
*
|
|
13
|
-
* @returns The
|
|
13
|
+
* @returns The effect to be used on atoms.
|
|
14
14
|
**/
|
|
15
|
-
export declare const indexedDb: (...[optionsArg]: [] | [undefined] | [IndexedDbOptions]) => import("./
|
|
15
|
+
export declare const indexedDb: (...[optionsArg]: [] | [undefined] | [IndexedDbOptions]) => import("./createEffect").EffectAtomCallback<IndexedDbOptions | undefined, any>;
|
|
@@ -23,6 +23,6 @@ export interface LocalStorageOptions {
|
|
|
23
23
|
* @param options.noTabSync Disable the synchronization of values over browser tabs.
|
|
24
24
|
* @param options.parser Custom functions to stringify and parse values. Defaults to JSON.stringify and JSON.parse. Use this when handling complex datatypes like Maps or Sets.
|
|
25
25
|
*
|
|
26
|
-
* @returns The
|
|
26
|
+
* @returns The effect to be used on atoms.
|
|
27
27
|
**/
|
|
28
|
-
export declare const localStorage: (...[optionsArg]: [] | [undefined] | [LocalStorageOptions]) => import("./
|
|
28
|
+
export declare const localStorage: (...[optionsArg]: [] | [undefined] | [LocalStorageOptions]) => import("./createEffect").EffectAtomCallback<LocalStorageOptions | undefined, any>;
|
|
@@ -9,11 +9,27 @@ export interface MigrationStep<Version extends string = string, PreviousVersion
|
|
|
9
9
|
validate?: (data: unknown) => data is OldData;
|
|
10
10
|
}
|
|
11
11
|
export interface MigrationOptions {
|
|
12
|
-
/**
|
|
12
|
+
/** An array of migration steps to perform for outdated values.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
14
|
+
* __Note:__ One step must have a `previous` version set to null as entry point.
|
|
15
15
|
**/
|
|
16
16
|
steps: MigrationStep[];
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
/** Effect to migrate the persisted value of an atom to a newer version.
|
|
19
|
+
* You can use the `createMigrationStep` helper to create migration steps.
|
|
20
|
+
*
|
|
21
|
+
* @param {MigrationOptions} options
|
|
22
|
+
* @param options.steps An array of migration steps to perform for outdated values.
|
|
23
|
+
*
|
|
24
|
+
* __Note:__ One step must have a `previous` version set to null as entry point.
|
|
25
|
+
*
|
|
26
|
+
* @returns The effect to be used on atoms.
|
|
27
|
+
**/
|
|
28
|
+
export declare const migration: (__0_0: MigrationOptions) => import("./createEffect").EffectAtomCallback<MigrationOptions, unknown>;
|
|
29
|
+
/** Helper to create a step for the migration effect.
|
|
30
|
+
*
|
|
31
|
+
* @param migration Migration step to create.
|
|
32
|
+
*
|
|
33
|
+
* @returns The migration step.
|
|
34
|
+
**/
|
|
19
35
|
export declare const createMigrationStep: <Version extends string, PreviousVersion extends string | null, OldData, NewData>(migration: MigrationStep<Version, PreviousVersion, OldData, NewData>) => MigrationStep<Version, PreviousVersion, OldData, NewData>;
|
package/dist/@types/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export * from "./base";
|
|
2
|
-
export * from "./
|
|
2
|
+
export * from "./effects";
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createActions = void 0;
|
|
4
|
+
/** Create actions to change the state of an atom.
|
|
5
|
+
*
|
|
6
|
+
* @param atom Atom to be used.
|
|
7
|
+
* @param reducers Reducers for custom actions to set the atoms value.
|
|
8
|
+
*
|
|
9
|
+
* @returns Actions to change the state of the atom.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* const counter = createAtom({ defaultValue: 0 })
|
|
13
|
+
* const actions = createActions(counter, {
|
|
14
|
+
* increment: (state) => state + 1,
|
|
15
|
+
* decrement: (state) => state - 1,
|
|
16
|
+
* add: (state, value: number) => state + value,
|
|
17
|
+
* subtract: (state, value: number) => state - value,
|
|
18
|
+
* })
|
|
19
|
+
* actions.increment()
|
|
20
|
+
* actions.add(5)
|
|
21
|
+
**/
|
|
22
|
+
const createActions = (atom, reducers) => Object.entries(reducers).reduce((result, [key, reducerFn]) => {
|
|
23
|
+
result[key] = (...payloadArgs) => {
|
|
24
|
+
atom.set((state) => reducerFn(state, ...payloadArgs));
|
|
25
|
+
};
|
|
26
|
+
return result;
|
|
27
|
+
}, {});
|
|
28
|
+
exports.createActions = createActions;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createAtom = exports.Atom = void 0;
|
|
4
|
+
const createActions_1 = require("./createActions");
|
|
5
|
+
const Stateful_1 = require("./Stateful");
|
|
6
|
+
const EffectDispatcher_1 = require("../effects/EffectDispatcher");
|
|
7
|
+
let key = 0;
|
|
8
|
+
class Atom extends Stateful_1.Stateful {
|
|
9
|
+
constructor({ defaultValue, name = `atom-${++key}`, effects, reducers = {}, }) {
|
|
10
|
+
super(defaultValue);
|
|
11
|
+
this.name = name;
|
|
12
|
+
this.defaultValue = defaultValue;
|
|
13
|
+
this.actions = (0, createActions_1.createActions)(this, reducers);
|
|
14
|
+
if (!effects || effects.length === 0) {
|
|
15
|
+
this.didInit = true;
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const { didInit } = new EffectDispatcher_1.EffectDispatcher({ atom: this, effects });
|
|
19
|
+
this.setDidInit(didInit);
|
|
20
|
+
}
|
|
21
|
+
/** Set the value of the atom.
|
|
22
|
+
*
|
|
23
|
+
* @param next New value or function to create the
|
|
24
|
+
* new value based off the previous value.
|
|
25
|
+
*/
|
|
26
|
+
set(next) {
|
|
27
|
+
const value = next instanceof Function ? next(this.get()) : next;
|
|
28
|
+
super.update(value);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.Atom = Atom;
|
|
32
|
+
/** Creates an atom store.
|
|
33
|
+
*
|
|
34
|
+
* @param config.defaultValue Value that will be used initially.
|
|
35
|
+
* @param config.name Name of the atom. Must be unique among all atoms. Defaults to "atom-{number}".
|
|
36
|
+
* @param config.effects Effects that will be applied on the atom.
|
|
37
|
+
* @param config.reducers Reducers for custom actions to set the atom's value.
|
|
38
|
+
*
|
|
39
|
+
* @returns An atom instance.
|
|
40
|
+
* - `result.get`: Read the value of state.
|
|
41
|
+
* - `result.subscribe`: Subscribe to value changes.
|
|
42
|
+
* - `result.set`: Set the value of the atom.
|
|
43
|
+
* - `result.actions`: All actions that were created with reducers.
|
|
44
|
+
* - `result.didInit`: State of the atom's effects initialization process.
|
|
45
|
+
* Will be a promise if the initialization is pending and `true` if finished.
|
|
46
|
+
**/
|
|
47
|
+
const createAtom = (config) => new Atom(config);
|
|
48
|
+
exports.createAtom = createAtom;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.createDerived = exports.SettableDerive = exports.Derive = void 0;
|
|
4
4
|
const utils_1 = require("@yaasl/utils");
|
|
5
5
|
const Stateful_1 = require("./Stateful");
|
|
6
6
|
const allDidInit = (atoms) => {
|
|
@@ -73,7 +73,7 @@ class SettableDerive extends Derive {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
exports.SettableDerive = SettableDerive;
|
|
76
|
-
function
|
|
76
|
+
function createDerived(getter, setter) {
|
|
77
77
|
if (setter) {
|
|
78
78
|
return new SettableDerive(getter, setter);
|
|
79
79
|
}
|
|
@@ -81,4 +81,4 @@ function derive(getter, setter) {
|
|
|
81
81
|
return new Derive(getter);
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
-
exports.
|
|
84
|
+
exports.createDerived = createDerived;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSelector = exports.CombinerSelector = exports.PathSelector = void 0;
|
|
4
|
+
const utils_1 = require("@yaasl/utils");
|
|
5
|
+
const Stateful_1 = require("./Stateful");
|
|
6
|
+
const selectPath = (state, path) => path
|
|
7
|
+
.split(".")
|
|
8
|
+
.reduce((result, key) => result[key], state);
|
|
9
|
+
class PathSelector extends Stateful_1.Stateful {
|
|
10
|
+
constructor(atom, path) {
|
|
11
|
+
super(selectPath(atom.get(), path));
|
|
12
|
+
atom.subscribe(state => this.update(selectPath(state, path)));
|
|
13
|
+
this.setDidInit(atom.didInit);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.PathSelector = PathSelector;
|
|
17
|
+
// -- Combiner selector
|
|
18
|
+
const allDidInit = (atoms) => {
|
|
19
|
+
const inits = atoms
|
|
20
|
+
.map(atom => atom.didInit)
|
|
21
|
+
.filter((didInit) => typeof didInit !== "boolean");
|
|
22
|
+
return inits.length === 0 ? true : Promise.all(inits).then(utils_1.toVoid);
|
|
23
|
+
};
|
|
24
|
+
class CombinerSelector extends Stateful_1.Stateful {
|
|
25
|
+
constructor(atoms, combiner) {
|
|
26
|
+
const selectState = () => {
|
|
27
|
+
const values = atoms.map(atom => atom.get());
|
|
28
|
+
return combiner(...values);
|
|
29
|
+
};
|
|
30
|
+
super(selectState());
|
|
31
|
+
atoms.forEach(atom => atom.subscribe(() => this.update(selectState())));
|
|
32
|
+
this.setDidInit(allDidInit(atoms));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.CombinerSelector = CombinerSelector;
|
|
36
|
+
const createSelector = (atoms, selector) => {
|
|
37
|
+
if (atoms instanceof Stateful_1.Stateful && typeof selector === "string") {
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
39
|
+
return new PathSelector(atoms, selector);
|
|
40
|
+
}
|
|
41
|
+
if (Array.isArray(atoms) && typeof selector === "function") {
|
|
42
|
+
return new CombinerSelector(atoms, selector);
|
|
43
|
+
}
|
|
44
|
+
throw new Error("Selector args do not match any overload");
|
|
45
|
+
};
|
|
46
|
+
exports.createSelector = createSelector;
|
package/dist/cjs/base/index.js
CHANGED
|
@@ -14,8 +14,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./atom"), exports);
|
|
18
|
-
__exportStar(require("./derive"), exports);
|
|
19
17
|
__exportStar(require("./config"), exports);
|
|
20
|
-
__exportStar(require("./
|
|
18
|
+
__exportStar(require("./createAtom"), exports);
|
|
19
|
+
__exportStar(require("./createDerived"), exports);
|
|
20
|
+
__exportStar(require("./createSelector"), exports);
|
|
21
21
|
__exportStar(require("./Stateful"), exports);
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.EffectDispatcher = void 0;
|
|
4
4
|
const utils_1 = require("@yaasl/utils");
|
|
5
5
|
const Scheduler_1 = require("../utils/Scheduler");
|
|
6
|
-
class
|
|
7
|
-
constructor({ atom,
|
|
6
|
+
class EffectDispatcher {
|
|
7
|
+
constructor({ atom, effects }) {
|
|
8
8
|
this.didInit = false;
|
|
9
|
-
this.
|
|
9
|
+
this.effects = [];
|
|
10
10
|
this.scheduler = new Scheduler_1.Scheduler();
|
|
11
|
-
this.
|
|
12
|
-
this.
|
|
11
|
+
this.effects = effects.map(create => create(atom));
|
|
12
|
+
this.callEffectAction("init", atom);
|
|
13
13
|
this.subscribeSetters(atom);
|
|
14
|
-
this.
|
|
14
|
+
this.callEffectAction("didInit", atom);
|
|
15
15
|
const { queue } = this.scheduler;
|
|
16
16
|
if (!(0, utils_1.isPromiseLike)(queue)) {
|
|
17
17
|
this.didInit = true;
|
|
@@ -22,16 +22,16 @@ class MiddlewareDispatcher {
|
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
24
|
subscribeSetters(atom) {
|
|
25
|
-
atom.subscribe(value => this.
|
|
25
|
+
atom.subscribe(value => this.callEffectAction("set", atom, () => value));
|
|
26
26
|
}
|
|
27
|
-
|
|
27
|
+
callEffectAction(action, atom,
|
|
28
28
|
/* Must be a function to make sure it is using the latest value when used in promise */
|
|
29
29
|
getValue = () => atom.get()) {
|
|
30
|
-
const tasks = this.
|
|
30
|
+
const tasks = this.effects.map(({ actions, options }) => {
|
|
31
31
|
const actionFn = actions[action];
|
|
32
32
|
return () => actionFn === null || actionFn === void 0 ? void 0 : actionFn({ value: getValue(), atom, options });
|
|
33
33
|
});
|
|
34
34
|
void this.scheduler.run(tasks);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
-
exports.
|
|
37
|
+
exports.EffectDispatcher = EffectDispatcher;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createEffect = void 0;
|
|
4
|
+
/** Create effects to be used in combination with atoms.
|
|
5
|
+
*
|
|
6
|
+
* Effects can be used to interact with an atom by using the following lifecycle actions:
|
|
7
|
+
*
|
|
8
|
+
* - `init`: Action to be called when the atom is created, but before subscribing to `set` events.
|
|
9
|
+
* May return a promise that can be awaited by using `atom.didInit`.
|
|
10
|
+
* - `didInit`: Action to be called when the atom is created, but after subscribing to `set` events.
|
|
11
|
+
* May return a promise that can be awaited by using `atom.didInit`.
|
|
12
|
+
* - `set`: Action to be called when the atom's `set` function is called.
|
|
13
|
+
*
|
|
14
|
+
* @param setup Effect actions or function to create effect actions.
|
|
15
|
+
* Effect actions are fired in the atom lifecycle, alongside to the subscriptions.
|
|
16
|
+
*
|
|
17
|
+
* @returns The effect to be used on atoms.
|
|
18
|
+
**/
|
|
19
|
+
const createEffect = (setup) => (...[optionsArg]) => (atom) => {
|
|
20
|
+
const options = optionsArg;
|
|
21
|
+
const actions = setup instanceof Function ? setup({ options, atom }) : setup;
|
|
22
|
+
return {
|
|
23
|
+
options,
|
|
24
|
+
actions,
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
exports.createEffect = createEffect;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.expiration = void 0;
|
|
4
|
-
const
|
|
4
|
+
const createEffect_1 = require("./createEffect");
|
|
5
5
|
const base_1 = require("../base");
|
|
6
6
|
const Expiration_1 = require("../utils/Expiration");
|
|
7
7
|
const STORAGE = window.localStorage;
|
|
@@ -13,7 +13,7 @@ const syncOverBrowserTabs = (observingKey, onChange) => window.addEventListener(
|
|
|
13
13
|
return;
|
|
14
14
|
onChange(newValue);
|
|
15
15
|
});
|
|
16
|
-
/**
|
|
16
|
+
/** Effect to make an atom value expirable and reset to its defaulValue.
|
|
17
17
|
*
|
|
18
18
|
* __Note:__ When using `expiresAt`, a function returning the date should be prefered since using a static date might end in an infinite loop.
|
|
19
19
|
*
|
|
@@ -21,9 +21,9 @@ const syncOverBrowserTabs = (observingKey, onChange) => window.addEventListener(
|
|
|
21
21
|
* @param options.expiresAt Date at which the value expires
|
|
22
22
|
* @param options.expiresIn Milliseconds in which the value expires. Will be ignored if expiresAt is set.
|
|
23
23
|
*
|
|
24
|
-
* @returns The
|
|
24
|
+
* @returns The effect to be used on atoms.
|
|
25
25
|
**/
|
|
26
|
-
exports.expiration = (0,
|
|
26
|
+
exports.expiration = (0, createEffect_1.createEffect)(({ atom, options = {} }) => {
|
|
27
27
|
var _a;
|
|
28
28
|
const hasExpiration = Boolean((_a = options.expiresAt) !== null && _a !== void 0 ? _a : options.expiresIn);
|
|
29
29
|
if (!hasExpiration)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createMigrationStep = exports.migration = exports.expiration = exports.indexedDb = exports.localStorage = exports.
|
|
4
|
-
var
|
|
5
|
-
Object.defineProperty(exports, "
|
|
3
|
+
exports.createMigrationStep = exports.migration = exports.expiration = exports.indexedDb = exports.localStorage = exports.createEffect = void 0;
|
|
4
|
+
var createEffect_1 = require("./createEffect");
|
|
5
|
+
Object.defineProperty(exports, "createEffect", { enumerable: true, get: function () { return createEffect_1.createEffect; } });
|
|
6
6
|
var localStorage_1 = require("./localStorage");
|
|
7
7
|
Object.defineProperty(exports, "localStorage", { enumerable: true, get: function () { return localStorage_1.localStorage; } });
|
|
8
8
|
var indexedDb_1 = require("./indexedDb");
|
|
@@ -10,7 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.indexedDb = void 0;
|
|
13
|
-
const
|
|
13
|
+
const createEffect_1 = require("./createEffect");
|
|
14
14
|
const base_1 = require("../base");
|
|
15
15
|
const Store_1 = require("../utils/Store");
|
|
16
16
|
let atomDb = null;
|
|
@@ -22,9 +22,9 @@ let atomDb = null;
|
|
|
22
22
|
* @param {IndexedDbOptions | undefined} options
|
|
23
23
|
* @param options.key Use your own store key. Will be `atom.name` by default.
|
|
24
24
|
*
|
|
25
|
-
* @returns The
|
|
25
|
+
* @returns The effect to be used on atoms.
|
|
26
26
|
**/
|
|
27
|
-
exports.indexedDb = (0,
|
|
27
|
+
exports.indexedDb = (0, createEffect_1.createEffect)(({ atom, options }) => {
|
|
28
28
|
var _a;
|
|
29
29
|
const key = (_a = options === null || options === void 0 ? void 0 : options.key) !== null && _a !== void 0 ? _a : atom.name;
|
|
30
30
|
return {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.localStorage = void 0;
|
|
4
|
-
const
|
|
4
|
+
const createEffect_1 = require("./createEffect");
|
|
5
5
|
const base_1 = require("../base");
|
|
6
6
|
const LocalStorage_1 = require("../utils/LocalStorage");
|
|
7
7
|
/** Middleware to save and load atom values to the local storage.
|
|
@@ -12,9 +12,9 @@ const LocalStorage_1 = require("../utils/LocalStorage");
|
|
|
12
12
|
* @param options.noTabSync Disable the synchronization of values over browser tabs.
|
|
13
13
|
* @param options.parser Custom functions to stringify and parse values. Defaults to JSON.stringify and JSON.parse. Use this when handling complex datatypes like Maps or Sets.
|
|
14
14
|
*
|
|
15
|
-
* @returns The
|
|
15
|
+
* @returns The effect to be used on atoms.
|
|
16
16
|
**/
|
|
17
|
-
exports.localStorage = (0,
|
|
17
|
+
exports.localStorage = (0, createEffect_1.createEffect)(({ atom, options = {} }) => {
|
|
18
18
|
const internalKey = base_1.CONFIG.name ? `${base_1.CONFIG.name}/${atom.name}` : atom.name;
|
|
19
19
|
const { key = internalKey, parser, noTabSync } = options;
|
|
20
20
|
const storage = new LocalStorage_1.LocalStorage(key, {
|