@momentum-ui/react-collaboration
Version:
Cisco Momentum UI Framework for React Collaboration Applications
316 lines • 15.3 kB
JavaScript
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import omit from 'lodash/omit';
import mapContextToProps from '@restart/context/mapContextToProps';
import qsa from 'dom-helpers/query/querySelectorAll';
import { UIDReset } from 'react-uid';
import SelectableContext from '../SelectableContext';
import ListContext from '../ListContext';
import MenuContext from '../MenuContext';
/**
* @deprecated - Components in the legacy folder (/src/legacy) are deprecated. Please use a component from the components folder (/src/components) instead. Legacy components may not follow accessibility standards.
**/
var Menu = /** @class */ (function (_super) {
__extends(Menu, _super);
function Menu(props) {
var _this = _super.call(this, props) || this;
_this.getFocusableItems = function (node, selector) {
var defaultSelector = '.md-list-item:not(.disabled):not(:disabled)' + ':not(.md-list-item--read-only)';
return qsa(node, selector || defaultSelector);
};
_this.getIncludesFirstCharacter = function (str, char) { return str.charAt(0).toLowerCase().includes(char); };
_this.handleSelect = function (e, opts) {
var _a = _this.props, onSelect = _a.onSelect, parentOnSelect = _a.parentOnSelect;
var eventKey = opts.eventKey, element = opts.element;
var children = element.props.children;
_this._selectRefocus = true;
_this.setState(function (state) { return ({
activeElement: children ? element : null,
currentElements: children ? [eventKey] : [state.currentElements[0]],
listContext: __assign(__assign({}, state.listContext), { focus: children ? eventKey : state.currentElements[0], active: [eventKey] }),
}); }, function () {
onSelect && onSelect(e, { eventKey: eventKey, element: element });
parentOnSelect && parentOnSelect(e, { eventKey: eventKey, element: element });
});
};
_this.setFocus = function (child, isParent, isChild) {
var currentElements = _this.state.currentElements;
var getCurrentElements = function () {
if (isParent) {
return [child.attributes['data-md-event-key'].value];
}
else if (isChild) {
return currentElements.concat(child.attributes['data-md-event-key'].value);
}
else
null;
};
_this.setState(function (state) { return ({
currentElements: getCurrentElements(),
listContext: __assign(__assign({}, state.listContext), { focus: child.attributes['data-md-event-key'].value }),
}); });
};
_this.setFocusByFirstCharacter = function (element, char) {
var _a = _this.state, currentElements = _a.currentElements, listContext = _a.listContext;
var items = _this.getFocusableItems(element);
var focusIdx = (listContext.focus &&
items.indexOf(element.querySelector("[data-md-event-key=\"".concat(listContext.focus, "\"]")))) ||
0;
var length = (items.length && items.length - 1) || 0;
var newFocusKey = items.reduce(function (agg, item, idx, arr) {
var index = focusIdx + idx + 1 > length ? Math.abs(focusIdx + idx - length) : focusIdx + idx + 1;
return !agg &&
arr[index].attributes['data-md-keyboard-key'] &&
arr[index].attributes['data-md-keyboard-key'].value &&
_this.getIncludesFirstCharacter(arr[index].attributes['data-md-keyboard-key'].value, char)
? arr[index].attributes['data-md-event-key'].value
: agg;
}, null);
typeof newFocusKey === 'string' &&
newFocusKey !== focus &&
_this.setState(function (state) { return ({
currentElements: !currentElements.length
? __spreadArray([], newFocusKey, true) : __spreadArray(__spreadArray([], currentElements.slice(0, currentElements.length - 1), true), [newFocusKey], false),
listContext: __assign(__assign({}, state.listContext), { focus: newFocusKey }),
}); });
};
_this.handleKeyDown = function (e, opts) {
var element = opts.element;
var _a = _this.state, activeElement = _a.activeElement, currentElements = _a.currentElements;
var char = e.key;
var target = e.currentTarget;
var activeParent = activeElement
? qsa(ReactDOM.findDOMNode(activeElement), '.md-menu-item-container')[0]
: _this.menuNode;
var isPrintableCharacter = function (char) {
return char.length === 1 && char.match(/\S/);
};
var flag = false;
var stopImmediatePropagation = false;
switch (e.which) {
case 38: //up
_this.getNextFocusedChild(activeParent, target, -1);
flag = true;
break;
case 40: //down
_this.getNextFocusedChild(activeParent, target, 1);
flag = true;
break;
case 39: //right
element.constructor &&
element.constructor.displayName &&
element.constructor.displayName === 'SubMenu' &&
_this.handleSelect(e, opts);
flag = true;
break;
case 27:
case 37: //escape or left
if (currentElements.length - 1) {
stopImmediatePropagation = true;
_this.setState(function (state) { return ({
currentElements: state.currentElements.slice(0, currentElements.length - 1),
activeElement: null,
listContext: {
focus: state.currentElements.length
? state.currentElements[0]
: state.listContext.focus,
active: [],
},
}); });
}
flag = true;
break;
case 33:
case 36: //home or page up
_this.setFocusToLimit(activeParent, 'start');
flag = true;
break;
case 34:
case 35: //end or page down
_this.setFocusToLimit(activeParent, 'end');
flag = true;
break;
default:
if (isPrintableCharacter(char)) {
_this.setFocusByFirstCharacter(activeParent, char);
flag = true;
}
break;
}
if (flag) {
e.stopPropagation();
e.preventDefault();
stopImmediatePropagation && e.nativeEvent.stopImmediatePropagation();
}
};
_this.state = {
currentElements: null,
activeElement: null,
listContext: {
active: [],
focus: null,
ariaConfig: _this.props.ariaConfig,
},
selectContext: {
parentKeyDown: _this.handleKeyDown,
parentOnSelect: _this.handleSelect,
},
};
return _this;
}
Menu.prototype.componentDidMount = function () {
var menuItems = this.getFocusableItems(this.menuNode);
menuItems.length && this.setFocus(menuItems[0], true);
};
Menu.prototype.componentDidUpdate = function (prevProps, prevState) {
var _a;
if (!this.menuNode)
return;
var focusFirst = this.props.focusFirst;
var _b = this.state, activeElement = _b.activeElement, listContext = _b.listContext;
if (prevState.listContext !== listContext) {
if (activeElement && this._selectRefocus) {
var activeNode = [];
try {
activeNode = ReactDOM.findDOMNode(activeElement);
}
catch (error) {
activeNode = ReactDOM.findDOMNode(prevState.activeElement);
}
var overlayItems = this.getFocusableItems(activeNode, '.md-menu-item-container');
var items = overlayItems.length && this.getFocusableItems(overlayItems[0]);
this._selectRefocus = false;
items.length && this.setFocus(items[0], false, true);
}
else if (listContext.focus !== prevState.listContext.focus) {
if (!prevState.listContext.focus && !focusFirst) {
return;
}
(_a = this.menuNode.querySelector("[data-md-event-key=\"".concat(listContext.focus, "\"]"))) === null || _a === void 0 ? void 0 : _a.focus();
}
}
};
Menu.prototype.getNextFocusedChild = function (element, current, offset) {
if (!element)
return null;
var _a = this.state, currentElements = _a.currentElements, listContext = _a.listContext;
var items = this.getFocusableItems(element);
var possibleIndex = items.indexOf(current) + offset;
var getIndex = function () {
if (possibleIndex < 0) {
return items.length - 1;
}
else if (possibleIndex > items.length - 1) {
return 0;
}
else
return possibleIndex;
};
var newFocusKey = items[getIndex()].attributes['data-md-event-key'].value;
newFocusKey !== listContext.focus &&
this.setState({
currentElements: !currentElements.length
? __spreadArray([], newFocusKey, true) : __spreadArray(__spreadArray([], currentElements.slice(0, currentElements.length - 1), true), [newFocusKey], false),
listContext: __assign(__assign({}, listContext), { focus: newFocusKey }),
});
};
Menu.prototype.setFocusToLimit = function (element, target) {
if (!element)
return null;
var _a = this.state, currentElements = _a.currentElements, listContext = _a.listContext;
var items = this.getFocusableItems(element);
var newFocusKey = items[target === 'start' ? 0 : items.length - 1].attributes['data-md-event-key'].value;
newFocusKey !== listContext.focus &&
this.setState({
currentElements: !currentElements.length
? __spreadArray([], newFocusKey, true) : __spreadArray(__spreadArray([], currentElements.slice(0, currentElements.length - 1), true), [newFocusKey], false),
listContext: __assign(__assign({}, listContext), { focus: newFocusKey }),
});
};
Menu.prototype.render = function () {
var _this = this;
var _a = this.props, ariaLabel = _a.ariaLabel, children = _a.children, className = _a.className, props = __rest(_a, ["ariaLabel", "children", "className"]);
var _b = this.state, listContext = _b.listContext, selectContext = _b.selectContext;
var otherProps = omit(__assign({}, props), ['ariaConfig', 'focusFirst', 'parentOnSelect']);
return (React.createElement(SelectableContext.Provider, { value: selectContext },
React.createElement(ListContext.Provider, { value: listContext },
React.createElement("div", __assign({ className: 'md-menu' + ' md-menu-item-container' + "".concat((className && " ".concat(className)) || ''), "aria-label": ariaLabel, ref: function (ref) { return (_this.menuNode = ref); }, role: "menubar", tabIndex: -1 }, otherProps),
React.createElement(UIDReset, null, children)))));
};
return Menu;
}(React.Component));
Menu.propTypes = {
/** @prop Text to display for accessibility features | '' */
ariaLabel: PropTypes.string,
/** @prop Accessibility Configuration Object */
ariaConfig: PropTypes.object,
/** @prop Children nodes to render inside Menu | null */
children: PropTypes.node,
/** @prop Optional css class name | '' */
className: PropTypes.string,
/** @prop Sets first Menu item to have focus | true */
focusFirst: PropTypes.bool,
/** @prop Callback function invoked when user selects | null */
onSelect: PropTypes.func,
// Internal Context Use Only
parentOnSelect: PropTypes.func,
};
Menu.defaultProps = {
ariaLabel: '',
ariaConfig: null,
children: null,
className: '',
focusFirst: true,
onSelect: null,
parentOnSelect: null,
};
Menu.displayName = 'Menu';
export default mapContextToProps(MenuContext, function (context) { return context; }, Menu);
//# sourceMappingURL=index.js.map