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 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
- Read code in `demo/` (it's very simple), and [see how it works](http://davidtheclark.github.io/focus-trap-react/demo/).
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
- Here's one simple example:
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.
@@ -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.setNode = function (el) {
25
- _this.node = el;
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
- this.focusTrap = this.props._createFocusTrap(this.node, tailoredFocusTrapOptions);
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.focusTrap.deactivate();
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 elementProps = {
87
- ref: this.setNode
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
- // This will get id, className, style, etc. -- arbitrary element props
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 React.createElement(this.props.tag, elementProps, this.props.children);
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": "4.0.0",
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": "^3.0.0"
61
+ "focus-trap": "^4.0.2"
62
62
  },
63
63
  "peerDependencies": {
64
64
  "react": "0.14.x || ^15.0.0 || ^16.0.0",
@@ -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
- this.node,
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.focusTrap.deactivate();
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
- setNode = el => {
76
- this.node = el;
73
+ setFocusTrapElement = element => {
74
+ this.focusTrapElement = element;
77
75
  };
78
76
 
79
77
  render() {
80
- const elementProps = {
81
- ref: this.setNode
82
- };
78
+ const child = React.Children.only(this.props.children);
83
79
 
84
- // This will get id, className, style, etc. -- arbitrary element props
85
- for (const prop in this.props) {
86
- if (!this.props.hasOwnProperty(prop)) continue;
87
- if (checkedProps.indexOf(prop) !== -1) continue;
88
- elementProps[prop] = this.props[prop];
80
+ const composedRefCallback = element => {
81
+ this.setFocusTrapElement(element);
82
+ if (typeof child.ref === 'function') {
83
+ child.ref(element);
84
+ }
89
85
  }
90
86
 
91
- return React.createElement(
92
- this.props.tag,
93
- elementProps,
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