ref(TS) Convert some native components to TS (#13200)

pull/13202/head jitsi-meet_8542
Robert Pintilii 2 years ago committed by GitHub
parent 046f9c53ab
commit 84ad0200a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      react/features/app/components/AbstractApp.ts
  2. 69
      react/features/app/components/App.native.tsx
  3. 2
      react/features/app/getRouteToRender.native.ts
  4. 2
      react/features/app/reducer.native.ts
  5. 2
      react/features/authentication/actions.any.ts
  6. 1
      react/features/authentication/components/index.native.ts
  7. 54
      react/features/authentication/components/native/LoginDialog.tsx
  8. 14
      react/features/authentication/components/native/WaitForOwnerDialog.tsx
  9. 1
      react/features/base/avatar/components/Avatar.tsx
  10. 22
      react/features/base/avatar/components/native/StatelessAvatar.tsx
  11. 2
      react/features/base/avatar/components/native/styles.ts
  12. 5
      react/features/base/avatar/components/web/StatelessAvatar.tsx
  13. 5
      react/features/base/avatar/types.ts
  14. 3
      react/features/base/color-scheme/ColorSchemeRegistry.ts
  15. 2
      react/features/base/conference/actions.ts
  16. 9
      react/features/base/connection/functions.ts
  17. 4
      react/features/base/dialog/components/AbstractDialogContainer.ts
  18. 6
      react/features/base/dialog/components/functions.native.tsx
  19. 2
      react/features/base/dialog/components/native/AbstractDialog.ts
  20. 19
      react/features/base/dialog/components/native/AlertDialog.tsx
  21. 34
      react/features/base/dialog/components/native/BottomSheet.tsx
  22. 32
      react/features/base/dialog/components/native/ConfirmDialog.tsx
  23. 3
      react/features/base/dialog/components/native/DialogContainer.tsx
  24. 49
      react/features/base/dialog/components/native/InputDialog.tsx
  25. 2
      react/features/base/dialog/components/native/styles.ts
  26. 22
      react/features/base/label/components/native/ExpandedLabel.tsx
  27. 41
      react/features/base/label/components/native/Label.tsx
  28. 4
      react/features/base/label/components/native/styles.ts
  29. 2
      react/features/base/media/components/AbstractAudio.ts
  30. 2
      react/features/base/media/components/AbstractVideoTrack.tsx
  31. 10
      react/features/base/media/components/native/Audio.ts
  32. 27
      react/features/base/media/components/native/Video.tsx
  33. 7
      react/features/base/media/components/native/VideoTrack.tsx
  34. 0
      react/features/base/media/components/native/styles.ts
  35. 14
      react/features/base/react/components/native/Pressable.tsx
  36. 63
      react/features/base/react/components/native/SlidingView.tsx
  37. 2
      react/features/base/react/components/native/slidingviewstyles.ts
  38. 26
      react/features/base/responsive-ui/components/DimensionsDetector.native.tsx
  39. 0
      react/features/mobile/navigation/actionTypes.ts
  40. 2
      react/features/participants-pane/components/native/MeetingParticipantList.tsx
  41. 28
      react/features/reactions/components/native/ReactionEmoji.tsx

@ -25,7 +25,7 @@ export interface IProps {
*
* @abstract
*/
export class AbstractApp extends BaseApp<IProps> {
export class AbstractApp<P extends IProps = IProps> extends BaseApp<P> {
/**
* The deferred for the initialisation {{promise, resolve, reject}}.
*/

@ -1,4 +1,4 @@
import React from 'react';
import React, { ComponentType } from 'react';
import { NativeModules, Platform, StyleSheet, View } from 'react-native';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import SplashScreen from 'react-native-splash-screen';
@ -14,14 +14,13 @@ import { updateSettings } from '../../base/settings/actions';
import { _getRouteToRender } from '../getRouteToRender.native';
import logger from '../logger';
import { AbstractApp } from './AbstractApp';
import type { Props as AbstractAppProps } from './AbstractApp';
import { AbstractApp, IProps as AbstractAppProps } from './AbstractApp';
// Register middlewares and reducers.
import '../middlewares';
import '../reducers';
import '../middlewares.native';
import '../reducers.native';
declare var __DEV__;
declare let __DEV__: any;
const { AppInfo } = NativeModules;
@ -32,37 +31,33 @@ const DialogContainerWrapper = Platform.select({
/**
* The type of React {@code Component} props of {@link App}.
*/
type Props = AbstractAppProps & {
interface IProps extends AbstractAppProps {
/**
* An object with the feature flags.
*/
flags: Object,
flags: Object;
/**
* An object with user information (display name, email, avatar URL).
*/
userInfo: ?Object
};
userInfo?: Object;
}
/**
* Root app {@code Component} on mobile/React Native.
*
* @augments AbstractApp
*/
export class App extends AbstractApp {
/**
* The deferred for the initialisation {{promise, resolve, reject}}.
*/
_init: Object;
export class App extends AbstractApp<IProps> {
/**
* Initializes a new {@code App} instance.
*
* @param {Props} props - The read-only React {@code Component} props with
* @param {IProps} props - The read-only React {@code Component} props with
* which the new instance is to be initialized.
*/
constructor(props: Props) {
constructor(props: IProps) {
super(props);
// In the Release configuration, React Native will (intentionally) throw
@ -99,10 +94,11 @@ export class App extends AbstractApp {
* @returns {void}
*/
async _extraInit() {
const { dispatch, getState } = this.state.store;
const { dispatch, getState } = this.state.store ?? {};
const { flags } = this.props;
// We set these early enough so then we avoid any unnecessary re-renders.
dispatch(updateFlags(this.props.flags));
dispatch?.(updateFlags(flags));
const route = await _getRouteToRender();
@ -113,8 +109,9 @@ export class App extends AbstractApp {
// Wait until the root navigator is ready.
// We really need to break the inheritance relationship between App,
// AbstractApp and BaseApp, it's very inflexible and cumbersome right now.
const rootNavigationReady = new Promise(resolve => {
const rootNavigationReady = new Promise<void>(resolve => {
const i = setInterval(() => {
// @ts-ignore
const { ready } = getState()['features/app'] || {};
if (ready) {
@ -127,26 +124,27 @@ export class App extends AbstractApp {
await rootNavigationReady;
// Check if serverURL is configured externally and not allowed to change.
const serverURLChangeEnabled = getFeatureFlag(getState(), SERVER_URL_CHANGE_ENABLED, true);
const serverURLChangeEnabled = getState && getFeatureFlag(getState(), SERVER_URL_CHANGE_ENABLED, true);
if (!serverURLChangeEnabled) {
// As serverURL is provided externally, so we push it to settings.
if (typeof this.props.url !== 'undefined') {
// @ts-ignore
const { serverURL } = this.props.url;
if (typeof serverURL !== 'undefined') {
dispatch(updateSettings({ serverURL }));
dispatch?.(updateSettings({ serverURL }));
}
}
}
dispatch(updateSettings(this.props.userInfo || {}));
dispatch?.(updateSettings(this.props.userInfo || {}));
// Update settings with feature-flag.
const callIntegrationEnabled = this.props.flags[CALL_INTEGRATION_ENABLED];
const callIntegrationEnabled = flags[CALL_INTEGRATION_ENABLED as keyof typeof flags];
if (typeof callIntegrationEnabled !== 'undefined') {
dispatch(updateSettings({ disableCallIntegration: !callIntegrationEnabled }));
dispatch?.(updateSettings({ disableCallIntegration: !callIntegrationEnabled }));
}
}
@ -156,7 +154,7 @@ export class App extends AbstractApp {
*
* @override
*/
_createMainElement(component, props) {
_createMainElement(component: ComponentType<any>, props: Object) {
return (
<SafeAreaProvider>
<DimensionsDetector
@ -196,17 +194,19 @@ export class App extends AbstractApp {
return;
}
// @ts-ignore
const oldHandler = global.ErrorUtils.getGlobalHandler();
const newHandler = _handleException;
if (!oldHandler || oldHandler !== newHandler) {
// @ts-ignore
newHandler.next = oldHandler;
// @ts-ignore
global.ErrorUtils.setGlobalHandler(newHandler);
}
}
_onDimensionsChanged: (width: number, height: number) => void;
/**
* Updates the known available size for the app to occupy.
*
@ -216,9 +216,9 @@ export class App extends AbstractApp {
* @returns {void}
*/
_onDimensionsChanged(width: number, height: number) {
const { dispatch } = this.state.store;
const { dispatch } = this.state.store ?? {};
dispatch(clientResized(width, height));
dispatch?.(clientResized(width, height));
}
/**
@ -232,10 +232,10 @@ export class App extends AbstractApp {
* @private
* @returns {void}
*/
_onSafeAreaInsetsChanged(insets) {
const { dispatch } = this.state.store;
_onSafeAreaInsetsChanged(insets: Object) {
const { dispatch } = this.state.store ?? {};
dispatch(setSafeAreaInsets(insets));
dispatch?.(setSafeAreaInsets(insets));
}
/**
@ -266,7 +266,7 @@ export class App extends AbstractApp {
* @private
* @returns {void}
*/
function _handleException(error, fatal) {
function _handleException(error: Error, fatal: boolean) {
if (fatal) {
// In the Release configuration, React Native will (intentionally) throw
// an unhandled JavascriptException for an unhandled JavaScript error.
@ -275,6 +275,7 @@ function _handleException(error, fatal) {
logger.error(error);
} else {
// Forward to the next globalHandler of ErrorUtils.
// @ts-ignore
const { next } = _handleException;
typeof next === 'function' && next(error, fatal);

@ -13,6 +13,6 @@ const route = {
* @param {any} _stateful - Used on web.
* @returns {Promise<Object>}
*/
export function _getRouteToRender(_stateful: any) {
export function _getRouteToRender(_stateful?: any) {
return Promise.resolve(route);
}

@ -9,7 +9,7 @@ import { _ROOT_NAVIGATION_READY } from '../mobile/navigation/actionTypes';
* @param {string} action.type - Type of action.
* @returns {Object}
*/
ReducerRegistry.register('features/app', (state = {}, action) => {
ReducerRegistry.register('features/app', (state: Object = {}, action) => {
switch (action.type) {
case _ROOT_NAVIGATION_READY:
return {

@ -8,8 +8,6 @@ import {
UPGRADE_ROLE_FINISHED,
UPGRADE_ROLE_STARTED, WAIT_FOR_OWNER
} from './actionTypes';
// eslint-disable-next-line lines-around-comment
// @ts-ignore
import { LoginDialog, WaitForOwnerDialog } from './components';
import logger from './logger';

@ -1,4 +1,3 @@
// @ts-ignore
export { default as LoginDialog } from './native/LoginDialog';
// eslint-disable-next-line lines-around-comment
// @ts-ignore

@ -1,8 +1,9 @@
import React, { Component } from 'react';
import Dialog from 'react-native-dialog';
import { connect as reduxConnect } from 'react-redux';
import type { Dispatch } from 'redux';
import { IReduxState, IStore } from '../../../app/types';
import { IJitsiConference } from '../../../base/conference/reducer';
import { connect } from '../../../base/connection/actions.native';
import { toJid } from '../../../base/connection/functions';
import { _abstractMapStateToProps } from '../../../base/dialog/functions';
@ -13,61 +14,68 @@ import { authenticateAndUpgradeRole, cancelLogin } from '../../actions.native';
/**
* The type of the React {@link Component} props of {@link LoginDialog}.
*/
type Props = {
interface IProps {
/**
* {@link JitsiConference} That needs authentication - will hold a valid
* value in XMPP login + guest access mode.
*/
_conference: Object,
_conference?: IJitsiConference;
/**
* The server hosts specified in the global config.
*/
_configHosts: Object,
_configHosts?: {
anonymousdomain?: string;
authdomain?: string;
domain: string;
focus?: string;
muc: string;
visitorFocus: string;
};
/**
* Indicates if the dialog should display "connecting" status message.
*/
_connecting: boolean,
_connecting: boolean;
/**
* The error which occurred during login/authentication.
*/
_error: Object,
_error: any;
/**
* The progress in the floating range between 0 and 1 of the authenticating
* and upgrading the role of the local participant/user.
*/
_progress: number,
_progress?: number;
/**
* Redux store dispatch method.
*/
dispatch: Dispatch<any>,
dispatch: IStore['dispatch'];
/**
* Invoked to obtain translated strings.
*/
t: Function
};
t: Function;
}
/**
* The type of the React {@link Component} state of {@link LoginDialog}.
*/
type State = {
interface IState {
/**
* The user entered password for the conference.
*/
password: string,
password: string;
/**
* The user entered local participant name.
*/
username: string
};
username: string;
}
/**
* Dialog asks user for username and password.
@ -96,14 +104,14 @@ type State = {
* See {@link https://github.com/jitsi/jicofo#secure-domain} for a description
* of the configuration parameters.
*/
class LoginDialog extends Component<Props, State> {
class LoginDialog extends Component<IProps, IState> {
/**
* Initializes a new LoginDialog instance.
*
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
*/
constructor(props: Props) {
constructor(props: IProps) {
super(props);
this.state = {
@ -179,7 +187,7 @@ class LoginDialog extends Component<Props, State> {
} = this.props;
let messageKey;
const messageOptions = {};
const messageOptions = { msg: '' };
if (progress && progress < 1) {
messageKey = 'connection.FETCH_SESSION_ID';
@ -196,7 +204,7 @@ class LoginDialog extends Component<Props, State> {
&& credentials.jid
=== toJid(
this.state.username,
this.props._configHosts)
this.props._configHosts ?? {})
&& credentials.password === this.state.password) {
messageKey = 'dialog.incorrectPassword';
}
@ -222,7 +230,7 @@ class LoginDialog extends Component<Props, State> {
* @returns {void}
* @private
*/
_onUsernameChange(text) {
_onUsernameChange(text: string) {
this.setState({
username: text.trim()
});
@ -235,7 +243,7 @@ class LoginDialog extends Component<Props, State> {
* @returns {void}
* @private
*/
_onPasswordChange(text) {
_onPasswordChange(text: string) {
this.setState({
password: text
});
@ -261,7 +269,7 @@ class LoginDialog extends Component<Props, State> {
_onLogin() {
const { _conference: conference, dispatch } = this.props;
const { password, username } = this.state;
const jid = toJid(username, this.props._configHosts);
const jid = toJid(username, this.props._configHosts ?? {});
let r;
// If there's a conference it means that the connection has succeeded,
@ -282,9 +290,9 @@ class LoginDialog extends Component<Props, State> {
*
* @param {Object} state - The Redux state.
* @private
* @returns {Props}
* @returns {IProps}
*/
function _mapStateToProps(state) {
function _mapStateToProps(state: IReduxState) {
const {
error: authenticateAndUpgradeRoleError,
progress,

@ -1,7 +1,7 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import type { Dispatch } from 'redux';
import { IStore } from '../../../app/types';
import ConfirmDialog from '../../../base/dialog/components/native/ConfirmDialog';
import { translate } from '../../../base/i18n/functions';
import { cancelWaitForOwner, openLoginDialog } from '../../actions.native';
@ -9,18 +9,18 @@ import { cancelWaitForOwner, openLoginDialog } from '../../actions.native';
/**
* The type of the React {@code Component} props of {@link WaitForOwnerDialog}.
*/
type Props = {
interface IProps {
/**
* Redux store dispatch function.
*/
dispatch: Dispatch<any>,
dispatch: IStore['dispatch'];
/**
* Invoked to obtain translated strings.
*/
t: Function
};
t: Function;
}
/**
* The dialog is display in XMPP password + guest access configuration, after
@ -28,14 +28,14 @@ type Props = {
*
* See {@link LoginDialog} description for more details.
*/
class WaitForOwnerDialog extends Component<Props> {
class WaitForOwnerDialog extends Component<IProps> {
/**
* Initializes a new WaitForWonderDialog instance.
*
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
*/
constructor(props) {
constructor(props: IProps) {
super(props);
// Bind event handlers so they are only bound once per instance.

@ -185,6 +185,7 @@ class Avatar<P extends IProps> extends PureComponent<P, IState> {
id?: string;
status?: string;
testId?: string;
url?: string;
useCORS?: boolean;
} = {
className,

@ -1,12 +1,11 @@
import React, { Component } from 'react';
import { Image, Text, View } from 'react-native';
import { Image, Text, TextStyle, View, ViewStyle } from 'react-native';
import Icon from '../../../icons/components/Icon';
import { StyleType } from '../../../styles/functions.native';
import { isIcon } from '../../functions';
import { IAvatarProps } from '../../types';
// @ts-ignore
import styles from './styles';
// eslint-disable-next-line @typescript-eslint/no-var-requires
@ -23,6 +22,11 @@ interface IProps extends IAvatarProps {
* External style passed to the component.
*/
style?: StyleType;
/**
* The URL of the avatar to render.
*/
url?: string;
}
/**
@ -66,7 +70,7 @@ export default class StatelessAvatar extends Component<IProps> {
<View>
<View
style = { [
styles.avatarContainer(size),
styles.avatarContainer(size) as ViewStyle,
style
] }>
{ avatar }
@ -90,7 +94,7 @@ export default class StatelessAvatar extends Component<IProps> {
return (
<View style = { styles.badgeContainer }>
<View style = { styles.badge(size, status) } />
<View style = { styles.badge(size, status) as ViewStyle } />
</View>
);
}
@ -125,7 +129,7 @@ export default class StatelessAvatar extends Component<IProps> {
return (
<View
style = { [
styles.initialsContainer,
styles.initialsContainer as ViewStyle,
{
backgroundColor: color
}
@ -148,12 +152,12 @@ export default class StatelessAvatar extends Component<IProps> {
return (
<View
style = { [
styles.initialsContainer,
styles.initialsContainer as ViewStyle,
{
backgroundColor: color
}
] }>
<Text style = { styles.initialsText(size) }> { initials } </Text>
<Text style = { styles.initialsText(size) as TextStyle }> { initials } </Text>
</View>
);
}
@ -166,9 +170,11 @@ export default class StatelessAvatar extends Component<IProps> {
_renderURLAvatar() {
const { onAvatarLoadError, size, url } = this.props;
return ( // @ts-ignore
return (
<Image
defaultSource = { DEFAULT_AVATAR }
// @ts-ignore
onError = { onAvatarLoadError }
resizeMode = 'cover'
source = {{ uri: url }}

@ -1,5 +1,3 @@
// @flow
import { StyleSheet } from 'react-native';
import { ColorPalette } from '../../../styles/components/styles/ColorPalette';

@ -35,6 +35,11 @@ interface IProps extends IAvatarProps {
*/
testId?: string;
/**
* The URL of the avatar to render.
*/
url?: string | Function;
/**
* Indicates whether to load the avatar using CORS or not.
*/

@ -24,9 +24,4 @@ export interface IAvatarProps {
* Expected size of the avatar.
*/
size?: number;
/**
* The URL of the avatar to render.
*/
url?: string | Function;
}

@ -65,7 +65,7 @@ class ColorSchemeRegistry {
* @param {StyleType} style - The style definition to register.
* @returns {void}
*/
register(componentName: string, style: StyleType): void {
register(componentName: string, style: any): void {
this._styleTemplates.set(componentName, style);
// If this is a style overwrite, we need to delete the processed version
@ -120,7 +120,6 @@ class ColorSchemeRegistry {
} else if (typeof styleValue === 'function') {
// The value is a function, which indicates that it's a
// dynamic, schemed color we need to resolve.
// $FlowExpectedError
const value = styleValue();
schemedStyle[styleName]

@ -530,8 +530,6 @@ export function createConference(overrideRoom?: string | String) {
if (tmp.domain) {
// eslint-disable-next-line no-new-wrappers
_room = new String(tmp);
// $FlowExpectedError
_room.domain = tmp.domain;
}

@ -89,6 +89,13 @@ export function isInviteURLReady(stateOrGetState: IStateful): boolean {
* @returns {string} A string in the form of a JID (i.e.
* {@code user@server.com}).
*/
export function toJid(id: string, { authdomain, domain }: { authdomain?: string; domain?: string; }): string {
export function toJid(id: string, { authdomain, domain }: {
anonymousdomain?: string;
authdomain?: string;
domain?: string;
focus?: string;
muc?: string;
visitorFocus?: string;
}): string {
return id.indexOf('@') >= 0 ? id : `${id}@${authdomain || domain}`;
}

@ -11,12 +11,12 @@ interface IProps {
/**
* The component to render.
*/
_component: ComponentType;
_component?: ComponentType<any>;
/**
* The props to pass to the component that will be rendered.
*/
_componentProps: Object;
_componentProps?: Object;
/**
* Array of reactions to be displayed.

@ -1,5 +1,5 @@
import React from 'react';
import { Text } from 'react-native';
import { Text, TextStyle } from 'react-native';
import { brandedDialog as styles } from './native/styles';
@ -10,7 +10,7 @@ import { brandedDialog as styles } from './native/styles';
* contain HTML to render.
* @returns {ReactElement[]|string}
*/
export function renderHTML(html) {
export function renderHTML(html?: string) {
if (typeof html === 'string') {
// At the time of this writing, the specified HTML contains a couple
// of spaces one after the other. They do not cause a visible
@ -36,7 +36,7 @@ export function renderHTML(html) {
if (c = closing.exec(html)) {
r.push(html.substring(prevClosingLastIndex, o.index));
r.push(
<Text style = { styles.boldDialogText }>
<Text style = { (styles.boldDialogText as TextStyle) }>
{ html.substring(opening.lastIndex, c.index) }
</Text>);
opening.lastIndex

@ -25,7 +25,7 @@ export interface IState {
/**
* An abstract implementation of a dialog on Web/React and mobile/react-native.
*/
export default class AbstractDialog<P extends IProps, S extends IState>
export default class AbstractDialog<P extends IProps, S extends IState = IState>
extends Component<P, S> {
_mounted: boolean;

@ -1,4 +1,5 @@
import React from 'react';
import { WithTranslation } from 'react-i18next';
import Dialog from 'react-native-dialog';
import { connect } from 'react-redux';
@ -6,10 +7,9 @@ import { translate } from '../../../i18n/functions';
import { _abstractMapStateToProps } from '../../functions';
import { renderHTML } from '../functions.native';
import AbstractDialog, { type Props as AbstractProps } from './AbstractDialog';
import AbstractDialog, { IProps as AbstractProps } from './AbstractDialog';
type Props = AbstractProps & {
interface IProps extends AbstractProps, WithTranslation {
/**
* Untranslated i18n key of the content to be displayed.
@ -18,19 +18,14 @@ type Props = AbstractProps & {
* translated using the provided params. See i18n function
* {@code translate(string, Object)} for more details.
*/
contentKey: string | { key: string, params: Object},
/**
* Translation function.
*/
t: Function
};
contentKey: string | { key: string; params: Object; };
}
/**
* Implements an alert dialog, to simply show an error or a message,
* then disappear on dismiss.
*/
class AlertDialog extends AbstractDialog<Props> {
class AlertDialog extends AbstractDialog<IProps> {
/**
* Implements React's {@link Component#render}.
*
@ -56,8 +51,6 @@ class AlertDialog extends AbstractDialog<Props> {
</Dialog.Container>
);
}
_onSubmit: () => boolean;
}
export default translate(connect(_abstractMapStateToProps)(AlertDialog));

@ -1,5 +1,5 @@
import React, { type Node, PureComponent } from 'react';
import { SafeAreaView, ScrollView, View } from 'react-native';
import React, { PureComponent, ReactNode } from 'react';
import { SafeAreaView, ScrollView, View, ViewStyle } from 'react-native';
import { connect } from 'react-redux';
import SlidingView from '../../../react/components/native/SlidingView';
@ -15,43 +15,43 @@ type Props = {
/**
* Whether to add padding to scroll view.
*/
addScrollViewPadding?: boolean,
addScrollViewPadding?: boolean;
/**
* The children to be displayed within this component.
*/
children: Node,
children: ReactNode;
/**
* Redux Dispatch function.
*/
dispatch: Function,
dispatch: Function;
/**
* Handler for the cancel event, which happens when the user dismisses
* the sheet.
*/
onCancel: ?Function,
onCancel?: Function;
/**
* Function to render a bottom sheet header element, if necessary.
* Function to render a bottom sheet footer element, if necessary.
*/
renderHeader: ?Function,
renderFooter?: Function;
/**
* Function to render a bottom sheet footer element, if necessary.
* Function to render a bottom sheet header element, if necessary.
*/
renderFooter: ?Function,
renderHeader?: Function;
/**
* Whether to show sliding view or not.
*/
showSlidingView?: boolean,
showSlidingView?: boolean;
/**
* The component's external style.
*/
style: Object
style?: Object;
};
/**
@ -109,19 +109,19 @@ class BottomSheet extends PureComponent<Props> {
} = this.props;
return (
<SlidingView
<SlidingView // @ts-ignore
accessibilityRole = 'menu'
accessibilityViewIsModal = { true }
onHide = { this._onCancel }
position = 'bottom'
show = { showSlidingView }>
show = { Boolean(showSlidingView) }>
<View
pointerEvents = 'box-none'
style = { styles.sheetContainer }>
style = { styles.sheetContainer as ViewStyle }>
<View
pointerEvents = 'box-none'
style = { styles.sheetAreaCover } />
{ renderHeader && renderHeader() }
{ renderHeader?.() }
<SafeAreaView
style = { [
styles.sheetItemContainer,
@ -140,7 +140,7 @@ class BottomSheet extends PureComponent<Props> {
] } >
{ this.props.children }
</ScrollView>
{ renderFooter && renderFooter() }
{ renderFooter?.() }
</SafeAreaView>
</View>
</SlidingView>

@ -1,11 +1,12 @@
import React from 'react';
import { WithTranslation } from 'react-i18next';
import Dialog from 'react-native-dialog';
import { connect } from 'react-redux';
import { translate } from '../../../i18n/functions';
import { renderHTML } from '../functions.native';
import AbstractDialog from './AbstractDialog';
import AbstractDialog, { IProps as AbstractProps } from './AbstractDialog';
import styles from './styles';
@ -13,43 +14,38 @@ import styles from './styles';
* The type of the React {@code Component} props of
* {@link ConfirmDialog}.
*/
type Props = {
interface IProps extends AbstractProps, WithTranslation {
/**
* The i18n key of the text label for the cancel button.
*/
cancelLabel: string,
cancelLabel: string;
/**
* The React {@code Component} children.
*/
children?: Node,
children?: React.ReactNode;
/**
* The i18n key of the text label for the confirm button.
*/
confirmLabel: string,
confirmLabel: string;
/**
* Dialog description key for translations.
*/
descriptionKey?: string | Object,
descriptionKey?: string | { key: string; params: string; };
/**
* Whether or not the nature of the confirm button is destructive.
*/
isConfirmDestructive?: Boolean,
/**
* Invoked to obtain translated strings.
*/
t: Function,
isConfirmDestructive?: Boolean;
/**
* Dialog title.
*/
title?: string
};
title?: string;
}
/**
* React Component for getting confirmation to stop a file recording session in
@ -57,7 +53,7 @@ type Props = {
*
* @augments Component
*/
class ConfirmDialog extends AbstractDialog<Props> {
class ConfirmDialog extends AbstractDialog<IProps> {
/**
* Default values for {@code ConfirmDialog} component's properties.
*
@ -78,7 +74,7 @@ class ConfirmDialog extends AbstractDialog<Props> {
= typeof descriptionKey === 'string'
? t(descriptionKey)
: renderHTML(
t(descriptionKey?.key, descriptionKey?.params)
t(descriptionKey?.key ?? '', descriptionKey?.params)
);
return (
@ -129,10 +125,6 @@ class ConfirmDialog extends AbstractDialog<Props> {
</Dialog.Container>
);
}
_onCancel: () => void;
_onSubmit: (?string) => void;
}
export default translate(connect()(ConfirmDialog));

@ -1,6 +1,7 @@
import React, { Fragment } from 'react';
import { connect } from 'react-redux';
import { IReduxState } from '../../../../app/types';
import ReactionEmoji from '../../../../reactions/components/native/ReactionEmoji';
import { getReactionsQueue } from '../../../../reactions/functions.native';
import AbstractDialogContainer, {
@ -47,7 +48,7 @@ class DialogContainer extends AbstractDialogContainer {
}
}
const mapStateToProps = state => {
const mapStateToProps = (state: IReduxState) => {
return {
...abstractMapStateToProps(state),
_reactionsQueue: getReactionsQueue(state)

@ -1,4 +1,6 @@
import React from 'react';
import { WithTranslation } from 'react-i18next';
import { TextStyle } from 'react-native';
import Dialog from 'react-native-dialog';
import { connect } from 'react-redux';
@ -6,67 +8,62 @@ import { translate } from '../../../i18n/functions';
import { _abstractMapStateToProps } from '../../functions';
import AbstractDialog, {
type Props as AbstractProps,
type State as AbstractState
IProps as AbstractProps,
IState as AbstractState
} from './AbstractDialog';
import { inputDialog as styles } from './styles';
type Props = AbstractProps & {
interface IProps extends AbstractProps, WithTranslation {
/**
* The dialog descriptionKey.
*/
descriptionKey: string,
descriptionKey: string;
/**
* An optional initial value to initiate the field with.
*/
initialValue?: ?string,
initialValue?: string;
/**
* A message key to be shown for the user (e.g. An error that is defined after submitting the form).
*/
messageKey?: string,
/**
* The translate function.
*/
t: Function,
messageKey?: string;
/**
* Props for the text input.
*/
textInputProps: ?Object,
textInputProps?: Object;
/**
* The untranslated i18n key for the dialog title.
*/
titleKey?: string,
titleKey?: string;
/**
* Validating of the input.
*/
validateInput: ?Function
validateInput?: Function;
}
type State = AbstractState & {
interface IState extends AbstractState {
/**
* The current value of the field.
*/
fieldValue: ?string
};
fieldValue?: string;
}
/**
* Implements a single field input dialog component.
*/
class InputDialog<P: Props, S: State> extends AbstractDialog<P, S> {
class InputDialog extends AbstractDialog<IProps, IState> {
/**
* Instantiates a new {@code InputDialog}.
*
* @inheritdoc
*/
constructor(props: Props) {
constructor(props: IProps) {
super(props);
this.state = {
@ -96,7 +93,7 @@ class InputDialog<P: Props, S: State> extends AbstractDialog<P, S> {
coverScreen = { false }
visible = { true }>
<Dialog.Title>
{ t(titleKey) }
{ t(titleKey ?? '') }
</Dialog.Title>
{
descriptionKey && (
@ -113,7 +110,7 @@ class InputDialog<P: Props, S: State> extends AbstractDialog<P, S> {
{
messageKey && (
<Dialog.Description
style = { styles.formMessage }>
style = { styles.formMessage as TextStyle }>
{ t(messageKey) }
</Dialog.Description>
)
@ -128,17 +125,13 @@ class InputDialog<P: Props, S: State> extends AbstractDialog<P, S> {
);
}
_onCancel: () => void;
_onChangeText: string => void;
/**
* Callback to be invoked when the text in the field changes.
*
* @param {string} fieldValue - The updated field value.
* @returns {void}
*/
_onChangeText(fieldValue) {
_onChangeText(fieldValue: string) {
if (this.props.validateInput && !this.props.validateInput(fieldValue)) {
return;
}
@ -148,10 +141,6 @@ class InputDialog<P: Props, S: State> extends AbstractDialog<P, S> {
});
}
_onSubmit: (?string) => boolean;
_onSubmitValue: () => boolean;
/**
* Callback to be invoked when the value of this dialog is submitted.
*

@ -1,9 +1,9 @@
import { StyleSheet } from 'react-native';
import BaseTheme from '../../../../base/ui/components/BaseTheme.native';
import ColorSchemeRegistry from '../../../color-scheme/ColorSchemeRegistry';
import { schemeColor } from '../../../color-scheme/functions';
import { BoxModel } from '../../../styles/components/styles/BoxModel';
import BaseTheme from '../../../ui/components/BaseTheme.native';
import { PREFERRED_DIALOG_SIZE } from '../../constants';
const BORDER_RADIUS = 5;

@ -1,37 +1,35 @@
// @flow
import React, { Component } from 'react';
import { Animated, Text, View } from 'react-native';
import styles, { DEFAULT_COLOR } from './styles';
export type Props = {
export interface IProps {
/**
* The position of the parent element (from right to left) to display the
* arrow.
*/
parentPosition: number,
parentPosition: number;
/**
* Custom styles.
*/
style: ?Object
};
style?: Object;
}
type State = {
interface IState {
/**
* The opacity animation Object.
*/
opacityAnimation: Object
};
opacityAnimation: Animated.Value;
}
/**
* A react {@code Component} that implements an expanded label as tooltip-like
* component to explain the meaning of the {@code Label}.
*/
export default class ExpandedLabel<P: Props> extends Component<P, State> {
export default class ExpandedLabel<P extends IProps> extends Component<P, IState> {
/**
* Instantiates a new {@code ExpandedLabel} instance.
*
@ -55,7 +53,7 @@ export default class ExpandedLabel<P: Props> extends Component<P, State> {
toValue: 1,
velocity: 1,
useNativeDriver: true
}).start();
} as Animated.DecayAnimationConfig).start();
}
/**
@ -89,8 +87,6 @@ export default class ExpandedLabel<P: Props> extends Component<P, State> {
*/
_getLabel: () => string;
_getColor: () => string;
/**
* Defines the color of the expanded label. This function returns a default
* value if implementing classes don't override it, but the goal is to have

@ -1,6 +1,5 @@
// @flow
import React, { Component } from 'react';
import { Animated, Text } from 'react-native';
import { Animated, Text, ViewStyle } from 'react-native';
import Icon from '../../../icons/components/Icon';
import { StyleType, combineStyles } from '../../../styles/functions.native';
@ -17,41 +16,41 @@ const STATUS_IN_PROGRESS = 'in_progress';
*/
const STATUS_OFF = 'off';
type Props = {
interface IProps {
/**
* An SVG icon to be rendered as the content of the label.
*/
icon?: Function,
icon?: Function;
/**
* Color for the icon.
*/
iconColor?: ?string,
iconColor?: string;
/**
* Status of the label. This prop adds some additional styles based on its
* value. E.g. If status = off, it will render the label symbolising that
* the thing it displays (e.g. Recording) is off.
*/
status: ('in_progress' | 'off' | 'on'),
status?: 'in_progress' | 'off' | 'on';
/**
* Style of the label.
*/
style?: ?StyleType,
style?: StyleType;
/**
* String or component that will be rendered as the label itself.
*/
text?: string,
text?: string;
/**
* Custom styles for the text.
*/
textStyle?: ?StyleType
textStyle?: StyleType;
};
}
type State = {
@ -59,25 +58,25 @@ type State = {
* An animation object handling the opacity changes of the in progress
* label.
*/
pulseAnimation: Object
}
pulseAnimation: Animated.Value;
};
/**
* Renders a circular indicator to be used for status icons, such as recording
* on, audio-only conference, video quality and similar.
*/
export default class Label extends Component<Props, State> {
export default class Label extends Component<IProps, State> {
/**
* A reference to the started animation of this label.
*/
animationReference: Object;
animationReference: Animated.CompositeAnimation;
/**
* Instantiates a new instance of {@code Label}.
*
* @inheritdoc
*/
constructor(props: Props) {
constructor(props: IProps) {
super(props);
this.state = {
@ -99,7 +98,7 @@ export default class Label extends Component<Props, State> {
*
* @inheritdoc
*/
componentDidUpdate(prevProps: Props) {
componentDidUpdate(prevProps: IProps) {
this._maybeToggleAnimation(prevProps, this.props);
}
@ -127,8 +126,8 @@ export default class Label extends Component<Props, State> {
return (
<Animated.View
style = { [
combineStyles(styles.labelContainer, style),
extraStyle
combineStyles(styles.labelContainer, style ?? {}),
extraStyle as ViewStyle
] }>
{ icon && <Icon
color = { iconColor }
@ -145,11 +144,11 @@ export default class Label extends Component<Props, State> {
* Checks if the animation has to be started or stopped and acts
* accordingly.
*
* @param {Props} oldProps - The previous values of the Props.
* @param {Props} newProps - The new values of the Props.
* @param {IProps} oldProps - The previous values of the Props.
* @param {IProps} newProps - The new values of the Props.
* @returns {void}
*/
_maybeToggleAnimation(oldProps, newProps) {
_maybeToggleAnimation(oldProps: Partial<IProps>, newProps: IProps) {
const { status: oldStatus } = oldProps;
const { status: newStatus } = newProps;
const { pulseAnimation } = this.state;

@ -1,7 +1,5 @@
// @flow
import { ColorPalette } from '../../../styles/components/styles/ColorPalette';
import BaseTheme from '../../../ui/components/BaseTheme';
import BaseTheme from '../../../ui/components/BaseTheme.native';
/**
* The default color of the {@code Label} and {@code ExpandedLabel}.

@ -92,7 +92,7 @@ export default class AbstractAudio extends Component<IProps> {
* @protected
* @returns {void}
*/
setAudioElementImpl(element?: AudioElement | null) {
setAudioElementImpl(element?: AudioElement | null | any) {
this._audioElementImpl = element;
const { setRef } = this.props;

@ -113,6 +113,8 @@ export default class AbstractVideoTrack<P extends IProps> extends Component<P> {
<Video
mirror = { videoTrack?.mirror }
onPlaying = { this._onVideoPlaying }
// @ts-ignore
onPress = { this.props.onPress }
stream = { stream }
zOrder = { this.props.zOrder }

@ -1,5 +1,3 @@
/* @flow */
import Sound from 'react-native-sound';
import logger from '../../logger';
@ -14,7 +12,7 @@ export default class Audio extends AbstractAudio {
/**
* Reference to 'react-native-sound} {@link Sound} instance.
*/
_sound: ?Sound;
_sound: Sound | undefined | null;
/**
* A callback passed to the 'react-native-sound''s {@link Sound} instance,
@ -25,7 +23,7 @@ export default class Audio extends AbstractAudio {
* @returns {void}
* @private
*/
_soundLoadedCallback(error) {
_soundLoadedCallback(error: Error) {
if (error) {
logger.error('Failed to load sound', error);
} else {
@ -42,7 +40,7 @@ export default class Audio extends AbstractAudio {
this._sound
= this.props.src
? new Sound(
this.props.src, null,
this.props.src, undefined,
this._soundLoadedCallback.bind(this))
: null;
}
@ -69,8 +67,6 @@ export default class Audio extends AbstractAudio {
play() {
if (this._sound) {
this._sound.setNumberOfLoops(this.props.loop ? -1 : 0);
// $FlowExpectedError
this._sound.play(success => {
if (!success) {
logger.warn(`Failed to play ${this.props.src}`);

@ -1,7 +1,6 @@
// @flow
import React, { Component } from 'react';
import { RTCView } from 'react-native-webrtc';
import { GestureResponderEvent } from 'react-native';
import { MediaStream, RTCView } from 'react-native-webrtc';
import Pressable from '../../../react/components/native/Pressable';
@ -11,17 +10,17 @@ import styles from './styles';
/**
* The type of the React {@code Component} props of {@link Video}.
*/
type Props = {
mirror: boolean,
interface IProps {
mirror: boolean;
onPlaying: Function,
onPlaying: Function;
/**
* Callback to invoke when the {@code Video} is clicked/pressed.
*/
onPress: Function,
onPress?: (event: GestureResponderEvent) => void;
stream: Object,
stream: MediaStream;
/**
* Similarly to the CSS property z-index, specifies the z-order of this
@ -46,20 +45,20 @@ type Props = {
* values: 0 for the remote video(s) which appear in the background, and
* 1 for the local video(s) which appear above the remote video(s).
*/
zOrder: number,
zOrder?: number;
/**
* Indicates whether zooming (pinch to zoom and/or drag) is enabled.
*/
zoomEnabled: boolean
};
zoomEnabled: boolean;
}
/**
* The React Native {@link Component} which is similar to Web's
* {@code HTMLVideoElement} and wraps around react-native-webrtc's
* {@link RTCView}.
*/
export default class Video extends Component<Props> {
export default class Video extends Component<IProps> {
/**
* React Component method that executes once component is mounted.
*
@ -70,7 +69,7 @@ export default class Video extends Component<Props> {
// onPlaying callback when <RTCView> is rendered.
const { onPlaying } = this.props;
onPlaying && onPlaying();
onPlaying?.();
}
/**
@ -88,7 +87,7 @@ export default class Video extends Component<Props> {
const objectFit
= zoomEnabled
? 'contain'
: (style && style.objectFit) || 'cover';
: 'cover';
const rtcView
= (
<RTCView

@ -1,11 +1,8 @@
/* @flow */
import React from 'react';
import { View } from 'react-native';
import { connect } from 'react-redux';
import AbstractVideoTrack from '../AbstractVideoTrack';
import type { Props } from '../AbstractVideoTrack';
import AbstractVideoTrack, { IProps } from '../AbstractVideoTrack';
import styles from './styles';
@ -14,7 +11,7 @@ import styles from './styles';
*
* @augments AbstractVideoTrack
*/
class VideoTrack extends AbstractVideoTrack<Props> {
class VideoTrack extends AbstractVideoTrack<IProps> {
/**
* Renders the video element for the associated video track.
*

@ -1,27 +1,25 @@
// @flow
import React, { Component } from 'react';
import { TouchableWithoutFeedback } from 'react-native';
import { GestureResponderEvent, TouchableWithoutFeedback } from 'react-native';
/**
* The type of the React {@link Component} props of {@link Pressable}.
*/
type Props = {
children: React$Node,
interface IProps {
children: React.ReactNode;
/**
* Called when the touch is released, but not if cancelled (e.g. By a scroll
* that steals the responder lock).
*/
onPress: Function
};
onPress?: (event: GestureResponderEvent) => void;
}
/**
* Adds support for {@code onPress} to a child React {@link Component} (which
* should probably not support the prop in question; otherwise, there's little
* point of using {@code Pressable} then in the first place).
*/
export default class Pressable extends Component<Props> {
export default class Pressable extends Component<IProps> {
/**
* Implements React's {@link Component#render()}.
*

@ -1,76 +1,75 @@
// @flow
import React, { type Node, PureComponent } from 'react';
import React, { PureComponent, ReactNode } from 'react';
import {
Animated,
BackHandler,
Dimensions,
TouchableWithoutFeedback,
View
View,
ViewStyle
} from 'react-native';
import { type StyleType } from '../../../styles';
import { StyleType } from '../../../styles/functions.any';
import styles from './slidingviewstyles';
/**
* The type of the React {@code Component} props of {@link SlidingView}.
*/
type Props = {
interface IProps {
/**
* The children of {@code SlidingView}.
*/
children: Node,
children: ReactNode;
/**
* Callback to notify the containing {@code Component} that the view is
* closing.
*/
onHide: Function,
onHide: Function;
/**
* Position of the SlidingView: 'left', 'right', 'top', 'bottom'.
* Later).
*/
position: string,
position: string;
/**
* Whether the {@code SlidingView} is to be displayed/rendered/shown or not.
*/
show: boolean,
show: boolean;
/**
* Style of the animated view.
*/
style: StyleType
};
style: StyleType;
}
/**
* The type of the React {@code Component} state of {@link SlidingView}.
*/
type State = {
interface IState {
/**
* Whether the sliding overlay should be displayed/rendered/shown.
* Offset to move the view out of the screen.
*/
showOverlay: boolean,
positionOffset: number;
/**
* The native animation object.
* Whether the sliding overlay should be displayed/rendered/shown.
*/
sliderAnimation: Animated.Value,
showOverlay: boolean;
/**
* Offset to move the view out of the screen.
* The native animation object.
*/
positionOffset: number
};
sliderAnimation: Animated.Value;
}
/**
* A generic animated slider view to be used for animated menus.
*/
export default class SlidingView extends PureComponent<Props, State> {
export default class SlidingView extends PureComponent<IProps, IState> {
/**
* True if the component is mounted.
*/
@ -81,7 +80,7 @@ export default class SlidingView extends PureComponent<Props, State> {
*
* @inheritdoc
*/
static getDerivedStateFromProps(props: Props, prevState: State) {
static getDerivedStateFromProps(props: IProps, prevState: IState) {
return {
showOverlay: props.show || prevState.showOverlay
};
@ -92,7 +91,7 @@ export default class SlidingView extends PureComponent<Props, State> {
*
* @inheritdoc
*/
constructor(props: Props) {
constructor(props: IProps) {
super(props);
const { height, width } = Dimensions.get('window');
@ -132,7 +131,7 @@ export default class SlidingView extends PureComponent<Props, State> {
*
* @inheritdoc
*/
componentDidUpdate(prevProps: Props) {
componentDidUpdate(prevProps: IProps) {
const { show } = this.props;
if (prevProps.show !== show) {
@ -173,15 +172,13 @@ export default class SlidingView extends PureComponent<Props, State> {
</TouchableWithoutFeedback>
<Animated.View
pointerEvents = 'box-none'
style = { this._getContentStyle() }>
style = { this._getContentStyle() as ViewStyle }>
{ this.props.children }
</Animated.View>
</View>
);
}
_getContentStyle: () => Array<Object>;
/**
* Assembles a style array for the SlideView content.
*
@ -221,8 +218,6 @@ export default class SlidingView extends PureComponent<Props, State> {
return style;
}
_onHardwareBackPress: () => boolean;
/**
* Callback to handle the hardware back button.
*
@ -234,8 +229,6 @@ export default class SlidingView extends PureComponent<Props, State> {
return true;
}
_onHide: () => void;
/**
* Hides the slider.
*
@ -247,12 +240,10 @@ export default class SlidingView extends PureComponent<Props, State> {
.then(() => {
const { onHide } = this.props;
onHide && onHide();
onHide?.();
});
}
_setShow: (boolean) => Promise<*>;
/**
* Shows/hides the slider menu.
*
@ -261,8 +252,8 @@ export default class SlidingView extends PureComponent<Props, State> {
* @private
* @returns {Promise}
*/
_setShow(show) {
return new Promise(resolve => {
_setShow(show: boolean) {
return new Promise<void>(resolve => {
if (!this._mounted) {
resolve();

@ -1,5 +1,3 @@
// @flow
import { StyleSheet } from 'react-native';
import { OVERLAY_Z_INDEX } from '../../constants';

@ -1,41 +1,39 @@
// @flow
import React, { useCallback, useEffect } from 'react';
import { StyleSheet, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
type Props = {
interface IProps {
/**
* The "onLayout" handler.
* Any nested components.
*/
onDimensionsChanged: Function,
children: React.ReactNode;
/**
* The safe are insets handler.
* The "onLayout" handler.
*/
onSafeAreaInsetsChanged: Function,
onDimensionsChanged?: Function;
/**
* Any nested components.
* The safe are insets handler.
*/
children: React$Node
};
onSafeAreaInsetsChanged?: Function;
}
/**
* A {@link View} which captures the 'onLayout' event and calls a prop with the
* component size.
*
* @param {Props} props - The read-only properties with which the new
* @param {IProps} props - The read-only properties with which the new
* instance is to be initialized.
* @returns {Component} - Renders the root view and it's children.
*/
export default function DimensionsDetector(props: Props) {
export default function DimensionsDetector(props: IProps) {
const { top = 0, right = 0, bottom = 0, left = 0 } = useSafeAreaInsets();
const { children, onDimensionsChanged, onSafeAreaInsetsChanged } = props;
useEffect(() => {
onSafeAreaInsetsChanged && onSafeAreaInsetsChanged({
onSafeAreaInsetsChanged?.({
top,
right,
bottom,
@ -53,7 +51,7 @@ export default function DimensionsDetector(props: Props) {
* @returns {void}
*/
const onLayout = useCallback(({ nativeEvent: { layout: { height, width } } }) => {
onDimensionsChanged && onDimensionsChanged(width, height);
onDimensionsChanged?.(width, height);
}, [ onDimensionsChanged ]);
return (

@ -196,8 +196,6 @@ class MeetingParticipantList extends PureComponent<IProps> {
t
} = this.props;
const title = _currentRoom?.name
// $FlowExpectedError
? `${_currentRoom.name} (${_participantsCount})`
: t('participantsPane.headings.participantsList',
{ count: _participantsCount });

@ -1,22 +1,20 @@
// @flow
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { Animated } from 'react-native';
import { useDispatch, useSelector } from 'react-redux';
import { IReduxState } from '../../../app/types';
import ColorSchemeRegistry from '../../../base/color-scheme/ColorSchemeRegistry';
import { removeReaction } from '../../actions.any';
import { REACTIONS, type ReactionEmojiProps } from '../../constants';
import { IReactionEmojiProps, REACTIONS } from '../../constants';
type Props = ReactionEmojiProps & {
interface IProps extends IReactionEmojiProps {
/**
* Index of reaction on the queue.
* Used to differentiate between first and other animations.
*/
index: number
};
index: number;
}
/**
@ -24,16 +22,16 @@ type Props = ReactionEmojiProps & {
*
* @returns {ReactElement}
*/
function ReactionEmoji({ reaction, uid, index }: Props) {
const _styles = useSelector(state => ColorSchemeRegistry.get(state, 'Toolbox'));
const _height = useSelector(state => state['features/base/responsive-ui'].clientHeight);
function ReactionEmoji({ reaction, uid, index }: IProps) {
const _styles: any = useSelector((state: IReduxState) => ColorSchemeRegistry.get(state, 'Toolbox'));
const _height = useSelector((state: IReduxState) => state['features/base/responsive-ui'].clientHeight);
const dispatch = useDispatch();
const animationVal = useRef(new Animated.Value(0)).current;
const vh = useState(_height / 100)[0];
const randomInt = (min, max) => Math.floor((Math.random() * (max - min + 1)) + min);
const randomInt = (min: number, max: number) => Math.floor((Math.random() * (max - min + 1)) + min);
const animationIndex = useMemo(() => index % 21, [ index ]);
@ -68,31 +66,23 @@ function ReactionEmoji({ reaction, uid, index }: Props) {
transform: [
{ translateY: animationVal.interpolate({
inputRange: [ 0, 0.70, 0.75, 1 ],
// $FlowExpectedError
outputRange: [ 0, coordinates.topY * vh, coordinates.topY * vh, coordinates.bottomY * vh ]
})
}, {
translateX: animationVal.interpolate({
inputRange: [ 0, 0.70, 0.75, 1 ],
// $FlowExpectedError
outputRange: [ 0, coordinates.topX, coordinates.topX,
coordinates.topX < 0 ? -coordinates.bottomX : coordinates.bottomX ]
})
}, {
scale: animationVal.interpolate({
inputRange: [ 0, 0.70, 0.75, 1 ],
// $FlowExpectedError
outputRange: [ 0.6, 1.5, 1.5, 1 ]
})
}
],
opacity: animationVal.interpolate({
inputRange: [ 0, 0.7, 0.75, 1 ],
// $FlowExpectedError
outputRange: [ 1, 1, 1, 0 ]
})
}}>
Loading…
Cancel
Save