diff --git a/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionButton.tsx b/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionButton.tsx index de8676eaf..9ce580df9 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionButton.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionButton.tsx @@ -50,7 +50,6 @@ export const ActionButton = ({ /> { }); break; case CaptchaDriverType.Turnstile: - // TODO: fix workspace-no-hardcoded-colors rule - // eslint-disable-next-line @nx/workspace-no-hardcoded-colors captchaWidget = window.turnstile.render('#captcha-widget', { sitekey: captcha.siteKey, }); diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownMenuContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownMenuContent.tsx index d1fa4550e..7caa6457c 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownMenuContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownMenuContent.tsx @@ -153,7 +153,6 @@ export const ObjectOptionsDropdownMenuContent = () => { {currentView?.key === 'INDEX' && ( { +}: ObjectOptionsDropdownMenuViewNameProps) => { const [viewPickerSelectedIcon, setViewPickerSelectedIcon] = useRecoilComponentStateV2(viewPickerSelectedIconComponentState); diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx index bf9db0711..3c28e9ca1 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoard.tsx @@ -62,7 +62,7 @@ export const RecordBoard = () => { useContext(RecordBoardContext); const boardRef = useRef(null); - const { toggleClickOutsideListener } = useClickOutsideListener( + const { toggleClickOutside } = useClickOutsideListener( RECORD_BOARD_CLICK_OUTSIDE_LISTENER_ID, ); @@ -73,11 +73,11 @@ export const RecordBoard = () => { const handleDragSelectionStart = () => { closeDropdown(actionMenuId); - toggleClickOutsideListener(false); + toggleClickOutside(false); }; const handleDragSelectionEnd = () => { - toggleClickOutsideListener(true); + toggleClickOutside(true); }; const visibleRecordGroupIds = useRecoilComponentFamilyValueV2( diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx index d855a7563..93b5fb572 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx @@ -24,6 +24,7 @@ const StyledNewButtonContainer = styled.div` padding-bottom: ${({ theme }) => theme.spacing(4)}; `; +// eslint-disable-next-line @nx/workspace-no-hardcoded-colors const StyledSkeletonCardContainer = styled.div` background-color: ${({ theme }) => theme.background.secondary}; border: 1px solid ${({ theme }) => theme.background.quaternary}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/__stories__/RecordTable.stories.tsx b/packages/twenty-front/src/modules/object-record/record-table/__stories__/RecordTable.stories.tsx index 016f10afc..b2d56122a 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/__stories__/RecordTable.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/__stories__/RecordTable.stories.tsx @@ -62,6 +62,11 @@ export const HeaderMenuOpen: Story = { }; export const ScrolledLeft: Story = { + parameters: { + container: { + width: 1000, + }, + }, play: async () => { const canvas = within(document.body); await canvas.findByText('Linkedin'); diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx index 621e5b068..57edee8de 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx @@ -20,7 +20,7 @@ export const RecordTable = () => { const tableBodyRef = useRef(null); - const { toggleClickOutsideListener } = useClickOutsideListener( + const { toggleClickOutside } = useClickOutsideListener( RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID, ); @@ -57,11 +57,11 @@ export const RecordTable = () => { const handleDragSelectionStart = () => { resetTableRowSelection(); - toggleClickOutsideListener(false); + toggleClickOutside(false); }; const handleDragSelectionEnd = () => { - toggleClickOutsideListener(true); + toggleClickOutside(true); }; return ( diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellInGroup.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellInGroup.ts index 2070def65..57fecfd13 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellInGroup.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellInGroup.ts @@ -15,7 +15,7 @@ export const useCloseRecordTableCellInGroup = () => { const setHotkeyScope = useSetHotkeyScope(); const { setDragSelectionStartEnabled } = useDragSelect(); - const { toggleClickOutsideListener } = useClickOutsideListener( + const { toggleClickOutside } = useClickOutsideListener( FOCUS_CLICK_OUTSIDE_LISTENER_ID, ); @@ -24,7 +24,7 @@ export const useCloseRecordTableCellInGroup = () => { const closeTableCellInGroup = useRecoilCallback( () => () => { - toggleClickOutsideListener(true); + toggleClickOutside(true); setDragSelectionStartEnabled(true); closeCurrentTableCellInEditMode(); setHotkeyScope(TableHotkeyScope.TableFocus); @@ -33,7 +33,7 @@ export const useCloseRecordTableCellInGroup = () => { closeCurrentTableCellInEditMode, setDragSelectionStartEnabled, setHotkeyScope, - toggleClickOutsideListener, + toggleClickOutside, ], ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellNoGroup.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellNoGroup.ts index 97b69d490..fa968f72d 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellNoGroup.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellNoGroup.ts @@ -15,7 +15,7 @@ export const useCloseRecordTableCellNoGroup = () => { const { setDragSelectionStartEnabled } = useDragSelect(); - const { toggleClickOutsideListener } = useClickOutsideListener( + const { toggleClickOutside } = useClickOutsideListener( FOCUS_CLICK_OUTSIDE_LISTENER_ID, ); @@ -23,7 +23,7 @@ export const useCloseRecordTableCellNoGroup = () => { useCloseCurrentTableCellInEditMode(recordTableId); const closeTableCellNoGroup = useCallback(() => { - toggleClickOutsideListener(true); + toggleClickOutside(true); setDragSelectionStartEnabled(true); closeCurrentTableCellInEditMode(); setHotkeyScope(TableHotkeyScope.TableFocus); @@ -31,7 +31,7 @@ export const useCloseRecordTableCellNoGroup = () => { closeCurrentTableCellInEditMode, setDragSelectionStartEnabled, setHotkeyScope, - toggleClickOutsideListener, + toggleClickOutside, ]); return { diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2.ts index b09ca7623..db5f3bee7 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2.ts @@ -24,7 +24,9 @@ import { recordTableCellEditModePositionComponentState } from '@/object-record/r import { getDropdownFocusIdForRecordField } from '@/object-record/utils/getDropdownFocusIdForRecordField'; import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId'; import { useSetActiveDropdownFocusIdAndMemorizePrevious } from '@/ui/layout/dropdown/hooks/useSetFocusedDropdownIdAndMemorizePrevious'; -import { useClickOustideListenerStates } from '@/ui/utilities/pointer-event/hooks/useClickOustideListenerStates'; + +import { clickOutsideListenerIsActivatedComponentState } from '@/ui/utilities/pointer-event/states/clickOutsideListenerIsActivatedComponentState'; +import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType'; import { useNavigate } from 'react-router-dom'; @@ -46,9 +48,11 @@ export type OpenTableCellArgs = { }; export const useOpenRecordTableCellV2 = (tableScopeId: string) => { - const { getClickOutsideListenerIsActivatedState } = - useClickOustideListenerStates(RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID); - + const clickOutsideListenerIsActivatedState = + useRecoilComponentCallbackStateV2( + clickOutsideListenerIsActivatedComponentState, + RECORD_TABLE_CLICK_OUTSIDE_LISTENER_ID, + ); const { indexIdentifierUrl } = useRecordIndexContextOrThrow(); const setCurrentTableCellInEditModePosition = useSetRecoilComponentStateV2( recordTableCellEditModePositionComponentState, @@ -58,7 +62,7 @@ export const useOpenRecordTableCellV2 = (tableScopeId: string) => { const { setDragSelectionStartEnabled } = useDragSelect(); const leaveTableFocus = useLeaveTableFocus(tableScopeId); - const { toggleClickOutsideListener } = useClickOutsideListener( + const { toggleClickOutside } = useClickOutsideListener( FOCUS_CLICK_OUTSIDE_LISTENER_ID, ); @@ -94,7 +98,7 @@ export const useOpenRecordTableCellV2 = (tableScopeId: string) => { return; } - set(getClickOutsideListenerIsActivatedState, false); + set(clickOutsideListenerIsActivatedState, false); const isFirstColumnCell = cellPosition.column === 0; @@ -163,7 +167,7 @@ export const useOpenRecordTableCellV2 = (tableScopeId: string) => { ), }); - toggleClickOutsideListener(false); + toggleClickOutside(false); setActiveDropdownFocusIdAndMemorizePrevious( getDropdownFocusIdForRecordField( @@ -174,12 +178,12 @@ export const useOpenRecordTableCellV2 = (tableScopeId: string) => { ); }, [ - getClickOutsideListenerIsActivatedState, + clickOutsideListenerIsActivatedState, setDragSelectionStartEnabled, openFieldInput, setCurrentTableCellInEditModePosition, initDraftValue, - toggleClickOutsideListener, + toggleClickOutside, setActiveDropdownFocusIdAndMemorizePrevious, leaveTableFocus, navigate, diff --git a/packages/twenty-front/src/modules/ui/input/editor/components/BlockEditor.tsx b/packages/twenty-front/src/modules/ui/input/editor/components/BlockEditor.tsx index 7ece92b6a..b3c97d345 100644 --- a/packages/twenty-front/src/modules/ui/input/editor/components/BlockEditor.tsx +++ b/packages/twenty-front/src/modules/ui/input/editor/components/BlockEditor.tsx @@ -22,6 +22,7 @@ interface BlockEditorProps { readonly?: boolean; } +// eslint-disable-next-line @nx/workspace-no-hardcoded-colors const StyledEditor = styled.div` width: 100%; diff --git a/packages/twenty-front/src/modules/ui/utilities/pointer-event/hooks/__tests__/useClickOutsideListener.test.tsx b/packages/twenty-front/src/modules/ui/utilities/pointer-event/hooks/__tests__/useClickOutsideListener.test.tsx index 04d2b8825..3406d13a4 100644 --- a/packages/twenty-front/src/modules/ui/utilities/pointer-event/hooks/__tests__/useClickOutsideListener.test.tsx +++ b/packages/twenty-front/src/modules/ui/utilities/pointer-event/hooks/__tests__/useClickOutsideListener.test.tsx @@ -1,8 +1,9 @@ import { act, renderHook } from '@testing-library/react'; -import { RecoilRoot, useRecoilValue } from 'recoil'; +import { RecoilRoot } from 'recoil'; -import { useClickOustideListenerStates } from '@/ui/utilities/pointer-event/hooks/useClickOustideListenerStates'; import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener'; +import { clickOutsideListenerIsActivatedComponentState } from '@/ui/utilities/pointer-event/states/clickOutsideListenerIsActivatedComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; const componentId = 'componentId'; @@ -10,12 +11,12 @@ describe('useClickOutsideListener', () => { it('should toggle the click outside listener activation state', async () => { const { result } = renderHook( () => { - const { getClickOutsideListenerIsActivatedState } = - useClickOustideListenerStates(componentId); - return { useClickOutside: useClickOutsideListener(componentId), - isActivated: useRecoilValue(getClickOutsideListenerIsActivatedState), + isActivated: useRecoilComponentValueV2( + clickOutsideListenerIsActivatedComponentState, + componentId, + ), }; }, { @@ -23,7 +24,7 @@ describe('useClickOutsideListener', () => { }, ); - const toggle = result.current.useClickOutside.toggleClickOutsideListener; + const toggle = result.current.useClickOutside.toggleClickOutside; act(() => { toggle(true); diff --git a/packages/twenty-front/src/modules/ui/utilities/pointer-event/hooks/useClickOustideListenerStates.ts b/packages/twenty-front/src/modules/ui/utilities/pointer-event/hooks/useClickOustideListenerStates.ts deleted file mode 100644 index 2cc0ea918..000000000 --- a/packages/twenty-front/src/modules/ui/utilities/pointer-event/hooks/useClickOustideListenerStates.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { clickOutsideListenerCallbacksComponentState } from '@/ui/utilities/pointer-event/states/clickOutsideListenerCallbacksComponentState'; -import { clickOutsideListenerIsActivatedComponentState } from '@/ui/utilities/pointer-event/states/clickOutsideListenerIsActivatedComponentState'; -import { clickOutsideListenerIsMouseDownInsideComponentState } from '@/ui/utilities/pointer-event/states/clickOutsideListenerIsMouseDownInsideComponentState'; -import { clickOutsideListenerMouseDownHappenedComponentState } from '@/ui/utilities/pointer-event/states/clickOutsideListenerMouseDownHappenedComponentState'; -import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState'; - -export const useClickOustideListenerStates = (componentId: string) => { - const scopeId = componentId; - - return { - scopeId, - getClickOutsideListenerCallbacksState: extractComponentState( - clickOutsideListenerCallbacksComponentState, - scopeId, - ), - getClickOutsideListenerIsMouseDownInsideState: extractComponentState( - clickOutsideListenerIsMouseDownInsideComponentState, - scopeId, - ), - getClickOutsideListenerIsActivatedState: extractComponentState( - clickOutsideListenerIsActivatedComponentState, - scopeId, - ), - getClickOutsideListenerMouseDownHappenedState: extractComponentState( - clickOutsideListenerMouseDownHappenedComponentState, - scopeId, - ), - }; -}; diff --git a/packages/twenty-front/src/modules/ui/utilities/pointer-event/hooks/useClickOutsideListener.ts b/packages/twenty-front/src/modules/ui/utilities/pointer-event/hooks/useClickOutsideListener.ts index a22628747..1bb649160 100644 --- a/packages/twenty-front/src/modules/ui/utilities/pointer-event/hooks/useClickOutsideListener.ts +++ b/packages/twenty-front/src/modules/ui/utilities/pointer-event/hooks/useClickOutsideListener.ts @@ -1,126 +1,38 @@ -import { useEffect } from 'react'; import { useRecoilCallback } from 'recoil'; -import { useClickOustideListenerStates } from '@/ui/utilities/pointer-event/hooks/useClickOustideListenerStates'; +import { clickOutsideListenerIsActivatedComponentState } from '@/ui/utilities/pointer-event/states/clickOutsideListenerIsActivatedComponentState'; +import { clickOutsideListenerMouseDownHappenedComponentState } from '@/ui/utilities/pointer-event/states/clickOutsideListenerMouseDownHappenedComponentState'; +import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; -import { ClickOutsideListenerCallback } from '@/ui/utilities/pointer-event/types/ClickOutsideListenerCallback'; -import { toSpliced } from '~/utils/array/toSpliced'; -import { isDefined } from 'twenty-shared/utils'; +export const useClickOutsideListener = (instanceId: string) => { + const clickOutsideListenerIsActivatedState = + useRecoilComponentCallbackStateV2( + clickOutsideListenerIsActivatedComponentState, + instanceId, + ); -export const useClickOutsideListener = (componentId: string) => { - const { - getClickOutsideListenerIsActivatedState, - getClickOutsideListenerCallbacksState, - getClickOutsideListenerMouseDownHappenedState, - } = useClickOustideListenerStates(componentId); + const clickOutsideListenerMouseDownHappenedState = + useRecoilComponentCallbackStateV2( + clickOutsideListenerMouseDownHappenedComponentState, + instanceId, + ); - const toggleClickOutsideListener = useRecoilCallback( + const toggleClickOutside = useRecoilCallback( ({ set }) => (activated: boolean) => { - set(getClickOutsideListenerIsActivatedState, activated); + set(clickOutsideListenerIsActivatedState, activated); if (!activated) { - set(getClickOutsideListenerMouseDownHappenedState, false); + set(clickOutsideListenerMouseDownHappenedState, false); } }, [ - getClickOutsideListenerIsActivatedState, - getClickOutsideListenerMouseDownHappenedState, + clickOutsideListenerIsActivatedState, + clickOutsideListenerMouseDownHappenedState, ], ); - const registerOnClickOutsideCallback = useRecoilCallback( - ({ set, snapshot }) => - ({ callbackFunction, callbackId }: ClickOutsideListenerCallback) => { - const existingCallbacks = snapshot - .getLoadable(getClickOutsideListenerCallbacksState) - .getValue(); - - const existingCallbackWithSameId = existingCallbacks.find( - (callback) => callback.callbackId === callbackId, - ); - - if (!isDefined(existingCallbackWithSameId)) { - const existingCallbacksWithNewCallback = existingCallbacks.concat({ - callbackId, - callbackFunction, - }); - - set( - getClickOutsideListenerCallbacksState, - existingCallbacksWithNewCallback, - ); - } else { - const existingCallbacksWithOverwrittenCallback = [ - ...existingCallbacks, - ]; - - const indexOfExistingCallbackWithSameId = - existingCallbacksWithOverwrittenCallback.findIndex( - (callback) => callback.callbackId === callbackId, - ); - - existingCallbacksWithOverwrittenCallback[ - indexOfExistingCallbackWithSameId - ] = { - callbackId, - callbackFunction, - }; - - set( - getClickOutsideListenerCallbacksState, - existingCallbacksWithOverwrittenCallback, - ); - } - }, - [getClickOutsideListenerCallbacksState], - ); - - const unregisterOnClickOutsideCallback = useRecoilCallback( - ({ set, snapshot }) => - ({ callbackId }: { callbackId: string }) => { - const existingCallbacks = snapshot - .getLoadable(getClickOutsideListenerCallbacksState) - .getValue(); - - const indexOfCallbackToUnsubscribe = existingCallbacks.findIndex( - (callback) => callback.callbackId === callbackId, - ); - - const callbackToUnsubscribeIsFound = indexOfCallbackToUnsubscribe > -1; - - if (callbackToUnsubscribeIsFound) { - const newCallbacksWithoutCallbackToUnsubscribe = toSpliced( - existingCallbacks, - indexOfCallbackToUnsubscribe, - 1, - ); - - set( - getClickOutsideListenerCallbacksState, - newCallbacksWithoutCallbackToUnsubscribe, - ); - } - }, - [getClickOutsideListenerCallbacksState], - ); - - const useRegisterClickOutsideListenerCallback = ( - callback: ClickOutsideListenerCallback, - ) => { - useEffect(() => { - registerOnClickOutsideCallback(callback); - - return () => { - unregisterOnClickOutsideCallback({ - callbackId: callback.callbackId, - }); - }; - }, [callback]); - }; - return { - toggleClickOutsideListener, - useRegisterClickOutsideListenerCallback, + toggleClickOutside, }; }; diff --git a/packages/twenty-front/src/modules/ui/utilities/pointer-event/hooks/useListenClickOutside.ts b/packages/twenty-front/src/modules/ui/utilities/pointer-event/hooks/useListenClickOutside.ts index 76be7d45a..57d76dd1e 100644 --- a/packages/twenty-front/src/modules/ui/utilities/pointer-event/hooks/useListenClickOutside.ts +++ b/packages/twenty-front/src/modules/ui/utilities/pointer-event/hooks/useListenClickOutside.ts @@ -1,8 +1,10 @@ +import { clickOutsideListenerIsActivatedComponentState } from '@/ui/utilities/pointer-event/states/clickOutsideListenerIsActivatedComponentState'; +import { clickOutsideListenerIsMouseDownInsideComponentState } from '@/ui/utilities/pointer-event/states/clickOutsideListenerIsMouseDownInsideComponentState'; +import { clickOutsideListenerMouseDownHappenedComponentState } from '@/ui/utilities/pointer-event/states/clickOutsideListenerMouseDownHappenedComponentState'; +import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; import React, { useEffect } from 'react'; import { useRecoilCallback } from 'recoil'; -import { useClickOustideListenerStates } from '@/ui/utilities/pointer-event/hooks/useClickOustideListenerStates'; - const CLICK_OUTSIDE_DEBUG_MODE = false; export enum ClickOutsideMode { @@ -27,20 +29,30 @@ export const useListenClickOutside = ({ listenerId, enabled = true, }: ClickOutsideListenerProps) => { - const { - getClickOutsideListenerIsMouseDownInsideState, - getClickOutsideListenerIsActivatedState, - getClickOutsideListenerMouseDownHappenedState, - } = useClickOustideListenerStates(listenerId); + const clickOutsideListenerIsMouseDownInsideState = + useRecoilComponentCallbackStateV2( + clickOutsideListenerIsMouseDownInsideComponentState, + listenerId, + ); + const clickOutsideListenerIsActivatedState = + useRecoilComponentCallbackStateV2( + clickOutsideListenerIsActivatedComponentState, + listenerId, + ); + const clickOutsideListenerMouseDownHappenedState = + useRecoilComponentCallbackStateV2( + clickOutsideListenerMouseDownHappenedComponentState, + listenerId, + ); const handleMouseDown = useRecoilCallback( ({ snapshot, set }) => (event: MouseEvent | TouchEvent) => { const clickOutsideListenerIsActivated = snapshot - .getLoadable(getClickOutsideListenerIsActivatedState) + .getLoadable(clickOutsideListenerIsActivatedState) .getValue(); - set(getClickOutsideListenerMouseDownHappenedState, true); + set(clickOutsideListenerMouseDownHappenedState, true); const isListening = clickOutsideListenerIsActivated && enabled; @@ -55,7 +67,7 @@ export const useListenClickOutside = ({ .some((ref) => ref.current?.contains(event.target as Node)); set( - getClickOutsideListenerIsMouseDownInsideState, + clickOutsideListenerIsMouseDownInsideState, clickedOnAtLeastOneRef, ); break; @@ -93,7 +105,7 @@ export const useListenClickOutside = ({ }); set( - getClickOutsideListenerIsMouseDownInsideState, + clickOutsideListenerIsMouseDownInsideState, clickedOnAtLeastOneRef, ); break; @@ -105,12 +117,12 @@ export const useListenClickOutside = ({ } }, [ - getClickOutsideListenerIsActivatedState, - getClickOutsideListenerMouseDownHappenedState, + clickOutsideListenerIsActivatedState, + clickOutsideListenerMouseDownHappenedState, enabled, mode, refs, - getClickOutsideListenerIsMouseDownInsideState, + clickOutsideListenerIsMouseDownInsideState, ], ); @@ -118,17 +130,17 @@ export const useListenClickOutside = ({ ({ snapshot }) => (event: MouseEvent | TouchEvent) => { const clickOutsideListenerIsActivated = snapshot - .getLoadable(getClickOutsideListenerIsActivatedState) + .getLoadable(clickOutsideListenerIsActivatedState) .getValue(); const isListening = clickOutsideListenerIsActivated && enabled; const isMouseDownInside = snapshot - .getLoadable(getClickOutsideListenerIsMouseDownInsideState) + .getLoadable(clickOutsideListenerIsMouseDownInsideState) .getValue(); const hasMouseDownHappened = snapshot - .getLoadable(getClickOutsideListenerMouseDownHappenedState) + .getLoadable(clickOutsideListenerMouseDownHappenedState) .getValue(); const clickedElement = event.target as HTMLElement; @@ -241,10 +253,10 @@ export const useListenClickOutside = ({ } }, [ - getClickOutsideListenerIsActivatedState, + clickOutsideListenerIsActivatedState, enabled, - getClickOutsideListenerIsMouseDownInsideState, - getClickOutsideListenerMouseDownHappenedState, + clickOutsideListenerIsMouseDownInsideState, + clickOutsideListenerMouseDownHappenedState, mode, refs, excludeClassNames, diff --git a/packages/twenty-front/src/modules/ui/utilities/pointer-event/states/clickOutsideListenerCallbacksComponentState.ts b/packages/twenty-front/src/modules/ui/utilities/pointer-event/states/clickOutsideListenerCallbacksComponentState.ts deleted file mode 100644 index d0c1ec291..000000000 --- a/packages/twenty-front/src/modules/ui/utilities/pointer-event/states/clickOutsideListenerCallbacksComponentState.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { ClickOutsideListenerCallback } from '@/ui/utilities/pointer-event/types/ClickOutsideListenerCallback'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; - -export const clickOutsideListenerCallbacksComponentState = createComponentState< - ClickOutsideListenerCallback[] ->({ - key: 'clickOutsideListenerCallbacksComponentState', - defaultValue: [], -}); diff --git a/packages/twenty-front/src/modules/ui/utilities/pointer-event/states/clickOutsideListenerIsActivatedComponentState.ts b/packages/twenty-front/src/modules/ui/utilities/pointer-event/states/clickOutsideListenerIsActivatedComponentState.ts index 8c08b27de..181b2080b 100644 --- a/packages/twenty-front/src/modules/ui/utilities/pointer-event/states/clickOutsideListenerIsActivatedComponentState.ts +++ b/packages/twenty-front/src/modules/ui/utilities/pointer-event/states/clickOutsideListenerIsActivatedComponentState.ts @@ -1,7 +1,9 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { ClickOutsideListenerComponentInstanceContext } from '@/ui/utilities/pointer-event/states/contexts/ClickOutsideListenerComponentInstanceContext'; +import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; export const clickOutsideListenerIsActivatedComponentState = - createComponentState({ + createComponentStateV2({ key: 'clickOutsideListenerIsActivatedComponentState', defaultValue: true, + componentInstanceContext: ClickOutsideListenerComponentInstanceContext, }); diff --git a/packages/twenty-front/src/modules/ui/utilities/pointer-event/states/clickOutsideListenerIsMouseDownInsideComponentState.ts b/packages/twenty-front/src/modules/ui/utilities/pointer-event/states/clickOutsideListenerIsMouseDownInsideComponentState.ts index 47bb8f0f5..ac08f2b06 100644 --- a/packages/twenty-front/src/modules/ui/utilities/pointer-event/states/clickOutsideListenerIsMouseDownInsideComponentState.ts +++ b/packages/twenty-front/src/modules/ui/utilities/pointer-event/states/clickOutsideListenerIsMouseDownInsideComponentState.ts @@ -1,7 +1,9 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { ClickOutsideListenerComponentInstanceContext } from '@/ui/utilities/pointer-event/states/contexts/ClickOutsideListenerComponentInstanceContext'; +import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; export const clickOutsideListenerIsMouseDownInsideComponentState = - createComponentState({ + createComponentStateV2({ key: 'clickOutsideListenerIsMouseDownInsideComponentState', defaultValue: false, + componentInstanceContext: ClickOutsideListenerComponentInstanceContext, }); diff --git a/packages/twenty-front/src/modules/ui/utilities/pointer-event/states/clickOutsideListenerMouseDownHappenedComponentState.ts b/packages/twenty-front/src/modules/ui/utilities/pointer-event/states/clickOutsideListenerMouseDownHappenedComponentState.ts index c9c9298c9..56c4ba4a4 100644 --- a/packages/twenty-front/src/modules/ui/utilities/pointer-event/states/clickOutsideListenerMouseDownHappenedComponentState.ts +++ b/packages/twenty-front/src/modules/ui/utilities/pointer-event/states/clickOutsideListenerMouseDownHappenedComponentState.ts @@ -1,7 +1,9 @@ -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; +import { ClickOutsideListenerComponentInstanceContext } from '@/ui/utilities/pointer-event/states/contexts/ClickOutsideListenerComponentInstanceContext'; +import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; export const clickOutsideListenerMouseDownHappenedComponentState = - createComponentState({ + createComponentStateV2({ key: 'clickOutsideListenerMouseDownHappenedComponentState', defaultValue: false, + componentInstanceContext: ClickOutsideListenerComponentInstanceContext, }); diff --git a/packages/twenty-front/src/modules/ui/utilities/pointer-event/states/contexts/ClickOutsideListenerComponentInstanceContext.ts b/packages/twenty-front/src/modules/ui/utilities/pointer-event/states/contexts/ClickOutsideListenerComponentInstanceContext.ts new file mode 100644 index 000000000..479bb216f --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/pointer-event/states/contexts/ClickOutsideListenerComponentInstanceContext.ts @@ -0,0 +1,4 @@ +import { createComponentInstanceContext } from '@/ui/utilities/state/component-state/utils/createComponentInstanceContext'; + +export const ClickOutsideListenerComponentInstanceContext = + createComponentInstanceContext(); diff --git a/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx b/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx index 0fa6d1ff8..0a93ae923 100644 --- a/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx @@ -13,6 +13,7 @@ import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; import { RecordTableBodyContextProvider } from '@/object-record/record-table/contexts/RecordTableBodyContext'; import { RecordTableContextProvider } from '@/object-record/record-table/contexts/RecordTableContext'; +import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector'; import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; @@ -21,6 +22,7 @@ import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewCompon import { View } from '@/views/types/View'; import { useEffect, useMemo } from 'react'; import { isDefined } from 'twenty-shared/utils'; +import { getCompaniesMock } from '~/testing/mock-data/companies'; import { mockedViewFieldsData } from '~/testing/mock-data/view-fields'; import { mockedViewsData } from '~/testing/mock-data/views'; @@ -31,6 +33,8 @@ const InternalTableStateLoaderEffect = ({ }) => { const { loadRecordIndexStates } = useLoadRecordIndexStates(); + const { setRecordTableData } = useRecordTable(); + const view = useMemo(() => { return { ...mockedViewsData[0], @@ -42,7 +46,11 @@ const InternalTableStateLoaderEffect = ({ useEffect(() => { loadRecordIndexStates(view, objectMetadataItem); - }, [loadRecordIndexStates, objectMetadataItem, view]); + setRecordTableData({ + records: getCompaniesMock(), + totalCount: getCompaniesMock().length, + }); + }, [loadRecordIndexStates, objectMetadataItem, setRecordTableData, view]); return null; }; diff --git a/tools/eslint-rules/jest.config.ts b/tools/eslint-rules/jest.config.ts index 6322fd9d3..d7b271c68 100644 --- a/tools/eslint-rules/jest.config.ts +++ b/tools/eslint-rules/jest.config.ts @@ -1,6 +1,7 @@ /* eslint-disable */ export default { displayName: 'eslint-rules', + silent: false, preset: '../../jest.preset.js', transform: { '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], diff --git a/tools/eslint-rules/rules/no-hardcoded-colors.spec.ts b/tools/eslint-rules/rules/no-hardcoded-colors.spec.ts index ec5b37d9f..1a7b72453 100644 --- a/tools/eslint-rules/rules/no-hardcoded-colors.spec.ts +++ b/tools/eslint-rules/rules/no-hardcoded-colors.spec.ts @@ -51,5 +51,21 @@ ruleTester.run(RULE_NAME, rule, { }, ], }, + { + code: 'const myCss = css`color: #123; background-color: ${theme.background.secondary};`', + errors: [ + { + messageId: 'hardcodedColor', + }, + ], + }, + { + code: 'const myCss = styled.div`color: ${({ theme }) => theme.font.color.primary};flex-shrink: 0;background-color: #123;text-overflow: ellipsis;white-space: nowrap;max-width: 100%;`', + errors: [ + { + messageId: 'hardcodedColor', + }, + ], + }, ], }); diff --git a/tools/eslint-rules/rules/no-hardcoded-colors.ts b/tools/eslint-rules/rules/no-hardcoded-colors.ts index 3505d4492..d7284f26f 100644 --- a/tools/eslint-rules/rules/no-hardcoded-colors.ts +++ b/tools/eslint-rules/rules/no-hardcoded-colors.ts @@ -21,7 +21,7 @@ export const rule = ESLintUtils.RuleCreator(() => __filename)({ defaultOptions: [], create: (context) => { const testHardcodedColor = ( - literal: TSESTree.Literal | TSESTree.TemplateLiteral, + literal: TSESTree.Literal | TSESTree.TemplateLiteral ) => { const colorRegex = /(?:rgba?\()|(?:#[0-9a-fA-F]{3,6})\b/i; @@ -39,23 +39,26 @@ export const rule = ESLintUtils.RuleCreator(() => __filename)({ }); } } else if (literal.type === TSESTree.AST_NODE_TYPES.TemplateLiteral) { - const firstStringValue = literal.quasis[0]?.value.raw; + for (const quasi of literal.quasis) { + const firstStringValue = quasi.value.raw; if (colorRegex.test(firstStringValue)) { context.report({ node: literal, messageId: 'hardcodedColor', data: { - color: firstStringValue, - }, - }); + color: firstStringValue, + }, + }); + } } } }; return { - Literal: testHardcodedColor, - TemplateLiteral: testHardcodedColor, + Literal: (literal: TSESTree.Literal) => testHardcodedColor(literal), + TemplateLiteral: (templateLiteral: TSESTree.TemplateLiteral) => + testHardcodedColor(templateLiteral), }; }, });