Skip to content

Commit 5bb0620

Browse files
authored
* WIP * finish up * address feedback
1 parent cc43141 commit 5bb0620

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+967
-654
lines changed

.eslintrc

-3
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,6 @@
6262
"children",
6363
"className",
6464
"style",
65-
"bsStyle",
66-
"bsClass",
67-
"bsSize"
6865
]
6966
}
7067
],

package.json

+9-9
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@
6767
"@babel/preset-env": "^7.0.0",
6868
"@babel/preset-react": "^7.0.0",
6969
"@babel/register": "^7.0.0",
70-
"@monastic.panic/enzyme-adapter-react-16": "^1.2.4",
7170
"@storybook/react": "^3.4.8",
7271
"babel-core": "^7.0.0-bridge.0",
7372
"babel-eslint": "^9.0.0",
@@ -77,11 +76,12 @@
7776
"babel-plugin-istanbul": "^5.0.1",
7877
"chai": "^4.1.2",
7978
"chalk": "^2.3.2",
80-
"codecov": "^3.0.4",
79+
"codecov": "^3.1.0",
8180
"colors": "^1.3.2",
8281
"create-react-class": "^15.6.3",
8382
"cross-env": "^5.2.0",
84-
"enzyme": "^3.5.0",
83+
"enzyme": "^3.6.0",
84+
"enzyme-adapter-react-16": "^1.5.0",
8585
"eslint": "^5.5.0",
8686
"eslint-config-airbnb": "^17.1.0",
8787
"eslint-config-prettier": "^3.0.1",
@@ -103,16 +103,16 @@
103103
"karma-mocha-reporter": "^2.0.4",
104104
"karma-sinon-chai": "^2.0.2",
105105
"karma-sourcemap-loader": "^0.3.7",
106-
"karma-webpack": "^3.0.2",
106+
"karma-webpack": "^3.0.4",
107107
"lint-staged": "^7.2.0",
108108
"lodash": "^4.17.10",
109109
"mocha": "^5.2.0",
110110
"prettier": "~1.13.7",
111-
"react": "^16.4.1",
112-
"react-dom": "^16.4.1",
113-
"react-test-renderer": "^16.4.1",
111+
"react": "^16.5.0",
112+
"react-dom": "^16.5.0",
113+
"react-test-renderer": "^16.5.0",
114114
"release-script": "^1.0.2",
115-
"sinon": "^6.1.5",
115+
"sinon": "^6.2.0",
116116
"sinon-chai": "^3.2.0",
117117
"webpack": "^4.17.2"
118118
},
@@ -127,7 +127,7 @@
127127
"prop-types": "^15.6.2",
128128
"prop-types-extra": "^1.1.0",
129129
"react-context-toolbox": "^1.2.1",
130-
"react-overlays": "^1.0.0-beta.16",
130+
"react-overlays": "^1.0.0-beta.17",
131131
"react-prop-types": "^0.4.0",
132132
"react-transition-group": "^2.4.0",
133133
"uncontrollable": "^6.0.0",

src/Button.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class Button extends React.Component {
7575
block,
7676
type,
7777
as,
78+
innerRef,
7879
...props
7980
} = this.props;
8081

@@ -92,14 +93,20 @@ class Button extends React.Component {
9293
<SafeAnchor
9394
{...props}
9495
as={as}
96+
innerRef={innerRef}
9597
className={classNames(classes, props.disabled && 'disabled')}
9698
/>
9799
);
98100
}
99101

100102
const Component = as || 'button';
103+
if (innerRef) props.ref = innerRef;
104+
101105
return <Component {...props} type={type} className={classes} />;
102106
}
103107
}
104108

105-
export default createBootstrapComponent(Button, 'btn');
109+
export default createBootstrapComponent(Button, {
110+
prefix: 'btn',
111+
forwardRefAs: 'innerRef',
112+
});

src/DropdownMenu.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import classNames from 'classnames';
2+
import { findDOMNode } from 'react-dom';
23
import React from 'react';
34
import PropTypes from 'prop-types';
45
import elementType from 'prop-types-extra/lib/elementType';
@@ -7,6 +8,12 @@ import NavbarContext from './NavbarContext';
78

