Skip to content

Commit ba5ddfd

Browse files
authored
Modal styles (#1029)
* Update vendored Modal file * Add dialogStyle and contentStyle props to Modal * Add tests
1 parent 5883af7 commit ba5ddfd

File tree

4 files changed

+133
-25
lines changed

4 files changed

+133
-25
lines changed

src/components/modal/Modal.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ const Modal = props => {
3232
style,
3333
zindex,
3434
zIndex,
35+
dialogStyle,
36+
dialog_style,
37+
contentStyle,
38+
content_style,
3539
...otherProps
3640
} = props;
3741

@@ -45,6 +49,8 @@ const Modal = props => {
4549
<RBModal
4650
animation={fade}
4751
dialogAs={tag}
52+
dialogStyle={dialog_style || dialogStyle}
53+
contentStyle={content_style || contentStyle}
4854
dialogClassName={class_name || className}
4955
className={modal_class_name || modalClassName}
5056
contentClassName={content_class_name || contentClassName}
@@ -87,6 +93,26 @@ Modal.propTypes = {
8793
*/
8894
style: PropTypes.object,
8995

96+
/**
97+
* Inline CSS styles to apply to the dialog
98+
*/
99+
dialog_style: PropTypes.object,
100+
101+
/**
102+
* Inline CSS styles to apply to the dialog
103+
*/
104+
dialogStyle: PropTypes.object,
105+
106+
/**
107+
* Inline CSS styles to apply to the content
108+
*/
109+
content_style: PropTypes.object,
110+
111+
/**
112+
* Inline CSS styles to apply to the content
113+
*/
114+
contentStyle: PropTypes.object,
115+
90116
/**
91117
* Often used with CSS to style elements with common properties.
92118
*/

src/components/modal/__tests__/Modal.test.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ describe('Modal', () => {
7575
'custom-modal-content'
7676
);
7777

78+
// Content style
79+
rerender(<Modal is_open content_style={{backgroundColor: 'red'}} />);
80+
expect(document.body.querySelector('.modal-content')).toHaveStyle({
81+
backgroundColor: 'red'
82+
});
83+
7884
// Backdrop class name
7985
rerender(<Modal is_open backdrop_class_name="custom-modal-backdrop" />);
8086
expect(document.body.querySelector('.modal-backdrop')).toHaveClass(
@@ -87,6 +93,19 @@ describe('Modal', () => {
8793
'custom-modal-dialog'
8894
);
8995

96+
// Dialog style
97+
rerender(
98+
<Modal
99+
is_open
100+
dialog_style={{position: 'absolute', top: '10px', left: '10px'}}
101+
/>
102+
);
103+
expect(document.body.querySelector('.modal-dialog')).toHaveStyle({
104+
position: 'absolute',
105+
top: '10px',
106+
left: '10px'
107+
});
108+
90109
// Modal class name
91110
rerender(<Modal is_open modal_class_name="custom-modal-class" />);
92111
expect(document.body.querySelector('.modal')).toHaveClass(

src/private/Modal.js

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// vendored from React-Bootstrap to allow us to set z-index of Modal backdrop
2-
// https://github.com/react-bootstrap/react-bootstrap/blob/93a8a0ef29409293dd69fad5873ad791634b3ed1/src/Modal.tsx
2+
// https://github.com/react-bootstrap/react-bootstrap/blob/be23c304fa40ddb209919b0faac1e5dd8cef53ad/src/Modal.tsx
33
import React, {useCallback, useMemo, useRef, useState} from 'react';
44

55
import classNames from 'classnames';
@@ -18,9 +18,10 @@ import BaseModal from '@restart/ui/Modal';
1818
import {getSharedManager} from 'react-bootstrap/BootstrapModalManager';
1919
import Fade from 'react-bootstrap/Fade';
2020
import ModalContext from 'react-bootstrap/ModalContext';
21-
import ModalDialog from 'react-bootstrap/ModalDialog';
2221
import {useBootstrapPrefix, useIsRTL} from 'react-bootstrap/ThemeProvider';
2322

23+
import ModalDialog from './ModalDialog';
24+
2425
const defaultProps = {
2526
show: false,
2627
backdrop: true,
@@ -51,7 +52,10 @@ const Modal = React.forwardRef(
5152
dialogClassName,
5253
contentClassName,
5354
children,
55+
dialogStyle,
56+
contentStyle,
5457
dialogAs: Dialog,
58+
'data-bs-theme': dataBsTheme,
5559
'aria-labelledby': ariaLabelledby,
5660
'aria-describedby': ariaDescribedby,
5761
'aria-label': ariaLabel,
@@ -139,7 +143,7 @@ const Modal = React.forwardRef(
139143
});
140144

141145
// We prevent the modal from closing during a drag by detecting where the
142-
// the click originates from. If it starts in the modal and then ends outside
146+
// click originates from. If it starts in the modal and then ends outside
143147
// don't close.
144148
const handleDialogMouseDown = () => {
145149
waitingForMouseUpRef.current = true;
@@ -185,13 +189,16 @@ const Modal = React.forwardRef(
185189
};
186190

187191
const handleEscapeKeyDown = e => {
188-
if (!keyboard && backdrop === 'static') {
189-
// Call preventDefault to stop modal from closing in restart ui,
190-
// then play our animation.
192+
if (keyboard) {
193+
onEscapeKeyDown?.(e);
194+
} else {
195+
// Call preventDefault to stop modal from closing in @restart/ui.
191196
e.preventDefault();
192-
handleStaticModalAnimation();
193-
} else if (keyboard && onEscapeKeyDown) {
194-
onEscapeKeyDown(e);
197+
198+
if (backdrop === 'static') {
199+
// Play static modal animation.
200+
handleStaticModalAnimation();
201+
}
195202
}
196203
};
197204

@@ -224,19 +231,17 @@ const Modal = React.forwardRef(
224231
};
225232

226233
const renderBackdrop = useCallback(
227-
backdropProps => {
228-
return (
229-
<div
230-
{...backdropProps}
231-
className={classNames(
232-
`${bsPrefix}-backdrop`,
233-
backdropClassName,
234-
!animation && 'show'
235-
)}
236-
style={{zIndex}}
237-
/>
238-
);
239-
},
234+
backdropProps => (
235+
<div
236+
{...backdropProps}
237+
className={classNames(
238+
`${bsPrefix}-backdrop`,
239+
backdropClassName,
240+
!animation && 'show'
241+
)}
242+
style={{zIndex}}
243+
/>
244+
),
240245
[animation, backdropClassName, bsPrefix, zIndex]
241246
);
242247

@@ -254,21 +259,23 @@ const Modal = React.forwardRef(
254259
className={classNames(
255260
className,
256261
bsPrefix,
257-
animateStaticModal && `${bsPrefix}-static`
262+
animateStaticModal && `${bsPrefix}-static`,
263+
!animation && 'show'
258264
)}
259265
onClick={backdrop ? handleClick : undefined}
260266
onMouseUp={handleMouseUp}
267+
data-bs-theme={dataBsTheme}
261268
aria-label={ariaLabel}
262269
aria-labelledby={ariaLabelledby}
263270
aria-describedby={ariaDescribedby}
264271
>
265-
{/*
266-
// @ts-ignore */}
267272
<Dialog
268273
{...props}
269274
onMouseDown={handleDialogMouseDown}
270275
className={dialogClassName}
271276
contentClassName={contentClassName}
277+
style={dialogStyle}
278+
contentStyle={contentStyle}
272279
>
273280
{children}
274281
</Dialog>

src/private/ModalDialog.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// vendored from React-Bootstrap to allow us to set content style
2+
// https://github.com/react-bootstrap/react-bootstrap/blob/be23c304fa40ddb209919b0faac1e5dd8cef53ad/src/ModalDialog.tsx
3+
import React from 'react';
4+
5+
import classNames from 'classnames';
6+
import {useBootstrapPrefix} from 'react-bootstrap/ThemeProvider';
7+
8+
const ModalDialog = React.forwardRef(
9+
(
10+
{
11+
bsPrefix,
12+
className,
13+
contentClassName,
14+
centered,
15+
size,
16+
fullscreen,
17+
children,
18+
scrollable,
19+
contentStyle,
20+
...props
21+
},
22+
ref
23+
) => {
24+
bsPrefix = useBootstrapPrefix(bsPrefix, 'modal');
25+
const dialogClass = `${bsPrefix}-dialog`;
26+
27+
const fullScreenClass =
28+
typeof fullscreen === 'string'
29+
? `${bsPrefix}-fullscreen-${fullscreen}`
30+
: `${bsPrefix}-fullscreen`;
31+
32+
return (
33+
<div
34+
{...props}
35+
ref={ref}
36+
className={classNames(
37+
dialogClass,
38+
className,
39+
size && `${bsPrefix}-${size}`,
40+
centered && `${dialogClass}-centered`,
41+
scrollable && `${dialogClass}-scrollable`,
42+
fullscreen && fullScreenClass
43+
)}
44+
>
45+
<div
46+
className={classNames(`${bsPrefix}-content`, contentClassName)}
47+
style={contentStyle}
48+
>
49+
{children}
50+
</div>
51+
</div>
52+
);
53+
}
54+
);
55+
56+
export default ModalDialog;

0 commit comments

Comments
 (0)