@momentum-ui/react-collaboration
Version:
Cisco Momentum UI Framework for React Collaboration Applications
289 lines • 13.8 kB
JavaScript
/** @component button-group */
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;
};
import React from 'react';
import PropTypes from 'prop-types';
import omit from 'lodash/omit';
import qsa from 'dom-helpers/query/querySelectorAll';
import { UIDReset } from 'react-uid';
import ButtonGroupContext from '../ButtonGroupContext';
import SelectableContext from '../SelectableContext';
/**
* @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 ButtonGroup = /** @class */ (function (_super) {
__extends(ButtonGroup, _super);
function ButtonGroup(props) {
var _this = _super.call(this, props) || this;
_this.determineInitialFocus = function () {
var bgContext = _this.state.bgContext;
var _a = _this.props, focusFirstQuery = _a.focusFirstQuery, focusOnLoad = _a.focusOnLoad;
var items = qsa(_this.containerNode, focusFirstQuery || ".md-button:not(.disabled):not(:disabled)");
var focus = bgContext.focus;
if (items.length) {
if (!focus) {
focus = _this.getNextFocusedChild(items, items[0], 0);
}
if (focus && focusOnLoad) {
_this.containerNode.querySelector("[data-md-event-key=\"".concat(focus, "\"]")).focus();
}
}
};
_this.handleSelect = function (e, opts) {
var _a = _this.props, highlightSelected = _a.highlightSelected, onSelect = _a.onSelect, type = _a.type;
var active = _this.state.bgContext.active;
var eventKey = opts.eventKey;
var items = _this.getFocusableItems();
var index = items.indexOf(_this.containerNode.querySelector("[data-md-event-key=\"".concat(eventKey, "\"]")));
_this.setFocus(items, index);
// Don't do anything if onSelect Event Handler is present
if (onSelect) {
return onSelect(e, {
eventKey: _this.getValue(items, index, 'event'),
});
}
// Don't do anything if index is the same or outside of the bounds
if (eventKey === active || index < 0 || index > items.length - 1)
return;
// Call change event handler
_this.setState(function (state) { return ({
bgContext: __assign(__assign({}, state.bgContext), { active: type === 'pill' ? false : highlightSelected && _this.getValue(items, index, 'event') }),
}); });
};
_this.getValue = function (arr, index, attribute) {
return arr[index].attributes["data-md-".concat(attribute, "-key")] &&
arr[index].attributes["data-md-".concat(attribute, "-key")].value;
};
_this.getIncludesFirstCharacter = function (str, char) { return str.charAt(0).toLowerCase().includes(char); };
_this.setFocus = function (items, index) {
_this.setState(function (state) { return ({
bgContext: __assign(__assign({}, state.bgContext), { focus: _this.getValue(items, index, 'event') }),
}); });
};
_this.setActiveAndFocus = function (active, focus) {
var _a = _this.props, type = _a.type, highlightSelected = _a.highlightSelected;
_this._needsRefocus = false;
_this.setState(function (state) { return ({
bgContext: __assign(__assign({}, state.bgContext), { active: type === 'pill' ? false : highlightSelected && active, focus: active || focus }),
}); });
};
_this.setFocusByFirstCharacter = function (char, focusIdx, items, length) {
var bgContext = _this.state.bgContext;
var newIndex = items.reduce(function (agg, item, idx, arr) {
var index = focusIdx + idx + 1 > length ? Math.abs(focusIdx + idx - length) : focusIdx + idx + 1;
return !agg.length &&
_this.getValue(arr, index, 'keyboard') &&
_this.getIncludesFirstCharacter(_this.getValue(arr, index, 'keyboard'), char)
? agg.concat(_this.getValue(arr, index, 'event'))
: agg;
}, []);
typeof newIndex[0] === 'string' &&
bgContext.focus !== newIndex[0] &&
_this.setState(function (state) { return ({
bgContext: __assign(__assign({}, state.bgContext), { focus: newIndex[0] }),
}); });
};
_this.getFocusableItems = function () {
if (!_this.containerNode)
return null;
var focusQuery = _this.props.focusQuery;
var defaultItems = qsa(_this.containerNode, ".md-button:not(.disabled):not(:disabled)");
var customItems = (focusQuery && qsa(_this.containerNode, focusQuery)) || [];
return customItems.length
? customItems.filter(function (item) { return customItems.indexOf(item) >= 0; })
: defaultItems;
};
_this.handleKeyDown = function (e) {
var focus = _this.state.bgContext.focus;
var flag = false;
var tgt = e.currentTarget;
var char = e.key;
var items = _this.getFocusableItems();
var focusIdx = (focus &&
items.indexOf(_this.containerNode.querySelector("[data-md-event-key=\"".concat(focus, "\"]")))) ||
0;
var length = (items.length && items.length - 1) || 0;
var isPrintableCharacter = function (str) {
return str.length === 1 && str.match(/\S/);
};
switch (e.which) {
case 38:
case 37:
_this.getNextFocusedChild(items, tgt, -1);
_this._needsRefocus = true;
flag = true;
break;
case 39:
case 40:
_this.getNextFocusedChild(items, tgt, 1);
_this._needsRefocus = true;
flag = true;
break;
default:
if (isPrintableCharacter(char)) {
_this.setFocusByFirstCharacter(char, focusIdx, items, length);
_this._needsRefocus = true;
flag = true;
}
break;
}
if (flag) {
e.stopPropagation();
e.preventDefault();
}
};
_this.state = {
bgContext: __assign({ active: props.type === 'pill' ? false : props.highlightSelected && props.active, focus: props.active || null, isButtonGroup: true }, (props.pillWidth && { width: props.pillWidth })),
selectContext: {
parentOnSelect: _this.handleSelect,
parentKeyDown: _this.handleKeyDown,
},
};
return _this;
}
ButtonGroup.getDerivedStateFromProps = function (_a, state) {
var active = _a.active;
return active
? __assign(__assign({}, state), { bgContext: __assign(__assign({}, state.bgContext), { active: active }) }) : state;
};
ButtonGroup.prototype.componentDidMount = function () {
this.containerNode && this.determineInitialFocus();
};
ButtonGroup.prototype.componentDidUpdate = function (prevProps, prevState) {
var bgContext = this.state.bgContext;
var active = this.props.active;
if (prevProps.active !== active) {
this.setActiveAndFocus(active, focus);
}
if (!this._needsRefocus || !this.containerNode)
return;
if (bgContext.focus && prevState.bgContext.focus !== bgContext.focus) {
this.containerNode.querySelector("[data-md-event-key=\"".concat(bgContext.focus, "\"]")).focus();
}
};
ButtonGroup.prototype.getNextFocusedChild = function (items, current, offset) {
if (!this.containerNode)
return null;
var bgContext = this.state.bgContext;
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;
};
bgContext.focus !== this.getValue(items, getIndex(), 'event') &&
this.setState({
bgContext: __assign(__assign({}, bgContext), { focus: this.getValue(items, getIndex(), 'event') }),
});
return this.getValue(items, getIndex(), 'event');
};
ButtonGroup.prototype.render = function () {
var _this = this;
var _a = this.props, ariaLabel = _a.ariaLabel, children = _a.children, className = _a.className, justified = _a.justified, theme = _a.theme, type = _a.type, props = __rest(_a, ["ariaLabel", "children", "className", "justified", "theme", "type"]);
var _b = this.state, bgContext = _b.bgContext, selectContext = _b.selectContext;
var otherProps = omit(__assign({}, props), [
'active',
'focusOnLoad',
'focusFirstQuery',
'focusQuery',
'highlightSelected',
'onSelect',
'pillWidth',
]);
return (React.createElement(SelectableContext.Provider, { value: selectContext },
React.createElement("div", __assign({ "aria-label": ariaLabel, className: 'md-button-group' +
"".concat((theme && " md-button-group--".concat(theme)) || '') +
"".concat((justified && " md-button-group--justified") || '') +
"".concat((type && " md-button-group--".concat(type)) || '') +
"".concat((className && " ".concat(className)) || ''), role: "group", ref: function (ref) { return (_this.containerNode = ref); } }, otherProps),
React.createElement(UIDReset, null,
React.createElement(ButtonGroupContext.Provider, { value: bgContext }, children)))));
};
return ButtonGroup;
}(React.Component));
ButtonGroup.propTypes = {
/** @prop Sets initial active Button by index | null */
active: PropTypes.string,
/** @prop Text to display for blindness accessibility features | '' */
ariaLabel: PropTypes.string,
/** @prop Children nodes to render inside ButtonGroup | null */
children: PropTypes.node,
/** @prop Optional css class string | '' */
className: PropTypes.string,
/** @prop Set focus to ButtonGroup when page is loaded | false */
focusOnLoad: PropTypes.bool,
/** @prop Queries children to find matching item to have focus | '' */
focusFirstQuery: PropTypes.string,
/** @prop Additional elements that can be focused by selector | '' */
focusQuery: PropTypes.string,
/** @prop Highlights the selected button within group | true */
highlightSelected: PropTypes.bool,
/** @prop Optional text-justified css styling | true */
justified: PropTypes.bool,
/** @prop Handler to be called when the user selects ButtonGroup | null */
onSelect: PropTypes.func,
/** @prop Sets width of a pill Button | '60px' */
pillWidth: PropTypes.string,
/** @prop Optional Button color theme for ButtonGroup | '' */
theme: PropTypes.oneOf(['', 'dark']),
/** @prop Optional Button type for ButtonGroup | '' */
type: PropTypes.oneOf(['', 'pill', 'unstyled']),
};
ButtonGroup.defaultProps = {
active: '',
ariaLabel: '',
children: null,
className: '',
focusOnLoad: false,
focusFirstQuery: '',
focusQuery: '',
highlightSelected: true,
justified: true,
onSelect: null,
pillWidth: '60px',
theme: '',
type: '',
};
ButtonGroup.displayName = 'ButtonGroup';
export default ButtonGroup;
//# sourceMappingURL=index.js.map