CreateComponentFamilyState -> createComponentFamilyStateV2 (#11546)

Refacto of createComponentFamilyState

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Guillim
2025-04-14 10:31:30 +02:00
committed by GitHub
parent 27f542e132
commit 0de8140b3a
36 changed files with 311 additions and 299 deletions

View File

@ -1,5 +1,7 @@
import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useEffect } from 'react';
import { useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
@ -9,10 +11,12 @@ export const CommandMenuDefaultSelectionEffect = ({
}: {
selectableItemIds: string[];
}) => {
const { setSelectedItemId, selectedItemIdState } =
useSelectableList('command-menu-list');
const { setSelectedItemId } = useSelectableList('command-menu-list');
const selectedItemId = useRecoilValue(selectedItemIdState);
const selectedItemId = useRecoilComponentValueV2(
selectedItemIdComponentState,
'command-menu-list',
);
const hasUserSelectedCommand = useRecoilValue(hasUserSelectedCommandState);

View File

@ -1,8 +1,8 @@
import { isNonEmptyString } from '@sniptt/guards';
import { useRecoilValue } from 'recoil';
import { useCommandMenuOnItemClick } from '@/command-menu/hooks/useCommandMenuOnItemClick';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { ReactNode } from 'react';
import { IconArrowUpRight, IconComponent } from 'twenty-ui/display';
import { MenuItemCommand } from 'twenty-ui/navigation';
@ -35,8 +35,10 @@ export const CommandMenuItem = ({
Icon = IconArrowUpRight;
}
const { isSelectedItemIdSelector } = useSelectableList();
const isSelectedItemId = useRecoilValue(isSelectedItemIdSelector(id));
const isSelectedItemId = useRecoilComponentFamilyValueV2(
isSelectedItemIdComponentFamilySelector,
id,
);
return (
<MenuItemCommand

View File

@ -79,7 +79,7 @@ export const CommandMenuList = ({
<ScrollWrapper componentInstanceId={`scroll-wrapper-command-menu`}>
<StyledInnerList>
<SelectableList
selectableListId="command-menu-list"
selectableListInstanceId="command-menu-list"
hotkeyScope={AppHotkeyScope.CommandMenuOpen}
selectableItemIdArray={selectableItemIds}
onEnter={(itemId) => {

View File

@ -144,7 +144,7 @@ export const AdvancedFilterFieldSelectMenu = ({
<SelectableList
hotkeyScope={FiltersHotkeyScope.ObjectFilterDropdownButton}
selectableItemIdArray={selectableFieldMetadataItemIds}
selectableListId={OBJECT_FILTER_DROPDOWN_ID}
selectableListInstanceId={OBJECT_FILTER_DROPDOWN_ID}
onEnter={handleEnter}
>
<DropdownMenuItemsContainer>

View File

@ -90,7 +90,7 @@ export const ObjectFilterDropdownBooleanSelect = () => {
return (
<SelectableList
selectableListId="boolean-select"
selectableListInstanceId="boolean-select"
selectableItemIdArray={options.map((option) => option.toString())}
hotkeyScope={SingleRecordPickerHotkeyScope.SingleRecordPicker}
onEnter={(itemId) => {

View File

@ -150,7 +150,7 @@ export const ObjectFilterDropdownFilterSelect = ({
<SelectableList
hotkeyScope={FiltersHotkeyScope.ObjectFilterDropdownButton}
selectableItemIdArray={selectableFieldMetadataItemIds}
selectableListId={OBJECT_FILTER_DROPDOWN_ID}
selectableListInstanceId={OBJECT_FILTER_DROPDOWN_ID}
onEnter={handleEnter}
>
<DropdownMenuItemsContainer>

View File

@ -15,14 +15,15 @@ import { findDuplicateRecordFilterInNonAdvancedRecordFilters } from '@/object-re
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { MenuItemSelect } from 'twenty-ui/navigation';
import { useIcons } from 'twenty-ui/display';
import { MenuItemSelect } from 'twenty-ui/navigation';
export type ObjectFilterDropdownFilterSelectMenuItemProps = {
fieldMetadataItemToSelect: FieldMetadataItem;
@ -48,12 +49,11 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({
objectFilterDropdownFilterIsSelectedComponentState,
);
const { isSelectedItemIdSelector, resetSelectedItem } = useSelectableList(
OBJECT_FILTER_DROPDOWN_ID,
);
const { resetSelectedItem } = useSelectableList(OBJECT_FILTER_DROPDOWN_ID);
const isSelectedItem = useRecoilValue(
isSelectedItemIdSelector(fieldMetadataItemToSelect.id),
const isSelectedItem = useRecoilComponentFamilyValueV2(
isSelectedItemIdComponentFamilySelector,
fieldMetadataItemToSelect.id,
);
const setSelectedOperandInDropdown = useSetRecoilComponentStateV2(

View File

@ -3,9 +3,10 @@ import { OBJECT_FILTER_DROPDOWN_ID } from '@/object-record/object-filter-dropdow
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { isCompositeField } from '@/object-record/object-filter-dropdown/utils/isCompositeField';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { useRecoilValue } from 'recoil';
import { MenuItemSelect } from 'twenty-ui/navigation';
import { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { useIcons } from 'twenty-ui/display';
import { MenuItemSelect } from 'twenty-ui/navigation';
export type ObjectFilterDropdownFilterSelectMenuItemV2Props = {
fieldMetadataItemToSelect: FieldMetadataItem;
@ -16,12 +17,11 @@ export const ObjectFilterDropdownFilterSelectMenuItemV2 = ({
fieldMetadataItemToSelect,
onClick,
}: ObjectFilterDropdownFilterSelectMenuItemV2Props) => {
const { isSelectedItemIdSelector, resetSelectedItem } = useSelectableList(
OBJECT_FILTER_DROPDOWN_ID,
);
const { resetSelectedItem } = useSelectableList(OBJECT_FILTER_DROPDOWN_ID);
const isSelectedItem = useRecoilValue(
isSelectedItemIdSelector(fieldMetadataItemToSelect.id),
const isSelectedItem = useRecoilComponentFamilyValueV2(
isSelectedItemIdComponentFamilySelector,
fieldMetadataItemToSelect.id,
);
const { getIcon } = useIcons();

View File

@ -1,5 +1,4 @@
import { useEffect, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum';
import { v4 } from 'uuid';
@ -8,7 +7,7 @@ import { useOptionsForSelect } from '@/object-record/object-filter-dropdown/hook
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
import { useSelectableListStates } from '@/ui/layout/selectable-list/hooks/internal/useSelectableListStates';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
@ -20,6 +19,7 @@ import { selectedFilterComponentState } from '@/object-record/object-filter-drop
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
@ -62,13 +62,12 @@ export const ObjectFilterDropdownOptionSelect = () => {
const { closeDropdown } = useDropdown();
const { selectedItemIdState } = useSelectableListStates({
selectableListScopeId: componentInstanceId,
});
const { resetSelectedItem } = useSelectableList(componentInstanceId);
const selectedItemId = useRecoilValue(selectedItemIdState);
const selectedItemId = useRecoilComponentValueV2(
selectedItemIdComponentState,
componentInstanceId,
);
const fieldMetaDataId = fieldMetadataItemUsedInDropdown?.id ?? '';
@ -164,7 +163,7 @@ export const ObjectFilterDropdownOptionSelect = () => {
return (
<SelectableList
selectableListId={componentInstanceId}
selectableListInstanceId={componentInstanceId}
selectableItemIdArray={objectRecordsIds}
hotkeyScope={SingleRecordPickerHotkeyScope.SingleRecordPicker}
onEnter={(itemId) => {

View File

@ -1,5 +1,4 @@
import styled from '@emotion/styled';
import { useRecoilValue } from 'recoil';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { getAvatarType } from '@/object-metadata/utils/getAvatarType';
@ -8,12 +7,12 @@ import { multipleRecordPickerIsSelectedComponentFamilySelector } from '@/object-
import { getMultipleRecordPickerSelectableListId } from '@/object-record/record-picker/multiple-record-picker/utils/getMultipleRecordPickerSelectableListId';
import { RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem';
import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { SearchRecord } from '~/generated-metadata/graphql';
import { Avatar } from 'twenty-ui/display';
import { MenuItemMultiSelectAvatar } from 'twenty-ui/navigation';
import { SearchRecord } from '~/generated-metadata/graphql';
export const StyledSelectableItem = styled(SelectableItem)`
height: 100%;
@ -38,14 +37,12 @@ export const MultipleRecordPickerMenuItemContent = ({
const selectableListComponentInstanceId =
getMultipleRecordPickerSelectableListId(componentInstanceId);
const { isSelectedItemIdSelector } = useSelectableList(
const isSelectedByKeyboard = useRecoilComponentFamilyValueV2(
isSelectedItemIdComponentFamilySelector,
searchRecord.recordId,
selectableListComponentInstanceId,
);
const isSelectedByKeyboard = useRecoilValue(
isSelectedItemIdSelector(searchRecord.recordId),
);
const isRecordSelectedWithObjectItem = useRecoilComponentFamilyValueV2(
multipleRecordPickerIsSelectedComponentFamilySelector,
searchRecord.recordId,

View File

@ -114,7 +114,7 @@ export const MultipleRecordPickerMenuItems = ({
return (
<DropdownMenuItemsContainer hasMaxHeight>
<SelectableList
selectableListId={selectableListComponentInstanceId}
selectableListInstanceId={selectableListComponentInstanceId}
selectableItemIdArray={pickableRecordIds}
hotkeyScope={MultipleRecordPickerHotkeyScope.MultipleRecordPicker}
onEnter={handleEnter}

View File

@ -12,7 +12,6 @@ import { isDefined } from 'twenty-shared/utils';
export const SINGLE_RECORD_PICKER_LISTENER_ID = 'single-record-select';
export type SingleRecordPickerProps = {
width?: number;
componentInstanceId: string;
} & SingleRecordPickerMenuItemsWithSearchProps;
@ -24,7 +23,6 @@ export const SingleRecordPicker = ({
onCreate,
onRecordSelected,
objectNameSingular,
width = 200,
componentInstanceId,
layoutDirection,
}: SingleRecordPickerProps) => {
@ -51,7 +49,7 @@ export const SingleRecordPicker = ({
<SingleRecordPickerComponentInstanceContext.Provider
value={{ instanceId: componentInstanceId }}
>
<DropdownMenu ref={containerRef} width={width} data-select-disable>
<DropdownMenu ref={containerRef} data-select-disable>
<SingleRecordPickerMenuItemsWithSearch
{...{
EmptyIcon,

View File

@ -1,12 +1,12 @@
import styled from '@emotion/styled';
import { useRecoilValue } from 'recoil';
import { SingleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/single-record-picker/states/contexts/SingleRecordPickerComponentInstanceContext';
import { SingleRecordPickerRecord } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerRecord';
import { getSingleRecordPickerSelectableListId } from '@/object-record/record-picker/single-record-picker/utils/getSingleRecordPickerSelectableListId';
import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { Avatar } from 'twenty-ui/display';
import { MenuItemSelectAvatar } from 'twenty-ui/navigation';
@ -33,12 +33,12 @@ export const SingleRecordPickerMenuItem = ({
const selectableListComponentInstanceId =
getSingleRecordPickerSelectableListId(recordPickerComponentInstanceId);
const { isSelectedItemIdSelector } = useSelectableList(
const isSelectedItemId = useRecoilComponentFamilyValueV2(
isSelectedItemIdComponentFamilySelector,
record.id,
selectableListComponentInstanceId,
);
const isSelectedItemId = useRecoilValue(isSelectedItemIdSelector(record.id));
return (
<StyledSelectableItem itemId={record.id} key={record.id}>
<MenuItemSelectAvatar

View File

@ -1,6 +1,5 @@
import { isNonEmptyString, isUndefined } from '@sniptt/guards';
import { useRef } from 'react';
import { useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum';
import { DropdownMenuSkeletonItem } from '@/ui/input/relation-picker/components/skeletons/DropdownMenuSkeletonItem';
@ -15,7 +14,9 @@ import { singleRecordPickerSelectedIdComponentState } from '@/object-record/reco
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
import { SingleRecordPickerRecord } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerRecord';
import { getSingleRecordPickerSelectableListId } from '@/object-record/record-picker/single-record-picker/utils/getSingleRecordPickerSelectableListId';
import { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
import styled from '@emotion/styled';
import { isDefined } from 'twenty-shared/utils';
@ -76,12 +77,14 @@ export const SingleRecordPickerMenuItems = ({
const selectableListComponentInstanceId =
getSingleRecordPickerSelectableListId(recordPickerComponentInstanceId);
const { isSelectedItemIdSelector, resetSelectedItem } = useSelectableList(
const { resetSelectedItem } = useSelectableList(
selectableListComponentInstanceId,
);
const isSelectedSelectNoneButton = useRecoilValue(
isSelectedItemIdSelector('select-none'),
const isSelectedSelectNoneButton = useRecoilComponentFamilyValueV2(
isSelectedItemIdComponentFamilySelector,
selectableListComponentInstanceId,
'select-none',
);
useScopedHotkeys(
@ -102,7 +105,7 @@ export const SingleRecordPickerMenuItems = ({
return (
<StyledContainer ref={containerRef}>
<SelectableList
selectableListId={selectableListComponentInstanceId}
selectableListInstanceId={selectableListComponentInstanceId}
selectableItemIdArray={selectableItemIds}
hotkeyScope={hotkeyScope}
onEnter={(itemId) => {

View File

@ -1,5 +1,4 @@
import { useEffect, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum';
import { StyledMultipleSelectDropdownAvatarChip } from '@/object-record/select/components/StyledMultipleSelectDropdownAvatarChip';
@ -8,9 +7,10 @@ import { DropdownMenuSkeletonItem } from '@/ui/input/relation-picker/components/
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
import { useSelectableListStates } from '@/ui/layout/selectable-list/hooks/internal/useSelectableListStates';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { MenuItem, MenuItemMultiSelectAvatar } from 'twenty-ui/navigation';
export const MultipleSelectDropdown = ({
@ -35,13 +35,13 @@ export const MultipleSelectDropdown = ({
loadingItems: boolean;
}) => {
const { closeDropdown } = useDropdown();
const { selectedItemIdState } = useSelectableListStates({
selectableListScopeId: selectableListId,
});
const { resetSelectedItem } = useSelectableList(selectableListId);
const selectedItemId = useRecoilValue(selectedItemIdState);
const selectedItemId = useRecoilComponentValueV2(
selectedItemIdComponentState,
selectableListId,
);
const handleItemSelectChange = (
itemToSelect: SelectableItem,
@ -90,7 +90,7 @@ export const MultipleSelectDropdown = ({
return (
<SelectableList
selectableListId={selectableListId}
selectableListInstanceId={selectableListId}
selectableItemIdArray={selectableItemIds}
hotkeyScope={hotkeyScope}
onEnter={(itemId) => {

View File

@ -1,5 +1,4 @@
import { useRef, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum';
import { FieldMultiSelectValue } from '@/object-record/record-field/types/FieldMetadata';
@ -8,14 +7,16 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
import { useSelectableListStates } from '@/ui/layout/selectable-list/hooks/internal/useSelectableListStates';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { isDefined } from 'twenty-shared/utils';
import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly';
import { MenuItemMultiSelectTag } from 'twenty-ui/navigation';
import { SelectOption } from 'twenty-ui/input';
import { MenuItemMultiSelectTag } from 'twenty-ui/navigation';
import { turnIntoEmptyStringIfWhitespacesOnly } from '~/utils/string/turnIntoEmptyStringIfWhitespacesOnly';
type MultiSelectInputProps = {
selectableListComponentInstanceId: string;
@ -34,14 +35,14 @@ export const MultiSelectInput = ({
onCancel,
onOptionSelected,
}: MultiSelectInputProps) => {
const { selectedItemIdState } = useSelectableListStates({
selectableListScopeId: selectableListComponentInstanceId,
});
const { resetSelectedItem } = useSelectableList(
selectableListComponentInstanceId,
);
const selectedItemId = useRecoilValue(selectedItemIdState);
const selectedItemId = useRecoilComponentValueV2(
selectedItemIdComponentState,
selectableListComponentInstanceId,
);
const [searchFilter, setSearchFilter] = useState('');
const containerRef = useRef<HTMLDivElement>(null);
@ -97,7 +98,7 @@ export const MultiSelectInput = ({
return (
<SelectableList
selectableListId={selectableListComponentInstanceId}
selectableListInstanceId={selectableListComponentInstanceId}
selectableItemIdArray={optionIds}
hotkeyScope={hotkeyScope}
onEnter={(itemId) => {

View File

@ -31,7 +31,7 @@ export const SelectInput = ({
}: SelectInputProps) => {
return (
<SelectableList
selectableListId={selectableListComponentInstanceId}
selectableListInstanceId={selectableListComponentInstanceId}
selectableItemIdArray={selectableItemIdArray}
hotkeyScope={hotkeyScope}
onEnter={onEnter}

View File

@ -1,6 +1,5 @@
import styled from '@emotion/styled';
import { useMemo, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
@ -9,10 +8,11 @@ import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/Dropdow
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { arrayToChunks } from '~/utils/array/arrayToChunks';
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { t } from '@lingui/core/macro';
import { IconApps, IconComponent, useIcons } from 'twenty-ui/display';
import {
@ -64,9 +64,10 @@ const IconPickerIcon = ({
selectedIconKey,
Icon,
}: IconPickerIconProps) => {
const { isSelectedItemIdSelector } = useSelectableList();
const isSelectedItemId = useRecoilValue(isSelectedItemIdSelector(iconKey));
const isSelectedItemId = useRecoilComponentValueV2(
selectedItemIdComponentState,
iconKey,
);
return (
<StyledLightIconButton
@ -74,7 +75,7 @@ const IconPickerIcon = ({
aria-label={convertIconKeyToLabel(iconKey)}
size="medium"
title={iconKey}
isSelected={iconKey === selectedIconKey || isSelectedItemId}
isSelected={iconKey === selectedIconKey || !!isSelectedItemId}
Icon={Icon}
onClick={onClick}
/>
@ -175,7 +176,7 @@ export const IconPicker = ({
dropdownWidth={176}
dropdownComponents={
<SelectableList
selectableListId="icon-list"
selectableListInstanceId="icon-list"
selectableItemIdMatrix={iconKeys2d}
hotkeyScope={IconPickerHotkeyScope.IconPicker}
onEnter={(iconKey) => {

View File

@ -1,7 +1,7 @@
import { ReactNode, useEffect, useRef } from 'react';
import { useRecoilValue } from 'recoil';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
import styled from '@emotion/styled';
const StyledContainer = styled.div`
@ -20,9 +20,10 @@ export const SelectableItem = ({
children,
className,
}: SelectableItemProps) => {
const { isSelectedItemIdSelector } = useSelectableList();
const isSelectedItemId = useRecoilValue(isSelectedItemIdSelector(itemId));
const isSelectedItemId = useRecoilComponentFamilyValueV2(
isSelectedItemIdComponentFamilySelector,
itemId,
);
const scrollRef = useRef<HTMLDivElement>(null);

View File

@ -1,34 +1,43 @@
import { ReactNode, useEffect } from 'react';
import { useSelectableListHotKeys } from '@/ui/layout/selectable-list/hooks/internal/useSelectableListHotKeys';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { SelectableListScope } from '@/ui/layout/selectable-list/scopes/SelectableListScope';
import { arrayToChunks } from '~/utils/array/arrayToChunks';
import { SelectableListComponentInstanceContext } from '@/ui/layout/selectable-list/states/contexts/SelectableListComponentInstanceContext';
import { selectableItemIdsComponentState } from '@/ui/layout/selectable-list/states/selectableItemIdsComponentState';
import { selectableListOnEnterComponentState } from '@/ui/layout/selectable-list/states/selectableListOnEnterComponentState';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { isDefined } from 'twenty-shared/utils';
import { arrayToChunks } from '~/utils/array/arrayToChunks';
type SelectableListProps = {
children: ReactNode;
selectableListId: string;
selectableItemIdArray?: string[];
selectableItemIdMatrix?: string[][];
onSelect?: (selected: string) => void;
hotkeyScope: string;
onEnter?: (itemId: string) => void;
selectableListInstanceId: string;
};
export const SelectableList = ({
children,
selectableListId,
hotkeyScope,
selectableItemIdArray,
selectableItemIdMatrix,
selectableListInstanceId,
onEnter,
onSelect,
}: SelectableListProps) => {
useSelectableListHotKeys(selectableListId, hotkeyScope, onSelect);
useSelectableListHotKeys(selectableListInstanceId, hotkeyScope, onSelect);
const { setSelectableItemIds, setSelectableListOnEnter, setSelectedItemId } =
useSelectableList(selectableListId);
const setSelectableListOnEnter = useSetRecoilComponentStateV2(
selectableListOnEnterComponentState,
selectableListInstanceId,
);
const setSelectableItemIds = useSetRecoilComponentStateV2(
selectableItemIdsComponentState,
selectableListInstanceId,
);
useEffect(() => {
setSelectableListOnEnter(() => onEnter);
@ -48,16 +57,15 @@ export const SelectableList = ({
if (isDefined(selectableItemIdArray)) {
setSelectableItemIds(arrayToChunks(selectableItemIdArray, 1));
}
}, [
selectableItemIdArray,
selectableItemIdMatrix,
setSelectableItemIds,
setSelectedItemId,
]);
}, [selectableItemIdArray, selectableItemIdMatrix, setSelectableItemIds]);
return (
<SelectableListScope selectableListScopeId={selectableListId}>
<SelectableListComponentInstanceContext.Provider
value={{
instanceId: selectableListInstanceId,
}}
>
{children}
</SelectableListScope>
</SelectableListComponentInstanceContext.Provider>
);
};

View File

@ -1,9 +1,12 @@
import { act } from 'react-dom/test-utils';
import { renderHook } from '@testing-library/react';
import { RecoilRoot, useRecoilState, useRecoilValue } from 'recoil';
import { act } from 'react-dom/test-utils';
import { RecoilRoot } from 'recoil';
import { useSelectableListStates } from '@/ui/layout/selectable-list/hooks/internal/useSelectableListStates';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { selectableItemIdsComponentState } from '@/ui/layout/selectable-list/states/selectableItemIdsComponentState';
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
const selectableListScopeId = 'testId';
const testArr = [['1'], ['2'], ['3']];
@ -13,15 +16,15 @@ describe('useSelectableList', () => {
it('Should setSelectableItemIds', async () => {
const { result } = renderHook(
() => {
const { setSelectableItemIds } = useSelectableList(
const setSelectableItemIds = useSetRecoilComponentStateV2(
selectableItemIdsComponentState,
selectableListScopeId,
);
const { selectableItemIdsState } = useSelectableListStates({
const selectableItemIds = useRecoilComponentValueV2(
selectableItemIdsComponentState,
selectableListScopeId,
});
const selectableItemIds = useRecoilValue(selectableItemIdsState);
);
return {
setSelectableItemIds,
@ -47,13 +50,14 @@ describe('useSelectableList', () => {
() => {
const { resetSelectedItem } = useSelectableList(selectableListScopeId);
const { selectedItemIdState } = useSelectableListStates({
const selectedItemId = useRecoilComponentValueV2(
selectedItemIdComponentState,
selectableListScopeId,
});
const [selectedItemId, setSelectedItemId] =
useRecoilState(selectedItemIdState);
);
const setSelectedItemId = useSetRecoilComponentStateV2(
selectedItemIdComponentState,
selectableListScopeId,
);
return {
resetSelectedItem,
selectedItemId,

View File

@ -2,14 +2,17 @@ import { isNonEmptyString } from '@sniptt/guards';
import { useRecoilCallback } from 'recoil';
import { Key } from 'ts-key-enum';
import { useSelectableListStates } from '@/ui/layout/selectable-list/hooks/internal/useSelectableListStates';
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 { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
type Direction = 'up' | 'down' | 'left' | 'right';
export const useSelectableListHotKeys = (
scopeId: string,
instanceId: string,
hotkeyScope: string,
onSelect?: (itemId: string) => void,
) => {
@ -29,22 +32,20 @@ export const useSelectableListHotKeys = (
}
};
const {
selectedItemIdState,
selectableItemIdsState,
isSelectedItemIdSelector,
selectableListOnEnterState,
} = useSelectableListStates({
selectableListScopeId: scopeId,
});
const handleSelect = useRecoilCallback(
({ snapshot, set }) =>
(direction: Direction) => {
const selectedItemId = getSnapshotValue(snapshot, selectedItemIdState);
const selectedItemId = getSnapshotValue(
snapshot,
selectedItemIdComponentState.atomFamily({
instanceId: instanceId,
}),
);
const selectableItemIds = getSnapshotValue(
snapshot,
selectableItemIdsState,
selectableItemIdsComponentState.atomFamily({
instanceId: instanceId,
}),
);
const currentPosition = findPosition(selectableItemIds, selectedItemId);
@ -104,22 +105,34 @@ export const useSelectableListHotKeys = (
if (selectedItemId !== nextId) {
if (isNonEmptyString(nextId)) {
set(isSelectedItemIdSelector(nextId), true);
set(selectedItemIdState, nextId);
set(
isSelectedItemIdComponentFamilySelector.selectorFamily({
instanceId: instanceId,
familyKey: nextId,
}),
true,
);
set(
selectedItemIdComponentState.atomFamily({
instanceId: instanceId,
}),
nextId,
);
onSelect?.(nextId);
}
if (isNonEmptyString(selectedItemId)) {
set(isSelectedItemIdSelector(selectedItemId), false);
set(
isSelectedItemIdComponentFamilySelector.selectorFamily({
instanceId: instanceId,
familyKey: selectedItemId,
}),
false,
);
}
}
},
[
isSelectedItemIdSelector,
onSelect,
selectableItemIdsState,
selectedItemIdState,
],
[instanceId, onSelect],
);
useScopedHotkeys(Key.ArrowUp, () => handleSelect('up'), hotkeyScope, []);
@ -142,18 +155,22 @@ export const useSelectableListHotKeys = (
() => {
const selectedItemId = getSnapshotValue(
snapshot,
selectedItemIdState,
selectedItemIdComponentState.atomFamily({
instanceId: instanceId,
}),
);
const onEnter = getSnapshotValue(
snapshot,
selectableListOnEnterState,
selectableListOnEnterComponentState.atomFamily({
instanceId: instanceId,
}),
);
if (isNonEmptyString(selectedItemId)) {
onEnter?.(selectedItemId);
}
},
[selectableListOnEnterState, selectedItemIdState],
[instanceId],
),
hotkeyScope,
[],

View File

@ -1,41 +0,0 @@
import { SelectableListScopeInternalContext } from '@/ui/layout/selectable-list/scopes/scope-internal-context/SelectableListScopeInternalContext';
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 { extractComponentFamilyState } from '@/ui/utilities/state/component-state/utils/extractComponentFamilyState';
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
type useSelectableListStatesProps = {
selectableListScopeId?: string;
};
export const useSelectableListStates = ({
selectableListScopeId,
}: useSelectableListStatesProps) => {
const scopeId = useAvailableScopeIdOrThrow(
SelectableListScopeInternalContext,
selectableListScopeId,
);
return {
scopeId,
isSelectedItemIdSelector: extractComponentFamilyState(
isSelectedItemIdFamilySelector,
scopeId,
),
selectableItemIdsState: extractComponentState(
selectableItemIdsComponentState,
scopeId,
),
selectableListOnEnterState: extractComponentState(
selectableListOnEnterComponentState,
scopeId,
),
selectedItemIdState: extractComponentState(
selectedItemIdComponentState,
scopeId,
),
};
};

View File

@ -1,4 +1,4 @@
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { isNonEmptyString } from '@sniptt/guards';
@ -7,15 +7,15 @@ import { Key } from 'ts-key-enum';
export const useListenToEnterHotkeyOnListItem = ({
hotkeyScope,
itemId,
onEnter,
}: {
hotkeyScope: string;
itemId: string;
onEnter: () => void;
}) => {
const { selectedItemIdState } = useSelectableList();
useScopedHotkeys(
Key.Enter,
useRecoilCallback(
@ -23,17 +23,19 @@ export const useListenToEnterHotkeyOnListItem = ({
() => {
const selectedItemId = getSnapshotValue(
snapshot,
selectedItemIdState,
selectedItemIdComponentState.atomFamily({
instanceId: itemId,
}),
);
if (isNonEmptyString(selectedItemId) && selectedItemId === itemId) {
onEnter?.();
}
},
[itemId, onEnter, selectedItemIdState],
[itemId, onEnter],
),
hotkeyScope,
[selectedItemIdState, itemId, onEnter],
[itemId, onEnter],
{
preventDefault: false,
},

View File

@ -1,60 +1,85 @@
import { useRecoilCallback, useSetRecoilState } from 'recoil';
import { useRecoilCallback } from 'recoil';
import { useSelectableListStates } from '@/ui/layout/selectable-list/hooks/internal/useSelectableListStates';
import { SelectableListComponentInstanceContext } from '@/ui/layout/selectable-list/states/contexts/SelectableListComponentInstanceContext';
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { isDefined } from 'twenty-shared/utils';
export const useSelectableList = (selectableListId?: string) => {
const {
scopeId,
selectableItemIdsState,
selectableListOnEnterState,
isSelectedItemIdSelector,
selectedItemIdState,
} = useSelectableListStates({
selectableListScopeId: selectableListId,
});
const setSelectableItemIds = useSetRecoilState(selectableItemIdsState);
const setSelectableListOnEnter = useSetRecoilState(
selectableListOnEnterState,
export const useSelectableList = (instanceId?: string) => {
const selectableListInstanceId = useAvailableComponentInstanceIdOrThrow(
SelectableListComponentInstanceContext,
instanceId,
);
const resetSelectedItem = useRecoilCallback(
({ snapshot, set }) =>
() => {
const selectedItemId = getSnapshotValue(snapshot, selectedItemIdState);
const selectedItemId = getSnapshotValue(
snapshot,
selectedItemIdComponentState.atomFamily({
instanceId: selectableListInstanceId,
}),
);
if (isDefined(selectedItemId)) {
set(selectedItemIdState, null);
set(isSelectedItemIdSelector(selectedItemId), false);
set(
selectedItemIdComponentState.atomFamily({
instanceId: selectableListInstanceId,
}),
null,
);
set(
isSelectedItemIdComponentFamilySelector.selectorFamily({
instanceId: selectableListInstanceId,
familyKey: selectedItemId,
}),
false,
);
}
},
[selectedItemIdState, isSelectedItemIdSelector],
[selectableListInstanceId],
);
const setSelectedItemId = useRecoilCallback(
({ set, snapshot }) =>
(itemId: string) => {
const selectedItemId = getSnapshotValue(snapshot, selectedItemIdState);
const selectedItemId = getSnapshotValue(
snapshot,
selectedItemIdComponentState.atomFamily({
instanceId: selectableListInstanceId,
}),
);
if (isDefined(selectedItemId)) {
set(isSelectedItemIdSelector(selectedItemId), false);
set(
isSelectedItemIdComponentFamilySelector.selectorFamily({
instanceId: selectableListInstanceId,
familyKey: selectedItemId,
}),
false,
);
}
set(selectedItemIdState, itemId);
set(isSelectedItemIdSelector(itemId), true);
set(
selectedItemIdComponentState.atomFamily({
instanceId: selectableListInstanceId,
}),
itemId,
);
set(
isSelectedItemIdComponentFamilySelector.selectorFamily({
instanceId: selectableListInstanceId,
familyKey: itemId,
}),
true,
);
},
[selectedItemIdState, isSelectedItemIdSelector],
[selectableListInstanceId],
);
return {
selectableListId: scopeId,
setSelectableItemIds,
isSelectedItemIdSelector,
setSelectableListOnEnter,
resetSelectedItem,
setSelectedItemId,
selectedItemIdState,
};
};

View File

@ -1,21 +0,0 @@
import { ReactNode } from 'react';
import { SelectableListScopeInternalContext } from './scope-internal-context/SelectableListScopeInternalContext';
type SelectableListScopeProps = {
children: ReactNode;
selectableListScopeId: string;
};
export const SelectableListScope = ({
children,
selectableListScopeId,
}: SelectableListScopeProps) => {
return (
<SelectableListScopeInternalContext.Provider
value={{ scopeId: selectableListScopeId }}
>
{children}
</SelectableListScopeInternalContext.Provider>
);
};

View File

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

View File

@ -0,0 +1,4 @@
import { createComponentInstanceContext } from '@/ui/utilities/state/component-state/utils/createComponentInstanceContext';
export const SelectableListComponentInstanceContext =
createComponentInstanceContext();

View File

@ -1,9 +1,9 @@
import { createComponentFamilyState } from '@/ui/utilities/state/component-state/utils/createComponentFamilyState';
import { SelectableListComponentInstanceContext } from '@/ui/layout/selectable-list/states/contexts/SelectableListComponentInstanceContext';
import { createComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentFamilyStateV2';
export const isSelectedItemIdComponentFamilyState = createComponentFamilyState<
boolean,
string
>({
key: 'isSelectedItemIdComponentFamilyState',
defaultValue: false,
});
export const isSelectedItemIdComponentFamilyState =
createComponentFamilyStateV2<boolean, string>({
key: 'isSelectedItemIdComponentFamilyState',
defaultValue: false,
componentInstanceContext: SelectableListComponentInstanceContext,
});

View File

@ -1,8 +1,10 @@
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
import { SelectableListComponentInstanceContext } from '@/ui/layout/selectable-list/states/contexts/SelectableListComponentInstanceContext';
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
export const selectableItemIdsComponentState = createComponentState<string[][]>(
{
key: 'selectableItemIdsComponentState',
defaultValue: [[]],
},
);
export const selectableItemIdsComponentState = createComponentStateV2<
string[][]
>({
key: 'selectableItemIdsComponentState',
defaultValue: [[]],
componentInstanceContext: SelectableListComponentInstanceContext,
});

View File

@ -1,8 +1,10 @@
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
import { SelectableListComponentInstanceContext } from '@/ui/layout/selectable-list/states/contexts/SelectableListComponentInstanceContext';
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
export const selectableListOnEnterComponentState = createComponentState<
export const selectableListOnEnterComponentState = createComponentStateV2<
((itemId: string) => void) | undefined
>({
key: 'selectableListOnEnterComponentState',
defaultValue: undefined,
componentInstanceContext: SelectableListComponentInstanceContext,
});

View File

@ -1,8 +1,10 @@
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
import { SelectableListComponentInstanceContext } from '@/ui/layout/selectable-list/states/contexts/SelectableListComponentInstanceContext';
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
export const selectedItemIdComponentState = createComponentState<string | null>(
{
key: 'selectedItemIdComponentState',
defaultValue: null,
},
);
export const selectedItemIdComponentState = createComponentStateV2<
string | null
>({
key: 'selectedItemIdComponentState',
defaultValue: null,
componentInstanceContext: SelectableListComponentInstanceContext,
});

View File

@ -0,0 +1,28 @@
import { SelectableListComponentInstanceContext } from '@/ui/layout/selectable-list/states/contexts/SelectableListComponentInstanceContext';
import { isSelectedItemIdComponentFamilyState } from '@/ui/layout/selectable-list/states/isSelectedItemIdComponentFamilyState';
import { createComponentFamilySelectorV2 } from '@/ui/utilities/state/component-state/utils/createComponentFamilySelectorV2';
export const isSelectedItemIdComponentFamilySelector =
createComponentFamilySelectorV2<boolean, string>({
key: 'isSelectedItemIdComponentFamilySelector',
componentInstanceContext: SelectableListComponentInstanceContext,
get:
({ instanceId, familyKey }: { instanceId: string; familyKey: string }) =>
({ get }) =>
get(
isSelectedItemIdComponentFamilyState.atomFamily({
instanceId: instanceId,
familyKey: familyKey,
}),
),
set:
({ instanceId, familyKey }: { instanceId: string; familyKey: string }) =>
({ set }, newValue) =>
set(
isSelectedItemIdComponentFamilyState.atomFamily({
instanceId: instanceId,
familyKey: familyKey,
}),
newValue,
),
});

View File

@ -1,28 +0,0 @@
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,4 +1,5 @@
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { ComponentFamilySelectorV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilySelectorV2';
import { ComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilyStateV2';
import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap';
import { SerializableParam, useRecoilState } from 'recoil';
@ -7,7 +8,9 @@ export const useRecoilComponentFamilyStateV2 = <
StateType,
FamilyKey extends SerializableParam,
>(
componentState: ComponentFamilyStateV2<StateType, FamilyKey>,
componentState:
| ComponentFamilyStateV2<StateType, FamilyKey>
| ComponentFamilySelectorV2<StateType, FamilyKey>,
familyKey: FamilyKey,
instanceIdFromProps?: string,
) => {
@ -26,5 +29,10 @@ export const useRecoilComponentFamilyStateV2 = <
instanceIdFromProps,
);
return useRecoilState(componentState.atomFamily({ instanceId, familyKey }));
const familySelector =
componentState.type === 'ComponentFamilyState'
? componentState.atomFamily({ instanceId, familyKey })
: componentState.selectorFamily({ instanceId, familyKey });
return useRecoilState(familySelector);
};

View File

@ -16,6 +16,7 @@ export function createComponentFamilySelectorV2<
>(options: {
key: string;
get: SelectorGetter<ValueType, ComponentFamilyStateKeyV2<FamilyKey>>;
set?: never;
componentInstanceContext: ComponentInstanceStateContext<any> | null;
}): ComponentFamilyReadOnlySelectorV2<ValueType, FamilyKey>;