feat(ui-components) Add Select component (#12182)
Remove @atlaskit/dropdown Convert some files to TS
This commit is contained in:
parent
f5e60a7ca4
commit
2d6e181a13
|
@ -11,7 +11,6 @@
|
|||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@amplitude/react-native": "2.7.0",
|
||||
"@atlaskit/dropdown-menu": "10.1.2",
|
||||
"@atlaskit/field-text-area": "8.0.4",
|
||||
"@atlaskit/flag": "14.1.0",
|
||||
"@atlaskit/icon": "21.2.0",
|
||||
|
@ -372,28 +371,6 @@
|
|||
"@babel/runtime": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@atlaskit/dropdown-menu": {
|
||||
"version": "10.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/dropdown-menu/-/dropdown-menu-10.1.2.tgz",
|
||||
"integrity": "sha512-1E03eM0aoXxwzTzRamnRrBsC9OX1mU2YATfDb45RZRmz+kOx0bw1q5xGXLQsHpUPZFgfK8rdFy8h94qvrucKsQ==",
|
||||
"dependencies": {
|
||||
"@atlaskit/analytics-next": "^8.0.0",
|
||||
"@atlaskit/button": "^15.1.0",
|
||||
"@atlaskit/droplist": "^11.0.0",
|
||||
"@atlaskit/icon": "^21.1.0",
|
||||
"@atlaskit/item": "^12.0.0",
|
||||
"@atlaskit/theme": "^11.0.0",
|
||||
"@babel/runtime": "^7.0.0",
|
||||
"array-find": "^1.0.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"react-uid": "^2.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0",
|
||||
"react-dom": "^16.8.0",
|
||||
"styled-components": "^3.2.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@atlaskit/droplist": {
|
||||
"version": "11.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/droplist/-/droplist-11.0.9.tgz",
|
||||
|
@ -7315,11 +7292,6 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/array-find": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/array-find/-/array-find-1.0.0.tgz",
|
||||
"integrity": "sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg="
|
||||
},
|
||||
"node_modules/array-flatten": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
|
||||
|
@ -20766,23 +20738,6 @@
|
|||
"@babel/runtime": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"@atlaskit/dropdown-menu": {
|
||||
"version": "10.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/dropdown-menu/-/dropdown-menu-10.1.2.tgz",
|
||||
"integrity": "sha512-1E03eM0aoXxwzTzRamnRrBsC9OX1mU2YATfDb45RZRmz+kOx0bw1q5xGXLQsHpUPZFgfK8rdFy8h94qvrucKsQ==",
|
||||
"requires": {
|
||||
"@atlaskit/analytics-next": "^8.0.0",
|
||||
"@atlaskit/button": "^15.1.0",
|
||||
"@atlaskit/droplist": "^11.0.0",
|
||||
"@atlaskit/icon": "^21.1.0",
|
||||
"@atlaskit/item": "^12.0.0",
|
||||
"@atlaskit/theme": "^11.0.0",
|
||||
"@babel/runtime": "^7.0.0",
|
||||
"array-find": "^1.0.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"react-uid": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"@atlaskit/droplist": {
|
||||
"version": "11.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@atlaskit/droplist/-/droplist-11.0.9.tgz",
|
||||
|
@ -25888,11 +25843,6 @@
|
|||
"resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
|
||||
"integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ="
|
||||
},
|
||||
"array-find": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/array-find/-/array-find-1.0.0.tgz",
|
||||
"integrity": "sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg="
|
||||
},
|
||||
"array-flatten": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
"readmeFilename": "README.md",
|
||||
"dependencies": {
|
||||
"@amplitude/react-native": "2.7.0",
|
||||
"@atlaskit/dropdown-menu": "10.1.2",
|
||||
"@atlaskit/field-text-area": "8.0.4",
|
||||
"@atlaskit/flag": "14.1.0",
|
||||
"@atlaskit/icon": "21.2.0",
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// @flow
|
||||
|
||||
import { Component } from 'react';
|
||||
|
||||
/**
|
||||
|
@ -10,17 +8,17 @@ export type Props = {
|
|||
/**
|
||||
* Function that closes the dialog.
|
||||
*/
|
||||
closeDialog: Function,
|
||||
closeDialog: Function;
|
||||
|
||||
/**
|
||||
* Callback to invoke on change.
|
||||
*/
|
||||
onTabStateChange: Function,
|
||||
onTabStateChange: Function;
|
||||
|
||||
/**
|
||||
* The id of the tab.
|
||||
*/
|
||||
tabId: number
|
||||
tabId: number;
|
||||
};
|
||||
|
||||
|
||||
|
@ -29,7 +27,7 @@ export type Props = {
|
|||
*
|
||||
* @augments Component
|
||||
*/
|
||||
class AbstractDialogTab<P: Props, S: *> extends Component<P, S> {
|
||||
class AbstractDialogTab<P extends Props, S> extends Component<P, S> {
|
||||
/**
|
||||
* Initializes a new {@code AbstractDialogTab} instance.
|
||||
*
|
||||
|
@ -43,8 +41,6 @@ class AbstractDialogTab<P: Props, S: *> extends Component<P, S> {
|
|||
this._onChange = this._onChange.bind(this);
|
||||
}
|
||||
|
||||
_onChange: (Object) => void;
|
||||
|
||||
/**
|
||||
* Uses the onTabStateChange function to pass the changed state of the
|
||||
* controlled tab component to the controlling DialogWithTabs component.
|
||||
|
@ -53,7 +49,7 @@ class AbstractDialogTab<P: Props, S: *> extends Component<P, S> {
|
|||
* value.
|
||||
* @returns {void}
|
||||
*/
|
||||
_onChange(change) {
|
||||
_onChange(change: Object) {
|
||||
const { onTabStateChange, tabId } = this.props;
|
||||
|
||||
onTabStateChange(tabId, {
|
|
@ -1,3 +1,3 @@
|
|||
<svg width="10" height="6" viewBox="0 0 10 6" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg width="10" height="6" viewBox="0 0 10 6" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.07001 0.248238C8.3471 -0.0596449 8.82132 -0.0846038 9.1292 0.192491C9.43709 0.469585 9.46205 0.943802 9.18495 1.25168L5.65622 5.19348C5.35829 5.52451 4.83922 5.52451 4.54128 5.19348L1.06752 1.25168C0.79043 0.943802 0.81539 0.469585 1.12327 0.192491C1.43115 -0.0846038 1.90537 -0.0596449 2.18247 0.248238L5.09875 3.57062L8.07001 0.248238Z"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 494 B After Width: | Height: | Size: 482 B |
|
@ -0,0 +1,179 @@
|
|||
import { Theme } from '@mui/material';
|
||||
import React, { ChangeEvent } from 'react';
|
||||
import { makeStyles } from 'tss-react/mui';
|
||||
|
||||
import { isMobileBrowser } from '../../../environment/utils';
|
||||
import Icon from '../../../icons/components/Icon';
|
||||
import { IconArrowDown } from '../../../icons/svg';
|
||||
import { withPixelLineHeight } from '../../../styles/functions.web';
|
||||
|
||||
interface SelectProps {
|
||||
|
||||
/**
|
||||
* Helper text to be displayed below the select.
|
||||
*/
|
||||
bottomLabel?: string;
|
||||
|
||||
/**
|
||||
* Class name for additional styles.
|
||||
*/
|
||||
className?: string;
|
||||
|
||||
/**
|
||||
* Wether or not the select is disabled.
|
||||
*/
|
||||
disabled?: boolean;
|
||||
|
||||
/**
|
||||
* Wether or not the select is in the error state.
|
||||
*/
|
||||
error?: boolean;
|
||||
|
||||
/**
|
||||
* Label to be displayed above the select.
|
||||
*/
|
||||
label?: string;
|
||||
|
||||
/**
|
||||
* Change handler.
|
||||
*/
|
||||
onChange: (e: ChangeEvent<HTMLSelectElement>) => void;
|
||||
|
||||
/**
|
||||
* The options of the select.
|
||||
*/
|
||||
options: Array<{
|
||||
label: string;
|
||||
value: number | string;
|
||||
}>;
|
||||
|
||||
/**
|
||||
* The value of the select.
|
||||
*/
|
||||
value: number | string;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles()((theme: Theme) => {
|
||||
return {
|
||||
container: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
},
|
||||
|
||||
label: {
|
||||
color: theme.palette.text01,
|
||||
...withPixelLineHeight(theme.typography.bodyShortRegular),
|
||||
marginBottom: theme.spacing(2),
|
||||
|
||||
'&.is-mobile': {
|
||||
...withPixelLineHeight(theme.typography.bodyShortRegularLarge)
|
||||
}
|
||||
},
|
||||
|
||||
selectContainer: {
|
||||
position: 'relative'
|
||||
},
|
||||
|
||||
select: {
|
||||
backgroundColor: theme.palette.ui03,
|
||||
borderRadius: `${theme.shape.borderRadius}px`,
|
||||
width: '100%',
|
||||
...withPixelLineHeight(theme.typography.bodyShortRegular),
|
||||
color: theme.palette.text01,
|
||||
padding: '8px 16px',
|
||||
paddingRight: '42px',
|
||||
border: 0,
|
||||
appearance: 'none',
|
||||
overflow: 'hidden',
|
||||
whiteSpace: 'nowrap',
|
||||
textOverflow: 'ellipsis',
|
||||
|
||||
'&:focus': {
|
||||
outline: 0,
|
||||
boxShadow: `0px 0px 0px 2px ${theme.palette.focus01}`
|
||||
},
|
||||
|
||||
'&:disabled': {
|
||||
color: theme.palette.text03
|
||||
},
|
||||
|
||||
'&.is-mobile': {
|
||||
...withPixelLineHeight(theme.typography.bodyShortRegularLarge),
|
||||
padding: '12px 16px',
|
||||
paddingRight: '46px'
|
||||
},
|
||||
|
||||
'&.error': {
|
||||
boxShadow: `0px 0px 0px 2px ${theme.palette.textError}`
|
||||
}
|
||||
},
|
||||
|
||||
icon: {
|
||||
position: 'absolute',
|
||||
top: '8px',
|
||||
right: '8px',
|
||||
pointerEvents: 'none',
|
||||
|
||||
'&.is-mobile': {
|
||||
top: '12px',
|
||||
right: '12px'
|
||||
}
|
||||
},
|
||||
|
||||
bottomLabel: {
|
||||
marginTop: theme.spacing(2),
|
||||
...withPixelLineHeight(theme.typography.labelRegular),
|
||||
color: theme.palette.text02,
|
||||
|
||||
'&.is-mobile': {
|
||||
...withPixelLineHeight(theme.typography.bodyShortRegular)
|
||||
},
|
||||
|
||||
'&.error': {
|
||||
color: theme.palette.textError
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const Select = ({
|
||||
bottomLabel,
|
||||
className,
|
||||
disabled,
|
||||
error,
|
||||
label,
|
||||
onChange,
|
||||
options,
|
||||
value }: SelectProps) => {
|
||||
const { classes, cx, theme } = useStyles();
|
||||
const isMobile = isMobileBrowser();
|
||||
|
||||
return (
|
||||
<div className = { classes.container }>
|
||||
{label && <span className = { cx(classes.label, isMobile && 'is-mobile') }>{label}</span>}
|
||||
<div className = { classes.selectContainer }>
|
||||
<select
|
||||
className = { cx(classes.select, isMobile && 'is-mobile', className, error && 'error') }
|
||||
disabled = { disabled }
|
||||
onChange = { onChange }
|
||||
value = { value }>
|
||||
{options.map(option => (<option
|
||||
key = { option.value }
|
||||
value = { option.value }>{option.label}</option>))}
|
||||
</select>
|
||||
<Icon
|
||||
className = { cx(classes.icon, isMobile && 'is-mobile') }
|
||||
color = { disabled ? theme.palette.icon03 : theme.palette.icon01 }
|
||||
size = { 22 }
|
||||
src = { IconArrowDown } />
|
||||
</div>
|
||||
{bottomLabel && (
|
||||
<span className = { cx(classes.bottomLabel, isMobile && 'is-mobile', error && 'error') }>
|
||||
{bottomLabel}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Select;
|
|
@ -1,12 +1,8 @@
|
|||
/* @flow */
|
||||
|
||||
import DropdownMenu, {
|
||||
DropdownItem,
|
||||
DropdownItemGroup
|
||||
} from '@atlaskit/dropdown-menu';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { translate } from '../../base/i18n/functions';
|
||||
import Select from '../../base/ui/components/web/Select';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link DeviceSelector}.
|
||||
|
@ -76,7 +72,6 @@ class DeviceSelector extends Component<Props> {
|
|||
super(props);
|
||||
|
||||
this._onSelect = this._onSelect.bind(this);
|
||||
this._createDropdownItem = this._createDropdownItem.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -98,7 +93,12 @@ class DeviceSelector extends Component<Props> {
|
|||
return this._renderNoDevices();
|
||||
}
|
||||
|
||||
const items = this.props.devices.map(this._createDropdownItem);
|
||||
const items = this.props.devices.map(device => {
|
||||
return {
|
||||
value: device.deviceId,
|
||||
label: device.label || device.deviceId
|
||||
};
|
||||
});
|
||||
const defaultSelected = this.props.devices.find(item =>
|
||||
item.deviceId === this.props.selectedDeviceId
|
||||
);
|
||||
|
@ -130,28 +130,6 @@ class DeviceSelector extends Component<Props> {
|
|||
);
|
||||
}
|
||||
|
||||
_createDropdownItem: (Object) => void;
|
||||
|
||||
/**
|
||||
* Creates an object in the format expected by AKDropdownMenu for an option.
|
||||
*
|
||||
* @param {MediaDeviceInfo} device - An object with a label and a deviceId.
|
||||
* @private
|
||||
* @returns {Object} The passed in media device description converted to a
|
||||
* format recognized as a valid AKDropdownMenu item.
|
||||
*/
|
||||
_createDropdownItem(device) {
|
||||
return (
|
||||
<DropdownItem
|
||||
data-deviceid = { device.deviceId }
|
||||
isSelected = { device.deviceId === this.props.selectedDeviceId }
|
||||
key = { device.deviceId }
|
||||
onClick = { this._onSelect }>
|
||||
{ device.label || device.deviceId }
|
||||
</DropdownItem>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a AKDropdownMenu Component using passed in props and options. If
|
||||
* the dropdown needs to be disabled, then only the AKDropdownMenu trigger
|
||||
|
@ -184,18 +162,10 @@ class DeviceSelector extends Component<Props> {
|
|||
|
||||
return (
|
||||
<div className = 'dropdown-menu'>
|
||||
<DropdownMenu
|
||||
shouldFitContainer = { true }
|
||||
trigger = { triggerText }
|
||||
triggerButtonProps = {{
|
||||
shouldFitContainer: true,
|
||||
id: this.props.id
|
||||
}}
|
||||
triggerType = 'button'>
|
||||
<DropdownItemGroup>
|
||||
{ options.items }
|
||||
</DropdownItemGroup>
|
||||
</DropdownMenu>
|
||||
<Select
|
||||
onChange = { this._onSelect }
|
||||
options = { options.items }
|
||||
value = { this.props.selectedDeviceId } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -211,7 +181,7 @@ class DeviceSelector extends Component<Props> {
|
|||
* @returns {void}
|
||||
*/
|
||||
_onSelect(e) {
|
||||
const deviceId = e.currentTarget.getAttribute('data-deviceid');
|
||||
const deviceId = e.target.value;
|
||||
|
||||
if (this.props.selectedDeviceId !== deviceId) {
|
||||
this.props.onSelect(deviceId);
|
||||
|
|
|
@ -1,196 +0,0 @@
|
|||
/* @flow */
|
||||
|
||||
import {
|
||||
DropdownItem,
|
||||
DropdownItemGroup,
|
||||
DropdownMenuStateless
|
||||
} from '@atlaskit/dropdown-menu';
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
import { translate } from '../../../../base/i18n';
|
||||
import { YOUTUBE_LIVE_DASHBOARD_URL } from '../constants';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link StreamKeyPicker}.
|
||||
*/
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Broadcasts available for selection. Each broadcast item should be an
|
||||
* object with a title for display in the dropdown and a boundStreamID to
|
||||
* return in the {@link onBroadcastSelected} callback.
|
||||
*/
|
||||
broadcasts: Array<Object>,
|
||||
|
||||
/**
|
||||
* Callback invoked when an item in the dropdown is selected. The selected
|
||||
* broadcast's boundStreamID will be passed back.
|
||||
*/
|
||||
onBroadcastSelected: Function,
|
||||
|
||||
/**
|
||||
* The boundStreamID of the broadcast that should display as selected in the
|
||||
* dropdown.
|
||||
*/
|
||||
selectedBoundStreamID: string,
|
||||
|
||||
/**
|
||||
* Invoked to obtain translated strings.
|
||||
*/
|
||||
t: Function
|
||||
};
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} state of {@link StreamKeyPicker}.
|
||||
*/
|
||||
type State = {
|
||||
|
||||
/**
|
||||
* Whether or not to display the dropdown menu to pick a YouTube broadcast.
|
||||
*/
|
||||
isDropdownOpen: boolean
|
||||
};
|
||||
|
||||
/**
|
||||
* A dropdown to select a YouTube broadcast.
|
||||
*
|
||||
* @augments Component
|
||||
*/
|
||||
class StreamKeyPicker extends PureComponent<Props, State> {
|
||||
/**
|
||||
* Default values for {@code StreamKeyForm} component's properties.
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
static defaultProps = {
|
||||
broadcasts: []
|
||||
};
|
||||
|
||||
/**
|
||||
* The initial state of a {@code StreamKeyForm} instance.
|
||||
*/
|
||||
state = {
|
||||
isDropdownOpen: false
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes a new {@code StreamKeyPicker} instance.
|
||||
*
|
||||
* @param {Props} props - The React {@code Component} props to initialize
|
||||
* the new {@code StreamKeyPicker} instance with.
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
// Bind event handlers so they are only bound once per instance.
|
||||
this._onDropdownOpenChange = this._onDropdownOpenChange.bind(this);
|
||||
this._onSelect = this._onSelect.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { broadcasts, selectedBoundStreamID, t } = this.props;
|
||||
|
||||
if (!broadcasts.length) {
|
||||
return (
|
||||
<a
|
||||
className = 'warning-text'
|
||||
href = { YOUTUBE_LIVE_DASHBOARD_URL }
|
||||
rel = 'noopener noreferrer'
|
||||
target = '_blank'>
|
||||
{ t('liveStreaming.getStreamKeyManually') }
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
const dropdownItems
|
||||
= broadcasts.map(broadcast => (
|
||||
<DropdownItem
|
||||
data-streamid = { broadcast.boundStreamID }
|
||||
key = { broadcast.boundStreamID }
|
||||
onClick = { this._onSelect }>
|
||||
{ broadcast.title }
|
||||
</DropdownItem>));
|
||||
const selected
|
||||
= this.props.broadcasts.find(
|
||||
broadcast => broadcast.boundStreamID === selectedBoundStreamID);
|
||||
const triggerText
|
||||
= (selected && selected.title) || t('liveStreaming.choose');
|
||||
|
||||
return (
|
||||
<div className = 'broadcast-dropdown dropdown-menu'>
|
||||
<DropdownMenuStateless
|
||||
isOpen = { this.state.isDropdownOpen }
|
||||
onItemActivated = { this._onSelect }
|
||||
onOpenChange = { this._onDropdownOpenChange }
|
||||
shouldFitContainer = { true }
|
||||
trigger = { triggerText }
|
||||
triggerButtonProps = {{
|
||||
className: 'broadcast-dropdown-trigger',
|
||||
shouldFitContainer: true
|
||||
}}
|
||||
triggerType = 'button'>
|
||||
<DropdownItemGroup>
|
||||
{ dropdownItems }
|
||||
</DropdownItemGroup>
|
||||
</DropdownMenuStateless>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the passed in broadcasts into an array of objects that can
|
||||
* be parsed by {@code DropdownMenuStateless}.
|
||||
*
|
||||
* @param {Array<Object>} broadcasts - The YouTube broadcasts to display.
|
||||
* @private
|
||||
* @returns {Array<Object>}
|
||||
*/
|
||||
_formatBroadcasts(broadcasts) {
|
||||
return broadcasts.map(broadcast => {
|
||||
return {
|
||||
content: broadcast.title,
|
||||
value: broadcast
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
_onDropdownOpenChange: (Object) => void;
|
||||
|
||||
/**
|
||||
* Sets the dropdown to be displayed or not based on the passed in event.
|
||||
*
|
||||
* @param {Object} dropdownEvent - The event passed from
|
||||
* {@code DropdownMenuStateless} indicating if the dropdown should be open
|
||||
* or closed.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onDropdownOpenChange(dropdownEvent) {
|
||||
this.setState({
|
||||
isDropdownOpen: dropdownEvent.isOpen
|
||||
});
|
||||
}
|
||||
|
||||
_onSelect: (string) => void;
|
||||
|
||||
/**
|
||||
* Callback invoked when an item has been clicked in the dropdown menu.
|
||||
*
|
||||
* @param {Object} e - The key event to handle.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_onSelect(e) {
|
||||
const streamId = e.currentTarget.getAttribute('data-streamid');
|
||||
|
||||
this.props.onBroadcastSelected(streamId);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(StreamKeyPicker);
|
|
@ -0,0 +1,125 @@
|
|||
import React, { PureComponent } from 'react';
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
|
||||
import { translate } from '../../../../base/i18n/functions';
|
||||
import Select from '../../../../base/ui/components/web/Select';
|
||||
import { YOUTUBE_LIVE_DASHBOARD_URL } from '../constants';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link StreamKeyPicker}.
|
||||
*/
|
||||
interface Props extends WithTranslation {
|
||||
|
||||
/**
|
||||
* Broadcasts available for selection. Each broadcast item should be an
|
||||
* object with a title for display in the dropdown and a boundStreamID to
|
||||
* return in the {@link onBroadcastSelected} callback.
|
||||
*/
|
||||
broadcasts: Array<{
|
||||
boundStreamID: string;
|
||||
title: string;
|
||||
}>;
|
||||
|
||||
/**
|
||||
* Callback invoked when an item in the dropdown is selected. The selected
|
||||
* broadcast's boundStreamID will be passed back.
|
||||
*/
|
||||
onBroadcastSelected: Function;
|
||||
|
||||
/**
|
||||
* The boundStreamID of the broadcast that should display as selected in the
|
||||
* dropdown.
|
||||
*/
|
||||
selectedBoundStreamID: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A dropdown to select a YouTube broadcast.
|
||||
*
|
||||
* @augments Component
|
||||
*/
|
||||
class StreamKeyPicker extends PureComponent<Props> {
|
||||
/**
|
||||
* Default values for {@code StreamKeyForm} component's properties.
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
static defaultProps = {
|
||||
broadcasts: []
|
||||
};
|
||||
|
||||
/**
|
||||
* The initial state of a {@code StreamKeyForm} instance.
|
||||
*/
|
||||
state = {
|
||||
isDropdownOpen: false
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes a new {@code StreamKeyPicker} instance.
|
||||
*
|
||||
* @param {Props} props - The React {@code Component} props to initialize
|
||||
* the new {@code StreamKeyPicker} instance with.
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
// Bind event handlers so they are only bound once per instance.
|
||||
this._onSelect = this._onSelect.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { broadcasts, selectedBoundStreamID, t } = this.props;
|
||||
|
||||
if (!broadcasts.length) {
|
||||
return (
|
||||
<a
|
||||
className = 'warning-text'
|
||||
href = { YOUTUBE_LIVE_DASHBOARD_URL }
|
||||
rel = 'noopener noreferrer'
|
||||
target = '_blank'>
|
||||
{ t('liveStreaming.getStreamKeyManually') }
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
const dropdownItems
|
||||
= broadcasts.map(broadcast => {
|
||||
return {
|
||||
value: broadcast.boundStreamID,
|
||||
label: broadcast.title
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<div className = 'broadcast-dropdown dropdown-menu'>
|
||||
<Select
|
||||
label = { t('liveStreaming.choose') }
|
||||
onChange = { this._onSelect }
|
||||
options = { dropdownItems }
|
||||
value = { selectedBoundStreamID } />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked when an item has been clicked in the dropdown menu.
|
||||
*
|
||||
* @param {Object} e - The key event to handle.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
_onSelect(e: React.ChangeEvent<HTMLSelectElement>) {
|
||||
const streamId = e.target.value;
|
||||
|
||||
this.props.onBroadcastSelected(streamId);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(StreamKeyPicker);
|
|
@ -10,7 +10,7 @@ import { translate } from '../../../base/i18n/functions';
|
|||
import Checkbox from '../../../base/ui/components/web/Checkbox';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link MoreTab}.
|
||||
* The type of the React {@code Component} props of {@link ModeratorTab}.
|
||||
*/
|
||||
export type Props = AbstractDialogTabProps & WithTranslation & {
|
||||
|
||||
|
@ -60,7 +60,7 @@ export type Props = AbstractDialogTabProps & WithTranslation & {
|
|||
*/
|
||||
class ModeratorTab extends AbstractDialogTab<Props> {
|
||||
/**
|
||||
* Initializes a new {@code MoreTab} instance.
|
||||
* Initializes a new {@code ModeratorTab} instance.
|
||||
*
|
||||
* @param {Object} props - The read-only properties with which the new
|
||||
* instance is to be initialized.
|
||||
|
|
|
@ -1,23 +1,16 @@
|
|||
/* eslint-disable lines-around-comment */
|
||||
import DropdownMenu, {
|
||||
DropdownItem,
|
||||
DropdownItemGroup
|
||||
} from '@atlaskit/dropdown-menu';
|
||||
import React from 'react';
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
|
||||
// @ts-ignore
|
||||
import keyboardShortcut from '../../../../../modules/keyboardshortcut/keyboardshortcut';
|
||||
// @ts-ignore
|
||||
import { AbstractDialogTab } from '../../../base/dialog';
|
||||
// @ts-ignore
|
||||
import type { Props as AbstractDialogTabProps } from '../../../base/dialog';
|
||||
import AbstractDialogTab, {
|
||||
Props as AbstractDialogTabProps
|
||||
} from '../../../base/dialog/components/web/AbstractDialogTab';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
import Checkbox from '../../../base/ui/components/web/Checkbox';
|
||||
// @ts-ignore
|
||||
import TouchmoveHack from '../../../chat/components/web/TouchmoveHack';
|
||||
import Select from '../../../base/ui/components/web/Select';
|
||||
import { MAX_ACTIVE_PARTICIPANTS } from '../../../filmstrip/constants';
|
||||
// @ts-ignore
|
||||
import { SS_DEFAULT_FRAME_RATE } from '../../constants';
|
||||
|
||||
/**
|
||||
|
@ -66,6 +59,11 @@ export type Props = AbstractDialogTabProps & WithTranslation & {
|
|||
*/
|
||||
languages: Array<string>;
|
||||
|
||||
/**
|
||||
* The number of max participants to display on stage.
|
||||
*/
|
||||
maxStageParticipants: number;
|
||||
|
||||
/**
|
||||
* Whether or not to display the language select dropdown.
|
||||
*/
|
||||
|
@ -91,34 +89,23 @@ export type Props = AbstractDialogTabProps & WithTranslation & {
|
|||
*/
|
||||
showPrejoinSettings: boolean;
|
||||
|
||||
/**
|
||||
* Wether or not the stage filmstrip is enabled.
|
||||
*/
|
||||
stageFilmstripEnabled: boolean;
|
||||
|
||||
/**
|
||||
* Invoked to obtain translated strings.
|
||||
*/
|
||||
t: Function;
|
||||
};
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} state of {@link MoreTab}.
|
||||
*/
|
||||
type State = {
|
||||
|
||||
/**
|
||||
* Whether or not the desktop share frame rate select dropdown is open.
|
||||
*/
|
||||
isFramerateSelectOpen: boolean;
|
||||
|
||||
/**
|
||||
* Whether or not the language select dropdown is open.
|
||||
*/
|
||||
isLanguageSelectOpen: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* React {@code Component} for modifying language and moderator settings.
|
||||
*
|
||||
* @augments Component
|
||||
*/
|
||||
class MoreTab extends AbstractDialogTab<Props, State> {
|
||||
class MoreTab extends AbstractDialogTab<Props, {}> {
|
||||
/**
|
||||
* Initializes a new {@code MoreTab} instance.
|
||||
*
|
||||
|
@ -128,17 +115,8 @@ class MoreTab extends AbstractDialogTab<Props, State> {
|
|||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
// @ts-ignore
|
||||
this.state = {
|
||||
isFramerateSelectOpen: false,
|
||||
isLanguageSelectOpen: false,
|
||||
isMaxStageParticipantsOpen: false
|
||||
};
|
||||
|
||||
// Bind event handler so it is only bound once for every instance.
|
||||
this._onFramerateDropdownOpenChange = this._onFramerateDropdownOpenChange.bind(this);
|
||||
this._onFramerateItemSelect = this._onFramerateItemSelect.bind(this);
|
||||
this._onLanguageDropdownOpenChange = this._onLanguageDropdownOpenChange.bind(this);
|
||||
this._onLanguageItemSelect = this._onLanguageItemSelect.bind(this);
|
||||
this._onEnabledNotificationsChanged = this._onEnabledNotificationsChanged.bind(this);
|
||||
this._onShowPrejoinPageChanged = this._onShowPrejoinPageChanged.bind(this);
|
||||
|
@ -146,7 +124,6 @@ class MoreTab extends AbstractDialogTab<Props, State> {
|
|||
this._onHideSelfViewChanged = this._onHideSelfViewChanged.bind(this);
|
||||
this._renderMaxStageParticipantsSelect = this._renderMaxStageParticipantsSelect.bind(this);
|
||||
this._onMaxStageParticipantsSelect = this._onMaxStageParticipantsSelect.bind(this);
|
||||
this._onMaxStageParticipantsOpenChange = this._onMaxStageParticipantsOpenChange.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -170,18 +147,6 @@ class MoreTab extends AbstractDialogTab<Props, State> {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked to toggle display of the desktop share framerate select dropdown.
|
||||
*
|
||||
* @param {Object} event - The event for opening or closing the dropdown.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onFramerateDropdownOpenChange({ isOpen }: { isOpen: boolean; }) {
|
||||
// @ts-ignore
|
||||
this.setState({ isFramerateSelectOpen: isOpen });
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked to select a frame rate from the select dropdown.
|
||||
*
|
||||
|
@ -190,23 +155,11 @@ class MoreTab extends AbstractDialogTab<Props, State> {
|
|||
* @returns {void}
|
||||
*/
|
||||
_onFramerateItemSelect(e: React.ChangeEvent<HTMLSelectElement>) {
|
||||
const frameRate = e.currentTarget.getAttribute('data-framerate');
|
||||
const frameRate = e.target.value;
|
||||
|
||||
super._onChange({ currentFramerate: frameRate });
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked to toggle display of the language select dropdown.
|
||||
*
|
||||
* @param {Object} event - The event for opening or closing the dropdown.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onLanguageDropdownOpenChange({ isOpen }: { isOpen: boolean; }) {
|
||||
// @ts-ignore
|
||||
this.setState({ isLanguageSelectOpen: isOpen });
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked to select a language from select dropdown.
|
||||
*
|
||||
|
@ -215,7 +168,7 @@ class MoreTab extends AbstractDialogTab<Props, State> {
|
|||
* @returns {void}
|
||||
*/
|
||||
_onLanguageItemSelect(e: React.ChangeEvent<HTMLSelectElement>) {
|
||||
const language = e.currentTarget.getAttribute('data-language');
|
||||
const language = e.target.value;
|
||||
|
||||
super._onChange({ currentLanguage: language });
|
||||
}
|
||||
|
@ -244,7 +197,6 @@ class MoreTab extends AbstractDialogTab<Props, State> {
|
|||
_onEnabledNotificationsChanged({ target: { checked } }: React.ChangeEvent<HTMLInputElement>, type: any) {
|
||||
super._onChange({
|
||||
enabledNotifications: {
|
||||
// @ts-ignore
|
||||
...this.props.enabledNotifications,
|
||||
[type]: checked
|
||||
}
|
||||
|
@ -275,18 +227,6 @@ class MoreTab extends AbstractDialogTab<Props, State> {
|
|||
super._onChange({ hideSelfView: checked });
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked to toggle display of the max stage participants select dropdown.
|
||||
*
|
||||
* @param {Object} event - The event for opening or closing the dropdown.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onMaxStageParticipantsOpenChange({ isOpen }: { isOpen: boolean; }) {
|
||||
// @ts-ignore
|
||||
this.setState({ isMaxStageParticipantsOpen: isOpen });
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked to select a max number of stage participants from the select dropdown.
|
||||
*
|
||||
|
@ -306,50 +246,27 @@ class MoreTab extends AbstractDialogTab<Props, State> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderFramerateSelect() {
|
||||
// @ts-ignore
|
||||
const { currentFramerate, desktopShareFramerates, t } = this.props;
|
||||
const frameRateItems = desktopShareFramerates.map((frameRate: string) => (
|
||||
<DropdownItem
|
||||
data-framerate = { frameRate }
|
||||
key = { frameRate }
|
||||
onClick = { this._onFramerateItemSelect }>
|
||||
{ `${frameRate} ${t('settings.framesPerSecond')}` }
|
||||
</DropdownItem>));
|
||||
const frameRateItems = desktopShareFramerates.map((frameRate: number) => {
|
||||
return {
|
||||
value: frameRate,
|
||||
label: `${frameRate} ${t('settings.framesPerSecond')}`
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
className = 'settings-sub-pane-element'
|
||||
key = 'frameRate'>
|
||||
<h2 className = 'mock-atlaskit-label'>
|
||||
{ t('settings.desktopShareFramerate') }
|
||||
</h2>
|
||||
<div className = 'dropdown-menu'>
|
||||
<TouchmoveHack
|
||||
flex = { true }
|
||||
isModal = { true }>
|
||||
<DropdownMenu
|
||||
// @ts-ignore
|
||||
isOpen = { this.state.isFramerateSelectOpen }
|
||||
onOpenChange = { this._onFramerateDropdownOpenChange }
|
||||
shouldFitContainer = { true }
|
||||
trigger = { currentFramerate
|
||||
? `${currentFramerate} ${t('settings.framesPerSecond')}`
|
||||
: '' }
|
||||
triggerButtonProps = {{
|
||||
shouldFitContainer: true
|
||||
}}
|
||||
triggerType = 'button'>
|
||||
<DropdownItemGroup>
|
||||
{ frameRateItems }
|
||||
</DropdownItemGroup>
|
||||
</DropdownMenu>
|
||||
</TouchmoveHack>
|
||||
</div>
|
||||
<div
|
||||
className = 'mock-atlaskit-label'>
|
||||
{ parseInt(currentFramerate, 10) > SS_DEFAULT_FRAME_RATE
|
||||
? t('settings.desktopShareHighFpsWarning')
|
||||
: t('settings.desktopShareWarning') }
|
||||
<Select
|
||||
bottomLabel = { parseInt(currentFramerate, 10) > SS_DEFAULT_FRAME_RATE
|
||||
? t('settings.desktopShareHighFpsWarning')
|
||||
: t('settings.desktopShareWarning') }
|
||||
label = { t('settings.desktopShareFramerate') }
|
||||
onChange = { this._onFramerateItemSelect }
|
||||
options = { frameRateItems }
|
||||
value = { currentFramerate } />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -362,16 +279,15 @@ class MoreTab extends AbstractDialogTab<Props, State> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderKeyboardShortcutCheckbox() {
|
||||
// @ts-ignore
|
||||
const { t } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className = 'settings-sub-pane-element'
|
||||
key = 'keyboard-shortcut'>
|
||||
<h2 className = 'mock-atlaskit-label'>
|
||||
<span className = 'checkbox-label'>
|
||||
{ t('keyboardShortcuts.keyboardShortcuts') }
|
||||
</h2>
|
||||
</span>
|
||||
<Checkbox
|
||||
checked = { keyboardShortcut.getEnabled() }
|
||||
label = { t('prejoin.keyboardShortcuts') }
|
||||
|
@ -388,16 +304,15 @@ class MoreTab extends AbstractDialogTab<Props, State> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderSelfViewCheckbox() {
|
||||
// @ts-ignore
|
||||
const { hideSelfView, t } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className = 'settings-sub-pane-element'
|
||||
key = 'selfview'>
|
||||
<h2 className = 'mock-atlaskit-label'>
|
||||
<span className = 'checkbox-label'>
|
||||
{ t('settings.selfView') }
|
||||
</h2>
|
||||
</span>
|
||||
<Checkbox
|
||||
checked = { hideSelfView }
|
||||
label = { t('videothumbnail.hideSelfView') }
|
||||
|
@ -418,46 +333,26 @@ class MoreTab extends AbstractDialogTab<Props, State> {
|
|||
currentLanguage,
|
||||
languages,
|
||||
t
|
||||
// @ts-ignore
|
||||
} = this.props;
|
||||
|
||||
const languageItems
|
||||
= languages.map((language: string) => (
|
||||
<DropdownItem
|
||||
data-language = { language }
|
||||
key = { language }
|
||||
onClick = { this._onLanguageItemSelect }>
|
||||
{ t(`languages:${language}`) }
|
||||
</DropdownItem>));
|
||||
= languages.map((language: string) => {
|
||||
return {
|
||||
value: language,
|
||||
label: t(`languages:${language}`)
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
className = 'settings-sub-pane-element'
|
||||
key = 'language'>
|
||||
<h2 className = 'mock-atlaskit-label'>
|
||||
{ t('settings.language') }
|
||||
</h2>
|
||||
<div className = 'dropdown-menu'>
|
||||
<TouchmoveHack
|
||||
flex = { true }
|
||||
isModal = { true }>
|
||||
<DropdownMenu
|
||||
// @ts-ignore
|
||||
isOpen = { this.state.isLanguageSelectOpen }
|
||||
onOpenChange = { this._onLanguageDropdownOpenChange }
|
||||
shouldFitContainer = { true }
|
||||
trigger = { currentLanguage
|
||||
? t(`languages:${currentLanguage}`)
|
||||
: '' }
|
||||
triggerButtonProps = {{
|
||||
shouldFitContainer: true
|
||||
}}
|
||||
triggerType = 'button'>
|
||||
<DropdownItemGroup>
|
||||
{ languageItems }
|
||||
</DropdownItemGroup>
|
||||
</DropdownMenu>
|
||||
</TouchmoveHack>
|
||||
<Select
|
||||
label = { t('settings.language') }
|
||||
onChange = { this._onLanguageItemSelect }
|
||||
options = { languageItems }
|
||||
value = { currentLanguage } />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -470,16 +365,15 @@ class MoreTab extends AbstractDialogTab<Props, State> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderPrejoinScreenSettings() {
|
||||
// @ts-ignore
|
||||
const { t, showPrejoinPage } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className = 'settings-sub-pane-element'
|
||||
key = 'prejoin-screen'>
|
||||
<h2 className = 'mock-atlaskit-label'>
|
||||
<span className = 'checkbox-label'>
|
||||
{ t('prejoin.premeeting') }
|
||||
</h2>
|
||||
</span>
|
||||
<Checkbox
|
||||
checked = { showPrejoinPage }
|
||||
label = { t('prejoin.showScreen') }
|
||||
|
@ -496,20 +390,19 @@ class MoreTab extends AbstractDialogTab<Props, State> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderNotificationsSettings() {
|
||||
// @ts-ignore
|
||||
const { t, enabledNotifications } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className = 'settings-sub-pane-element'
|
||||
key = 'notifications'>
|
||||
<h2 className = 'mock-atlaskit-label'>
|
||||
<span className = 'checkbox-label'>
|
||||
{ t('notify.displayNotifications') }
|
||||
</h2>
|
||||
</span>
|
||||
{
|
||||
Object.keys(enabledNotifications).map(key => (
|
||||
<Checkbox
|
||||
checked = { enabledNotifications[key] }
|
||||
checked = { Boolean(enabledNotifications[key as keyof typeof enabledNotifications]) }
|
||||
key = { key }
|
||||
label = { t(key) }
|
||||
name = { `show-${key}` }
|
||||
|
@ -527,47 +420,29 @@ class MoreTab extends AbstractDialogTab<Props, State> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderMaxStageParticipantsSelect() {
|
||||
// @ts-ignore
|
||||
const { maxStageParticipants, t, stageFilmstripEnabled } = this.props;
|
||||
|
||||
if (!stageFilmstripEnabled) {
|
||||
return null;
|
||||
}
|
||||
const maxParticipantsItems = Array(MAX_ACTIVE_PARTICIPANTS).fill(0)
|
||||
.map((no, index) => (
|
||||
<DropdownItem
|
||||
data-maxparticipants = { index + 1 }
|
||||
key = { index + 1 }
|
||||
onClick = { this._onMaxStageParticipantsSelect }>
|
||||
{index + 1}
|
||||
</DropdownItem>));
|
||||
.map((no, index) => {
|
||||
return {
|
||||
value: index + 1,
|
||||
label: `${index + 1}`
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
className = 'settings-sub-pane-element'
|
||||
key = 'maxStageParticipants'>
|
||||
<h2 className = 'mock-atlaskit-label'>
|
||||
{ t('settings.maxStageParticipants') }
|
||||
</h2>
|
||||
<div className = 'dropdown-menu'>
|
||||
<TouchmoveHack
|
||||
flex = { true }
|
||||
isModal = { true }>
|
||||
<DropdownMenu
|
||||
// @ts-ignore
|
||||
isOpen = { this.state.isMaxStageParticipantsOpen }
|
||||
onOpenChange = { this._onMaxStageParticipantsOpenChange }
|
||||
shouldFitContainer = { true }
|
||||
trigger = { maxStageParticipants }
|
||||
triggerButtonProps = {{
|
||||
shouldFitContainer: true
|
||||
}}
|
||||
triggerType = 'button'>
|
||||
<DropdownItemGroup>
|
||||
{ maxParticipantsItems }
|
||||
</DropdownItemGroup>
|
||||
</DropdownMenu>
|
||||
</TouchmoveHack>
|
||||
<Select
|
||||
label = { t('settings.maxStageParticipants') }
|
||||
onChange = { this._onMaxStageParticipantsSelect }
|
||||
options = { maxParticipantsItems }
|
||||
value = { maxStageParticipants } />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -580,7 +455,6 @@ class MoreTab extends AbstractDialogTab<Props, State> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderSettingsRight() {
|
||||
// @ts-ignore
|
||||
const { showLanguageSettings } = this.props;
|
||||
|
||||
return (
|
||||
|
@ -600,7 +474,6 @@ class MoreTab extends AbstractDialogTab<Props, State> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderSettingsLeft() {
|
||||
// @ts-ignore
|
||||
const { disableHideSelfView, showNotificationsSettings, showPrejoinSettings } = this.props;
|
||||
|
||||
return (
|
||||
|
@ -616,5 +489,4 @@ class MoreTab extends AbstractDialogTab<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
export default translate(MoreTab);
|
||||
|
|
|
@ -9,6 +9,7 @@ import { getAvailableDevices } from '../../../base/devices';
|
|||
// @ts-ignore
|
||||
import { DialogWithTabs, hideDialog } from '../../../base/dialog';
|
||||
import { connect } from '../../../base/redux/functions';
|
||||
import { withPixelLineHeight } from '../../../base/styles/functions.web';
|
||||
// @ts-ignore
|
||||
import { isCalendarEnabled } from '../../../calendar-sync';
|
||||
import {
|
||||
|
@ -113,6 +114,14 @@ const styles = (theme: Theme) => {
|
|||
padding: `20px 0px ${theme.spacing(1)} 0px`
|
||||
},
|
||||
|
||||
'& .checkbox-label': {
|
||||
color: theme.palette.text01,
|
||||
...withPixelLineHeight(theme.typography.bodyShortRegular),
|
||||
marginBottom: theme.spacing(2),
|
||||
display: 'block',
|
||||
marginTop: '20px'
|
||||
},
|
||||
|
||||
'& input[type="checkbox"]:checked + svg': {
|
||||
'--checkbox-background-color': '#6492e7',
|
||||
'--checkbox-border-color': '#6492e7'
|
||||
|
@ -158,6 +167,10 @@ const styles = (theme: Theme) => {
|
|||
flex: 1
|
||||
},
|
||||
|
||||
'& .dropdown-menu': {
|
||||
marginTop: '20px'
|
||||
},
|
||||
|
||||
'& .settings-checkbox': {
|
||||
display: 'flex',
|
||||
marginBottom: theme.spacing(2)
|
||||
|
|
Loading…
Reference in New Issue