focus-trap-react 3.1.0 → 3.1.4
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/dist/focus-trap-react.js +9 -17
- package/index.d.ts +8 -8
- package/package.json +6 -1
- package/src/focus-trap-react.js +3 -1
- package/.eslintignore +0 -1
- package/.eslintrc +0 -20
- package/.travis.yml +0 -8
- package/CODE_OF_CONDUCT.md +0 -22
- package/demo/index.html +0 -74
- package/demo/js/demo-five.js +0 -61
- package/demo/js/demo-four.js +0 -76
- package/demo/js/demo-one.js +0 -68
- package/demo/js/demo-three.js +0 -72
- package/demo/js/demo-two.js +0 -75
- package/demo/js/index.js +0 -5
- package/demo/style.css +0 -28
- package/index.js +0 -95
- package/test/activation.test.js +0 -145
- package/test/deactivation.test.js +0 -103
- package/test/dom.test.js +0 -67
- package/test/jest-setup.js +0 -3
- package/yarn.lock +0 -4697
package/index.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
const React = require('react');
|
|
2
|
-
const PropTypes = require('prop-types');
|
|
3
|
-
const createFocusTrap = require('focus-trap');
|
|
4
|
-
|
|
5
|
-
const checkedProps = {
|
|
6
|
-
active: PropTypes.bool.isRequired,
|
|
7
|
-
paused: PropTypes.bool.isRequired,
|
|
8
|
-
tag: PropTypes.string.isRequired,
|
|
9
|
-
focusTrapOptions: PropTypes.object.isRequired,
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
class FocusTrap extends React.Component {
|
|
13
|
-
componentWillMount() {
|
|
14
|
-
if (typeof document !== 'undefined') {
|
|
15
|
-
this.previouslyFocusedElement = document.activeElement;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
componentDidMount() {
|
|
20
|
-
// We need to hijack the returnFocusOnDeactivate option,
|
|
21
|
-
// because React can move focus into the element before we arrived at
|
|
22
|
-
// this lifecycle hook (e.g. with autoFocus inputs). So the component
|
|
23
|
-
// captures the previouslyFocusedElement in componentWillMount,
|
|
24
|
-
// then (optionally) returns focus to it in componentWillUnmount.
|
|
25
|
-
const specifiedFocusTrapOptions = this.props.focusTrapOptions;
|
|
26
|
-
const tailoredFocusTrapOptions = {
|
|
27
|
-
returnFocusOnDeactivate: false,
|
|
28
|
-
};
|
|
29
|
-
for (const optionName in specifiedFocusTrapOptions) {
|
|
30
|
-
if (!specifiedFocusTrapOptions.hasOwnProperty(optionName)) continue;
|
|
31
|
-
if (optionName === 'returnFocusOnDeactivate') continue;
|
|
32
|
-
tailoredFocusTrapOptions[optionName] = specifiedFocusTrapOptions[optionName];
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
this.focusTrap = createFocusTrap(this.node, tailoredFocusTrapOptions);
|
|
36
|
-
if (this.props.active) {
|
|
37
|
-
this.focusTrap.activate();
|
|
38
|
-
}
|
|
39
|
-
if (this.props.paused) {
|
|
40
|
-
this.focusTrap.pause();
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
componentDidUpdate(prevProps) {
|
|
45
|
-
if (prevProps.active && !this.props.active) {
|
|
46
|
-
this.focusTrap.deactivate();
|
|
47
|
-
} else if (!prevProps.active && this.props.active) {
|
|
48
|
-
this.focusTrap.activate();
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (prevProps.paused && !this.props.paused) {
|
|
52
|
-
this.focusTrap.unpause();
|
|
53
|
-
} else if (!prevProps.paused && this.props.paused) {
|
|
54
|
-
this.focusTrap.pause();
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
componentWillUnmount() {
|
|
59
|
-
this.focusTrap.deactivate();
|
|
60
|
-
if (this.props.focusTrapOptions.returnFocusOnDeactivate !== false && this.previouslyFocusedElement) {
|
|
61
|
-
this.previouslyFocusedElement.focus();
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
render() {
|
|
66
|
-
const props = this.props;
|
|
67
|
-
|
|
68
|
-
const elementProps = {
|
|
69
|
-
ref: function(el) {
|
|
70
|
-
this.node = el;
|
|
71
|
-
}.bind(this),
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
// This will get id, className, style, etc. -- arbitrary element props
|
|
75
|
-
for (const prop in props) {
|
|
76
|
-
if (!props.hasOwnProperty(prop)) continue;
|
|
77
|
-
if (checkedProps[prop]) continue;
|
|
78
|
-
elementProps[prop] = props[prop];
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return React.createElement(this.props.tag, elementProps, this.props.children);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
FocusTrap.propTypes = checkedProps;
|
|
87
|
-
|
|
88
|
-
FocusTrap.defaultProps = {
|
|
89
|
-
active: true,
|
|
90
|
-
tag: 'div',
|
|
91
|
-
paused: false,
|
|
92
|
-
focusTrapOptions: {},
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
module.exports = FocusTrap;
|
package/test/activation.test.js
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
const React = require('react');
|
|
2
|
-
const ReactDOM = require('react-dom');
|
|
3
|
-
const TestUtils = require('react-dom/test-utils');
|
|
4
|
-
const FocusTrap = require('../dist/focus-trap-react');
|
|
5
|
-
|
|
6
|
-
describe('activation', () => {
|
|
7
|
-
let domContainer;
|
|
8
|
-
const mockFocusTrap = {
|
|
9
|
-
activate: jest.fn(),
|
|
10
|
-
deactivate: jest.fn(),
|
|
11
|
-
pause: jest.fn()
|
|
12
|
-
};
|
|
13
|
-
let mockCreateFocusTrap;
|
|
14
|
-
|
|
15
|
-
beforeEach(() => {
|
|
16
|
-
mockCreateFocusTrap = jest.fn(() => mockFocusTrap);
|
|
17
|
-
domContainer = document.createElement('div');
|
|
18
|
-
document.body.appendChild(domContainer);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
afterEach(() => {
|
|
22
|
-
ReactDOM.unmountComponentAtNode(domContainer);
|
|
23
|
-
document.body.removeChild(domContainer);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
test('default activation', () => {
|
|
27
|
-
const trap = ReactDOM.render(
|
|
28
|
-
<FocusTrap
|
|
29
|
-
_createFocusTrap={mockCreateFocusTrap}
|
|
30
|
-
focusTrapOptions={{ onDeactivate: noop }}
|
|
31
|
-
>
|
|
32
|
-
<button>
|
|
33
|
-
something special
|
|
34
|
-
</button>
|
|
35
|
-
</FocusTrap>,
|
|
36
|
-
domContainer
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
expect(mockCreateFocusTrap).toHaveBeenCalledTimes(1);
|
|
40
|
-
expect(mockCreateFocusTrap).toHaveBeenCalledWith(
|
|
41
|
-
ReactDOM.findDOMNode(trap),
|
|
42
|
-
{
|
|
43
|
-
onDeactivate: noop,
|
|
44
|
-
returnFocusOnDeactivate: false
|
|
45
|
-
}
|
|
46
|
-
);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test('activation with initialFocus as selector', () => {
|
|
50
|
-
const trap = ReactDOM.render(
|
|
51
|
-
<FocusTrap
|
|
52
|
-
_createFocusTrap={mockCreateFocusTrap}
|
|
53
|
-
focusTrapOptions={{
|
|
54
|
-
onDeactivate: noop,
|
|
55
|
-
initialFocus: '#initial-focusee'
|
|
56
|
-
}}
|
|
57
|
-
>
|
|
58
|
-
<button>
|
|
59
|
-
something special
|
|
60
|
-
</button>
|
|
61
|
-
<button id="initial-focusee">
|
|
62
|
-
another thing
|
|
63
|
-
</button>
|
|
64
|
-
</FocusTrap>,
|
|
65
|
-
domContainer
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
expect(mockCreateFocusTrap).toHaveBeenCalledTimes(1);
|
|
69
|
-
expect(mockCreateFocusTrap).toHaveBeenCalledWith(
|
|
70
|
-
ReactDOM.findDOMNode(trap),
|
|
71
|
-
{
|
|
72
|
-
onDeactivate: noop,
|
|
73
|
-
initialFocus: '#initial-focusee',
|
|
74
|
-
returnFocusOnDeactivate: false
|
|
75
|
-
}
|
|
76
|
-
);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
test('mounting without activation', () => {
|
|
80
|
-
ReactDOM.render(
|
|
81
|
-
<FocusTrap
|
|
82
|
-
_createFocusTrap={mockCreateFocusTrap}
|
|
83
|
-
focusTrapOptions={{ onDeactivate: noop }}
|
|
84
|
-
active={false}
|
|
85
|
-
>
|
|
86
|
-
<button>
|
|
87
|
-
something special
|
|
88
|
-
</button>
|
|
89
|
-
</FocusTrap>,
|
|
90
|
-
domContainer
|
|
91
|
-
);
|
|
92
|
-
expect(mockCreateFocusTrap).toHaveBeenCalledTimes(1);
|
|
93
|
-
expect(mockFocusTrap.activate).toHaveBeenCalledTimes(0);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
test('mounting without activation then activating', () => {
|
|
97
|
-
class TestZone extends React.Component {
|
|
98
|
-
state = {
|
|
99
|
-
trapActive: false
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
activateTrap = () => {
|
|
103
|
-
this.setState({ trapActive: true });
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
render() {
|
|
107
|
-
return (
|
|
108
|
-
<div>
|
|
109
|
-
<button ref="trigger" onClick={this.activateTrap}>
|
|
110
|
-
activate
|
|
111
|
-
</button>
|
|
112
|
-
<FocusTrap
|
|
113
|
-
_createFocusTrap={mockCreateFocusTrap}
|
|
114
|
-
ref="trap"
|
|
115
|
-
focusTrapOptions={{ onDeactivate: noop }}
|
|
116
|
-
active={this.state.trapActive}
|
|
117
|
-
>
|
|
118
|
-
<button>
|
|
119
|
-
something special
|
|
120
|
-
</button>
|
|
121
|
-
</FocusTrap>
|
|
122
|
-
</div>
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const zone = ReactDOM.render(<TestZone />, domContainer);
|
|
128
|
-
|
|
129
|
-
expect(mockCreateFocusTrap).toHaveBeenCalledTimes(1);
|
|
130
|
-
expect(mockCreateFocusTrap).toHaveBeenCalledWith(
|
|
131
|
-
ReactDOM.findDOMNode(zone.refs.trap),
|
|
132
|
-
{
|
|
133
|
-
onDeactivate: noop,
|
|
134
|
-
returnFocusOnDeactivate: false
|
|
135
|
-
}
|
|
136
|
-
);
|
|
137
|
-
expect(mockFocusTrap.activate).toHaveBeenCalledTimes(0);
|
|
138
|
-
|
|
139
|
-
TestUtils.Simulate.click(ReactDOM.findDOMNode(zone.refs.trigger));
|
|
140
|
-
|
|
141
|
-
expect(mockFocusTrap.activate).toHaveBeenCalledTimes(1);
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
function noop() {}
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
const React = require('react');
|
|
2
|
-
const ReactDOM = require('react-dom');
|
|
3
|
-
const TestUtils = require('react-dom/test-utils');
|
|
4
|
-
const FocusTrap = require('../dist/focus-trap-react');
|
|
5
|
-
|
|
6
|
-
describe('deactivation', () => {
|
|
7
|
-
let domContainer;
|
|
8
|
-
const mockFocusTrap = {
|
|
9
|
-
activate: jest.fn(),
|
|
10
|
-
deactivate: jest.fn(),
|
|
11
|
-
pause: jest.fn()
|
|
12
|
-
};
|
|
13
|
-
let mockCreateFocusTrap;
|
|
14
|
-
|
|
15
|
-
beforeEach(() => {
|
|
16
|
-
mockCreateFocusTrap = jest.fn(() => mockFocusTrap);
|
|
17
|
-
domContainer = document.createElement('div');
|
|
18
|
-
document.body.appendChild(domContainer);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
afterEach(() => {
|
|
22
|
-
ReactDOM.unmountComponentAtNode(domContainer);
|
|
23
|
-
document.body.removeChild(domContainer);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
test('deactivation', () => {
|
|
27
|
-
class TestZone extends React.Component {
|
|
28
|
-
state = {
|
|
29
|
-
trapActive: true
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
deactivateTrap = () => {
|
|
33
|
-
this.setState({ trapActive: false });
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
render() {
|
|
37
|
-
return (
|
|
38
|
-
<div>
|
|
39
|
-
<button ref="trigger" onClick={this.deactivateTrap}>
|
|
40
|
-
deactivate
|
|
41
|
-
</button>
|
|
42
|
-
<FocusTrap
|
|
43
|
-
ref="trap"
|
|
44
|
-
_createFocusTrap={mockCreateFocusTrap}
|
|
45
|
-
active={this.state.trapActive}
|
|
46
|
-
>
|
|
47
|
-
<button>
|
|
48
|
-
something special
|
|
49
|
-
</button>
|
|
50
|
-
</FocusTrap>
|
|
51
|
-
</div>
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const zone = ReactDOM.render(<TestZone />, domContainer);
|
|
57
|
-
|
|
58
|
-
expect(mockFocusTrap.deactivate).toHaveBeenCalledTimes(0);
|
|
59
|
-
|
|
60
|
-
TestUtils.Simulate.click(ReactDOM.findDOMNode(zone.refs.trigger));
|
|
61
|
-
|
|
62
|
-
expect(mockFocusTrap.deactivate).toHaveBeenCalledTimes(1);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
test('deactivation by dismount', () => {
|
|
66
|
-
class TestZone extends React.Component {
|
|
67
|
-
state = {
|
|
68
|
-
trapActive: true
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
deactivateTrap = () => {
|
|
72
|
-
this.setState({ trapActive: false });
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
render() {
|
|
76
|
-
const trap = this.state.trapActive
|
|
77
|
-
? <FocusTrap _createFocusTrap={mockCreateFocusTrap} ref="trap">
|
|
78
|
-
<button>
|
|
79
|
-
something special
|
|
80
|
-
</button>
|
|
81
|
-
</FocusTrap>
|
|
82
|
-
: false;
|
|
83
|
-
|
|
84
|
-
return (
|
|
85
|
-
<div>
|
|
86
|
-
<button ref="trigger" onClick={this.deactivateTrap}>
|
|
87
|
-
deactivate
|
|
88
|
-
</button>
|
|
89
|
-
{trap}
|
|
90
|
-
</div>
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const zone = ReactDOM.render(<TestZone />, domContainer);
|
|
96
|
-
|
|
97
|
-
expect(mockFocusTrap.deactivate).toHaveBeenCalledTimes(0);
|
|
98
|
-
|
|
99
|
-
TestUtils.Simulate.click(ReactDOM.findDOMNode(zone.refs.trigger));
|
|
100
|
-
|
|
101
|
-
expect(mockFocusTrap.deactivate).toHaveBeenCalledTimes(1);
|
|
102
|
-
});
|
|
103
|
-
});
|
package/test/dom.test.js
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
const React = require('react');
|
|
2
|
-
const ReactDOM = require('react-dom');
|
|
3
|
-
const TestUtils = require('react-dom/test-utils');
|
|
4
|
-
const FocusTrap = require('../dist/focus-trap-react');
|
|
5
|
-
|
|
6
|
-
describe('dom', () => {
|
|
7
|
-
let domContainer;
|
|
8
|
-
const mockFocusTrap = {
|
|
9
|
-
activate: jest.fn(),
|
|
10
|
-
deactivate: jest.fn(),
|
|
11
|
-
pause: jest.fn()
|
|
12
|
-
};
|
|
13
|
-
let mockCreateFocusTrap;
|
|
14
|
-
|
|
15
|
-
beforeEach(() => {
|
|
16
|
-
mockCreateFocusTrap = jest.fn(() => mockFocusTrap);
|
|
17
|
-
domContainer = document.createElement('div');
|
|
18
|
-
document.body.appendChild(domContainer);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
afterEach(() => {
|
|
22
|
-
ReactDOM.unmountComponentAtNode(domContainer);
|
|
23
|
-
document.body.removeChild(domContainer);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
test('DOM with only required props', () => {
|
|
27
|
-
const trap = TestUtils.renderIntoDocument(
|
|
28
|
-
<FocusTrap _createFocusTrap={mockCreateFocusTrap}>
|
|
29
|
-
<button>
|
|
30
|
-
something special
|
|
31
|
-
</button>
|
|
32
|
-
</FocusTrap>
|
|
33
|
-
);
|
|
34
|
-
const trapNode = ReactDOM.findDOMNode(trap);
|
|
35
|
-
|
|
36
|
-
expect(trapNode.tagName).toBe('DIV');
|
|
37
|
-
expect(trapNode.getAttribute('id')).toBe(null);
|
|
38
|
-
expect(trapNode.getAttribute('class')).toBe(null);
|
|
39
|
-
expect(trapNode.getAttribute('style')).toBe(null);
|
|
40
|
-
expect(trapNode.children.length).toBe(1);
|
|
41
|
-
expect(trapNode.firstChild.tagName).toBe('BUTTON');
|
|
42
|
-
expect(trapNode.firstChild.innerHTML).toBe('something special');
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
test('DOM with all possible DOM-related props', () => {
|
|
46
|
-
const trap = TestUtils.renderIntoDocument(
|
|
47
|
-
<FocusTrap
|
|
48
|
-
_createFocusTrap={mockCreateFocusTrap}
|
|
49
|
-
id="foo"
|
|
50
|
-
className="bar"
|
|
51
|
-
tag="figure"
|
|
52
|
-
>
|
|
53
|
-
<button>
|
|
54
|
-
something special
|
|
55
|
-
</button>
|
|
56
|
-
</FocusTrap>
|
|
57
|
-
);
|
|
58
|
-
const trapNode = ReactDOM.findDOMNode(trap);
|
|
59
|
-
|
|
60
|
-
expect(trapNode.tagName).toBe('FIGURE');
|
|
61
|
-
expect(trapNode.getAttribute('id')).toBe('foo');
|
|
62
|
-
expect(trapNode.getAttribute('class')).toBe('bar');
|
|
63
|
-
expect(trapNode.children.length).toBe(1);
|
|
64
|
-
expect(trapNode.firstChild.tagName).toBe('BUTTON');
|
|
65
|
-
expect(trapNode.firstChild.innerHTML).toBe('something special');
|
|
66
|
-
});
|
|
67
|
-
});
|
package/test/jest-setup.js
DELETED