feat(ui-components) Add clickable icon component (#11976)

This commit is contained in:
Robert Pintilii 2022-08-05 15:07:44 +03:00 committed by GitHub
parent 5b34068435
commit 0f57c37d6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 93 additions and 66 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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)));