react-aria-menubutton 7.0.3 → 8.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/README.md +140 -122
- package/dist/index.d.ts +59 -0
- package/dist/react-aria-menubutton.cjs.js +1 -0
- package/dist/react-aria-menubutton.es.js +566 -0
- package/dist/react-aria-menubutton.umd.js +1 -0
- package/package.json +62 -57
- package/CHANGELOG.md +0 -176
- package/CODE_OF_CONDUCT.md +0 -22
- package/dist/Button.js +0 -140
- package/dist/ManagerContext.js +0 -7
- package/dist/Menu.js +0 -131
- package/dist/MenuItem.js +0 -96
- package/dist/Wrapper.js +0 -74
- package/dist/createManager.js +0 -163
- package/dist/externalStateControl.js +0 -32
- package/dist/index.js +0 -12
- package/dist/propTypes.js +0 -7
- package/dist/specialAssign.js +0 -11
- package/src/Button.js +0 -129
- package/src/ManagerContext.js +0 -5
- package/src/Menu.js +0 -118
- package/src/MenuItem.js +0 -84
- package/src/Wrapper.js +0 -62
- package/src/__tests__/Button.test.js +0 -169
- package/src/__tests__/Menu.test.js +0 -130
- package/src/__tests__/MenuItem.test.js +0 -106
- package/src/__tests__/__snapshots__/Button.test.js.snap +0 -41
- package/src/__tests__/__snapshots__/Menu.test.js.snap +0 -54
- package/src/__tests__/__snapshots__/MenuItem.test.js.snap +0 -37
- package/src/__tests__/createManager.test.js +0 -190
- package/src/__tests__/helpers/MockWrapper.js +0 -24
- package/src/__tests__/helpers/createMockKeyEvent.js +0 -7
- package/src/__tests__/helpers/createMockManager.js +0 -22
- package/src/__tests__/helpers/jest-setup.js +0 -5
- package/src/__tests__/helpers/raf.js +0 -3
- package/src/createManager.js +0 -173
- package/src/externalStateControl.js +0 -31
- package/src/index.js +0 -10
- package/src/propTypes.js +0 -8
- package/src/specialAssign.js +0 -9
- package/umd/ReactAriaMenuButton.js +0 -1
- package/webpack-demo.config.js +0 -14
- package/webpack-umd.config.js +0 -35
package/dist/MenuItem.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
4
|
-
|
|
5
|
-
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
|
6
|
-
|
|
7
|
-
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; }
|
|
8
|
-
|
|
9
|
-
var React = require('react');
|
|
10
|
-
var PropTypes = require('prop-types');
|
|
11
|
-
var ManagerContext = require('./ManagerContext');
|
|
12
|
-
|
|
13
|
-
var _require = require("./propTypes"),
|
|
14
|
-
refType = _require.refType;
|
|
15
|
-
|
|
16
|
-
var specialAssign = require('./specialAssign');
|
|
17
|
-
|
|
18
|
-
var checkedProps = {
|
|
19
|
-
ambManager: PropTypes.object.isRequired,
|
|
20
|
-
children: PropTypes.node.isRequired,
|
|
21
|
-
forwardedRef: refType,
|
|
22
|
-
tag: PropTypes.string,
|
|
23
|
-
text: PropTypes.string,
|
|
24
|
-
value: PropTypes.any
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
var AriaMenuButtonMenuItem = function (_React$Component) {
|
|
28
|
-
_inherits(AriaMenuButtonMenuItem, _React$Component);
|
|
29
|
-
|
|
30
|
-
function AriaMenuButtonMenuItem() {
|
|
31
|
-
var _temp, _this, _ret;
|
|
32
|
-
|
|
33
|
-
_classCallCheck(this, AriaMenuButtonMenuItem);
|
|
34
|
-
|
|
35
|
-
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
|
36
|
-
args[_key] = arguments[_key];
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return _ret = (_temp = (_this = _possibleConstructorReturn(this, _React$Component.call.apply(_React$Component, [this].concat(args))), _this), _this.ref = React.createRef(), _this.handleKeyDown = function (event) {
|
|
40
|
-
if (event.key !== 'Enter' && event.key !== ' ') return;
|
|
41
|
-
if (_this.props.tag === 'a' && _this.props.href) return;
|
|
42
|
-
event.preventDefault();
|
|
43
|
-
_this.selectItem(event);
|
|
44
|
-
}, _this.selectItem = function (event) {
|
|
45
|
-
// If there's no value, we'll send the child
|
|
46
|
-
var value = typeof _this.props.value !== 'undefined' ? _this.props.value : _this.props.children;
|
|
47
|
-
_this.props.ambManager.handleSelection(value, event);
|
|
48
|
-
}, _this.setRef = function (instance) {
|
|
49
|
-
_this.ref.current = instance;
|
|
50
|
-
if (typeof _this.props.forwardedRef === "function") {
|
|
51
|
-
_this.props.forwardedRef(instance);
|
|
52
|
-
} else if (_this.props.forwardedRef) {
|
|
53
|
-
_this.props.forwardedRef.current = instance;
|
|
54
|
-
}
|
|
55
|
-
}, _temp), _possibleConstructorReturn(_this, _ret);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
AriaMenuButtonMenuItem.prototype.componentDidMount = function componentDidMount() {
|
|
59
|
-
this.props.ambManager.addItem({
|
|
60
|
-
node: this.ref.current,
|
|
61
|
-
text: this.props.text
|
|
62
|
-
});
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
AriaMenuButtonMenuItem.prototype.render = function render() {
|
|
66
|
-
var menuItemProps = {
|
|
67
|
-
onClick: this.selectItem,
|
|
68
|
-
onKeyDown: this.handleKeyDown,
|
|
69
|
-
role: 'menuitem',
|
|
70
|
-
tabIndex: '-1',
|
|
71
|
-
ref: this.setRef
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
specialAssign(menuItemProps, this.props, checkedProps);
|
|
75
|
-
|
|
76
|
-
return React.createElement(this.props.tag, menuItemProps, this.props.children);
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
return AriaMenuButtonMenuItem;
|
|
80
|
-
}(React.Component);
|
|
81
|
-
|
|
82
|
-
AriaMenuButtonMenuItem.propTypes = checkedProps;
|
|
83
|
-
AriaMenuButtonMenuItem.defaultProps = { tag: 'div' };
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
module.exports = React.forwardRef(function (props, ref) {
|
|
87
|
-
return React.createElement(ManagerContext.Consumer, null, function (ambManager) {
|
|
88
|
-
var buttonProps = { ambManager: ambManager, forwardedRef: ref };
|
|
89
|
-
specialAssign(buttonProps, props, {
|
|
90
|
-
ambManager: checkedProps.ambManager,
|
|
91
|
-
children: checkedProps.children,
|
|
92
|
-
forwardedRef: checkedProps.forwardedRef
|
|
93
|
-
});
|
|
94
|
-
return React.createElement(AriaMenuButtonMenuItem, buttonProps, props.children);
|
|
95
|
-
});
|
|
96
|
-
});
|
package/dist/Wrapper.js
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
4
|
-
|
|
5
|
-
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
|
6
|
-
|
|
7
|
-
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; }
|
|
8
|
-
|
|
9
|
-
var React = require('react');
|
|
10
|
-
var PropTypes = require('prop-types');
|
|
11
|
-
var createManager = require('./createManager');
|
|
12
|
-
var ManagerContext = require('./ManagerContext');
|
|
13
|
-
|
|
14
|
-
var _require = require("./propTypes"),
|
|
15
|
-
refType = _require.refType;
|
|
16
|
-
|
|
17
|
-
var specialAssign = require('./specialAssign');
|
|
18
|
-
|
|
19
|
-
var checkedProps = {
|
|
20
|
-
children: PropTypes.node.isRequired,
|
|
21
|
-
forwardedRef: refType,
|
|
22
|
-
onMenuToggle: PropTypes.func,
|
|
23
|
-
onSelection: PropTypes.func,
|
|
24
|
-
closeOnSelection: PropTypes.bool,
|
|
25
|
-
closeOnBlur: PropTypes.bool,
|
|
26
|
-
tag: PropTypes.string
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
var managerOptionsFromProps = function managerOptionsFromProps(props) {
|
|
30
|
-
return {
|
|
31
|
-
onMenuToggle: props.onMenuToggle,
|
|
32
|
-
onSelection: props.onSelection,
|
|
33
|
-
closeOnSelection: props.closeOnSelection,
|
|
34
|
-
closeOnBlur: props.closeOnBlur,
|
|
35
|
-
id: props.id
|
|
36
|
-
};
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
var AriaMenuButtonWrapper = function (_React$Component) {
|
|
40
|
-
_inherits(AriaMenuButtonWrapper, _React$Component);
|
|
41
|
-
|
|
42
|
-
function AriaMenuButtonWrapper(props) {
|
|
43
|
-
_classCallCheck(this, AriaMenuButtonWrapper);
|
|
44
|
-
|
|
45
|
-
var _this = _possibleConstructorReturn(this, _React$Component.call(this, props));
|
|
46
|
-
|
|
47
|
-
_this.manager = createManager(managerOptionsFromProps(props));
|
|
48
|
-
return _this;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
AriaMenuButtonWrapper.prototype.componentDidUpdate = function componentDidUpdate() {
|
|
52
|
-
this.manager.updateOptions(managerOptionsFromProps(this.props));
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
AriaMenuButtonWrapper.prototype.render = function render() {
|
|
56
|
-
var wrapperProps = {};
|
|
57
|
-
specialAssign(wrapperProps, this.props, checkedProps);
|
|
58
|
-
|
|
59
|
-
return React.createElement(ManagerContext.Provider, { value: this.manager }, React.createElement(this.props.tag, wrapperProps, this.props.children));
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
return AriaMenuButtonWrapper;
|
|
63
|
-
}(React.Component);
|
|
64
|
-
|
|
65
|
-
AriaMenuButtonWrapper.propTypes = checkedProps;
|
|
66
|
-
AriaMenuButtonWrapper.defaultProps = { tag: 'div' };
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
module.exports = React.forwardRef(function (props, ref) {
|
|
70
|
-
var wrapperProps = { forwardedRef: ref };
|
|
71
|
-
specialAssign(wrapperProps, props, { children: checkedProps.children, forwardedRef: checkedProps.forwardedRef });
|
|
72
|
-
specialAssign(wrapperProps, { forwardedRef: ref });
|
|
73
|
-
return React.createElement(AriaMenuButtonWrapper, wrapperProps, props.children);
|
|
74
|
-
});
|
package/dist/createManager.js
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var createFocusGroup = require('focus-group');
|
|
4
|
-
var externalStateControl = require('./externalStateControl');
|
|
5
|
-
|
|
6
|
-
var focusGroupOptions = {
|
|
7
|
-
wrap: true,
|
|
8
|
-
stringSearch: true
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
var protoManager = {
|
|
12
|
-
init: function init(options) {
|
|
13
|
-
this.updateOptions(options);
|
|
14
|
-
|
|
15
|
-
this.handleBlur = handleBlur.bind(this);
|
|
16
|
-
this.handleSelection = handleSelection.bind(this);
|
|
17
|
-
this.handleMenuKey = handleMenuKey.bind(this);
|
|
18
|
-
|
|
19
|
-
// "With focus on the drop-down menu, the Up and Down Arrow
|
|
20
|
-
// keys move focus within the menu items, "wrapping" at the top and bottom."
|
|
21
|
-
// "Typing a letter (printable character) key moves focus to the next
|
|
22
|
-
// instance of a visible node whose title begins with that printable letter."
|
|
23
|
-
//
|
|
24
|
-
// All of the above is handled by focus-group.
|
|
25
|
-
this.focusGroup = createFocusGroup(focusGroupOptions);
|
|
26
|
-
|
|
27
|
-
// These component references are added when the relevant components mount
|
|
28
|
-
this.button = null;
|
|
29
|
-
this.menu = null;
|
|
30
|
-
|
|
31
|
-
// State trackers
|
|
32
|
-
this.isOpen = false;
|
|
33
|
-
},
|
|
34
|
-
updateOptions: function updateOptions(options) {
|
|
35
|
-
var oldOptions = this.options;
|
|
36
|
-
|
|
37
|
-
this.options = options || this.options || {};
|
|
38
|
-
|
|
39
|
-
if (typeof this.options.closeOnSelection === 'undefined') {
|
|
40
|
-
this.options.closeOnSelection = true;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (typeof this.options.closeOnBlur === 'undefined') {
|
|
44
|
-
this.options.closeOnBlur = true;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (this.options.id) {
|
|
48
|
-
externalStateControl.registerManager(this.options.id, this);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (oldOptions && oldOptions.id && oldOptions.id !== this.options.id) {
|
|
52
|
-
externalStateControl.unregisterManager(this.options.id, this);
|
|
53
|
-
}
|
|
54
|
-
},
|
|
55
|
-
focusItem: function focusItem(index) {
|
|
56
|
-
this.focusGroup.focusNodeAtIndex(index);
|
|
57
|
-
},
|
|
58
|
-
addItem: function addItem(item) {
|
|
59
|
-
this.focusGroup.addMember(item);
|
|
60
|
-
},
|
|
61
|
-
clearItems: function clearItems() {
|
|
62
|
-
this.focusGroup.clearMembers();
|
|
63
|
-
},
|
|
64
|
-
handleButtonNonArrowKey: function handleButtonNonArrowKey(event) {
|
|
65
|
-
this.focusGroup._handleUnboundKey(event);
|
|
66
|
-
},
|
|
67
|
-
destroy: function destroy() {
|
|
68
|
-
this.button = null;
|
|
69
|
-
this.menu = null;
|
|
70
|
-
this.focusGroup.deactivate();
|
|
71
|
-
clearTimeout(this.blurTimer);
|
|
72
|
-
clearTimeout(this.moveFocusTimer);
|
|
73
|
-
},
|
|
74
|
-
update: function update() {
|
|
75
|
-
this.menu.setState({ isOpen: this.isOpen });
|
|
76
|
-
this.button.setState({ menuOpen: this.isOpen });
|
|
77
|
-
this.options.onMenuToggle && this.options.onMenuToggle({ isOpen: this.isOpen });
|
|
78
|
-
},
|
|
79
|
-
openMenu: function openMenu(openOptions) {
|
|
80
|
-
if (this.isOpen) return;
|
|
81
|
-
openOptions = openOptions || {};
|
|
82
|
-
if (openOptions.focusMenu === undefined) {
|
|
83
|
-
openOptions.focusMenu = true;
|
|
84
|
-
}
|
|
85
|
-
this.isOpen = true;
|
|
86
|
-
this.update();
|
|
87
|
-
this.focusGroup.activate();
|
|
88
|
-
if (openOptions.focusMenu) {
|
|
89
|
-
var self = this;
|
|
90
|
-
this.moveFocusTimer = setTimeout(function () {
|
|
91
|
-
self.focusItem(0);
|
|
92
|
-
}, 0);
|
|
93
|
-
}
|
|
94
|
-
},
|
|
95
|
-
closeMenu: function closeMenu(closeOptions) {
|
|
96
|
-
if (!this.isOpen) return;
|
|
97
|
-
closeOptions = closeOptions || {};
|
|
98
|
-
this.isOpen = false;
|
|
99
|
-
this.update();
|
|
100
|
-
if (closeOptions.focusButton) {
|
|
101
|
-
this.button.ref.current.focus();
|
|
102
|
-
}
|
|
103
|
-
},
|
|
104
|
-
toggleMenu: function toggleMenu(closeOptions, openOptions) {
|
|
105
|
-
closeOptions = closeOptions || {};
|
|
106
|
-
openOptions = openOptions || {};
|
|
107
|
-
if (this.isOpen) {
|
|
108
|
-
this.closeMenu(closeOptions);
|
|
109
|
-
} else {
|
|
110
|
-
this.openMenu(openOptions);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
function handleBlur() {
|
|
116
|
-
var self = this;
|
|
117
|
-
self.blurTimer = setTimeout(function () {
|
|
118
|
-
if (!self.button) return;
|
|
119
|
-
var buttonNode = self.button.ref.current;
|
|
120
|
-
if (!buttonNode) return;
|
|
121
|
-
var activeEl = buttonNode.ownerDocument.activeElement;
|
|
122
|
-
if (buttonNode && activeEl === buttonNode) return;
|
|
123
|
-
var menuNode = self.menu.ref.current;
|
|
124
|
-
if (menuNode === activeEl) {
|
|
125
|
-
self.focusItem(0);
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
if (menuNode && menuNode.contains(activeEl)) return;
|
|
129
|
-
if (self.isOpen) self.closeMenu({ focusButton: false });
|
|
130
|
-
}, 0);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function handleSelection(value, event) {
|
|
134
|
-
if (this.options.closeOnSelection) this.closeMenu({ focusButton: true });
|
|
135
|
-
if (this.options.onSelection) this.options.onSelection(value, event);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function handleMenuKey(event) {
|
|
139
|
-
if (this.isOpen) {
|
|
140
|
-
switch (event.key) {
|
|
141
|
-
// With focus on the drop-down menu, pressing Escape closes
|
|
142
|
-
// the menu and returns focus to the button.
|
|
143
|
-
case 'Escape':
|
|
144
|
-
event.preventDefault();
|
|
145
|
-
this.closeMenu({ focusButton: true });
|
|
146
|
-
break;
|
|
147
|
-
case 'Home':
|
|
148
|
-
event.preventDefault();
|
|
149
|
-
this.focusGroup.moveFocusToFirst();
|
|
150
|
-
break;
|
|
151
|
-
case 'End':
|
|
152
|
-
event.preventDefault();
|
|
153
|
-
this.focusGroup.moveFocusToLast();
|
|
154
|
-
break;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
module.exports = function (options) {
|
|
160
|
-
var newManager = Object.create(protoManager);
|
|
161
|
-
newManager.init(options);
|
|
162
|
-
return newManager;
|
|
163
|
-
};
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var registeredManagers = {};
|
|
4
|
-
|
|
5
|
-
var errorCommon = 'a menu outside a mounted Wrapper with an id, or a menu that does not exist';
|
|
6
|
-
|
|
7
|
-
function registerManager(menuId, manager) {
|
|
8
|
-
registeredManagers[menuId] = manager;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function unregisterManager(menuId) {
|
|
12
|
-
delete registeredManagers[menuId];
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function openMenu(menuId, openOptions) {
|
|
16
|
-
var manager = registeredManagers[menuId];
|
|
17
|
-
if (!manager) throw new Error('Cannot open ' + errorCommon);
|
|
18
|
-
manager.openMenu(openOptions);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function closeMenu(menuId, closeOptions) {
|
|
22
|
-
var manager = registeredManagers[menuId];
|
|
23
|
-
if (!manager) throw new Error('Cannot close ' + errorCommon);
|
|
24
|
-
manager.closeMenu(closeOptions);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
module.exports = {
|
|
28
|
-
registerManager: registerManager,
|
|
29
|
-
unregisterManager: unregisterManager,
|
|
30
|
-
openMenu: openMenu,
|
|
31
|
-
closeMenu: closeMenu
|
|
32
|
-
};
|
package/dist/index.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var externalStateControl = require('./externalStateControl');
|
|
4
|
-
|
|
5
|
-
module.exports = {
|
|
6
|
-
Wrapper: require('./Wrapper'),
|
|
7
|
-
Button: require('./Button'),
|
|
8
|
-
Menu: require('./Menu'),
|
|
9
|
-
MenuItem: require('./MenuItem'),
|
|
10
|
-
openMenu: externalStateControl.openMenu,
|
|
11
|
-
closeMenu: externalStateControl.closeMenu
|
|
12
|
-
};
|
package/dist/propTypes.js
DELETED
package/dist/specialAssign.js
DELETED
package/src/Button.js
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
const React = require('react');
|
|
2
|
-
const PropTypes = require('prop-types');
|
|
3
|
-
const ManagerContext = require('./ManagerContext');
|
|
4
|
-
const { refType } = require("./propTypes");
|
|
5
|
-
const specialAssign = require('./specialAssign');
|
|
6
|
-
|
|
7
|
-
const checkedProps = {
|
|
8
|
-
ambManager: PropTypes.object.isRequired,
|
|
9
|
-
children: PropTypes.node.isRequired,
|
|
10
|
-
disabled: PropTypes.bool,
|
|
11
|
-
forwardedRef: refType,
|
|
12
|
-
tag: PropTypes.string
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
// List retrieved from https://www.w3schools.com/tags/att_disabled.asp
|
|
16
|
-
const disabledSupportedTags = () => [
|
|
17
|
-
'button',
|
|
18
|
-
'fieldset',
|
|
19
|
-
'input',
|
|
20
|
-
'optgroup',
|
|
21
|
-
'option',
|
|
22
|
-
'select',
|
|
23
|
-
'textarea'
|
|
24
|
-
];
|
|
25
|
-
|
|
26
|
-
class AriaMenuButtonButton extends React.Component {
|
|
27
|
-
static propTypes = checkedProps;
|
|
28
|
-
|
|
29
|
-
static defaultProps = { tag: 'span' };
|
|
30
|
-
|
|
31
|
-
ref = React.createRef();
|
|
32
|
-
|
|
33
|
-
componentDidMount() {
|
|
34
|
-
this.props.ambManager.button = this;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
componentWillUnmount() {
|
|
38
|
-
this.props.ambManager.destroy();
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
handleKeyDown = event => {
|
|
42
|
-
if (this.props.disabled) return;
|
|
43
|
-
|
|
44
|
-
const ambManager = this.props.ambManager;
|
|
45
|
-
|
|
46
|
-
switch (event.key) {
|
|
47
|
-
case 'ArrowDown':
|
|
48
|
-
event.preventDefault();
|
|
49
|
-
if (!ambManager.isOpen) {
|
|
50
|
-
ambManager.openMenu();
|
|
51
|
-
} else {
|
|
52
|
-
ambManager.focusItem(0);
|
|
53
|
-
}
|
|
54
|
-
break;
|
|
55
|
-
case 'Enter':
|
|
56
|
-
case ' ':
|
|
57
|
-
event.preventDefault();
|
|
58
|
-
ambManager.toggleMenu();
|
|
59
|
-
break;
|
|
60
|
-
case 'Escape':
|
|
61
|
-
ambManager.handleMenuKey(event);
|
|
62
|
-
break;
|
|
63
|
-
default:
|
|
64
|
-
// (Potential) letter keys
|
|
65
|
-
ambManager.handleButtonNonArrowKey(event);
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
handleClick = () => {
|
|
70
|
-
if (this.props.disabled) return;
|
|
71
|
-
this.props.ambManager.toggleMenu({}, { focusMenu: false });
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
setRef = instance => {
|
|
75
|
-
this.ref.current = instance;
|
|
76
|
-
if (typeof this.props.forwardedRef === "function") {
|
|
77
|
-
this.props.forwardedRef(instance);
|
|
78
|
-
} else if (this.props.forwardedRef) {
|
|
79
|
-
this.props.forwardedRef.current = instance;
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
render() {
|
|
84
|
-
const props = this.props;
|
|
85
|
-
const ambManager = this.props.ambManager;
|
|
86
|
-
|
|
87
|
-
const buttonProps = {
|
|
88
|
-
// "The menu button itself has a role of button."
|
|
89
|
-
role: 'button',
|
|
90
|
-
tabIndex: props.disabled ? '' : '0',
|
|
91
|
-
// "The menu button has an aria-haspopup property, set to true."
|
|
92
|
-
'aria-haspopup': true,
|
|
93
|
-
'aria-expanded': ambManager.isOpen,
|
|
94
|
-
'aria-disabled': props.disabled,
|
|
95
|
-
onKeyDown: this.handleKeyDown,
|
|
96
|
-
onClick: this.handleClick
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
const reserved = {};
|
|
100
|
-
specialAssign(reserved, checkedProps);
|
|
101
|
-
// The disabled property should be passed down to the Button element
|
|
102
|
-
// if the tag has support for disabled attribute. So it needs to be removed
|
|
103
|
-
// from the reserved property object
|
|
104
|
-
if (disabledSupportedTags().indexOf(props.tag) >= 0) {
|
|
105
|
-
delete reserved.disabled;
|
|
106
|
-
}
|
|
107
|
-
if (ambManager.options.closeOnBlur) {
|
|
108
|
-
buttonProps.onBlur = ambManager.handleBlur;
|
|
109
|
-
}
|
|
110
|
-
specialAssign(buttonProps, props, reserved);
|
|
111
|
-
specialAssign(buttonProps, { ref: this.setRef });
|
|
112
|
-
|
|
113
|
-
return React.createElement(props.tag, buttonProps, props.children);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
module.exports = React.forwardRef((props, ref) => React.createElement(
|
|
118
|
-
ManagerContext.Consumer,
|
|
119
|
-
null,
|
|
120
|
-
(ambManager) => {
|
|
121
|
-
const buttonProps = { ambManager, forwardedRef: ref };
|
|
122
|
-
specialAssign(buttonProps, props, {
|
|
123
|
-
ambManager: checkedProps.ambManager,
|
|
124
|
-
children: checkedProps.children,
|
|
125
|
-
forwardedRef: checkedProps.forwardedRef
|
|
126
|
-
});
|
|
127
|
-
return React.createElement(AriaMenuButtonButton, buttonProps, props.children);
|
|
128
|
-
}
|
|
129
|
-
));
|
package/src/ManagerContext.js
DELETED
package/src/Menu.js
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
const React = require('react');
|
|
2
|
-
const PropTypes = require('prop-types');
|
|
3
|
-
const createTapListener = require('teeny-tap');
|
|
4
|
-
const ManagerContext = require('./ManagerContext');
|
|
5
|
-
const { refType } = require("./propTypes");
|
|
6
|
-
const specialAssign = require('./specialAssign');
|
|
7
|
-
|
|
8
|
-
const checkedProps = {
|
|
9
|
-
ambManager: PropTypes.object.isRequired,
|
|
10
|
-
children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]).isRequired,
|
|
11
|
-
forwardedRef: refType,
|
|
12
|
-
tag: PropTypes.string
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
class AriaMenuButtonMenu extends React.Component {
|
|
16
|
-
static propTypes = checkedProps;
|
|
17
|
-
static defaultProps = { tag: 'div' };
|
|
18
|
-
|
|
19
|
-
ref = React.createRef();
|
|
20
|
-
|
|
21
|
-
componentDidMount() {
|
|
22
|
-
this.props.ambManager.menu = this;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
componentDidUpdate() {
|
|
26
|
-
const ambManager = this.props.ambManager;
|
|
27
|
-
if (!ambManager.options.closeOnBlur) return;
|
|
28
|
-
if (ambManager.isOpen && !this.tapListener) {
|
|
29
|
-
this.addTapListener();
|
|
30
|
-
} else if (!ambManager.isOpen && this.tapListener) {
|
|
31
|
-
this.tapListener.remove();
|
|
32
|
-
delete this.tapListener;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (!ambManager.isOpen) {
|
|
36
|
-
// Clear the ambManager's items, so they
|
|
37
|
-
// can be reloaded next time this menu opens
|
|
38
|
-
ambManager.clearItems();
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
componentWillUnmount() {
|
|
43
|
-
if (this.tapListener) this.tapListener.remove();
|
|
44
|
-
this.props.ambManager.destroy();
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
addTapListener = () => {
|
|
48
|
-
const el = this.ref.current;
|
|
49
|
-
if (!el) return;
|
|
50
|
-
const doc = el.ownerDocument;
|
|
51
|
-
if (!doc) return;
|
|
52
|
-
this.tapListener = createTapListener(doc.documentElement, this.handleTap);
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
handleTap = event => {
|
|
56
|
-
if (this.ref.current.contains(event.target)) return;
|
|
57
|
-
if (
|
|
58
|
-
this.props.ambManager.button.ref.current.contains(
|
|
59
|
-
event.target
|
|
60
|
-
)
|
|
61
|
-
)
|
|
62
|
-
return;
|
|
63
|
-
this.props.ambManager.closeMenu();
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
setRef = instance => {
|
|
67
|
-
this.ref.current = instance;
|
|
68
|
-
if (typeof this.props.forwardedRef === "function") {
|
|
69
|
-
this.props.forwardedRef(instance);
|
|
70
|
-
} else if (this.props.forwardedRef) {
|
|
71
|
-
this.props.forwardedRef.current = instance;
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
render() {
|
|
76
|
-
const props = this.props;
|
|
77
|
-
const ambManager = this.props.ambManager;
|
|
78
|
-
|
|
79
|
-
const childrenToRender = (function() {
|
|
80
|
-
if (typeof props.children === 'function') {
|
|
81
|
-
return props.children({ isOpen: ambManager.isOpen });
|
|
82
|
-
}
|
|
83
|
-
if (ambManager.isOpen) return props.children;
|
|
84
|
-
return false;
|
|
85
|
-
})();
|
|
86
|
-
|
|
87
|
-
if (!childrenToRender) return false;
|
|
88
|
-
|
|
89
|
-
const menuProps = {
|
|
90
|
-
onKeyDown: ambManager.handleMenuKey,
|
|
91
|
-
role: 'menu',
|
|
92
|
-
tabIndex: -1
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
if (ambManager.options.closeOnBlur) {
|
|
96
|
-
menuProps.onBlur = ambManager.handleBlur;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
specialAssign(menuProps, props, checkedProps);
|
|
100
|
-
specialAssign(menuProps, { ref: this.setRef });
|
|
101
|
-
|
|
102
|
-
return React.createElement(props.tag, menuProps, childrenToRender);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
module.exports = React.forwardRef((props, ref) => React.createElement(
|
|
107
|
-
ManagerContext.Consumer,
|
|
108
|
-
null,
|
|
109
|
-
(ambManager) => {
|
|
110
|
-
const buttonProps = { ambManager, forwardedRef: ref };
|
|
111
|
-
specialAssign(buttonProps, props, {
|
|
112
|
-
ambManager: checkedProps.ambManager,
|
|
113
|
-
children: checkedProps.children,
|
|
114
|
-
forwardedRef: checkedProps.forwardedRef
|
|
115
|
-
});
|
|
116
|
-
return React.createElement(AriaMenuButtonMenu, buttonProps, props.children);
|
|
117
|
-
}
|
|
118
|
-
));
|