Introduce ComponentState (#4386)

* Proof of concept ComponentState

* Migrate to createState and createFamilyState

* Refactor

* Fix

* Fix tests

* Fix lint

* Fix tests

* Re-enable coverage
This commit is contained in:
Charles Bochet
2024-03-09 11:31:00 +01:00
committed by GitHub
parent 17511be0cf
commit 86c0f311f5
451 changed files with 1718 additions and 2557 deletions

View File

@ -0,0 +1,6 @@
import { SerializableParam } from 'recoil';
export type ComponentFamilyStateKey<FamilyKey extends SerializableParam> = {
scopeId: string;
familyKey: FamilyKey;
};

View File

@ -0,0 +1,3 @@
export type ComponentStateKey = {
scopeId: string;
};

View File

@ -0,0 +1,24 @@
import { selectorFamily, SerializableParam } from 'recoil';
import { ComponentFamilyStateKey } from '@/ui/utilities/state/component-state/types/ComponentFamilyStateKey';
import { SelectorGetter } from '@/ui/utilities/state/types/SelectorGetter';
import { SelectorSetter } from '@/ui/utilities/state/types/SelectorSetter';
export const createComponentFamilySelector = <
ValueType,
FamilyKey extends SerializableParam,
>({
key,
get,
set,
}: {
key: string;
get: SelectorGetter<ValueType, ComponentFamilyStateKey<FamilyKey>>;
set: SelectorSetter<ValueType, ComponentFamilyStateKey<FamilyKey>>;
}) => {
return selectorFamily<ValueType, ComponentFamilyStateKey<FamilyKey>>({
key,
get,
set,
});
};

View File

@ -0,0 +1,19 @@
import { atomFamily, SerializableParam } from 'recoil';
import { ComponentFamilyStateKey } from '@/ui/utilities/state/component-state/types/ComponentFamilyStateKey';
export const createComponentFamilyState = <
ValueType,
FamilyKey extends SerializableParam,
>({
key,
defaultValue,
}: {
key: string;
defaultValue: ValueType;
}) => {
return atomFamily<ValueType, ComponentFamilyStateKey<FamilyKey>>({
key,
default: defaultValue,
});
};

View File

@ -0,0 +1,17 @@
import { selectorFamily } from 'recoil';
import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey';
import { SelectorGetter } from '@/ui/utilities/state/types/SelectorGetter';
export const createComponentReadOnlySelector = <ValueType>({
key,
get,
}: {
key: string;
get: SelectorGetter<ValueType, ComponentStateKey>;
}) => {
return selectorFamily<ValueType, ComponentStateKey>({
key,
get,
});
};

View File

@ -0,0 +1,21 @@
import { selectorFamily } from 'recoil';
import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey';
import { SelectorGetter } from '@/ui/utilities/state/types/SelectorGetter';
import { SelectorSetter } from '@/ui/utilities/state/types/SelectorSetter';
export const createComponentSelector = <ValueType>({
key,
get,
set,
}: {
key: string;
get: SelectorGetter<ValueType, ComponentStateKey>;
set: SelectorSetter<ValueType, ComponentStateKey>;
}) => {
return selectorFamily<ValueType, ComponentStateKey>({
key,
get,
set,
});
};

View File

@ -0,0 +1,16 @@
import { atomFamily } from 'recoil';
import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey';
export const createComponentState = <ValueType>({
key,
defaultValue,
}: {
key: string;
defaultValue: ValueType;
}) => {
return atomFamily<ValueType, ComponentStateKey>({
key,
default: defaultValue,
});
};

View File

@ -0,0 +1,19 @@
import { RecoilState, SerializableParam } from 'recoil';
import { ComponentFamilyStateKey } from '@/ui/utilities/state/component-state/types/ComponentFamilyStateKey';
export const extractComponentFamilyState = <
StateType,
FamilyKey extends SerializableParam,
>(
componentfamilyState: (
componentFamilyStateKey: ComponentFamilyStateKey<FamilyKey>,
) => RecoilState<StateType>,
scopeId: string,
) => {
return (familyKey: FamilyKey) =>
componentfamilyState({
scopeId,
familyKey: familyKey || ('' as FamilyKey),
});
};

View File

@ -0,0 +1,12 @@
import { RecoilValueReadOnly } from 'recoil';
import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey';
export const extractComponentReadOnlySelector = <StateType>(
componentSelector: (
componentStateKey: ComponentStateKey,
) => RecoilValueReadOnly<StateType>,
scopeId: string,
) => {
return () => componentSelector({ scopeId });
};

View File

@ -0,0 +1,12 @@
import { RecoilState } from 'recoil';
import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey';
export const extractComponentSelector = <StateType>(
componentSelector: (
componentStateKey: ComponentStateKey,
) => RecoilState<StateType>,
scopeId: string,
) => {
return () => componentSelector({ scopeId });
};

View File

@ -0,0 +1,12 @@
import { RecoilState } from 'recoil';
import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey';
export const extractComponentState = <StateType>(
componentState: (
componentStateKey: ComponentStateKey,
) => RecoilState<StateType>,
scopeId: string,
) => {
return () => componentState({ scopeId });
};

View File

@ -0,0 +1,14 @@
import {
GetCallback,
GetRecoilValue,
Loadable,
RecoilValue,
WrappedValue,
} from 'recoil';
export type SelectorGetter<T, P> = (
param: P,
) => (opts: {
get: GetRecoilValue;
getCallback: GetCallback;
}) => Promise<T> | RecoilValue<T> | Loadable<T> | WrappedValue<T> | T;

View File

@ -0,0 +1,13 @@
import {
DefaultValue,
GetRecoilValue,
ResetRecoilState,
SetRecoilState,
} from 'recoil';
export type SelectorSetter<T, P> = (
param: P,
) => (
opts: { set: SetRecoilState; get: GetRecoilValue; reset: ResetRecoilState },
newValue: T | DefaultValue,
) => void;

View File

@ -0,0 +1,17 @@
import { atomFamily, SerializableParam } from 'recoil';
export const createFamilyState = <
ValueType,
FamilyKey extends SerializableParam,
>({
key,
defaultValue,
}: {
key: string;
defaultValue: ValueType;
}) => {
return atomFamily<ValueType, FamilyKey>({
key,
default: defaultValue,
});
};

View File

@ -0,0 +1,18 @@
import { atom, AtomEffect } from 'recoil';
export const createState = <ValueType>({
key,
defaultValue,
effects,
}: {
key: string;
defaultValue: ValueType;
effects?: ReadonlyArray<AtomEffect<ValueType>>;
}) => {
const recoilState = atom<ValueType>({
key,
default: defaultValue,
effects,
});
return () => recoilState;
};

View File

@ -0,0 +1,8 @@
import { RecoilState, RecoilValueReadOnly, Snapshot } from 'recoil';
export const getSnapshotValue = <StateType>(
snapshot: Snapshot,
state: RecoilState<StateType> | RecoilValueReadOnly<StateType>,
) => {
return snapshot.getLoadable(state).getValue();
};

View File

@ -0,0 +1,8 @@
import { DefaultValue } from 'recoil';
export const guardRecoilDefaultValue = (
candidate: any,
): candidate is DefaultValue => {
if (candidate instanceof DefaultValue) return true;
return false;
};