Skip to content

Commit d70f617

Browse files
committed
[changed] tooltips and popovers required id's for a11y
1 parent 389cf3f commit d70f617

11 files changed

+124
-27
lines changed

docs/assets/style.css

+7
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,10 @@ body {
165165
.prop-table {
166166
background-color: white;
167167
}
168+
169+
.bs-example.tooltip-static .tooltip {
170+
position: relative;
171+
display: inline-block;
172+
margin: 5px 10px;
173+
174+
}

docs/examples/PopoverContained.js

+32-12
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,33 @@
1-
const positionerInstance = (
2-
<ButtonToolbar>
3-
<OverlayTrigger
4-
container={mountNode} containerPadding={20}
5-
trigger='click' placement='bottom'
6-
overlay={<Popover title='Popover bottom'><strong>Holy guacamole!</strong> Check this info.</Popover>}
7-
>
8-
<Button bsStyle='default'>Holy guacamole!</Button>
9-
</OverlayTrigger>
10-
</ButtonToolbar>
11-
);
1+
class Example extends React.Component {
2+
constructor(props, context){
3+
super(props, context);
4+
this.state = { show: false };
5+
}
6+
render(){
127

13-
React.render(positionerInstance, mountNode);
8+
return (
9+
<ButtonToolbar>
10+
<Button
11+
bsStyle='default'
12+
onClick={e => this.setState({ target: e.target, show: !this.state.show })}
13+
>
14+
Holy guacamole!
15+
</Button>
16+
17+
<Overlay
18+
show={this.state.show}
19+
target={()=> React.findDOMNode(this.state.target)}
20+
placement='bottom'
21+
container={mountNode}
22+
containerPadding={20}
23+
>
24+
<Popover title='Popover bottom'>
25+
<strong>Holy guacamole!</strong> Check this info.
26+
</Popover>
27+
</Overlay>
28+
</ButtonToolbar>
29+
);
30+
}
31+
}
32+
33+
React.render(<Example/>, mountNode);

docs/examples/TooltipBasic.js

+14-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
11
const tooltipInstance = (
2-
<div style={{ height: 50 }}>
3-
<Tooltip placement="right" positionLeft={150} positionTop={50}>
4-
<strong>Holy guacamole!</strong> Check this info.
2+
<div>
3+
<Tooltip placement="right">
4+
Tooltip right
5+
</Tooltip>
6+
<Tooltip placement="top">
7+
Tooltip top
8+
</Tooltip>
9+
10+
<Tooltip placement="left">
11+
Tooltip left
12+
</Tooltip>
13+
14+
<Tooltip placement="bottom">
15+
Tooltip bottom
516
</Tooltip>
617
</div>
718
);

docs/examples/TooltipInCopy.js

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
const LinkWithTooltip = React.createClass({
22
render() {
3-
let tooltip = <Tooltip>{this.props.tooltip}</Tooltip>;
3+
let tooltip = <Tooltip placement='top'>{this.props.tooltip}</Tooltip>;
44

55
return (
6-
<OverlayTrigger placement='top' overlay={tooltip} delayShow={300} delayHide={150}>
6+
<OverlayTrigger overlay={tooltip} delayShow={300} delayHide={150}>
77
<a href={this.props.href}>{this.props.children}</a>
88
</OverlayTrigger>
99
);
@@ -12,7 +12,13 @@ const LinkWithTooltip = React.createClass({
1212

1313
const copyInstance = (
1414
<p className='muted' style={{ marginBottom: 0 }}>
15-
Tight pants next level keffiyeh <LinkWithTooltip tooltip='Default tooltip' href='#'>you probably</LinkWithTooltip> haven't heard of them. Photo booth beard raw denim letterpress vegan messenger bag stumptown. Farm-to-table seitan, mcsweeney's fixie sustainable quinoa 8-bit american apparel <LinkWithTooltip tooltip={<span>Another <strong>tooltip</strong></span>} href='#'>have a</LinkWithTooltip> terry richardson vinyl chambray. Beard stumptown, cardigans banh mi lomo thundercats. Tofu biodiesel williamsburg marfa, four loko mcsweeney's cleanse vegan chambray. A really ironic artisan <LinkWithTooltip tooltip='Another one here too' href='#'>whatever keytar</LinkWithTooltip>, scenester farm-to-table banksy Austin <LinkWithTooltip tooltip='The last tip!' href='#'>twitter handle</LinkWithTooltip> freegan cred raw denim single-origin coffee viral.
15+
Tight pants next level keffiyeh <LinkWithTooltip tooltip='Default tooltip' href='#'>you probably</LinkWithTooltip> haven't
16+
heard of them. Photo booth beard raw denim letterpress vegan messenger bag stumptown. Farm-to-table seitan, mcsweeney's
17+
fixie sustainable quinoa 8-bit american apparel <LinkWithTooltip tooltip={<span>Another <strong>tooltip</strong></span>} href='#'>have a</LinkWithTooltip>
18+
terry richardson vinyl chambray. Beard stumptown, cardigans banh mi lomo thundercats. Tofu biodiesel williamsburg marfa, four
19+
loko mcsweeney's cleanse vegan chambray. A really ironic artisan <LinkWithTooltip tooltip='Another one here too' href='#'>whatever keytar</LinkWithTooltip>,
20+
scenester farm-to-table banksy Austin <LinkWithTooltip tooltip='The last tip!' href='#'>twitter handle</LinkWithTooltip> freegan
21+
cred raw denim single-origin coffee viral.
1622
</p>
1723
);
1824

docs/examples/TooltipPositioned.js

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
1+
2+
const tooltip = (
3+
<Tooltip><strong>Holy guacamole!</strong> Check this info.</Tooltip>
4+
);
5+
16
const positionerInstance = (
27
<ButtonToolbar>
3-
<OverlayTrigger placement='left' overlay={<Tooltip><strong>Holy guacamole!</strong> Check this info.</Tooltip>}>
8+
<OverlayTrigger placement='left' overlay={tooltip}>
49
<Button bsStyle='default'>Holy guacamole!</Button>
510
</OverlayTrigger>
6-
<OverlayTrigger placement='top' overlay={<Tooltip><strong>Holy guacamole!</strong> Check this info.</Tooltip>}>
11+
12+
<OverlayTrigger placement='top' overlay={tooltip}>
713
<Button bsStyle='default'>Holy guacamole!</Button>
814
</OverlayTrigger>
9-
<OverlayTrigger placement='bottom' overlay={<Tooltip><strong>Holy guacamole!</strong> Check this info.</Tooltip>}>
15+
16+
<OverlayTrigger placement='bottom' overlay={tooltip}>
1017
<Button bsStyle='default'>Holy guacamole!</Button>
1118
</OverlayTrigger>
12-
<OverlayTrigger placement='right' overlay={<Tooltip><strong>Holy guacamole!</strong> Check this info.</Tooltip>}>
19+
20+
<OverlayTrigger placement='right' overlay={tooltip}>
1321
<Button bsStyle='default'>Holy guacamole!</Button>
1422
</OverlayTrigger>
1523
</ButtonToolbar>

docs/src/ReactPlayground.js

+13
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import * as modPagination from '../../src/Pagination';
3636
import * as modPanel from '../../src/Panel';
3737
import * as modPanelGroup from '../../src/PanelGroup';
3838
import * as modPopover from '../../src/Popover';
39+
//import * as modPopoverTrigger from '../../src/PopoverTrigger';
3940
import * as modProgressBar from '../../src/ProgressBar';
4041
import * as modRow from '../../src/Row';
4142
import * as modSplitButton from '../../src/SplitButton';
@@ -44,14 +45,22 @@ import * as modTable from '../../src/Table';
4445
import * as modTabPane from '../../src/TabPane';
4546
import * as modThumbnail from '../../src/Thumbnail';
4647
import * as modTooltip from '../../src/Tooltip';
48+
//import * as modTooltipTrigger from '../../src/TooltipTrigger';
4749
import * as modWell from '../../src/Well';
4850

51+
import * as modPortal from '../../src/Portal';
52+
import * as modOverlay from '../../src/Overlay';
53+
4954
import babel from 'babel-core/browser';
5055

5156
import CodeExample from './CodeExample';
5257

58+
59+
5360
const classNames = modClassNames.default;
5461
/* eslint-disable */
62+
const Portal = modPortal.default;
63+
5564
const React = modReact.default;
5665
const Accordion = modAccordion.default;
5766
const Alert = modAlert.default;
@@ -89,6 +98,7 @@ const Pager = modPager.default;
8998
const Panel = modPanel.default;
9099
const PanelGroup = modPanelGroup.default;
91100
const Popover = modPopover.default;
101+
//const PopoverTrigger = modPopoverTrigger.default;
92102
const ProgressBar = modProgressBar.default;
93103
const Row = modRow.default;
94104
const SplitButton = modSplitButton.default;
@@ -97,7 +107,10 @@ const Table = modTable.default;
97107
const TabPane = modTabPane.default;
98108
const Thumbnail = modThumbnail.default;
99109
const Tooltip = modTooltip.default;
110+
//const TooltipTrigger = modTooltipTrigger.default;
100111
const Well = modWell.default;
112+
const Overlay = modOverlay.default;
113+
101114
/* eslint-enable */
102115

103116
const IS_MOBILE = typeof navigator !== 'undefined' && (

docs/src/Samples.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export default {
3232
CollapsibleParagraph: require('fs').readFileSync(__dirname + '/../examples/CollapsibleParagraph.js', 'utf8'),
3333
ModalStatic: require('fs').readFileSync(__dirname + '/../examples/ModalStatic.js', 'utf8'),
3434
ModalTrigger: require('fs').readFileSync(__dirname + '/../examples/ModalTrigger.js', 'utf8'),
35-
ModalOverlayMixin: require('fs').readFileSync(__dirname + '/../examples/ModalOverlayMixin.js', 'utf8'),
35+
3636
ModalContained: require('fs').readFileSync(__dirname + '/../examples/ModalContained.js', 'utf8'),
3737
ModalDefaultSizing: require('fs').readFileSync(__dirname + '/../examples/ModalDefaultSizing.js', 'utf8'),
3838
ModalCustomSizing: require('fs').readFileSync(__dirname + '/../examples/ModalCustomSizing.js', 'utf8'),
@@ -99,5 +99,8 @@ export default {
9999
InputValidation: require('fs').readFileSync(__dirname + '/../examples/InputValidation.js', 'utf8'),
100100
InputHorizontal: require('fs').readFileSync(__dirname + '/../examples/InputHorizontal.js', 'utf8'),
101101
InputWrapper: require('fs').readFileSync(__dirname + '/../examples/InputWrapper.js', 'utf8'),
102-
MenuItem: require('fs').readFileSync(__dirname + '/../examples/MenuItem.js', 'utf8')
102+
MenuItem: require('fs').readFileSync(__dirname + '/../examples/MenuItem.js', 'utf8'),
103+
104+
Overlay: require('fs').readFileSync(__dirname + '/../examples/Overlay.js', 'utf8'),
105+
OverlayTrigger: require('fs').readFileSync(__dirname + '/../examples/OverlayTrigger.js', 'utf8')
103106
};

src/Popover.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
/* eslint-disable react/no-multi-comp */
12
import React from 'react';
23
import classNames from 'classnames';
34
import BootstrapMixin from './BootstrapMixin';
45
import FadeMixin from './FadeMixin';
56

67
const Popover = React.createClass({
8+
79
mixins: [BootstrapMixin, FadeMixin],
810

911
propTypes: {
@@ -48,7 +50,7 @@ const Popover = React.createClass({
4850
};
4951

5052
return (
51-
<div {...this.props} className={classNames(this.props.className, classes)} style={style} title={null}>
53+
<div role='tooltip' {...this.props} className={classNames(this.props.className, classes)} style={style} title={null}>
5254
<div className="arrow" style={arrowStyle} />
5355
{this.props.title ? this.renderTitle() : null}
5456
<div className="popover-content">

src/Tooltip.js

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,33 @@
1+
/* eslint-disable react/no-multi-comp */
12
import React from 'react';
23
import classNames from 'classnames';
34
import BootstrapMixin from './BootstrapMixin';
45
import FadeMixin from './FadeMixin';
6+
import CustomPropTypes from './utils/CustomPropTypes';
57

68
const Tooltip = React.createClass({
79
mixins: [BootstrapMixin, FadeMixin],
810

911
propTypes: {
12+
/**
13+
* An html id attribute, necessary for accessibility
14+
* @type {string}
15+
* @required
16+
*/
17+
id: CustomPropTypes.isRequiredForA11y(React.PropTypes.string),
18+
1019
placement: React.PropTypes.oneOf(['top', 'right', 'bottom', 'left']),
1120
positionLeft: React.PropTypes.number,
1221
positionTop: React.PropTypes.number,
22+
1323
arrowOffsetLeft: React.PropTypes.oneOfType([
1424
React.PropTypes.number, React.PropTypes.string
1525
]),
26+
1627
arrowOffsetTop: React.PropTypes.oneOfType([
1728
React.PropTypes.number, React.PropTypes.string
1829
]),
30+
1931
animation: React.PropTypes.bool
2032
},
2133

@@ -46,7 +58,7 @@ const Tooltip = React.createClass({
4658
};
4759

4860
return (
49-
<div {...this.props} className={classNames(this.props.className, classes)} style={style}>
61+
<div role='tooltip' {...this.props} className={classNames(this.props.className, classes)} style={style}>
5062
<div className="tooltip-arrow" style={arrowStyle} />
5163
<div className="tooltip-inner">
5264
{this.props.children}

src/index.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ import Tooltip from './Tooltip';
5353
import utils from './utils';
5454
import Well from './Well';
5555
import styleMaps from './styleMaps';
56-
5756
import Portal from './Portal';
57+
import Position from './Position';
5858

5959
export default {
6060
Accordion,
@@ -101,6 +101,7 @@ export default {
101101
Pagination,
102102
Popover,
103103
Portal,
104+
Position,
104105
ProgressBar,
105106
Row,
106107
SplitButton,

src/utils/CustomPropTypes.js

+14
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,20 @@ import React from 'react';
33
const ANONYMOUS = '<<anonymous>>';
44

55
const CustomPropTypes = {
6+
7+
isRequiredForA11y(propType){
8+
return function(props, propName, componentName){
9+
if (props[propName] === null) {
10+
return new Error(
11+
'The prop `' + propName + '` is required to make ' + componentName + ' accessible ' +
12+
'for users using assistive technologies such as screen readers `'
13+
);
14+
}
15+
16+
return propType(props, propName, componentName);
17+
};
18+
},
19+
620
/**
721
* Checks whether a prop provides a DOM element
822
*

0 commit comments

Comments
 (0)