Last active
June 21, 2017 18:00
-
-
Save bjankord/efd75a6812f3ccaf972ce5687c6b4b8a to your computer and use it in GitHub Desktop.
Toggler with inert aria-hidden content
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import PropTypes from 'prop-types'; | |
import classNames from 'classnames'; | |
import AnimateHeight from 'react-animate-height'; | |
import 'terra-base/lib/baseStyles'; | |
import './Toggler.scss'; | |
const propTypes = { | |
/** | |
* Content in the body of the toggler component that will be expanded or collapsed | |
*/ | |
children: PropTypes.node.isRequired, | |
/** | |
* When set, will animate the toggler component as it is expanded or collapsed | |
*/ | |
isAnimated: PropTypes.bool, | |
/** | |
* Used to expand or collapse toggler content | |
*/ | |
isOpen: PropTypes.bool, | |
onAnimationEnd: PropTypes.func, | |
onAnimationStart: PropTypes.func, | |
}; | |
const defaultProps = { | |
children: null, | |
isAnimated: false, | |
isOpen: false, | |
}; | |
class Toggler extends React.Component { | |
constructor(props) { | |
super(props); | |
this.handleOnAnimationEnd = this.handleOnAnimationEnd.bind(this); | |
this.handleOnAnimationStart = this.handleOnAnimationStart.bind(this); | |
} | |
handleOnAnimationEnd(open) { | |
if (!open) { | |
if (this.contentContainer) { | |
const inertLinks = this.contentContainer.getElementsByTagName('a'); | |
const inertButtons = this.contentContainer.getElementsByTagName('button'); | |
const inertInputs = this.contentContainer.getElementsByTagName('input'); | |
const inertSelects = this.contentContainer.getElementsByTagName('select'); | |
const inertTextareas = this.contentContainer.getElementsByTagName('textarea'); | |
const inertFormElements = [...inertButtons, ...inertInputs, ...inertSelects, ...inertTextareas]; | |
// Make links inert | |
let l = 0; | |
while (l < inertLinks.length) { | |
inertLinks[l].setAttribute('tabindex', '-1'); | |
l += 1; | |
} | |
// Make form elements inert | |
let f = 0; | |
while (f < inertFormElements.length) { | |
inertFormElements[f].setAttribute('disabled', ''); | |
f += 1; | |
} | |
} | |
} | |
} | |
handleOnAnimationStart(open) { | |
if (open) { | |
if (this.contentContainer) { | |
const inertLinks = this.contentContainer.getElementsByTagName('a'); | |
const inertButtons = this.contentContainer.getElementsByTagName('button'); | |
const inertInputs = this.contentContainer.getElementsByTagName('input'); | |
const inertSelects = this.contentContainer.getElementsByTagName('select'); | |
const inertTextareas = this.contentContainer.getElementsByTagName('textarea'); | |
const inertFormElements = [...inertButtons, ...inertInputs, ...inertSelects, ...inertTextareas]; | |
// Make links inert | |
let l = 0; | |
while (l < inertLinks.length) { | |
inertLinks[l].removeAttribute('tabindex'); | |
l += 1; | |
} | |
// Make form elements inert | |
let f = 0; | |
while (f < inertFormElements.length) { | |
inertFormElements[f].removeAttribute('disabled'); | |
f += 1; | |
} | |
} | |
} | |
} | |
render() { | |
const { isAnimated, isOpen, children, onAnimationEnd, onAnimationStart, ...customProps } = this.props; | |
const attributes = Object.assign({}, customProps); | |
const TogglerClassNames = classNames([ | |
'terra-Toggler', | |
attributes.className, | |
]); | |
const height = isOpen ? 'auto' : '0'; | |
let body; | |
if (isAnimated) { | |
body = ( | |
<div ref={(div) => { this.contentContainer = div; }}> | |
<AnimateHeight | |
duration={250} | |
height={height} | |
onAnimationEnd={this.handleOnAnimationEnd(isOpen)} | |
onAnimationStart={this.handleOnAnimationStart(isOpen)} | |
> | |
{children} | |
</AnimateHeight> | |
</div> | |
); | |
} else { | |
body = ( | |
isOpen && children | |
); | |
} | |
return ( | |
<div | |
{...attributes} | |
className={TogglerClassNames} | |
aria-hidden={!isOpen} | |
ref={(div) => { this.toggleDiv = div; }} | |
> | |
{body} | |
</div> | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Toggler extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
display: 'block', | |
}; | |
this.handleOnAnimationEnd = this.handleOnAnimationEnd.bind(this); | |
this.handleOnAnimationStart = this.handleOnAnimationStart.bind(this); | |
} | |
handleOnAnimationEnd(open) { | |
if (!open) { | |
setTimeout(function() { this.setState({ display: 'none' }); }.bind(this), 250); | |
} | |
} | |
handleOnAnimationStart(open) { | |
if (open) { | |
setTimeout(function() { this.setState({ display: 'block' }); }.bind(this), 0); | |
} | |
} | |
render() { | |
const { isAnimated, isOpen, children, onAnimationEnd, onAnimationStart, ...customProps } = this.props; | |
const attributes = Object.assign({}, customProps); | |
const TogglerClassNames = classNames([ | |
'terra-Toggler', | |
attributes.className, | |
]); | |
const height = isOpen ? 'auto' : '0'; | |
let body; | |
if (isAnimated) { | |
body = ( | |
<AnimateHeight | |
duration={250} | |
height={height} | |
onAnimationEnd={this.handleOnAnimationEnd(isOpen)} | |
onAnimationStart={this.handleOnAnimationStart(isOpen)} | |
style={{ display: this.state.display }} | |
> | |
{children} | |
</AnimateHeight> | |
); | |
} else { | |
body = ( | |
isOpen && children | |
); | |
} | |
return ( | |
<div | |
{...attributes} | |
className={TogglerClassNames} | |
aria-hidden={!isOpen} | |
ref={(div) => { this.toggleDiv = div; }} | |
> | |
{body} | |
</div> | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment