Merge pull request #12474 from Tainan404/refactor-dropdown
refactor: Decrease amount of imports in dropdown
This commit is contained in:
commit
9395f50b99
@ -4,13 +4,8 @@ import PropTypes from 'prop-types';
|
||||
import { defineMessages } from 'react-intl';
|
||||
import Button from '/imports/ui/components/button/component';
|
||||
import Dropdown from '/imports/ui/components/dropdown/component';
|
||||
import DropdownTrigger from '/imports/ui/components/dropdown/trigger/component';
|
||||
import DropdownContent from '/imports/ui/components/dropdown/content/component';
|
||||
import DropdownList from '/imports/ui/components/dropdown/list/component';
|
||||
import DropdownListItem from '/imports/ui/components/dropdown/list/item/component';
|
||||
import { withModalMounter } from '/imports/ui/components/modal/service';
|
||||
import withShortcutHelper from '/imports/ui/components/shortcut-help/service';
|
||||
import DropdownListSeparator from '/imports/ui/components/dropdown/list/separator/component';
|
||||
import ExternalVideoModal from '/imports/ui/components/external-video-player/modal/container';
|
||||
import RandomUserSelectContainer from '/imports/ui/components/modal/random-user/container';
|
||||
import cx from 'classnames';
|
||||
@ -145,7 +140,7 @@ class ActionsDropdown extends PureComponent {
|
||||
return _.compact([
|
||||
(amIPresenter && isPollingEnabled
|
||||
? (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
icon="polling"
|
||||
data-test="polling"
|
||||
label={formatMessage(pollBtnLabel)}
|
||||
@ -170,7 +165,7 @@ class ActionsDropdown extends PureComponent {
|
||||
: null),
|
||||
(!amIPresenter
|
||||
? (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
icon="presentation"
|
||||
label={formatMessage(takePresenter)}
|
||||
description={formatMessage(takePresenterDesc)}
|
||||
@ -181,7 +176,7 @@ class ActionsDropdown extends PureComponent {
|
||||
: null),
|
||||
(amIPresenter
|
||||
? (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
data-test="uploadPresentation"
|
||||
icon="presentation"
|
||||
label={formatMessage(presentationLabel)}
|
||||
@ -193,7 +188,7 @@ class ActionsDropdown extends PureComponent {
|
||||
: null),
|
||||
(amIPresenter && allowExternalVideo
|
||||
? (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
icon="video"
|
||||
label={!isSharingVideo ? intl.formatMessage(intlMessages.startExternalVideoLabel)
|
||||
: intl.formatMessage(intlMessages.stopExternalVideoLabel)}
|
||||
@ -205,7 +200,7 @@ class ActionsDropdown extends PureComponent {
|
||||
: null),
|
||||
(amIPresenter && isSelectRandomUserEnabled
|
||||
? (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
icon="user"
|
||||
label={intl.formatMessage(intlMessages.selectRandUserLabel)}
|
||||
description={intl.formatMessage(intlMessages.selectRandUserDesc)}
|
||||
@ -238,7 +233,7 @@ class ActionsDropdown extends PureComponent {
|
||||
itemStyles[styles.isCurrent] = p.current;
|
||||
|
||||
return (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
className={cx(itemStyles)}
|
||||
icon="file"
|
||||
iconRight={p.current ? 'check' : null}
|
||||
@ -252,7 +247,7 @@ class ActionsDropdown extends PureComponent {
|
||||
);
|
||||
});
|
||||
|
||||
presentationItemElements.push(<DropdownListSeparator key={_.uniqueId('list-separator-')} />);
|
||||
presentationItemElements.push(<Dropdown.DropdownListSeparator key={_.uniqueId('list-separator-')} />);
|
||||
return presentationItemElements;
|
||||
}
|
||||
|
||||
@ -288,7 +283,7 @@ class ActionsDropdown extends PureComponent {
|
||||
className={styles.dropdown}
|
||||
ref={(ref) => { this._dropdown = ref; }}
|
||||
>
|
||||
<DropdownTrigger tabIndex={0} accessKey={OPEN_ACTIONS_AK}>
|
||||
<Dropdown.DropdownTrigger tabIndex={0} accessKey={OPEN_ACTIONS_AK}>
|
||||
<Button
|
||||
className={isDropdownOpen ? styles.hideDropdownButton : ''}
|
||||
hideLabel
|
||||
@ -300,12 +295,12 @@ class ActionsDropdown extends PureComponent {
|
||||
circle
|
||||
onClick={() => null}
|
||||
/>
|
||||
</DropdownTrigger>
|
||||
<DropdownContent placement="top left">
|
||||
<DropdownList className={styles.scrollableList}>
|
||||
</Dropdown.DropdownTrigger>
|
||||
<Dropdown.DropdownContent placement="top left">
|
||||
<Dropdown.DropdownList className={styles.scrollableList}>
|
||||
{children}
|
||||
</DropdownList>
|
||||
</DropdownContent>
|
||||
</Dropdown.DropdownList>
|
||||
</Dropdown.DropdownContent>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
|
@ -4,10 +4,6 @@ import { defineMessages } from 'react-intl';
|
||||
import _ from 'lodash';
|
||||
import Button from '/imports/ui/components/button/component';
|
||||
import Dropdown from '/imports/ui/components/dropdown/component';
|
||||
import DropdownTrigger from '/imports/ui/components/dropdown/trigger/component';
|
||||
import DropdownContent from '/imports/ui/components/dropdown/content/component';
|
||||
import DropdownList from '/imports/ui/components/dropdown/list/component';
|
||||
import DropdownListItem from '/imports/ui/components/dropdown/list/item/component';
|
||||
import { styles } from '../styles';
|
||||
import { PANELS, ACTIONS } from '../../layout/enums';
|
||||
|
||||
@ -111,7 +107,7 @@ const getAvailableQuickPolls = (
|
||||
}).join('');
|
||||
|
||||
return (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
label={itemLabel}
|
||||
key={_.uniqueId('quick-poll-item')}
|
||||
onClick={() => {
|
||||
@ -210,14 +206,14 @@ class QuickPollDropdown extends Component {
|
||||
|
||||
dropdown = (
|
||||
<Dropdown className={className}>
|
||||
<DropdownTrigger tabIndex={0}>
|
||||
<Dropdown.DropdownTrigger tabIndex={0}>
|
||||
{btn}
|
||||
</DropdownTrigger>
|
||||
<DropdownContent placement="top left">
|
||||
<DropdownList>
|
||||
</Dropdown.DropdownTrigger>
|
||||
<Dropdown.DropdownContent placement="top left">
|
||||
<Dropdown.DropdownList>
|
||||
{quickPolls}
|
||||
</DropdownList>
|
||||
</DropdownContent>
|
||||
</Dropdown.DropdownList>
|
||||
</Dropdown.DropdownContent>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
|
@ -5,12 +5,6 @@ import { defineMessages, injectIntl } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
import Button from '/imports/ui/components/button/component';
|
||||
import Dropdown from '/imports/ui/components/dropdown/component';
|
||||
import DropdownTrigger from '/imports/ui/components/dropdown/trigger/component';
|
||||
import DropdownContent from '/imports/ui/components/dropdown/content/component';
|
||||
import DropdownList from '/imports/ui/components/dropdown/list/component';
|
||||
import DropdownListSeparator from '/imports/ui/components/dropdown/list/separator/component';
|
||||
import DropdownListItem from '/imports/ui/components/dropdown/list/item/component';
|
||||
import DropdownListTitle from '/imports/ui/components/dropdown/list/title/component';
|
||||
import withShortcutHelper from '/imports/ui/components/shortcut-help/service';
|
||||
import cx from 'classnames';
|
||||
|
||||
@ -222,14 +216,14 @@ class InputStreamLiveSelector extends Component {
|
||||
const listLenght = list ? list.length : -1;
|
||||
|
||||
const listTitle = [
|
||||
<DropdownListTitle key={`audioDeviceList-${deviceKind}`}>
|
||||
<Dropdown.DropdownListTitle key={`audioDeviceList-${deviceKind}`}>
|
||||
{title}
|
||||
</DropdownListTitle>,
|
||||
</Dropdown.DropdownListTitle>,
|
||||
];
|
||||
|
||||
const deviceList = (listLenght > 0)
|
||||
? list.map((device) => (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
key={`${device.deviceId}-${deviceKind}`}
|
||||
label={InputStreamLiveSelector.truncateDeviceName(device.label)}
|
||||
onClick={() => this.onDeviceListClick(device.deviceId, deviceKind,
|
||||
@ -239,7 +233,7 @@ class InputStreamLiveSelector extends Component {
|
||||
/>
|
||||
))
|
||||
: [
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
key={`noDeviceFoundKey-${deviceKind}-`}
|
||||
className={styles.disableDeviceSelection}
|
||||
label={
|
||||
@ -251,7 +245,7 @@ class InputStreamLiveSelector extends Component {
|
||||
];
|
||||
|
||||
const listSeparator = [
|
||||
<DropdownListSeparator key={`audioDeviceListSeparator-${deviceKind}`} />,
|
||||
<Dropdown.DropdownListSeparator key={`audioDeviceListSeparator-${deviceKind}`} />,
|
||||
];
|
||||
|
||||
return listTitle.concat(deviceList).concat(listSeparator);
|
||||
@ -295,7 +289,7 @@ class InputStreamLiveSelector extends Component {
|
||||
|
||||
const dropdownListComplete = inputDeviceList.concat(outputDeviceList)
|
||||
.concat([
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
key="leaveAudioButtonKey"
|
||||
className={styles.stopButton}
|
||||
label={intl.formatMessage(intlMessages.leaveAudio)}
|
||||
@ -306,7 +300,7 @@ class InputStreamLiveSelector extends Component {
|
||||
|
||||
return (
|
||||
<Dropdown>
|
||||
<DropdownTrigger>
|
||||
<Dropdown.DropdownTrigger>
|
||||
<Button
|
||||
aria-label={intl.formatMessage(intlMessages.changeLeaveAudio)}
|
||||
label={intl.formatMessage(intlMessages.changeLeaveAudio)}
|
||||
@ -317,12 +311,14 @@ class InputStreamLiveSelector extends Component {
|
||||
circle
|
||||
onClick={() => {}}
|
||||
/>
|
||||
</DropdownTrigger>
|
||||
<DropdownContent className={styles.dropdownContent}>
|
||||
<DropdownList className={cx(styles.scrollableList, styles.dropdownListContainer)}>
|
||||
</Dropdown.DropdownTrigger>
|
||||
<Dropdown.DropdownContent className={styles.dropdownContent}>
|
||||
<Dropdown.DropdownList
|
||||
className={cx(styles.scrollableList, styles.dropdownListContainer)}
|
||||
>
|
||||
{dropdownListComplete}
|
||||
</DropdownList>
|
||||
</DropdownContent>
|
||||
</Dropdown.DropdownList>
|
||||
</Dropdown.DropdownContent>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
|
@ -4,10 +4,6 @@ import { withModalMounter } from '/imports/ui/components/modal/service';
|
||||
import Clipboard from 'clipboard';
|
||||
import _ from 'lodash';
|
||||
import Dropdown from '/imports/ui/components/dropdown/component';
|
||||
import DropdownTrigger from '/imports/ui/components/dropdown/trigger/component';
|
||||
import DropdownContent from '/imports/ui/components/dropdown/content/component';
|
||||
import DropdownList from '/imports/ui/components/dropdown/list/component';
|
||||
import DropdownListItem from '/imports/ui/components/dropdown/list/item/component';
|
||||
import Button from '/imports/ui/components/button/component';
|
||||
|
||||
import ChatService from '../service';
|
||||
@ -89,7 +85,7 @@ class ChatDropdown extends PureComponent {
|
||||
const saveIcon = 'download';
|
||||
const copyIcon = 'copy';
|
||||
return _.compact([
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
data-test="chatSave"
|
||||
icon={saveIcon}
|
||||
label={intl.formatMessage(intlMessages.save)}
|
||||
@ -109,7 +105,7 @@ class ChatDropdown extends PureComponent {
|
||||
link.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));
|
||||
}}
|
||||
/>,
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
data-test="chatCopy"
|
||||
icon={copyIcon}
|
||||
id="clipboardButton"
|
||||
@ -117,7 +113,7 @@ class ChatDropdown extends PureComponent {
|
||||
key={this.actionsKey[1]}
|
||||
/>,
|
||||
!meetingIsBreakout && amIModerator && isMeteorConnected ? (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
data-test="chatClear"
|
||||
icon={clearIcon}
|
||||
label={intl.formatMessage(intlMessages.clear)}
|
||||
@ -140,7 +136,7 @@ class ChatDropdown extends PureComponent {
|
||||
onShow={this.onActionsShow}
|
||||
onHide={this.onActionsHide}
|
||||
>
|
||||
<DropdownTrigger tabIndex={0}>
|
||||
<Dropdown.DropdownTrigger tabIndex={0}>
|
||||
<Button
|
||||
data-test="chatDropdownTrigger"
|
||||
icon="more"
|
||||
@ -153,10 +149,10 @@ class ChatDropdown extends PureComponent {
|
||||
aria-label={intl.formatMessage(intlMessages.options)}
|
||||
onClick={() => null}
|
||||
/>
|
||||
</DropdownTrigger>
|
||||
<DropdownContent placement="bottom right">
|
||||
<DropdownList>{availableActions}</DropdownList>
|
||||
</DropdownContent>
|
||||
</Dropdown.DropdownTrigger>
|
||||
<Dropdown.DropdownContent placement="bottom right">
|
||||
<Dropdown.DropdownList>{availableActions}</Dropdown.DropdownList>
|
||||
</Dropdown.DropdownContent>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
|
@ -9,8 +9,13 @@ import Button from '/imports/ui/components/button/component';
|
||||
import screenreaderTrap from 'makeup-screenreader-trap';
|
||||
import { Session } from 'meteor/session';
|
||||
import { styles } from './styles';
|
||||
import DropdownTrigger from './trigger/component';
|
||||
import DropdownContent from './content/component';
|
||||
|
||||
import DropdownTrigger from '/imports/ui/components/dropdown/trigger/component';
|
||||
import DropdownContent from '/imports/ui/components/dropdown/content/component';
|
||||
import DropdownList from '/imports/ui/components/dropdown/list/component';
|
||||
import DropdownListSeparator from '/imports/ui/components/dropdown/list/separator/component';
|
||||
import DropdownListItem from '/imports/ui/components/dropdown/list/item/component';
|
||||
import DropdownListTitle from '/imports/ui/components/dropdown/list/title/component';
|
||||
|
||||
const intlMessages = defineMessages({
|
||||
close: {
|
||||
@ -33,8 +38,8 @@ const propTypes = {
|
||||
+ ` \`${componentName}\`. Validation failed.`);
|
||||
}
|
||||
|
||||
const trigger = children.find(x => x.type === DropdownTrigger);
|
||||
const content = children.find(x => x.type === DropdownContent);
|
||||
const trigger = children.find((x) => x.type === DropdownTrigger);
|
||||
const content = children.find((x) => x.type === DropdownContent);
|
||||
|
||||
if (!trigger) {
|
||||
return new Error(`Invalid prop \`${propName}\` supplied to`
|
||||
@ -53,11 +58,12 @@ const propTypes = {
|
||||
onHide: PropTypes.func,
|
||||
onShow: PropTypes.func,
|
||||
autoFocus: PropTypes.bool,
|
||||
intl: PropTypes.object.isRequired,
|
||||
tethered: PropTypes.bool,
|
||||
getContent: PropTypes.func,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
tethered: false,
|
||||
children: null,
|
||||
onShow: noop,
|
||||
onHide: noop,
|
||||
@ -79,11 +85,19 @@ const targetAttachments = {
|
||||
class Dropdown extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { isOpen: false, isPortrait:deviceInfo.isPortrait() };
|
||||
this.state = {
|
||||
isOpen: false,
|
||||
isPortrait: deviceInfo.isPortrait(),
|
||||
};
|
||||
this.handleShow = this.handleShow.bind(this);
|
||||
this.handleHide = this.handleHide.bind(this);
|
||||
this.handleToggle = this.handleToggle.bind(this);
|
||||
this.handleWindowClick = this.handleWindowClick.bind(this);
|
||||
this.updateOrientation = this.updateOrientation.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
window.addEventListener('resize', this.updateOrientation);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
@ -92,8 +106,6 @@ class Dropdown extends Component {
|
||||
onHide,
|
||||
keepOpen,
|
||||
tethered,
|
||||
sidebarContentPanel,
|
||||
sidebarNavPanel
|
||||
} = this.props;
|
||||
|
||||
const { isOpen } = this.state;
|
||||
@ -113,16 +125,8 @@ class Dropdown extends Component {
|
||||
if (prevProps.keepOpen && !keepOpen) onHide();
|
||||
}
|
||||
|
||||
handleShow() {
|
||||
Session.set('dropdownOpen', true);
|
||||
const {
|
||||
onShow,
|
||||
} = this.props;
|
||||
this.setState({ isOpen: true }, () => {
|
||||
const { addEventListener } = window;
|
||||
onShow();
|
||||
addEventListener('click', this.handleWindowClick, true);
|
||||
});
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('resize', this.updateOrientation);
|
||||
}
|
||||
|
||||
handleHide() {
|
||||
@ -135,16 +139,17 @@ class Dropdown extends Component {
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
window.addEventListener('resize', this.updateOrientation);
|
||||
handleShow() {
|
||||
Session.set('dropdownOpen', true);
|
||||
const {
|
||||
onShow,
|
||||
} = this.props;
|
||||
this.setState({ isOpen: true }, () => {
|
||||
const { addEventListener } = window;
|
||||
onShow();
|
||||
addEventListener('click', this.handleWindowClick, true);
|
||||
});
|
||||
}
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('resize', this.updateOrientation);
|
||||
}
|
||||
|
||||
updateOrientation = () => {
|
||||
this.setState({ isPortrait:deviceInfo.isPortrait() });
|
||||
};
|
||||
|
||||
handleWindowClick(event) {
|
||||
const { keepOpen, onHide } = this.props;
|
||||
@ -187,6 +192,10 @@ class Dropdown extends Component {
|
||||
return isOpen ? this.handleHide() : this.handleShow();
|
||||
}
|
||||
|
||||
updateOrientation() {
|
||||
this.setState({ isPortrait: deviceInfo.isPortrait() });
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
children,
|
||||
@ -198,7 +207,6 @@ class Dropdown extends Component {
|
||||
getContent,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
const { isOpen, isPortrait } = this.state;
|
||||
const { isPhone } = deviceInfo;
|
||||
const placements = placement && placement.replace(' ', '-');
|
||||
@ -212,8 +220,8 @@ class Dropdown extends Component {
|
||||
transform: '',
|
||||
};
|
||||
|
||||
let trigger = children.find(x => x.type === DropdownTrigger);
|
||||
let content = children.find(x => x.type === DropdownContent);
|
||||
let trigger = children.find((x) => x.type === DropdownTrigger);
|
||||
let content = children.find((x) => x.type === DropdownContent);
|
||||
|
||||
trigger = React.cloneElement(trigger, {
|
||||
ref: (ref) => { this.trigger = ref; },
|
||||
@ -238,7 +246,6 @@ class Dropdown extends Component {
|
||||
});
|
||||
|
||||
const showCloseBtn = (isOpen && keepOpen) || (isOpen && keepOpen === null);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx(styles.dropdown, className)}
|
||||
@ -270,11 +277,12 @@ class Dropdown extends Component {
|
||||
to: 'scrollParent',
|
||||
},
|
||||
]}
|
||||
renderTarget={ref => (
|
||||
renderTarget={(ref) => (
|
||||
<span ref={ref}>
|
||||
{trigger}
|
||||
</span>)}
|
||||
renderElement={ref => (
|
||||
</span>
|
||||
)}
|
||||
renderElement={(ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
>
|
||||
@ -290,11 +298,12 @@ class Dropdown extends Component {
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>)
|
||||
: (
|
||||
<Fragment>
|
||||
// Fix eslint rule https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-fragments.md
|
||||
<>
|
||||
{trigger}
|
||||
{content}
|
||||
{showCloseBtn
|
||||
@ -307,7 +316,7 @@ class Dropdown extends Component {
|
||||
onClick={this.handleHide}
|
||||
/>
|
||||
) : null}
|
||||
</Fragment>
|
||||
</>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
@ -317,4 +326,11 @@ class Dropdown extends Component {
|
||||
|
||||
Dropdown.propTypes = propTypes;
|
||||
Dropdown.defaultProps = defaultProps;
|
||||
|
||||
Dropdown.DropdownTrigger = DropdownTrigger;
|
||||
Dropdown.DropdownContent = DropdownContent;
|
||||
Dropdown.DropdownList = DropdownList;
|
||||
Dropdown.DropdownListSeparator = DropdownListSeparator;
|
||||
Dropdown.DropdownListItem = DropdownListItem;
|
||||
Dropdown.DropdownListTitle = DropdownListTitle;
|
||||
export default injectIntl(Dropdown, { forwardRef: true });
|
||||
|
@ -11,9 +11,9 @@ const propTypes = {
|
||||
/* We should recheck this proptype, sometimes we need to create an container and send to
|
||||
dropdown, but with this proptype, is not possible. */
|
||||
children: PropTypes.arrayOf((propValue, key, componentName, propFullName) => {
|
||||
if (propValue[key].type !== ListItem &&
|
||||
propValue[key].type !== ListSeparator &&
|
||||
propValue[key].type !== ListTitle) {
|
||||
if (propValue[key].type !== ListItem
|
||||
&& propValue[key].type !== ListSeparator
|
||||
&& propValue[key].type !== ListTitle) {
|
||||
return new Error(`Invalid prop \`${propFullName}\` supplied to` +
|
||||
` \`${componentName}\`. Validation failed.`);
|
||||
}
|
||||
@ -41,14 +41,13 @@ export default class DropdownList extends Component {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this._menu.addEventListener('keydown', event => this.handleItemKeyDown(event));
|
||||
this._menu.addEventListener('keydown', (event) => this.handleItemKeyDown(event));
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
|
||||
const { focusedIndex } = this.state;
|
||||
const children = [].slice.call(this._menu.children);
|
||||
this.menuRefs = children.filter(child => child.getAttribute('role') === 'menuitem');
|
||||
this.menuRefs = children.filter((child) => child.getAttribute('role') === 'menuitem');
|
||||
|
||||
const activeRef = this.menuRefs[focusedIndex];
|
||||
|
||||
@ -58,7 +57,10 @@ export default class DropdownList extends Component {
|
||||
}
|
||||
|
||||
handleItemKeyDown(event, callback) {
|
||||
const { getDropdownMenuParent } = this.props;
|
||||
const {
|
||||
getDropdownMenuParent,
|
||||
horizontal,
|
||||
} = this.props;
|
||||
const { focusedIndex } = this.state;
|
||||
|
||||
let nextFocusedIndex = focusedIndex > 0 ? focusedIndex : 0;
|
||||
@ -67,7 +69,7 @@ export default class DropdownList extends Component {
|
||||
nextFocusedIndex = this.menuRefs.indexOf(document.activeElement);
|
||||
}
|
||||
|
||||
const isHorizontal = this.props.horizontal;
|
||||
const isHorizontal = horizontal;
|
||||
const navigationKeys = {
|
||||
previous: KEY_CODES[`ARROW_${isHorizontal ? 'LEFT' : 'UP'}`],
|
||||
next: KEY_CODES[`ARROW_${isHorizontal ? 'RIGHT' : 'DOWN'}`],
|
||||
@ -126,7 +128,13 @@ export default class DropdownList extends Component {
|
||||
}
|
||||
|
||||
handleItemClick(event, callback) {
|
||||
const { getDropdownMenuParent, onActionsHide, dropdownHide, keepOpen} = this.props;
|
||||
const {
|
||||
getDropdownMenuParent,
|
||||
onActionsHide,
|
||||
dropdownHide,
|
||||
keepOpen,
|
||||
} = this.props;
|
||||
|
||||
if (!keepOpen) {
|
||||
if (getDropdownMenuParent) {
|
||||
onActionsHide();
|
||||
@ -142,7 +150,12 @@ export default class DropdownList extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { children, style, className } = this.props;
|
||||
const {
|
||||
children,
|
||||
style,
|
||||
className,
|
||||
horizontal,
|
||||
} = this.props;
|
||||
|
||||
const boundChildren = Children.map(
|
||||
children,
|
||||
@ -173,7 +186,7 @@ export default class DropdownList extends Component {
|
||||
},
|
||||
);
|
||||
|
||||
const listDirection = this.props.horizontal ? styles.horizontalList : styles.verticalList;
|
||||
const listDirection = horizontal ? styles.horizontalList : styles.verticalList;
|
||||
return (
|
||||
<ul
|
||||
style={style}
|
||||
|
@ -11,6 +11,7 @@ const propTypes = {
|
||||
label: PropTypes.string,
|
||||
description: PropTypes.string,
|
||||
accessKey: PropTypes.string,
|
||||
tabIndex: PropTypes.number,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
@ -52,13 +53,21 @@ class DropdownListItem extends Component {
|
||||
|
||||
render() {
|
||||
const {
|
||||
id, label, description, children, injectRef, tabIndex, onClick, onKeyDown,
|
||||
className, style, intl,
|
||||
id,
|
||||
label,
|
||||
description,
|
||||
children,
|
||||
injectRef,
|
||||
tabIndex,
|
||||
onClick,
|
||||
onKeyDown,
|
||||
className,
|
||||
style,
|
||||
intl,
|
||||
} = this.props;
|
||||
|
||||
const isSelected = className && className.includes('emojiSelected');
|
||||
const _label = isSelected ? `${label} (${intl.formatMessage(messages.activeAriaLabel)})` : label;
|
||||
|
||||
return (
|
||||
<li
|
||||
id={id}
|
||||
@ -71,7 +80,6 @@ class DropdownListItem extends Component {
|
||||
className={cx(styles.item, className)}
|
||||
style={style}
|
||||
role="menuitem"
|
||||
data-test={this.props['data-test']}
|
||||
>
|
||||
{
|
||||
children || this.renderDefault()
|
||||
|
@ -3,8 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import cx from 'classnames';
|
||||
import { styles } from '../styles';
|
||||
|
||||
const DropdownListSeparator = ({ style, className }) =>
|
||||
(
|
||||
const DropdownListSeparator = ({ style, className }) => (
|
||||
<li style={style} className={cx(styles.separator, className)} />
|
||||
);
|
||||
|
||||
|
@ -1,13 +1,8 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import cx from 'classnames';
|
||||
import _ from 'lodash';
|
||||
import { styles } from '../styles';
|
||||
|
||||
const propTypes = {
|
||||
description: PropTypes.string,
|
||||
};
|
||||
|
||||
export default class DropdownListTitle extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@ -15,14 +10,15 @@ export default class DropdownListTitle extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { className } = this.props;
|
||||
const {
|
||||
className,
|
||||
children,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<li className={cx(styles.title, className)} aria-hidden>
|
||||
{this.props.children}
|
||||
{children}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DropdownListTitle.propTypes = propTypes;
|
||||
|
@ -14,11 +14,12 @@ export default class DropdownTrigger extends Component {
|
||||
super(props);
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||
this.trigger = null;
|
||||
}
|
||||
|
||||
handleClick() {
|
||||
const { dropdownToggle, onClick } = this.props;
|
||||
onClick && onClick();
|
||||
if (onClick) onClick();
|
||||
return dropdownToggle();
|
||||
}
|
||||
|
||||
@ -28,20 +29,15 @@ export default class DropdownTrigger extends Component {
|
||||
if ([KEY_CODES.SPACE, KEY_CODES.ENTER].includes(event.which)) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
return findDOMNode(this).click();
|
||||
}
|
||||
|
||||
if ([KEY_CODES.ARROW_UP, KEY_CODES.ARROW_DOWN].includes(event.which)) {
|
||||
} else if ([KEY_CODES.ARROW_UP, KEY_CODES.ARROW_DOWN].includes(event.which)) {
|
||||
dropdownShow();
|
||||
}
|
||||
|
||||
if (KEY_CODES.ESCAPE === event.which) {
|
||||
} else if (KEY_CODES.ESCAPE === event.which) {
|
||||
dropdownHide();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { dropdownIsOpen } = this.props;
|
||||
const remainingProps = { ...this.props };
|
||||
delete remainingProps.dropdownToggle;
|
||||
delete remainingProps.dropdownShow;
|
||||
@ -58,10 +54,11 @@ export default class DropdownTrigger extends Component {
|
||||
|
||||
const TriggerComponentBounded = React.cloneElement(TriggerComponent, {
|
||||
...restProps,
|
||||
ref: (ref) => { this.trigger = ref; },
|
||||
onClick: this.handleClick,
|
||||
onKeyDown: this.handleKeyDown,
|
||||
className: cx(children.props.className, className),
|
||||
'aria-expanded': this.props.dropdownIsOpen,
|
||||
'aria-expanded': dropdownIsOpen,
|
||||
});
|
||||
|
||||
return TriggerComponentBounded;
|
||||
|
@ -9,11 +9,6 @@ import AboutContainer from '/imports/ui/components/about/container';
|
||||
import SettingsMenuContainer from '/imports/ui/components/settings/container';
|
||||
import Button from '/imports/ui/components/button/component';
|
||||
import Dropdown from '/imports/ui/components/dropdown/component';
|
||||
import DropdownTrigger from '/imports/ui/components/dropdown/trigger/component';
|
||||
import DropdownContent from '/imports/ui/components/dropdown/content/component';
|
||||
import DropdownList from '/imports/ui/components/dropdown/list/component';
|
||||
import DropdownListItem from '/imports/ui/components/dropdown/list/item/component';
|
||||
import DropdownListSeparator from '/imports/ui/components/dropdown/list/separator/component';
|
||||
import ShortcutHelpComponent from '/imports/ui/components/shortcut-help/component';
|
||||
import withShortcutHelper from '/imports/ui/components/shortcut-help/service';
|
||||
import FullscreenService from '../../fullscreen-button/service';
|
||||
@ -178,7 +173,7 @@ class SettingsDropdown extends PureComponent {
|
||||
}
|
||||
|
||||
return (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
key="list-item-fullscreen"
|
||||
icon={fullscreenIcon}
|
||||
label={fullscreenLabel}
|
||||
@ -210,7 +205,7 @@ class SettingsDropdown extends PureComponent {
|
||||
} = Meteor.settings.public.app;
|
||||
|
||||
const logoutOption = (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
key="list-item-logout"
|
||||
data-test="logout"
|
||||
icon="logout"
|
||||
@ -226,7 +221,7 @@ class SettingsDropdown extends PureComponent {
|
||||
|
||||
return _.compact([
|
||||
this.getFullscreenItem(),
|
||||
(<DropdownListItem
|
||||
(<Dropdown.DropdownListItem
|
||||
key="list-item-settings"
|
||||
icon="settings"
|
||||
data-test="settings"
|
||||
@ -234,7 +229,7 @@ class SettingsDropdown extends PureComponent {
|
||||
description={intl.formatMessage(intlMessages.settingsDesc)}
|
||||
onClick={() => mountModal(<SettingsMenuContainer />)}
|
||||
/>),
|
||||
(<DropdownListItem
|
||||
(<Dropdown.DropdownListItem
|
||||
key="list-item-about"
|
||||
icon="about"
|
||||
label={intl.formatMessage(intlMessages.aboutLabel)}
|
||||
@ -243,7 +238,7 @@ class SettingsDropdown extends PureComponent {
|
||||
/>),
|
||||
!helpButton ? null
|
||||
: (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
key="list-item-help"
|
||||
icon="help"
|
||||
iconRight="popout_window"
|
||||
@ -252,16 +247,16 @@ class SettingsDropdown extends PureComponent {
|
||||
onClick={() => window.open(`${helpLink}`)}
|
||||
/>
|
||||
),
|
||||
(<DropdownListItem
|
||||
(<Dropdown.DropdownListItem
|
||||
key="list-item-shortcuts"
|
||||
icon="shortcuts"
|
||||
label={intl.formatMessage(intlMessages.hotkeysLabel)}
|
||||
description={intl.formatMessage(intlMessages.hotkeysDesc)}
|
||||
onClick={() => mountModal(<ShortcutHelpComponent />)}
|
||||
/>),
|
||||
(isMeteorConnected ? <DropdownListSeparator key={_.uniqueId('list-separator-')} /> : null),
|
||||
(isMeteorConnected ? <Dropdown.DropdownListSeparator key={_.uniqueId('list-separator-')} /> : null),
|
||||
allowedToEndMeeting && isMeteorConnected
|
||||
? (<DropdownListItem
|
||||
? (<Dropdown.DropdownListItem
|
||||
key="list-item-end-meeting"
|
||||
icon="application"
|
||||
label={intl.formatMessage(intlMessages.endMeetingLabel)}
|
||||
@ -291,7 +286,7 @@ class SettingsDropdown extends PureComponent {
|
||||
onShow={this.onActionsShow}
|
||||
onHide={this.onActionsHide}
|
||||
>
|
||||
<DropdownTrigger tabIndex={0} accessKey={OPEN_OPTIONS_AK}>
|
||||
<Dropdown.DropdownTrigger tabIndex={0} accessKey={OPEN_OPTIONS_AK}>
|
||||
<Button
|
||||
label={intl.formatMessage(intlMessages.optionsLabel)}
|
||||
icon="more"
|
||||
@ -304,12 +299,12 @@ class SettingsDropdown extends PureComponent {
|
||||
// even after the DropdownTrigger inject an onClick handler
|
||||
onClick={() => null}
|
||||
/>
|
||||
</DropdownTrigger>
|
||||
<DropdownContent placement="bottom right">
|
||||
<DropdownList>
|
||||
</Dropdown.DropdownTrigger>
|
||||
<Dropdown.DropdownContent placement="bottom right">
|
||||
<Dropdown.DropdownList>
|
||||
{this.renderMenuItems()}
|
||||
</DropdownList>
|
||||
</DropdownContent>
|
||||
</Dropdown.DropdownList>
|
||||
</Dropdown.DropdownContent>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
|
@ -4,11 +4,6 @@ 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';
|
||||
import DropdownTrigger from '/imports/ui/components/dropdown/trigger/component';
|
||||
import DropdownContent from '/imports/ui/components/dropdown/content/component';
|
||||
import DropdownList from '/imports/ui/components/dropdown/list/component';
|
||||
import DropdownListItem from '/imports/ui/components/dropdown/list/item/component';
|
||||
import DropdownListSeparator from '/imports/ui/components/dropdown/list/separator/component';
|
||||
import Dropdown from '/imports/ui/components/dropdown/component';
|
||||
import lockContextContainer from '/imports/ui/components/lock-viewers/context/container';
|
||||
import { withModalMounter } from '/imports/ui/components/modal/service';
|
||||
@ -293,7 +288,7 @@ class UserDropdown extends PureComponent {
|
||||
));
|
||||
}
|
||||
|
||||
actions.push(<DropdownListSeparator key={_.uniqueId('list-separator-')} />);
|
||||
actions.push(<Dropdown.DropdownListSeparator key={_.uniqueId('list-separator-')} />);
|
||||
|
||||
const statuses = Object.keys(getEmojiList);
|
||||
statuses.map(status => actions.push(this.makeDropdownItem(
|
||||
@ -465,7 +460,7 @@ class UserDropdown extends PureComponent {
|
||||
makeDropdownItem(key, label, onClick, icon = null, iconRight = null) {
|
||||
const { getEmoji } = this.props;
|
||||
return (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
{...{
|
||||
key,
|
||||
label,
|
||||
@ -672,24 +667,24 @@ class UserDropdown extends PureComponent {
|
||||
getContent={dropdownContent => this.dropdownContent = dropdownContent}
|
||||
tethered
|
||||
>
|
||||
<DropdownTrigger>
|
||||
<Dropdown.DropdownTrigger>
|
||||
{contents}
|
||||
</DropdownTrigger>
|
||||
<DropdownContent
|
||||
</Dropdown.DropdownTrigger>
|
||||
<Dropdown.DropdownContent
|
||||
style={{
|
||||
visibility: dropdownVisible ? 'visible' : 'hidden',
|
||||
}}
|
||||
className={styles.dropdownContent}
|
||||
placement={placement}
|
||||
>
|
||||
<DropdownList
|
||||
<Dropdown.DropdownList
|
||||
ref={(ref) => { this.list = ref; }}
|
||||
getDropdownMenuParent={this.getDropdownMenuParent}
|
||||
onActionsHide={this.onActionsHide}
|
||||
>
|
||||
{actions}
|
||||
</DropdownList>
|
||||
</DropdownContent>
|
||||
</Dropdown.DropdownList>
|
||||
</Dropdown.DropdownContent>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
|
@ -1,281 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { findDOMNode } from 'react-dom';
|
||||
import cx from 'classnames';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import deviceInfo from '/imports/utils/deviceInfo';
|
||||
import Button from '/imports/ui/components/button/component';
|
||||
import screenreaderTrap from 'makeup-screenreader-trap';
|
||||
import TetherComponent from 'react-tether';
|
||||
import { styles } from '/imports/ui/components/dropdown/styles';
|
||||
|
||||
import DropdownTrigger from '/imports/ui/components/dropdown/trigger/component';
|
||||
import DropdownContent from '/imports/ui/components/dropdown/content/component';
|
||||
|
||||
const intlMessages = defineMessages({
|
||||
close: {
|
||||
id: 'app.dropdown.close',
|
||||
description: 'Close button label',
|
||||
},
|
||||
});
|
||||
|
||||
const noop = () => { };
|
||||
|
||||
const propTypes = {
|
||||
/**
|
||||
* The dropdown needs a trigger and a content component as children
|
||||
*/
|
||||
children: (props, propName, componentName) => {
|
||||
const children = props[propName];
|
||||
|
||||
if (!children || children.length < 2) {
|
||||
return new Error(`Invalid prop \`${propName}\` supplied to`
|
||||
+ ` \`${componentName}\`. Validation failed.`);
|
||||
}
|
||||
|
||||
const trigger = children.find(x => x.type === DropdownTrigger);
|
||||
const content = children.find(x => x.type === DropdownContent);
|
||||
|
||||
if (!trigger) {
|
||||
return new Error(`Invalid prop \`${propName}\` supplied to`
|
||||
+ ` \`${componentName}\`. Missing \`DropdownTrigger\`. Validation failed.`);
|
||||
}
|
||||
|
||||
if (!content) {
|
||||
return new Error(`Invalid prop \`${propName}\` supplied to`
|
||||
+ ` \`${componentName}\`. Missing \`DropdownContent\`. Validation failed.`);
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
isOpen: PropTypes.bool,
|
||||
keepOpen: PropTypes.bool,
|
||||
onHide: PropTypes.func,
|
||||
onShow: PropTypes.func,
|
||||
autoFocus: PropTypes.bool,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
children: null,
|
||||
onShow: noop,
|
||||
onHide: noop,
|
||||
autoFocus: false,
|
||||
isOpen: false,
|
||||
keepOpen: null,
|
||||
};
|
||||
|
||||
const attachments = {
|
||||
'right-bottom': 'bottom left',
|
||||
'right-top': 'bottom left',
|
||||
};
|
||||
|
||||
const targetAttachments = {
|
||||
'right-bottom': 'bottom right',
|
||||
'right-top': 'top right',
|
||||
};
|
||||
|
||||
class Dropdown extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { isOpen: false };
|
||||
this.handleShow = this.handleShow.bind(this);
|
||||
this.handleHide = this.handleHide.bind(this);
|
||||
this.handleToggle = this.handleToggle.bind(this);
|
||||
this.handleWindowClick = this.handleWindowClick.bind(this);
|
||||
}
|
||||
|
||||
componentWillUpdate(nextProps, nextState) {
|
||||
return nextState.isOpen ? screenreaderTrap.trap(this.dropdown) : screenreaderTrap.untrap();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
const {
|
||||
onShow,
|
||||
onHide,
|
||||
keepOpen,
|
||||
} = this.props;
|
||||
const { isOpen } = this.state;
|
||||
|
||||
if (isOpen && !prevState.isOpen) { onShow(); }
|
||||
|
||||
if (!isOpen && prevState.isOpen) { onHide(); }
|
||||
|
||||
if (prevProps.keepOpen && !keepOpen) { onHide(); }
|
||||
}
|
||||
|
||||
handleShow() {
|
||||
Session.set('dropdownOpen', true);
|
||||
const {
|
||||
onShow,
|
||||
} = this.props;
|
||||
this.setState({ isOpen: true }, () => {
|
||||
const { addEventListener } = window;
|
||||
onShow();
|
||||
addEventListener('click', this.handleWindowClick, true);
|
||||
});
|
||||
}
|
||||
|
||||
handleHide() {
|
||||
Session.set('dropdownOpen', false);
|
||||
const { onHide } = this.props;
|
||||
this.setState({ isOpen: false }, () => {
|
||||
const { removeEventListener } = window;
|
||||
onHide();
|
||||
removeEventListener('click', this.handleWindowClick, true);
|
||||
});
|
||||
}
|
||||
|
||||
handleWindowClick(event) {
|
||||
const { keepOpen, onHide } = this.props;
|
||||
const { isOpen } = this.state;
|
||||
const triggerElement = findDOMNode(this.trigger);
|
||||
const contentElement = findDOMNode(this.content);
|
||||
if (!(triggerElement && contentElement)) return;
|
||||
if (triggerElement && triggerElement.contains(event.target)) {
|
||||
if (keepOpen) {
|
||||
onHide();
|
||||
return;
|
||||
}
|
||||
if (isOpen) {
|
||||
this.handleHide();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (keepOpen && isOpen && !contentElement.contains(event.target)) {
|
||||
if (triggerElement) {
|
||||
const { parentElement } = triggerElement;
|
||||
if (parentElement) parentElement.focus();
|
||||
}
|
||||
onHide();
|
||||
this.handleHide();
|
||||
return;
|
||||
}
|
||||
|
||||
if (keepOpen && triggerElement) {
|
||||
const { parentElement } = triggerElement;
|
||||
if (parentElement) parentElement.focus();
|
||||
}
|
||||
|
||||
if (keepOpen !== null) return;
|
||||
this.handleHide();
|
||||
}
|
||||
|
||||
handleToggle() {
|
||||
const { isOpen } = this.state;
|
||||
return isOpen ? this.handleHide() : this.handleShow();
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
children,
|
||||
className,
|
||||
intl,
|
||||
keepOpen,
|
||||
getContent,
|
||||
placement,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
const { isOpen } = this.state;
|
||||
|
||||
const { isMobile } = deviceInfo;
|
||||
|
||||
let trigger = children.find(x => x.type === DropdownTrigger);
|
||||
let content = children.find(x => x.type === DropdownContent);
|
||||
|
||||
trigger = React.cloneElement(trigger, {
|
||||
ref: (ref) => { this.trigger = ref; },
|
||||
dropdownIsOpen: isOpen,
|
||||
dropdownToggle: this.handleToggle,
|
||||
dropdownShow: this.handleShow,
|
||||
dropdownHide: this.handleHide,
|
||||
});
|
||||
|
||||
content = React.cloneElement(content, {
|
||||
ref: (ref) => {
|
||||
getContent(ref);
|
||||
this.content = ref;
|
||||
},
|
||||
keepOpen,
|
||||
'aria-expanded': isOpen,
|
||||
dropdownIsOpen: isOpen,
|
||||
dropdownToggle: this.handleToggle,
|
||||
dropdownShow: this.handleShow,
|
||||
dropdownHide: this.handleHide,
|
||||
});
|
||||
|
||||
const showCloseBtn = (isOpen && keepOpen) || (isOpen && keepOpen === null);
|
||||
const placements = placement.replace(' ', '-');
|
||||
// workaround
|
||||
const test = isMobile ? {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
transform: 'translateY(0)',
|
||||
} : {
|
||||
width: '',
|
||||
height: '',
|
||||
transform: '',
|
||||
};
|
||||
return (
|
||||
<div
|
||||
className={cx(styles.dropdown, className)}
|
||||
aria-live={otherProps['aria-live']}
|
||||
aria-relevant={otherProps['aria-relevant']}
|
||||
aria-haspopup={otherProps['aria-haspopup']}
|
||||
aria-label={otherProps['aria-label']}
|
||||
ref={(node) => { this.dropdown = node; }}
|
||||
tabIndex={-1}
|
||||
>
|
||||
<TetherComponent
|
||||
style={{
|
||||
zIndex: isOpen ? 15 : '',
|
||||
...test,
|
||||
}}
|
||||
attachment={
|
||||
isMobile ? 'middle bottom'
|
||||
: attachments[placements]
|
||||
}
|
||||
targetAttachment={
|
||||
isMobile ? ''
|
||||
: targetAttachments[placements]
|
||||
}
|
||||
|
||||
constraints={[
|
||||
{
|
||||
to: 'scrollParent',
|
||||
},
|
||||
]}
|
||||
|
||||
renderTarget={ref => (
|
||||
<span ref={ref}>
|
||||
{trigger}
|
||||
</span>)}
|
||||
renderElement={ref => (
|
||||
<div
|
||||
ref={ref}
|
||||
>
|
||||
{content}
|
||||
{showCloseBtn
|
||||
? (
|
||||
<Button
|
||||
className={styles.close}
|
||||
label={intl.formatMessage(intlMessages.close)}
|
||||
size="lg"
|
||||
color="default"
|
||||
onClick={this.handleHide}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Dropdown.propTypes = propTypes;
|
||||
Dropdown.defaultProps = defaultProps;
|
||||
export default injectIntl(Dropdown);
|
@ -5,16 +5,11 @@ import _ from 'lodash';
|
||||
import { withModalMounter } from '/imports/ui/components/modal/service';
|
||||
import Button from '/imports/ui/components/button/component';
|
||||
import Dropdown from '/imports/ui/components/dropdown/component';
|
||||
import DropdownTrigger from '/imports/ui/components/dropdown/trigger/component';
|
||||
import DropdownContent from '/imports/ui/components/dropdown/content/component';
|
||||
import DropdownList from '/imports/ui/components/dropdown/list/component';
|
||||
import DropdownListItem from '/imports/ui/components/dropdown/list/item/component';
|
||||
import LockViewersContainer from '/imports/ui/components/lock-viewers/container';
|
||||
import GuestPolicyContainer from '/imports/ui/components/waiting-users/guest-policy/container';
|
||||
import BreakoutRoom from '/imports/ui/components/actions-bar/create-breakout-room/container';
|
||||
import CaptionsService from '/imports/ui/components/captions/service';
|
||||
import CaptionsWriterMenu from '/imports/ui/components/captions/writer-menu/container';
|
||||
import DropdownListSeparator from '/imports/ui/components/dropdown/list/separator/component';
|
||||
import { styles } from './styles';
|
||||
import { getUserNamesLink } from '/imports/ui/components/user-list/service';
|
||||
|
||||
@ -244,7 +239,7 @@ class UserOptions extends PureComponent {
|
||||
|
||||
this.menuItems = _.compact([
|
||||
(isMeteorConnected ? (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
key={this.clearStatusId}
|
||||
icon="clear_status"
|
||||
label={intl.formatMessage(intlMessages.clearAllLabel)}
|
||||
@ -254,7 +249,7 @@ class UserOptions extends PureComponent {
|
||||
) : null
|
||||
),
|
||||
(!meetingIsBreakout && isMeteorConnected ? (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
key={this.muteAllId}
|
||||
icon={isMeetingMuted ? 'unmute' : 'mute'}
|
||||
label={intl.formatMessage(intlMessages[isMeetingMuted ? 'unmuteAllLabel' : 'muteAllLabel'])}
|
||||
@ -264,7 +259,7 @@ class UserOptions extends PureComponent {
|
||||
) : null
|
||||
),
|
||||
(!meetingIsBreakout && !isMeetingMuted && isMeteorConnected ? (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
key={this.muteId}
|
||||
icon="mute"
|
||||
label={intl.formatMessage(intlMessages.muteAllExceptPresenterLabel)}
|
||||
@ -275,7 +270,7 @@ class UserOptions extends PureComponent {
|
||||
),
|
||||
(amIModerator
|
||||
? (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
icon="download"
|
||||
label={intl.formatMessage(intlMessages.saveUserNames)}
|
||||
key={this.saveUsersNameId}
|
||||
@ -285,7 +280,7 @@ class UserOptions extends PureComponent {
|
||||
: null
|
||||
),
|
||||
(!meetingIsBreakout && isMeteorConnected ? (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
key={this.lockId}
|
||||
icon="lock"
|
||||
label={intl.formatMessage(intlMessages.lockViewersLabel)}
|
||||
@ -295,7 +290,7 @@ class UserOptions extends PureComponent {
|
||||
) : null
|
||||
),
|
||||
(!meetingIsBreakout && isMeteorConnected && dynamicGuestPolicy ? (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
key={this.guestPolicyId}
|
||||
icon="user"
|
||||
label={intl.formatMessage(intlMessages.guestPolicyLabel)}
|
||||
@ -305,9 +300,9 @@ class UserOptions extends PureComponent {
|
||||
/>
|
||||
) : null
|
||||
),
|
||||
(isMeteorConnected ? <DropdownListSeparator key={_.uniqueId('list-separator-')} /> : null),
|
||||
(isMeteorConnected ? <Dropdown.DropdownListSeparator key={_.uniqueId('list-separator-')} /> : null),
|
||||
(canCreateBreakout && isMeteorConnected ? (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
data-test="createBreakoutRooms"
|
||||
key={this.createBreakoutId}
|
||||
icon="rooms"
|
||||
@ -318,7 +313,7 @@ class UserOptions extends PureComponent {
|
||||
) : null
|
||||
),
|
||||
(canInviteUsers && isMeteorConnected ? (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
data-test="inviteBreakoutRooms"
|
||||
icon="rooms"
|
||||
label={intl.formatMessage(intlMessages.invitationItem)}
|
||||
@ -329,7 +324,7 @@ class UserOptions extends PureComponent {
|
||||
),
|
||||
(amIModerator && CaptionsService.isCaptionsEnabled() && isMeteorConnected
|
||||
? (
|
||||
<DropdownListItem
|
||||
<Dropdown.DropdownListItem
|
||||
icon="closed_caption"
|
||||
label={intl.formatMessage(intlMessages.captionsLabel)}
|
||||
description={intl.formatMessage(intlMessages.captionsDesc)}
|
||||
@ -356,7 +351,7 @@ class UserOptions extends PureComponent {
|
||||
onHide={this.onActionsHide}
|
||||
className={styles.dropdown}
|
||||
>
|
||||
<DropdownTrigger tabIndex={0}>
|
||||
<Dropdown.DropdownTrigger tabIndex={0}>
|
||||
<Button
|
||||
label={intl.formatMessage(intlMessages.optionsLabel)}
|
||||
data-test="manageUsers"
|
||||
@ -368,17 +363,17 @@ class UserOptions extends PureComponent {
|
||||
size="sm"
|
||||
onClick={() => null}
|
||||
/>
|
||||
</DropdownTrigger>
|
||||
<DropdownContent
|
||||
</Dropdown.DropdownTrigger>
|
||||
<Dropdown.DropdownContent
|
||||
className={styles.dropdownContent}
|
||||
placement="right top"
|
||||
>
|
||||
<DropdownList>
|
||||
<Dropdown.DropdownList>
|
||||
{
|
||||
this.renderMenuItems()
|
||||
}
|
||||
</DropdownList>
|
||||
</DropdownContent>
|
||||
</Dropdown.DropdownList>
|
||||
</Dropdown.DropdownContent>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
|
@ -5,12 +5,6 @@ import PropTypes from 'prop-types';
|
||||
import _ from 'lodash';
|
||||
import cx from 'classnames';
|
||||
import Dropdown from '/imports/ui/components/dropdown/component';
|
||||
import DropdownTrigger from '/imports/ui/components/dropdown/trigger/component';
|
||||
import DropdownContent from '/imports/ui/components/dropdown/content/component';
|
||||
import DropdownList from '/imports/ui/components/dropdown/list/component';
|
||||
import DropdownListTitle from '/imports/ui/components/dropdown/list/title/component';
|
||||
import DropdownListSeparator from '/imports/ui/components/dropdown/list/separator/component';
|
||||
import DropdownListItem from '/imports/ui/components/dropdown/list/item/component';
|
||||
import Icon from '/imports/ui/components/icon/component';
|
||||
import FullscreenService from '/imports/ui/components/fullscreen-button/service';
|
||||
import FullscreenButtonContainer from '/imports/ui/components/fullscreen-button/container';
|
||||
@ -141,9 +135,9 @@ class VideoListItem extends Component {
|
||||
} = this.props;
|
||||
|
||||
return _.compact([
|
||||
<DropdownListTitle className={styles.hiddenDesktop} key="name">{name}</DropdownListTitle>,
|
||||
<DropdownListSeparator className={styles.hiddenDesktop} key="sep" />,
|
||||
...actions.map(action => (<DropdownListItem key={`${cameraId}-${action.actionName}`} {...action} />)),
|
||||
<Dropdown.DropdownListTitle className={styles.hiddenDesktop} key="name">{name}</Dropdown.DropdownListTitle>,
|
||||
<Dropdown.DropdownListSeparator className={styles.hiddenDesktop} key="sep" />,
|
||||
...actions.map(action => (<Dropdown.DropdownListItem key={`${cameraId}-${action.actionName}`} {...action} />)),
|
||||
]);
|
||||
}
|
||||
|
||||
@ -242,14 +236,14 @@ class VideoListItem extends Component {
|
||||
{enableVideoMenu && availableActions.length >= 3
|
||||
? (
|
||||
<Dropdown tethered={isTethered} placement="right bottom" className={isFirefox ? styles.dropdownFireFox : styles.dropdown}>
|
||||
<DropdownTrigger className={styles.dropdownTrigger}>
|
||||
<Dropdown.DropdownTrigger className={styles.dropdownTrigger}>
|
||||
<span>{name}</span>
|
||||
</DropdownTrigger>
|
||||
<DropdownContent placement="top left" className={styles.dropdownContent}>
|
||||
<DropdownList className={styles.dropdownList}>
|
||||
</Dropdown.DropdownTrigger>
|
||||
<Dropdown.DropdownContent placement="top left" className={styles.dropdownContent}>
|
||||
<Dropdown.DropdownList className={styles.dropdownList}>
|
||||
{availableActions}
|
||||
</DropdownList>
|
||||
</DropdownContent>
|
||||
</Dropdown.DropdownList>
|
||||
</Dropdown.DropdownContent>
|
||||
</Dropdown>
|
||||
)
|
||||
: (
|
||||
|
Loading…
Reference in New Issue
Block a user