feat(ui-components) Add button component (#11868)
This commit is contained in:
parent
718d32990d
commit
b08ed3ade4
|
@ -0,0 +1,4 @@
|
||||||
|
declare module '*.svg' {
|
||||||
|
const content: any;
|
||||||
|
export default content;
|
||||||
|
}
|
|
@ -17,7 +17,9 @@ module.exports = {
|
||||||
'@typescript-eslint/no-empty-function': 'off',
|
'@typescript-eslint/no-empty-function': 'off',
|
||||||
'@typescript-eslint/ban-types': 'off',
|
'@typescript-eslint/ban-types': 'off',
|
||||||
'@typescript-eslint/no-explicit-any': 'off',
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
'no-prototype-builtins': 'off'
|
'no-prototype-builtins': 'off',
|
||||||
|
'no-shadow': 'off',
|
||||||
|
'@typescript-eslint/no-shadow': [ 'error' ]
|
||||||
},
|
},
|
||||||
'plugins': [ '@typescript-eslint' ],
|
'plugins': [ '@typescript-eslint' ],
|
||||||
'extends': [
|
'extends': [
|
||||||
|
|
|
@ -0,0 +1,195 @@
|
||||||
|
import { makeStyles } from '@material-ui/core';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import Icon from '../../icons/components/Icon';
|
||||||
|
import { BUTTON_TYPES } from '../../react/constants';
|
||||||
|
import { withPixelLineHeight } from '../../styles/functions.web';
|
||||||
|
|
||||||
|
import { ButtonProps } from './types';
|
||||||
|
|
||||||
|
interface IButtonProps extends ButtonProps {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the button should be full width.
|
||||||
|
*/
|
||||||
|
fullWidth?: boolean,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The id of the button.
|
||||||
|
*/
|
||||||
|
id?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Click callback.
|
||||||
|
*/
|
||||||
|
onClick: () => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Which size the button should be.
|
||||||
|
*/
|
||||||
|
size?: 'small' | 'medium' | 'large';
|
||||||
|
}
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme: any) => {
|
||||||
|
return {
|
||||||
|
button: {
|
||||||
|
backgroundColor: theme.palette.action01,
|
||||||
|
color: theme.palette.text01,
|
||||||
|
borderRadius: theme.shape.borderRadius,
|
||||||
|
padding: '10px 16px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
border: 0,
|
||||||
|
...withPixelLineHeight(theme.typography.bodyShortBold),
|
||||||
|
transition: 'background .2s',
|
||||||
|
cursor: 'pointer',
|
||||||
|
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: theme.palette.action01Hover
|
||||||
|
},
|
||||||
|
|
||||||
|
'&:active': {
|
||||||
|
backgroundColor: theme.palette.action01Active
|
||||||
|
},
|
||||||
|
|
||||||
|
'&:focus': {
|
||||||
|
outline: 0,
|
||||||
|
boxShadow: `0px 0px 0px 2px ${theme.palette.focus01}`
|
||||||
|
},
|
||||||
|
|
||||||
|
'& svg': {
|
||||||
|
fill: theme.palette.icon01
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
primary: {},
|
||||||
|
|
||||||
|
secondary: {
|
||||||
|
backgroundColor: theme.palette.action02,
|
||||||
|
color: theme.palette.text04,
|
||||||
|
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: theme.palette.action02Hover
|
||||||
|
},
|
||||||
|
|
||||||
|
'&:active': {
|
||||||
|
backgroundColor: theme.palette.action02Active
|
||||||
|
},
|
||||||
|
|
||||||
|
'& svg': {
|
||||||
|
fill: theme.palette.icon04
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
tertiary: {
|
||||||
|
backgroundColor: theme.palette.action03,
|
||||||
|
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: theme.palette.action03Hover
|
||||||
|
},
|
||||||
|
|
||||||
|
'&:active': {
|
||||||
|
backgroundColor: theme.palette.action03Active
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
destructive: {
|
||||||
|
backgroundColor: theme.palette.actionDanger,
|
||||||
|
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: theme.palette.actionDangerHover
|
||||||
|
},
|
||||||
|
|
||||||
|
'&:active': {
|
||||||
|
backgroundColor: theme.palette.actionDangerActive
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
disabled: {
|
||||||
|
backgroundColor: theme.palette.disabled01,
|
||||||
|
color: theme.palette.text03,
|
||||||
|
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: theme.palette.disabled01,
|
||||||
|
color: theme.palette.text03
|
||||||
|
},
|
||||||
|
|
||||||
|
'&:active': {
|
||||||
|
backgroundColor: theme.palette.disabled01,
|
||||||
|
color: theme.palette.text03
|
||||||
|
},
|
||||||
|
|
||||||
|
'& svg': {
|
||||||
|
fill: theme.palette.icon03
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
iconButton: {
|
||||||
|
padding: '10px'
|
||||||
|
},
|
||||||
|
|
||||||
|
textWithIcon: {
|
||||||
|
marginLeft: `${theme.spacing(2)}px`
|
||||||
|
},
|
||||||
|
|
||||||
|
small: {
|
||||||
|
padding: '8px 16px',
|
||||||
|
...withPixelLineHeight(theme.typography.labelBold),
|
||||||
|
|
||||||
|
'&.iconButton': {
|
||||||
|
padding: '6px'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
medium: {},
|
||||||
|
|
||||||
|
large: {
|
||||||
|
padding: '13px 16px',
|
||||||
|
...withPixelLineHeight(theme.typography.bodyShortBoldLarge),
|
||||||
|
|
||||||
|
'&.iconButton': {
|
||||||
|
padding: '14px'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
fullWidth: {
|
||||||
|
width: '100%'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const Button = ({
|
||||||
|
accessibilityLabel,
|
||||||
|
disabled,
|
||||||
|
fullWidth,
|
||||||
|
icon,
|
||||||
|
id,
|
||||||
|
label,
|
||||||
|
onClick,
|
||||||
|
size = 'medium',
|
||||||
|
type = BUTTON_TYPES.PRIMARY
|
||||||
|
}: IButtonProps) => {
|
||||||
|
const styles = useStyles();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
aria-label = { accessibilityLabel }
|
||||||
|
className = { clsx(styles.button, styles[type],
|
||||||
|
disabled && styles.disabled,
|
||||||
|
icon && !label && `${styles.iconButton} iconButton`,
|
||||||
|
styles[size], fullWidth && styles.fullWidth) }
|
||||||
|
disabled = { disabled }
|
||||||
|
{ ...(id ? { id } : {}) }
|
||||||
|
onClick = { onClick }
|
||||||
|
type = 'button'>
|
||||||
|
{icon && <Icon
|
||||||
|
size = { 20 }
|
||||||
|
src = { icon } />}
|
||||||
|
{label && <span className = { icon ? styles.textWithIcon : '' }>{label}</span>}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Button;
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { BUTTON_TYPES } from '../../react/constants';
|
||||||
|
|
||||||
|
export interface ButtonProps {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Label used for accessibility.
|
||||||
|
*/
|
||||||
|
accessibilityLabel: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the button is disabled.
|
||||||
|
*/
|
||||||
|
disabled?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The icon to be displayed on the button.
|
||||||
|
*/
|
||||||
|
icon?: Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The text to be displayed on the button.
|
||||||
|
*/
|
||||||
|
label?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of button to be displayed.
|
||||||
|
*/
|
||||||
|
type?: BUTTON_TYPES;
|
||||||
|
}
|
|
@ -1,8 +1,10 @@
|
||||||
// @flow
|
/* eslint-disable import/order */
|
||||||
|
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import { Container } from '../../react/base';
|
import { Container } from '../../react/base';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import { styleTypeToObject } from '../../styles';
|
import { styleTypeToObject } from '../../styles';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -15,7 +17,7 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* Color of the icon (if not provided by the style object).
|
* Color of the icon (if not provided by the style object).
|
||||||
*/
|
*/
|
||||||
color?: ?string,
|
color?: string,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Id prop (mainly for autotests).
|
* Id prop (mainly for autotests).
|
||||||
|
@ -35,7 +37,7 @@ type Props = {
|
||||||
/**
|
/**
|
||||||
* The size of the icon (if not provided by the style object).
|
* The size of the icon (if not provided by the style object).
|
||||||
*/
|
*/
|
||||||
size?: ?number | string,
|
size?: number | string,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The preloaded icon component to render.
|
* The preloaded icon component to render.
|
||||||
|
@ -82,12 +84,12 @@ type Props = {
|
||||||
*/
|
*/
|
||||||
ariaControls?: string,
|
ariaControls?: string,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TabIndex for the Icon.
|
* TabIndex for the Icon.
|
||||||
*/
|
*/
|
||||||
tabIndex?: number,
|
tabIndex?: number,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Role for the Icon.
|
* Role for the Icon.
|
||||||
*/
|
*/
|
||||||
role?: string,
|
role?: string,
|
||||||
|
@ -110,7 +112,7 @@ export const DEFAULT_SIZE = navigator.product === 'ReactNative' ? 36 : 22;
|
||||||
* Implements an Icon component that takes a loaded SVG file as prop and renders it as an icon.
|
* Implements an Icon component that takes a loaded SVG file as prop and renders it as an icon.
|
||||||
*
|
*
|
||||||
* @param {Props} props - The props of the component.
|
* @param {Props} props - The props of the component.
|
||||||
* @returns {Reactelement}
|
* @returns {ReactElement}
|
||||||
*/
|
*/
|
||||||
export default function Icon(props: Props) {
|
export default function Icon(props: Props) {
|
||||||
const {
|
const {
|
|
@ -1,5 +1,3 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
export { default as IconAdd } from './add.svg';
|
export { default as IconAdd } from './add.svg';
|
||||||
export { default as IconAddPeople } from './link.svg';
|
export { default as IconAddPeople } from './link.svg';
|
||||||
export { default as IconArrowBack } from './arrow_back.svg';
|
export { default as IconArrowBack } from './arrow_back.svg';
|
|
@ -11,13 +11,13 @@ import {
|
||||||
import BaseTheme from '../../../ui/components/BaseTheme.native';
|
import BaseTheme from '../../../ui/components/BaseTheme.native';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { BUTTON_MODES, BUTTON_TYPES } from '../../constants';
|
import { BUTTON_MODES, BUTTON_TYPES } from '../../constants';
|
||||||
import { ButtonProps } from '../../types';
|
import { IButtonProps } from '../../types';
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
|
||||||
|
|
||||||
const Button: React.FC<ButtonProps> = ({
|
const Button: React.FC<IButtonProps> = ({
|
||||||
accessibilityLabel,
|
accessibilityLabel,
|
||||||
color: buttonColor,
|
color: buttonColor,
|
||||||
disabled,
|
disabled,
|
||||||
|
@ -27,7 +27,7 @@ const Button: React.FC<ButtonProps> = ({
|
||||||
onPress,
|
onPress,
|
||||||
style,
|
style,
|
||||||
type
|
type
|
||||||
}: ButtonProps) => {
|
}: IButtonProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { CONTAINED } = BUTTON_MODES;
|
const { CONTAINED } = BUTTON_MODES;
|
||||||
const { DESTRUCTIVE, PRIMARY, SECONDARY, TERTIARY } = BUTTON_TYPES;
|
const { DESTRUCTIVE, PRIMARY, SECONDARY, TERTIARY } = BUTTON_TYPES;
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Z-index for components that are to be rendered like an overlay, to be over
|
* Z-index for components that are to be rendered like an overlay, to be over
|
||||||
* everything, such as modal-type of components, or dialogs.
|
* everything, such as modal-type of components, or dialogs.
|
||||||
|
@ -9,12 +7,12 @@ export const OVERLAY_Z_INDEX = 1000;
|
||||||
/**
|
/**
|
||||||
* The types of the buttons.
|
* The types of the buttons.
|
||||||
*/
|
*/
|
||||||
export const BUTTON_TYPES = {
|
export enum BUTTON_TYPES {
|
||||||
PRIMARY: 'primary',
|
PRIMARY = 'primary',
|
||||||
SECONDARY: 'secondary',
|
SECONDARY = 'secondary',
|
||||||
TERTIARY: 'tertiary',
|
TERTIARY = 'tertiary',
|
||||||
DESTRUCTIVE: 'destructive'
|
DESTRUCTIVE = 'destructive'
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The modes of the buttons.
|
* The modes of the buttons.
|
|
@ -1,13 +1,10 @@
|
||||||
export interface ButtonProps {
|
import { ButtonProps } from '../components/common/types';
|
||||||
accessibilityLabel?: string;
|
|
||||||
|
export interface IButtonProps extends ButtonProps {
|
||||||
color?: string;
|
color?: string;
|
||||||
disabled?: boolean;
|
|
||||||
icon?: JSX.Element;
|
|
||||||
label?: string;
|
|
||||||
labelStyle?: Object|undefined;
|
labelStyle?: Object|undefined;
|
||||||
onPress?: Function;
|
onPress?: Function;
|
||||||
style?: Object|undefined;
|
style?: Object|undefined;
|
||||||
type?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IconButtonProps {
|
export interface IconButtonProps {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// @flow
|
// @ts-ignore
|
||||||
|
import { StyleType } from './functions.any';
|
||||||
import { type StyleType } from './functions.any';
|
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
export * from './functions.any';
|
export * from './functions.any';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,7 +32,7 @@ export function getFixedPlatformStyle(style: StyleType): StyleType {
|
||||||
* @param {Object} base - The base object containing the `lineHeight` property.
|
* @param {Object} base - The base object containing the `lineHeight` property.
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
export function withPixelLineHeight(base: Object): Object {
|
export function withPixelLineHeight(base: any): Object {
|
||||||
return {
|
return {
|
||||||
...base,
|
...base,
|
||||||
lineHeight: `${base.lineHeight}px`
|
lineHeight: `${base.lineHeight}px`
|
|
@ -1,36 +1,27 @@
|
||||||
// @flow
|
/* eslint-disable lines-around-comment */
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/core/styles';
|
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
|
import Button from '../../../../../base/components/common/Button';
|
||||||
|
import { BUTTON_TYPES } from '../../../../../base/react/constants';
|
||||||
|
// @ts-ignore
|
||||||
import { createBreakoutRoom } from '../../../../../breakout-rooms/actions';
|
import { createBreakoutRoom } from '../../../../../breakout-rooms/actions';
|
||||||
import ParticipantPaneBaseButton from '../../../web/ParticipantPaneBaseButton';
|
|
||||||
|
|
||||||
const useStyles = makeStyles(() => {
|
|
||||||
return {
|
|
||||||
button: {
|
|
||||||
width: '100%'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
export const AddBreakoutRoomButton = () => {
|
export const AddBreakoutRoomButton = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const styles = useStyles();
|
|
||||||
|
|
||||||
const onAdd = useCallback(() =>
|
const onAdd = useCallback(() =>
|
||||||
dispatch(createBreakoutRoom())
|
dispatch(createBreakoutRoom())
|
||||||
, [ dispatch ]);
|
, [ dispatch ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ParticipantPaneBaseButton
|
<Button
|
||||||
accessibilityLabel = { t('breakoutRooms.actions.add') }
|
accessibilityLabel = { t('breakoutRooms.actions.add') }
|
||||||
className = { styles.button }
|
fullWidth = { true }
|
||||||
onClick = { onAdd }>
|
label = { t('breakoutRooms.actions.add') }
|
||||||
{t('breakoutRooms.actions.add')}
|
onClick = { onAdd }
|
||||||
</ParticipantPaneBaseButton>
|
type = { BUTTON_TYPES.SECONDARY } />
|
||||||
);
|
);
|
||||||
};
|
};
|
|
@ -1,42 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/styles';
|
|
||||||
import React, { useCallback } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useDispatch } from 'react-redux';
|
|
||||||
|
|
||||||
import { autoAssignToBreakoutRooms } from '../../../../../breakout-rooms/actions';
|
|
||||||
import ParticipantPaneBaseButton from '../../../web/ParticipantPaneBaseButton';
|
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
|
||||||
return {
|
|
||||||
button: {
|
|
||||||
color: theme.palette.link01,
|
|
||||||
width: '100%',
|
|
||||||
backgroundColor: 'transparent',
|
|
||||||
|
|
||||||
'&:hover': {
|
|
||||||
backgroundColor: 'transparent'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
export const AutoAssignButton = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const dispatch = useDispatch();
|
|
||||||
const styles = useStyles();
|
|
||||||
|
|
||||||
const onAutoAssign = useCallback(() => {
|
|
||||||
dispatch(autoAssignToBreakoutRooms());
|
|
||||||
}, [ dispatch ]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ParticipantPaneBaseButton
|
|
||||||
accessibilityLabel = { t('breakoutRooms.actions.autoAssign') }
|
|
||||||
className = { styles.button }
|
|
||||||
onClick = { onAutoAssign }>
|
|
||||||
{t('breakoutRooms.actions.autoAssign')}
|
|
||||||
</ParticipantPaneBaseButton>
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* eslint-disable lines-around-comment */
|
||||||
|
import React, { useCallback } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
|
import Button from '../../../../../base/components/common/Button';
|
||||||
|
import { BUTTON_TYPES } from '../../../../../base/react/constants';
|
||||||
|
// @ts-ignore
|
||||||
|
import { autoAssignToBreakoutRooms } from '../../../../../breakout-rooms/actions';
|
||||||
|
|
||||||
|
export const AutoAssignButton = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const onAutoAssign = useCallback(() => {
|
||||||
|
dispatch(autoAssignToBreakoutRooms());
|
||||||
|
}, [ dispatch ]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
accessibilityLabel = { t('breakoutRooms.actions.autoAssign') }
|
||||||
|
fullWidth = { true }
|
||||||
|
label = { t('breakoutRooms.actions.autoAssign') }
|
||||||
|
onClick = { onAutoAssign }
|
||||||
|
type = { BUTTON_TYPES.TERTIARY } />
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,44 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/styles';
|
|
||||||
import React, { useCallback } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useDispatch } from 'react-redux';
|
|
||||||
|
|
||||||
import { createBreakoutRoomsEvent, sendAnalytics } from '../../../../../analytics';
|
|
||||||
import { moveToRoom } from '../../../../../breakout-rooms/actions';
|
|
||||||
import ParticipantPaneBaseButton from '../../../web/ParticipantPaneBaseButton';
|
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
|
||||||
return {
|
|
||||||
button: {
|
|
||||||
color: theme.palette.textError,
|
|
||||||
backgroundColor: 'transparent',
|
|
||||||
width: '100%',
|
|
||||||
|
|
||||||
'&:hover': {
|
|
||||||
backgroundColor: 'transparent'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
export const LeaveButton = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const dispatch = useDispatch();
|
|
||||||
const styles = useStyles();
|
|
||||||
|
|
||||||
const onLeave = useCallback(() => {
|
|
||||||
sendAnalytics(createBreakoutRoomsEvent('leave'));
|
|
||||||
dispatch(moveToRoom());
|
|
||||||
}, [ dispatch ]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ParticipantPaneBaseButton
|
|
||||||
accessibilityLabel = { t('breakoutRooms.actions.leaveBreakoutRoom') }
|
|
||||||
className = { styles.button }
|
|
||||||
onClick = { onLeave }>
|
|
||||||
{t('breakoutRooms.actions.leaveBreakoutRoom')}
|
|
||||||
</ParticipantPaneBaseButton>
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
/* eslint-disable lines-around-comment */
|
||||||
|
import React, { useCallback } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import { createBreakoutRoomsEvent, sendAnalytics } from '../../../../../analytics';
|
||||||
|
import Button from '../../../../../base/components/common/Button';
|
||||||
|
import { BUTTON_TYPES } from '../../../../../base/react/constants';
|
||||||
|
// @ts-ignore
|
||||||
|
import { moveToRoom } from '../../../../../breakout-rooms/actions';
|
||||||
|
|
||||||
|
export const LeaveButton = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const onLeave = useCallback(() => {
|
||||||
|
sendAnalytics(createBreakoutRoomsEvent('leave'));
|
||||||
|
dispatch(moveToRoom());
|
||||||
|
}, [ dispatch ]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
accessibilityLabel = { t('breakoutRooms.actions.leaveBreakoutRoom') }
|
||||||
|
fullWidth = { true }
|
||||||
|
label = { t('breakoutRooms.actions.leaveBreakoutRoom') }
|
||||||
|
onClick = { onLeave }
|
||||||
|
type = { BUTTON_TYPES.DESTRUCTIVE } />
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,57 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/styles';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import ParticipantPaneBaseButton from './ParticipantPaneBaseButton';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Label used for accessibility.
|
|
||||||
*/
|
|
||||||
accessibilityLabel: String,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Children of the component.
|
|
||||||
*/
|
|
||||||
children: string | React$Node,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Button id.
|
|
||||||
*/
|
|
||||||
id?: string,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not the button is icon button (no text).
|
|
||||||
*/
|
|
||||||
isIconButton?: boolean,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Click handler.
|
|
||||||
*/
|
|
||||||
onClick: Function
|
|
||||||
}
|
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
|
||||||
return {
|
|
||||||
button: {
|
|
||||||
padding: `${theme.spacing(2)}px`
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const FooterButton = ({ accessibilityLabel, children, id, isIconButton = false, onClick }: Props) => {
|
|
||||||
const styles = useStyles();
|
|
||||||
|
|
||||||
return (<ParticipantPaneBaseButton
|
|
||||||
accessibilityLabel = { accessibilityLabel }
|
|
||||||
className = { isIconButton ? styles.button : '' }
|
|
||||||
id = { id }
|
|
||||||
onClick = { onClick }>
|
|
||||||
{children}
|
|
||||||
</ParticipantPaneBaseButton>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default FooterButton;
|
|
|
@ -1,48 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/styles';
|
|
||||||
import React, { useCallback } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useDispatch } from 'react-redux';
|
|
||||||
|
|
||||||
import { createToolbarEvent, sendAnalytics } from '../../../analytics';
|
|
||||||
import { Icon, IconInviteMore } from '../../../base/icons';
|
|
||||||
import { beginAddPeople } from '../../../invite';
|
|
||||||
|
|
||||||
import ParticipantPaneBaseButton from './ParticipantPaneBaseButton';
|
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
|
||||||
return {
|
|
||||||
button: {
|
|
||||||
width: '100%',
|
|
||||||
|
|
||||||
'& > *:not(:last-child)': {
|
|
||||||
marginRight: `${theme.spacing(2)}px`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
export const InviteButton = () => {
|
|
||||||
const dispatch = useDispatch();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const styles = useStyles();
|
|
||||||
|
|
||||||
const onInvite = useCallback(() => {
|
|
||||||
sendAnalytics(createToolbarEvent('invite'));
|
|
||||||
dispatch(beginAddPeople());
|
|
||||||
}, [ dispatch ]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ParticipantPaneBaseButton
|
|
||||||
accessibilityLabel = { t('participantsPane.actions.invite') }
|
|
||||||
className = { styles.button }
|
|
||||||
onClick = { onInvite }
|
|
||||||
primary = { true }>
|
|
||||||
<Icon
|
|
||||||
size = { 20 }
|
|
||||||
src = { IconInviteMore } />
|
|
||||||
<span>{t('participantsPane.actions.invite')}</span>
|
|
||||||
</ParticipantPaneBaseButton>
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/* eslint-disable lines-around-comment */
|
||||||
|
import React, { useCallback } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import { createToolbarEvent, sendAnalytics } from '../../../analytics';
|
||||||
|
import Button from '../../../base/components/common/Button';
|
||||||
|
import { IconInviteMore } from '../../../base/icons/svg/index';
|
||||||
|
import { BUTTON_TYPES } from '../../../base/react/constants';
|
||||||
|
// @ts-ignore
|
||||||
|
import { beginAddPeople } from '../../../invite';
|
||||||
|
|
||||||
|
export const InviteButton = () => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const onInvite = useCallback(() => {
|
||||||
|
sendAnalytics(createToolbarEvent('invite'));
|
||||||
|
dispatch(beginAddPeople());
|
||||||
|
}, [ dispatch ]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
accessibilityLabel = { t('participantsPane.actions.invite') }
|
||||||
|
fullWidth = { true }
|
||||||
|
icon = { IconInviteMore }
|
||||||
|
label = { t('participantsPane.actions.invite') }
|
||||||
|
onClick = { onInvite }
|
||||||
|
type = { BUTTON_TYPES.PRIMARY } />
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,98 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/styles';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
import participantsPaneTheme from '../../../base/components/themes/participantsPaneTheme.json';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Label used for accessibility.
|
|
||||||
*/
|
|
||||||
accessibilityLabel: String,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Additional class name for custom styles.
|
|
||||||
*/
|
|
||||||
className?: string,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Children of the component.
|
|
||||||
*/
|
|
||||||
children: string | React$Node,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Button id.
|
|
||||||
*/
|
|
||||||
id?: string,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Click handler.
|
|
||||||
*/
|
|
||||||
onClick: Function,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not the button should have primary button style.
|
|
||||||
*/
|
|
||||||
primary?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => {
|
|
||||||
return {
|
|
||||||
button: {
|
|
||||||
alignItems: 'center',
|
|
||||||
backgroundColor: theme.palette.ui03,
|
|
||||||
border: 0,
|
|
||||||
borderRadius: `${theme.shape.borderRadius}px`,
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
minHeight: '40px',
|
|
||||||
padding: `${theme.spacing(2)}px ${theme.spacing(3)}px`,
|
|
||||||
...theme.typography.labelButton,
|
|
||||||
lineHeight: `${theme.typography.labelButton.lineHeight}px`,
|
|
||||||
|
|
||||||
'&:hover': {
|
|
||||||
backgroundColor: theme.palette.ui04
|
|
||||||
},
|
|
||||||
|
|
||||||
[`@media (max-width: ${participantsPaneTheme.MD_BREAKPOINT})`]: {
|
|
||||||
...theme.typography.labelButtonLarge,
|
|
||||||
lineHeight: `${theme.typography.labelButtonLarge.lineHeight}px`,
|
|
||||||
minWidth: '48px',
|
|
||||||
minHeight: '48px'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
buttonPrimary: {
|
|
||||||
backgroundColor: theme.palette.action01,
|
|
||||||
|
|
||||||
'&:hover': {
|
|
||||||
backgroundColor: theme.palette.action01Hover
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const ParticipantPaneBaseButton = ({
|
|
||||||
accessibilityLabel,
|
|
||||||
className,
|
|
||||||
children,
|
|
||||||
id,
|
|
||||||
onClick,
|
|
||||||
primary = false
|
|
||||||
}: Props) => {
|
|
||||||
const styles = useStyles();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
aria-label = { accessibilityLabel }
|
|
||||||
className = { `${styles.button} ${primary ? styles.buttonPrimary : ''} ${className ?? ''}` }
|
|
||||||
id = { id }
|
|
||||||
onClick = { onClick }>
|
|
||||||
{children}
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ParticipantPaneBaseButton;
|
|
|
@ -3,11 +3,13 @@
|
||||||
import { withStyles } from '@material-ui/core';
|
import { withStyles } from '@material-ui/core';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
|
import Button from '../../../base/components/common/Button';
|
||||||
import participantsPaneTheme from '../../../base/components/themes/participantsPaneTheme.json';
|
import participantsPaneTheme from '../../../base/components/themes/participantsPaneTheme.json';
|
||||||
import { openDialog } from '../../../base/dialog';
|
import { openDialog } from '../../../base/dialog';
|
||||||
import { translate } from '../../../base/i18n';
|
import { translate } from '../../../base/i18n';
|
||||||
import { Icon, IconClose, IconHorizontalPoints } from '../../../base/icons';
|
import { Icon, IconClose, IconHorizontalPoints } from '../../../base/icons';
|
||||||
import { isLocalParticipantModerator } from '../../../base/participants/functions';
|
import { isLocalParticipantModerator } from '../../../base/participants/functions';
|
||||||
|
import { BUTTON_TYPES } from '../../../base/react/constants';
|
||||||
import { connect } from '../../../base/redux';
|
import { connect } from '../../../base/redux';
|
||||||
import { isAddBreakoutRoomButtonVisible } from '../../../breakout-rooms/functions';
|
import { isAddBreakoutRoomButtonVisible } from '../../../breakout-rooms/functions';
|
||||||
import { MuteEveryoneDialog } from '../../../video-menu/components/';
|
import { MuteEveryoneDialog } from '../../../video-menu/components/';
|
||||||
|
@ -21,7 +23,6 @@ import {
|
||||||
import { AddBreakoutRoomButton } from '../breakout-rooms/components/web/AddBreakoutRoomButton';
|
import { AddBreakoutRoomButton } from '../breakout-rooms/components/web/AddBreakoutRoomButton';
|
||||||
import { RoomList } from '../breakout-rooms/components/web/RoomList';
|
import { RoomList } from '../breakout-rooms/components/web/RoomList';
|
||||||
|
|
||||||
import FooterButton from './FooterButton';
|
|
||||||
import { FooterContextMenu } from './FooterContextMenu';
|
import { FooterContextMenu } from './FooterContextMenu';
|
||||||
import LobbyParticipants from './LobbyParticipants';
|
import LobbyParticipants from './LobbyParticipants';
|
||||||
import MeetingParticipants from './MeetingParticipants';
|
import MeetingParticipants from './MeetingParticipants';
|
||||||
|
@ -258,21 +259,20 @@ class ParticipantsPane extends Component<Props, State> {
|
||||||
{_showFooter && (
|
{_showFooter && (
|
||||||
<div className = { classes.footer }>
|
<div className = { classes.footer }>
|
||||||
{_showMuteAllButton && (
|
{_showMuteAllButton && (
|
||||||
<FooterButton
|
<Button
|
||||||
accessibilityLabel = { t('participantsPane.actions.muteAll') }
|
accessibilityLabel = { t('participantsPane.actions.muteAll') }
|
||||||
onClick = { this._onMuteAll }>
|
label = { t('participantsPane.actions.muteAll') }
|
||||||
{t('participantsPane.actions.muteAll')}
|
onClick = { this._onMuteAll }
|
||||||
</FooterButton>
|
type = { BUTTON_TYPES.SECONDARY } />
|
||||||
)}
|
)}
|
||||||
{_showMoreActionsButton && (
|
{_showMoreActionsButton && (
|
||||||
<div className = { classes.footerMoreContainer }>
|
<div className = { classes.footerMoreContainer }>
|
||||||
<FooterButton
|
<Button
|
||||||
accessibilityLabel = { t('participantsPane.actions.moreModerationActions') }
|
accessibilityLabel = { t('participantsPane.actions.moreModerationActions') }
|
||||||
|
icon = { IconHorizontalPoints }
|
||||||
id = 'participants-pane-context-menu'
|
id = 'participants-pane-context-menu'
|
||||||
isIconButton = { true }
|
onClick = { this._onToggleContext }
|
||||||
onClick = { this._onToggleContext }>
|
type = { BUTTON_TYPES.SECONDARY } />
|
||||||
<Icon src = { IconHorizontalPoints } />
|
|
||||||
</FooterButton>
|
|
||||||
<FooterContextMenu
|
<FooterContextMenu
|
||||||
isOpen = { contextOpen }
|
isOpen = { contextOpen }
|
||||||
onDrawerClose = { this._onDrawerClose }
|
onDrawerClose = { this._onDrawerClose }
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"include": ["react/features/**/*.ts", "react/features/**/*.tsx"],
|
"include": ["react/features/**/*.ts", "react/features/**/*.tsx", "./custom.d.ts"],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"module": "es6",
|
"module": "es6",
|
||||||
|
|
Loading…
Reference in New Issue