Fixes active row state after opening the file preview (#12264)

Fixes #12093
This bug was quite hard to fix because it was an issue with the
`AnimatePresence` component of the framer motion library.

After investigating the issue with @Devessier, here is what we
understood:

Since the modal component has an exit animation but wasn't wrapped
inside an `AnimatePresence` component, the animation seemed to never be
marked as complete when we closed the modal and the component did not
appear anymore but was still in the dom.

This caused an issue when closing the side panel because the state
cleanup function of the command menu is triggered when its closing
animation is complete. This cleanup function emits a right drawer close
event, which is listened by the record table row to update it's state.

The `onExitComplete` was never triggered because the exit animation of
the modal was never considered as complete, and since it's a children
animation of the command menu `AnimatePresence`, this animation was
never considered as complete either (see [PresenceChild
doc](https://github.com/motiondivision/motion/blob/main/packages/framer-motion/src/components/AnimatePresence/PresenceChild.tsx).

This caused the cleanup function to never be executed and the close
event to never be emitted, so the row stayed active.

Before:


https://github.com/user-attachments/assets/a165039b-6203-43d6-b992-dcfb4dfb8f2b


After:


https://github.com/user-attachments/assets/42eab2e8-62c9-4c25-85d6-78210d7ebe89
This commit is contained in:
Raphaël Bosi
2025-05-23 18:26:30 +02:00
committed by GitHub
parent 5428348d7f
commit 1e5257f95b
2 changed files with 52 additions and 57 deletions

View File

@ -1,5 +1,4 @@
import styled from '@emotion/styled';
import { AnimatePresence, LayoutGroup } from 'framer-motion';
import { ReactNode, useState } from 'react';
import { useDebouncedCallback } from 'use-debounce';
@ -108,62 +107,58 @@ export const ConfirmationModal = ({
};
return (
<AnimatePresence mode="wait">
<LayoutGroup>
<StyledConfirmationModal
modalId={modalId}
onClose={() => {
onClose?.();
}}
onEnter={handleEnter}
isClosable={true}
padding="large"
modalVariant={modalVariant}
data-globally-prevent-click-outside
>
<StyledCenteredTitle>
<H1Title title={title} fontColor={H1TitleFontColor.Primary} />
</StyledCenteredTitle>
<StyledSection
alignment={SectionAlignment.Center}
fontColor={SectionFontColor.Primary}
>
{subtitle}
</StyledSection>
{confirmationValue && (
<Section>
<TextInput
dataTestId="confirmation-modal-input"
value={inputConfirmationValue}
onChange={handleInputConfimrationValueChange}
placeholder={confirmationPlaceholder}
fullWidth
disableHotkeys
key={'input-' + confirmationValue}
/>
</Section>
)}
<StyledCenteredButton
onClick={handleCancelClick}
variant="secondary"
title={t`Cancel`}
<StyledConfirmationModal
modalId={modalId}
onClose={() => {
onClose?.();
}}
onEnter={handleEnter}
isClosable={true}
padding="large"
modalVariant={modalVariant}
data-globally-prevent-click-outside
>
<StyledCenteredTitle>
<H1Title title={title} fontColor={H1TitleFontColor.Primary} />
</StyledCenteredTitle>
<StyledSection
alignment={SectionAlignment.Center}
fontColor={SectionFontColor.Primary}
>
{subtitle}
</StyledSection>
{confirmationValue && (
<Section>
<TextInput
dataTestId="confirmation-modal-input"
value={inputConfirmationValue}
onChange={handleInputConfimrationValueChange}
placeholder={confirmationPlaceholder}
fullWidth
dataTestId="confirmation-modal-cancel-button"
disableHotkeys
key={'input-' + confirmationValue}
/>
</Section>
)}
<StyledCenteredButton
onClick={handleCancelClick}
variant="secondary"
title={t`Cancel`}
fullWidth
dataTestId="confirmation-modal-cancel-button"
/>
{AdditionalButtons}
{AdditionalButtons}
<StyledCenteredButton
onClick={handleConfirmClick}
variant="secondary"
accent={confirmButtonAccent}
title={confirmButtonText}
disabled={!isValidValue || loading}
fullWidth
dataTestId="confirmation-modal-confirm-button"
/>
</StyledConfirmationModal>
</LayoutGroup>
</AnimatePresence>
<StyledCenteredButton
onClick={handleConfirmClick}
variant="secondary"
accent={confirmButtonAccent}
title={confirmButtonText}
disabled={!isValidValue || loading}
fullWidth
dataTestId="confirmation-modal-confirm-button"
/>
</StyledConfirmationModal>
);
};

View File

@ -12,7 +12,7 @@ import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { css, useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { motion } from 'framer-motion';
import { AnimatePresence, motion } from 'framer-motion';
import React, { useRef } from 'react';
const StyledModalDiv = styled(motion.div)<{
size?: ModalSize;
@ -221,7 +221,7 @@ export const Modal = ({
};
return (
<>
<AnimatePresence mode="wait">
{isModalOpened && (
<ModalComponentInstanceContext.Provider
value={{
@ -266,7 +266,7 @@ export const Modal = ({
</ClickOutsideListenerContext.Provider>
</ModalComponentInstanceContext.Provider>
)}
</>
</AnimatePresence>
);
};