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

@ -1,9 +1,9 @@
import { DropdownScopeInternalContext } from '@/ui/layout/dropdown/scopes/scope-internal-context/DropdownScopeInternalContext';
import { dropdownHotkeyStateScopeMap } from '@/ui/layout/dropdown/states/dropdownHotkeyStateScopeMap';
import { dropdownWidthStateScopeMap } from '@/ui/layout/dropdown/states/dropdownWidthStateScopeMap';
import { isDropdownOpenStateScopeMap } from '@/ui/layout/dropdown/states/isDropdownOpenStateScopeMap';
import { dropdownHotkeyComponentState } from '@/ui/layout/dropdown/states/dropdownHotkeyComponentState';
import { dropdownWidthComponentState } from '@/ui/layout/dropdown/states/dropdownWidthComponentState';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
import { getState } from '@/ui/utilities/recoil-scope/utils/getState';
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
type UseDropdownStatesProps = {
dropdownScopeId?: string;
@ -19,8 +19,17 @@ export const useDropdownStates = ({
return {
scopeId,
dropdownHotkeyScopeState: getState(dropdownHotkeyStateScopeMap, scopeId),
dropdownWidthState: getState(dropdownWidthStateScopeMap, scopeId),
isDropdownOpenState: getState(isDropdownOpenStateScopeMap, scopeId),
dropdownHotkeyScopeState: extractComponentState(
dropdownHotkeyComponentState,
scopeId,
),
dropdownWidthState: extractComponentState(
dropdownWidthComponentState,
scopeId,
),
isDropdownOpenState: extractComponentState(
isDropdownOpenComponentState,
scopeId,
),
};
};

View File

@ -1,7 +1,7 @@
import { StateScopeMapKey } from '@/ui/utilities/recoil-scope/scopes-internal/types/StateScopeMapKey';
import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext';
import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey';
type DropdownScopeInternalContextProps = StateScopeMapKey;
type DropdownScopeInternalContextProps = ComponentStateKey;
export const DropdownScopeInternalContext =
createScopeInternalContext<DropdownScopeInternalContextProps>();

View File

@ -0,0 +1,9 @@
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
export const dropdownHotkeyComponentState = createComponentState<
HotkeyScope | null | undefined
>({
key: 'dropdownHotkeyComponentState',
defaultValue: null,
});

View File

@ -1,9 +0,0 @@
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { createStateScopeMap } from '@/ui/utilities/recoil-scope/utils/createStateScopeMap';
export const dropdownHotkeyStateScopeMap = createStateScopeMap<
HotkeyScope | null | undefined
>({
key: 'dropdownHotkeyStateScopeMap',
defaultValue: null,
});

View File

@ -0,0 +1,8 @@
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
export const dropdownWidthComponentState = createComponentState<
number | undefined
>({
key: 'dropdownWidthComponentState',
defaultValue: 160,
});

View File

@ -1,8 +0,0 @@
import { createStateScopeMap } from '@/ui/utilities/recoil-scope/utils/createStateScopeMap';
export const dropdownWidthStateScopeMap = createStateScopeMap<
number | undefined
>({
key: 'dropdownWidthStateScopeMap',
defaultValue: 160,
});

View File

@ -0,0 +1,6 @@
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
export const isDropdownOpenComponentState = createComponentState<boolean>({
key: 'isDropdownOpenComponentState',
defaultValue: false,
});

View File

@ -1,6 +0,0 @@
import { createStateScopeMap } from '@/ui/utilities/recoil-scope/utils/createStateScopeMap';
export const isDropdownOpenStateScopeMap = createStateScopeMap<boolean>({
key: 'isDropdownOpenStateScopeMap',
defaultValue: false,
});

View File

@ -2,7 +2,7 @@ import { useRef } from 'react';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { motion } from 'framer-motion';
import { useRecoilState } from 'recoil';
import { useRecoilState, useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum';
import { RIGHT_DRAWER_CLICK_OUTSIDE_LISTENER_ID } from '@/ui/layout/right-drawer/constants/RightDrawerClickOutsideListener';
@ -41,12 +41,12 @@ const StyledRightDrawer = styled.div`
export const RightDrawer = () => {
const [isRightDrawerOpen, setIsRightDrawerOpen] = useRecoilState(
isRightDrawerOpenState,
isRightDrawerOpenState(),
);
const [isRightDrawerExpanded] = useRecoilState(isRightDrawerExpandedState);
const isRightDrawerExpanded = useRecoilValue(isRightDrawerExpandedState());
const [rightDrawerPage] = useRecoilState(rightDrawerPageState);
const rightDrawerPage = useRecoilValue(rightDrawerPageState());
const { closeRightDrawer } = useRightDrawer();

View File

@ -28,7 +28,7 @@ const StyledRightDrawerBody = styled.div`
`;
export const RightDrawerRouter = () => {
const [rightDrawerPage] = useRecoilState(rightDrawerPageState);
const [rightDrawerPage] = useRecoilState(rightDrawerPageState());
let page = <></>;
let topBar = <></>;

View File

@ -10,7 +10,7 @@ import { isRightDrawerExpandedState } from '../states/isRightDrawerExpandedState
export const RightDrawerTopBarExpandButton = () => {
const [isRightDrawerExpanded, setIsRightDrawerExpanded] = useRecoilState(
isRightDrawerExpandedState,
isRightDrawerExpandedState(),
);
const handleButtonClick = () => {

View File

@ -12,10 +12,12 @@ describe('useRightDrawer', () => {
it('Should test the default behavior of useRightDrawer and change the states as the function calls', async () => {
const useCombinedHooks = () => {
const { openRightDrawer, closeRightDrawer } = useRightDrawer();
const isRightDrawerOpen = useRecoilValue(isRightDrawerOpenState);
const isRightDrawerExpanded = useRecoilValue(isRightDrawerExpandedState);
const isRightDrawerOpen = useRecoilValue(isRightDrawerOpenState());
const isRightDrawerExpanded = useRecoilValue(
isRightDrawerExpandedState(),
);
const rightDrawerPage = useRecoilValue(rightDrawerPageState);
const rightDrawerPage = useRecoilValue(rightDrawerPageState());
return {
openRightDrawer,

View File

@ -1,4 +1,4 @@
import { useRecoilState } from 'recoil';
import { useRecoilState, useSetRecoilState } from 'recoil';
import { isRightDrawerExpandedState } from '../states/isRightDrawerExpandedState';
import { isRightDrawerOpenState } from '../states/isRightDrawerOpenState';
@ -7,14 +7,15 @@ import { RightDrawerPages } from '../types/RightDrawerPages';
export const useRightDrawer = () => {
const [isRightDrawerOpen, setIsRightDrawerOpen] = useRecoilState(
isRightDrawerOpenState,
isRightDrawerOpenState(),
);
const [, setIsRightDrawerExpanded] = useRecoilState(
isRightDrawerExpandedState,
const setIsRightDrawerExpanded = useSetRecoilState(
isRightDrawerExpandedState(),
);
const [rightDrawerPage, setRightDrawerPage] =
useRecoilState(rightDrawerPageState);
const [rightDrawerPage, setRightDrawerPage] = useRecoilState(
rightDrawerPageState(),
);
const openRightDrawer = (rightDrawerPage: RightDrawerPages) => {
setRightDrawerPage(rightDrawerPage);

View File

@ -1,6 +1,6 @@
import { atom } from 'recoil';
import { createState } from '@/ui/utilities/state/utils/createState';
export const isRightDrawerExpandedState = atom<boolean>({
export const isRightDrawerExpandedState = createState<boolean>({
key: 'isRightDrawerExpandedState',
default: false,
defaultValue: false,
});

View File

@ -1,6 +1,6 @@
import { atom } from 'recoil';
import { createState } from '@/ui/utilities/state/utils/createState';
export const isRightDrawerOpenState = atom<boolean>({
export const isRightDrawerOpenState = createState<boolean>({
key: 'ui/layout/is-right-drawer-open',
default: false,
defaultValue: false,
});

View File

@ -1,8 +1,8 @@
import { atom } from 'recoil';
import { createState } from '@/ui/utilities/state/utils/createState';
import { RightDrawerPages } from '../types/RightDrawerPages';
export const rightDrawerPageState = atom<RightDrawerPages | null>({
export const rightDrawerPageState = createState<RightDrawerPages | null>({
key: 'ui/layout/right-drawer-page',
default: null,
defaultValue: null,
});

View File

@ -1,11 +1,11 @@
import { SelectableListScopeInternalContext } from '@/ui/layout/selectable-list/scopes/scope-internal-context/SelectableListScopeInternalContext';
import { selectableItemIdsStateScopeMap } from '@/ui/layout/selectable-list/states/selectableItemIdsStateScopeMap';
import { selectableListOnEnterStateScopeMap } from '@/ui/layout/selectable-list/states/selectableListOnEnterStateScopeMap';
import { selectedItemIdStateScopeMap } from '@/ui/layout/selectable-list/states/selectedItemIdStateScopeMap';
import { isSelectedItemIdFamilySelectorScopeMap } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdFamilySelectorScopeMap';
import { selectableItemIdsComponentState } from '@/ui/layout/selectable-list/states/selectableItemIdsComponentState';
import { selectableListOnEnterComponentState } from '@/ui/layout/selectable-list/states/selectableListOnEnterComponentState';
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { isSelectedItemIdFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdFamilySelector';
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
import { getFamilyState } from '@/ui/utilities/recoil-scope/utils/getFamilyState';
import { getState } from '@/ui/utilities/recoil-scope/utils/getState';
import { extractComponentFamilyState } from '@/ui/utilities/state/component-state/utils/extractComponentFamilyState';
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
type useSelectableListStatesProps = {
selectableListScopeId?: string;
@ -21,15 +21,21 @@ export const useSelectableListStates = ({
return {
scopeId,
isSelectedItemIdSelector: getFamilyState(
isSelectedItemIdFamilySelectorScopeMap,
isSelectedItemIdSelector: extractComponentFamilyState(
isSelectedItemIdFamilySelector,
scopeId,
),
selectableItemIdsState: getState(selectableItemIdsStateScopeMap, scopeId),
selectableListOnEnterState: getState(
selectableListOnEnterStateScopeMap,
selectableItemIdsState: extractComponentState(
selectableItemIdsComponentState,
scopeId,
),
selectableListOnEnterState: extractComponentState(
selectableListOnEnterComponentState,
scopeId,
),
selectedItemIdState: extractComponentState(
selectedItemIdComponentState,
scopeId,
),
selectedItemIdState: getState(selectedItemIdStateScopeMap, scopeId),
};
};

View File

@ -1,7 +1,7 @@
import { StateScopeMapKey } from '@/ui/utilities/recoil-scope/scopes-internal/types/StateScopeMapKey';
import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext';
import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey';
type SelectableListScopeInternalContextProps = StateScopeMapKey;
type SelectableListScopeInternalContextProps = ComponentStateKey;
export const SelectableListScopeInternalContext =
createScopeInternalContext<SelectableListScopeInternalContextProps>();

View File

@ -0,0 +1,9 @@
import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState';
export const isSelectedItemIdComponentFamilyState = createComponentFamilyState<
boolean,
string
>({
key: 'isSelectedItemIdComponentFamilyState',
defaultValue: false,
});

View File

@ -1,9 +0,0 @@
import { createFamilyStateScopeMap } from '@/ui/utilities/recoil-scope/utils/createFamilyStateScopeMap';
export const isSelectedItemIdFamilyStateScopeMap = createFamilyStateScopeMap<
boolean,
string
>({
key: 'isSelectedItemIdMapScopedFamilyState',
defaultValue: false,
});

View File

@ -0,0 +1,8 @@
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
export const selectableItemIdsComponentState = createComponentState<string[][]>(
{
key: 'selectableItemIdsComponentState',
defaultValue: [[]],
},
);

View File

@ -1,6 +0,0 @@
import { createStateScopeMap } from '@/ui/utilities/recoil-scope/utils/createStateScopeMap';
export const selectableItemIdsStateScopeMap = createStateScopeMap<string[][]>({
key: 'selectableItemIdsScopedState',
defaultValue: [[]],
});

View File

@ -0,0 +1,8 @@
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
export const selectableListOnEnterComponentState = createComponentState<
((itemId: string) => void) | undefined
>({
key: 'selectableListOnEnterComponentState',
defaultValue: undefined,
});

View File

@ -1,8 +0,0 @@
import { createStateScopeMap } from '@/ui/utilities/recoil-scope/utils/createStateScopeMap';
export const selectableListOnEnterStateScopeMap = createStateScopeMap<
((itemId: string) => void) | undefined
>({
key: 'selectableListOnEnterScopedState',
defaultValue: undefined,
});

View File

@ -0,0 +1,8 @@
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
export const selectedItemIdComponentState = createComponentState<string | null>(
{
key: 'selectedItemIdComponentState',
defaultValue: null,
},
);

View File

@ -1,6 +0,0 @@
import { createStateScopeMap } from '@/ui/utilities/recoil-scope/utils/createStateScopeMap';
export const selectedItemIdStateScopeMap = createStateScopeMap<string | null>({
key: 'selectedItemIdScopedState',
defaultValue: null,
});

View File

@ -0,0 +1,28 @@
import { isSelectedItemIdComponentFamilyState } from '@/ui/layout/selectable-list/states/isSelectedItemIdComponentFamilyState';
import { createComponentFamilySelector } from '@/ui/utilities/state/component-state/utils/createComponentFamilySelector';
export const isSelectedItemIdFamilySelector = createComponentFamilySelector<
boolean,
string
>({
key: 'isSelectedItemIdFamilySelector',
get:
({ scopeId, familyKey }: { scopeId: string; familyKey: string }) =>
({ get }) =>
get(
isSelectedItemIdComponentFamilyState({
scopeId: scopeId,
familyKey: familyKey,
}),
),
set:
({ scopeId, familyKey }: { scopeId: string; familyKey: string }) =>
({ set }, newValue) =>
set(
isSelectedItemIdComponentFamilyState({
scopeId: scopeId,
familyKey: familyKey,
}),
newValue,
),
});

View File

@ -1,26 +0,0 @@
import { isSelectedItemIdFamilyStateScopeMap } from '@/ui/layout/selectable-list/states/isSelectedItemIdFamilyStateScopeMap';
import { createFamilySelectorScopeMap } from '@/ui/utilities/recoil-scope/utils/createFamilySelectorScopeMap';
export const isSelectedItemIdFamilySelectorScopeMap =
createFamilySelectorScopeMap<boolean, string>({
key: 'isSelectedItemIdScopedFamilySelector',
get:
({ scopeId, familyKey }: { scopeId: string; familyKey: string }) =>
({ get }) =>
get(
isSelectedItemIdFamilyStateScopeMap({
scopeId: scopeId,
familyKey: familyKey,
}),
),
set:
({ scopeId, familyKey }: { scopeId: string; familyKey: string }) =>
({ set }, newValue) =>
set(
isSelectedItemIdFamilyStateScopeMap({
scopeId: scopeId,
familyKey: familyKey,
}),
newValue,
),
});

View File

@ -26,7 +26,7 @@ export const ShowPageMoreButton = ({
objectNameSingular: string;
}) => {
const { closeDropdown, toggleDropdown } = useDropdown('more-show-page');
const navigationMemorizedUrl = useRecoilValue(navigationMemorizedUrlState);
const navigationMemorizedUrl = useRecoilValue(navigationMemorizedUrlState());
const navigate = useNavigate();
const { deleteOneRecord } = useDeleteOneRecord({

View File

@ -1,7 +1,7 @@
import { TabListScopeInternalContext } from '@/ui/layout/tab/scopes/scope-internal-context/TabListScopeInternalContext';
import { activeTabIdStateScopeMap } from '@/ui/layout/tab/states/activeTabIdStateScopeMap';
import { activeTabIdComponentState } from '@/ui/layout/tab/states/activeTabIdComponentState';
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
import { getState } from '@/ui/utilities/recoil-scope/utils/getState';
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
type useTabListStatesProps = {
tabListScopeId?: string;
@ -15,6 +15,9 @@ export const useTabListStates = ({ tabListScopeId }: useTabListStatesProps) => {
return {
scopeId,
getActiveTabIdState: getState(activeTabIdStateScopeMap, scopeId),
getActiveTabIdState: extractComponentState(
activeTabIdComponentState,
scopeId,
),
};
};

View File

@ -1,7 +1,7 @@
import { StateScopeMapKey } from '@/ui/utilities/recoil-scope/scopes-internal/types/StateScopeMapKey';
import { createScopeInternalContext } from '@/ui/utilities/recoil-scope/scopes-internal/utils/createScopeInternalContext';
import { ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey';
type TabListScopeInternalContextProps = StateScopeMapKey;
type TabListScopeInternalContextProps = ComponentStateKey;
export const TabListScopeInternalContext =
createScopeInternalContext<TabListScopeInternalContextProps>();

View File

@ -0,0 +1,6 @@
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
export const activeTabIdComponentState = createComponentState<string | null>({
key: 'activeTabIdComponentState',
defaultValue: null,
});

View File

@ -1,6 +0,0 @@
import { createStateScopeMap } from '@/ui/utilities/recoil-scope/utils/createStateScopeMap';
export const activeTabIdStateScopeMap = createStateScopeMap<string | null>({
key: 'activeTabIdStateScopeMap',
defaultValue: null,
});