Skip to content

Commit 1b1af04

Browse files
committed
[changed] deprecate ModalTrigger
1 parent 83b4cbc commit 1b1af04

File tree

6 files changed

+133
-42
lines changed

6 files changed

+133
-42
lines changed

docs/generate-metadata.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ let isLiteral = str => (/^('|")/).test(str.trim());
2626
* @param {ComponentMetadata|PropMetadata} obj
2727
*/
2828
function parseDoclets(obj){
29-
obj.doclets = metadata.parseDoclets(obj.desc || '');
29+
obj.doclets = metadata.parseDoclets(obj.desc || '') || {};
3030
obj.desc = cleanDoclets(obj.desc || '');
3131
obj.descHtml = marked(obj.desc || '');
3232
}

docs/src/PropTable.js

+61-31
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,46 @@ import Label from '../../src/Label';
55
import Table from '../../src/Table';
66

77

8-
let cleanDocletValue = str => str.replace(/^\{|\}$/g, '');
8+
let cleanDocletValue = str => str.trim().replace(/^\{/, '').replace(/\}$/, '');
9+
10+
function getPropsData(componentData, metadata){
11+
12+
let props = componentData.props || {};
13+
14+
if (componentData.composes) {
15+
componentData.composes.forEach( other => {
16+
props = merge({}, getPropsData(metadata[other] || {}, metadata), props);
17+
18+
});
19+
}
20+
21+
if (componentData.mixins) {
22+
componentData.mixins.forEach( other => {
23+
if ( componentData.composes.indexOf(other) === -1) {
24+
props = merge({}, getPropsData(metadata[other] || {}, metadata), props);
25+
}
26+
});
27+
}
28+
29+
return props;
30+
}
931

1032
const PropTable = React.createClass({
1133

1234
contextTypes: {
1335
metadata: React.PropTypes.object
1436
},
1537

38+
componentWillMount(){
39+
let componentData = this.context.metadata[this.props.component] || {};
40+
41+
this.propsData = getPropsData(componentData, this.context.metadata);
42+
},
43+
1644
render(){
17-
let metadata = this.context.metadata[this.props.component] || {};
45+
let propsData = this.propsData;
1846

19-
if ( !Object.keys(metadata.props || {}).length){
47+
if ( !Object.keys(propsData).length){
2048
return <span/>;
2149
}
2250

@@ -31,46 +59,36 @@ const PropTable = React.createClass({
3159
</tr>
3260
</thead>
3361
<tbody>
34-
{ this._renderRows() }
62+
{ this._renderRows(propsData) }
3563
</tbody>
3664
</Table>
3765
);
3866
},
3967

40-
_renderRows(){
41-
let metadata = this.context.metadata[this.props.component] || {};
42-
let props = metadata.props || {};
68+
_renderRows(propsData){
4369

44-
if (metadata.composes) {
45-
metadata.composes.forEach( other => {
46-
props = merge(props, (this.context.metadata[other] || {}).props);
47-
});
48-
}
49-
50-
if (metadata.mixins) {
51-
metadata.mixins.forEach( other => {
52-
if ( metadata.composes.indexOf(other) === -1) {
53-
props = merge(props, (this.context.metadata[other] || {}).props);
54-
}
55-
});
56-
}
57-
58-
return Object.keys(props)
70+
return Object.keys(propsData)
5971
.sort()
60-
.filter(propName => props[propName].type && !props[propName].doclets.private )
72+
.filter(propName => propsData[propName].type && !propsData[propName].doclets.private )
6173
.map(propName => {
62-
let prop = props[propName];
74+
let propData = propsData[propName];
6375

6476
return (
6577
<tr key={propName} className='prop-table-row'>
6678
<td>
67-
{propName} {this.renderRequiredLabel(prop)}
79+
{propName} {this.renderRequiredLabel(propData)}
6880
</td>
6981
<td>
70-
<div>{this.getType(prop)}</div>
82+
<div>{this.getType(propData)}</div>
83+
</td>
84+
<td>{propData.defaultValue}</td>
85+
86+
<td>
87+
{ propData.doclets.deprecated
88+
&& <div><strong className='text-danger'>{'Deprecated: ' + propData.doclets.deprecated + ' '}</strong></div>
89+
}
90+
<div dangerouslySetInnerHTML={{__html: propData.descHtml }} />
7191
</td>
72-
<td>{prop.defaultValue}</td>
73-
<td dangerouslySetInnerHTML={{__html: prop.descHtml }}></td>
7492
</tr>
7593
);
7694
});
@@ -87,17 +105,29 @@ const PropTable = React.createClass({
87105
},
88106

89107
getType(prop) {
90-
let type = prop.type;
108+
let type = prop.type || {};
91109
let name = this.getDisplayTypeName(type.name);
92110
let doclets = prop.doclets || {};
93111

94112
switch (name) {
95113
case 'object':
96114
return name;
97115
case 'union':
98-
return type.value.map(val => this.getType({ type: val })).join(' | ');
116+
return type.value.reduce((current, val, i, list) => {
117+
let item = this.getType({ type: val });
118+
119+
if (React.isValidElement(item)) {
120+
item = React.cloneElement(item, {key: i});
121+
}
122+
123+
current = current.concat(item);
124+
125+
return i === (list.length - 1) ? current : current.concat(' | ');
126+
}, []);
99127
case 'array':
100-
return `array<${this.getDisplayTypeName(type.value.name)}>`;
128+
let child = this.getType({ type: type.value });
129+
130+
return <span>{'array<'}{ child }{'>'}</span>;
101131
case 'enum':
102132
return this.renderEnum(type);
103133
case 'custom':

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595
"phantomjs": "^1.9.17",
9696
"portfinder": "^0.4.0",
9797
"react": "^0.13.1",
98-
"react-component-metadata": "^1.1.1",
98+
"react-component-metadata": "^1.2.1",
9999
"react-hot-loader": "^1.2.7",
100100
"react-router": "^0.13.1",
101101
"rimraf": "^2.3.2",

src/ModalTrigger.js

+49-9
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
import React, { cloneElement } from 'react';
2-
import OverlayMixin from './OverlayMixin';
2+
3+
import deprecationWarning from './utils/deprecationWarning';
34

45
import createChainedFunction from './utils/createChainedFunction';
56
import createContextWrapper from './utils/createContextWrapper';
67

8+
function createHideDepreciationWrapper(hide){
9+
return function(...args){
10+
deprecationWarning(
11+
'The Modal prop `onRequestHide`', 'the `onHide` prop');
12+
13+
return hide(...args);
14+
};
15+
}
16+
717
const ModalTrigger = React.createClass({
8-
mixins: [OverlayMixin],
918

1019
propTypes: {
1120
modal: React.PropTypes.node.isRequired,
@@ -39,15 +48,31 @@ const ModalTrigger = React.createClass({
3948
});
4049
},
4150

42-
renderOverlay() {
43-
if (!this.state.isOverlayShown) {
44-
return <span />;
45-
}
51+
componentDidMount(){
52+
this._overlay = document.createElement('div');
53+
React.render(this.getOverlay(), this._overlay);
54+
},
55+
56+
componentWillUnmount() {
57+
React.unmountComponentAtNode(this._overlay);
58+
this._overlay = null;
59+
clearTimeout(this._hoverDelay);
60+
},
61+
62+
componentDidUpdate(){
63+
React.render(this.getOverlay(), this._overlay);
64+
},
65+
66+
getOverlay() {
67+
let modal = this.props.modal;
4668

4769
return cloneElement(
48-
this.props.modal,
70+
modal,
4971
{
50-
onRequestHide: this.hide
72+
show: this.state.isOverlayShown,
73+
onHide: this.hide,
74+
onRequestHide: createHideDepreciationWrapper(this.hide),
75+
container: modal.props.container || this.props.container
5176
}
5277
);
5378
},
@@ -82,4 +107,19 @@ const ModalTrigger = React.createClass({
82107
*/
83108
ModalTrigger.withContext = createContextWrapper(ModalTrigger, 'modal');
84109

85-
export default ModalTrigger;
110+
let DepreciatedModalTrigger = React.createClass({
111+
componentWillMount(){
112+
deprecationWarning(
113+
'The `ModalTrigger` component', 'the `Modal` component directly'
114+
, 'http://react-bootstrap.github.io/components.html#modals');
115+
},
116+
117+
render(){
118+
return (<ModalTrigger {...this.props}/>);
119+
}
120+
});
121+
122+
DepreciatedModalTrigger.withContext = ModalTrigger.withContext;
123+
DepreciatedModalTrigger.ModalTrigger = ModalTrigger;
124+
125+
export default DepreciatedModalTrigger;

src/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import NavItem from './NavItem';
3939
import ModalTrigger from './ModalTrigger';
4040
import OverlayTrigger from './OverlayTrigger';
4141
import OverlayMixin from './OverlayMixin';
42+
import Overlay from './Overlay';
4243
import PageHeader from './PageHeader';
4344
import Pagination from './Pagination';
4445
import Panel from './Panel';
@@ -100,6 +101,7 @@ export default {
100101
Navbar,
101102
NavItem,
102103
ModalTrigger,
104+
Overlay,
103105
OverlayTrigger,
104106
OverlayMixin,
105107
PageHeader,

test/ModalTriggerSpec.js

+19
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,27 @@
11
import React from 'react';
22
import ReactTestUtils from 'react/lib/ReactTestUtils';
33
import ModalTrigger from '../src/ModalTrigger';
4+
import { shouldWarn } from './helpers';
5+
46

57
describe('ModalTrigger', function() {
8+
9+
afterEach(()=> {
10+
if ( console.warn.called ) {
11+
shouldWarn('The `ModalTrigger` component is deprecated');
12+
}
13+
});
14+
15+
it('Should warn about deprecated Component', function() {
16+
ReactTestUtils.renderIntoDocument(
17+
<ModalTrigger modal={<div>test</div>}>
18+
<button>button</button>
19+
</ModalTrigger>
20+
);
21+
22+
shouldWarn('The `ModalTrigger` component is deprecated');
23+
});
24+
625
it('Should create ModalTrigger element', function() {
726
const instance = ReactTestUtils.renderIntoDocument(
827
<ModalTrigger modal={<div>test</div>}>

0 commit comments

Comments
 (0)