feat(ui-components) Add clickable icon component (#11976)
This commit is contained in:
parent
5b34068435
commit
0f57c37d6a
|
@ -50,7 +50,7 @@ export interface IConferenceState {
|
||||||
authEnabled?: boolean|undefined;
|
authEnabled?: boolean|undefined;
|
||||||
authLogin?: string|undefined;
|
authLogin?: string|undefined;
|
||||||
authRequired?: Object;
|
authRequired?: Object;
|
||||||
conference: Object|undefined;
|
conference: any|undefined;
|
||||||
conferenceTimestamp?: number;
|
conferenceTimestamp?: number;
|
||||||
e2eeSupported: boolean|undefined;
|
e2eeSupported: boolean|undefined;
|
||||||
followMeEnabled?: boolean;
|
followMeEnabled?: boolean;
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
import { makeStyles } from '@material-ui/core';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { isMobileBrowser } from '../../../environment/utils';
|
||||||
|
import Icon from '../../../icons/components/Icon';
|
||||||
|
import { Theme } from '../../types';
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
accessibilityLabel: string;
|
||||||
|
icon: Function;
|
||||||
|
onClick: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme: Theme) => {
|
||||||
|
return {
|
||||||
|
button: {
|
||||||
|
padding: '2px',
|
||||||
|
backgroundColor: theme.palette.action03,
|
||||||
|
border: 0,
|
||||||
|
outline: 0,
|
||||||
|
borderRadius: `${theme.shape.borderRadius}px`,
|
||||||
|
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: theme.palette.ui02
|
||||||
|
},
|
||||||
|
|
||||||
|
'&:active': {
|
||||||
|
backgroundColor: theme.palette.ui03
|
||||||
|
},
|
||||||
|
|
||||||
|
'&.is-mobile': {
|
||||||
|
padding: '10px'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const ClickableIcon = ({ accessibilityLabel, icon, onClick }: IProps) => {
|
||||||
|
const styles = useStyles();
|
||||||
|
const isMobile = isMobileBrowser();
|
||||||
|
|
||||||
|
return (<button
|
||||||
|
aria-label = { accessibilityLabel }
|
||||||
|
className = { clsx(styles.button, isMobile && 'is-mobile') }
|
||||||
|
onClick = { onClick }>
|
||||||
|
<Icon
|
||||||
|
size = { 24 }
|
||||||
|
src = { icon } />
|
||||||
|
</button>);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ClickableIcon;
|
|
@ -1,36 +1,50 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { withStyles } from '@material-ui/core';
|
import { withStyles } from '@material-ui/core';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import { WithTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
import { IState } from '../../../app/types';
|
||||||
import participantsPaneTheme from '../../../base/components/themes/participantsPaneTheme.json';
|
import participantsPaneTheme from '../../../base/components/themes/participantsPaneTheme.json';
|
||||||
|
// @ts-ignore
|
||||||
import { openDialog } from '../../../base/dialog';
|
import { openDialog } from '../../../base/dialog';
|
||||||
import { translate } from '../../../base/i18n';
|
import { translate } from '../../../base/i18n/functions';
|
||||||
import { Icon, IconClose, IconHorizontalPoints } from '../../../base/icons';
|
import { IconClose, IconHorizontalPoints } from '../../../base/icons/svg/index';
|
||||||
|
// @ts-ignore
|
||||||
import { isLocalParticipantModerator } from '../../../base/participants/functions';
|
import { isLocalParticipantModerator } from '../../../base/participants/functions';
|
||||||
import { connect } from '../../../base/redux';
|
import { connect } from '../../../base/redux/functions';
|
||||||
import Button from '../../../base/ui/components/web/Button';
|
import Button from '../../../base/ui/components/web/Button';
|
||||||
|
import ClickableIcon from '../../../base/ui/components/web/ClickableIcon';
|
||||||
import { BUTTON_TYPES } from '../../../base/ui/constants';
|
import { BUTTON_TYPES } from '../../../base/ui/constants';
|
||||||
|
import { Theme } from '../../../base/ui/types';
|
||||||
|
// @ts-ignore
|
||||||
import { isAddBreakoutRoomButtonVisible } from '../../../breakout-rooms/functions';
|
import { isAddBreakoutRoomButtonVisible } from '../../../breakout-rooms/functions';
|
||||||
|
// @ts-ignore
|
||||||
import { MuteEveryoneDialog } from '../../../video-menu/components/';
|
import { MuteEveryoneDialog } from '../../../video-menu/components/';
|
||||||
|
// @ts-ignore
|
||||||
import { close } from '../../actions';
|
import { close } from '../../actions';
|
||||||
import {
|
import {
|
||||||
findAncestorByClass,
|
findAncestorByClass,
|
||||||
getParticipantsPaneOpen,
|
getParticipantsPaneOpen,
|
||||||
isMoreActionsVisible,
|
isMoreActionsVisible,
|
||||||
isMuteAllVisible
|
isMuteAllVisible
|
||||||
|
// @ts-ignore
|
||||||
} from '../../functions';
|
} from '../../functions';
|
||||||
|
// @ts-ignore
|
||||||
import { AddBreakoutRoomButton } from '../breakout-rooms/components/web/AddBreakoutRoomButton';
|
import { AddBreakoutRoomButton } from '../breakout-rooms/components/web/AddBreakoutRoomButton';
|
||||||
|
// @ts-ignore
|
||||||
import { RoomList } from '../breakout-rooms/components/web/RoomList';
|
import { RoomList } from '../breakout-rooms/components/web/RoomList';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import { FooterContextMenu } from './FooterContextMenu';
|
import { FooterContextMenu } from './FooterContextMenu';
|
||||||
|
// @ts-ignore
|
||||||
import LobbyParticipants from './LobbyParticipants';
|
import LobbyParticipants from './LobbyParticipants';
|
||||||
|
// @ts-ignore
|
||||||
import MeetingParticipants from './MeetingParticipants';
|
import MeetingParticipants from './MeetingParticipants';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the React {@code Component} props of {@link ParticipantsPane}.
|
* The type of the React {@code Component} props of {@link ParticipantsPane}.
|
||||||
*/
|
*/
|
||||||
type Props = {
|
interface Props extends WithTranslation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether there is backend support for Breakout Rooms.
|
* Whether there is backend support for Breakout Rooms.
|
||||||
|
@ -52,6 +66,11 @@ type Props = {
|
||||||
*/
|
*/
|
||||||
_showAddRoomButton: boolean,
|
_showAddRoomButton: boolean,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to show the footer menu.
|
||||||
|
*/
|
||||||
|
_showFooter: boolean,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to show the more actions button.
|
* Whether to show the more actions button.
|
||||||
*/
|
*/
|
||||||
|
@ -63,25 +82,15 @@ type Props = {
|
||||||
_showMuteAllButton: boolean,
|
_showMuteAllButton: boolean,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to show the footer menu.
|
* An object containing the CSS classes.
|
||||||
*/
|
*/
|
||||||
_showFooter: boolean,
|
classes: any,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Redux dispatch function.
|
* The Redux dispatch function.
|
||||||
*/
|
*/
|
||||||
dispatch: Function,
|
dispatch: Function
|
||||||
|
}
|
||||||
/**
|
|
||||||
* An object containing the CSS classes.
|
|
||||||
*/
|
|
||||||
classes: Object,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The i18n translate function.
|
|
||||||
*/
|
|
||||||
t: Function
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the React {@code Component} state of {@link ParticipantsPane}.
|
* The type of the React {@code Component} state of {@link ParticipantsPane}.
|
||||||
|
@ -99,7 +108,7 @@ type State = {
|
||||||
searchString: string
|
searchString: string
|
||||||
};
|
};
|
||||||
|
|
||||||
const styles = theme => {
|
const styles = (theme: Theme) => {
|
||||||
return {
|
return {
|
||||||
container: {
|
container: {
|
||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
|
@ -170,7 +179,7 @@ class ParticipantsPane extends Component<Props, State> {
|
||||||
*
|
*
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
constructor(props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
|
@ -181,7 +190,6 @@ class ParticipantsPane extends Component<Props, State> {
|
||||||
// Bind event handlers so they are only bound once per instance.
|
// Bind event handlers so they are only bound once per instance.
|
||||||
this._onClosePane = this._onClosePane.bind(this);
|
this._onClosePane = this._onClosePane.bind(this);
|
||||||
this._onDrawerClose = this._onDrawerClose.bind(this);
|
this._onDrawerClose = this._onDrawerClose.bind(this);
|
||||||
this._onKeyPress = this._onKeyPress.bind(this);
|
|
||||||
this._onMuteAll = this._onMuteAll.bind(this);
|
this._onMuteAll = this._onMuteAll.bind(this);
|
||||||
this._onToggleContext = this._onToggleContext.bind(this);
|
this._onToggleContext = this._onToggleContext.bind(this);
|
||||||
this._onWindowClickListener = this._onWindowClickListener.bind(this);
|
this._onWindowClickListener = this._onWindowClickListener.bind(this);
|
||||||
|
@ -235,17 +243,10 @@ class ParticipantsPane extends Component<Props, State> {
|
||||||
<div className = 'participants_pane'>
|
<div className = 'participants_pane'>
|
||||||
<div className = 'participants_pane-content'>
|
<div className = 'participants_pane-content'>
|
||||||
<div className = { classes.header }>
|
<div className = { classes.header }>
|
||||||
<div
|
<ClickableIcon
|
||||||
aria-label = { t('participantsPane.close', 'Close') }
|
accessibilityLabel = { t('participantsPane.close', 'Close') }
|
||||||
className = { classes.closeButton }
|
icon = { IconClose }
|
||||||
onClick = { this._onClosePane }
|
onClick = { this._onClosePane } />
|
||||||
onKeyPress = { this._onKeyPress }
|
|
||||||
role = 'button'
|
|
||||||
tabIndex = { 0 }>
|
|
||||||
<Icon
|
|
||||||
size = { 24 }
|
|
||||||
src = { IconClose } />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className = { classes.container }>
|
<div className = { classes.container }>
|
||||||
<LobbyParticipants />
|
<LobbyParticipants />
|
||||||
|
@ -286,22 +287,18 @@ class ParticipantsPane extends Component<Props, State> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
setSearchString: (string) => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the search string.
|
* Sets the search string.
|
||||||
*
|
*
|
||||||
* @param {string} newSearchString - The new search string.
|
* @param {string} newSearchString - The new search string.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
setSearchString(newSearchString) {
|
setSearchString(newSearchString: string) {
|
||||||
this.setState({
|
this.setState({
|
||||||
searchString: newSearchString
|
searchString: newSearchString
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_onClosePane: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for closing the participant pane.
|
* Callback for closing the participant pane.
|
||||||
*
|
*
|
||||||
|
@ -312,8 +309,6 @@ class ParticipantsPane extends Component<Props, State> {
|
||||||
this.props.dispatch(close());
|
this.props.dispatch(close());
|
||||||
}
|
}
|
||||||
|
|
||||||
_onDrawerClose: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for closing the drawer.
|
* Callback for closing the drawer.
|
||||||
*
|
*
|
||||||
|
@ -326,24 +321,6 @@ class ParticipantsPane extends Component<Props, State> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_onKeyPress: (Object) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* KeyPress handler for accessibility for closing the participants pane.
|
|
||||||
*
|
|
||||||
* @param {Object} e - The key event to handle.
|
|
||||||
*
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
_onKeyPress(e) {
|
|
||||||
if (e.key === ' ' || e.key === 'Enter') {
|
|
||||||
e.preventDefault();
|
|
||||||
this._onClosePane();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_onMuteAll: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The handler for clicking mute all button.
|
* The handler for clicking mute all button.
|
||||||
*
|
*
|
||||||
|
@ -353,8 +330,6 @@ class ParticipantsPane extends Component<Props, State> {
|
||||||
this.props.dispatch(openDialog(MuteEveryoneDialog));
|
this.props.dispatch(openDialog(MuteEveryoneDialog));
|
||||||
}
|
}
|
||||||
|
|
||||||
_onToggleContext: () => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for toggling open/close of the footer context menu.
|
* Handler for toggling open/close of the footer context menu.
|
||||||
*
|
*
|
||||||
|
@ -366,15 +341,13 @@ class ParticipantsPane extends Component<Props, State> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_onWindowClickListener: (event: Object) => void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Window click event listener.
|
* Window click event listener.
|
||||||
*
|
*
|
||||||
* @param {Event} e - The click event.
|
* @param {Event} e - The click event.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_onWindowClickListener(e) {
|
_onWindowClickListener(e: any) {
|
||||||
if (this.state.contextOpen && !findAncestorByClass(e.target, this.props.classes.footerMoreContainer)) {
|
if (this.state.contextOpen && !findAncestorByClass(e.target, this.props.classes.footerMoreContainer)) {
|
||||||
this.setState({
|
this.setState({
|
||||||
contextOpen: false
|
contextOpen: false
|
||||||
|
@ -393,7 +366,7 @@ class ParticipantsPane extends Component<Props, State> {
|
||||||
* @protected
|
* @protected
|
||||||
* @returns {Props}
|
* @returns {Props}
|
||||||
*/
|
*/
|
||||||
function _mapStateToProps(state: Object) {
|
function _mapStateToProps(state: IState) {
|
||||||
const isPaneOpen = getParticipantsPaneOpen(state);
|
const isPaneOpen = getParticipantsPaneOpen(state);
|
||||||
const { conference } = state['features/base/conference'];
|
const { conference } = state['features/base/conference'];
|
||||||
const _isBreakoutRoomsSupported = conference?.getBreakoutRooms()?.isSupported();
|
const _isBreakoutRoomsSupported = conference?.getBreakoutRooms()?.isSupported();
|
||||||
|
@ -408,4 +381,5 @@ function _mapStateToProps(state: Object) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
export default translate(connect(_mapStateToProps)(withStyles(styles)(ParticipantsPane)));
|
export default translate(connect(_mapStateToProps)(withStyles(styles)(ParticipantsPane)));
|
Loading…
Reference in New Issue