Skip to content

Commit 4d19b09

Browse files
SethTheSharpieOne
authored andcommitted
feat(Modal): add charCode prop for custom icon (#1162)
Closes #1155
1 parent 2a9ac21 commit 4d19b09

File tree

4 files changed

+78
-1
lines changed

4 files changed

+78
-1
lines changed

docs/lib/Components/ModalsPage.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ const ModalFadelessExampleSource = require('!!raw!../examples/ModalFadeless');
2121
import ModalExternalExample from '../examples/ModalExternal';
2222
const ModalExternalExampleSource = require('!!raw!../examples/ModalExternal');
2323

24+
import ModalCustomCloseIconExample from '../examples/ModalCustomCloseIcon';
25+
const ModalCustomCloseIconExampleSource = require('!!raw!../examples/ModalCutomCloseIcon');
26+
2427
export default class ModalsPage extends React.Component {
2528
render() {
2629
return (
@@ -171,6 +174,20 @@ export default class ModalsPage extends React.Component {
171174
{ModalExternalExampleSource}
172175
</PrismCode>
173176
</pre>
177+
178+
<h4>Modals with custom close icon</h4>
179+
<div className="docs-example">
180+
<div className="btn-group">
181+
<div className="btn">
182+
<ModalCustomCloseIconExample buttonLabel="Launch Modal with custom close button" />
183+
</div>
184+
</div>
185+
</div>
186+
<pre>
187+
<PrismCode className="language-jsx">
188+
{ModalCustomCloseIconExampleSource}
189+
</PrismCode>
190+
</pre>
174191
</div>
175192
);
176193
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/* eslint react/no-multi-comp: 0, react/prop-types: 0 */
2+
3+
import React from 'react';
4+
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
5+
6+
class ModalExample extends React.Component {
7+
constructor(props) {
8+
super(props);
9+
this.state = {
10+
modal: false
11+
};
12+
13+
this.toggle = this.toggle.bind(this);
14+
}
15+
16+
toggle() {
17+
this.setState({
18+
modal: !this.state.modal
19+
});
20+
}
21+
22+
render() {
23+
return (
24+
<div>
25+
<Button color="danger" onClick={this.toggle}>{this.props.buttonLabel}</Button>
26+
<Modal isOpen={this.state.modal} toggle={this.toggle} className={this.props.className}>
27+
<ModalHeader toggle={this.toggle} charCode="Y">Modal title</ModalHeader>
28+
<ModalBody>
29+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
30+
</ModalBody>
31+
<ModalFooter>
32+
<Button color="primary" onClick={this.toggle}>Do Something</Button>{' '}
33+
<Button color="secondary" onClick={this.toggle}>Cancel</Button>
34+
</ModalFooter>
35+
</Modal>
36+
</div>
37+
);
38+
}
39+
}
40+
41+
export default ModalExample;

src/ModalHeader.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ const propTypes = {
1111
cssModule: PropTypes.object,
1212
children: PropTypes.node,
1313
closeAriaLabel: PropTypes.string,
14+
charCode: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
1415
};
1516

1617
const defaultProps = {
1718
tag: 'h5',
1819
wrapTag: 'div',
1920
closeAriaLabel: 'Close',
21+
charCode: 215,
2022
};
2123

2224
const ModalHeader = (props) => {
@@ -29,6 +31,7 @@ const ModalHeader = (props) => {
2931
tag: Tag,
3032
wrapTag: WrapTag,
3133
closeAriaLabel,
34+
charCode,
3235
...attributes } = props;
3336

3437
const classes = mapToCssModules(classNames(
@@ -37,9 +40,10 @@ const ModalHeader = (props) => {
3740
), cssModule);
3841

3942
if (toggle) {
43+
const closeIcon = typeof charCode === 'number' ? String.fromCharCode(charCode) : charCode;
4044
closeButton = (
4145
<button type="button" onClick={toggle} className={mapToCssModules('close', cssModule)} aria-label={closeAriaLabel}>
42-
<span aria-hidden="true">{String.fromCharCode(215)}</span>
46+
<span aria-hidden="true">{closeIcon}</span>
4347
</button>
4448
);
4549
}

src/__tests__/ModalHeader.spec.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,19 @@ describe('ModalHeader', () => {
4444
const closeButton = wrapper.find('button.close').first();
4545
expect(closeButton.prop('aria-label')).toBe('oseclay');
4646
});
47+
48+
it('should render close button with default icon', () => {
49+
const wrapper = shallow(<ModalHeader toggle={() => {}}>Yo!</ModalHeader>);
50+
51+
const closeButtonIcon = wrapper.find('button.close span');
52+
const defaultIcon = String.fromCharCode(215);
53+
expect(closeButtonIcon.text()).toEqual(defaultIcon);
54+
});
55+
56+
it('should render close button with custom icon', () => {
57+
const wrapper = shallow(<ModalHeader toggle={() => {}} charCode={'X'}>Yo!</ModalHeader>);
58+
59+
const closeButtonIcon = wrapper.find('button.close span');
60+
expect(closeButtonIcon.text()).toEqual('X');
61+
});
4762
});

0 commit comments

Comments
 (0)