Add proptypes and a few more refactors

This commit is contained in:
Klaus 2017-08-17 11:18:02 -03:00
parent c87f3054b9
commit 4fa10ec656
5 changed files with 111 additions and 65 deletions

View File

@ -1,8 +1,9 @@
import React, { Component, Children, cloneElement } from 'react';
import PropTypes from 'prop-types';
import styles from './styles';
import cx from 'classnames';
import UserAction from '/imports/ui/components/user-list/user-list-item/user-action/component';
import KEY_CODES from '/imports/utils/keyCodes';
import styles from './styles';
import ListItem from './item/component';
import ListSeparator from './separator/component';
import ListTitle from './title/component';
@ -11,13 +12,15 @@ const propTypes = {
children: PropTypes.arrayOf((propValue, key, componentName, location, propFullName) => {
if (propValue[key].type !== ListItem &&
propValue[key].type !== ListSeparator &&
propValue[key].type !== ListTitle) {
propValue[key].type !== ListTitle &&
propValue[key].type !== UserAction) {
return new Error(
`Invalid prop \`${propFullName}\` supplied to` +
` \`${componentName}\`. Validation failed.`,
);
}
}),
return true;
}).isRequired,
};
export default class DropdownList extends Component {
@ -29,27 +32,22 @@ export default class DropdownList extends Component {
this.handleItemClick = this.handleItemClick.bind(this);
}
componentDidMount() {
this._menu.addEventListener('keydown', event=>this.handleItemKeyDown(event));
}
componentWillMount() {
this.setState({
focusedIndex: 0,
});
}
componentDidUpdate(prevProps, prevState) {
let { focusedIndex } = this.state;
this.menuRefs = [];
for (let i = 0; i < (this._menu.children.length); i++) {
if (this._menu.children[i].getAttribute("role") === 'menuitem') {
this.menuRefs.push(this._menu.children[i]);
}
componentDidMount() {
this._menu.addEventListener('keydown', event => this.handleItemKeyDown(event));
}
componentDidUpdate() {
const { focusedIndex } = this.state;
const childrens = [].slice.call(this._menu.children);
this.menuRefs = childrens.filter(child => child.getAttribute('role') === 'menuitem');
const activeRef = this.menuRefs[focusedIndex];
if (activeRef) {
@ -58,7 +56,7 @@ export default class DropdownList extends Component {
}
handleItemKeyDown(event, callback) {
const { onActionsHide, getDropdownMenuParent, } = this.props;
const { getDropdownMenuParent } = this.props;
let nextFocusedIndex = this.state.focusedIndex;
if (KEY_CODES.ARROW_UP === event.which) {
@ -108,8 +106,7 @@ export default class DropdownList extends Component {
}
handleItemClick(event, callback) {
const { getDropdownMenuParent, onActionsHide} = this.props;
const { dropdownHide } = this.props;
const { getDropdownMenuParent, onActionsHide, dropdownHide } = this.props;
if (getDropdownMenuParent) {
onActionsHide();
@ -127,7 +124,7 @@ export default class DropdownList extends Component {
const { children, style, className } = this.props;
const boundChildren = Children.map(children,
(item, i) => {
(item) => {
if (item.type === ListSeparator) {
return item;
}
@ -140,13 +137,13 @@ export default class DropdownList extends Component {
onClick: (event) => {
let { onClick } = item.props;
onClick = onClick ? onClick.bind(item) : null;
onClick = onClick ? () => onClick.call(item) : null;
this.handleItemClick(event, onClick);
},
onKeyDown: (event) => {
let { onKeyDown } = item.props;
onKeyDown = onKeyDown ? onKeyDown.bind(item) : null;
onKeyDown = onKeyDown ? () => onKeyDown.call(item) : null;
this.handleItemKeyDown(event, onKeyDown);
},
@ -157,7 +154,12 @@ export default class DropdownList extends Component {
<ul
style={style}
className={cx(styles.list, className)}
role="menu" ref={(r) => this._menu = r}>
role="menu"
ref={(r) => {
this._menu = r;
return r;
}}
>
{boundChildren}
</ul>
);

View File

@ -15,6 +15,7 @@ const defaultProps = {
icon: '',
label: '',
description: '',
tabIndex: 0,
};
export default class DropdownListItem extends Component {

View File

@ -2,9 +2,9 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router';
import { injectIntl } from 'react-intl';
import DropdownListItem from '/imports/ui/components/dropdown/list/item/component';
import _ from 'lodash';
import UserListContent from './user-list-content/component';
import UserAction from './user-action/component';
const normalizeEmojiName = (emoji) => {
const emojisNormalized = {
@ -32,14 +32,33 @@ const propTypes = {
currentUser: PropTypes.shape({
id: PropTypes.string.isRequired,
}).isRequired,
compact: PropTypes.bool.isRequired,
intl: PropTypes.object.isRequired,
userActions: PropTypes.object.isRequired,
router: PropTypes.object.isRequired,
isBreakoutRoom: PropTypes.bool.isRequired,
getAvailableActions: PropTypes.func.isRequired,
};
const defaultProps = {
shouldShowActions: false,
isBreakoutRoom: false,
};
class UserListItem extends Component {
static createAction(action, ...options) {
return (
<UserAction
key={_.uniqueId('action-item-')}
icon={action.icon}
label={action.label}
handler={action.handler}
options={[...options]}
/>
);
}
getUsersActions() {
const {
currentUser,
@ -69,32 +88,16 @@ class UserListItem extends Component {
allowedToKick,
allowedToSetPresenter } = actions;
return _.compact([
(allowedToChatPrivately ? this.renderUserAction(openChat, router, user) : null),
(allowedToMuteAudio ? this.renderUserAction(unmute, user) : null),
(allowedToUnmuteAudio ? this.renderUserAction(mute, user) : null),
(allowedToResetStatus ? this.renderUserAction(clearStatus, user) : null),
(allowedToSetPresenter ? this.renderUserAction(setPresenter, user) : null),
(allowedToKick ? this.renderUserAction(kick, user) : null),
(allowedToChatPrivately ? UserListItem.createAction(openChat, router, user) : null),
(allowedToMuteAudio ? UserListItem.createAction(unmute, user) : null),
(allowedToUnmuteAudio ? UserListItem.createAction(mute, user) : null),
(allowedToResetStatus ? UserListItem.createAction(clearStatus, user) : null),
(allowedToSetPresenter ? UserListItem.createAction(setPresenter, user) : null),
(allowedToKick ? UserListItem.createAction(kick, user) : null),
]);
}
renderUserAction(action, ...parameters) {
const userAction = (
<DropdownListItem
key={_.uniqueId('action-item-')}
icon={action.icon}
label={action.label}
defaultMessage={action.label}
onClick={action.handler.bind(this, ...parameters)}
/>
);
return userAction;
}
render() {
const {
compact,

View File

@ -0,0 +1,29 @@
import React from 'react';
import PropTypes from 'prop-types';
import DropdownListItem from '/imports/ui/components/dropdown/list/item/component';
const propTypes = {
icon: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
handler: PropTypes.func.isRequired,
options: PropTypes.array.isRequired,
};
const UserActions = (props) => {
const { key, icon, label, handler, options } = props;
const userAction = (
<DropdownListItem
key={key}
icon={icon}
label={label}
defaultMessage={label}
onClick={() => handler.call(this, ...options)}
/>
);
return userAction;
};
UserActions.propTypes = propTypes;
export default UserActions;

View File

@ -1,6 +1,7 @@
import React, { Component } from 'react';
import { defineMessages } from 'react-intl';
import cx from 'classnames';
import PropTypes from 'prop-types';
import { findDOMNode } from 'react-dom';
import UserAvatar from '/imports/ui/components/user-avatar/component';
import Icon from '/imports/ui/components/icon/component';
@ -41,6 +42,15 @@ const messages = defineMessages({
},
});
const propTypes = {
compact: PropTypes.bool.isRequired,
user: PropTypes.object.isRequired,
intl: PropTypes.object.isRequired,
normalizeEmojiName: PropTypes.func.isRequired,
actions: PropTypes.array.isRequired,
};
class UserListContent extends Component {
/**
@ -108,7 +118,6 @@ class UserListContent extends Component {
});
}
/**
* Check if the dropdown is visible, if so, check if should be draw on top or bottom direction.
*/
@ -172,6 +181,7 @@ class UserListContent extends Component {
dropdownDirection,
dropdownOffset,
} = this.state;
const userItemContentsStyle = {};
userItemContentsStyle[styles.userItemContentsCompact] = compact;
@ -276,4 +286,5 @@ class UserListContent extends Component {
}
}
UserListContent.propTypes = propTypes;
export default UserListContent;