Skip to content

Commit b06fdb1

Browse files
Cherry-pick: Fix action menu modals rendering (twentyhq#16478)
1 parent 7f07617 commit b06fdb1

File tree

3 files changed

+31
-21
lines changed

3 files changed

+31
-21
lines changed

packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ export const ConfirmationModal = ({
117117
padding="large"
118118
modalVariant={modalVariant}
119119
dataGloballyPreventClickOutside
120+
ignoreContainer
120121
>
121122
<StyledCenteredTitle>
122123
<H1Title title={title} fontColor={H1TitleFontColor.Primary} />

packages/twenty-front/src/modules/ui/layout/modal/components/Modal.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import styled from '@emotion/styled';
1515
import { AnimatePresence, motion } from 'framer-motion';
1616
import React, { useRef } from 'react';
1717
import { createPortal } from 'react-dom';
18+
import { isDefined } from 'twenty-shared/utils';
1819
const StyledModalDiv = styled(motion.div)<{
1920
size?: ModalSize;
2021
padding?: ModalPadding;
@@ -200,6 +201,7 @@ export type ModalProps = React.PropsWithChildren & {
200201
modalVariant?: ModalVariants;
201202
dataGloballyPreventClickOutside?: boolean;
202203
shouldCloseModalOnClickOutsideOrEscape?: boolean;
204+
ignoreContainer?: boolean;
203205
} & (
204206
| { isClosable: true; onClose?: () => void }
205207
| { isClosable?: false; onClose?: never }
@@ -223,11 +225,17 @@ export const Modal = ({
223225
modalVariant = 'primary',
224226
dataGloballyPreventClickOutside = false,
225227
shouldCloseModalOnClickOutsideOrEscape = true,
228+
ignoreContainer = false,
226229
}: ModalProps) => {
227230
const isMobile = useIsMobile();
228231
const modalRef = useRef<HTMLDivElement>(null);
229232
const { container } = useModalContainer();
230-
const isInContainer = container !== null;
233+
const effectiveContainer = ignoreContainer
234+
? isDefined(document)
235+
? document.body
236+
: null
237+
: container;
238+
const isInContainer = isDefined(container) && !ignoreContainer;
231239

232240
const theme = useTheme();
233241

@@ -300,8 +308,8 @@ export const Modal = ({
300308
</AnimatePresence>
301309
);
302310

303-
if (container !== null) {
304-
return createPortal(modalContent, container);
311+
if (isDefined(effectiveContainer)) {
312+
return createPortal(modalContent, effectiveContainer);
305313
}
306314

307315
return modalContent;

packages/twenty-front/src/modules/ui/layout/modal/components/__stories__/ConfirmationModal.stories.tsx

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export const Default: Story = {
5656
title: 'Pariatur labore.',
5757
subtitle: 'Velit dolore aliquip laborum occaecat fugiat.',
5858
confirmButtonText: 'Delete',
59+
onConfirmClick: fn(),
5960
},
6061
};
6162

@@ -75,10 +76,10 @@ export const CloseOnEscape: Story = {
7576
confirmButtonText: 'Confirm',
7677
onClose: closeMock,
7778
},
78-
play: async ({ canvasElement }) => {
79-
const canvas = within(canvasElement);
79+
play: async () => {
80+
const body = within(document.body);
8081

81-
await canvas.findByText('Escape Key Test');
82+
await body.findByText('Escape Key Test');
8283

8384
closeMock.mockClear();
8485

@@ -98,12 +99,12 @@ export const CloseOnClickOutside: Story = {
9899
confirmButtonText: 'Confirm',
99100
onClose: closeMock,
100101
},
101-
play: async ({ canvasElement }) => {
102-
const canvas = within(canvasElement);
102+
play: async () => {
103+
const body = within(document.body);
103104

104-
await canvas.findByText('Click Outside Test');
105+
await body.findByText('Click Outside Test');
105106

106-
const backdrop = await canvas.findByTestId('modal-backdrop');
107+
const backdrop = await body.findByTestId('modal-backdrop');
107108

108109
// We need to wait for the outside click listener to be registered
109110
await sleep(100);
@@ -124,10 +125,10 @@ export const ConfirmWithEnterKey: Story = {
124125
confirmButtonText: 'Confirm',
125126
onConfirmClick: confirmMock,
126127
},
127-
play: async ({ canvasElement }) => {
128-
const canvas = within(canvasElement);
128+
play: async () => {
129+
const body = within(document.body);
129130

130-
await canvas.findByText('Enter Key Test');
131+
await body.findByText('Enter Key Test');
131132

132133
await userEvent.keyboard('{Enter}');
133134

@@ -145,12 +146,12 @@ export const CancelButtonClick: Story = {
145146
confirmButtonText: 'Confirm',
146147
onClose: closeMock,
147148
},
148-
play: async ({ canvasElement }) => {
149-
const canvas = within(canvasElement);
149+
play: async () => {
150+
const body = within(document.body);
150151

151-
await canvas.findByText('Cancel Button Test');
152+
await body.findByText('Cancel Button Test');
152153

153-
const cancelButton = await canvas.findByRole('button', {
154+
const cancelButton = await body.findByRole('button', {
154155
name: /Cancel/,
155156
});
156157
await userEvent.click(cancelButton);
@@ -169,12 +170,12 @@ export const ConfirmButtonClick: Story = {
169170
confirmButtonText: 'Confirm',
170171
onConfirmClick: confirmMock,
171172
},
172-
play: async ({ canvasElement }) => {
173-
const canvas = within(canvasElement);
173+
play: async () => {
174+
const body = within(document.body);
174175

175-
await canvas.findByText('Confirm Button Test');
176+
await body.findByText('Confirm Button Test');
176177

177-
const confirmButton = await canvas.findByRole('button', {
178+
const confirmButton = await body.findByRole('button', {
178179
name: /Confirm/,
179180
});
180181

0 commit comments

Comments
 (0)