Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-accessible-accordion

Package Overview
Dependencies
Maintainers
1
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-accessible-accordion - npm Package Compare versions

Comparing version 0.5.0 to 0.6.0

dist/utils/index.js

8

CHANGELOG.md

@@ -7,2 +7,10 @@ Changelog

## [[v0.6.0]](https://github.com/springload/react-accessible-accordion/releases/tag/v0.6.0)
- Improved accessibility support (Following https://github.com/springload/react-accessible-accordion/pull/19)
- Adds possibility to programmatically open items(https://github.com/springload/react-accessible-accordion/pull/13)
Thanks @epotockiy for the contribution
- Improved accessibility status on demo page
- Documentation about accessibility for this component
## [[v0.5.0]](https://github.com/springload/react-accessible-accordion/releases/tag/v0.5.0)

@@ -9,0 +17,0 @@

38

dist/Accordion/accordion.js

@@ -17,2 +17,4 @@ 'use strict';

var _utils = require('../utils');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -31,3 +33,4 @@

onChange: function onChange() {},
className: 'accordion'
className: 'accordion',
activeItems: []
};

@@ -38,2 +41,3 @@

children: _propTypes2.default.oneOfType([_propTypes2.default.arrayOf(_propTypes2.default.element), _propTypes2.default.object]).isRequired,
activeItems: _propTypes2.default.arrayOf(_propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.number])),
className: _propTypes2.default.string,

@@ -61,2 +65,19 @@ onChange: _propTypes2.default.func

_createClass(Accordion, [{
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(nextProps) {
if (!(0, _utils.isArraysEqualShallow)(nextProps.activeItems, this.state.activeItems)) {
var newActiveItems = void 0;
if (nextProps.accordion) {
newActiveItems = nextProps.activeItems.length ? [nextProps.activeItems[0]] : [];
} else {
newActiveItems = nextProps.activeItems.slice();
}
this.setState({
activeItems: newActiveItems
});
nextProps.onChange(nextProps.accordion ? newActiveItems[0] : newActiveItems);
}
}
}, {
key: 'preExpandedItems',

@@ -70,8 +91,11 @@ value: function preExpandedItems() {

if (_this2.props.accordion) {
if (activeItems.length === 0) activeItems.push(index);
if (activeItems.length === 0) activeItems.push(item.props.customKey || index);
} else {
activeItems.push(index);
activeItems.push(item.props.customKey || index);
}
}
});
if (activeItems.length === 0 && this.props.activeItems.length !== 0) {
activeItems = this.props.accordion ? [this.props.activeItems[0]] : this.props.activeItems.slice();
}
return activeItems;

@@ -113,3 +137,3 @@ }

return _react2.default.Children.map(children, function (item, index) {
var key = index;
var key = item.props.customKey || index;
var expanded = _this3.state.activeItems.indexOf(key) !== -1 && !item.props.disabled;

@@ -129,7 +153,9 @@

value: function render() {
var className = this.props.className;
var _props2 = this.props,
className = _props2.className,
accordion = _props2.accordion;
return _react2.default.createElement(
'div',
{ className: className },
{ role: accordion ? 'tablist' : null, className: className },
this.renderItems()

@@ -136,0 +162,0 @@ );

@@ -205,2 +205,263 @@ 'use strict';

});
it('pre expand accordion via accordion props', function () {
var tree = _reactTestRenderer2.default.create(_react2.default.createElement(
_accordion2.default,
{ activeItems: [0] },
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
),
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
)
)).toJSON();
expect(tree).toMatchSnapshot();
});
it('pre expand accordion via accordion props vs accordion item props. Expanded only second item.', function () {
var tree = _reactTestRenderer2.default.create(_react2.default.createElement(
_accordion2.default,
{ activeItems: [0] },
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
),
_react2.default.createElement(
_accordionItem2.default,
{ expanded: true },
'Fake Child'
)
)).toJSON();
expect(tree).toMatchSnapshot();
});
it('pre expand multiple accordions via accordion props', function () {
var tree = _reactTestRenderer2.default.create(_react2.default.createElement(
_accordion2.default,
{ accordion: false, activeItems: [0, 2] },
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
),
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
),
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
)
)).toJSON();
expect(tree).toMatchSnapshot();
});
it('pre expand accordion via accordion props with custom key', function () {
var tree = _reactTestRenderer2.default.create(_react2.default.createElement(
_accordion2.default,
{ activeItems: ['custom'] },
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
),
_react2.default.createElement(
_accordionItem2.default,
{ customKey: 'custom' },
'Fake Child'
)
)).toJSON();
expect(tree).toMatchSnapshot();
});
it('expand accordion via accordion props dynamicly', function () {
var wrapper = _reactTestRenderer2.default.create(_react2.default.createElement(
_accordion2.default,
{ activeItems: [0] },
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
),
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
)
));
wrapper.update(_react2.default.createElement(
_accordion2.default,
{ activeItems: [1] },
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
),
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
)
));
expect(wrapper.getInstance().state.activeItems).toEqual([1]);
expect(wrapper).toMatchSnapshot();
});
it('expand multiple accordions via accordion props props dynamicly', function () {
var wrapper = _reactTestRenderer2.default.create(_react2.default.createElement(
_accordion2.default,
{ accordion: false, activeItems: [0, 2] },
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
),
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
),
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
)
));
wrapper.update(_react2.default.createElement(
_accordion2.default,
{ accordion: false, activeItems: [1, 2] },
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
),
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
),
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
)
));
expect(wrapper.getInstance().state.activeItems).toEqual([1, 2]);
expect(wrapper).toMatchSnapshot();
});
it('expand multiple accordions via accordion props props dynamicly with default\n expanded on accordion items', function () {
var wrapper = _reactTestRenderer2.default.create(_react2.default.createElement(
_accordion2.default,
{ accordion: false },
_react2.default.createElement(
_accordionItem2.default,
{ expanded: true },
'Fake Child'
),
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
),
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
)
));
wrapper.update(_react2.default.createElement(
_accordion2.default,
{ accordion: false, activeItems: [1, 2] },
_react2.default.createElement(
_accordionItem2.default,
{ expanded: true },
'Fake Child'
),
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
),
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
)
));
expect(wrapper.getInstance().state.activeItems).toEqual([1, 2]);
expect(wrapper).toMatchSnapshot();
});
it('close accordions via accordion props props dynamicly', function () {
var wrapper = _reactTestRenderer2.default.create(_react2.default.createElement(
_accordion2.default,
{ activeItems: [1] },
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
),
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
)
));
wrapper.update(_react2.default.createElement(
_accordion2.default,
{ activeItems: [] },
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
),
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
)
));
expect(wrapper.getInstance().state.activeItems).toEqual([]);
expect(wrapper).toMatchSnapshot();
});
it('different className with the same activeItems prop', function () {
var wrapper = _reactTestRenderer2.default.create(_react2.default.createElement(
_accordion2.default,
{ activeItems: [1], className: 'test-1' },
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
),
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
)
));
wrapper.update(_react2.default.createElement(
_accordion2.default,
{ activeItems: [1], className: 'test-2' },
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
),
_react2.default.createElement(
_accordionItem2.default,
null,
'Fake Child'
)
));
expect(wrapper).toMatchSnapshot();
});
});

24

dist/AccordionItem/accordion-item.js

@@ -21,4 +21,10 @@ 'use strict';

var _classnames = require('classnames');
var _classnames2 = _interopRequireDefault(_classnames);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

@@ -34,3 +40,4 @@

onClick: function onClick() {},
className: 'accordion__item'
className: 'accordion__item',
hideBodyClassName: null
};

@@ -43,3 +50,4 @@

children: _propTypes2.default.arrayOf(_propTypes2.default.element).isRequired,
className: _propTypes2.default.string
className: _propTypes2.default.string,
hideBodyClassName: _propTypes2.default.string
};

@@ -89,3 +97,3 @@

itemProps.id = 'accordion__body-' + itemUuid;
itemProps.role = accordion ? 'tabpanel' : '';
itemProps.role = accordion ? 'tabpanel' : null;

@@ -101,7 +109,13 @@ return _react2.default.cloneElement(item, itemProps);

value: function render() {
var className = this.props.className;
var _props2 = this.props,
className = _props2.className,
expanded = _props2.expanded,
hideBodyClassName = _props2.hideBodyClassName;
var itemClassName = (0, _classnames2.default)(className, _defineProperty({}, hideBodyClassName, !expanded && hideBodyClassName));
return _react2.default.createElement(
'div',
{ className: className },
{ className: itemClassName },
this.renderChildren()

@@ -108,0 +122,0 @@ );

@@ -192,2 +192,28 @@ 'use strict';

it('renders with different hideBodyClassName', function () {
var tree = _reactTestRenderer2.default.create(_react2.default.createElement(
_accordionItem2.default,
{ expanded: false, hideBodyClassName: 'testCSSClass--hidden' },
_react2.default.createElement(
_accordionItemTitle2.default,
null,
_react2.default.createElement(
'div',
null,
'Fake title'
)
),
_react2.default.createElement(
_accordionItemBody2.default,
null,
_react2.default.createElement(
'div',
null,
'Fake body'
)
)
)).toJSON();
expect(tree).toMatchSnapshot();
});
it('renders correctly with other blocks inside', function () {

@@ -194,0 +220,0 @@ var tree = _reactTestRenderer2.default.create(_react2.default.createElement(

@@ -56,2 +56,3 @@ 'use strict';

'aria-hidden': ariaHidden,
'aria-labelledby': id.replace('accordion__body-', 'accordion__title-'),
role: role

@@ -58,0 +59,0 @@ },

@@ -69,2 +69,15 @@ 'use strict';

});
it('renders correctly with an id (aria-labelledBy filled)', function () {
var tree = _reactTestRenderer2.default.create(_react2.default.createElement(
_accordionItemBody2.default,
{ id: 'accordion__body-HASHID', expanded: true },
_react2.default.createElement(
'div',
null,
'Fake body'
)
)).toJSON();
expect(tree).toMatchSnapshot();
});
});

@@ -17,4 +17,10 @@ 'use strict';

var _classnames = require('classnames');
var _classnames2 = _interopRequireDefault(_classnames);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

@@ -32,2 +38,3 @@

className: 'accordion__title',
hideBodyClassName: null,
role: ''

@@ -43,2 +50,3 @@ };

className: _propTypes2.default.string,
hideBodyClassName: _propTypes2.default.string,
role: _propTypes2.default.string

@@ -78,11 +86,30 @@ };

