Migrate dropdown to jotai (#18063)

Here we go again
This commit is contained in:
Charles Bochet
2026-02-19 00:58:26 +01:00
committed by GitHub
parent 66deb8be63
commit 36c2b0e23b
54 changed files with 599 additions and 370 deletions
@@ -9,6 +9,8 @@ import { SOURCE_LOCALE } from 'twenty-shared/translations';
// eslint-disable-next-line no-restricted-imports
import { RootDecorator } from '../src/testing/decorators/RootDecorator';
// eslint-disable-next-line no-restricted-imports
import { resetJotaiStore } from '../src/modules/ui/utilities/state/jotai/jotaiStore';
import 'react-loading-skeleton/dist/skeleton.css';
import 'twenty-ui/style.css';
@@ -84,6 +86,10 @@ const preview: Preview = {
RootDecorator,
],
beforeEach: () => {
resetJotaiStore();
},
loaders: [mswLoader],
parameters: {
@@ -1,4 +1,5 @@
import { type Meta, type StoryObj } from '@storybook/react-vite';
import { Provider as JotaiProvider } from 'jotai';
import { RecoilRoot } from 'recoil';
import * as test from 'storybook/test';
import { expect, userEvent, waitFor, within } from 'storybook/test';
@@ -10,6 +11,7 @@ import { ActionMenuComponentInstanceContext } from '@/action-menu/states/context
import { recordIndexActionMenuDropdownPositionComponentState } from '@/action-menu/states/recordIndexActionMenuDropdownPositionComponentState';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
import { RouterDecorator } from 'twenty-ui/testing';
import { ContextStoreDecorator } from '~/testing/decorators/ContextStoreDecorator';
@@ -21,44 +23,48 @@ const meta: Meta<typeof RecordIndexActionMenuDropdown> = {
title: 'Modules/ActionMenu/RecordIndexActionMenuDropdown',
component: RecordIndexActionMenuDropdown,
decorators: [
(Story) => (
<RecoilRoot
initializeState={({ set }) => {
set(
recordIndexActionMenuDropdownPositionComponentState.atomFamily({
instanceId: 'action-menu-dropdown-story',
}),
{ x: 10, y: 10 },
);
(Story) => {
jotaiStore.set(
isDropdownOpenComponentState.atomFamily({
instanceId: 'action-menu-dropdown-story-action-menu',
}),
true,
);
set(
isDropdownOpenComponentState.atomFamily({
instanceId: 'action-menu-dropdown-story-action-menu',
}),
true,
);
}}
>
<ActionMenuComponentInstanceContext.Provider
value={{ instanceId: 'story-action-menu' }}
>
<ActionMenuContext.Provider
value={{
isInRightDrawer: true,
displayType: 'dropdownItem',
actionMenuType: 'index-page-action-menu-dropdown',
actions: createMockActionMenuActions({
deleteMock,
addToFavoritesMock,
exportMock,
}),
return (
<JotaiProvider store={jotaiStore}>
<RecoilRoot
initializeState={({ set }) => {
set(
recordIndexActionMenuDropdownPositionComponentState.atomFamily({
instanceId: 'action-menu-dropdown-story',
}),
{ x: 10, y: 10 },
);
}}
>
<Story />
</ActionMenuContext.Provider>
</ActionMenuComponentInstanceContext.Provider>
</RecoilRoot>
),
<ActionMenuComponentInstanceContext.Provider
value={{ instanceId: 'story-action-menu' }}
>
<ActionMenuContext.Provider
value={{
isInRightDrawer: true,
displayType: 'dropdownItem',
actionMenuType: 'index-page-action-menu-dropdown',
actions: createMockActionMenuActions({
deleteMock,
addToFavoritesMock,
exportMock,
}),
}}
>
<Story />
</ActionMenuContext.Provider>
</ActionMenuComponentInstanceContext.Provider>
</RecoilRoot>
</JotaiProvider>
);
},
ContextStoreDecorator,
RouterDecorator,
],
@@ -9,7 +9,7 @@ import {
} from '@/ui/layout/dropdown/components/Dropdown';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
export type CommandMenuItemDropdownProps = CommandMenuItemProps &
Pick<
@@ -31,7 +31,7 @@ export const CommandMenuItemDropdown = ({
dropdownId,
disabled = false,
}: CommandMenuItemDropdownProps) => {
const isDropdownOpen = useRecoilComponentValue(
const isDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
dropdownId,
);
@@ -26,6 +26,7 @@ import { currentFavoriteFolderIdStateV2 } from '@/ui/navigation/navigation-drawe
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
import { getNavigationSubItemLeftAdornment } from '@/ui/navigation/navigation-drawer/utils/getNavigationSubItemLeftAdornment';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { Droppable } from '@hello-pangea/dnd';
import { useLingui } from '@lingui/react/macro';
import { useContext, useState } from 'react';
@@ -95,7 +96,7 @@ export const CurrentWorkspaceMemberFavorites = ({
const dropdownId = `favorite-folder-edit-${folder.folderId}`;
const isDropdownOpenComponent = useRecoilComponentValue(
const isDropdownOpenComponent = useRecoilComponentValueV2(
isDropdownOpenComponentState,
dropdownId,
);
@@ -45,6 +45,7 @@ import { currentNavigationMenuItemFolderIdStateV2 } from '@/ui/navigation/naviga
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
import { getNavigationSubItemLeftAdornment } from '@/ui/navigation/navigation-drawer/utils/getNavigationSubItemLeftAdornment';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { isNonEmptyString } from '@sniptt/guards';
import { isDefined } from 'twenty-shared/utils';
@@ -123,7 +124,7 @@ export const CurrentWorkspaceMemberNavigationMenuItems = ({
const dropdownId = `navigation-menu-item-folder-edit-${folder.id}`;
const isDropdownOpenComponent = useRecoilComponentValue(
const isDropdownOpenComponent = useRecoilComponentValueV2(
isDropdownOpenComponentState,
dropdownId,
);
@@ -10,7 +10,7 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
import { DROPDOWN_OFFSET_Y } from '@/ui/layout/dropdown/constants/DropdownOffsetY';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { type ViewType } from '@/views/types/ViewType';
import { Trans } from '@lingui/react/macro';
@@ -28,7 +28,7 @@ export const ObjectOptionsDropdown = ({
const { currentContentId, handleContentChange, handleResetContent } =
useDropdownContextCurrentContentId<ObjectOptionsContentId>();
const isDropdownOpen = useRecoilComponentValue(
const isDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
OBJECT_OPTIONS_DROPDOWN_ID,
);
@@ -27,6 +27,7 @@ import { SelectableListItem } from '@/ui/layout/selectable-list/components/Selec
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { Trans, useLingui } from '@lingui/react/macro';
import { useRecoilValue } from 'recoil';
@@ -138,7 +139,7 @@ export const ObjectSortDropdownButton = () => {
setIsRecordSortDirectionMenuUnfolded(false);
};
const isDropdownOpen = useRecoilComponentValue(
const isDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
OBJECT_SORT_DROPDOWN_ID,
);
@@ -1,6 +1,6 @@
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import styled from '@emotion/styled';
import { type Nullable } from 'twenty-shared/types';
import { Tag } from 'twenty-ui/components';
@@ -23,7 +23,7 @@ export const RecordBoardColumnHeaderAggregateDropdownButton = ({
value?: Nullable<string | number>;
tooltip?: Nullable<string>;
}) => {
const isDropdownOpen = useRecoilComponentValue(
const isDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
dropdownId,
);
@@ -12,7 +12,7 @@ import { type FieldMorphRelationMetadata } from '@/object-record/record-field/ui
import { getRecordFieldCardRelationPickerDropdownId } from '@/object-record/record-show/utils/getRecordFieldCardRelationPickerDropdownId';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { RecordDetailMorphRelationSectionDropdown } from '@/object-record/record-field-list/record-detail-section/relation/components/RecordDetailMorphRelationSectionDropdown';
import { RecordDetailRelationRecordsList } from '@/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationRecordsList';
@@ -49,7 +49,7 @@ export const RecordDetailMorphRelationSection = ({
instanceId: scopeInstanceId,
});
const isDropdownOpen = useRecoilComponentValue(
const isDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
dropdownId,
);
@@ -16,7 +16,7 @@ import { getRecordFieldCardRelationPickerDropdownId } from '@/object-record/reco
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { dropdownPlacementComponentState } from '@/ui/layout/dropdown/states/dropdownPlacementComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { FieldMetadataType } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
@@ -65,7 +65,7 @@ export const RecordDetailMorphRelationSectionDropdownManyToOne = ({
const { closeDropdown } = useCloseDropdown();
const dropdownPlacement = useRecoilComponentValue(
const dropdownPlacement = useRecoilComponentValueV2(
dropdownPlacementComponentState,
dropdownId,
);
@@ -18,7 +18,7 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { dropdownPlacementComponentState } from '@/ui/layout/dropdown/states/dropdownPlacementComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { FieldMetadataType } from 'twenty-shared/types';
import { CustomError, isDefined } from 'twenty-shared/utils';
@@ -68,7 +68,7 @@ export const RecordDetailMorphRelationSectionDropdownOneToMany = ({
const { closeDropdown } = useCloseDropdown();
const dropdownPlacement = useRecoilComponentValue(
const dropdownPlacement = useRecoilComponentValueV2(
dropdownPlacementComponentState,
dropdownId,
);
@@ -28,7 +28,7 @@ import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { t } from '@lingui/core/macro';
import { Trans } from '@lingui/react/macro';
@@ -152,7 +152,7 @@ export const RecordDetailRelationRecordsListItem = ({
const dropdownInstanceId = `record-field-card-menu:${scopeInstanceId}:${relationFieldMetadataId}:${relationRecord.id}`;
const { closeDropdown } = useCloseDropdown();
const isDropdownOpen = useRecoilComponentValue(
const isDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
dropdownInstanceId,
);
@@ -21,7 +21,7 @@ import { AggregateOperations } from '@/object-record/record-table/constants/Aggr
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { coreIndexViewIdFromObjectMetadataItemFamilySelector } from '@/views/states/selectors/coreIndexViewIdFromObjectMetadataItemFamilySelector';
import { useLingui } from '@lingui/react/macro';
import {
@@ -100,7 +100,7 @@ export const RecordDetailRelationSection = ({
instanceId: scopeInstanceId,
});
const isDropdownOpen = useRecoilComponentValue(
const isDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
dropdownId,
);
@@ -21,7 +21,7 @@ import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { dropdownPlacementComponentState } from '@/ui/layout/dropdown/states/dropdownPlacementComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { CustomError, isDefined } from 'twenty-shared/utils';
import { IconPlus } from 'twenty-ui/display';
@@ -85,7 +85,7 @@ export const RecordDetailRelationSectionDropdownToMany = ({
const { closeDropdown } = useCloseDropdown();
const dropdownPlacement = useRecoilComponentValue(
const dropdownPlacement = useRecoilComponentValueV2(
dropdownPlacementComponentState,
dropdownId,
);
@@ -18,7 +18,7 @@ import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { dropdownPlacementComponentState } from '@/ui/layout/dropdown/states/dropdownPlacementComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
@@ -96,7 +96,7 @@ export const RecordDetailRelationSectionDropdownToOne = ({
const { closeDropdown } = useCloseDropdown();
const dropdownPlacement = useRecoilComponentValue(
const dropdownPlacement = useRecoilComponentValueV2(
dropdownPlacementComponentState,
dropdownId,
);
@@ -20,7 +20,7 @@ import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDrop
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById';
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { isStandaloneVariableString } from '@/workflow/utils/isStandaloneVariableString';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
@@ -128,7 +128,7 @@ export const FormArrayFieldInput = ({
const containerRef = useRef<HTMLDivElement>(null);
const dropdownId = `dropdown-${instanceId}`;
const isDropdownOpen = useRecoilComponentValue(
const isDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
dropdownId,
);
@@ -4,7 +4,7 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { MenuItemWithOptionDropdown } from '@/ui/navigation/menu-item/components/MenuItemWithOptionDropdown';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import React, { useState } from 'react';
import {
IconBookmark,
@@ -44,7 +44,7 @@ export const MultiItemFieldMenuItem = <T,>({
}: MultiItemFieldMenuItemProps<T>) => {
const [isHovered, setIsHovered] = useState(false);
const { closeDropdown } = useCloseDropdown();
const isDropdownOpen = useRecoilComponentValue(
const isDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
dropdownId,
);
@@ -19,7 +19,7 @@ import { usePersistFieldFromFieldInputContext } from '@/object-record/record-fie
import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropdownFocusIdForRecordField';
import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId';
import { activeDropdownFocusIdState } from '@/ui/layout/dropdown/states/activeDropdownFocusIdState';
import { useRecoilCallback } from 'recoil';
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
import { useIcons } from 'twenty-ui/display';
import { RecordInlineCellContainer } from './RecordInlineCellContainer';
import {
@@ -133,37 +133,36 @@ export const RecordInlineCell = ({
closeInlineCell();
};
const handleClickOutside = useRecoilCallback(
({ snapshot }) =>
({
event,
newValue,
skipPersist,
}: Parameters<FieldInputClickOutsideEvent>[0]) => {
const currentDropdownFocusId = snapshot
.getLoadable(activeDropdownFocusIdState)
.getValue();
const handleClickOutside = useCallback(
({
event,
newValue,
skipPersist,
}: Parameters<FieldInputClickOutsideEvent>[0]) => {
const currentDropdownFocusId = jotaiStore.get(
activeDropdownFocusIdState.atom,
);
const expectedDropdownFocusId = getDropdownFocusIdForRecordField({
recordId,
fieldMetadataId: fieldDefinition.fieldMetadataId,
componentType: 'inline-cell',
instanceId: scopeInstanceId,
});
const expectedDropdownFocusId = getDropdownFocusIdForRecordField({
recordId,
fieldMetadataId: fieldDefinition.fieldMetadataId,
componentType: 'inline-cell',
instanceId: scopeInstanceId,
});
if (currentDropdownFocusId !== expectedDropdownFocusId) {
return;
}
if (currentDropdownFocusId !== expectedDropdownFocusId) {
return;
}
event?.preventDefault();
event?.stopImmediatePropagation();
event?.preventDefault();
event?.stopImmediatePropagation();
if (skipPersist !== true) {
persistFieldFromFieldInputContext(newValue);
}
if (skipPersist !== true) {
persistFieldFromFieldInputContext(newValue);
}
closeInlineCell();
},
closeInlineCell();
},
[
recordId,
fieldDefinition.fieldMetadataId,
@@ -6,6 +6,7 @@ import { RecordTableColumnAggregateFooterValue } from '@/object-record/record-ta
import { hasAggregateOperationForViewFieldFamilySelector } from '@/object-record/record-table/record-table-footer/states/hasAggregateOperationForViewFieldFamilySelector';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useContext, useState } from 'react';
@@ -57,7 +58,7 @@ export const RecordTableColumnAggregateFooterValueCell = ({
}) => {
const [isHovered, setIsHovered] = useState(false);
const isDropdownOpen = useRecoilComponentValue(
const isDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
dropdownId,
);
@@ -24,7 +24,7 @@ import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropd
import { FieldWidgetInlineCellContainer } from '@/page-layout/widgets/field/components/FieldWidgetInlineCellContainer';
import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId';
import { activeDropdownFocusIdState } from '@/ui/layout/dropdown/states/activeDropdownFocusIdState';
import { useRecoilCallback } from 'recoil';
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
type FieldWidgetInlineCellProps = {
loading?: boolean;
@@ -132,37 +132,36 @@ export const FieldWidgetInlineCell = ({
closeInlineCell();
};
const handleClickOutside = useRecoilCallback(
({ snapshot }) =>
({
event,
newValue,
skipPersist,
}: Parameters<FieldInputClickOutsideEvent>[0]) => {
const currentDropdownFocusId = snapshot
.getLoadable(activeDropdownFocusIdState)
.getValue();
const handleClickOutside = useCallback(
({
event,
newValue,
skipPersist,
}: Parameters<FieldInputClickOutsideEvent>[0]) => {
const currentDropdownFocusId = jotaiStore.get(
activeDropdownFocusIdState.atom,
);
const expectedDropdownFocusId = getDropdownFocusIdForRecordField({
recordId,
fieldMetadataId: fieldDefinition.fieldMetadataId,
componentType: 'inline-cell',
instanceId: scopeInstanceId,
});
const expectedDropdownFocusId = getDropdownFocusIdForRecordField({
recordId,
fieldMetadataId: fieldDefinition.fieldMetadataId,
componentType: 'inline-cell',
instanceId: scopeInstanceId,
});
if (currentDropdownFocusId !== expectedDropdownFocusId) {
return;
}
if (currentDropdownFocusId !== expectedDropdownFocusId) {
return;
}
event?.preventDefault();
event?.stopImmediatePropagation();
event?.preventDefault();
event?.stopImmediatePropagation();
if (skipPersist !== true) {
persistFieldFromFieldInputContext(newValue);
}
if (skipPersist !== true) {
persistFieldFromFieldInputContext(newValue);
}
closeInlineCell();
},
closeInlineCell();
},
[
closeInlineCell,
recordId,
@@ -20,7 +20,7 @@ import { isFieldMorphRelation } from '@/object-record/record-field/ui/types/guar
import { getRecordFieldCardRelationPickerDropdownId } from '@/object-record/record-show/utils/getRecordFieldCardRelationPickerDropdownId';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { css } from '@emotion/react';
import styled from '@emotion/styled';
import { CustomError } from 'twenty-shared/utils';
@@ -99,7 +99,7 @@ export const FieldWidgetRelationEditAction = ({
instanceId: scopeInstanceId,
});
const isRelationSelectionDropdownOpen = useRecoilComponentValue(
const isRelationSelectionDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
relationSelectionDropdownId,
);
@@ -13,7 +13,7 @@ import { SELECT_COUNTRY_DROPDOWN_ID } from '@/ui/input/components/internal/count
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { activeDropdownFocusIdState } from '@/ui/layout/dropdown/states/activeDropdownFocusIdState';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { useRecoilValue } from 'recoil';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { isDefined } from 'twenty-shared/utils';
import { MOBILE_VIEWPORT } from 'twenty-ui/theme';
import { v4 } from 'uuid';
@@ -236,7 +236,7 @@ export const AddressInput = ({
onShiftTab: handleShiftTab,
});
const activeDropdownFocusId = useRecoilValue(activeDropdownFocusIdState);
const activeDropdownFocusId = useRecoilValueV2(activeDropdownFocusIdState);
useListenClickOutside({
refs: [wrapperRef],
@@ -10,7 +10,7 @@ import { PhoneCountryPickerDropdownSelect } from './PhoneCountryPickerDropdownSe
import { PHONE_COUNTRY_CODE_PICKER_DROPDOWN_ID } from '@/ui/input/components/internal/phone/constants/PhoneCountryCodePickerDropdownId';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import 'react-phone-number-input/style.css';
import { isDefined } from 'twenty-shared/utils';
import { IconChevronDown, IconWorld } from 'twenty-ui/display';
@@ -78,7 +78,7 @@ export const PhoneCountryPickerDropdownButton = ({
const [selectedCountry, setSelectedCountry] = useState<Country>();
const isDropdownOpen = useRecoilComponentValue(
const isDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
PHONE_COUNTRY_CODE_PICKER_DROPDOWN_ID,
);
@@ -13,8 +13,8 @@ import { dropdownYPositionComponentState } from '@/ui/layout/dropdown/states/int
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { type DropdownOffset } from '@/ui/layout/dropdown/types/DropdownOffset';
import { type GlobalHotkeysConfig } from '@/ui/utilities/hotkey/types/GlobalHotkeysConfig';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2';
import styled from '@emotion/styled';
import {
type Placement,
@@ -24,10 +24,9 @@ import {
size,
useFloating,
} from '@floating-ui/react';
import { type MouseEvent, type ReactNode } from 'react';
import { type MouseEvent, type ReactNode, useCallback } from 'react';
import { flushSync } from 'react-dom';
import { type Keys } from 'react-hotkeys-hook';
import { useRecoilCallback } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { useIsMobile } from 'twenty-ui/utilities';
@@ -89,7 +88,7 @@ export const Dropdown = ({
disableClickForClickableComponent = false,
middlewareBoundaryPadding = {},
}: DropdownProps) => {
const isDropdownOpen = useRecoilComponentValue(
const isDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
dropdownId,
);
@@ -108,17 +107,17 @@ export const Dropdown = ({
]
: [];
const setDropdownMaxHeight = useSetRecoilComponentState(
const setDropdownMaxHeight = useSetRecoilComponentStateV2(
dropdownMaxHeightComponentState,
dropdownId,
);
const setDropdownMaxWidth = useSetRecoilComponentState(
const setDropdownMaxWidth = useSetRecoilComponentStateV2(
dropdownMaxWidthComponentState,
dropdownId,
);
const setDropdownYPosition = useSetRecoilComponentState(
const setDropdownYPosition = useSetRecoilComponentStateV2(
dropdownYPositionComponentState,
dropdownId,
);
@@ -173,8 +172,8 @@ export const Dropdown = ({
strategy: dropdownStrategy,
});
const handleClickableComponentClick = useRecoilCallback(
() => async (event: MouseEvent) => {
const handleClickableComponentClick = useCallback(
async (event: MouseEvent) => {
if (disableClickForClickableComponent) return;
event.stopPropagation();
event.preventDefault();
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
export const DropdownOnToggleEffect = ({
onDropdownClose,
@@ -10,7 +10,9 @@ export const DropdownOnToggleEffect = ({
onDropdownClose?: () => void;
onDropdownOpen?: () => void;
}) => {
const isDropdownOpen = useRecoilComponentValue(isDropdownOpenComponentState);
const isDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
);
const [currentIsDropdownOpen, setCurrentIsDropdownOpen] =
useState(isDropdownOpen);
@@ -11,8 +11,9 @@ import { HotkeyEffect } from '@/ui/utilities/hotkey/components/HotkeyEffect';
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
import { ClickOutsideListenerContext } from '@/ui/utilities/pointer-event/contexts/ClickOutsideListenerContext';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2';
import styled from '@emotion/styled';
import {
FloatingPortal,
@@ -21,7 +22,6 @@ import {
} from '@floating-ui/react';
import { useContext, useEffect } from 'react';
import { type Keys } from 'react-hotkeys-hook';
import { useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum';
export const StyledDropdownContentContainer = styled.div<{
@@ -70,23 +70,25 @@ export const DropdownInternalContainer = ({
excludedClickOutsideIds,
isDropdownInModal = false,
}: DropdownInternalContainerProps) => {
const isDropdownOpen = useRecoilComponentValue(isDropdownOpenComponentState);
const isDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
);
const { closeDropdown } = useCloseDropdown();
const activeDropdownFocusId = useRecoilValue(activeDropdownFocusIdState);
const activeDropdownFocusId = useRecoilValueV2(activeDropdownFocusIdState);
const dropdownMaxHeight = useRecoilComponentValue(
const dropdownMaxHeight = useRecoilComponentValueV2(
dropdownMaxHeightComponentState,
dropdownId,
);
const dropdownMaxWidth = useRecoilComponentValue(
const dropdownMaxWidth = useRecoilComponentValueV2(
dropdownMaxWidthComponentState,
dropdownId,
);
const setDropdownPlacement = useSetRecoilComponentState(
const setDropdownPlacement = useSetRecoilComponentStateV2(
dropdownPlacementComponentState,
dropdownId,
);
@@ -1,4 +1,5 @@
import { renderHook } from '@testing-library/react';
import { Provider as JotaiProvider } from 'jotai';
import { act } from 'react';
import { RecoilRoot } from 'recoil';
@@ -6,27 +7,37 @@ import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/
import { useCloseAnyOpenDropdown } from '@/ui/layout/dropdown/hooks/useCloseAnyOpenDropdown';
import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
const dropdownId = 'test-dropdown-id';
const Wrapper = ({ children }: { children: React.ReactNode }) => {
return (
<RecoilRoot>
<DropdownComponentInstanceContext.Provider
value={{ instanceId: dropdownId }}
>
{children}
</DropdownComponentInstanceContext.Provider>
</RecoilRoot>
<JotaiProvider store={jotaiStore}>
<RecoilRoot>
<DropdownComponentInstanceContext.Provider
value={{ instanceId: dropdownId }}
>
{children}
</DropdownComponentInstanceContext.Provider>
</RecoilRoot>
</JotaiProvider>
);
};
describe('useCloseAnyOpenDropdown', () => {
beforeEach(() => {
jotaiStore.set(
isDropdownOpenComponentState.atomFamily({ instanceId: dropdownId }),
false,
);
});
it('should open dropdown and then close it with closeAnyOpenDropdown', async () => {
const { result } = renderHook(
() => {
const isDropdownOpen = useRecoilComponentValue(
const isDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
dropdownId,
);
@@ -1,4 +1,5 @@
import { renderHook } from '@testing-library/react';
import { Provider as JotaiProvider } from 'jotai';
import { act } from 'react';
import { RecoilRoot } from 'recoil';
@@ -6,36 +7,52 @@ import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
const dropdownId = 'test-dropdown-id';
const outsideDropdownId = 'test-dropdown-id-outside';
const Wrapper = ({ children }: { children: React.ReactNode }) => {
return (
<RecoilRoot>
<DropdownComponentInstanceContext.Provider
value={{ instanceId: dropdownId }}
>
{children}
</DropdownComponentInstanceContext.Provider>
<DropdownComponentInstanceContext.Provider
value={{ instanceId: outsideDropdownId }}
></DropdownComponentInstanceContext.Provider>
</RecoilRoot>
<JotaiProvider store={jotaiStore}>
<RecoilRoot>
<DropdownComponentInstanceContext.Provider
value={{ instanceId: dropdownId }}
>
{children}
</DropdownComponentInstanceContext.Provider>
<DropdownComponentInstanceContext.Provider
value={{ instanceId: outsideDropdownId }}
></DropdownComponentInstanceContext.Provider>
</RecoilRoot>
</JotaiProvider>
);
};
describe('useCloseDropdown', () => {
beforeEach(() => {
jotaiStore.set(
isDropdownOpenComponentState.atomFamily({ instanceId: dropdownId }),
false,
);
jotaiStore.set(
isDropdownOpenComponentState.atomFamily({
instanceId: outsideDropdownId,
}),
false,
);
});
it('should close dropdown from inside component instance context', async () => {
const { result } = renderHook(
() => {
const isOutsideDropdownOpen = useRecoilComponentValue(
const isOutsideDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
outsideDropdownId,
);
const isInsideDropdownOpen = useRecoilComponentValue(
const isInsideDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
);
@@ -72,12 +89,12 @@ describe('useCloseDropdown', () => {
it('should close dropdown from outside component instance context', async () => {
const { result } = renderHook(
() => {
const isOutsideDropdownOpen = useRecoilComponentValue(
const isOutsideDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
outsideDropdownId,
);
const isInsideDropdownOpen = useRecoilComponentValue(
const isInsideDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
);
@@ -1,40 +1,57 @@
import { renderHook } from '@testing-library/react';
import { Provider as JotaiProvider } from 'jotai';
import { act } from 'react';
import { RecoilRoot } from 'recoil';
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
const dropdownId = 'test-dropdown-id';
const outsideDropdownId = 'test-dropdown-id-outside';
const Wrapper = ({ children }: { children: React.ReactNode }) => {
return (
<RecoilRoot>
<DropdownComponentInstanceContext.Provider
value={{ instanceId: dropdownId }}
>
{children}
</DropdownComponentInstanceContext.Provider>
<DropdownComponentInstanceContext.Provider
value={{ instanceId: outsideDropdownId }}
></DropdownComponentInstanceContext.Provider>
</RecoilRoot>
<JotaiProvider store={jotaiStore}>
<RecoilRoot>
<DropdownComponentInstanceContext.Provider
value={{ instanceId: dropdownId }}
>
{children}
</DropdownComponentInstanceContext.Provider>
<DropdownComponentInstanceContext.Provider
value={{ instanceId: outsideDropdownId }}
></DropdownComponentInstanceContext.Provider>
</RecoilRoot>
</JotaiProvider>
);
};
describe('useOpenDropdown', () => {
beforeEach(() => {
jotaiStore.set(
isDropdownOpenComponentState.atomFamily({ instanceId: dropdownId }),
false,
);
jotaiStore.set(
isDropdownOpenComponentState.atomFamily({
instanceId: outsideDropdownId,
}),
false,
);
});
it('should open dropdown from inside component instance context', async () => {
const { result } = renderHook(
() => {
const isOutsideDropdownOpen = useRecoilComponentValue(
const isOutsideDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
outsideDropdownId,
);
const isInsideDropdownOpen = useRecoilComponentValue(
const isInsideDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
);
@@ -61,12 +78,12 @@ describe('useOpenDropdown', () => {
it('should open dropdown from outside component instance context', async () => {
const { result } = renderHook(
() => {
const isOutsideDropdownOpen = useRecoilComponentValue(
const isOutsideDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
outsideDropdownId,
);
const isInsideDropdownOpen = useRecoilComponentValue(
const isInsideDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
);
@@ -1,40 +1,57 @@
import { renderHook } from '@testing-library/react';
import { Provider as JotaiProvider } from 'jotai';
import { act } from 'react';
import { RecoilRoot } from 'recoil';
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { useToggleDropdown } from '@/ui/layout/dropdown/hooks/useToggleDropdown';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
const dropdownId = 'test-dropdown-id';
const outsideDropdownId = 'test-dropdown-id-outside';
const Wrapper = ({ children }: { children: React.ReactNode }) => {
return (
<RecoilRoot>
<DropdownComponentInstanceContext.Provider
value={{ instanceId: dropdownId }}
>
{children}
</DropdownComponentInstanceContext.Provider>
<DropdownComponentInstanceContext.Provider
value={{ instanceId: outsideDropdownId }}
></DropdownComponentInstanceContext.Provider>
</RecoilRoot>
<JotaiProvider store={jotaiStore}>
<RecoilRoot>
<DropdownComponentInstanceContext.Provider
value={{ instanceId: dropdownId }}
>
{children}
</DropdownComponentInstanceContext.Provider>
<DropdownComponentInstanceContext.Provider
value={{ instanceId: outsideDropdownId }}
></DropdownComponentInstanceContext.Provider>
</RecoilRoot>
</JotaiProvider>
);
};
describe('useToggleDropdown', () => {
beforeEach(() => {
jotaiStore.set(
isDropdownOpenComponentState.atomFamily({ instanceId: dropdownId }),
false,
);
jotaiStore.set(
isDropdownOpenComponentState.atomFamily({
instanceId: outsideDropdownId,
}),
false,
);
});
it('should toggle dropdown from inside component instance context', async () => {
const { result } = renderHook(
() => {
const isOutsideDropdownOpen = useRecoilComponentValue(
const isOutsideDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
outsideDropdownId,
);
const isInsideDropdownOpen = useRecoilComponentValue(
const isInsideDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
);
const { toggleDropdown } = useToggleDropdown();
@@ -74,12 +91,12 @@ describe('useToggleDropdown', () => {
it('should toggle dropdown from outside component instance context', async () => {
const { result } = renderHook(
() => {
const isOutsideDropdownOpen = useRecoilComponentValue(
const isOutsideDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
outsideDropdownId,
);
const isInsideDropdownOpen = useRecoilComponentValue(
const isInsideDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
);
const { toggleDropdown } = useToggleDropdown();
@@ -1,8 +1,10 @@
import { useCallback } from 'react';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { activeDropdownFocusIdState } from '@/ui/layout/dropdown/states/activeDropdownFocusIdState';
import { previousDropdownFocusIdState } from '@/ui/layout/dropdown/states/previousDropdownFocusIdState';
import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById';
import { useRecoilCallback } from 'recoil';
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
import { isDefined } from 'twenty-shared/utils';
export const useCloseAnyOpenDropdown = () => {
@@ -11,46 +13,41 @@ export const useCloseAnyOpenDropdown = () => {
const { removeFocusItemFromFocusStackById } =
useRemoveFocusItemFromFocusStackById();
const closeAnyOpenDropdown = useRecoilCallback(
({ snapshot, set }) =>
() => {
const previousDropdownFocusId = snapshot
.getLoadable(previousDropdownFocusIdState)
.getValue();
const closeAnyOpenDropdown = useCallback(() => {
const previousDropdownFocusId = jotaiStore.get(
previousDropdownFocusIdState.atom,
);
const activeDropdownFocusId = snapshot
.getLoadable(activeDropdownFocusIdState)
.getValue();
const activeDropdownFocusId = jotaiStore.get(
activeDropdownFocusIdState.atom,
);
const thereIsNoDropdownOpen =
!isDefined(activeDropdownFocusId) &&
!isDefined(previousDropdownFocusId);
const thereIsNoDropdownOpen =
!isDefined(activeDropdownFocusId) && !isDefined(previousDropdownFocusId);
if (thereIsNoDropdownOpen) {
return;
}
if (thereIsNoDropdownOpen) {
return;
}
const thereIsOneNestedDropdownOpen = isDefined(previousDropdownFocusId);
const thereIsOneNestedDropdownOpen = isDefined(previousDropdownFocusId);
if (isDefined(activeDropdownFocusId)) {
closeDropdown(activeDropdownFocusId);
removeFocusItemFromFocusStackById({
focusId: activeDropdownFocusId,
});
}
if (isDefined(activeDropdownFocusId)) {
closeDropdown(activeDropdownFocusId);
removeFocusItemFromFocusStackById({
focusId: activeDropdownFocusId,
});
}
if (thereIsOneNestedDropdownOpen) {
closeDropdown(previousDropdownFocusId);
removeFocusItemFromFocusStackById({
focusId: previousDropdownFocusId,
});
}
if (thereIsOneNestedDropdownOpen) {
closeDropdown(previousDropdownFocusId);
removeFocusItemFromFocusStackById({
focusId: previousDropdownFocusId,
});
}
set(previousDropdownFocusIdState, null);
set(activeDropdownFocusIdState, null);
},
[closeDropdown, removeFocusItemFromFocusStackById],
);
jotaiStore.set(previousDropdownFocusIdState.atom, null);
jotaiStore.set(activeDropdownFocusIdState.atom, null);
}, [closeDropdown, removeFocusItemFromFocusStackById]);
return { closeAnyOpenDropdown };
};
@@ -1,10 +1,12 @@
import { useCallback } from 'react';
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { useGoBackToPreviousDropdownFocusId } from '@/ui/layout/dropdown/hooks/useGoBackToPreviousDropdownFocusId';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById';
import { useAvailableComponentInstanceId } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId';
import { useRecoilCallback } from 'recoil';
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
import { isDefined } from 'twenty-shared/utils';
export const useCloseDropdown = () => {
@@ -17,40 +19,37 @@ export const useCloseDropdown = () => {
const dropdownComponentInstanceIdFromContext =
useAvailableComponentInstanceId(DropdownComponentInstanceContext);
const closeDropdown = useRecoilCallback(
({ set, snapshot }) =>
(dropdownComponentInstanceIdFromProps?: string) => {
const dropdownComponentInstanceId =
dropdownComponentInstanceIdFromProps ??
dropdownComponentInstanceIdFromContext;
const closeDropdown = useCallback(
(dropdownComponentInstanceIdFromProps?: string) => {
const dropdownComponentInstanceId =
dropdownComponentInstanceIdFromProps ??
dropdownComponentInstanceIdFromContext;
if (!isDefined(dropdownComponentInstanceId)) {
throw new Error('Dropdown component instance ID is not defined');
}
if (!isDefined(dropdownComponentInstanceId)) {
throw new Error('Dropdown component instance ID is not defined');
}
const isDropdownOpen = snapshot
.getLoadable(
isDropdownOpenComponentState.atomFamily({
instanceId: dropdownComponentInstanceId,
}),
)
.getValue();
const isDropdownOpen = jotaiStore.get(
isDropdownOpenComponentState.atomFamily({
instanceId: dropdownComponentInstanceId,
}),
);
if (isDropdownOpen) {
removeFocusItemFromFocusStackById({
focusId: dropdownComponentInstanceId,
});
if (isDropdownOpen) {
removeFocusItemFromFocusStackById({
focusId: dropdownComponentInstanceId,
});
goBackToPreviousDropdownFocusId();
goBackToPreviousDropdownFocusId();
set(
isDropdownOpenComponentState.atomFamily({
instanceId: dropdownComponentInstanceId,
}),
false,
);
}
},
jotaiStore.set(
isDropdownOpenComponentState.atomFamily({
instanceId: dropdownComponentInstanceId,
}),
false,
);
}
},
[
removeFocusItemFromFocusStackById,
goBackToPreviousDropdownFocusId,
@@ -1,22 +1,22 @@
import { useRecoilCallback } from 'recoil';
import { useCallback } from 'react';
import { activeDropdownFocusIdState } from '@/ui/layout/dropdown/states/activeDropdownFocusIdState';
import { previousDropdownFocusIdState } from '@/ui/layout/dropdown/states/previousDropdownFocusIdState';
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
// TODO: this won't work for more than 1 nested dropdown
export const useGoBackToPreviousDropdownFocusId = () => {
const goBackToPreviousDropdownFocusId = useRecoilCallback(
({ snapshot, set }) =>
() => {
const previouslyFocusedDropdownId = snapshot
.getLoadable(previousDropdownFocusIdState)
.getValue();
const goBackToPreviousDropdownFocusId = useCallback(() => {
const previouslyFocusedDropdownId = jotaiStore.get(
previousDropdownFocusIdState.atom,
);
set(activeDropdownFocusIdState, previouslyFocusedDropdownId);
set(previousDropdownFocusIdState, null);
},
[],
);
jotaiStore.set(
activeDropdownFocusIdState.atom,
previouslyFocusedDropdownId,
);
jotaiStore.set(previousDropdownFocusIdState.atom, null);
}, []);
return {
goBackToPreviousDropdownFocusId,
@@ -1,3 +1,5 @@
import { useCallback } from 'react';
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious';
@@ -6,7 +8,7 @@ import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePush
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
import { type GlobalHotkeysConfig } from '@/ui/utilities/hotkey/types/GlobalHotkeysConfig';
import { useAvailableComponentInstanceId } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId';
import { useRecoilCallback } from 'recoil';
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
import { isDefined } from 'twenty-shared/utils';
type OpenDropdownArgs = {
@@ -22,44 +24,41 @@ export const useOpenDropdown = () => {
const dropdownComponentInstanceIdFromContext =
useAvailableComponentInstanceId(DropdownComponentInstanceContext);
const openDropdown = useRecoilCallback(
({ set }) =>
(args?: OpenDropdownArgs | null | undefined) => {
const dropdownComponentInstanceId =
args?.dropdownComponentInstanceIdFromProps ??
dropdownComponentInstanceIdFromContext;
const openDropdown = useCallback(
(args?: OpenDropdownArgs | null | undefined) => {
const dropdownComponentInstanceId =
args?.dropdownComponentInstanceIdFromProps ??
dropdownComponentInstanceIdFromContext;
if (!isDefined(dropdownComponentInstanceId)) {
throw new Error('Dropdown component instance ID is not defined');
}
if (!isDefined(dropdownComponentInstanceId)) {
throw new Error('Dropdown component instance ID is not defined');
}
set(
isDropdownOpenComponentState.atomFamily({
instanceId: dropdownComponentInstanceId,
}),
true,
);
jotaiStore.set(
isDropdownOpenComponentState.atomFamily({
instanceId: dropdownComponentInstanceId,
}),
true,
);
setActiveDropdownFocusIdAndMemorizePrevious(
dropdownComponentInstanceId,
);
setActiveDropdownFocusIdAndMemorizePrevious(dropdownComponentInstanceId);
pushFocusItemToFocusStack({
focusId: dropdownComponentInstanceId,
component: {
type: FocusComponentType.DROPDOWN,
instanceId: dropdownComponentInstanceId,
},
globalHotkeysConfig: {
enableGlobalHotkeysConflictingWithKeyboard:
args?.globalHotkeysConfig
?.enableGlobalHotkeysConflictingWithKeyboard ?? false,
enableGlobalHotkeysWithModifiers:
args?.globalHotkeysConfig?.enableGlobalHotkeysWithModifiers ??
false,
},
});
},
pushFocusItemToFocusStack({
focusId: dropdownComponentInstanceId,
component: {
type: FocusComponentType.DROPDOWN,
instanceId: dropdownComponentInstanceId,
},
globalHotkeysConfig: {
enableGlobalHotkeysConflictingWithKeyboard:
args?.globalHotkeysConfig
?.enableGlobalHotkeysConflictingWithKeyboard ?? false,
enableGlobalHotkeysWithModifiers:
args?.globalHotkeysConfig?.enableGlobalHotkeysWithModifiers ??
false,
},
});
},
[
pushFocusItemToFocusStack,
setActiveDropdownFocusIdAndMemorizePrevious,
@@ -1,23 +1,23 @@
import { useRecoilCallback } from 'recoil';
import { useCallback } from 'react';
import { activeDropdownFocusIdState } from '@/ui/layout/dropdown/states/activeDropdownFocusIdState';
import { previousDropdownFocusIdState } from '@/ui/layout/dropdown/states/previousDropdownFocusIdState';
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
export const useSetActiveDropdownFocusIdAndMemorizePrevious = () => {
const setActiveDropdownFocusIdAndMemorizePrevious = useRecoilCallback(
({ snapshot, set }) =>
(dropdownId: string | null) => {
const activeDropdownFocusId = snapshot
.getLoadable(activeDropdownFocusIdState)
.getValue();
const setActiveDropdownFocusIdAndMemorizePrevious = useCallback(
(dropdownId: string | null) => {
const activeDropdownFocusId = jotaiStore.get(
activeDropdownFocusIdState.atom,
);
if (activeDropdownFocusId === dropdownId) {
return;
}
if (activeDropdownFocusId === dropdownId) {
return;
}
set(previousDropdownFocusIdState, activeDropdownFocusId);
set(activeDropdownFocusIdState, dropdownId);
},
jotaiStore.set(previousDropdownFocusIdState.atom, activeDropdownFocusId);
jotaiStore.set(activeDropdownFocusIdState.atom, dropdownId);
},
[],
);
@@ -1,10 +1,12 @@
import { useCallback } from 'react';
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { type GlobalHotkeysConfig } from '@/ui/utilities/hotkey/types/GlobalHotkeysConfig';
import { useAvailableComponentInstanceId } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceId';
import { useRecoilCallback } from 'recoil';
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
import { isDefined } from 'twenty-shared/utils';
type ToggleDropdownArgs = {
@@ -19,34 +21,31 @@ export const useToggleDropdown = () => {
const { openDropdown } = useOpenDropdown();
const { closeDropdown } = useCloseDropdown();
const toggleDropdown = useRecoilCallback(
({ snapshot }) =>
(args?: ToggleDropdownArgs | null | undefined) => {
const dropdownComponentInstanceId =
args?.dropdownComponentInstanceIdFromProps ??
dropdownComponentInstanceIdFromContext;
const toggleDropdown = useCallback(
(args?: ToggleDropdownArgs | null | undefined) => {
const dropdownComponentInstanceId =
args?.dropdownComponentInstanceIdFromProps ??
dropdownComponentInstanceIdFromContext;
if (!isDefined(dropdownComponentInstanceId)) {
throw new Error('Dropdown component instance ID is not defined');
}
if (!isDefined(dropdownComponentInstanceId)) {
throw new Error('Dropdown component instance ID is not defined');
}
const isDropdownOpen = snapshot
.getLoadable(
isDropdownOpenComponentState.atomFamily({
instanceId: dropdownComponentInstanceId,
}),
)
.getValue();
const isDropdownOpen = jotaiStore.get(
isDropdownOpenComponentState.atomFamily({
instanceId: dropdownComponentInstanceId,
}),
);
if (isDropdownOpen) {
closeDropdown(dropdownComponentInstanceId);
} else {
openDropdown({
dropdownComponentInstanceIdFromProps: dropdownComponentInstanceId,
globalHotkeysConfig: args?.globalHotkeysConfig,
});
}
},
if (isDropdownOpen) {
closeDropdown(dropdownComponentInstanceId);
} else {
openDropdown({
dropdownComponentInstanceIdFromProps: dropdownComponentInstanceId,
globalHotkeysConfig: args?.globalHotkeysConfig,
});
}
},
[closeDropdown, openDropdown, dropdownComponentInstanceIdFromContext],
);
@@ -1,6 +1,6 @@
import { createState } from '@/ui/utilities/state/utils/createState';
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const activeDropdownFocusIdState = createState<string | null>({
export const activeDropdownFocusIdState = createStateV2<string | null>({
key: 'activeDropdownFocusIdState',
defaultValue: null,
});
@@ -1,10 +1,10 @@
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2';
import { type Placement } from '@floating-ui/react';
export const dropdownPlacementComponentState =
createComponentState<Placement | null>({
createComponentStateV2<Placement | null>({
key: 'dropdownPlacementComponentState',
componentInstanceContext: DropdownComponentInstanceContext,
defaultValue: null,
@@ -1,7 +1,7 @@
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2';
export const dropdownMaxHeightComponentState = createComponentState<
export const dropdownMaxHeightComponentState = createComponentStateV2<
number | undefined
>({
key: 'dropdownMaxHeightComponentState',
@@ -1,7 +1,7 @@
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2';
export const dropdownMaxWidthComponentState = createComponentState<
export const dropdownMaxWidthComponentState = createComponentStateV2<
number | undefined
>({
key: 'dropdownMaxWidthComponentState',
@@ -1,7 +1,7 @@
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2';
export const dropdownYPositionComponentState = createComponentState<
export const dropdownYPositionComponentState = createComponentStateV2<
number | undefined
>({
key: 'dropdownYPositionComponentState',
@@ -1,7 +1,7 @@
import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext';
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
import { createComponentStateV2 } from '@/ui/utilities/state/jotai/utils/createComponentStateV2';
export const isDropdownOpenComponentState = createComponentState<boolean>({
export const isDropdownOpenComponentState = createComponentStateV2<boolean>({
key: 'isDropdownOpenComponentState',
defaultValue: false,
componentInstanceContext: DropdownComponentInstanceContext,
@@ -1,6 +1,6 @@
import { createState } from '@/ui/utilities/state/utils/createState';
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const previousDropdownFocusIdState = createState<string | null>({
export const previousDropdownFocusIdState = createStateV2<string | null>({
key: 'previousDropdownFocusIdState',
defaultValue: null,
});
@@ -0,0 +1,30 @@
import { useAtom } from 'jotai';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap';
import { type ComponentStateV2 } from '@/ui/utilities/state/jotai/types/ComponentStateV2';
export const useRecoilComponentStateV2 = <StateType>(
componentState: ComponentStateV2<StateType>,
instanceIdFromProps?: string,
): [
StateType,
(value: StateType | ((prev: StateType) => StateType)) => void,
] => {
const componentInstanceContext = globalComponentInstanceContextMap.get(
componentState.key,
);
if (!componentInstanceContext) {
throw new Error(
`Instance context for key "${componentState.key}" is not defined`,
);
}
const instanceId = useAvailableComponentInstanceIdOrThrow(
componentInstanceContext,
instanceIdFromProps,
);
return useAtom(componentState.atomFamily({ instanceId }));
};
@@ -0,0 +1,27 @@
import { useAtomValue } from 'jotai';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap';
import { type ComponentStateV2 } from '@/ui/utilities/state/jotai/types/ComponentStateV2';
export const useRecoilComponentValueV2 = <StateType>(
componentState: ComponentStateV2<StateType>,
instanceIdFromProps?: string,
): StateType => {
const componentInstanceContext = globalComponentInstanceContextMap.get(
componentState.key,
);
if (!componentInstanceContext) {
throw new Error(
`Instance context for key "${componentState.key}" is not defined`,
);
}
const instanceId = useAvailableComponentInstanceIdOrThrow(
componentInstanceContext,
instanceIdFromProps,
);
return useAtomValue(componentState.atomFamily({ instanceId }));
};
@@ -0,0 +1,27 @@
import { useSetAtom } from 'jotai';
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap';
import { type ComponentStateV2 } from '@/ui/utilities/state/jotai/types/ComponentStateV2';
export const useSetRecoilComponentStateV2 = <ValueType>(
componentState: ComponentStateV2<ValueType>,
instanceIdFromProps?: string,
): ((value: ValueType | ((prev: ValueType) => ValueType)) => void) => {
const componentInstanceContext = globalComponentInstanceContextMap.get(
componentState.key,
);
if (!componentInstanceContext) {
throw new Error(
`Instance context for key "${componentState.key}" is not defined`,
);
}
const instanceId = useAvailableComponentInstanceIdOrThrow(
componentInstanceContext,
instanceIdFromProps,
);
return useSetAtom(componentState.atomFamily({ instanceId }));
};
@@ -1,3 +1,8 @@
import { createStore } from 'jotai';
export const jotaiStore = createStore();
export let jotaiStore = createStore();
export const resetJotaiStore = () => {
jotaiStore = createStore();
return jotaiStore;
};
@@ -0,0 +1,15 @@
import { type WritableAtom } from 'jotai';
import { type ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey';
type JotaiWritableAtom<ValueType> = WritableAtom<
ValueType,
[ValueType | ((prev: ValueType) => ValueType)],
void
>;
export type ComponentStateV2<ValueType> = {
type: 'ComponentStateV2';
key: string;
atomFamily: (key: ComponentStateKey) => JotaiWritableAtom<ValueType>;
};
@@ -0,0 +1,50 @@
import { atom } from 'jotai';
import { type ComponentInstanceStateContext } from '@/ui/utilities/state/component-state/types/ComponentInstanceStateContext';
import { type ComponentStateKey } from '@/ui/utilities/state/component-state/types/ComponentStateKey';
import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap';
import { type ComponentStateV2 } from '@/ui/utilities/state/jotai/types/ComponentStateV2';
import { isDefined } from 'twenty-shared/utils';
export const createComponentStateV2 = <ValueType>({
key,
defaultValue,
componentInstanceContext,
}: {
key: string;
defaultValue: ValueType;
componentInstanceContext: ComponentInstanceStateContext<any> | null;
}): ComponentStateV2<ValueType> => {
if (isDefined(componentInstanceContext)) {
globalComponentInstanceContextMap.set(key, componentInstanceContext);
}
const atomCache = new Map<
string,
ReturnType<ComponentStateV2<ValueType>['atomFamily']>
>();
const familyFunction = ({
instanceId,
}: ComponentStateKey): ReturnType<
ComponentStateV2<ValueType>['atomFamily']
> => {
const existing = atomCache.get(instanceId);
if (existing !== undefined) {
return existing;
}
const baseAtom = atom(defaultValue);
baseAtom.debugLabel = `${key}__${instanceId}`;
atomCache.set(instanceId, baseAtom);
return baseAtom;
};
return {
type: 'ComponentStateV2',
key,
atomFamily: familyFunction,
};
};
@@ -5,6 +5,7 @@ import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObje
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleTrashColumnFilter';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { AdvancedFilterDropdownButton } from '@/views/advanced-filter-chip/components/AdvancedFilterDropdownButton';
import { ViewBarDetailsAddFilterButton } from '@/views/components/ViewBarDetailsAddFilterButton';
import { EditableSortChip } from '@/views/editable-chip/components/EditableSortChip';
@@ -185,7 +186,7 @@ export const ViewBarDetails = ({
const shouldShowAdvancedFilterDropdownButton =
currentRecordFilterGroups.length > 0;
const isAnyFieldSearchDropdownOpen = useRecoilComponentValue(
const isAnyFieldSearchDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
ANY_FIELD_SEARCH_DROPDOWN_ID,
);
@@ -1,11 +1,11 @@
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds';
import { Trans } from '@lingui/react/macro';
export const ViewBarFilterButton = () => {
const isDropdownOpen = useRecoilComponentValue(
const isDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
ViewBarFilterDropdownIds.MAIN,
);
@@ -12,6 +12,7 @@ import { DraggableList } from '@/ui/layout/draggable-list/components/DraggableLi
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { dropdownYPositionComponentState } from '@/ui/layout/dropdown/states/internal/dropdownYPositionComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { ViewType } from '@/views/types/ViewType';
import { useContext } from 'react';
import { isDefined } from 'twenty-shared/utils';
@@ -77,7 +78,7 @@ export const ViewFieldsVisibleDropdownSection = () => {
)
.toSorted(sortByProperty('position'));
const dropdownYPosition = useRecoilComponentValue(
const dropdownYPosition = useRecoilComponentValueV2(
dropdownYPositionComponentState,
);
@@ -5,7 +5,7 @@ import { t } from '@lingui/core/macro';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { StyledDropdownButtonContainer } from '@/ui/layout/dropdown/components/StyledDropdownButtonContainer';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { useGetRecordIndexTotalCount } from '@/views/hooks/internal/useGetRecordIndexTotalCount';
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
import { ViewPickerContentCreateMode } from '@/views/view-picker/components/ViewPickerContentCreateMode';
@@ -61,7 +61,7 @@ export const ViewPickerDropdown = () => {
const { totalCount } = useGetRecordIndexTotalCount();
const isDropdownOpen = useRecoilComponentValue(
const isDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
VIEW_PICKER_DROPDOWN_ID,
);
@@ -2,7 +2,7 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { StyledDropdownButtonContainer } from '@/ui/layout/dropdown/components/StyledDropdownButtonContainer';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
import { type InputSchemaPropertyType } from 'twenty-shared/workflow';
import { WorkflowVariablesDropdownStepItems } from '@/workflow/workflow-variables/components/WorkflowVariablesDropdownStepItems';
import { WorkflowVariablesDropdownSteps } from '@/workflow/workflow-variables/components/WorkflowVariablesDropdownSteps';
@@ -53,7 +53,7 @@ export const WorkflowVariablesDropdown = ({
const theme = useTheme();
const dropdownId = `${SEARCH_VARIABLES_DROPDOWN_ID}-${instanceId}`;
const isDropdownOpen = useRecoilComponentValue(
const isDropdownOpen = useRecoilComponentValueV2(
isDropdownOpenComponentState,
dropdownId,
);