atomaric
Version:
Manage your project state
183 lines (157 loc) • 6.08 kB
TypeScript
import { useSyncExternalStore } from 'react';
import { Path, PathValue, PathValueDonor } from './paths';
export interface Register {}
export type ObjectActionsSetDeepPartial = Register extends {
keyPathSeparator: infer Separator extends string;
}
? Separator
: '.';
type Sunscriber<Value> = (value: Value) => void;
export type AtomStoreKey = `${string}${string}:${string}${string}`;
export type AtomOptions<Value, Actions extends Record<string, Function> = {}> = {
/** **default: true** */
warnOnDuplicateStoreKey?: boolean;
/** will update value if localStorage value is changed
* **default: true**
*/
listenStorageChanges?: boolean;
/** zip Value to stringifiable value */
zipValue?: (value: Value) => any;
/** unzip stringifiable value to Value */
unzipValue?: (packedValue: any) => Value;
/** make your localStorage value unchangable */
unchangable?: true;
/** return value expire Date */
exp?: (self: Atom<Value>, isValueWasStoraged: boolean) => Date;
} & (
| {
/** save in localStorage by this key */
storeKey: AtomStoreKey;
securifyKeyLevel?: AtomSecureLevel;
securifyValueLevel?: AtomSecureLevel;
}
| {
/** declare your custom actions */
do: (
set: AtomSetMethod<Value>,
get: () => Value,
self: Atom<Value>,
setDeferred: AtomSetDeferredMethod<Value>,
) => Actions;
}
);
export type AtomSetMethod<Value> = (value: Value | ((prev: Value) => Value), isPreventSave?: boolean) => void;
export type AtomSetDeferredMethod<Value> = (
value: Value | ((prev: Value) => Value),
debounceMs?: number,
isPreventSave?: boolean,
isInitInvoke?: boolean,
) => void;
export type AtomSubscribeMethod<Value> = (subscriber: Sunscriber<Value>) => () => void;
export type UpdateAction<Value> = {
/** transform current taken value */
update: (updater: (value: Value) => void) => void;
};
export type NumberActions<Value> = {
/** pass the 2 to increment on 2, pass the -2 to decrement on 2
* **default: 1**
*/
increment: (delta?: number) => void;
};
export type ObjectActions<Value> = UpdateAction<Value> & {
/** pass partial object to update some field values */
setPartial: (value: Partial<Value> | ((value: Value) => Partial<Value>)) => void;
/** pass partial value to update some deep values by flat path */
setDeepPartial: <
ValuePath extends Path<Value, Sep>,
Val extends PathValue<Value, Sep, ValuePath>,
Sep extends string = ObjectActionsSetDeepPartial,
>(
path: ValuePath,
value: Val | ((value: Val) => Val),
donor: PathValueDonor<Value, Sep, ValuePath> | null,
separator?: Sep,
) => void;
};
export type BooleanActions = {
/** toggle current value between true/false */
toggle: () => void;
};
export type SetActions<Value> = {
/** like the Set.prototype.add() method */
add: (value: Value) => void;
/** like the Set.prototype.delete() method */
delete: (value: Value) => void;
/** will add value if it doesn't exist, otherwise delete */
toggle: (value: Value) => void;
/** like the Set.prototype.clear() method */
clear: () => void;
};
export type ArrayActions<Value> = UpdateAction<Value[]> & {
/** like the Array.prototype.push() method */
push: (...values: Value[]) => void;
/** like the Array.prototype.unshift() method */
unshift: (...values: Value[]) => void;
/** like the Array.prototype.filter() method, but callback is optional - (it) => !!it */
filter: (filter?: (value: Value, index: number, array: Value[]) => any) => void;
/** will add value if it doesn't exist, otherwise delete */
toggle: (value: Value, isAddInStart?: boolean) => void;
/** will add value if not exists */
add: (value: Value) => void;
/** will delete value from array */
remove: (value: Value) => void;
};
export type DefaultActions<Value> = Value extends Set<infer Val>
? SetActions<Val>
: Value extends boolean
? BooleanActions
: Value extends (infer Val)[]
? ArrayActions<Val>
: Value extends number
? NumberActions<Value>
: Value extends object
? ObjectActions<Value>
: {};
declare class Atom<Value, Actions extends Record<string, Function> = {}> {
constructor(initialValue: Value, storeKeyOrOptions: StoreKeyOrOptions<Value, Actions> | undefined);
/** initial value */
readonly initialValue: Value;
/** get current value */
readonly get: () => Value;
/** set current value */
readonly set: AtomSetMethod<Value>;
/** set current value with debounce */
readonly setDeferred: AtomSetDeferredMethod<Value>;
/** set current value as default (initial) */
readonly reset: () => void;
/** subscribe on value changes */
readonly subscribe: AtomSubscribeMethod<Value>;
/** your custom actions */
readonly do: Actions & DefaultActions<Value>;
/** check is current value not changed */
readonly isInitialValue: () => boolean;
}
export function useAtom<Value>(atom: Atom<Value>): [Value, AtomSetMethod<Value>];
/** observable atom value */
export function useAtomValue<Value>(atom: Atom<Value>): Value;
export function useAtomSet<Value>(atom: Atom<Value>): AtomSetMethod<Value>;
export function useAtomSetDeferred<Value>(atom: Atom<Value>): AtomSetDeferredMethod<Value>;
export function useAtomGet<Value>(atom: Atom<Value>): () => Value;
/** get your custom actions */
export function useAtomDo<Value, Actions extends Record<string, Function> = {}>(
atom: Atom<Value, Actions>,
): Actions & DefaultActions<Value>;
export type StoreKeyOrOptions<Value, Actions extends Record<string, Function> = {}> =
| AtomStoreKey
| AtomOptions<Value, Actions>;
export function atom<Value, Actions extends Record<string, Function> = {}>(
value: Value,
storeKeyOrOptions?: StoreKeyOrOptions<Value, Actions>,
): Atom<Value, Actions>;
/** invoke this function before all atom usages */
export function configureAtomaric(options: {
useSyncExternalStore: typeof useSyncExternalStore;
keyPathSeparator: ObjectActionsSetDeepPartial;
securifyKeyLevel?: AtomSecureLevel;
securifyValueLevel?: AtomSecureLevel;
}): void;