Improve command menu animation (#16197)
https://github.com/user-attachments/assets/c9ff288d-0e68-4877-af6b-8685a6bbeeaf
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Removes legacy layout and refactors `CommandMenuPageLayout` to use
width-based animation with shared constants and close-animation cleanup.
>
> - **UI/Command Menu**:
> - **Refactor `CommandMenuPageLayout`**:
> - Switch to width/margin animation on `StyledSidePanelWrapper`; remove
side panel `x` translate animation.
> - Use shared `COMMAND_MENU_SIDE_PANEL_WIDTH` constant.
> - Add close-state handling via `isCommandMenuClosingState` and
`useCommandMenuCloseAnimationCompleteCleanup` on animation completion.
> - Simplify props: remove `isSidePanelOpen`; rely on
`isCommandMenuOpenedState` and internal `shouldRenderContent`.
> - **Cleanup**:
> - Remove obsolete `CommandMenuLayout.tsx`.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
d6cb01114c. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Félix Malfait <[email protected]>
This commit is contained in:
co-authored by
Félix Malfait
parent
f489bbdbab
commit
b5ec6df62f
@@ -1,151 +0,0 @@
|
||||
import { CommandMenuRouter } from '@/command-menu/components/CommandMenuRouter';
|
||||
import { useCommandMenuHotKeys } from '@/command-menu/hooks/useCommandMenuHotKeys';
|
||||
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
|
||||
import { tableWidthResizeIsActiveState } from '@/object-record/record-table/states/tableWidthResizeIsActivedState';
|
||||
import { ModalContainerContext } from '@/ui/layout/modal/contexts/ModalContainerContext';
|
||||
import { PageBody } from '@/ui/layout/page/components/PageBody';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { motion } from 'framer-motion';
|
||||
import { type ReactNode, useCallback, useState } from 'react';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
import { useIsMobile } from 'twenty-ui/utilities';
|
||||
|
||||
type CommandMenuPageLayoutProps = {
|
||||
children: ReactNode;
|
||||
isSidePanelOpen?: boolean;
|
||||
};
|
||||
|
||||
const DEFAULT_SIDE_PANEL_WIDTH = 400;
|
||||
|
||||
const StyledLayout = styled.div`
|
||||
display: flex;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
padding-bottom: ${({ theme }) => theme.spacing(3)};
|
||||
padding-right: ${({ theme }) => theme.spacing(3)};
|
||||
`;
|
||||
|
||||
const StyledPageBody = styled(PageBody)`
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding-bottom: 0;
|
||||
padding-right: 0;
|
||||
`;
|
||||
|
||||
const StyledSidePanelWrapper = styled(motion.div)`
|
||||
flex-shrink: 0;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
const StyledSidePanel = styled(motion.aside)`
|
||||
background: ${({ theme }) => theme.background.primary};
|
||||
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||
border-radius: ${({ theme }) => theme.border.radius.md};
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
width: ${DEFAULT_SIDE_PANEL_WIDTH}px;
|
||||
box-sizing: border-box;
|
||||
`;
|
||||
|
||||
const StyledModalContainer = styled.div`
|
||||
height: 100%;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
`;
|
||||
|
||||
export const CommandMenuPageLayout = ({
|
||||
children,
|
||||
isSidePanelOpen,
|
||||
}: CommandMenuPageLayoutProps) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useIsMobile();
|
||||
const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState);
|
||||
const [modalContainer, setModalContainer] = useState<HTMLDivElement | null>(
|
||||
null,
|
||||
);
|
||||
|
||||
const setTableWidthResizeIsActive = useSetRecoilState(
|
||||
tableWidthResizeIsActiveState,
|
||||
);
|
||||
|
||||
const resolvedIsSidePanelOpen =
|
||||
isSidePanelOpen ?? isCommandMenuOpened ?? false;
|
||||
|
||||
const [shouldRenderContent, setShouldRenderContent] = useState(
|
||||
resolvedIsSidePanelOpen,
|
||||
);
|
||||
|
||||
const shouldShowContent = resolvedIsSidePanelOpen || shouldRenderContent;
|
||||
|
||||
const handleAnimationComplete = () => {
|
||||
if (!resolvedIsSidePanelOpen) {
|
||||
setShouldRenderContent(false);
|
||||
}
|
||||
|
||||
setTableWidthResizeIsActive(true);
|
||||
};
|
||||
|
||||
const handleAnimationStart = () => {
|
||||
if (resolvedIsSidePanelOpen && !shouldRenderContent) {
|
||||
setShouldRenderContent(true);
|
||||
}
|
||||
|
||||
setTableWidthResizeIsActive(false);
|
||||
};
|
||||
|
||||
const handleModalContainerRef = useCallback(
|
||||
(element: HTMLDivElement | null) => {
|
||||
setModalContainer(element);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
useCommandMenuHotKeys();
|
||||
|
||||
if (isMobile) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
return (
|
||||
<StyledLayout>
|
||||
<StyledPageBody>{children}</StyledPageBody>
|
||||
|
||||
<StyledSidePanelWrapper
|
||||
initial={false}
|
||||
animate={{
|
||||
width: resolvedIsSidePanelOpen ? DEFAULT_SIDE_PANEL_WIDTH : 0,
|
||||
marginLeft: resolvedIsSidePanelOpen ? theme.spacing(2) : 0,
|
||||
}}
|
||||
transition={{
|
||||
duration: theme.animation.duration.normal,
|
||||
}}
|
||||
onAnimationStart={handleAnimationStart}
|
||||
onAnimationComplete={handleAnimationComplete}
|
||||
>
|
||||
<StyledSidePanel
|
||||
initial={false}
|
||||
animate={{
|
||||
x: resolvedIsSidePanelOpen ? 0 : DEFAULT_SIDE_PANEL_WIDTH,
|
||||
}}
|
||||
transition={{
|
||||
duration: theme.animation.duration.normal,
|
||||
}}
|
||||
>
|
||||
<StyledModalContainer ref={handleModalContainerRef} />
|
||||
<ModalContainerContext.Provider value={{ container: modalContainer }}>
|
||||
{shouldShowContent && <CommandMenuRouter />}
|
||||
</ModalContainerContext.Provider>
|
||||
</StyledSidePanel>
|
||||
</StyledSidePanelWrapper>
|
||||
</StyledLayout>
|
||||
);
|
||||
};
|
||||
@@ -135,9 +135,6 @@ export const CommandMenuPageLayout = ({
|
||||
>
|
||||
<StyledSidePanel
|
||||
initial={false}
|
||||
animate={{
|
||||
x: isCommandMenuOpened ? 0 : COMMAND_MENU_SIDE_PANEL_WIDTH,
|
||||
}}
|
||||
transition={{
|
||||
duration: theme.animation.duration.normal,
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user