89
import { createBootstrapComponent } from './ThemeProvider';
910

11+
const wrapRef = props => {
12+
const { ref } = props;
13+
props.ref = ref.__wrapped || (ref.__wrapped = r => ref(findDOMNode(r)));
14+
return props;
15+
};
16+
1017
class DropdownMenu extends React.Component {
1118
static propTypes = {
1219
/**
@@ -57,8 +64,6 @@ class DropdownMenu extends React.Component {
5764
...props
5865
} = this.props;
5966

60-
// For custom components provide additional, non-DOM, props;
61-
6267
return (
6368
<NavbarContext>
6469
{isNavbar => (
@@ -69,6 +74,8 @@ class DropdownMenu extends React.Component {
6974
rootCloseEvent={rootCloseEvent}
7075
>
7176
{({ placement, show, alignEnd, close, props: menuProps }) => {
77+
wrapRef(menuProps);
78+
// For custom components provide additional, non-DOM, props;
7279
if (typeof Component !== 'string') {
7380
menuProps.show = show;
7481
menuProps.close = close;

src/DropdownToggle.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import classNames from 'classnames';
2+
import { findDOMNode } from 'react-dom';
23
import PropTypes from 'prop-types';
34
import isRequiredForA11y from 'prop-types-extra/lib/isRequiredForA11y';
45
import elementType from 'prop-types-extra/lib/elementType';
@@ -8,6 +9,12 @@ import React from 'react';
89
import Button from './Button';
910
import { createBootstrapComponent } from './ThemeProvider';
1011

12+
const wrapRef = props => {
13+
const { ref } = props;
14+
props.ref = ref.__wrapped || (ref.__wrapped = r => ref(findDOMNode(r)));
15+
return props;
16+
};
17+
1118
class DropdownToggle extends React.Component {
1219
static propTypes = {
1320
/**
@@ -49,7 +56,7 @@ class DropdownToggle extends React.Component {
4956
...props
5057
} = this.props;
5158

52-
// This intentionally forwards bsSize and bsStyle (if set) to the
59+
// This intentionally forwards size and variant (if set) to the
5360
// underlying component, to allow it to render size and style variants.
5461
return (
5562
<BaseDropdownToggle>
@@ -62,7 +69,7 @@ class DropdownToggle extends React.Component {
6269
bsPrefix,
6370
split && `${bsPrefix}-split`,
6471
)}
65-
{...toggleProps}
72+
{...wrapRef(toggleProps)}
6673
{...props}
6774
>
6875
{children}

src/SafeAnchor.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,13 @@ class SafeAnchor extends React.Component {
6565
}
6666

6767
render() {
68-
const { as: Component, disabled, onKeyDown, ...props } = this.props;
68+
const {
69+
as: Component,
70+
disabled,
71+
onKeyDown,
72+
innerRef,
73+
...props
74+
} = this.props;
6975

7076
if (isTrivialHref(props.href)) {
7177
props.role = props.role || 'button';
@@ -78,7 +84,7 @@ class SafeAnchor extends React.Component {
7884
props.tabIndex = -1;
7985
props['aria-disabled'] = true;
8086
}
81-
87+
if (innerRef) props.ref = innerRef;
8288
return (
8389
<Component
8490
{...props}

src/ToggleButton.js

+26-5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import React from 'react';
44

55
import Button from './Button';
66

7+
const noop = () => {};
8+
79
const propTypes = {
810
/**
911
* The `<input>` element `type`
@@ -17,7 +19,7 @@ const propTypes = {
1719
name: PropTypes.string,
1820

1921
/**
20-
* The checked state of the input, managed by `<ToggleButtonGroup>`` automatically
22+
* The checked state of the input, managed by `<ToggleButtonGroup>` automatically
2123
*/
2224
checked: PropTypes.bool,
2325

@@ -36,6 +38,15 @@ const propTypes = {
3638
* `ToggleButtonGroup`.
3739
*/
3840
value: PropTypes.any.isRequired,
41+
42+
/**
43+
* A ref attached to the `<input>` element
44+
* @type {ReactRef}
45+
*/
46+
inputRef: PropTypes.any,
47+
48+
/** @ignore */
49+
innerRef: PropTypes.any,
3950
};
4051

4152
class ToggleButton extends React.Component {
@@ -58,15 +69,22 @@ class ToggleButton extends React.Component {
5869
type,
5970
onChange,
6071
value,
72+
disabled,
73+
inputRef,
74+
innerRef,
6175
...props
6276
} = this.props;
6377
const { focused } = this.state;
64-
const disabled = props.disabled;
6578

6679
return (
6780
<Button
6881
{...props}
69-
className={classNames(className, focused && 'focus')}
82+
ref={innerRef}
83+
className={classNames(
84+
className,
85+
focused && 'focus',
86+
disabled && 'disabled',
87+
)}
7088
type={null}
7189
active={!!checked}
7290
as="label"
@@ -75,12 +93,13 @@ class ToggleButton extends React.Component {
7593
name={name}
7694
type={type}
7795
value={value}
96+
ref={inputRef}
7897
autoComplete="off"
7998
checked={!!checked}
8099
disabled={!!disabled}
81100
onFocus={this.handleFocus}
82101
onBlur={this.handleBlur}
83-
onChange={onChange}
102+
onChange={onChange || noop}
84103
/>
85104

86105
{children}
@@ -91,4 +110,6 @@ class ToggleButton extends React.Component {
91110

92111
ToggleButton.propTypes = propTypes;
93112

94-
export default ToggleButton;
113+
export default React.forwardRef((props, ref) => (
114+
<ToggleButton innerRef={ref} {...props} />
115+
));

test/AlertSpec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ describe('<Alert>', () => {
5050
<Alert.Heading>Well done</Alert.Heading>
5151
Message
5252
</Alert>,
53-
).assertSingle('.alert-heading');
53+
).assertSingle('div.alert-heading');
5454
});
5555

5656
it('Should have div styled as an h4 by default', () => {

test/ButtonSpec.js

+21
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,27 @@ describe('<Button>', () => {
2626
.should.equal('submit');
2727
});
2828

29+
it('should forward refs to the button', () => {
30+
const ref = React.createRef();
31+
mount(
32+
<div>
33+
<Button ref={ref}>Yo</Button>
34+
</div>,
35+
);
36+
37+
ref.current.tagName.should.equal('BUTTON');
38+
39+
mount(
40+
<div>
41+
<Button ref={ref} href="a">
42+
Yo
43+
</Button>
44+
</div>,
45+
);
46+
47+
ref.current.tagName.should.equal('A');
48+
});
49+
2950
it('Should output an anchor if called with a href', () => {
3051
let href = '/url';
3152

test/DropdownSpec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ describe('<Dropdown>', () => {
5252

5353
it('forwards alignRight to menu', () => {
5454
mount(<Dropdown alignRight>{dropdownChildren}</Dropdown>).assertSingle(
55-
'DropdownMenu[alignEnd=true]',
55+
'ReactOverlaysDropdownMenu[alignEnd=true]',
5656
);
5757
});
5858

test/ModalSpec.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@ describe('<Modal>', () => {
1212

1313
it('Should render the modal content', () => {
1414
const noOp = () => {};
15-
const instance = mount(
15+
mount(
1616
<Modal show onHide={noOp} animation={false}>
1717
<strong>Message</strong>
1818
</Modal>,
19-
).instance();
20-
21-
assert.ok(instance._modal.dialog.querySelector('strong'));
19+
)
20+
.find('strong')
21+
.text()
22+
.should.equal('Message');
2223
});
2324

2425
it('Should close the modal when the modal dialog is clicked', done => {

test/OverlayTriggerSpec.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ describe('<OverlayTrigger>', () => {
5050

5151
wrapper.find('button').simulate('click');
5252

53-
wrapper.assertSingle('.test');
53+
wrapper.assertSingle('div.test');
5454
});
5555

5656
it('Should not set aria-describedby if the state is not show', () => {
@@ -122,7 +122,7 @@ describe('<OverlayTrigger>', () => {
122122
);
123123
wrapper.find('button').simulate('click');
124124

125-
wrapper.assertSingle('.test-overlay');
125+
wrapper.assertSingle('div.test-overlay');
126126
});
127127

128128
it('Should pass transition callbacks to Transition', done => {

0 commit comments

Comments
 (0)