Skip to content

Commit c3ae9bd

Browse files
committed
change Modal component to FC
1 parent 07f8a41 commit c3ae9bd

File tree

1 file changed

+107
-91
lines changed

1 file changed

+107
-91
lines changed

src/scripts/Modal.tsx

Lines changed: 107 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,25 @@
1-
import React, { Component, HTMLAttributes, CSSProperties } from 'react';
1+
import React, {
2+
HTMLAttributes,
3+
CSSProperties,
4+
FC,
5+
createContext,
6+
useContext,
7+
useCallback,
8+
useMemo,
9+
} from 'react';
210
import classnames from 'classnames';
311
import { Button } from './Button';
412

13+
/**
14+
*
15+
*/
16+
const ModalHandlersContext = createContext<{
17+
onHide?: () => void;
18+
}>({});
19+
20+
/**
21+
*
22+
*/
523
export type ModalHeaderProps = {
624
className?: string;
725
title?: string;
@@ -10,48 +28,54 @@ export type ModalHeaderProps = {
1028
onClose?: () => void;
1129
};
1230

13-
export class ModalHeader extends Component<ModalHeaderProps> {
14-
constructor(props: Readonly<ModalHeaderProps>) {
15-
super(props);
16-
17-
this.onClose = this.onClose.bind(this);
18-
}
19-
20-
onClose() {
21-
if (this.props.onClose) {
22-
this.props.onClose();
23-
}
24-
}
25-
26-
render() {
27-
const { className, title, tagline, closeButton, ...props } = this.props;
28-
delete props.onClose;
29-
const hdClassNames = classnames(className, 'slds-modal__header');
30-
return (
31-
<div className={hdClassNames} {...props}>
32-
<h2 className='slds-text-heading_medium'>{title}</h2>
33-
{tagline ? <p className='slds-m-top_x-small'>{tagline}</p> : null}
34-
{closeButton ? (
35-
<Button
36-
type='icon-inverse'
37-
className='slds-modal__close'
38-
icon='close'
39-
iconSize='large'
40-
alt='Close'
41-
inverse
42-
onClick={this.onClose}
43-
/>
44-
) : null}
45-
</div>
46-
);
47-
}
48-
}
31+
/**
32+
*
33+
*/
34+
export const ModalHeader: FC<ModalHeaderProps> = (props_) => {
35+
const {
36+
className,
37+
title,
38+
tagline,
39+
closeButton,
40+
onClose: onClose_,
41+
...rprops
42+
} = props_;
43+
const { onHide: onHideModal } = useContext(ModalHandlersContext);
44+
const onClose = useCallback(() => {
45+
onClose_?.();
46+
onHideModal?.();
47+
}, [onHideModal, onClose_]);
48+
const hdClassNames = classnames(className, 'slds-modal__header');
49+
return (
50+
<div className={hdClassNames} {...rprops}>
51+
<h2 className='slds-text-heading_medium'>{title}</h2>
52+
{tagline ? <p className='slds-m-top_x-small'>{tagline}</p> : null}
53+
{closeButton ? (
54+
<Button
55+
type='icon-inverse'
56+
className='slds-modal__close'
57+
icon='close'
58+
iconSize='large'
59+
alt='Close'
60+
inverse
61+
onClick={onClose}
62+
/>
63+
) : null}
64+
</div>
65+
);
66+
};
4967

68+
/**
69+
*
70+
*/
5071
export type ModalContentProps = {
5172
className?: string;
5273
};
5374

54-
export const ModalContent: React.FC<ModalContentProps> = ({
75+
/**
76+
*
77+
*/
78+
export const ModalContent: FC<ModalContentProps> = ({
5579
className,
5680
children,
5781
...props
@@ -64,12 +88,18 @@ export const ModalContent: React.FC<ModalContentProps> = ({
6488
);
6589
};
6690

91+
/**
92+
*
93+
*/
6794
export type ModalFooterProps = {
6895
className?: string;
6996
directional?: boolean;
7097
};
7198

72-
export const ModalFooter: React.FC<ModalFooterProps> = ({
99+
/**
100+
*
101+
*/
102+
export const ModalFooter: FC<ModalFooterProps> = ({
73103
className,
74104
directional,
75105
children,
@@ -85,6 +115,9 @@ export const ModalFooter: React.FC<ModalFooterProps> = ({
85115
);
86116
};
87117

118+
/**
119+
*
120+
*/
88121
export type ModalSize = 'large';
89122

90123
export type ModalProps = {
@@ -94,57 +127,40 @@ export type ModalProps = {
94127
onHide?: () => void;
95128
} & HTMLAttributes<HTMLDivElement>;
96129

97-
export class Modal extends Component<ModalProps> {
98-
static Header = ModalHeader;
99-
100-
static Content = ModalContent;
101-
102-
static Footer = ModalFooter;
103-
104-
constructor(props: Readonly<ModalProps>) {
105-
super(props);
106-
107-
this.renderChildComponent = this.renderChildComponent.bind(this);
108-
}
109-
110-
hide() {
111-
if (this.props.onHide) {
112-
this.props.onHide();
113-
}
114-
}
115-
116-
renderChildComponent(comp: any) {
117-
if (comp.type === ModalHeader) {
118-
return React.cloneElement(comp, { onClose: this.hide.bind(this) } as any);
119-
}
120-
return comp;
121-
}
122-
123-
render() {
124-
const { className, opened, children, size, containerStyle, ...props } =
125-
this.props;
126-
delete props.onHide;
127-
const modalClassNames = classnames(className, 'slds-modal', {
128-
'slds-fade-in-open': opened,
129-
'slds-modal_large': size === 'large',
130-
});
131-
const backdropClassNames = classnames(className, 'slds-backdrop', {
132-
'slds-backdrop_open': opened,
133-
});
134-
return (
135-
<div>
136-
<div
137-
className={modalClassNames}
138-
aria-hidden={!opened}
139-
role='dialog'
140-
{...props}
141-
>
142-
<div className='slds-modal__container' style={containerStyle}>
143-
{React.Children.map(children, this.renderChildComponent)}
144-
</div>
130+
/**
131+
*
132+
*/
133+
export const Modal: FC<ModalProps> = (props) => {
134+
const {
135+
className,
136+
opened,
137+
children,
138+
size,
139+
containerStyle,
140+
onHide,
141+
...rprops
142+
} = props;
143+
const modalClassNames = classnames(className, 'slds-modal', {
144+
'slds-fade-in-open': opened,
145+
'slds-modal_large': size === 'large',
146+
});
147+
const backdropClassNames = classnames(className, 'slds-backdrop', {
148+
'slds-backdrop_open': opened,
149+
});
150+
const handlers = useMemo(() => ({ onHide }), [onHide]);
151+
return (
152+
<ModalHandlersContext.Provider value={handlers}>
153+
<div
154+
className={modalClassNames}
155+
aria-hidden={!opened}
156+
role='dialog'
157+
{...rprops}
158+
>
159+
<div className='slds-modal__container' style={containerStyle}>
160+
{children}
145161
</div>
146-
<div className={backdropClassNames} />
147162
</div>
148-
);
149-
}
150-
}
163+
<div className={backdropClassNames} />
164+
</ModalHandlersContext.Provider>
165+
);
166+
};

0 commit comments

Comments
 (0)