Skip to content

Commit 9db5775

Browse files
authored
fix(modal): center overlays using flexbox via renderDialog (#2477)
use react-overlays' renderDialog prop to render a full-viewport flex container that centers modal children, replacing the fragile position:fixed + transform centering on the Modal component. - overlay.tsx: use renderDialog for flexbox centering, add z-max to backdrop and dialog container, simplify OverlayProps interface (hidden is now optional, decoupled from react-overlays types) - modal.tsx: remove position:fixed centering (overlay owns layout) - remove @ts-expect-error from buffer-config-modal and log-warning-modal (hidden is now optional) - ipns e2e test: dismiss import notification before opening the publish modal (dialog overlay now correctly blocks interaction with content behind it)
1 parent bd8f77f commit 9db5775

File tree

5 files changed

+28
-28
lines changed

5 files changed

+28
-28
lines changed

src/components/modal/modal.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,7 @@ export const Modal: React.FC<ModalProps> = ({
7272
<div
7373
className={`${className} bg-white w-80 shadow-4 sans-serif relative`}
7474
data-testid="ipfs-modal"
75-
style={{
76-
maxWidth: '34em',
77-
position: 'fixed',
78-
top: '50%',
79-
left: '50%',
80-
transform: 'translate(-50%, -50%)'
81-
}}
75+
style={{ maxWidth: '34em' }}
8276
{...props}
8377
>
8478
{onCancel && (

src/components/overlay/overlay.tsx

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,37 @@
11
import React from 'react'
22
import { Modal } from 'react-overlays'
33

4-
type ModalProps = React.ComponentProps<typeof Modal>
5-
6-
export interface OverlayProps extends Omit<ModalProps, 'renderBackdrop' | 'onHide'> {
4+
export interface OverlayProps {
75
show: boolean
86
onLeave: () => void
9-
hidden: boolean
7+
hidden?: boolean
8+
className?: string
9+
children?: React.ReactNode
1010
}
1111

12-
const Overlay: React.FC<OverlayProps> = ({ children, show, onLeave, className = '', hidden, ...props }) => {
13-
const renderBackdrop: React.FC<React.HTMLAttributes<HTMLDivElement>> = (props) => (
14-
<div className='fixed top-0 left-0 right-0 bottom-0 bg-black o-50' hidden={hidden} {...props} />
15-
)
16-
12+
const Overlay: React.FC<OverlayProps> = ({ children, show, onLeave, hidden }) => {
1713
return (
18-
// Note: react-overlays Modal manages its own portal and positioning.
19-
// The Modal child component uses fixed positioning to center itself.
20-
// onHide handles both backdrop clicks and escape key presses.
2114
<Modal
22-
{...props}
2315
show={show}
2416
backdrop={true}
25-
className={`${className} z-max`}
26-
renderBackdrop={renderBackdrop}
27-
onHide={onLeave}>
17+
onHide={onLeave}
18+
renderBackdrop={(props) => (
19+
<div className='fixed top-0 left-0 right-0 bottom-0 bg-black o-50 z-max' hidden={hidden} {...props} />
20+
)}
21+
renderDialog={(dialogProps) => (
22+
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/click-events-have-key-events
23+
<div
24+
{...dialogProps}
25+
role='dialog'
26+
className={`${dialogProps.className || ''} fixed top-0 left-0 right-0 bottom-0 flex justify-center items-center z-max`}
27+
style={{ outline: 'none' }}
28+
onClick={(e: React.MouseEvent) => {
29+
if (e.target === e.currentTarget) onLeave()
30+
}}
31+
>
32+
{children}
33+
</div>
34+
)}>
2835
{children}
2936
</Modal>
3037
)

src/diagnostics/logs-screen/buffer-config-modal.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ export const BufferConfigModal: React.FC<BufferConfigModalProps> = ({
6363
}
6464

6565
return (
66-
// @ts-expect-error - Overlay is not typed
6766
<Overlay show={isOpen} onLeave={handleCancel}>
6867
<Modal onCancel={handleCancel} className="outline-0">
6968
<div className='pa4'>

src/diagnostics/logs-screen/log-warning-modal.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ const LogWarningModal: React.FC<LogWarningModalProps> = ({
8383
if (warningType == null) return null
8484

8585
return (
86-
// @ts-expect-error - Overlay is not typed
8786
<Overlay show={isOpen} onLeave={onClose}>
8887
<Modal onCancel={onClose} className="outline-0">
8988
<ModalBody>

test/e2e/ipns.test.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ test.describe('IPNS publishing', () => {
114114
const fileRow = page.getByTestId('file-row').filter({ hasText: testFilename })
115115
await expect(fileRow).toBeVisible()
116116

117+
// dismiss import notification before opening the publish modal
118+
// (modal overlay blocks interaction with content behind it)
119+
await dismissImportNotification(page)
120+
117121
// click on the context menu
118122
await page.locator(`.File:has-text('${testFilename}') .file-context-menu`).click()
119123

@@ -135,9 +139,6 @@ test.describe('IPNS publishing', () => {
135139
// (ipns will fail to publish without peers)
136140
await ipfs.swarm.connect(peerAddr)
137141

138-
// dismiss import notification created earlier in this test
139-
await dismissImportNotification(page)
140-
141142
await publishButton.click()
142143

143144
// IPNS publishing can take time depending on network/DHT conditions

0 commit comments

Comments
 (0)