react-accessible-accordion
Advanced tools
Comparing version 2.4.5 to 3.0.0
365
CHANGELOG.md
# Changelog | ||
> All notable changes to this project are documented in this file. | ||
> This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). | ||
> All notable changes to this project are documented in this file. This project | ||
> adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). | ||
## [[v3.0.0]](https://github.com/springload/react-accessible-accordion/releases/tag/v3.0.0) | ||
This release is the culmination of a massive amount of work, resulting in some | ||
new features and significantly stronger and more reliable WAI ARIA spec | ||
compliance. Notably, the project has been migrated from Flow to Typescript, and | ||
a full accessibility audit has been performed - revealing a few holes in our | ||
compliance which have now been entirely addressed. | ||
Thanks to everyone who has contributed to this release - and not just those who | ||
have written code. Contribution by way of issues relating to spec compliance, | ||
pull-request commentary, advice and assistance is all greatly appreciated. | ||
Thanks also to the patient users who have endured an extended period without a | ||
release while we made sure to get this 100% right! Release cadence should return | ||
to normal again now. | ||
### Breaking Changes - Upgrade Guide: | ||
1. Rename all of your `AccordionItemTitle` components to `AccordionItemHeading` | ||
and then nest an `AccordionItemButton` directly inside of each one. Note that | ||
in order for your Accordion to remain spec-compliant, you may _not_ put any | ||
other children inside `AccordionItemHeading`. | ||
```tsx | ||
// Before: | ||
import { AccordionItemTitle } from 'react-accessible-accordion'; | ||
const headingBefore = <AccordionItemTitle>Foo</AccordionItemTitle>; | ||
``` | ||
```tsx | ||
// After: | ||
import { | ||
AcccordionItemHeading, | ||
AccordionItemButton, | ||
} from 'react-accessible-accordion'; | ||
const headingAfter = ( | ||
<AccordionItemHeading> | ||
<AccordionItemButton>Foo</AccordionItemButton> | ||
</AccordionItemHeading> | ||
); | ||
``` | ||
2. Rename all of your `AccordionItemBody` components to `AccordionItemPanel`. | ||
```tsx | ||
// Before: | ||
import { AccordionItemBody } from 'react-accessible-accordion'; | ||
const panelBefore = ( | ||
<AccordionItemBody> | ||
Voluptate elit eiusmod laborum proident esse officia dolor laboris | ||
laboris amet nulla officia cillum. | ||
</AccordionItemBody> | ||
); | ||
``` | ||
```tsx | ||
// After: | ||
import { AccordionItemPanel } from 'react-accessible-accordion'; | ||
const panelAfter = ( | ||
<AccordionItemPanel> | ||
Voluptate elit eiusmod laborum proident esse officia dolor laboris | ||
laboris amet nulla officia cillum. | ||
</AccordionItemPanel> | ||
); | ||
``` | ||
3. Remove all instances of `hideBodyClassName`. This prop is no longer valid, as | ||
`AccordionItemPanel` components are now hidden without additional styling. If | ||
you _must_ have a different `className` prop when an item is collapsed, then | ||
you may leverage the new `AccordionItemState` component. | ||
```tsx | ||
// Before | ||
import { AccordionItemPanel } from 'react-accessible-accordion'; | ||
const panelBefore = ( | ||
<AccordionItemPanel className="foo" hideBodyClassName="foo--hidden" /> | ||
); | ||
``` | ||
```tsx | ||
// After: | ||
import { | ||
AccordionItemPanel, | ||
AccordionItemState, | ||
} from 'react-accessible-accordion'; | ||
const panelAfter = ( | ||
<AccordionItemState> | ||
{({ expanded }) => ( | ||
<AccordionItemPanel | ||
className={expanded ? 'foo' : 'foo foo--hidden'} | ||
/> | ||
)} | ||
</AccordionItemState> | ||
); | ||
``` | ||
4. Remove all instances of `AccordionItem`’s `expanded` prop and instead use | ||
`Accordion`’s `preExpanded` prop. Note that this means that ‘controlled’ | ||
accordions are no longer a supported pattern. Please raise an issue if you | ||
have a use-case which calls for the ability to manually control expanded | ||
state. | ||
```tsx | ||
// Before | ||
import { Accordion, AccordionItem } from 'react-accessible-accordion'; | ||
const accordionBefore = ( | ||
<Accordion> | ||
<AccordionItem expanded /> | ||
</Accordion> | ||
); | ||
``` | ||
```tsx | ||
// After: | ||
import { Accordion, AccordionItem } from 'react-accessible-accordion'; | ||
const accordionAfter = ( | ||
<Accordion preExpanded={['foo']}> | ||
<AccordionItem uuid="foo" /> | ||
</Accordion> | ||
); | ||
``` | ||
5. Remove all instances of `Accordion`’s `accordion` prop. Instead, use a | ||
combination of `allowZeroExpanded` and `allowMultipleExpanded` props to suit | ||
your requirements. If you were not explicitly setting `accordion` to `false` | ||
then you probably are not required to make any changes here. | ||
```tsx | ||
// Before | ||
import { Accordion } from 'react-accessible-accordion'; | ||
const accordionBefore = <Accordion accordion={false} />; | ||
``` | ||
```tsx | ||
// After: | ||
import { Accordion } from 'react-accessible-accordion'; | ||
const accordionAfter = <Accordion allowMultipleExpanded />; | ||
``` | ||
6. Upgrade to React v16.3+ | ||
7. Remove your `minimal-example.css` import. These styles only applied | ||
`display: none` to panels when collapsed, but browsers apply these styles to | ||
elements with the `hidden` attribute, which the `AccordionItemPanel` | ||
component now has (when collapsed). | ||
### Added | ||
- Added `AccordionItemButton` component. | ||
- Added `AccordionItemState` component. | ||
- Added `allowZeroExpanded` prop to `Accordion`. | ||
- Added `allowMultipleExpanded` prop to `Accordion`. | ||
- Out-of-the-box Typescript support. | ||
- Integration tests to explicitly assert every line of the WAI ARIA | ||
'Accordion' spec. | ||
- Additional keyboard functionality (Up, Down, Left, Right, Home, End). | ||
### Changed | ||
- Renamed `AccordionItemTitle` to `AccordionItemHeading` to be consistent with | ||
the language used in the WAI ARIA spec. | ||
- Renamed `AccordionItemBody` to `AccordionItemPanel` to be consistent with | ||
the language used in the WAI ARIA spec. | ||
- Updated `AccordionItemPanel` to have a `hidden` attribute. | ||
- Roles and aria attributes all audited and updated to match the WAI ARIA | ||
spec. | ||
- Update `onChange` to always be called with an array of the currently | ||
expanded items. | ||
### Fixed | ||
- Fixes SSR (server-side rendering). | ||
- Fixes incorrect roles and attributes as per the WAI ARIA spec. | ||
### Removed | ||
- Removed Flow support (but we hope to reinstate typing in the future. Track | ||
progress | ||
[here](https://github.com/springload/react-accessible-accordion/issues/151)). | ||
- Removed undocumented `expanded` mechanism for `AccordionItems`. | ||
- Removed undocumented `disabled` mechanism for `AccordionItems`. | ||
- Remove `hideBodyClassName` prop. | ||
## [[v2.4.5]](https://github.com/springload/react-accessible-accordion/releases/tag/v2.4.5) | ||
@@ -10,3 +202,3 @@ | ||
* Fixes SSR. | ||
- Fixes SSR. | ||
@@ -17,3 +209,5 @@ ## [[v2.4.4]](https://github.com/springload/react-accessible-accordion/releases/tag/v2.4.4) | ||
* Fixes [performance issue](https://github.com/springload/react-accessible-accordion/issues/110) with not re-instantiating render-prop callbacks on each re-render. | ||
- Fixes | ||
[performance issue](https://github.com/springload/react-accessible-accordion/issues/110) | ||
with not re-instantiating render-prop callbacks on each re-render. | ||
@@ -24,4 +218,4 @@ ## [[v2.4.3]](https://github.com/springload/react-accessible-accordion/releases/tag/v2.4.3) | ||
* Fixes issue with spacebar scrolling the page (see PR#99) | ||
* Fixes IE compatibility by replacing uses of Array.prototype.find. | ||
- Fixes issue with spacebar scrolling the page (see PR#99) | ||
- Fixes IE compatibility by replacing uses of Array.prototype.find. | ||
@@ -32,19 +226,21 @@ ## [[v2.4.2]](https://github.com/springload/react-accessible-accordion/releases/tag/v2.4.2) | ||
* Removes invalid test | ||
* Minor change to package.json to remove some redundant Jest config. | ||
* Upgrade one forgotten devDependency. | ||
- Removes invalid test | ||
- Minor change to package.json to remove some redundant Jest config. | ||
- Upgrade one forgotten devDependency. | ||
### Fixed | ||
* Emergency bug fix to remove asyc/await from the code (see PR#95) | ||
- Emergency bug fix to remove asyc/await from the code (see PR#95) | ||
## [[v2.4.1]](https://github.com/springload/react-accessible-accordion/releases/tag/v2.4.1) | ||
This release brings support for React 16.3+ by way of some minor refactoring to remove deprecated lifecycle methods. | ||
This release brings support for React 16.3+ by way of some minor refactoring to | ||
remove deprecated lifecycle methods. | ||
### Changed | ||
* Replace deprecated lifecycle methods 'componentWillReceiveProps', 'componentWillUpdate' and 'componentWillMount'. | ||
* Updated `unstated` (internal dependency) to latest major release. | ||
* Updated all devDependencies. | ||
- Replace deprecated lifecycle methods 'componentWillReceiveProps', | ||
'componentWillUpdate' and 'componentWillMount'. | ||
- Updated `unstated` (internal dependency) to latest major release. | ||
- Updated all devDependencies. | ||
@@ -55,8 +251,10 @@ ## [[v2.4.0]](https://github.com/springload/react-accessible-accordion/releases/tag/v2.4.0) | ||
* Possibility to have custom uuid on `AccordionItem` - suggested by https://github.com/springload/react-accessible-accordion/issues/70 | ||
- Possibility to have custom uuid on `AccordionItem` - suggested by | ||
https://github.com/springload/react-accessible-accordion/issues/70 | ||
### Fixed | ||
* Fix rollup config after version bump - https://gist.github.com/Rich-Harris/d472c50732dab03efeb37472b08a3f32 | ||
* Adds existing arrow animation for aria-selected=true in fancy CSS | ||
- Fix rollup config after version bump - | ||
https://gist.github.com/Rich-Harris/d472c50732dab03efeb37472b08a3f32 | ||
- Adds existing arrow animation for aria-selected=true in fancy CSS | ||
@@ -67,10 +265,13 @@ ## [[v2.3.1]](https://github.com/springload/react-accessible-accordion/releases/tag/v2.3.1) | ||
* Add `dist` folder to list of Flow ignores, so Flow doesn’t error after a build. | ||
* Issue with babel helpers. Just reverted commit 6f9f2c324a6fad4a35a84307241f4f710407f242 for now. | ||
- Add `dist` folder to list of Flow ignores, so Flow doesn’t error after a | ||
build. | ||
- Issue with babel helpers. Just reverted commit | ||
6f9f2c324a6fad4a35a84307241f4f710407f242 for now. | ||
### Changed | ||
* Removed a couple of old npm scripts from the days before we introduced rollup to the build | ||
pipeline. | ||
* Upgraded a bunch of devDependencies, including Webpack which required a bit of a config refactor. | ||
- Removed a couple of old npm scripts from the days before we introduced | ||
rollup to the build pipeline. | ||
- Upgraded a bunch of devDependencies, including Webpack which required a bit | ||
of a config refactor. | ||
@@ -81,4 +282,4 @@ ## [[v2.3.0]](https://github.com/springload/react-accessible-accordion/releases/tag/v2.3.0) | ||
* Refactored to use `unstated` for state-management instead of `mobx` + `mobx-react`, cutting the | ||
size of the bundle by approximately 60% 🎉. | ||
- Refactored to use `unstated` for state-management instead of `mobx` + | ||
`mobx-react`, cutting the size of the bundle by approximately 60% 🎉. | ||
@@ -89,3 +290,3 @@ ## [[v2.2.1]](https://github.com/springload/react-accessible-accordion/releases/tag/v2.2.1) | ||
* Fixes mixed up filenames in the README | ||
- Fixes mixed up filenames in the README | ||
@@ -96,5 +297,7 @@ ## [[v2.2.0]](https://github.com/springload/react-accessible-accordion/releases/tag/v2.2.0) | ||
* Demo styles added to the bundle as two optional files: | ||
* `minimal-example.css`: 'Minimal' theme - hide/show the AccordionBody component | ||
* `fancy-example.css`: 'Fancy' theme - boilerplate styles for all components, as seen on our demo | ||
- Demo styles added to the bundle as two optional files: | ||
- `minimal-example.css`: 'Minimal' theme - hide/show the AccordionBody | ||
component | ||
- `fancy-example.css`: 'Fancy' theme - boilerplate styles for all | ||
components, as seen on our demo | ||
@@ -105,36 +308,58 @@ ## [[v2.1.0]](https://github.com/springload/react-accessible-accordion/releases/tag/v2.1.0) | ||
* Publish flow types. | ||
- Publish flow types. | ||
### Changed | ||
* Update all React components to accept arbitrary HTMLDivElement props (eg. 'lang', 'role' etc). | ||
* Upgrade all dev-dependencies except the eslint configs. | ||
* Replace snapshot tests with explicit assertions in AccordionItemBody and AccordionItemTitle. | ||
* Add specific assertions to tests in accordionStore. | ||
* Minor syntax change in AccordionItemBody | ||
- Update all React components to accept arbitrary HTMLDivElement props (eg. | ||
'lang', 'role' etc). | ||
- Upgrade all dev-dependencies except the eslint configs. | ||
- Replace snapshot tests with explicit assertions in AccordionItemBody and | ||
AccordionItemTitle. | ||
- Add specific assertions to tests in accordionStore. | ||
- Minor syntax change in AccordionItemBody | ||
## [[v2.0.0]](https://github.com/springload/react-accessible-accordion/releases/tag/v2.0.0) | ||
Version 2.0 represents a total refactor, with a new context-based approach which should make this library more flexible, more maintainable and more comprehensively testable. | ||
Version 2.0 represents a total refactor, with a new context-based approach which | ||
should make this library more flexible, more maintainable and more | ||
comprehensively testable. | ||
As this is a major release, users should expect some breaking changes - though they should be limited to the removal of the `activeItems` prop (read more below). | ||
As this is a major release, users should expect some breaking changes - though | ||
they should be limited to the removal of the `activeItems` prop (read more | ||
below). | ||
### Added | ||
* Exports `resetNextId` (https://github.com/springload/react-accessible-accordion/issues/41). | ||
- Exports `resetNextId` | ||
(https://github.com/springload/react-accessible-accordion/issues/41). | ||
### Fixed | ||
* Defect where controlled components' props were overridden by React.Children.map (https://github.com/springload/react-accessible-accordion/issues/33). | ||
* Defect where accordion crashed with unexpected `children` types (https://github.com/springload/react-accessible-accordion/issues/45). | ||
* Defect where React Accessible Accordion's components could not be extended. | ||
* Defect where the `children` of `Accordion` or `AccordionItem` could not be arbitrary. | ||
* Defect where `AccordionItem` had to be a child of `Accordion` (as opposed to to an arbitrary-level descendant). | ||
* Defect where `AccordionItemBody` and `AccordionItemTitle` had to be children of `AccordionItem` (as opposed to arbitrary-level descendants). | ||
- Defect where controlled components' props were overridden by | ||
React.Children.map | ||
(https://github.com/springload/react-accessible-accordion/issues/33). | ||
- Defect where accordion crashed with unexpected `children` types | ||
(https://github.com/springload/react-accessible-accordion/issues/45). | ||
- Defect where React Accessible Accordion's components could not be extended. | ||
- Defect where the `children` of `Accordion` or `AccordionItem` could not be | ||
arbitrary. | ||
- Defect where `AccordionItem` had to be a child of `Accordion` (as opposed to | ||
to an arbitrary-level descendant). | ||
- Defect where `AccordionItemBody` and `AccordionItemTitle` had to be children | ||
of `AccordionItem` (as opposed to arbitrary-level descendants). | ||
### Removed: | ||
* 🚨 Breaking change 🚨 `activeItems` property is no longer supported. | ||
- 🚨 Breaking change 🚨 `activeItems` property is no longer supported. | ||
Control at the `Accordion` level (via the `activeItems` prop) and `AccordionItem` level (via the `expanded` prop) fought against one another, and choosing which control mechanism to give preference to would have been an arbitrary decision - and whichever way we went, we would have had test cases which demonstrated unusual/unpredictable behaviour. The `activeItems` mechanism was the obvious one to remove - it was arguably the "less React-y way", and we considered it more of a convenience than a feature. Crucially though, it fought too hard against the new architecture of the library, and keeping it would have prevented us enabling lots of other new features or resolving some of the issues that our users had raised. | ||
Control at the `Accordion` level (via the `activeItems` prop) and | ||
`AccordionItem` level (via the `expanded` prop) fought against one another, and | ||
choosing which control mechanism to give preference to would have been an | ||
arbitrary decision - and whichever way we went, we would have had test cases | ||
which demonstrated unusual/unpredictable behaviour. The `activeItems` mechanism | ||
was the obvious one to remove - it was arguably the "less React-y way", and we | ||
considered it more of a convenience than a feature. Crucially though, it fought | ||
too hard against the new architecture of the library, and keeping it would have | ||
prevented us enabling lots of other new features or resolving some of the issues | ||
that our users had raised. | ||
@@ -158,48 +383,56 @@ If you're currently using activeItems, you're upgrade path might look like this: | ||
Please don't hesitate to reach out to one of the maintainers (or raise an issue) if you're having trouble upgrading - we're happy to help! | ||
Please don't hesitate to reach out to one of the maintainers (or raise an issue) | ||
if you're having trouble upgrading - we're happy to help! | ||
## [[v1.0.1]](https://github.com/springload/react-accessible-accordion/releases/tag/v1.0.1) | ||
* Renders predictable `id` attributes.(https://github.com/springload/react-accessible-accordion/pull/29) | ||
- Renders predictable `id` | ||
attributes.(https://github.com/springload/react-accessible-accordion/pull/29) | ||
## [[v1.0.0]](https://github.com/springload/react-accessible-accordion/releases/tag/v1.0.0) | ||
* Replace prop-types implementation with flow-types (https://github.com/springload/react-accessible-accordion/pull/22) | ||
Thanks @ryami333 for the great contribution | ||
- Replace prop-types implementation with flow-types | ||
(https://github.com/springload/react-accessible-accordion/pull/22) Thanks | ||
@ryami333 for the great contribution | ||
NB: This version is backward compatible. It's just bumping to 1.0 to represent maturity rather than API changes. | ||
NB: This version is backward compatible. It's just bumping to 1.0 to represent | ||
maturity rather than API changes. | ||
## [[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) | ||
- 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 | ||
- 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) | ||
* Possibility to add a CSS class to hidden blocks (Following https://github.com/springload/react-accessible-accordion/pull/16) | ||
* Githooks are executable (https://github.com/springload/react-accessible-accordion/pull/15) | ||
* Bump to Node 8 / NPM 5 | ||
- Possibility to add a CSS class to hidden blocks (Following | ||
https://github.com/springload/react-accessible-accordion/pull/16) | ||
- Githooks are executable | ||
(https://github.com/springload/react-accessible-accordion/pull/15) | ||
- Bump to Node 8 / NPM 5 | ||
## [[v0.4.0]](https://github.com/springload/react-accessible-accordion/releases/tag/v0.4.0) | ||
* Supports React 15.5+ | ||
- Supports React 15.5+ | ||
## [[v0.3.0]](https://github.com/springload/react-accessible-accordion/releases/tag/v0.3.0) | ||
* No warnings when you have only one item in the accordion | ||
- No warnings when you have only one item in the accordion | ||
## [[v0.2.0]](https://github.com/springload/react-accessible-accordion/releases/tag/v0.2.0) | ||
* Possibility to have extra blocks in AccordionItem | ||
- Possibility to have extra blocks in AccordionItem | ||
## [[v0.1.2]](https://github.com/springload/react-accessible-accordion/releases/tag/v0.1.2) | ||
* Accordion mode / Collapse mode | ||
* Possibility to pre expand items | ||
* 100% coverage with unit tests | ||
* Possibility to customise CSS. | ||
* Clean CSS for the demo/github page. | ||
- Accordion mode / Collapse mode | ||
- Possibility to pre expand items | ||
- 100% coverage with unit tests | ||
- Possibility to customise CSS. | ||
- Clean CSS for the demo/github page. | ||
@@ -210,3 +443,3 @@ ## [[vx.y.z]](https://github.com/springload/Quicktube.js/releases/tag/x.y.z) Template from http://keepachangelog.com/ | ||
* Something was added to the API / a new feature was introduced. | ||
- Something was added to the API / a new feature was introduced. | ||
@@ -213,0 +446,0 @@ ### Changed |
@@ -7,31 +7,18 @@ # Contributing | ||
> Clone the project on your computer, and install [Node](https://nodejs.org). This project also uses [nvm](https://github.com/springload/frontend-starter-kit/blob/master/docs/useful-tooling.md#nvm). | ||
Clone the project on your computer, and install [Node](https://nodejs.org). This | ||
project also uses | ||
[nvm](https://github.com/springload/frontend-starter-kit/blob/master/docs/useful-tooling.md#nvm). | ||
### Working on the project | ||
```sh | ||
# Use the right node version. | ||
nvm install | ||
# Then, install all project dependencies. | ||
npm install | ||
# Install the git hooks. | ||
./.githooks/deploy | ||
# Set up a `.env` file with the appropriate secrets. | ||
touch .env | ||
# Install dependencies. | ||
yarn install | ||
``` | ||
### Working on the project | ||
Once installed, see the `scripts` key in `package.json` for all of the available | ||
tasks. | ||
> Everything mentioned in the installation process should already be done. | ||
```sh | ||
# Make sure you use the right node version. | ||
nvm use | ||
# Start the the development tools in watch mode. | ||
npm run start | ||
# Runs linting. | ||
npm run lint | ||
# Runs tests. | ||
npm run test | ||
# View other available commands with: | ||
npm run | ||
``` | ||
### Run the demo | ||
@@ -45,3 +32,3 @@ | ||
# Start the server and the development tools. | ||
npm run start-demo | ||
yarn start-demo | ||
``` | ||
@@ -56,1 +43,38 @@ | ||
``` | ||
# Project Principles | ||
The following principles should help to inform decisions at every level of the | ||
project's architecture, from communication to implementation, and everything in | ||
between. | ||
## Inclusivity | ||
The driving principal behind the existence of React Accessible Accordion is an | ||
inclusive web. Primarily, this relates to the inclusivity of those web users | ||
with disabilities or impairments which require the use of assistive hardware or | ||
other assistive technology, such as screenreaders. This principle of inclusivity | ||
should also apply to the technical community as a whole, such that RAA should | ||
_try_ to remain as technology-agnostic as possible. Examples of technical | ||
decisions driven by the principle of inclusivity: | ||
- A deep browser backward compatibility. | ||
- A deep React version backward compatibility. | ||
- Maintenance of both Typescript _and_ Flow types (WIP at time of writing). | ||
## Trust | ||
Our users need to be able to trust that we are making sensible decisions with | ||
regards to performance, spec-compliance and API patterns, or they will simply | ||
use another Accordion component which may not. This manifests in closing issues | ||
quickly, releasing often, communicating openly and effectively, making sensible | ||
technology choices and limiting the number of breaking changes, to name a few. | ||
## Fast + Light | ||
Consuming React Accessible Accordion should not result in enormous bundle sizes. | ||
The bundle size should be routinely audited, using a tool such as | ||
[Bundlephobia](https://bundlephobia.com/result?p=react-accessible-accordion). We | ||
avoid using third-party dependencies where possible, particularly when they do | ||
not support tree-shaking or add bloat which is disproportionate to their | ||
utility. |
1217
dist/es/index.js
@@ -1,2 +0,2 @@ | ||
import React, { Component } from 'react'; | ||
import { createContext, createElement, PureComponent, Component, Fragment } from 'react'; | ||
@@ -180,8 +180,124 @@ function _classCallCheck(instance, Constructor) { | ||
// Arbitrary, but ought to be unique to avoid context namespace clashes. | ||
var CONTEXT_KEY = 'react-accessible-accordion@AccordionContainer'; | ||
var DisplayName; | ||
(function (DisplayName) { | ||
DisplayName["Accordion"] = "Accordion"; | ||
DisplayName["AccordionItem"] = "AccordionItem"; | ||
DisplayName["AccordionItemButton"] = "AccordionItemButton"; | ||
DisplayName["AccordionItemHeading"] = "AccordionItemHeading"; | ||
DisplayName["AccordionItemPanel"] = "AccordionItemPanel"; | ||
})(DisplayName || (DisplayName = {})); | ||
var DisplayName$1 = DisplayName; | ||
var AccordionStore = function AccordionStore(_ref) { | ||
var _this = this; | ||
var _ref$expanded = _ref.expanded, | ||
_expanded = _ref$expanded === void 0 ? [] : _ref$expanded, | ||
_ref$allowMultipleExp = _ref.allowMultipleExpanded, | ||
allowMultipleExpanded = _ref$allowMultipleExp === void 0 ? false : _ref$allowMultipleExp, | ||
_ref$allowZeroExpande = _ref.allowZeroExpanded, | ||
allowZeroExpanded = _ref$allowZeroExpande === void 0 ? false : _ref$allowZeroExpande; | ||
_classCallCheck(this, AccordionStore); | ||
_defineProperty(this, "expanded", void 0); | ||
_defineProperty(this, "allowMultipleExpanded", void 0); | ||
_defineProperty(this, "allowZeroExpanded", void 0); | ||
_defineProperty(this, "toggleExpanded", function (uuid) { | ||
if (_this.isItemDisabled(uuid)) { | ||
return _this; | ||
} | ||
var isExpanded = _this.isItemExpanded(uuid); | ||
if (!isExpanded) { | ||
return _this.augment({ | ||
expanded: _this.allowMultipleExpanded ? [].concat(_toConsumableArray(_this.expanded), [uuid]) : [uuid] | ||
}); | ||
} else { | ||
return _this.augment({ | ||
expanded: _this.expanded.filter(function (expandedUuid) { | ||
return expandedUuid !== uuid; | ||
}) | ||
}); | ||
} | ||
}); | ||
_defineProperty(this, "isItemDisabled", function (uuid) { | ||
var isExpanded = _this.isItemExpanded(uuid); | ||
var isOnlyOneExpanded = _this.expanded.length === 1; | ||
return Boolean(isExpanded && !_this.allowZeroExpanded && isOnlyOneExpanded); | ||
}); | ||
_defineProperty(this, "isItemExpanded", function (uuid) { | ||
return _this.expanded.findIndex(function (expandedUuid) { | ||
return expandedUuid === uuid; | ||
}) !== -1; | ||
}); | ||
_defineProperty(this, "getPanelAttributes", function (uuid) { | ||
var expanded = _this.isItemExpanded(uuid); | ||
return { | ||
role: _this.allowMultipleExpanded ? undefined : 'region', | ||
'aria-hidden': _this.allowMultipleExpanded ? !expanded : undefined, | ||
'aria-labelledby': _this.getButtonId(uuid), | ||
id: _this.getPanelId(uuid), | ||
hidden: expanded ? undefined : true | ||
}; | ||
}); | ||
_defineProperty(this, "getHeadingAttributes", function (uuid) { | ||
return { | ||
role: 'heading' | ||
}; | ||
}); | ||
_defineProperty(this, "getButtonAttributes", function (uuid) { | ||
var expanded = _this.isItemExpanded(uuid); | ||
var disabled = _this.isItemDisabled(uuid); | ||
return { | ||
id: _this.getButtonId(uuid), | ||
'aria-disabled': disabled, | ||
'aria-expanded': expanded, | ||
'aria-controls': _this.getPanelId(uuid), | ||
role: 'button', | ||
tabIndex: 0 | ||
}; | ||
}); | ||
_defineProperty(this, "getPanelId", function (uuid) { | ||
return "accordion__panel-".concat(uuid); | ||
}); | ||
_defineProperty(this, "getButtonId", function (uuid) { | ||
return "accordion__heading-".concat(uuid); | ||
}); | ||
_defineProperty(this, "augment", function (args) { | ||
return new AccordionStore(_objectSpread({ | ||
expanded: _this.expanded, | ||
allowMultipleExpanded: _this.allowMultipleExpanded, | ||
allowZeroExpanded: _this.allowZeroExpanded | ||
}, args)); | ||
}); | ||
this.expanded = _expanded; | ||
this.allowMultipleExpanded = allowMultipleExpanded; | ||
this.allowZeroExpanded = allowZeroExpanded; | ||
}; | ||
var Context = createContext(null); | ||
var Provider = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(Provider, _Component); | ||
function (_React$PureComponent) { | ||
_inherits(Provider, _React$PureComponent); | ||
@@ -201,76 +317,38 @@ function Provider() { | ||
_defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "state", { | ||
items: _this.props.items || [] | ||
}); | ||
_defineProperty(_assertThisInitialized(_this), "state", new AccordionStore({ | ||
expanded: _this.props.preExpanded, | ||
allowMultipleExpanded: _this.props.allowMultipleExpanded, | ||
allowZeroExpanded: _this.props.allowZeroExpanded | ||
})); | ||
_defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "addItem", function (newItem) { | ||
// Need to use callback style otherwise race-conditions are created by concurrent registrations. | ||
_defineProperty(_assertThisInitialized(_this), "toggleExpanded", function (key) { | ||
_this.setState(function (state) { | ||
var items; | ||
if (state.items.some(function (item) { | ||
return item.uuid === newItem.uuid; | ||
})) { | ||
// eslint-disable-next-line no-console | ||
console.error("AccordionItem error: One item already has the uuid \"".concat(newItem.uuid, "\". Uuid property must be unique. See: https://github.com/springload/react-accessible-accordion#accordionitem")); | ||
return state.toggleExpanded(key); | ||
}, function () { | ||
if (_this.props.onChange) { | ||
_this.props.onChange(_this.state.expanded); | ||
} | ||
if (_this.props.accordion && newItem.expanded) { | ||
// If this is a true accordion and the new item is expanded, then the others must be closed. | ||
items = _toConsumableArray(state.items.map(function (item) { | ||
return _objectSpread({}, item, { | ||
expanded: false | ||
}); | ||
})).concat([newItem]); | ||
} else { | ||
items = _toConsumableArray(state.items).concat([newItem]); | ||
} | ||
return { | ||
items: items | ||
}; | ||
}); | ||
}); | ||
_defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "removeItem", function (key) { | ||
return _this.setState(function (state) { | ||
return { | ||
items: state.items.filter(function (item) { | ||
return item.uuid !== key; | ||
}) | ||
}; | ||
}); | ||
_defineProperty(_assertThisInitialized(_this), "isItemDisabled", function (key) { | ||
return _this.state.isItemDisabled(key); | ||
}); | ||
_defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "setExpanded", function (key, expanded) { | ||
return _this.setState(function (state) { | ||
return { | ||
items: state.items.map(function (item) { | ||
if (item.uuid === key) { | ||
return _objectSpread({}, item, { | ||
expanded: expanded | ||
}); | ||
} | ||
_defineProperty(_assertThisInitialized(_this), "isItemExpanded", function (key) { | ||
return _this.state.isItemExpanded(key); | ||
}); | ||
if (_this.props.accordion && expanded) { | ||
// If this is an accordion, we might need to collapse the other expanded item. | ||
return _objectSpread({}, item, { | ||
expanded: false | ||
}); | ||
} | ||
_defineProperty(_assertThisInitialized(_this), "getPanelAttributes", function (key) { | ||
return _this.state.getPanelAttributes(key); | ||
}); | ||
return item; | ||
}) | ||
}; | ||
}, function () { | ||
if (_this.props.onChange) { | ||
_this.props.onChange(_this.props.accordion ? key : _this.state.items.filter(function (item) { | ||
return item.expanded; | ||
}).map(function (item) { | ||
return item.uuid; | ||
})); | ||
} | ||
}); | ||
_defineProperty(_assertThisInitialized(_this), "getHeadingAttributes", function (key) { | ||
return _this.state.getHeadingAttributes(key); | ||
}); | ||
_defineProperty(_assertThisInitialized(_this), "getButtonAttributes", function (key) { | ||
return _this.state.getButtonAttributes(key); | ||
}); | ||
return _this; | ||
@@ -280,17 +358,19 @@ } | ||
_createClass(Provider, [{ | ||
key: "getChildContext", | ||
value: function getChildContext() { | ||
var context = { | ||
items: this.state.items, | ||
accordion: !!this.props.accordion, | ||
addItem: this.addItem, | ||
removeItem: this.removeItem, | ||
setExpanded: this.setExpanded | ||
}; | ||
return _defineProperty({}, CONTEXT_KEY, context); | ||
} | ||
}, { | ||
key: "render", | ||
value: function render() { | ||
return this.props.children || null; | ||
var _this$state = this.state, | ||
allowZeroExpanded = _this$state.allowZeroExpanded, | ||
allowMultipleExpanded = _this$state.allowMultipleExpanded; | ||
return createElement(Context.Provider, { | ||
value: { | ||
allowMultipleExpanded: allowMultipleExpanded, | ||
allowZeroExpanded: allowZeroExpanded, | ||
toggleExpanded: this.toggleExpanded, | ||
isItemDisabled: this.isItemDisabled, | ||
isItemExpanded: this.isItemExpanded, | ||
getPanelAttributes: this.getPanelAttributes, | ||
getHeadingAttributes: this.getHeadingAttributes, | ||
getButtonAttributes: this.getButtonAttributes | ||
} | ||
}, this.props.children || null); | ||
} | ||
@@ -300,17 +380,32 @@ }]); | ||
return Provider; | ||
}(Component); // eslint-disable-next-line react/no-multi-comp | ||
}(PureComponent); | ||
_defineProperty(Provider, "childContextTypes", _defineProperty({}, CONTEXT_KEY, function () { | ||
return null; | ||
})); | ||
_defineProperty(Provider, "defaultProps", { | ||
allowMultipleExpanded: false, | ||
allowZeroExpanded: false | ||
}); | ||
var Consumer = | ||
/*#__PURE__*/ | ||
function (_Component2) { | ||
_inherits(Consumer, _Component2); | ||
function (_React$PureComponent2) { | ||
_inherits(Consumer, _React$PureComponent2); | ||
function Consumer() { | ||
var _getPrototypeOf3; | ||
var _this2; | ||
_classCallCheck(this, Consumer); | ||
return _possibleConstructorReturn(this, _getPrototypeOf(Consumer).apply(this, arguments)); | ||
for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { | ||
args[_key3] = arguments[_key3]; | ||
} | ||
_this2 = _possibleConstructorReturn(this, (_getPrototypeOf3 = _getPrototypeOf(Consumer)).call.apply(_getPrototypeOf3, [this].concat(args))); | ||
_defineProperty(_assertThisInitialized(_this2), "renderChildren", function (container) { | ||
return container ? _this2.props.children(container) : null; | ||
}); | ||
return _this2; | ||
} | ||
@@ -321,3 +416,3 @@ | ||
value: function render() { | ||
return this.props.children(this.context[CONTEXT_KEY]); | ||
return createElement(Context.Consumer, null, this.renderChildren); | ||
} | ||
@@ -327,36 +422,10 @@ }]); | ||
return Consumer; | ||
}(Component); | ||
}(PureComponent); | ||
_defineProperty(Consumer, "contextTypes", _defineProperty({}, CONTEXT_KEY, function () { | ||
return null; | ||
})); | ||
var accordionDefaultProps = { | ||
accordion: true | ||
}; | ||
var Accordion = function Accordion(_ref) { | ||
var accordion = _ref.accordion, | ||
rest = _objectWithoutProperties(_ref, ["accordion"]); | ||
return React.createElement("div", _extends({ | ||
role: accordion ? 'tablist' : null | ||
}, rest)); | ||
}; | ||
Accordion.defaultProps = accordionDefaultProps; | ||
var defaultProps = { | ||
accordion: true, | ||
onChange: function onChange() {}, | ||
className: 'accordion', | ||
children: null | ||
}; | ||
var AccordionWrapper = | ||
var Accordion = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(AccordionWrapper, _Component); | ||
function (_React$Component) { | ||
_inherits(Accordion, _React$Component); | ||
function AccordionWrapper() { | ||
function Accordion() { | ||
var _getPrototypeOf2; | ||
@@ -366,3 +435,3 @@ | ||
_classCallCheck(this, AccordionWrapper); | ||
_classCallCheck(this, Accordion); | ||
@@ -373,12 +442,14 @@ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(AccordionWrapper)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(Accordion)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
_defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "renderAccordion", function (accordionStore) { | ||
_defineProperty(_assertThisInitialized(_this), "renderAccordion", function (accordionContext) { | ||
var _this$props = _this.props, | ||
accordion = _this$props.accordion, | ||
preExpanded = _this$props.preExpanded, | ||
allowMultipleExpanded = _this$props.allowMultipleExpanded, | ||
allowZeroExpanded = _this$props.allowZeroExpanded, | ||
onChange = _this$props.onChange, | ||
rest = _objectWithoutProperties(_this$props, ["accordion", "onChange"]); | ||
rest = _objectWithoutProperties(_this$props, ["preExpanded", "allowMultipleExpanded", "allowZeroExpanded", "onChange"]); | ||
return React.createElement(Accordion, _extends({ | ||
accordion: accordionStore.accordion | ||
return createElement("div", _extends({ | ||
"data-accordion-component": "Accordion" | ||
}, rest)); | ||
@@ -390,429 +461,368 @@ }); | ||
_createClass(AccordionWrapper, [{ | ||
_createClass(Accordion, [{ | ||
key: "render", | ||
value: function render() { | ||
return React.createElement(Provider, { | ||
accordion: this.props.accordion, | ||
return createElement(Provider, { | ||
preExpanded: this.props.preExpanded, | ||
allowMultipleExpanded: this.props.allowMultipleExpanded, | ||
allowZeroExpanded: this.props.allowZeroExpanded, | ||
onChange: this.props.onChange | ||
}, React.createElement(Consumer, null, this.renderAccordion)); | ||
}, createElement(Consumer, null, this.renderAccordion)); | ||
} | ||
}]); | ||
return AccordionWrapper; | ||
return Accordion; | ||
}(Component); | ||
_defineProperty(AccordionWrapper, "defaultProps", defaultProps); | ||
_defineProperty(Accordion, "defaultProps", { | ||
allowMultipleExpanded: undefined, | ||
allowZeroExpanded: undefined, | ||
onChange: undefined, | ||
className: 'accordion', | ||
children: undefined | ||
}); | ||
function _extends$1() { | ||
_extends$1 = Object.assign || function (target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i]; | ||
_defineProperty(Accordion, "displayName", DisplayName$1.Accordion); | ||
for (var key in source) { | ||
if (Object.prototype.hasOwnProperty.call(source, key)) { | ||
target[key] = source[key]; | ||
} | ||
} | ||
} | ||
return target; | ||
}; | ||
return _extends$1.apply(this, arguments); | ||
var DEFAULT = 0; | ||
var counter = DEFAULT; | ||
function nextUuid() { | ||
var current = counter; | ||
counter = counter + 1; | ||
return current; | ||
} | ||
/** | ||
* Copyright (c) 2013-present, Facebook, Inc. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @typechecks | ||
* | ||
*/ | ||
function _inheritsLoose$1(subClass, superClass) { | ||
subClass.prototype = Object.create(superClass.prototype); | ||
subClass.prototype.constructor = subClass; | ||
subClass.__proto__ = superClass; | ||
function resetNextUuid() { | ||
counter = DEFAULT; | ||
} | ||
/** | ||
* Copyright (c) 2013-present, Facebook, Inc. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
var Context$1 = createContext(null); | ||
function unwrapExports (x) { | ||
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; | ||
} | ||
var Provider$1 = | ||
/*#__PURE__*/ | ||
function (_React$Component) { | ||
_inherits(Provider, _React$Component); | ||
function createCommonjsModule(fn, module) { | ||
return module = { exports: {} }, fn(module, module.exports), module.exports; | ||
} | ||
function Provider() { | ||
var _getPrototypeOf2; | ||
var lib = createCommonjsModule(function (module, exports) { | ||
var _this; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
_classCallCheck(this, Provider); | ||
var createChangeEmitter = exports.createChangeEmitter = function createChangeEmitter() { | ||
var currentListeners = []; | ||
var nextListeners = currentListeners; | ||
function ensureCanMutateNextListeners() { | ||
if (nextListeners === currentListeners) { | ||
nextListeners = currentListeners.slice(); | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
} | ||
function listen(listener) { | ||
if (typeof listener !== 'function') { | ||
throw new Error('Expected listener to be a function.'); | ||
} | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(Provider)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
var isSubscribed = true; | ||
ensureCanMutateNextListeners(); | ||
nextListeners.push(listener); | ||
return function () { | ||
if (!isSubscribed) { | ||
return; | ||
} | ||
_defineProperty(_assertThisInitialized(_this), "toggleExpanded", function () { | ||
_this.props.accordionContext.toggleExpanded(_this.props.uuid); | ||
}); | ||
isSubscribed = false; | ||
ensureCanMutateNextListeners(); | ||
var index = nextListeners.indexOf(listener); | ||
nextListeners.splice(index, 1); | ||
}; | ||
} | ||
_defineProperty(_assertThisInitialized(_this), "renderChildren", function (accordionContext) { | ||
var uuid = _this.props.uuid; | ||
var expanded = accordionContext.isItemExpanded(uuid); | ||
var disabled = accordionContext.isItemDisabled(uuid); | ||
var panelAttributes = accordionContext.getPanelAttributes(uuid); | ||
var headingAttributes = accordionContext.getHeadingAttributes(uuid); | ||
var buttonAttributes = accordionContext.getButtonAttributes(uuid); | ||
return createElement(Context$1.Provider, { | ||
value: { | ||
uuid: uuid, | ||
expanded: expanded, | ||
disabled: disabled, | ||
toggleExpanded: _this.toggleExpanded, | ||
panelAttributes: panelAttributes, | ||
headingAttributes: headingAttributes, | ||
buttonAttributes: buttonAttributes | ||
}, | ||
children: _this.props.children | ||
}); | ||
}); | ||
function emit() { | ||
currentListeners = nextListeners; | ||
var listeners = currentListeners; | ||
for (var i = 0; i < listeners.length; i++) { | ||
listeners[i].apply(listeners, arguments); | ||
} | ||
return _this; | ||
} | ||
return { | ||
listen: listen, | ||
emit: emit | ||
}; | ||
}; | ||
}); | ||
unwrapExports(lib); | ||
var lib_1 = lib.createChangeEmitter; | ||
function symbolObservablePonyfill(root) { | ||
var result; | ||
var Symbol = root.Symbol; | ||
if (typeof Symbol === 'function') { | ||
if (Symbol.observable) { | ||
result = Symbol.observable; | ||
} else { | ||
result = Symbol('observable'); | ||
Symbol.observable = result; | ||
_createClass(Provider, [{ | ||
key: "render", | ||
value: function render() { | ||
return createElement(Consumer, null, this.renderChildren); | ||
} | ||
} else { | ||
result = '@@observable'; | ||
} | ||
}]); | ||
return result; | ||
} | ||
return Provider; | ||
}(Component); | ||
/* global window */ | ||
var root; | ||
var ProviderWrapper = function ProviderWrapper(props) { | ||
return createElement(Consumer, null, function (accordionContext) { | ||
return createElement(Provider$1, _extends({}, props, { | ||
accordionContext: accordionContext | ||
})); | ||
}); | ||
}; | ||
var Consumer$1 = | ||
/*#__PURE__*/ | ||
function (_React$PureComponent) { | ||
_inherits(Consumer, _React$PureComponent); | ||
if (typeof self !== 'undefined') { | ||
root = self; | ||
} else if (typeof window !== 'undefined') { | ||
root = window; | ||
} else if (typeof global !== 'undefined') { | ||
root = global; | ||
} else if (typeof module !== 'undefined') { | ||
root = module; | ||
} else { | ||
root = Function('return this')(); | ||
} | ||
function Consumer() { | ||
var _getPrototypeOf3; | ||
var result = symbolObservablePonyfill(root); | ||
var _this2; | ||
var Nothing = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inheritsLoose$1(Nothing, _Component); | ||
_classCallCheck(this, Consumer); | ||
function Nothing() { | ||
return _Component.apply(this, arguments) || this; | ||
} | ||
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | ||
args[_key2] = arguments[_key2]; | ||
} | ||
var _proto = Nothing.prototype; | ||
_this2 = _possibleConstructorReturn(this, (_getPrototypeOf3 = _getPrototypeOf(Consumer)).call.apply(_getPrototypeOf3, [this].concat(args))); | ||
_proto.render = function render() { | ||
return null; | ||
}; | ||
_defineProperty(_assertThisInitialized(_this2), "renderChildren", function (container) { | ||
return container ? _this2.props.children(container) : null; | ||
}); | ||
return Nothing; | ||
}(Component); | ||
var fromRenderProps = function fromRenderProps(RenderPropsComponent, propsMapper, renderPropName) { | ||
if (renderPropName === void 0) { | ||
renderPropName = 'children'; | ||
return _this2; | ||
} | ||
return function (BaseComponent) { | ||
var baseFactory = React.createFactory(BaseComponent); | ||
var renderPropsFactory = React.createFactory(RenderPropsComponent); | ||
_createClass(Consumer, [{ | ||
key: "render", | ||
value: function render() { | ||
return createElement(Context$1.Consumer, null, this.renderChildren); | ||
} | ||
}]); | ||
var FromRenderProps = function FromRenderProps(ownerProps) { | ||
var _renderPropsFactory; | ||
return Consumer; | ||
}(PureComponent); | ||
return renderPropsFactory((_renderPropsFactory = {}, _renderPropsFactory[renderPropName] = function () { | ||
return baseFactory(_extends({}, ownerProps, propsMapper.apply(void 0, arguments))); | ||
}, _renderPropsFactory)); | ||
}; | ||
return FromRenderProps; | ||
}; | ||
var defaultProps = { | ||
className: 'accordion__item' | ||
}; | ||
var compose = function compose() { | ||
for (var _len = arguments.length, funcs = new Array(_len), _key = 0; _key < _len; _key++) { | ||
funcs[_key] = arguments[_key]; | ||
} | ||
var AccordionItem = | ||
/*#__PURE__*/ | ||
function (_React$Component) { | ||
_inherits(AccordionItem, _React$Component); | ||
return funcs.reduce(function (a, b) { | ||
return function () { | ||
return a(b.apply(void 0, arguments)); | ||
}; | ||
}, function (arg) { | ||
return arg; | ||
}); | ||
}; | ||
function AccordionItem() { | ||
var _getPrototypeOf2; | ||
/*! | ||
* consecutive | ||
* Get consecutive numbers | ||
* Copyright(c) 2017 ivanoff .$ curl -A cv ivanoff.org.ua | ||
* MIT Licensed | ||
*/ | ||
var _this; | ||
var consecutive = function (begin, base, inc) { | ||
var number = begin || 0; | ||
if (typeof base !== 'number') base = 10; | ||
if (typeof inc !== 'number') inc = 1; | ||
return function () { | ||
var res; | ||
_classCallCheck(this, AccordionItem); | ||
if (typeof base === 'undefined' || base === 10) { | ||
res = number; | ||
number += inc; | ||
} else { | ||
res = number.toString(); | ||
number = (parseInt(number, base) + inc).toString(base); | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
return res; | ||
}; | ||
}; | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(AccordionItem)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
// Arbitrary, but ought to be unique to avoid context namespace clashes. | ||
var CONTEXT_KEY$1 = 'react-accessible-accordion@ItemContainer'; | ||
var Provider$1 = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(Provider, _Component); | ||
_defineProperty(_assertThisInitialized(_this), "instanceUuid", nextUuid()); | ||
function Provider() { | ||
_classCallCheck(this, Provider); | ||
return _possibleConstructorReturn(this, _getPrototypeOf(Provider).apply(this, arguments)); | ||
return _this; | ||
} | ||
_createClass(Provider, [{ | ||
key: "getChildContext", | ||
value: function getChildContext() { | ||
var uuid = this.props.uuid; | ||
var context = { | ||
uuid: uuid | ||
}; | ||
return _defineProperty({}, CONTEXT_KEY$1, context); | ||
} | ||
}, { | ||
_createClass(AccordionItem, [{ | ||
key: "render", | ||
value: function render() { | ||
return this.props.children || null; | ||
var _this$props = this.props, | ||
_this$props$uuid = _this$props.uuid, | ||
uuid = _this$props$uuid === void 0 ? this.instanceUuid : _this$props$uuid, | ||
rest = _objectWithoutProperties(_this$props, ["uuid"]); | ||
return createElement(ProviderWrapper, { | ||
uuid: uuid | ||
}, createElement("div", _extends({ | ||
"data-accordion-component": "AccordionItem" | ||
}, rest))); | ||
} | ||
}]); | ||
return Provider; | ||
return AccordionItem; | ||
}(Component); | ||
_defineProperty(Provider$1, "childContextTypes", _defineProperty({}, CONTEXT_KEY$1, function () { | ||
return null; | ||
})); | ||
_defineProperty(AccordionItem, "defaultProps", defaultProps); | ||
// eslint-disable-next-line react/no-multi-comp | ||
var Consumer$1 = | ||
/*#__PURE__*/ | ||
function (_Component2) { | ||
_inherits(Consumer, _Component2); | ||
_defineProperty(AccordionItem, "displayName", DisplayName$1.AccordionItem); | ||
function Consumer() { | ||
_classCallCheck(this, Consumer); | ||
function getClosestAccordion(el) { | ||
return el && (el.matches('[data-accordion-component="Accordion"]') ? el : getClosestAccordion(el.parentElement)); | ||
} | ||
function getSiblingButtons(item) { | ||
var parentAccordion = getClosestAccordion(item); | ||
return parentAccordion && Array.from(parentAccordion.querySelectorAll('[data-accordion-component="AccordionItemButton"]')); | ||
} | ||
function focusFirstSiblingOf(item) { | ||
var siblings = getSiblingButtons(item) || []; | ||
var first = siblings[0]; | ||
return _possibleConstructorReturn(this, _getPrototypeOf(Consumer).apply(this, arguments)); | ||
if (first) { | ||
first.focus(); | ||
} | ||
} | ||
function focusLastSiblingOf(item) { | ||
var siblings = getSiblingButtons(item) || []; | ||
var last = siblings[siblings.length - 1]; | ||
_createClass(Consumer, [{ | ||
key: "render", | ||
value: function render() { | ||
return this.props.children(this.context[CONTEXT_KEY$1]); | ||
if (last) { | ||
last.focus(); | ||
} | ||
} | ||
function focusNextSiblingOf(item) { | ||
var siblings = getSiblingButtons(item) || []; | ||
var currentIndex = siblings.indexOf(item); | ||
if (currentIndex !== -1) { | ||
var next = siblings[currentIndex + 1]; | ||
if (next) { | ||
next.focus(); | ||
} | ||
}]); | ||
} | ||
} | ||
function focusPreviousSiblingOf(item) { | ||
var siblings = getSiblingButtons(item) || []; | ||
var currentIndex = siblings.indexOf(item); | ||
return Consumer; | ||
}(Component); | ||
if (currentIndex !== -1) { | ||
var previous = siblings[currentIndex - 1]; | ||
_defineProperty(Consumer$1, "contextTypes", _defineProperty({}, CONTEXT_KEY$1, function () { | ||
return null; | ||
})); | ||
if (previous) { | ||
previous.focus(); | ||
} | ||
} | ||
} | ||
var classnames = createCommonjsModule(function (module) { | ||
/*! | ||
Copyright (c) 2016 Jed Watson. | ||
Licensed under the MIT License (MIT), see | ||
http://jedwatson.github.io/classnames | ||
*/ | ||
var keycodes = { | ||
DOWN: '40', | ||
END: '35', | ||
ENTER: '13', | ||
HOME: '36', | ||
LEFT: '37', | ||
RIGHT: '39', | ||
SPACE: '32', | ||
UP: '38' | ||
}; | ||
/* global define */ | ||
(function () { | ||
var defaultProps$1 = { | ||
className: 'accordion__button' | ||
}; | ||
var AccordionItemButton = | ||
/*#__PURE__*/ | ||
function (_React$PureComponent) { | ||
_inherits(AccordionItemButton, _React$PureComponent); | ||
var hasOwn = {}.hasOwnProperty; | ||
function AccordionItemButton() { | ||
var _getPrototypeOf2; | ||
function classNames() { | ||
var classes = []; | ||
var _this; | ||
for (var i = 0; i < arguments.length; i++) { | ||
var arg = arguments[i]; | ||
if (!arg) continue; | ||
var argType = typeof arg; | ||
_classCallCheck(this, AccordionItemButton); | ||
if (argType === 'string' || argType === 'number') { | ||
classes.push(arg); | ||
} else if (Array.isArray(arg)) { | ||
classes.push(classNames.apply(null, arg)); | ||
} else if (argType === 'object') { | ||
for (var key in arg) { | ||
if (hasOwn.call(arg, key) && arg[key]) { | ||
classes.push(key); | ||
} | ||
} | ||
} | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
return classes.join(' '); | ||
} | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(AccordionItemButton)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
if (module.exports) { | ||
module.exports = classNames; | ||
} else if (typeof undefined === 'function' && typeof undefined.amd === 'object' && undefined.amd) { | ||
// register as 'classnames', consistent with npm package name | ||
undefined('classnames', [], function () { | ||
return classNames; | ||
}); | ||
} else { | ||
window.classNames = classNames; | ||
} | ||
})(); | ||
}); | ||
_defineProperty(_assertThisInitialized(_this), "handleKeyPress", function (evt) { | ||
var keyCode = evt.which.toString(); | ||
var AccordionItem = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(AccordionItem, _Component); | ||
if (keyCode === keycodes.ENTER || keyCode === keycodes.SPACE) { | ||
evt.preventDefault(); | ||
function AccordionItem() { | ||
_classCallCheck(this, AccordionItem); | ||
_this.props.toggleExpanded(); | ||
} | ||
/* The following block is ignored from test coverage because at time | ||
* time of writing Jest/react-testing-library can not assert 'focus' | ||
* functionality. | ||
*/ | ||
// istanbul ignore next | ||
return _possibleConstructorReturn(this, _getPrototypeOf(AccordionItem).apply(this, arguments)); | ||
} | ||
_createClass(AccordionItem, [{ | ||
key: "componentDidMount", | ||
value: function componentDidMount() { | ||
var _this$props = this.props, | ||
uuid = _this$props.uuid, | ||
accordionStore = _this$props.accordionStore, | ||
disabled = _this$props.disabled; | ||
accordionStore.addItem({ | ||
uuid: uuid, | ||
expanded: this.props.expanded || false, | ||
disabled: disabled | ||
}); | ||
} | ||
}, { | ||
key: "componentWillUnmount", | ||
value: function componentWillUnmount() { | ||
this.props.accordionStore.removeItem(this.props.uuid); | ||
} // This is here so that the user can dynamically set the 'expanded' state using the 'expanded' prop. | ||
if (evt.target instanceof HTMLElement) { | ||
switch (keyCode) { | ||
case keycodes.HOME: | ||
{ | ||
evt.preventDefault(); | ||
focusFirstSiblingOf(evt.target); | ||
break; | ||
} | ||
}, { | ||
key: "componentDidUpdate", | ||
value: function componentDidUpdate(prevProps) { | ||
var _this$props2 = this.props, | ||
uuid = _this$props2.uuid, | ||
expanded = _this$props2.expanded, | ||
accordionStore = _this$props2.accordionStore; | ||
case keycodes.END: | ||
{ | ||
evt.preventDefault(); | ||
focusLastSiblingOf(evt.target); | ||
break; | ||
} | ||
if (expanded !== prevProps.expanded) { | ||
accordionStore.setExpanded(uuid, expanded); | ||
} | ||
} | ||
}, { | ||
key: "render", | ||
value: function render() { | ||
var _this$props3 = this.props, | ||
uuid = _this$props3.uuid, | ||
className = _this$props3.className, | ||
hideBodyClassName = _this$props3.hideBodyClassName, | ||
accordionStore = _this$props3.accordionStore, | ||
disabled = _this$props3.disabled, | ||
expanded = _this$props3.expanded, | ||
rest = _objectWithoutProperties(_this$props3, ["uuid", "className", "hideBodyClassName", "accordionStore", "disabled", "expanded"]); // Deliberately not using 'find' because IE compat. | ||
case keycodes.LEFT: | ||
case keycodes.UP: | ||
{ | ||
evt.preventDefault(); | ||
focusPreviousSiblingOf(evt.target); | ||
break; | ||
} | ||
case keycodes.RIGHT: | ||
case keycodes.DOWN: | ||
{ | ||
evt.preventDefault(); | ||
focusNextSiblingOf(evt.target); | ||
break; | ||
} | ||
var currentItem = accordionStore.items.filter(function (item) { | ||
return item.uuid === uuid; | ||
})[0]; | ||
default: | ||
if (!currentItem) { | ||
return null; | ||
} | ||
} | ||
}); | ||
return React.createElement("div", _extends({ | ||
className: classnames(className, _defineProperty({}, hideBodyClassName, !currentItem.expanded && hideBodyClassName)) | ||
}, rest)); | ||
return _this; | ||
} | ||
_createClass(AccordionItemButton, [{ | ||
key: "render", | ||
value: function render() { | ||
var _this$props = this.props, | ||
toggleExpanded = _this$props.toggleExpanded, | ||
rest = _objectWithoutProperties(_this$props, ["toggleExpanded"]); | ||
return createElement("div", _extends({}, rest, { | ||
// tslint:disable-next-line react-a11y-event-has-role | ||
onClick: toggleExpanded, | ||
onKeyDown: this.handleKeyPress, | ||
"data-accordion-component": "AccordionItemButton" | ||
})); | ||
} | ||
}]); | ||
return AccordionItem; | ||
}(Component); | ||
return AccordionItemButton; | ||
}(PureComponent); | ||
var nextUuid = consecutive(); | ||
function resetNextUuid() { | ||
nextUuid = consecutive(); | ||
} | ||
_defineProperty(AccordionItemButton, "defaultProps", defaultProps$1); | ||
var AccordionItemWrapper = | ||
var AccordionItemButtonWrapper = function AccordionItemButtonWrapper(props) { | ||
return createElement(Consumer$1, null, function (itemContext) { | ||
var toggleExpanded = itemContext.toggleExpanded, | ||
buttonAttributes = itemContext.buttonAttributes; | ||
return createElement(AccordionItemButton, _extends({ | ||
toggleExpanded: toggleExpanded | ||
}, props, buttonAttributes)); | ||
}); | ||
}; | ||
AccordionItemButtonWrapper.displayName = DisplayName$1.AccordionItemButton; | ||
var defaultProps$2 = { | ||
className: 'accordion__heading', | ||
'aria-level': 3 | ||
}; | ||
var SPEC_ERROR = "AccordionItemButton may contain only one child element, which must be an instance of AccordionItemButton.\n\nFrom the WAI-ARIA spec (https://www.w3.org/TR/wai-aria-practices-1.1/#accordion):\n\n\u201CThe button element is the only element inside the heading element. That is, if there are other visually persistent elements, they are not included inside the heading element.\u201D\n\n"; | ||
var AccordionItemHeading = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(AccordionItemWrapper, _Component); | ||
function (_React$PureComponent) { | ||
_inherits(AccordionItemHeading, _React$PureComponent); | ||
function AccordionItemWrapper() { | ||
function AccordionItemHeading() { | ||
var _getPrototypeOf2; | ||
@@ -822,3 +832,3 @@ | ||
_classCallCheck(this, AccordionItemWrapper); | ||
_classCallCheck(this, AccordionItemHeading); | ||
@@ -829,50 +839,69 @@ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(AccordionItemWrapper)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(AccordionItemHeading)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
_defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "id", nextUuid()); | ||
_defineProperty(_assertThisInitialized(_this), "ref", void 0); | ||
_defineProperty(_assertThisInitialized(_this), "setRef", function (ref) { | ||
_this.ref = ref; | ||
}); | ||
return _this; | ||
} | ||
_createClass(AccordionItemWrapper, [{ | ||
_createClass(AccordionItemHeading, [{ | ||
key: "componentDidUpdate", | ||
value: function componentDidUpdate() { | ||
AccordionItemHeading.VALIDATE(this.ref); | ||
} | ||
}, { | ||
key: "componentDidMount", | ||
value: function componentDidMount() { | ||
AccordionItemHeading.VALIDATE(this.ref); | ||
} | ||
}, { | ||
key: "render", | ||
value: function render() { | ||
var _this$props = this.props, | ||
accordionStore = _this$props.accordionStore, | ||
uuid = _this$props.uuid, | ||
rest = _objectWithoutProperties(_this$props, ["accordionStore", "uuid"]); | ||
return createElement("div", _extends({ | ||
"data-accordion-component": "AccordionItemHeading" | ||
}, this.props, { | ||
ref: this.setRef | ||
})); | ||
} | ||
}], [{ | ||
key: "VALIDATE", | ||
value: function VALIDATE(ref) { | ||
if (ref === undefined) { | ||
throw new Error('ref is undefined'); | ||
} | ||
var itemUuid = uuid !== undefined ? uuid : this.id; | ||
return React.createElement(Provider$1, { | ||
uuid: itemUuid | ||
}, React.createElement(AccordionItem, _extends({}, rest, { | ||
uuid: itemUuid, | ||
accordionStore: accordionStore | ||
}))); | ||
if (!(ref.childElementCount === 1 && ref.firstElementChild && ref.firstElementChild.getAttribute('data-accordion-component') === 'AccordionItemButton')) { | ||
throw new Error(SPEC_ERROR); | ||
} | ||
} | ||
}]); | ||
return AccordionItemWrapper; | ||
}(Component); | ||
return AccordionItemHeading; | ||
}(PureComponent); | ||
_defineProperty(AccordionItemWrapper, "defaultProps", { | ||
className: 'accordion__item', | ||
hideBodyClassName: '', | ||
disabled: false, | ||
expanded: false, | ||
uuid: undefined | ||
}); | ||
_defineProperty(AccordionItemHeading, "defaultProps", defaultProps$2); | ||
var AccordionItem_wrapper = compose(fromRenderProps(Consumer, function (accordionStore) { | ||
return { | ||
accordionStore: accordionStore | ||
}; | ||
}))(AccordionItemWrapper); | ||
var AccordionItemHeadingWrapper = function AccordionItemHeadingWrapper(props) { | ||
return createElement(Consumer$1, null, function (itemContext) { | ||
var headingAttributes = itemContext.headingAttributes; | ||
return createElement(AccordionItemHeading, _extends({}, props, headingAttributes)); | ||
}); | ||
}; | ||
var AccordionItemTitle = | ||
AccordionItemHeadingWrapper.displayName = DisplayName$1.AccordionItemHeading; | ||
var defaultProps$3 = { | ||
className: 'accordion__panel' | ||
}; | ||
var AccordionItemPanel = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(AccordionItemTitle, _Component); | ||
function (_React$Component) { | ||
_inherits(AccordionItemPanel, _React$Component); | ||
function AccordionItemTitle() { | ||
function AccordionItemPanel() { | ||
var _getPrototypeOf2; | ||
@@ -882,3 +911,3 @@ | ||
_classCallCheck(this, AccordionItemTitle); | ||
_classCallCheck(this, AccordionItemPanel); | ||
@@ -889,198 +918,68 @@ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(AccordionItemTitle)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(AccordionItemPanel)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
_defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleClick", function () { | ||
var _this$props = _this.props, | ||
uuid = _this$props.uuid, | ||
expanded = _this$props.expanded, | ||
setExpanded = _this$props.setExpanded; | ||
setExpanded(uuid, !expanded); | ||
_defineProperty(_assertThisInitialized(_this), "renderChildren", function (_ref) { | ||
var panelAttributes = _ref.panelAttributes; | ||
return createElement("div", _extends({ | ||
"data-accordion-component": "AccordionItemPanel" | ||
}, _this.props, panelAttributes)); | ||
}); | ||
_defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleKeyPress", function (evt) { | ||
if (evt.charCode === 13 || evt.charCode === 32) { | ||
evt.preventDefault(); | ||
_this.handleClick(); | ||
} | ||
}); | ||
return _this; | ||
} | ||
_createClass(AccordionItemTitle, [{ | ||
_createClass(AccordionItemPanel, [{ | ||
key: "render", | ||
value: function render() { | ||
var _this$props2 = this.props, | ||
className = _this$props2.className, | ||
hideBodyClassName = _this$props2.hideBodyClassName, | ||
item = _this$props2.item, | ||
accordion = _this$props2.accordion, | ||
setExpanded = _this$props2.setExpanded, | ||
expanded = _this$props2.expanded, | ||
uuid = _this$props2.uuid, | ||
disabled = _this$props2.disabled, | ||
rest = _objectWithoutProperties(_this$props2, ["className", "hideBodyClassName", "item", "accordion", "setExpanded", "expanded", "uuid", "disabled"]); | ||
var id = "accordion__title-".concat(uuid); | ||
var ariaControls = "accordion__body-".concat(uuid); | ||
var role = accordion ? 'tab' : 'button'; | ||
var titleClassName = classnames(className, _defineProperty({}, hideBodyClassName, hideBodyClassName && !expanded)); | ||
if (role === 'tab') { | ||
return React.createElement("div", _extends({ | ||
id: id, | ||
"aria-selected": expanded, | ||
"aria-controls": ariaControls, | ||
className: titleClassName, | ||
onClick: disabled ? undefined : this.handleClick, | ||
role: role, | ||
tabIndex: "0" // eslint-disable-line jsx-a11y/no-noninteractive-tabindex | ||
, | ||
onKeyPress: this.handleKeyPress, | ||
disabled: disabled | ||
}, rest)); | ||
} | ||
return React.createElement("div", _extends({ | ||
id: id, | ||
"aria-expanded": expanded, | ||
"aria-controls": ariaControls, | ||
className: titleClassName, | ||
onClick: disabled ? undefined : this.handleClick, | ||
role: role, | ||
tabIndex: "0" // eslint-disable-line jsx-a11y/no-noninteractive-tabindex | ||
, | ||
onKeyPress: this.handleKeyPress, | ||
disabled: disabled | ||
}, rest)); | ||
return createElement(Consumer$1, null, this.renderChildren); | ||
} | ||
}]); | ||
return AccordionItemTitle; | ||
return AccordionItemPanel; | ||
}(Component); | ||
_defineProperty(AccordionItemTitle, "accordionElementName", 'AccordionItemTitle'); | ||
_defineProperty(AccordionItemPanel, "defaultProps", defaultProps$3); | ||
// eslint-disable-next-line react/prefer-stateless-function | ||
var AccordionItemTitleWrapper = | ||
_defineProperty(AccordionItemPanel, "displayName", DisplayName$1.AccordionItemPanel); | ||
var AccordionItemState = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(AccordionItemTitleWrapper, _Component); | ||
function (_React$Component) { | ||
_inherits(AccordionItemState, _React$Component); | ||
function AccordionItemTitleWrapper() { | ||
_classCallCheck(this, AccordionItemTitleWrapper); | ||
function AccordionItemState() { | ||
var _getPrototypeOf2; | ||
return _possibleConstructorReturn(this, _getPrototypeOf(AccordionItemTitleWrapper).apply(this, arguments)); | ||
} | ||
var _this; | ||
_createClass(AccordionItemTitleWrapper, [{ | ||
key: "render", | ||
value: function render() { | ||
var _this$props = this.props, | ||
itemStore = _this$props.itemStore, | ||
accordionStore = _this$props.accordionStore, | ||
rest = _objectWithoutProperties(_this$props, ["itemStore", "accordionStore"]); | ||
_classCallCheck(this, AccordionItemState); | ||
var uuid = itemStore.uuid; | ||
var items = accordionStore.items, | ||
accordion = accordionStore.accordion; | ||
var item = items.filter(function (stateItem) { | ||
return stateItem.uuid === uuid; | ||
})[0]; | ||
return React.createElement(AccordionItemTitle, _extends({}, rest, item, { | ||
setExpanded: accordionStore.setExpanded, | ||
accordion: accordion | ||
})); | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
}]); | ||
return AccordionItemTitleWrapper; | ||
}(Component); | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(AccordionItemState)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
_defineProperty(AccordionItemTitleWrapper, "defaultProps", { | ||
className: 'accordion__title', | ||
hideBodyClassName: '' | ||
}); | ||
_defineProperty(_assertThisInitialized(_this), "renderChildren", function (itemContext) { | ||
var expanded = itemContext.expanded, | ||
disabled = itemContext.disabled; | ||
return createElement(Fragment, null, _this.props.children({ | ||
expanded: expanded, | ||
disabled: disabled | ||
})); | ||
}); | ||
var AccordionItemTitle_wrapper = compose(fromRenderProps(Consumer, function (accordionStore) { | ||
return { | ||
accordionStore: accordionStore | ||
}; | ||
}), fromRenderProps(Consumer$1, function (itemStore) { | ||
return { | ||
itemStore: itemStore | ||
}; | ||
}))(AccordionItemTitleWrapper); | ||
var AccordionItemBody = function AccordionItemBody(props) { | ||
var className = props.className, | ||
hideBodyClassName = props.hideBodyClassName, | ||
uuid = props.uuid, | ||
expanded = props.expanded, | ||
disabled = props.disabled, | ||
accordion = props.accordion, | ||
rest = _objectWithoutProperties(props, ["className", "hideBodyClassName", "uuid", "expanded", "disabled", "accordion"]); | ||
return React.createElement("div", _extends({ | ||
id: "accordion__body-".concat(uuid), | ||
className: classnames(className, _defineProperty({}, hideBodyClassName, !expanded)), | ||
"aria-hidden": !expanded, | ||
"aria-labelledby": "accordion__title-".concat(uuid), | ||
role: accordion ? 'tabpanel' : null | ||
}, rest)); | ||
}; | ||
// eslint-disable-next-line react/prefer-stateless-function | ||
var AccordionItemBodyWrapper = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(AccordionItemBodyWrapper, _Component); | ||
function AccordionItemBodyWrapper() { | ||
_classCallCheck(this, AccordionItemBodyWrapper); | ||
return _possibleConstructorReturn(this, _getPrototypeOf(AccordionItemBodyWrapper).apply(this, arguments)); | ||
return _this; | ||
} | ||
_createClass(AccordionItemBodyWrapper, [{ | ||
_createClass(AccordionItemState, [{ | ||
key: "render", | ||
value: function render() { | ||
var _this$props = this.props, | ||
itemStore = _this$props.itemStore, | ||
accordionStore = _this$props.accordionStore, | ||
rest = _objectWithoutProperties(_this$props, ["itemStore", "accordionStore"]); | ||
var uuid = itemStore.uuid; | ||
var items = accordionStore.items, | ||
accordion = accordionStore.accordion; | ||
var item = items.filter(function (stateItem) { | ||
return stateItem.uuid === uuid; | ||
})[0]; | ||
return item ? React.createElement(AccordionItemBody, _extends({}, rest, item, { | ||
accordion: accordion | ||
})) : null; | ||
return createElement(Consumer$1, null, this.renderChildren); | ||
} | ||
}]); | ||
return AccordionItemBodyWrapper; | ||
return AccordionItemState; | ||
}(Component); | ||
_defineProperty(AccordionItemBodyWrapper, "defaultProps", { | ||
className: 'accordion__body', | ||
hideBodyClassName: 'accordion__body--hidden' | ||
}); | ||
var AccordionItemBody_wrapper = compose(fromRenderProps(Consumer, function (accordionStore) { | ||
return { | ||
accordionStore: accordionStore | ||
}; | ||
}), fromRenderProps(Consumer$1, function (itemStore) { | ||
return { | ||
itemStore: itemStore | ||
}; | ||
}))(AccordionItemBodyWrapper); | ||
// eslint-disable-next-line | ||
export { AccordionWrapper as Accordion, AccordionItem_wrapper as AccordionItem, AccordionItemTitle_wrapper as AccordionItemTitle, AccordionItemBody_wrapper as AccordionItemBody, resetNextUuid }; | ||
export { Accordion, AccordionItem, AccordionItemButtonWrapper as AccordionItemButton, AccordionItemHeadingWrapper as AccordionItemHeading, AccordionItemPanel, AccordionItemState, resetNextUuid }; |
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) : | ||
typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) : | ||
(factory((global.reactAccessibleAccordion = {}),global.React)); | ||
}(this, (function (exports,React) { 'use strict'; | ||
(global = global || self, factory(global.reactAccessibleAccordion = {}, global.React)); | ||
}(this, function (exports, React) { 'use strict'; | ||
var React__default = 'default' in React ? React['default'] : React; | ||
function _classCallCheck(instance, Constructor) { | ||
@@ -186,8 +184,124 @@ if (!(instance instanceof Constructor)) { | ||
// Arbitrary, but ought to be unique to avoid context namespace clashes. | ||
var CONTEXT_KEY = 'react-accessible-accordion@AccordionContainer'; | ||
var DisplayName; | ||
(function (DisplayName) { | ||
DisplayName["Accordion"] = "Accordion"; | ||
DisplayName["AccordionItem"] = "AccordionItem"; | ||
DisplayName["AccordionItemButton"] = "AccordionItemButton"; | ||
DisplayName["AccordionItemHeading"] = "AccordionItemHeading"; | ||
DisplayName["AccordionItemPanel"] = "AccordionItemPanel"; | ||
})(DisplayName || (DisplayName = {})); | ||
var DisplayName$1 = DisplayName; | ||
var AccordionStore = function AccordionStore(_ref) { | ||
var _this = this; | ||
var _ref$expanded = _ref.expanded, | ||
_expanded = _ref$expanded === void 0 ? [] : _ref$expanded, | ||
_ref$allowMultipleExp = _ref.allowMultipleExpanded, | ||
allowMultipleExpanded = _ref$allowMultipleExp === void 0 ? false : _ref$allowMultipleExp, | ||
_ref$allowZeroExpande = _ref.allowZeroExpanded, | ||
allowZeroExpanded = _ref$allowZeroExpande === void 0 ? false : _ref$allowZeroExpande; | ||
_classCallCheck(this, AccordionStore); | ||
_defineProperty(this, "expanded", void 0); | ||
_defineProperty(this, "allowMultipleExpanded", void 0); | ||
_defineProperty(this, "allowZeroExpanded", void 0); | ||
_defineProperty(this, "toggleExpanded", function (uuid) { | ||
if (_this.isItemDisabled(uuid)) { | ||
return _this; | ||
} | ||
var isExpanded = _this.isItemExpanded(uuid); | ||
if (!isExpanded) { | ||
return _this.augment({ | ||
expanded: _this.allowMultipleExpanded ? [].concat(_toConsumableArray(_this.expanded), [uuid]) : [uuid] | ||
}); | ||
} else { | ||
return _this.augment({ | ||
expanded: _this.expanded.filter(function (expandedUuid) { | ||
return expandedUuid !== uuid; | ||
}) | ||
}); | ||
} | ||
}); | ||
_defineProperty(this, "isItemDisabled", function (uuid) { | ||
var isExpanded = _this.isItemExpanded(uuid); | ||
var isOnlyOneExpanded = _this.expanded.length === 1; | ||
return Boolean(isExpanded && !_this.allowZeroExpanded && isOnlyOneExpanded); | ||
}); | ||
_defineProperty(this, "isItemExpanded", function (uuid) { | ||
return _this.expanded.findIndex(function (expandedUuid) { | ||
return expandedUuid === uuid; | ||
}) !== -1; | ||
}); | ||
_defineProperty(this, "getPanelAttributes", function (uuid) { | ||
var expanded = _this.isItemExpanded(uuid); | ||
return { | ||
role: _this.allowMultipleExpanded ? undefined : 'region', | ||
'aria-hidden': _this.allowMultipleExpanded ? !expanded : undefined, | ||
'aria-labelledby': _this.getButtonId(uuid), | ||
id: _this.getPanelId(uuid), | ||
hidden: expanded ? undefined : true | ||
}; | ||
}); | ||
_defineProperty(this, "getHeadingAttributes", function (uuid) { | ||
return { | ||
role: 'heading' | ||
}; | ||
}); | ||
_defineProperty(this, "getButtonAttributes", function (uuid) { | ||
var expanded = _this.isItemExpanded(uuid); | ||
var disabled = _this.isItemDisabled(uuid); | ||
return { | ||
id: _this.getButtonId(uuid), | ||
'aria-disabled': disabled, | ||
'aria-expanded': expanded, | ||
'aria-controls': _this.getPanelId(uuid), | ||
role: 'button', | ||
tabIndex: 0 | ||
}; | ||
}); | ||
_defineProperty(this, "getPanelId", function (uuid) { | ||
return "accordion__panel-".concat(uuid); | ||
}); | ||
_defineProperty(this, "getButtonId", function (uuid) { | ||
return "accordion__heading-".concat(uuid); | ||
}); | ||
_defineProperty(this, "augment", function (args) { | ||
return new AccordionStore(_objectSpread({ | ||
expanded: _this.expanded, | ||
allowMultipleExpanded: _this.allowMultipleExpanded, | ||
allowZeroExpanded: _this.allowZeroExpanded | ||
}, args)); | ||
}); | ||
this.expanded = _expanded; | ||
this.allowMultipleExpanded = allowMultipleExpanded; | ||
this.allowZeroExpanded = allowZeroExpanded; | ||
}; | ||
var Context = React.createContext(null); | ||
var Provider = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(Provider, _Component); | ||
function (_React$PureComponent) { | ||
_inherits(Provider, _React$PureComponent); | ||
@@ -207,76 +321,38 @@ function Provider() { | ||
_defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "state", { | ||
items: _this.props.items || [] | ||
}); | ||
_defineProperty(_assertThisInitialized(_this), "state", new AccordionStore({ | ||
expanded: _this.props.preExpanded, | ||
allowMultipleExpanded: _this.props.allowMultipleExpanded, | ||
allowZeroExpanded: _this.props.allowZeroExpanded | ||
})); | ||
_defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "addItem", function (newItem) { | ||
// Need to use callback style otherwise race-conditions are created by concurrent registrations. | ||
_defineProperty(_assertThisInitialized(_this), "toggleExpanded", function (key) { | ||
_this.setState(function (state) { | ||
var items; | ||
if (state.items.some(function (item) { | ||
return item.uuid === newItem.uuid; | ||
})) { | ||
// eslint-disable-next-line no-console | ||
console.error("AccordionItem error: One item already has the uuid \"".concat(newItem.uuid, "\". Uuid property must be unique. See: https://github.com/springload/react-accessible-accordion#accordionitem")); | ||
return state.toggleExpanded(key); | ||
}, function () { | ||
if (_this.props.onChange) { | ||
_this.props.onChange(_this.state.expanded); | ||
} | ||
if (_this.props.accordion && newItem.expanded) { | ||
// If this is a true accordion and the new item is expanded, then the others must be closed. | ||
items = _toConsumableArray(state.items.map(function (item) { | ||
return _objectSpread({}, item, { | ||
expanded: false | ||
}); | ||
})).concat([newItem]); | ||
} else { | ||
items = _toConsumableArray(state.items).concat([newItem]); | ||
} | ||
return { | ||
items: items | ||
}; | ||
}); | ||
}); | ||
_defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "removeItem", function (key) { | ||
return _this.setState(function (state) { | ||
return { | ||
items: state.items.filter(function (item) { | ||
return item.uuid !== key; | ||
}) | ||
}; | ||
}); | ||
_defineProperty(_assertThisInitialized(_this), "isItemDisabled", function (key) { | ||
return _this.state.isItemDisabled(key); | ||
}); | ||
_defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "setExpanded", function (key, expanded) { | ||
return _this.setState(function (state) { | ||
return { | ||
items: state.items.map(function (item) { | ||
if (item.uuid === key) { | ||
return _objectSpread({}, item, { | ||
expanded: expanded | ||
}); | ||
} | ||
_defineProperty(_assertThisInitialized(_this), "isItemExpanded", function (key) { | ||
return _this.state.isItemExpanded(key); | ||
}); | ||
if (_this.props.accordion && expanded) { | ||
// If this is an accordion, we might need to collapse the other expanded item. | ||
return _objectSpread({}, item, { | ||
expanded: false | ||
}); | ||
} | ||
_defineProperty(_assertThisInitialized(_this), "getPanelAttributes", function (key) { | ||
return _this.state.getPanelAttributes(key); | ||
}); | ||
return item; | ||
}) | ||
}; | ||
}, function () { | ||
if (_this.props.onChange) { | ||
_this.props.onChange(_this.props.accordion ? key : _this.state.items.filter(function (item) { | ||
return item.expanded; | ||
}).map(function (item) { | ||
return item.uuid; | ||
})); | ||
} | ||
}); | ||
_defineProperty(_assertThisInitialized(_this), "getHeadingAttributes", function (key) { | ||
return _this.state.getHeadingAttributes(key); | ||
}); | ||
_defineProperty(_assertThisInitialized(_this), "getButtonAttributes", function (key) { | ||
return _this.state.getButtonAttributes(key); | ||
}); | ||
return _this; | ||
@@ -286,17 +362,19 @@ } | ||
_createClass(Provider, [{ | ||
key: "getChildContext", | ||
value: function getChildContext() { | ||
var context = { | ||
items: this.state.items, | ||
accordion: !!this.props.accordion, | ||
addItem: this.addItem, | ||
removeItem: this.removeItem, | ||
setExpanded: this.setExpanded | ||
}; | ||
return _defineProperty({}, CONTEXT_KEY, context); | ||
} | ||
}, { | ||
key: "render", | ||
value: function render() { | ||
return this.props.children || null; | ||
var _this$state = this.state, | ||
allowZeroExpanded = _this$state.allowZeroExpanded, | ||
allowMultipleExpanded = _this$state.allowMultipleExpanded; | ||
return React.createElement(Context.Provider, { | ||
value: { | ||
allowMultipleExpanded: allowMultipleExpanded, | ||
allowZeroExpanded: allowZeroExpanded, | ||
toggleExpanded: this.toggleExpanded, | ||
isItemDisabled: this.isItemDisabled, | ||
isItemExpanded: this.isItemExpanded, | ||
getPanelAttributes: this.getPanelAttributes, | ||
getHeadingAttributes: this.getHeadingAttributes, | ||
getButtonAttributes: this.getButtonAttributes | ||
} | ||
}, this.props.children || null); | ||
} | ||
@@ -306,17 +384,32 @@ }]); | ||
return Provider; | ||
}(React.Component); // eslint-disable-next-line react/no-multi-comp | ||
}(React.PureComponent); | ||
_defineProperty(Provider, "childContextTypes", _defineProperty({}, CONTEXT_KEY, function () { | ||
return null; | ||
})); | ||
_defineProperty(Provider, "defaultProps", { | ||
allowMultipleExpanded: false, | ||
allowZeroExpanded: false | ||
}); | ||
var Consumer = | ||
/*#__PURE__*/ | ||
function (_Component2) { | ||
_inherits(Consumer, _Component2); | ||
function (_React$PureComponent2) { | ||
_inherits(Consumer, _React$PureComponent2); | ||
function Consumer() { | ||
var _getPrototypeOf3; | ||
var _this2; | ||
_classCallCheck(this, Consumer); | ||
return _possibleConstructorReturn(this, _getPrototypeOf(Consumer).apply(this, arguments)); | ||
for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { | ||
args[_key3] = arguments[_key3]; | ||
} | ||
_this2 = _possibleConstructorReturn(this, (_getPrototypeOf3 = _getPrototypeOf(Consumer)).call.apply(_getPrototypeOf3, [this].concat(args))); | ||
_defineProperty(_assertThisInitialized(_this2), "renderChildren", function (container) { | ||
return container ? _this2.props.children(container) : null; | ||
}); | ||
return _this2; | ||
} | ||
@@ -327,3 +420,3 @@ | ||
value: function render() { | ||
return this.props.children(this.context[CONTEXT_KEY]); | ||
return React.createElement(Context.Consumer, null, this.renderChildren); | ||
} | ||
@@ -333,36 +426,10 @@ }]); | ||
return Consumer; | ||
}(React.Component); | ||
}(React.PureComponent); | ||
_defineProperty(Consumer, "contextTypes", _defineProperty({}, CONTEXT_KEY, function () { | ||
return null; | ||
})); | ||
var accordionDefaultProps = { | ||
accordion: true | ||
}; | ||
var Accordion = function Accordion(_ref) { | ||
var accordion = _ref.accordion, | ||
rest = _objectWithoutProperties(_ref, ["accordion"]); | ||
return React__default.createElement("div", _extends({ | ||
role: accordion ? 'tablist' : null | ||
}, rest)); | ||
}; | ||
Accordion.defaultProps = accordionDefaultProps; | ||
var defaultProps = { | ||
accordion: true, | ||
onChange: function onChange() {}, | ||
className: 'accordion', | ||
children: null | ||
}; | ||
var AccordionWrapper = | ||
var Accordion = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(AccordionWrapper, _Component); | ||
function (_React$Component) { | ||
_inherits(Accordion, _React$Component); | ||
function AccordionWrapper() { | ||
function Accordion() { | ||
var _getPrototypeOf2; | ||
@@ -372,3 +439,3 @@ | ||
_classCallCheck(this, AccordionWrapper); | ||
_classCallCheck(this, Accordion); | ||
@@ -379,12 +446,14 @@ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(AccordionWrapper)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(Accordion)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
_defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "renderAccordion", function (accordionStore) { | ||
_defineProperty(_assertThisInitialized(_this), "renderAccordion", function (accordionContext) { | ||
var _this$props = _this.props, | ||
accordion = _this$props.accordion, | ||
preExpanded = _this$props.preExpanded, | ||
allowMultipleExpanded = _this$props.allowMultipleExpanded, | ||
allowZeroExpanded = _this$props.allowZeroExpanded, | ||
onChange = _this$props.onChange, | ||
rest = _objectWithoutProperties(_this$props, ["accordion", "onChange"]); | ||
rest = _objectWithoutProperties(_this$props, ["preExpanded", "allowMultipleExpanded", "allowZeroExpanded", "onChange"]); | ||
return React__default.createElement(Accordion, _extends({ | ||
accordion: accordionStore.accordion | ||
return React.createElement("div", _extends({ | ||
"data-accordion-component": "Accordion" | ||
}, rest)); | ||
@@ -396,429 +465,368 @@ }); | ||
_createClass(AccordionWrapper, [{ | ||
_createClass(Accordion, [{ | ||
key: "render", | ||
value: function render() { | ||
return React__default.createElement(Provider, { | ||
accordion: this.props.accordion, | ||
return React.createElement(Provider, { | ||
preExpanded: this.props.preExpanded, | ||
allowMultipleExpanded: this.props.allowMultipleExpanded, | ||
allowZeroExpanded: this.props.allowZeroExpanded, | ||
onChange: this.props.onChange | ||
}, React__default.createElement(Consumer, null, this.renderAccordion)); | ||
}, React.createElement(Consumer, null, this.renderAccordion)); | ||
} | ||
}]); | ||
return AccordionWrapper; | ||
return Accordion; | ||
}(React.Component); | ||
_defineProperty(AccordionWrapper, "defaultProps", defaultProps); | ||
_defineProperty(Accordion, "defaultProps", { | ||
allowMultipleExpanded: undefined, | ||
allowZeroExpanded: undefined, | ||
onChange: undefined, | ||
className: 'accordion', | ||
children: undefined | ||
}); | ||
function _extends$1() { | ||
_extends$1 = Object.assign || function (target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i]; | ||
_defineProperty(Accordion, "displayName", DisplayName$1.Accordion); | ||
for (var key in source) { | ||
if (Object.prototype.hasOwnProperty.call(source, key)) { | ||
target[key] = source[key]; | ||
} | ||
} | ||
} | ||
return target; | ||
}; | ||
return _extends$1.apply(this, arguments); | ||
var DEFAULT = 0; | ||
var counter = DEFAULT; | ||
function nextUuid() { | ||
var current = counter; | ||
counter = counter + 1; | ||
return current; | ||
} | ||
/** | ||
* Copyright (c) 2013-present, Facebook, Inc. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @typechecks | ||
* | ||
*/ | ||
function _inheritsLoose$1(subClass, superClass) { | ||
subClass.prototype = Object.create(superClass.prototype); | ||
subClass.prototype.constructor = subClass; | ||
subClass.__proto__ = superClass; | ||
function resetNextUuid() { | ||
counter = DEFAULT; | ||
} | ||
/** | ||
* Copyright (c) 2013-present, Facebook, Inc. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
var Context$1 = React.createContext(null); | ||
function unwrapExports (x) { | ||
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; | ||
} | ||
var Provider$1 = | ||
/*#__PURE__*/ | ||
function (_React$Component) { | ||
_inherits(Provider, _React$Component); | ||
function createCommonjsModule(fn, module) { | ||
return module = { exports: {} }, fn(module, module.exports), module.exports; | ||
} | ||
function Provider() { | ||
var _getPrototypeOf2; | ||
var lib = createCommonjsModule(function (module, exports) { | ||
var _this; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
_classCallCheck(this, Provider); | ||
var createChangeEmitter = exports.createChangeEmitter = function createChangeEmitter() { | ||
var currentListeners = []; | ||
var nextListeners = currentListeners; | ||
function ensureCanMutateNextListeners() { | ||
if (nextListeners === currentListeners) { | ||
nextListeners = currentListeners.slice(); | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
} | ||
function listen(listener) { | ||
if (typeof listener !== 'function') { | ||
throw new Error('Expected listener to be a function.'); | ||
} | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(Provider)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
var isSubscribed = true; | ||
ensureCanMutateNextListeners(); | ||
nextListeners.push(listener); | ||
return function () { | ||
if (!isSubscribed) { | ||
return; | ||
} | ||
_defineProperty(_assertThisInitialized(_this), "toggleExpanded", function () { | ||
_this.props.accordionContext.toggleExpanded(_this.props.uuid); | ||
}); | ||
isSubscribed = false; | ||
ensureCanMutateNextListeners(); | ||
var index = nextListeners.indexOf(listener); | ||
nextListeners.splice(index, 1); | ||
}; | ||
} | ||
_defineProperty(_assertThisInitialized(_this), "renderChildren", function (accordionContext) { | ||
var uuid = _this.props.uuid; | ||
var expanded = accordionContext.isItemExpanded(uuid); | ||
var disabled = accordionContext.isItemDisabled(uuid); | ||
var panelAttributes = accordionContext.getPanelAttributes(uuid); | ||
var headingAttributes = accordionContext.getHeadingAttributes(uuid); | ||
var buttonAttributes = accordionContext.getButtonAttributes(uuid); | ||
return React.createElement(Context$1.Provider, { | ||
value: { | ||
uuid: uuid, | ||
expanded: expanded, | ||
disabled: disabled, | ||
toggleExpanded: _this.toggleExpanded, | ||
panelAttributes: panelAttributes, | ||
headingAttributes: headingAttributes, | ||
buttonAttributes: buttonAttributes | ||
}, | ||
children: _this.props.children | ||
}); | ||
}); | ||
function emit() { | ||
currentListeners = nextListeners; | ||
var listeners = currentListeners; | ||
for (var i = 0; i < listeners.length; i++) { | ||
listeners[i].apply(listeners, arguments); | ||
} | ||
return _this; | ||
} | ||
return { | ||
listen: listen, | ||
emit: emit | ||
}; | ||
}; | ||
}); | ||
unwrapExports(lib); | ||
var lib_1 = lib.createChangeEmitter; | ||
function symbolObservablePonyfill(root) { | ||
var result; | ||
var Symbol = root.Symbol; | ||
if (typeof Symbol === 'function') { | ||
if (Symbol.observable) { | ||
result = Symbol.observable; | ||
} else { | ||
result = Symbol('observable'); | ||
Symbol.observable = result; | ||
_createClass(Provider, [{ | ||
key: "render", | ||
value: function render() { | ||
return React.createElement(Consumer, null, this.renderChildren); | ||
} | ||
} else { | ||
result = '@@observable'; | ||
} | ||
}]); | ||
return result; | ||
} | ||
return Provider; | ||
}(React.Component); | ||
/* global window */ | ||
var root; | ||
var ProviderWrapper = function ProviderWrapper(props) { | ||
return React.createElement(Consumer, null, function (accordionContext) { | ||
return React.createElement(Provider$1, _extends({}, props, { | ||
accordionContext: accordionContext | ||
})); | ||
}); | ||
}; | ||
var Consumer$1 = | ||
/*#__PURE__*/ | ||
function (_React$PureComponent) { | ||
_inherits(Consumer, _React$PureComponent); | ||
if (typeof self !== 'undefined') { | ||
root = self; | ||
} else if (typeof window !== 'undefined') { | ||
root = window; | ||
} else if (typeof global !== 'undefined') { | ||
root = global; | ||
} else if (typeof module !== 'undefined') { | ||
root = module; | ||
} else { | ||
root = Function('return this')(); | ||
} | ||
function Consumer() { | ||
var _getPrototypeOf3; | ||
var result = symbolObservablePonyfill(root); | ||
var _this2; | ||
var Nothing = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inheritsLoose$1(Nothing, _Component); | ||
_classCallCheck(this, Consumer); | ||
function Nothing() { | ||
return _Component.apply(this, arguments) || this; | ||
} | ||
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | ||
args[_key2] = arguments[_key2]; | ||
} | ||
var _proto = Nothing.prototype; | ||
_this2 = _possibleConstructorReturn(this, (_getPrototypeOf3 = _getPrototypeOf(Consumer)).call.apply(_getPrototypeOf3, [this].concat(args))); | ||
_proto.render = function render() { | ||
return null; | ||
}; | ||
_defineProperty(_assertThisInitialized(_this2), "renderChildren", function (container) { | ||
return container ? _this2.props.children(container) : null; | ||
}); | ||
return Nothing; | ||
}(React.Component); | ||
var fromRenderProps = function fromRenderProps(RenderPropsComponent, propsMapper, renderPropName) { | ||
if (renderPropName === void 0) { | ||
renderPropName = 'children'; | ||
return _this2; | ||
} | ||
return function (BaseComponent) { | ||
var baseFactory = React__default.createFactory(BaseComponent); | ||
var renderPropsFactory = React__default.createFactory(RenderPropsComponent); | ||
_createClass(Consumer, [{ | ||
key: "render", | ||
value: function render() { | ||
return React.createElement(Context$1.Consumer, null, this.renderChildren); | ||
} | ||
}]); | ||
var FromRenderProps = function FromRenderProps(ownerProps) { | ||
var _renderPropsFactory; | ||
return Consumer; | ||
}(React.PureComponent); | ||
return renderPropsFactory((_renderPropsFactory = {}, _renderPropsFactory[renderPropName] = function () { | ||
return baseFactory(_extends({}, ownerProps, propsMapper.apply(void 0, arguments))); | ||
}, _renderPropsFactory)); | ||
}; | ||
return FromRenderProps; | ||
}; | ||
var defaultProps = { | ||
className: 'accordion__item' | ||
}; | ||
var compose = function compose() { | ||
for (var _len = arguments.length, funcs = new Array(_len), _key = 0; _key < _len; _key++) { | ||
funcs[_key] = arguments[_key]; | ||
} | ||
var AccordionItem = | ||
/*#__PURE__*/ | ||
function (_React$Component) { | ||
_inherits(AccordionItem, _React$Component); | ||
return funcs.reduce(function (a, b) { | ||
return function () { | ||
return a(b.apply(void 0, arguments)); | ||
}; | ||
}, function (arg) { | ||
return arg; | ||
}); | ||
}; | ||
function AccordionItem() { | ||
var _getPrototypeOf2; | ||
/*! | ||
* consecutive | ||
* Get consecutive numbers | ||
* Copyright(c) 2017 ivanoff .$ curl -A cv ivanoff.org.ua | ||
* MIT Licensed | ||
*/ | ||
var _this; | ||
var consecutive = function (begin, base, inc) { | ||
var number = begin || 0; | ||
if (typeof base !== 'number') base = 10; | ||
if (typeof inc !== 'number') inc = 1; | ||
return function () { | ||
var res; | ||
_classCallCheck(this, AccordionItem); | ||
if (typeof base === 'undefined' || base === 10) { | ||
res = number; | ||
number += inc; | ||
} else { | ||
res = number.toString(); | ||
number = (parseInt(number, base) + inc).toString(base); | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
return res; | ||
}; | ||
}; | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(AccordionItem)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
// Arbitrary, but ought to be unique to avoid context namespace clashes. | ||
var CONTEXT_KEY$1 = 'react-accessible-accordion@ItemContainer'; | ||
var Provider$1 = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(Provider, _Component); | ||
_defineProperty(_assertThisInitialized(_this), "instanceUuid", nextUuid()); | ||
function Provider() { | ||
_classCallCheck(this, Provider); | ||
return _possibleConstructorReturn(this, _getPrototypeOf(Provider).apply(this, arguments)); | ||
return _this; | ||
} | ||
_createClass(Provider, [{ | ||
key: "getChildContext", | ||
value: function getChildContext() { | ||
var uuid = this.props.uuid; | ||
var context = { | ||
uuid: uuid | ||
}; | ||
return _defineProperty({}, CONTEXT_KEY$1, context); | ||
} | ||
}, { | ||
_createClass(AccordionItem, [{ | ||
key: "render", | ||
value: function render() { | ||
return this.props.children || null; | ||
var _this$props = this.props, | ||
_this$props$uuid = _this$props.uuid, | ||
uuid = _this$props$uuid === void 0 ? this.instanceUuid : _this$props$uuid, | ||
rest = _objectWithoutProperties(_this$props, ["uuid"]); | ||
return React.createElement(ProviderWrapper, { | ||
uuid: uuid | ||
}, React.createElement("div", _extends({ | ||
"data-accordion-component": "AccordionItem" | ||
}, rest))); | ||
} | ||
}]); | ||
return Provider; | ||
return AccordionItem; | ||
}(React.Component); | ||
_defineProperty(Provider$1, "childContextTypes", _defineProperty({}, CONTEXT_KEY$1, function () { | ||
return null; | ||
})); | ||
_defineProperty(AccordionItem, "defaultProps", defaultProps); | ||
// eslint-disable-next-line react/no-multi-comp | ||
var Consumer$1 = | ||
/*#__PURE__*/ | ||
function (_Component2) { | ||
_inherits(Consumer, _Component2); | ||
_defineProperty(AccordionItem, "displayName", DisplayName$1.AccordionItem); | ||
function Consumer() { | ||
_classCallCheck(this, Consumer); | ||
function getClosestAccordion(el) { | ||
return el && (el.matches('[data-accordion-component="Accordion"]') ? el : getClosestAccordion(el.parentElement)); | ||
} | ||
function getSiblingButtons(item) { | ||
var parentAccordion = getClosestAccordion(item); | ||
return parentAccordion && Array.from(parentAccordion.querySelectorAll('[data-accordion-component="AccordionItemButton"]')); | ||
} | ||
function focusFirstSiblingOf(item) { | ||
var siblings = getSiblingButtons(item) || []; | ||
var first = siblings[0]; | ||
return _possibleConstructorReturn(this, _getPrototypeOf(Consumer).apply(this, arguments)); | ||
if (first) { | ||
first.focus(); | ||
} | ||
} | ||
function focusLastSiblingOf(item) { | ||
var siblings = getSiblingButtons(item) || []; | ||
var last = siblings[siblings.length - 1]; | ||
_createClass(Consumer, [{ | ||
key: "render", | ||
value: function render() { | ||
return this.props.children(this.context[CONTEXT_KEY$1]); | ||
if (last) { | ||
last.focus(); | ||
} | ||
} | ||
function focusNextSiblingOf(item) { | ||
var siblings = getSiblingButtons(item) || []; | ||
var currentIndex = siblings.indexOf(item); | ||
if (currentIndex !== -1) { | ||
var next = siblings[currentIndex + 1]; | ||
if (next) { | ||
next.focus(); | ||
} | ||
}]); | ||
} | ||
} | ||
function focusPreviousSiblingOf(item) { | ||
var siblings = getSiblingButtons(item) || []; | ||
var currentIndex = siblings.indexOf(item); | ||
return Consumer; | ||
}(React.Component); | ||
if (currentIndex !== -1) { | ||
var previous = siblings[currentIndex - 1]; | ||
_defineProperty(Consumer$1, "contextTypes", _defineProperty({}, CONTEXT_KEY$1, function () { | ||
return null; | ||
})); | ||
if (previous) { | ||
previous.focus(); | ||
} | ||
} | ||
} | ||
var classnames = createCommonjsModule(function (module) { | ||
/*! | ||
Copyright (c) 2016 Jed Watson. | ||
Licensed under the MIT License (MIT), see | ||
http://jedwatson.github.io/classnames | ||
*/ | ||
var keycodes = { | ||
DOWN: '40', | ||
END: '35', | ||
ENTER: '13', | ||
HOME: '36', | ||
LEFT: '37', | ||
RIGHT: '39', | ||
SPACE: '32', | ||
UP: '38' | ||
}; | ||
/* global define */ | ||
(function () { | ||
var defaultProps$1 = { | ||
className: 'accordion__button' | ||
}; | ||
var AccordionItemButton = | ||
/*#__PURE__*/ | ||
function (_React$PureComponent) { | ||
_inherits(AccordionItemButton, _React$PureComponent); | ||
var hasOwn = {}.hasOwnProperty; | ||
function AccordionItemButton() { | ||
var _getPrototypeOf2; | ||
function classNames() { | ||
var classes = []; | ||
var _this; | ||
for (var i = 0; i < arguments.length; i++) { | ||
var arg = arguments[i]; | ||
if (!arg) continue; | ||
var argType = typeof arg; | ||
_classCallCheck(this, AccordionItemButton); | ||
if (argType === 'string' || argType === 'number') { | ||
classes.push(arg); | ||
} else if (Array.isArray(arg)) { | ||
classes.push(classNames.apply(null, arg)); | ||
} else if (argType === 'object') { | ||
for (var key in arg) { | ||
if (hasOwn.call(arg, key) && arg[key]) { | ||
classes.push(key); | ||
} | ||
} | ||
} | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
return classes.join(' '); | ||
} | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(AccordionItemButton)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
if (module.exports) { | ||
module.exports = classNames; | ||
} else if (typeof undefined === 'function' && typeof undefined.amd === 'object' && undefined.amd) { | ||
// register as 'classnames', consistent with npm package name | ||
undefined('classnames', [], function () { | ||
return classNames; | ||
}); | ||
} else { | ||
window.classNames = classNames; | ||
} | ||
})(); | ||
}); | ||
_defineProperty(_assertThisInitialized(_this), "handleKeyPress", function (evt) { | ||
var keyCode = evt.which.toString(); | ||
var AccordionItem = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(AccordionItem, _Component); | ||
if (keyCode === keycodes.ENTER || keyCode === keycodes.SPACE) { | ||
evt.preventDefault(); | ||
function AccordionItem() { | ||
_classCallCheck(this, AccordionItem); | ||
_this.props.toggleExpanded(); | ||
} | ||
/* The following block is ignored from test coverage because at time | ||
* time of writing Jest/react-testing-library can not assert 'focus' | ||
* functionality. | ||
*/ | ||
// istanbul ignore next | ||
return _possibleConstructorReturn(this, _getPrototypeOf(AccordionItem).apply(this, arguments)); | ||
} | ||
_createClass(AccordionItem, [{ | ||
key: "componentDidMount", | ||
value: function componentDidMount() { | ||
var _this$props = this.props, | ||
uuid = _this$props.uuid, | ||
accordionStore = _this$props.accordionStore, | ||
disabled = _this$props.disabled; | ||
accordionStore.addItem({ | ||
uuid: uuid, | ||
expanded: this.props.expanded || false, | ||
disabled: disabled | ||
}); | ||
} | ||
}, { | ||
key: "componentWillUnmount", | ||
value: function componentWillUnmount() { | ||
this.props.accordionStore.removeItem(this.props.uuid); | ||
} // This is here so that the user can dynamically set the 'expanded' state using the 'expanded' prop. | ||
if (evt.target instanceof HTMLElement) { | ||
switch (keyCode) { | ||
case keycodes.HOME: | ||
{ | ||
evt.preventDefault(); | ||
focusFirstSiblingOf(evt.target); | ||
break; | ||
} | ||
}, { | ||
key: "componentDidUpdate", | ||
value: function componentDidUpdate(prevProps) { | ||
var _this$props2 = this.props, | ||
uuid = _this$props2.uuid, | ||
expanded = _this$props2.expanded, | ||
accordionStore = _this$props2.accordionStore; | ||
case keycodes.END: | ||
{ | ||
evt.preventDefault(); | ||
focusLastSiblingOf(evt.target); | ||
break; | ||
} | ||
if (expanded !== prevProps.expanded) { | ||
accordionStore.setExpanded(uuid, expanded); | ||
} | ||
} | ||
}, { | ||
key: "render", | ||
value: function render() { | ||
var _this$props3 = this.props, | ||
uuid = _this$props3.uuid, | ||
className = _this$props3.className, | ||
hideBodyClassName = _this$props3.hideBodyClassName, | ||
accordionStore = _this$props3.accordionStore, | ||
disabled = _this$props3.disabled, | ||
expanded = _this$props3.expanded, | ||
rest = _objectWithoutProperties(_this$props3, ["uuid", "className", "hideBodyClassName", "accordionStore", "disabled", "expanded"]); // Deliberately not using 'find' because IE compat. | ||
case keycodes.LEFT: | ||
case keycodes.UP: | ||
{ | ||
evt.preventDefault(); | ||
focusPreviousSiblingOf(evt.target); | ||
break; | ||
} | ||
case keycodes.RIGHT: | ||
case keycodes.DOWN: | ||
{ | ||
evt.preventDefault(); | ||
focusNextSiblingOf(evt.target); | ||
break; | ||
} | ||
var currentItem = accordionStore.items.filter(function (item) { | ||
return item.uuid === uuid; | ||
})[0]; | ||
default: | ||
if (!currentItem) { | ||
return null; | ||
} | ||
} | ||
}); | ||
return React__default.createElement("div", _extends({ | ||
className: classnames(className, _defineProperty({}, hideBodyClassName, !currentItem.expanded && hideBodyClassName)) | ||
}, rest)); | ||
return _this; | ||
} | ||
_createClass(AccordionItemButton, [{ | ||
key: "render", | ||
value: function render() { | ||
var _this$props = this.props, | ||
toggleExpanded = _this$props.toggleExpanded, | ||
rest = _objectWithoutProperties(_this$props, ["toggleExpanded"]); | ||
return React.createElement("div", _extends({}, rest, { | ||
// tslint:disable-next-line react-a11y-event-has-role | ||
onClick: toggleExpanded, | ||
onKeyDown: this.handleKeyPress, | ||
"data-accordion-component": "AccordionItemButton" | ||
})); | ||
} | ||
}]); | ||
return AccordionItem; | ||
}(React.Component); | ||
return AccordionItemButton; | ||
}(React.PureComponent); | ||
var nextUuid = consecutive(); | ||
function resetNextUuid() { | ||
nextUuid = consecutive(); | ||
} | ||
_defineProperty(AccordionItemButton, "defaultProps", defaultProps$1); | ||
var AccordionItemWrapper = | ||
var AccordionItemButtonWrapper = function AccordionItemButtonWrapper(props) { | ||
return React.createElement(Consumer$1, null, function (itemContext) { | ||
var toggleExpanded = itemContext.toggleExpanded, | ||
buttonAttributes = itemContext.buttonAttributes; | ||
return React.createElement(AccordionItemButton, _extends({ | ||
toggleExpanded: toggleExpanded | ||
}, props, buttonAttributes)); | ||
}); | ||
}; | ||
AccordionItemButtonWrapper.displayName = DisplayName$1.AccordionItemButton; | ||
var defaultProps$2 = { | ||
className: 'accordion__heading', | ||
'aria-level': 3 | ||
}; | ||
var SPEC_ERROR = "AccordionItemButton may contain only one child element, which must be an instance of AccordionItemButton.\n\nFrom the WAI-ARIA spec (https://www.w3.org/TR/wai-aria-practices-1.1/#accordion):\n\n\u201CThe button element is the only element inside the heading element. That is, if there are other visually persistent elements, they are not included inside the heading element.\u201D\n\n"; | ||
var AccordionItemHeading = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(AccordionItemWrapper, _Component); | ||
function (_React$PureComponent) { | ||
_inherits(AccordionItemHeading, _React$PureComponent); | ||
function AccordionItemWrapper() { | ||
function AccordionItemHeading() { | ||
var _getPrototypeOf2; | ||
@@ -828,3 +836,3 @@ | ||
_classCallCheck(this, AccordionItemWrapper); | ||
_classCallCheck(this, AccordionItemHeading); | ||
@@ -835,50 +843,69 @@ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(AccordionItemWrapper)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(AccordionItemHeading)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
_defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "id", nextUuid()); | ||
_defineProperty(_assertThisInitialized(_this), "ref", void 0); | ||
_defineProperty(_assertThisInitialized(_this), "setRef", function (ref) { | ||
_this.ref = ref; | ||
}); | ||
return _this; | ||
} | ||
_createClass(AccordionItemWrapper, [{ | ||
_createClass(AccordionItemHeading, [{ | ||
key: "componentDidUpdate", | ||
value: function componentDidUpdate() { | ||
AccordionItemHeading.VALIDATE(this.ref); | ||
} | ||
}, { | ||
key: "componentDidMount", | ||
value: function componentDidMount() { | ||
AccordionItemHeading.VALIDATE(this.ref); | ||
} | ||
}, { | ||
key: "render", | ||
value: function render() { | ||
var _this$props = this.props, | ||
accordionStore = _this$props.accordionStore, | ||
uuid = _this$props.uuid, | ||
rest = _objectWithoutProperties(_this$props, ["accordionStore", "uuid"]); | ||
return React.createElement("div", _extends({ | ||
"data-accordion-component": "AccordionItemHeading" | ||
}, this.props, { | ||
ref: this.setRef | ||
})); | ||
} | ||
}], [{ | ||
key: "VALIDATE", | ||
value: function VALIDATE(ref) { | ||
if (ref === undefined) { | ||
throw new Error('ref is undefined'); | ||
} | ||
var itemUuid = uuid !== undefined ? uuid : this.id; | ||
return React__default.createElement(Provider$1, { | ||
uuid: itemUuid | ||
}, React__default.createElement(AccordionItem, _extends({}, rest, { | ||
uuid: itemUuid, | ||
accordionStore: accordionStore | ||
}))); | ||
if (!(ref.childElementCount === 1 && ref.firstElementChild && ref.firstElementChild.getAttribute('data-accordion-component') === 'AccordionItemButton')) { | ||
throw new Error(SPEC_ERROR); | ||
} | ||
} | ||
}]); | ||
return AccordionItemWrapper; | ||
}(React.Component); | ||
return AccordionItemHeading; | ||
}(React.PureComponent); | ||
_defineProperty(AccordionItemWrapper, "defaultProps", { | ||
className: 'accordion__item', | ||
hideBodyClassName: '', | ||
disabled: false, | ||
expanded: false, | ||
uuid: undefined | ||
}); | ||
_defineProperty(AccordionItemHeading, "defaultProps", defaultProps$2); | ||
var AccordionItem_wrapper = compose(fromRenderProps(Consumer, function (accordionStore) { | ||
return { | ||
accordionStore: accordionStore | ||
}; | ||
}))(AccordionItemWrapper); | ||
var AccordionItemHeadingWrapper = function AccordionItemHeadingWrapper(props) { | ||
return React.createElement(Consumer$1, null, function (itemContext) { | ||
var headingAttributes = itemContext.headingAttributes; | ||
return React.createElement(AccordionItemHeading, _extends({}, props, headingAttributes)); | ||
}); | ||
}; | ||
var AccordionItemTitle = | ||
AccordionItemHeadingWrapper.displayName = DisplayName$1.AccordionItemHeading; | ||
var defaultProps$3 = { | ||
className: 'accordion__panel' | ||
}; | ||
var AccordionItemPanel = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(AccordionItemTitle, _Component); | ||
function (_React$Component) { | ||
_inherits(AccordionItemPanel, _React$Component); | ||
function AccordionItemTitle() { | ||
function AccordionItemPanel() { | ||
var _getPrototypeOf2; | ||
@@ -888,3 +915,3 @@ | ||
_classCallCheck(this, AccordionItemTitle); | ||
_classCallCheck(this, AccordionItemPanel); | ||
@@ -895,202 +922,74 @@ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(AccordionItemTitle)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(AccordionItemPanel)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
_defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleClick", function () { | ||
var _this$props = _this.props, | ||
uuid = _this$props.uuid, | ||
expanded = _this$props.expanded, | ||
setExpanded = _this$props.setExpanded; | ||
setExpanded(uuid, !expanded); | ||
_defineProperty(_assertThisInitialized(_this), "renderChildren", function (_ref) { | ||
var panelAttributes = _ref.panelAttributes; | ||
return React.createElement("div", _extends({ | ||
"data-accordion-component": "AccordionItemPanel" | ||
}, _this.props, panelAttributes)); | ||
}); | ||
_defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleKeyPress", function (evt) { | ||
if (evt.charCode === 13 || evt.charCode === 32) { | ||
evt.preventDefault(); | ||
_this.handleClick(); | ||
} | ||
}); | ||
return _this; | ||
} | ||
_createClass(AccordionItemTitle, [{ | ||
_createClass(AccordionItemPanel, [{ | ||
key: "render", | ||
value: function render() { | ||
var _this$props2 = this.props, | ||
className = _this$props2.className, | ||
hideBodyClassName = _this$props2.hideBodyClassName, | ||
item = _this$props2.item, | ||
accordion = _this$props2.accordion, | ||
setExpanded = _this$props2.setExpanded, | ||
expanded = _this$props2.expanded, | ||
uuid = _this$props2.uuid, | ||
disabled = _this$props2.disabled, | ||
rest = _objectWithoutProperties(_this$props2, ["className", "hideBodyClassName", "item", "accordion", "setExpanded", "expanded", "uuid", "disabled"]); | ||
var id = "accordion__title-".concat(uuid); | ||
var ariaControls = "accordion__body-".concat(uuid); | ||
var role = accordion ? 'tab' : 'button'; | ||
var titleClassName = classnames(className, _defineProperty({}, hideBodyClassName, hideBodyClassName && !expanded)); | ||
if (role === 'tab') { | ||
return React__default.createElement("div", _extends({ | ||
id: id, | ||
"aria-selected": expanded, | ||
"aria-controls": ariaControls, | ||
className: titleClassName, | ||
onClick: disabled ? undefined : this.handleClick, | ||
role: role, | ||
tabIndex: "0" // eslint-disable-line jsx-a11y/no-noninteractive-tabindex | ||
, | ||
onKeyPress: this.handleKeyPress, | ||
disabled: disabled | ||
}, rest)); | ||
} | ||
return React__default.createElement("div", _extends({ | ||
id: id, | ||
"aria-expanded": expanded, | ||
"aria-controls": ariaControls, | ||
className: titleClassName, | ||
onClick: disabled ? undefined : this.handleClick, | ||
role: role, | ||
tabIndex: "0" // eslint-disable-line jsx-a11y/no-noninteractive-tabindex | ||
, | ||
onKeyPress: this.handleKeyPress, | ||
disabled: disabled | ||
}, rest)); | ||
return React.createElement(Consumer$1, null, this.renderChildren); | ||
} | ||
}]); | ||
return AccordionItemTitle; | ||
return AccordionItemPanel; | ||
}(React.Component); | ||
_defineProperty(AccordionItemTitle, "accordionElementName", 'AccordionItemTitle'); | ||
_defineProperty(AccordionItemPanel, "defaultProps", defaultProps$3); | ||
// eslint-disable-next-line react/prefer-stateless-function | ||
var AccordionItemTitleWrapper = | ||
_defineProperty(AccordionItemPanel, "displayName", DisplayName$1.AccordionItemPanel); | ||
var AccordionItemState = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(AccordionItemTitleWrapper, _Component); | ||
function (_React$Component) { | ||
_inherits(AccordionItemState, _React$Component); | ||
function AccordionItemTitleWrapper() { | ||
_classCallCheck(this, AccordionItemTitleWrapper); | ||
function AccordionItemState() { | ||
var _getPrototypeOf2; | ||
return _possibleConstructorReturn(this, _getPrototypeOf(AccordionItemTitleWrapper).apply(this, arguments)); | ||
} | ||
var _this; | ||
_createClass(AccordionItemTitleWrapper, [{ | ||
key: "render", | ||
value: function render() { | ||
var _this$props = this.props, | ||
itemStore = _this$props.itemStore, | ||
accordionStore = _this$props.accordionStore, | ||
rest = _objectWithoutProperties(_this$props, ["itemStore", "accordionStore"]); | ||
_classCallCheck(this, AccordionItemState); | ||
var uuid = itemStore.uuid; | ||
var items = accordionStore.items, | ||
accordion = accordionStore.accordion; | ||
var item = items.filter(function (stateItem) { | ||
return stateItem.uuid === uuid; | ||
})[0]; | ||
return React__default.createElement(AccordionItemTitle, _extends({}, rest, item, { | ||
setExpanded: accordionStore.setExpanded, | ||
accordion: accordion | ||
})); | ||
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | ||
args[_key] = arguments[_key]; | ||
} | ||
}]); | ||
return AccordionItemTitleWrapper; | ||
}(React.Component); | ||
_this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(AccordionItemState)).call.apply(_getPrototypeOf2, [this].concat(args))); | ||
_defineProperty(AccordionItemTitleWrapper, "defaultProps", { | ||
className: 'accordion__title', | ||
hideBodyClassName: '' | ||
}); | ||
_defineProperty(_assertThisInitialized(_this), "renderChildren", function (itemContext) { | ||
var expanded = itemContext.expanded, | ||
disabled = itemContext.disabled; | ||
return React.createElement(React.Fragment, null, _this.props.children({ | ||
expanded: expanded, | ||
disabled: disabled | ||
})); | ||
}); | ||
var AccordionItemTitle_wrapper = compose(fromRenderProps(Consumer, function (accordionStore) { | ||
return { | ||
accordionStore: accordionStore | ||
}; | ||
}), fromRenderProps(Consumer$1, function (itemStore) { | ||
return { | ||
itemStore: itemStore | ||
}; | ||
}))(AccordionItemTitleWrapper); | ||
var AccordionItemBody = function AccordionItemBody(props) { | ||
var className = props.className, | ||
hideBodyClassName = props.hideBodyClassName, | ||
uuid = props.uuid, | ||
expanded = props.expanded, | ||
disabled = props.disabled, | ||
accordion = props.accordion, | ||
rest = _objectWithoutProperties(props, ["className", "hideBodyClassName", "uuid", "expanded", "disabled", "accordion"]); | ||
return React__default.createElement("div", _extends({ | ||
id: "accordion__body-".concat(uuid), | ||
className: classnames(className, _defineProperty({}, hideBodyClassName, !expanded)), | ||
"aria-hidden": !expanded, | ||
"aria-labelledby": "accordion__title-".concat(uuid), | ||
role: accordion ? 'tabpanel' : null | ||
}, rest)); | ||
}; | ||
// eslint-disable-next-line react/prefer-stateless-function | ||
var AccordionItemBodyWrapper = | ||
/*#__PURE__*/ | ||
function (_Component) { | ||
_inherits(AccordionItemBodyWrapper, _Component); | ||
function AccordionItemBodyWrapper() { | ||
_classCallCheck(this, AccordionItemBodyWrapper); | ||
return _possibleConstructorReturn(this, _getPrototypeOf(AccordionItemBodyWrapper).apply(this, arguments)); | ||
return _this; | ||
} | ||
_createClass(AccordionItemBodyWrapper, [{ | ||
_createClass(AccordionItemState, [{ | ||
key: "render", | ||
value: function render() { | ||
var _this$props = this.props, | ||
itemStore = _this$props.itemStore, | ||
accordionStore = _this$props.accordionStore, | ||
rest = _objectWithoutProperties(_this$props, ["itemStore", "accordionStore"]); | ||
var uuid = itemStore.uuid; | ||
var items = accordionStore.items, | ||
accordion = accordionStore.accordion; | ||
var item = items.filter(function (stateItem) { | ||
return stateItem.uuid === uuid; | ||
})[0]; | ||
return item ? React__default.createElement(AccordionItemBody, _extends({}, rest, item, { | ||
accordion: accordion | ||
})) : null; | ||
return React.createElement(Consumer$1, null, this.renderChildren); | ||
} | ||
}]); | ||
return AccordionItemBodyWrapper; | ||
return AccordionItemState; | ||
}(React.Component); | ||
_defineProperty(AccordionItemBodyWrapper, "defaultProps", { | ||
className: 'accordion__body', | ||
hideBodyClassName: 'accordion__body--hidden' | ||
}); | ||
var AccordionItemBody_wrapper = compose(fromRenderProps(Consumer, function (accordionStore) { | ||
return { | ||
accordionStore: accordionStore | ||
}; | ||
}), fromRenderProps(Consumer$1, function (itemStore) { | ||
return { | ||
itemStore: itemStore | ||
}; | ||
}))(AccordionItemBodyWrapper); | ||
// eslint-disable-next-line | ||
exports.Accordion = AccordionWrapper; | ||
exports.AccordionItem = AccordionItem_wrapper; | ||
exports.AccordionItemTitle = AccordionItemTitle_wrapper; | ||
exports.AccordionItemBody = AccordionItemBody_wrapper; | ||
exports.Accordion = Accordion; | ||
exports.AccordionItem = AccordionItem; | ||
exports.AccordionItemButton = AccordionItemButtonWrapper; | ||
exports.AccordionItemHeading = AccordionItemHeadingWrapper; | ||
exports.AccordionItemPanel = AccordionItemPanel; | ||
exports.AccordionItemState = AccordionItemState; | ||
exports.resetNextUuid = resetNextUuid; | ||
@@ -1100,2 +999,2 @@ | ||
}))); | ||
})); |
245
package.json
{ | ||
"name": "react-accessible-accordion", | ||
"version": "2.4.5", | ||
"description": "Accessible Accordion component for React", | ||
"main": "dist/umd/index.js", | ||
"jsnext:main": "dist/es/index.js", | ||
"scripts": { | ||
"test": "jest", | ||
"test:watch": "jest --watch", | ||
"test:coverage": "jest --coverage", | ||
"test:coverage:watch": "jest --coverage --watch", | ||
"coveralls": "cat ./coverage/lcov.info | coveralls", | ||
"lint": "eslint .", | ||
"build:css": "cp src/css/*.css dist", | ||
"build:clean": "mkdir dist || true & rm -rf dist/*", | ||
"build:rollup": "rollup -c", | ||
"build:flow": "flow-copy-source src dist/es -i \"**/*.spec.js\"", | ||
"build": "npm run build:clean && npm run build:css && npm run build:flow && npm run build:rollup", | ||
"start-demo": "webpack-dev-server --mode=development", | ||
"pages": "rm -rf pages && webpack --mode=production --progress && cp demo/*.css pages && cp demo/*.ico pages", | ||
"deploy": "npm run pages && ./bin/deploy.sh", | ||
"prettier": "prettier **/*.js --write", | ||
"prepublishOnly": "npm run build" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/springload/react-accessible-accordion.git" | ||
}, | ||
"jest": { | ||
"setupFiles": [ | ||
"./src/setupTests.js" | ||
"name": "react-accessible-accordion", | ||
"version": "3.0.0", | ||
"description": "Accessible Accordion component for React", | ||
"main": "dist/umd/index.js", | ||
"jsnext:main": "dist/es/index.js", | ||
"types": "dist/types/index.d.ts", | ||
"scripts": { | ||
"test": "jest", | ||
"test:integration": "yarn build:integration && yarn jest --config=integration/jest.config.js integration", | ||
"test:watch": "jest --watch", | ||
"test:coverage": "jest --coverage", | ||
"test:coverage:watch": "jest --coverage --watch", | ||
"coveralls": "cat ./coverage/lcov.info | coveralls", | ||
"lint": "tslint --project .", | ||
"typecheck": "tsc --project .", | ||
"build": "rimraf \"dist/**/*\" && yarn build:rollup && yarn build:types && yarn build:css", | ||
"build:css": "cp src/css/*.css dist", | ||
"build:rollup": "rollup -c", | ||
"build:types": "yarn tsc --project tsconfig.declaration.json", | ||
"build:demo": "rimraf \"demo/dist/**/*\" && yarn webpack --context=demo --mode=production --progress --output-path=demo/dist", | ||
"build:integration": "rimraf \"integration/dist/**/*\" && yarn webpack --context=integration --mode=production --progress --output-path=integration/dist", | ||
"start-demo": "webpack-dev-server --context=demo --mode=development --hot", | ||
"pages": "yarn build:demo && yarn gh-pages -d demo/dist", | ||
"deploy": "yarn pages && ./bin/deploy.sh", | ||
"format": "prettier \"**/*\" --write", | ||
"prepublishOnly": "yarn typecheck && yarn lint && yarn test && yarn build" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/springload/react-accessible-accordion.git" | ||
}, | ||
"keywords": [ | ||
"react", | ||
"component", | ||
"accordion", | ||
"collapse", | ||
"accessible", | ||
"accessibility", | ||
"wai-aria", | ||
"aria", | ||
"a11y" | ||
], | ||
"setupTestFrameworkScriptFile": "./src/setupTestFramework.js", | ||
"testPathIgnorePatterns": [ | ||
"/node_modules/", | ||
"/dist/" | ||
] | ||
}, | ||
"keywords": [ | ||
"react", | ||
"component", | ||
"accordion", | ||
"collapse", | ||
"accessible", | ||
"accessibility" | ||
], | ||
"authors": [ | ||
"Vincent Audebert <vincent@springload.co.nz>" | ||
], | ||
"contributors": [ | ||
{ | ||
"name": "Mitch Ryan", | ||
"url": "https://github.com/ryami333" | ||
"contributors": [ | ||
{ | ||
"name": "Vincent Audebert", | ||
"url": "https://github.com/vincentaudebert" | ||
}, | ||
{ | ||
"name": "Mitch Ryan", | ||
"url": "https://github.com/ryami333" | ||
}, | ||
{ | ||
"name": "Samantha Sanders", | ||
"url": "https://github.com/samanthaksanders" | ||
}, | ||
{ | ||
"name": "Thibaud Colas", | ||
"url": "https://github.com/thibaudcolas" | ||
}, | ||
{ | ||
"name": "Cate Palmer", | ||
"url": "https://github.com/catepalmer" | ||
} | ||
], | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/springload/react-accessible-accordion/issues" | ||
}, | ||
{ | ||
"name": "Samantha Sanders" | ||
"homepage": "https://github.com/springload/react-accessible-accordion#readme", | ||
"devDependencies": { | ||
"@babel/cli": "^7.2.0", | ||
"@babel/core": "^7.3.4", | ||
"@babel/plugin-proposal-class-properties": "^7.3.4", | ||
"@babel/polyfill": "^7.0.0", | ||
"@babel/preset-env": "^7.3.4", | ||
"@babel/preset-react": "^7.0.0", | ||
"@babel/preset-typescript": "^7.1.0", | ||
"@types/jest": "^24.0.9", | ||
"@types/react": "^16.8.6", | ||
"@types/react-dom": "^16.8.0", | ||
"@types/react-test-renderer": "^16.8.0", | ||
"@types/uuid": "^3.4.4", | ||
"babel-core": "^7.0.0-bridge.0", | ||
"babel-jest": "^24.1.0", | ||
"babel-loader": "^8.0.4", | ||
"coveralls": "^3.0.3", | ||
"css-loader": "^2.0.1", | ||
"file-loader": "^3.0.1", | ||
"gh-pages": "^2.0.1", | ||
"html-webpack-plugin": "^3.2.0", | ||
"husky": "^1.2.1", | ||
"jest": "^24.1.0", | ||
"lint-staged": "^8.1.5", | ||
"mini-css-extract-plugin": "^0.5.0", | ||
"prettier": "^1.16.3", | ||
"puppeteer": "1.11.0", | ||
"react": "16.3.2", | ||
"react-dom": "16.3.3", | ||
"react-test-renderer": "^16.8.1", | ||
"react-testing-library": "^6.0.0", | ||
"rimraf": "^2.6.3", | ||
"rollup": "^1.4.1", | ||
"rollup-plugin-babel": "^4.2.0", | ||
"rollup-plugin-commonjs": "^9.2.1", | ||
"rollup-plugin-node-resolve": "^4.0.1", | ||
"rollup-plugin-replace": "^2.1.0", | ||
"style-loader": "^0.23.1", | ||
"tslint": "^5.13.1", | ||
"tslint-config-prettier": "^1.18.0", | ||
"tslint-microsoft-contrib": "^6.1.0", | ||
"tslint-plugin-prettier": "^2.0.1", | ||
"tslint-react": "^3.6.0", | ||
"typescript": "^3.3.3333", | ||
"uuid": "^3.3.2", | ||
"webpack": "^4.29.6", | ||
"webpack-cli": "^3.1.0", | ||
"webpack-dev-server": "^3.2.1" | ||
}, | ||
{ | ||
"name": "Thibaud Colas" | ||
"peerDependencies": { | ||
"react": "^16.3.2", | ||
"react-dom": "^16.3.3" | ||
}, | ||
"husky": { | ||
"hooks": { | ||
"pre-commit": "lint-staged && yarn typecheck" | ||
} | ||
}, | ||
"lint-staged": { | ||
"linters": { | ||
"*.{ts,tsx}": [ | ||
"yarn lint" | ||
] | ||
} | ||
} | ||
], | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/springload/react-accessible-accordion/issues" | ||
}, | ||
"homepage": "https://github.com/springload/react-accessible-accordion#readme", | ||
"devDependencies": { | ||
"@babel/cli": "7.0.0", | ||
"@babel/core": "7.0.0", | ||
"@babel/plugin-proposal-class-properties": "7.0.0", | ||
"@babel/polyfill": "7.0.0", | ||
"@babel/preset-env": "7.0.0", | ||
"@babel/preset-flow": "7.0.0", | ||
"@babel/preset-react": "7.0.0", | ||
"babel-core": "^7.0.0-bridge.0", | ||
"babel-eslint": "^8.2.2", | ||
"babel-jest": "^23.4.2", | ||
"babel-loader": "^8.0.0", | ||
"coveralls": "^3.0.0", | ||
"css-loader": "^1.0.0", | ||
"enzyme": "^3.3.0", | ||
"enzyme-adapter-react-16": "^1.1.1", | ||
"enzyme-to-json": "^3.3.4", | ||
"eslint": "^5.1.0", | ||
"eslint-config-airbnb": "^17.0.0", | ||
"eslint-config-prettier": "^2.9.0", | ||
"eslint-plugin-flowtype": "^2.50.0", | ||
"eslint-plugin-flowtype-errors": "^3.6.0", | ||
"eslint-plugin-import": "^2.13.0", | ||
"eslint-plugin-jsx-a11y": "^6.1.1", | ||
"eslint-plugin-react": "^7.10.0", | ||
"flow-bin": "^0.76.0", | ||
"flow-copy-source": "^2.0.2", | ||
"html-webpack-plugin": "^3.2.0", | ||
"jest": "^23.5.0", | ||
"prettier": "^1.12.0", | ||
"raf": "^3.4.0", | ||
"react": "^16.4.0", | ||
"react-dom": "^16.4.0", | ||
"react-test-renderer": "^16.4.0", | ||
"rollup": "^0.59.4", | ||
"rollup-plugin-babel": "^4.0.2", | ||
"rollup-plugin-commonjs": "^9.1.0", | ||
"rollup-plugin-eslint": "^4.0.0", | ||
"rollup-plugin-node-resolve": "^3.3.0", | ||
"rollup-plugin-replace": "^2.0.0", | ||
"style-loader": "^0.21.0", | ||
"webpack": "^4.5.0", | ||
"webpack-cli": "^3.1.0", | ||
"webpack-dev-server": "^3.1.3" | ||
}, | ||
"dependencies": { | ||
"classnames": "^2.2.5", | ||
"consecutive": "^5.0.4", | ||
"recompose": "^0.30.0" | ||
}, | ||
"peerDependencies": { | ||
"react": "^15.4.0 || ^16.0.0", | ||
"react-dom": "^15.4.0 || ^16.0.0" | ||
} | ||
} |
374
README.md
@@ -1,2 +0,5 @@ | ||
[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) | ||
[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) | ||
[![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-tested-brightgreen.svg)](http://wave.webaim.org/report#/https://springload.github.io/react-accessible-accordion/) | ||
@@ -14,10 +17,10 @@ ========= | ||
```sh | ||
npm install --save react-accessible-accordion react react-dom | ||
npm install --save react-accessible-accordion | ||
``` | ||
Then, import the editor and use it in your code. Here is a [basic example](https://springload.github.io/react-accessible-accordion/): | ||
Then, import the editor and use it in your code. Here is a | ||
[basic example](https://springload.github.io/react-accessible-accordion/): | ||
```jsx | ||
import React from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
@@ -27,4 +30,4 @@ import { | ||
AccordionItem, | ||
AccordionItemTitle, | ||
AccordionItemBody, | ||
AccordionItemHeading, | ||
AccordionItemPanel, | ||
} from 'react-accessible-accordion'; | ||
@@ -35,25 +38,37 @@ | ||
const Example = () => ( | ||
<Accordion> | ||
<AccordionItem> | ||
<AccordionItemTitle> | ||
<h3>Simple title</h3> | ||
</AccordionItemTitle> | ||
<AccordionItemBody> | ||
<p>Body content</p> | ||
</AccordionItemBody> | ||
</AccordionItem> | ||
<AccordionItem> | ||
<AccordionItemTitle> | ||
<h3>Complex title</h3> | ||
<div>With a bit of description</div> | ||
</AccordionItemTitle> | ||
<AccordionItemBody> | ||
<p>Body content</p> | ||
</AccordionItemBody> | ||
</AccordionItem> | ||
</Accordion> | ||
); | ||
ReactDOM.render(<Example />, document.querySelector('[data-mount]')); | ||
export default function Example() { | ||
return ( | ||
<Accordion> | ||
<AccordionItem> | ||
<AccordionItemHeading> | ||
<AccordionItemButton> | ||
What harsh truths do you prefer to ignore? | ||
</AccordionItemButton> | ||
</AccordionItemHeading> | ||
<AccordionItemPanel> | ||
<p> | ||
Exercitation in fugiat est ut ad ea cupidatat ut in | ||
cupidatat occaecat ut occaecat consequat est minim minim | ||
esse tempor laborum consequat esse adipisicing eu | ||
reprehenderit enim. | ||
</p> | ||
</AccordionItemPanel> | ||
</AccordionItem> | ||
<AccordionItem> | ||
<AccordionItemHeading> | ||
<AccordionItemButton> | ||
Is free will real or just an illusion? | ||
</AccordionItemButton> | ||
</AccordionItemHeading> | ||
<AccordionItemPanel> | ||
<p> | ||
In ad velit in ex nostrud dolore cupidatat consectetur | ||
ea in ut nostrud velit in irure cillum tempor laboris | ||
sed adipisicing eu esse duis nulla non. | ||
</p> | ||
</AccordionItemPanel> | ||
</AccordionItem> | ||
</Accordion> | ||
); | ||
} | ||
``` | ||
@@ -63,203 +78,174 @@ | ||
We strongly encourage you to write your own styles for your accordions, but we've published these two starter stylesheets to help you get up and running: | ||
We strongly encourage you to write your own styles for your accordions, but | ||
we've published the styles used on our demo page to help you get up and running: | ||
```js | ||
// 'Minimal' theme - hide/show the AccordionBody component: | ||
import 'react-accessible-accordion/dist/minimal-example.css'; | ||
// 'Fancy' theme - boilerplate styles for all components, as seen on our demo: | ||
import 'react-accessible-accordion/dist/fancy-example.css'; | ||
``` | ||
We recommend that you copy them into your own app and modify them to suit your needs, particularly if you're using your own `className`s. | ||
We recommend that you copy them into your own app and modify them to suit your | ||
needs, particularly if you're using your own `className`s. | ||
## API | ||
## Component API | ||
### Accordion | ||
#### props: | ||
#### allowMultipleExpanded : `boolean` [*optional*, default: `false`] | ||
<table class="table table-bordered table-striped"> | ||
<thead> | ||
<tr> | ||
<th style="width: 100px;">name</th> | ||
<th style="width: 50px;">type</th> | ||
<th>default</th> | ||
<th>description</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
<tr> | ||
<td>accordion</td> | ||
<td>Boolean</td> | ||
<td>true</td> | ||
<td>Open only one item at a time or not</td> | ||
</tr> | ||
<tr> | ||
<td>onChange</td> | ||
<td>Function(keys)</td> | ||
<td>noop</td> | ||
<td>Triggered on change (open/close items)</td> | ||
</tr> | ||
<tr> | ||
<td>className</td> | ||
<td>String</td> | ||
<td>accordion</td> | ||
<td>CSS class(es) applied to the component</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
Don't autocollapse items when expanding other items. | ||
#### allowZeroExpanded : `boolean` [*optional*, default: `false`] | ||
Allow the only remaining expanded item to be collapsed. | ||
#### preExpanded: `string[]` [_optional_, default: `[]`] | ||
Accepts an array of strings and any `AccordionItem` whose `uuid` prop matches on | ||
of these strings will be expanded on mount. | ||
#### className : `string` [*optional*, default: `'accordion'`] | ||
Class(es) to apply to element. | ||
#### onChange : `(string[]) => void` [*optional*] | ||
Callback which is invoked when items are expanded or collapsed. Gets passed | ||
`uuid`s of the currently expanded `AccordionItem`s. | ||
--- | ||
### AccordionItem | ||
#### props: | ||
#### className : `string` [*optional*, default: `accordion__item`] | ||
<table class="table table-bordered table-striped"> | ||
<thead> | ||
<tr> | ||
<th style="width: 100px;">name</th> | ||
<th style="width: 50px;">type</th> | ||
<th>default</th> | ||
<th>description</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
<tr> | ||
<td>expanded</td> | ||
<td>Boolean</td> | ||
<td>false</td> | ||
<td>Expands this item on first render</td> | ||
</tr> | ||
<tr> | ||
<td>className</td> | ||
<td>String</td> | ||
<td>accordion__item</td> | ||
<td>CSS class(es) applied to the component</td> | ||
</tr> | ||
<tr> | ||
<td>hideBodyClassName</td> | ||
<td>String</td> | ||
<td>null</td> | ||
<td>Class name for hidden body state</td> | ||
</tr> | ||
<tr> | ||
<td>uuid</td> | ||
<td>String</td> | ||
<td>null</td> | ||
<td>Custom uuid to be passed to Accordion - onChange. Has to be unique.</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
Class(es) to apply to element. | ||
### AccordionItemTitle | ||
#### uuid : `string|number` [*optional*] | ||
#### props: | ||
Recommended for use with `onChange`. Will be auto-generated if not provided. | ||
<table class="table table-bordered table-striped"> | ||
<thead> | ||
<tr> | ||
<th style="width: 100px;">name</th> | ||
<th style="width: 50px;">type</th> | ||
<th>default</th> | ||
<th>description</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
<tr> | ||
<td>className</td> | ||
<td>String</td> | ||
<td>accordion__title</td> | ||
<td>CSS class(es) applied to the component</td> | ||
</tr> | ||
<tr> | ||
<td>hideBodyClassName</td> | ||
<td>String</td> | ||
<td>null</td> | ||
<td>Class name for hidden body state</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
--- | ||
### AccordionItemBody | ||
### AccordionItemHeading | ||
#### props: | ||
#### className : `string` [*optional*, default: `'accordion__heading'`] | ||
<table class="table table-bordered table-striped"> | ||
<thead> | ||
<tr> | ||
<th style="width: 100px;">name</th> | ||
<th style="width: 50px;">type</th> | ||
<th>default</th> | ||
<th>description</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
<tr> | ||
<td>className</td> | ||
<td>String</td> | ||
<td>accordion__body</td> | ||
<td>CSS class(es) applied to the component</td> | ||
</tr> | ||
<tr> | ||
<td>hideBodyClassName</td> | ||
<td>String</td> | ||
<td>accordion__body--hidden</td> | ||
<td>Class name for hidden body state</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
Class(es) to apply to the 'heading' element. | ||
### resetNextUuid | ||
#### aria-level : `number` [*optional*, default: `3`] | ||
<table class="table table-bordered table-striped"> | ||
<tbody> | ||
<tr> | ||
<td>Function(void)</td> | ||
</tr> | ||
<tr> | ||
<td>Resets the internal counter for Accordion items' identifiers (including `id` attributes). For use in test suites and isomorphic frameworks.</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
Semantics to apply to the 'heading' element. A value of `1` would make your | ||
heading element hierarchically equivalent to an `<h1>` tag, and likewise a value | ||
of `6` would make it equivalent to an `<h6>` tag. | ||
## Accessibility | ||
### AccordionItemButton | ||
### What this project is doing accessibility-wise? | ||
#### className : `string` [*optional*, default: `'accordion__button'`] | ||
This project manages two types of Accordions, with single or multiple items open. | ||
Class(es) to apply to the 'button' element. | ||
#### Single item | ||
--- | ||
> Use this with with props `accordion` set to `true` on `Accordion`. | ||
### AccordionItemPanel | ||
For this type of Accordion, you will get the following `role` set up on your elements: | ||
#### className : `string` [*optional*, default: `'accordion__panel'`] | ||
* Accordion: `tablist` | ||
* AccordionItem: no specific role | ||
* AccordionItemTitle: `tab` | ||
* AccordionItemBody: `tabpanel` | ||
Class(es) to apply to element. | ||
#### Multiple items | ||
--- | ||
For this type of Accordion, you will get the following `role` set up on your elements: | ||
### AccordionItemState | ||
> Use this with with props `accordion` set to `false` on `Accordion`. | ||
#### children : `({ expanded: boolean, disabled: boolean }): JSX.Element` [**required**] | ||
* Accordion: no specific role | ||
* AccordionItem: no specific role | ||
* AccordionItemTitle: `button` | ||
* AccordionItemBody: no specific role | ||
--- | ||
# Browser support | ||
## Helpers | ||
### resetNextUuid : `(): void` | ||
Resets the internal counter for Accordion items' identifiers (including `id` | ||
attributes). For use in test suites and isomorphic frameworks. | ||
--- | ||
## Accessibility Best-Practice | ||
Authoring an 'accordion' component to the | ||
[WAI ARIA spec](https://www.w3.org/TR/wai-aria-practices-1.1/#accordion) can be | ||
complex, but `React Accessible Accordion` does most of the heavy lifting for | ||
you, including: | ||
- Applying appropriate aria attributes (`aria-expanded`, `aria-controls`, | ||
`aria-disabled`, `aria-hidden` and `aria-labelledby`). | ||
- Applying appropriate `role` attributes (`button`, `heading`, `region`). | ||
- Applying appropriate `tabindex` attributes. | ||
- Applying keyboard interactivity ('space', 'end', 'tab', 'up', 'down', 'home' | ||
and 'end' keys). | ||
However, there's still a couple of things you need to keep in mind to remain | ||
spec-compliant: | ||
- Only ever use | ||
[phrasing content](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_categories#Phrasing_content) | ||
inside of your `AccordionItemHeading` component. If in doubt, use text only. | ||
- Always provide an `aria-level` prop to your `AccordionItemHeading` | ||
component, _especially_ if you are nesting accordions. This attribute is a | ||
signal used by assistive technologies (eg. screenreaders) to determine which | ||
heading level (ie. `h1`-`h6`) to treat your heading as. | ||
If you have any questions about your implementation, then please don't be afraid | ||
to get in touch via our | ||
[issues](https://github.com/springload/react-accessible-accordion/issues). | ||
## FAQs | ||
### Which design patterns does this component aim to solve? | ||
Those described by the WAI ARIA spec's description of an 'accordion': | ||
> An accordion is a vertically stacked set of interactive headings that each | ||
> contain a title, content snippet, or thumbnail representing a section of | ||
> content. The headings function as controls that enable users to reveal or hide | ||
> their associated sections of content. Accordions are commonly used to reduce | ||
> the need to scroll when presenting multiple sections of content on a single | ||
> page. | ||
### Which design patterns does this component NOT aim to solve? | ||
Components which are "accordion-like" but do not match the WAI ARIA spec's | ||
description, as written above. By "accordion-like", we mean components which | ||
have collapsible items but require bespoke interactive mechanisms in order to | ||
expand, collapse and 'disable' them. This includes (but is not limited to) | ||
multi-step forms, like those seen in many cart/checkout flows, which we believe | ||
require (other) complex markup in order to be considered 'accessible'. | ||
If you believe that you have a valid use-case for 'disabled' items, or items | ||
which require manual 'expanded' state-management, then please | ||
[let us know](https://github.com/springload/react-accessible-accordion/issues/new) - | ||
we're always open for critical (but polite) feedback. Otherwise, we don't plan | ||
on implementing this functionality in the near future. | ||
### How do I disable an item? | ||
See "Which design patterns does this component NOT aim to solve?". | ||
### How do I manually control the expanded state of an item? | ||
See "Which design patterns does this component NOT aim to solve?". You may use | ||
the 'preExpanded' prop to set the initial expanded state, but it may not be | ||
controlled manually thereafter. | ||
## 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 | | | ||
| Browser | Device/OS | Version | | ||
| ------------- | --------- | ------- | | ||
| Mobile Safari | iOS | latest | | ||
| Chrome | Android | latest | | ||
| IE | Windows | 11 | | ||
| MS Edge | Windows | latest | | ||
| Chrome | Desktop | latest | | ||
| Firefox | Desktop | latest | | ||
| Safari | OSX | latest | |
import resolve from 'rollup-plugin-node-resolve'; | ||
import eslint from 'rollup-plugin-eslint'; | ||
import babel from 'rollup-plugin-babel'; | ||
@@ -8,11 +7,27 @@ import commonjs from 'rollup-plugin-commonjs'; | ||
const output = { | ||
name: 'reactAccessibleAccordion', | ||
globals: { | ||
react: 'React', | ||
}, | ||
}; | ||
const extensions = ['.ts', '.tsx', '.js', '.jsx', '.json']; | ||
export default [ | ||
{ | ||
input: 'src/index.js', | ||
input: 'src/index.tsx', | ||
external: ['react', 'react-dom'], | ||
output: [ | ||
{ file: pkg.main, format: 'umd', name: 'reactAccessibleAccordion' }, | ||
{ file: pkg['jsnext:main'], format: 'es' }, | ||
{ | ||
...output, | ||
file: pkg.main, | ||
format: 'umd', | ||
}, | ||
{ | ||
...output, | ||
file: pkg['jsnext:main'], | ||
format: 'es', | ||
}, | ||
], | ||
name: 'reactAccessibleAccordion', | ||
plugins: [ | ||
@@ -26,5 +41,8 @@ replace({ | ||
browser: true, | ||
extensions, | ||
}), | ||
eslint(), | ||
babel(), | ||
babel({ | ||
exclude: 'node_modules/**', | ||
extensions, | ||
}), | ||
commonjs(), | ||
@@ -31,0 +49,0 @@ ], |
@@ -5,9 +5,7 @@ // Used to run webpack dev server to test the demo in local | ||
const HtmlWebpackPlugin = require('html-webpack-plugin'); | ||
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); | ||
module.exports = (env, options) => ({ | ||
mode: options.mode, | ||
devtool: 'source-map', | ||
entry: path.resolve(__dirname, 'demo/js/demo.js'), | ||
output: { | ||
path: path.resolve(__dirname, 'pages'), | ||
filename: | ||
@@ -21,3 +19,3 @@ options.mode === 'production' | ||
{ | ||
test: /\.js$/, | ||
test: /\.(js|ts)x?$/, | ||
exclude: [/node_modules/], | ||
@@ -32,19 +30,27 @@ use: [ | ||
test: /\.css$/, | ||
loaders: ['style-loader', 'css-loader'], | ||
use: [ | ||
options.mode === 'production' | ||
? MiniCssExtractPlugin.loader | ||
: 'style-loader', | ||
'css-loader', | ||
], | ||
}, | ||
{ | ||
test: /\.ico$/, | ||
loaders: ['file-loader'], | ||
}, | ||
], | ||
}, | ||
resolve: { | ||
extensions: ['.wasm', '.mjs', '.js', '.jsx', '.json', '.ts', '.tsx'], | ||
}, | ||
plugins: [ | ||
options.mode === 'development' | ||
? new webpack.HotModuleReplacementPlugin() | ||
: () => {}, | ||
new HtmlWebpackPlugin({ | ||
template: path.resolve(__dirname, 'demo/index.html'), | ||
template: 'src/index.html', | ||
}), | ||
new MiniCssExtractPlugin({ | ||
filename: '[name][contenthash].css', | ||
}), | ||
], | ||
devServer: { | ||
contentBase: './demo', | ||
}, | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
258795
2
36
1
47
2388
248
- Removedclassnames@^2.2.5
- Removedconsecutive@^5.0.4
- Removedrecompose@^0.30.0
- Removed@babel/runtime@7.26.0(transitive)
- Removedasap@2.0.6(transitive)
- Removedchange-emitter@0.1.6(transitive)
- Removedclassnames@2.5.1(transitive)
- Removedconsecutive@5.0.6(transitive)
- Removedcore-js@1.2.7(transitive)
- Removedencoding@0.1.13(transitive)
- Removedfbjs@0.8.18(transitive)
- Removedhoist-non-react-statics@2.5.5(transitive)
- Removediconv-lite@0.6.3(transitive)
- Removedis-stream@1.1.0(transitive)
- Removedisomorphic-fetch@2.2.1(transitive)
- Removednode-fetch@1.7.3(transitive)
- Removedpromise@7.3.1(transitive)
- Removedreact-lifecycles-compat@3.0.4(transitive)
- Removedrecompose@0.30.0(transitive)
- Removedregenerator-runtime@0.14.1(transitive)
- Removedsafer-buffer@2.1.2(transitive)
- Removedsetimmediate@1.0.5(transitive)
- Removedsymbol-observable@1.2.0(transitive)
- Removedua-parser-js@0.7.39(transitive)
- Removedwhatwg-fetch@3.6.20(transitive)