className = _props.className,
role = _props.role;
role = _props.role,
hideBodyClassName = _props.hideBodyClassName;
var titleClassName = (0, _classnames2.default)(className, _defineProperty({}, hideBodyClassName, hideBodyClassName && !expanded));
if (role === 'tab') {
return _react2.default.createElement(
'div',
{
id: id,
'aria-selected': expanded,
'aria-controls': ariaControls,
className: titleClassName,
onClick: onClick,
role: role,
tabIndex: '0',
onKeyPress: this.handleKeyPress
},
children
);
}
return _react2.default.createElement(
'div',
{ // eslint-disable-line jsx-a11y/no-static-element-interactions
{
id: id,
'aria-expanded': expanded,
'aria-controls': ariaControls,
className: className,
className: titleClassName,
onClick: onClick,

@@ -89,0 +116,0 @@ role: role,

@@ -44,2 +44,28 @@ 'use strict';

it('renders with different hideBodyClassName', function () {
var tree = _reactTestRenderer2.default.create(_react2.default.createElement(
_accordionItemTitle2.default,
{ expanded: false, hideBodyClassName: 'testCSSClass--hidden' },
_react2.default.createElement(
'div',
null,
'Fake title'
)
)).toJSON();
expect(tree).toMatchSnapshot();
});
it('doesn\'t respect hideBodyClassName when collapsed', function () {
var tree = _reactTestRenderer2.default.create(_react2.default.createElement(
_accordionItemTitle2.default,
{ expanded: true, hideBodyClassName: 'testCSSClass--hidden' },
_react2.default.createElement(
'div',
null,
'Fake title'
)
)).toJSON();
expect(tree).toMatchSnapshot();
});
it('renders correctly when pressing enter', function () {

@@ -95,2 +121,15 @@ var mockOnClick = jest.fn();

});
it('renders correctly with role of tab', function () {
var tree = _reactTestRenderer2.default.create(_react2.default.createElement(
_accordionItemTitle2.default,
{ role: 'tab', className: 'testCSSClass' },
_react2.default.createElement(
'div',
null,
'Fake Title'
)
)).toJSON();
expect(tree).toMatchSnapshot();
});
});
{
"name": "react-accessible-accordion",
"version": "0.5.0",
"version": "0.6.0",
"description": "Accessible Accordion component for React",

@@ -5,0 +5,0 @@ "main": "dist/index.js",

[react-accessible-accordion](https://springload.github.io/react-accessible-accordion/) [![npm](https://img.shields.io/npm/v/react-accessible-accordion.svg?style=flat-square)](https://www.npmjs.com/package/react-accessible-accordion) [![Build Status](https://travis-ci.org/springload/react-accessible-accordion.svg?branch=master)](https://travis-ci.org/springload/react-accessible-accordion) [![Coverage Status](https://coveralls.io/repos/github/springload/react-accessible-accordion/badge.svg)](https://coveralls.io/github/springload/react-accessible-accordion) [![Dependency Status](https://david-dm.org/springload/react-accessible-accordion.svg?style=flat-square)](https://david-dm.org/springload/react-accessible-accordion) [![devDependency Status](https://david-dm.org/springload/react-accessible-accordion/dev-status.svg?style=flat-square)](https://david-dm.org/springload/react-accessible-accordion#info=devDependencies)
[![Accessibility status](https://img.shields.io/badge/a11y-0%20error-brightgreen.svg)](http://wave.webaim.org/report#/https://springload.github.io/react-accessible-accordion/)
=========

@@ -96,2 +97,8 @@

</tr>
<tr>
<td>activeItems</td>
<td>Array</td>
<td>[]</td>
<td>Indexes (or custom keys) to pre expand items. Can be changed dynamically. Doesn't have the priority against `AccordionItem - expanded` on first render.</td>
</tr>
</tbody>

@@ -132,2 +139,8 @@ </table>

</tr>
<tr>
<td>customKey</td>
<td>String</td>
<td></td>
<td>Custom key to be used as a reference in `Accordion - activeItems`</td>
</tr>
</tbody>

@@ -194,2 +207,30 @@ </table>

## Accessibility
### What this project is doing accessibility-wise?
This project manages two types of Accordions, with single or multiple items open.
#### Single item
> Use this with with props `accordion` set to `true` on `Accordion`.
For this type of Accordion, you will get the following `role` set up on your elements:
- Accordion: `tablist`
- AccordionItem: no specific role
- AccordionItemTitle: `tab`
- AccordionItemBody: `tabpanel`
#### Multiple items
For this type of Accordion, you will get the following `role` set up on your elements:
> Use this with with props `accordion` set to `false` on `Accordion`.
- Accordion: no specific role
- AccordionItem: no specific role
- AccordionItemTitle: `button`
- AccordionItemBody: no specific role
## Development

@@ -246,1 +287,16 @@

```
# Browser support
**Supported browser / device versions:**
| Browser | Device/OS | Version | Notes |
|---------|-----------|---------|-------|
| Mobile Safari | iOS | latest ||
| Chrome | Android | latest ||
| IE | Windows | 11 ||
| MS Edge | Windows | latest ||
| Chrome | Desktop | latest ||
| Firefox | Desktop | latest ||
| Safari | OSX | latest ||
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc