From d70f617d28e572ca5a9ffce1e5f83c4a78b4b628 Mon Sep 17 00:00:00 2001 From: jquense Date: Sun, 28 Jun 2015 20:03:15 -0400 Subject: [PATCH] [changed] tooltips and popovers required id's for a11y --- docs/assets/style.css | 7 +++++ docs/examples/PopoverContained.js | 44 ++++++++++++++++++++++-------- docs/examples/TooltipBasic.js | 17 ++++++++++-- docs/examples/TooltipInCopy.js | 12 ++++++-- docs/examples/TooltipPositioned.js | 16 ++++++++--- docs/src/ReactPlayground.js | 13 +++++++++ docs/src/Samples.js | 7 +++-- src/Popover.js | 4 ++- src/Tooltip.js | 14 +++++++++- src/index.js | 3 +- src/utils/CustomPropTypes.js | 14 ++++++++++ 11 files changed, 124 insertions(+), 27 deletions(-) diff --git a/docs/assets/style.css b/docs/assets/style.css index 8821e2ba6e..d03afccb44 100644 --- a/docs/assets/style.css +++ b/docs/assets/style.css @@ -165,3 +165,10 @@ body { .prop-table { background-color: white; } + +.bs-example.tooltip-static .tooltip { + position: relative; + display: inline-block; + margin: 5px 10px; + +} diff --git a/docs/examples/PopoverContained.js b/docs/examples/PopoverContained.js index afd3019e3e..3e0c036cee 100644 --- a/docs/examples/PopoverContained.js +++ b/docs/examples/PopoverContained.js @@ -1,13 +1,33 @@ -const positionerInstance = ( - - Holy guacamole! Check this info.} - > - - - -); +class Example extends React.Component { + constructor(props, context){ + super(props, context); + this.state = { show: false }; + } + render(){ -React.render(positionerInstance, mountNode); + return ( + + + + React.findDOMNode(this.state.target)} + placement='bottom' + container={mountNode} + containerPadding={20} + > + + Holy guacamole! Check this info. + + + + ); + } +} + +React.render(, mountNode); diff --git a/docs/examples/TooltipBasic.js b/docs/examples/TooltipBasic.js index f2df4f4a66..ff21989d5e 100644 --- a/docs/examples/TooltipBasic.js +++ b/docs/examples/TooltipBasic.js @@ -1,7 +1,18 @@ const tooltipInstance = ( -
- - Holy guacamole! Check this info. +
+ + Tooltip right + + + Tooltip top + + + + Tooltip left + + + + Tooltip bottom
); diff --git a/docs/examples/TooltipInCopy.js b/docs/examples/TooltipInCopy.js index 8842122aee..40c8d09ab0 100644 --- a/docs/examples/TooltipInCopy.js +++ b/docs/examples/TooltipInCopy.js @@ -1,9 +1,9 @@ const LinkWithTooltip = React.createClass({ render() { - let tooltip = {this.props.tooltip}; + let tooltip = {this.props.tooltip}; return ( - + {this.props.children} ); @@ -12,7 +12,13 @@ const LinkWithTooltip = React.createClass({ const copyInstance = (

- Tight pants next level keffiyeh you probably 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 Another tooltip} href='#'>have a 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 whatever keytar, scenester farm-to-table banksy Austin twitter handle freegan cred raw denim single-origin coffee viral. + Tight pants next level keffiyeh you probably 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 Another tooltip} href='#'>have a + 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 whatever keytar, + scenester farm-to-table banksy Austin twitter handle freegan + cred raw denim single-origin coffee viral.

); diff --git a/docs/examples/TooltipPositioned.js b/docs/examples/TooltipPositioned.js index cedb961fa9..5f94bca114 100644 --- a/docs/examples/TooltipPositioned.js +++ b/docs/examples/TooltipPositioned.js @@ -1,15 +1,23 @@ + +const tooltip = ( + Holy guacamole! Check this info. +); + const positionerInstance = ( - Holy guacamole! Check this info.
}> + - Holy guacamole! Check this info.}> + + - Holy guacamole! Check this info.}> + + - Holy guacamole! Check this info.}> + + diff --git a/docs/src/ReactPlayground.js b/docs/src/ReactPlayground.js index 0b33a304a3..16c7c14d96 100644 --- a/docs/src/ReactPlayground.js +++ b/docs/src/ReactPlayground.js @@ -36,6 +36,7 @@ import * as modPagination from '../../src/Pagination'; import * as modPanel from '../../src/Panel'; import * as modPanelGroup from '../../src/PanelGroup'; import * as modPopover from '../../src/Popover'; +//import * as modPopoverTrigger from '../../src/PopoverTrigger'; import * as modProgressBar from '../../src/ProgressBar'; import * as modRow from '../../src/Row'; import * as modSplitButton from '../../src/SplitButton'; @@ -44,14 +45,22 @@ import * as modTable from '../../src/Table'; import * as modTabPane from '../../src/TabPane'; import * as modThumbnail from '../../src/Thumbnail'; import * as modTooltip from '../../src/Tooltip'; +//import * as modTooltipTrigger from '../../src/TooltipTrigger'; import * as modWell from '../../src/Well'; +import * as modPortal from '../../src/Portal'; +import * as modOverlay from '../../src/Overlay'; + import babel from 'babel-core/browser'; import CodeExample from './CodeExample'; + + const classNames = modClassNames.default; /* eslint-disable */ +const Portal = modPortal.default; + const React = modReact.default; const Accordion = modAccordion.default; const Alert = modAlert.default; @@ -89,6 +98,7 @@ const Pager = modPager.default; const Panel = modPanel.default; const PanelGroup = modPanelGroup.default; const Popover = modPopover.default; +//const PopoverTrigger = modPopoverTrigger.default; const ProgressBar = modProgressBar.default; const Row = modRow.default; const SplitButton = modSplitButton.default; @@ -97,7 +107,10 @@ const Table = modTable.default; const TabPane = modTabPane.default; const Thumbnail = modThumbnail.default; const Tooltip = modTooltip.default; +//const TooltipTrigger = modTooltipTrigger.default; const Well = modWell.default; +const Overlay = modOverlay.default; + /* eslint-enable */ const IS_MOBILE = typeof navigator !== 'undefined' && ( diff --git a/docs/src/Samples.js b/docs/src/Samples.js index c9b0aee582..b02ee906a6 100644 --- a/docs/src/Samples.js +++ b/docs/src/Samples.js @@ -32,7 +32,7 @@ export default { CollapsibleParagraph: require('fs').readFileSync(__dirname + '/../examples/CollapsibleParagraph.js', 'utf8'), ModalStatic: require('fs').readFileSync(__dirname + '/../examples/ModalStatic.js', 'utf8'), ModalTrigger: require('fs').readFileSync(__dirname + '/../examples/ModalTrigger.js', 'utf8'), - ModalOverlayMixin: require('fs').readFileSync(__dirname + '/../examples/ModalOverlayMixin.js', 'utf8'), + ModalContained: require('fs').readFileSync(__dirname + '/../examples/ModalContained.js', 'utf8'), ModalDefaultSizing: require('fs').readFileSync(__dirname + '/../examples/ModalDefaultSizing.js', 'utf8'), ModalCustomSizing: require('fs').readFileSync(__dirname + '/../examples/ModalCustomSizing.js', 'utf8'), @@ -99,5 +99,8 @@ export default { InputValidation: require('fs').readFileSync(__dirname + '/../examples/InputValidation.js', 'utf8'), InputHorizontal: require('fs').readFileSync(__dirname + '/../examples/InputHorizontal.js', 'utf8'), InputWrapper: require('fs').readFileSync(__dirname + '/../examples/InputWrapper.js', 'utf8'), - MenuItem: require('fs').readFileSync(__dirname + '/../examples/MenuItem.js', 'utf8') + MenuItem: require('fs').readFileSync(__dirname + '/../examples/MenuItem.js', 'utf8'), + + Overlay: require('fs').readFileSync(__dirname + '/../examples/Overlay.js', 'utf8'), + OverlayTrigger: require('fs').readFileSync(__dirname + '/../examples/OverlayTrigger.js', 'utf8') }; diff --git a/src/Popover.js b/src/Popover.js index c0ea27a6eb..63229ca8a1 100644 --- a/src/Popover.js +++ b/src/Popover.js @@ -1,9 +1,11 @@ +/* eslint-disable react/no-multi-comp */ import React from 'react'; import classNames from 'classnames'; import BootstrapMixin from './BootstrapMixin'; import FadeMixin from './FadeMixin'; const Popover = React.createClass({ + mixins: [BootstrapMixin, FadeMixin], propTypes: { @@ -48,7 +50,7 @@ const Popover = React.createClass({ }; return ( -
+
{this.props.title ? this.renderTitle() : null}
diff --git a/src/Tooltip.js b/src/Tooltip.js index 1c7dafeb80..e98001187b 100644 --- a/src/Tooltip.js +++ b/src/Tooltip.js @@ -1,21 +1,33 @@ +/* eslint-disable react/no-multi-comp */ import React from 'react'; import classNames from 'classnames'; import BootstrapMixin from './BootstrapMixin'; import FadeMixin from './FadeMixin'; +import CustomPropTypes from './utils/CustomPropTypes'; const Tooltip = React.createClass({ mixins: [BootstrapMixin, FadeMixin], propTypes: { + /** + * An html id attribute, necessary for accessibility + * @type {string} + * @required + */ + id: CustomPropTypes.isRequiredForA11y(React.PropTypes.string), + placement: React.PropTypes.oneOf(['top', 'right', 'bottom', 'left']), positionLeft: React.PropTypes.number, positionTop: React.PropTypes.number, + arrowOffsetLeft: React.PropTypes.oneOfType([ React.PropTypes.number, React.PropTypes.string ]), + arrowOffsetTop: React.PropTypes.oneOfType([ React.PropTypes.number, React.PropTypes.string ]), + animation: React.PropTypes.bool }, @@ -46,7 +58,7 @@ const Tooltip = React.createClass({ }; return ( -
+
{this.props.children} diff --git a/src/index.js b/src/index.js index 437008dabb..a16f1649c1 100644 --- a/src/index.js +++ b/src/index.js @@ -53,8 +53,8 @@ import Tooltip from './Tooltip'; import utils from './utils'; import Well from './Well'; import styleMaps from './styleMaps'; - import Portal from './Portal'; +import Position from './Position'; export default { Accordion, @@ -101,6 +101,7 @@ export default { Pagination, Popover, Portal, + Position, ProgressBar, Row, SplitButton, diff --git a/src/utils/CustomPropTypes.js b/src/utils/CustomPropTypes.js index 53c96e29c1..cb57a653cb 100644 --- a/src/utils/CustomPropTypes.js +++ b/src/utils/CustomPropTypes.js @@ -3,6 +3,20 @@ import React from 'react'; const ANONYMOUS = '<>'; const CustomPropTypes = { + + isRequiredForA11y(propType){ + return function(props, propName, componentName){ + if (props[propName] === null) { + return new Error( + 'The prop `' + propName + '` is required to make ' + componentName + ' accessible ' + + 'for users using assistive technologies such as screen readers `' + ); + } + + return propType(props, propName, componentName); + }; + }, + /** * Checks whether a prop provides a DOM element *