focus-trap-react 4.0.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.md +27 -12
- package/dist/focus-trap-react.js +22 -16
- package/index.d.ts +2 -4
- package/package.json +2 -2
- package/src/focus-trap-react.js +19 -26
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 6.0.0
|
|
4
|
+
|
|
5
|
+
- Update focus-trap to 4.0.2, which includes [a queue of traps](https://github.com/davidtheclark/focus-trap/blob/master/CHANGELOG.md#400), so when a trap is paused because another trap activates, it will be unpaused when that other trap deactivates. If Trap A was automatically paused because Trap B activated (existing behavior), when Trap B is deactivated Trap A will be automatically unpaused (new behavior).
|
|
6
|
+
|
|
7
|
+
## 5.0.1
|
|
8
|
+
|
|
9
|
+
- Fix TypeScript declarations.
|
|
10
|
+
|
|
11
|
+
## 5.0.0
|
|
12
|
+
|
|
13
|
+
- **Breaking change:** `<FocusTrap>` now expects exactly one child element which can be any HTML element or other React component that contains focusable elements. The `tag` prop has been removed, as has support for additional props that are passed through to the `tag`, because it is no longer necessary: you should provide your own element, with whatever props you want, as a child of `<FocusTrap>`.
|
|
14
|
+
|
|
15
|
+
## 4.0.1
|
|
16
|
+
|
|
17
|
+
- Fix bug that caused `returnFocusOnDeactivate: true` to be ignored when using the `active` prop to activate & deactivate the focus trap.
|
|
18
|
+
|
|
3
19
|
## 4.0.0
|
|
4
20
|
|
|
5
21
|
- Update focus-trap to 3.0.0, which includes [a couple of behavior changes](https://github.com/davidtheclark/focus-trap/blob/master/CHANGELOG.md#300). The key change is that focus management has been changed so that you can include tricky focusable elements like radio groups, iframes, and shadow DOM components in your trap — as long as the first and last focusable elements in the trap can still be detected by [Tabbable](https://github.com/davidtheclark/tabbable).
|
package/README.md
CHANGED
|
@@ -7,6 +7,12 @@ tailored to your React-specific needs.
|
|
|
7
7
|
|
|
8
8
|
You might want it for, say, building [an accessible modal](https://github.com/davidtheclark/react-aria-modal)?
|
|
9
9
|
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
**Looking for co-maintainers!** If you'd like to help maintain this project, please let me know.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
10
16
|
## What it does
|
|
11
17
|
|
|
12
18
|
[Check out the demo](http://davidtheclark.github.io/focus-trap-react/demo/).
|
|
@@ -41,9 +47,28 @@ Why? Because this module's core functionality comes from focus-trap, which uses
|
|
|
41
47
|
|
|
42
48
|
## Usage
|
|
43
49
|
|
|
44
|
-
|
|
50
|
+
You wrap any element that you want to act as a focus trap with the `<FocusTrap>` component. `<FocusTrap>` expects exactly one child element which can be any HTML element or other React component that contains focusable elements.
|
|
51
|
+
|
|
52
|
+
For example:
|
|
53
|
+
|
|
54
|
+
```js
|
|
55
|
+
<FocusTrap>
|
|
56
|
+
<div id="modal-dialog" className="modal" >
|
|
57
|
+
<button>Ok</button>
|
|
58
|
+
<button>Cancel</button>
|
|
59
|
+
</div>
|
|
60
|
+
</FocusTrap>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
```js
|
|
64
|
+
<FocusTrap>
|
|
65
|
+
<ModalDialog okButtonText="Ok" cancelButtonText="Cancel" />
|
|
66
|
+
</FocusTrap>
|
|
67
|
+
```
|
|
45
68
|
|
|
46
|
-
|
|
69
|
+
You can read further code examples in `demo/` (it's very simple), and [see how it works](http://davidtheclark.github.io/focus-trap-react/demo/).
|
|
70
|
+
|
|
71
|
+
Here's one more simple example:
|
|
47
72
|
|
|
48
73
|
```js
|
|
49
74
|
const React = require('react');
|
|
@@ -138,16 +163,6 @@ Type: `Boolean`, optional
|
|
|
138
163
|
|
|
139
164
|
If you would like to pause or unpause the focus trap (see [`focus-trap`'s documentation](https://github.com/davidtheclark/focus-trap#focustrappause)), toggle this prop.
|
|
140
165
|
|
|
141
|
-
#### tag
|
|
142
|
-
|
|
143
|
-
Type: `String`, Default: `div`, optional
|
|
144
|
-
|
|
145
|
-
An HTML tag for the FocusTrap's DOM node.
|
|
146
|
-
|
|
147
|
-
#### additional props
|
|
148
|
-
|
|
149
|
-
All props not mentioned above are passed directly to the rendered DOM element. This means that you can pass `id`, `className`, `style`, `aria-`attributes, `data-`attributes, or any other arbitrary property that you want to use to customize the element.
|
|
150
|
-
|
|
151
166
|
## Contributing & Development
|
|
152
167
|
|
|
153
168
|
Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.
|
package/dist/focus-trap-react.js
CHANGED
|
@@ -9,10 +9,9 @@ function _possibleConstructorReturn(self, call) { if (!self) { throw new Referen
|
|
|
9
9
|
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
|
10
10
|
|
|
11
11
|
var React = require('react');
|
|
12
|
+
var ReactDOM = require('react-dom');
|
|
12
13
|
var createFocusTrap = require('focus-trap');
|
|
13
14
|
|
|
14
|
-
var checkedProps = ['active', 'paused', 'tag', 'focusTrapOptions', '_createFocusTrap'];
|
|
15
|
-
|
|
16
15
|
var FocusTrap = function (_React$Component) {
|
|
17
16
|
_inherits(FocusTrap, _React$Component);
|
|
18
17
|
|
|
@@ -21,8 +20,8 @@ var FocusTrap = function (_React$Component) {
|
|
|
21
20
|
|
|
22
21
|
var _this = _possibleConstructorReturn(this, (FocusTrap.__proto__ || Object.getPrototypeOf(FocusTrap)).call(this, props));
|
|
23
22
|
|
|
24
|
-
_this.
|
|
25
|
-
_this.
|
|
23
|
+
_this.setFocusTrapElement = function (element) {
|
|
24
|
+
_this.focusTrapElement = element;
|
|
26
25
|
};
|
|
27
26
|
|
|
28
27
|
if (typeof document !== 'undefined') {
|
|
@@ -49,7 +48,9 @@ var FocusTrap = function (_React$Component) {
|
|
|
49
48
|
tailoredFocusTrapOptions[optionName] = specifiedFocusTrapOptions[optionName];
|
|
50
49
|
}
|
|
51
50
|
|
|
52
|
-
|
|
51
|
+
var focusTrapElementDOMNode = ReactDOM.findDOMNode(this.focusTrapElement);
|
|
52
|
+
|
|
53
|
+
this.focusTrap = this.props._createFocusTrap(focusTrapElementDOMNode, tailoredFocusTrapOptions);
|
|
53
54
|
if (this.props.active) {
|
|
54
55
|
this.focusTrap.activate();
|
|
55
56
|
}
|
|
@@ -61,7 +62,11 @@ var FocusTrap = function (_React$Component) {
|
|
|
61
62
|
key: 'componentDidUpdate',
|
|
62
63
|
value: function componentDidUpdate(prevProps) {
|
|
63
64
|
if (prevProps.active && !this.props.active) {
|
|
64
|
-
this.
|
|
65
|
+
var returnFocusOnDeactivate = this.props.focusTrapOptions.returnFocusOnDeactivate;
|
|
66
|
+
|
|
67
|
+
var returnFocus = returnFocusOnDeactivate || false;
|
|
68
|
+
var config = { returnFocus: returnFocus };
|
|
69
|
+
this.focusTrap.deactivate(config);
|
|
65
70
|
} else if (!prevProps.active && this.props.active) {
|
|
66
71
|
this.focusTrap.activate();
|
|
67
72
|
}
|
|
@@ -83,18 +88,20 @@ var FocusTrap = function (_React$Component) {
|
|
|
83
88
|
}, {
|
|
84
89
|
key: 'render',
|
|
85
90
|
value: function render() {
|
|
86
|
-
var
|
|
87
|
-
|
|
91
|
+
var _this2 = this;
|
|
92
|
+
|
|
93
|
+
var child = React.Children.only(this.props.children);
|
|
94
|
+
|
|
95
|
+
var composedRefCallback = function composedRefCallback(element) {
|
|
96
|
+
_this2.setFocusTrapElement(element);
|
|
97
|
+
if (typeof child.ref === 'function') {
|
|
98
|
+
child.ref(element);
|
|
99
|
+
}
|
|
88
100
|
};
|
|
89
101
|
|
|
90
|
-
|
|
91
|
-
for (var prop in this.props) {
|
|
92
|
-
if (!this.props.hasOwnProperty(prop)) continue;
|
|
93
|
-
if (checkedProps.indexOf(prop) !== -1) continue;
|
|
94
|
-
elementProps[prop] = this.props[prop];
|
|
95
|
-
}
|
|
102
|
+
var childWithRef = React.cloneElement(child, { ref: composedRefCallback });
|
|
96
103
|
|
|
97
|
-
return
|
|
104
|
+
return childWithRef;
|
|
98
105
|
}
|
|
99
106
|
}]);
|
|
100
107
|
|
|
@@ -103,7 +110,6 @@ var FocusTrap = function (_React$Component) {
|
|
|
103
110
|
|
|
104
111
|
FocusTrap.defaultProps = {
|
|
105
112
|
active: true,
|
|
106
|
-
tag: 'div',
|
|
107
113
|
paused: false,
|
|
108
114
|
focusTrapOptions: {},
|
|
109
115
|
_createFocusTrap: createFocusTrap
|
package/index.d.ts
CHANGED
|
@@ -5,13 +5,11 @@ export = FocusTrap;
|
|
|
5
5
|
|
|
6
6
|
declare namespace FocusTrap {
|
|
7
7
|
export interface Props extends React.AllHTMLAttributes<any> {
|
|
8
|
+
children: React.ReactElement<any>;
|
|
8
9
|
active?: boolean;
|
|
9
10
|
paused?: boolean;
|
|
10
|
-
tag?: string;
|
|
11
11
|
focusTrapOptions?: FocusTrapOptions;
|
|
12
|
-
// Allow through any properties that weren't picked up
|
|
13
|
-
[prop: string]: any;
|
|
14
12
|
}
|
|
15
13
|
}
|
|
16
14
|
|
|
17
|
-
declare class FocusTrap extends React.Component<FocusTrap.Props> {}
|
|
15
|
+
declare class FocusTrap extends React.Component<FocusTrap.Props> { }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "focus-trap-react",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "A React component that traps focus.",
|
|
5
5
|
"main": "dist/focus-trap-react.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"react-dom": "^16.0.0"
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"focus-trap": "^
|
|
61
|
+
"focus-trap": "^4.0.2"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
64
|
"react": "0.14.x || ^15.0.0 || ^16.0.0",
|
package/src/focus-trap-react.js
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
const React = require('react');
|
|
2
|
+
const ReactDOM = require('react-dom');
|
|
2
3
|
const createFocusTrap = require('focus-trap');
|
|
3
4
|
|
|
4
|
-
const checkedProps = [
|
|
5
|
-
'active',
|
|
6
|
-
'paused',
|
|
7
|
-
'tag',
|
|
8
|
-
'focusTrapOptions',
|
|
9
|
-
'_createFocusTrap'
|
|
10
|
-
];
|
|
11
|
-
|
|
12
5
|
class FocusTrap extends React.Component {
|
|
13
6
|
constructor(props) {
|
|
14
7
|
super(props)
|
|
@@ -35,8 +28,10 @@ class FocusTrap extends React.Component {
|
|
|
35
28
|
specifiedFocusTrapOptions[optionName];
|
|
36
29
|
}
|
|
37
30
|
|
|
31
|
+
const focusTrapElementDOMNode = ReactDOM.findDOMNode(this.focusTrapElement);
|
|
32
|
+
|
|
38
33
|
this.focusTrap = this.props._createFocusTrap(
|
|
39
|
-
|
|
34
|
+
focusTrapElementDOMNode,
|
|
40
35
|
tailoredFocusTrapOptions
|
|
41
36
|
);
|
|
42
37
|
if (this.props.active) {
|
|
@@ -49,7 +44,10 @@ class FocusTrap extends React.Component {
|
|
|
49
44
|
|
|
50
45
|
componentDidUpdate(prevProps) {
|
|
51
46
|
if (prevProps.active && !this.props.active) {
|
|
52
|
-
this.
|
|
47
|
+
const { returnFocusOnDeactivate } = this.props.focusTrapOptions;
|
|
48
|
+
const returnFocus = returnFocusOnDeactivate || false;
|
|
49
|
+
const config = { returnFocus };
|
|
50
|
+
this.focusTrap.deactivate(config);
|
|
53
51
|
} else if (!prevProps.active && this.props.active) {
|
|
54
52
|
this.focusTrap.activate();
|
|
55
53
|
}
|
|
@@ -72,33 +70,28 @@ class FocusTrap extends React.Component {
|
|
|
72
70
|
}
|
|
73
71
|
}
|
|
74
72
|
|
|
75
|
-
|
|
76
|
-
this.
|
|
73
|
+
setFocusTrapElement = element => {
|
|
74
|
+
this.focusTrapElement = element;
|
|
77
75
|
};
|
|
78
76
|
|
|
79
77
|
render() {
|
|
80
|
-
const
|
|
81
|
-
ref: this.setNode
|
|
82
|
-
};
|
|
78
|
+
const child = React.Children.only(this.props.children);
|
|
83
79
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (
|
|
87
|
-
|
|
88
|
-
|
|
80
|
+
const composedRefCallback = element => {
|
|
81
|
+
this.setFocusTrapElement(element);
|
|
82
|
+
if (typeof child.ref === 'function') {
|
|
83
|
+
child.ref(element);
|
|
84
|
+
}
|
|
89
85
|
}
|
|
90
86
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
this.props.children
|
|
95
|
-
);
|
|
87
|
+
const childWithRef = React.cloneElement(child, { ref: composedRefCallback });
|
|
88
|
+
|
|
89
|
+
return childWithRef;
|
|
96
90
|
}
|
|
97
91
|
}
|
|
98
92
|
|
|
99
93
|
FocusTrap.defaultProps = {
|
|
100
94
|
active: true,
|
|
101
|
-
tag: 'div',
|
|
102
95
|
paused: false,
|
|
103
96
|
focusTrapOptions: {},
|
|
104
97
|
_createFocusTrap: createFocusTrap
|