ref(AOT) Change buttons to not use abstract classes (#11302)

This reduces the bundle size by about 100KB
It also decouples the AOT buttons from the classes that are used to implement other features
This commit is contained in:
Robert Pintilii 2022-04-04 13:38:49 +03:00 committed by GitHub
parent 3443d256f2
commit c2399deb55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 182 additions and 12 deletions

View File

@ -1,10 +1,14 @@
// @flow
import React, { Component } from 'react';
// We need to reference these files directly to avoid loading things that are not available
// in this environment (e.g. JitsiMeetJS or interfaceConfig)
import AbstractAudioMuteButton from '../base/toolbox/components/AbstractAudioMuteButton';
import { IconMicrophoneEmpty, IconMicrophoneEmptySlash } from '../base/icons';
import type { Props } from '../base/toolbox/components/AbstractButton';
import ToolbarButton from './ToolbarButton';
const { api } = window.alwaysOnTop;
/**
@ -26,9 +30,9 @@ type State = {
/**
* Stateless "mute/unmute audio" button for the Always-on-Top windows.
*/
export default class AudioMuteButton
extends AbstractAudioMuteButton<Props, State> {
export default class AudioMuteButton extends Component<Props, State> {
icon = IconMicrophoneEmpty;
toggledIcon = IconMicrophoneEmptySlash;
accessibilityLabel = 'Audio mute';
/**
@ -49,6 +53,7 @@ export default class AudioMuteButton
this._audioAvailabilityListener
= this._audioAvailabilityListener.bind(this);
this._audioMutedListener = this._audioMutedListener.bind(this);
this._onClick = this._onClick.bind(this);
}
/**
@ -145,4 +150,33 @@ export default class AudioMuteButton
_setAudioMuted(audioMuted: boolean) { // eslint-disable-line no-unused-vars
this.state.audioAvailable && api.executeCommand('toggleAudio');
}
_onClick: () => {};
/**
* Handles clicking / pressing the button, and toggles the audio mute state
* accordingly.
*
* @returns {void}
*/
_onClick() {
this._setAudioMuted(!this._isAudioMuted());
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
const toggled = this._isAudioMuted();
return (<ToolbarButton
accessibilityLabel = { this.accessibilityLabel }
disabled = { this._isDisabled() }
icon = { toggled ? this.toggledIcon : this.icon }
onClick = { this._onClick }
toggled = { toggled } />);
}
}

View File

@ -1,27 +1,59 @@
// @flow
import React, { Component } from 'react';
// We need to reference these files directly to avoid loading things that are not available
// in this environment (e.g. JitsiMeetJS or interfaceConfig)
import { IconHangup } from '../base/icons';
import type { Props } from '../base/toolbox/components/AbstractButton';
import AbstractHangupButton from '../base/toolbox/components/AbstractHangupButton';
import ToolbarButton from './ToolbarButton';
const { api } = window.alwaysOnTop;
/**
* Stateless hangup button for the Always-on-Top windows.
*/
export default class HangupButton extends AbstractHangupButton<Props, *> {
export default class HangupButton extends Component<Props, *> {
accessibilityLabel = 'Hangup';
icon = IconHangup;
/**
* Helper function to perform the actual hangup action.
* Initializes a new {@code HangupButton} instance.
*
* @param {Props} props - The React {@code Component} props to initialize
* the new {@code HangupButton} instance with.
*/
constructor(props: Props) {
super(props);
// Bind event handlers so they are only bound once per instance.
this._onClick = this._onClick.bind(this);
}
_onClick: () => {};
/**
* Handles clicking / pressing the button, and disconnects the conference.
*
* @override
* @protected
* @returns {void}
*/
_doHangup() {
_onClick() {
api.executeCommand('hangup');
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
return (<ToolbarButton
accessibilityLabel = { this.accessibilityLabel }
customClass = 'hangup-button'
icon = { this.icon }
onClick = { this._onClick } />);
}
}

View File

@ -0,0 +1,69 @@
import React, { useCallback } from 'react';
import { Icon } from '../base/icons';
type Props = {
/**
* Accessibility label for button.
*/
accessibilityLabel: string,
/**
* An extra class name to be added at the end of the element's class name
* in order to enable custom styling.
*/
customClass?: string,
/**
* Whether or not the button is disabled.
*/
disabled?: boolean,
/**
* Click handler.
*/
onClick: Function,
/**
* Button icon.
*/
icon: Object,
/**
* Whether or not the button is toggled.
*/
toggled?: boolean
}
const ToolbarButton = ({
accessibilityLabel,
customClass,
disabled = false,
onClick,
icon,
toggled = false
}: Props) => {
const onKeyPress = useCallback(event => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
onClick();
}
}, [ onClick ]);
return (<div
aria-disabled = { disabled }
aria-label = { accessibilityLabel }
aria-pressed = { toggled }
className = { `toolbox-button ${disabled ? ' disabled' : ''}` }
onClick = { disabled ? undefined : onClick }
onKeyPress = { disabled ? undefined : onKeyPress }
role = 'button'
tabIndex = { 0 }>
<div className = { `toolbox-icon ${disabled ? 'disabled' : ''} ${customClass ?? ''}` }>
<Icon src = { icon } />
</div>
</div>);
};
export default ToolbarButton;

View File

@ -1,9 +1,12 @@
// @flow
import React, { Component } from 'react';
// We need to reference these files directly to avoid loading things that are not available
// in this environment (e.g. JitsiMeetJS or interfaceConfig)
import { IconCameraEmpty, IconCameraEmptyDisabled } from '../base/icons';
import type { Props } from '../base/toolbox/components/AbstractButton';
import AbstractVideoMuteButton from '../base/toolbox/components/AbstractVideoMuteButton';
import ToolbarButton from './ToolbarButton';
const { api } = window.alwaysOnTop;
@ -26,9 +29,10 @@ type State = {
/**
* Stateless "mute/unmute video" button for the Always-on-Top windows.
*/
export default class VideoMuteButton
extends AbstractVideoMuteButton<Props, State> {
export default class VideoMuteButton extends Component<Props, State> {
icon = IconCameraEmpty;
toggledIcon = IconCameraEmptyDisabled;
accessibilityLabel = 'Video mute';
/**
@ -49,6 +53,7 @@ export default class VideoMuteButton
this._videoAvailabilityListener
= this._videoAvailabilityListener.bind(this);
this._videoMutedListener = this._videoMutedListener.bind(this);
this._onClick = this._onClick.bind(this);
}
/**
@ -145,4 +150,34 @@ export default class VideoMuteButton
_videoMutedListener({ muted }) {
this.setState({ videoMuted: muted });
}
_onClick: () => {};
/**
* Handles clicking / pressing the button, and toggles the video mute state
* accordingly.
*
* @protected
* @returns {void}
*/
_onClick() {
this._setVideoMuted(!this._isVideoMuted());
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
const toggled = this._isVideoMuted();
return (<ToolbarButton
accessibilityLabel = { this.accessibilityLabel }
disabled = { this._isDisabled() }
icon = { toggled ? this.toggledIcon : this.icon }
onClick = { this._onClick }
toggled = { toggled } />);
}
}