diff --git a/.eslintignore b/.eslintignore index cdc0de02b21f..9c7eff025c11 100644 --- a/.eslintignore +++ b/.eslintignore @@ -30,8 +30,9 @@ webpack.config.ts # Temporarily ignored during TSLint transition # JIRA: DESKTOP-304 -ts/components/*.ts -ts/components/*.tsx +sticker-creator/**/*.ts +sticker-creator/**/*.tsx +ts/*.ts ts/components/conversation/** ts/components/stickers/** ts/shims/** @@ -44,5 +45,3 @@ ts/textsecure/** ts/types/** ts/updater/** ts/util/** -sticker-creator/**/*.ts -sticker-creator/**/*.tsx diff --git a/.eslintrc.js b/.eslintrc.js index 7dcd2f1e6f72..e6827f54ef70 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -59,7 +59,24 @@ const rules = { }, ], + 'react/jsx-props-no-spreading': 'off', + + // Updated to reflect future airbnb standard + // Allows for declaring defaultProps inside a class + 'react/static-property-placement': ['error', 'static public field'], + + // JIRA: DESKTOP-657 + 'react/sort-comp': 'off', + + // We don't have control over the media we're sharing, so can't require + // captions. + 'jsx-a11y/media-has-caption': 'off', + + // We prefer named exports 'import/prefer-default-export': 'off', + + // Prefer functional components with default params + 'react/require-default-props': 'off', }; module.exports = { @@ -101,7 +118,6 @@ module.exports = { rules: { ...rules, 'import/no-extraneous-dependencies': 'off', - 'react/jsx-props-no-spreading': 'off', }, }, ], diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 9de50fac5641..858f91fb1efc 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -671,6 +671,10 @@ "message": "Search", "description": "Placeholder text in the search input" }, + "clearSearch": { + "message": "Clear Search", + "description": "Aria label for clear search button" + }, "searchIn": { "message": "Search in $conversationName$", "description": "Shown in the search box before text is entered when searching in a specific conversation", @@ -3568,5 +3572,25 @@ "example": "5" } } + }, + "close": { + "message": "close", + "description": "Generic close label" + }, + "previous": { + "message": "previous", + "description": "Generic previous label" + }, + "next": { + "message": "next", + "description": "Generic next label" + }, + "CompositionArea--expand": { + "message": "Expand", + "description": "Aria label for expanding composition area" + }, + "CompositionArea--attach-file": { + "message": "Attach file", + "description": "Aria label for file attachment button in composition area" } } diff --git a/ts/components/Avatar.stories.tsx b/ts/components/Avatar.stories.tsx index e80220695443..e4ce0fca3724 100644 --- a/ts/components/Avatar.stories.tsx +++ b/ts/components/Avatar.stories.tsx @@ -1,14 +1,11 @@ import * as React from 'react'; -import { Avatar, Props } from './Avatar'; import { storiesOf } from '@storybook/react'; import { boolean, select, text } from '@storybook/addon-knobs'; import { action } from '@storybook/addon-actions'; -// @ts-ignore +import { Avatar, Props } from './Avatar'; import { setup as setupI18n } from '../../js/modules/i18n'; - -// @ts-ignore import enMessages from '../../_locales/en/messages.json'; import { Colors, ColorType } from '../types/Colors'; diff --git a/ts/components/Avatar.tsx b/ts/components/Avatar.tsx index 0e8afde31a7f..d0ffcb1e1636 100644 --- a/ts/components/Avatar.tsx +++ b/ts/components/Avatar.tsx @@ -56,15 +56,16 @@ export class Avatar extends React.Component { return state; } - public handleImageError() { - // tslint:disable-next-line no-console - console.log('Avatar: Image failed to load; failing over to placeholder'); + public handleImageError(): void { + window.log.info( + 'Avatar: Image failed to load; failing over to placeholder' + ); this.setState({ imageBroken: true, }); } - public renderImage() { + public renderImage(): JSX.Element | null { const { avatarPath, i18n, title } = this.props; const { imageBroken } = this.state; @@ -81,7 +82,7 @@ export class Avatar extends React.Component { ); } - public renderNoImage() { + public renderNoImage(): JSX.Element { const { conversationType, name, @@ -129,7 +130,7 @@ export class Avatar extends React.Component { ); } - public render() { + public render(): JSX.Element { const { avatarPath, color, @@ -151,7 +152,11 @@ export class Avatar extends React.Component { if (onClick) { contents = ( - ); diff --git a/ts/components/AvatarPopup.stories.tsx b/ts/components/AvatarPopup.stories.tsx index 586423c00c5d..e65d1eecd8f7 100644 --- a/ts/components/AvatarPopup.stories.tsx +++ b/ts/components/AvatarPopup.stories.tsx @@ -2,14 +2,11 @@ import * as React from 'react'; import { storiesOf } from '@storybook/react'; import { action } from '@storybook/addon-actions'; -import { AvatarPopup, Props } from './AvatarPopup'; -import { Colors, ColorType } from '../types/Colors'; import { boolean, select, text } from '@storybook/addon-knobs'; -// @ts-ignore +import { AvatarPopup, Props } from './AvatarPopup'; +import { Colors, ColorType } from '../types/Colors'; import { setup as setupI18n } from '../../js/modules/i18n'; - -// @ts-ignore import enMessages from '../../_locales/en/messages.json'; const i18n = setupI18n('en', enMessages); diff --git a/ts/components/AvatarPopup.tsx b/ts/components/AvatarPopup.tsx index 11f600bc338c..03b5a22fc42f 100644 --- a/ts/components/AvatarPopup.tsx +++ b/ts/components/AvatarPopup.tsx @@ -17,7 +17,7 @@ export type Props = { style: React.CSSProperties; } & AvatarProps; -export const AvatarPopup = (props: Props) => { +export const AvatarPopup = (props: Props): JSX.Element => { const focusRef = React.useRef(null); const { i18n, @@ -54,6 +54,7 @@ export const AvatarPopup = (props: Props) => {
- ); @@ -55,9 +55,14 @@ type StateType = { }; export class CallScreen extends React.Component { + // eslint-disable-next-line @typescript-eslint/no-explicit-any private interval: any; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any private controlsFadeTimer: any; + private readonly localVideoRef: React.RefObject; + private readonly remoteVideoRef: React.RefObject; constructor(props: PropsType) { @@ -75,18 +80,22 @@ export class CallScreen extends React.Component { this.remoteVideoRef = React.createRef(); } - public componentDidMount() { + public componentDidMount(): void { + const { setLocalPreview, setRendererCanvas } = this.props; + // It's really jump with a value of 500ms. this.interval = setInterval(this.updateAcceptedTimer, 100); this.fadeControls(); document.addEventListener('keydown', this.handleKeyDown); - this.props.setLocalPreview({ element: this.localVideoRef }); - this.props.setRendererCanvas({ element: this.remoteVideoRef }); + setLocalPreview({ element: this.localVideoRef }); + setRendererCanvas({ element: this.remoteVideoRef }); } - public componentWillUnmount() { + public componentWillUnmount(): void { + const { setLocalPreview, setRendererCanvas } = this.props; + document.removeEventListener('keydown', this.handleKeyDown); if (this.interval) { @@ -95,11 +104,12 @@ export class CallScreen extends React.Component { if (this.controlsFadeTimer) { clearTimeout(this.controlsFadeTimer); } - this.props.setLocalPreview({ element: undefined }); - this.props.setRendererCanvas({ element: undefined }); + + setLocalPreview({ element: undefined }); + setRendererCanvas({ element: undefined }); } - updateAcceptedTimer = () => { + updateAcceptedTimer = (): void => { const { acceptedTime } = this.state; const { callState } = this.props; @@ -119,7 +129,7 @@ export class CallScreen extends React.Component { } }; - handleKeyDown = (event: KeyboardEvent) => { + handleKeyDown = (event: KeyboardEvent): void => { const { callDetails } = this.props; if (!callDetails) { @@ -143,8 +153,10 @@ export class CallScreen extends React.Component { } }; - showControls = () => { - if (!this.state.showControls) { + showControls = (): void => { + const { showControls } = this.state; + + if (!showControls) { this.setState({ showControls: true, }); @@ -153,7 +165,7 @@ export class CallScreen extends React.Component { this.fadeControls(); }; - fadeControls = () => { + fadeControls = (): void => { if (this.controlsFadeTimer) { clearTimeout(this.controlsFadeTimer); } @@ -165,7 +177,7 @@ export class CallScreen extends React.Component { }, 5000); }; - toggleAudio = () => { + toggleAudio = (): void => { const { callDetails, hasLocalAudio, setLocalAudio } = this.props; if (!callDetails) { @@ -178,7 +190,7 @@ export class CallScreen extends React.Component { }); }; - toggleVideo = () => { + toggleVideo = (): void => { const { callDetails, hasLocalVideo, setLocalVideo } = this.props; if (!callDetails) { @@ -188,7 +200,7 @@ export class CallScreen extends React.Component { setLocalVideo({ callId: callDetails.callId, enabled: !hasLocalVideo }); }; - public render() { + public render(): JSX.Element | null { const { callDetails, callState, @@ -238,6 +250,7 @@ export class CallScreen extends React.Component { {this.renderMessage(callState)}
@@ -144,14 +146,13 @@ export const CallingDeviceSelection = ({ {i18n('callingDeviceSelection__settings')} -