diff --git a/src/action-sheets/index.js b/src/action-sheets/index.js index 8a91ab6b8c..7bc8fff573 100644 --- a/src/action-sheets/index.js +++ b/src/action-sheets/index.js @@ -44,7 +44,7 @@ import { Role, type RoleT } from '../api/permissionsTypes'; import { roleIsAtLeast } from '../permissionSelectors'; import { kNotificationBotEmail } from '../api/constants'; import type { AppNavigationMethods } from '../nav/AppNavigator'; -import typeof ComposeBox from '../compose/ComposeBox'; +import { type ImperativeHandle as ComposeBoxImperativeHandle } from '../compose/ComposeBox'; // TODO really this belongs in a libdef. export type ShowActionSheetWithOptions = ( @@ -94,7 +94,7 @@ type MessageArgs = { dispatch: Dispatch, startEditMessage: (editMessage: EditMessage) => void, setDoNotMarkMessagesAsRead: boolean => void, - composeBoxRefCurrent: React$ElementRef | null, + composeBoxImperativeHandle: ComposeBoxImperativeHandle | null, navigation: AppNavigationMethods, _: GetText, ... @@ -133,12 +133,12 @@ const reply = { const quoteAndReply = { title: 'Quote and reply', errorMessage: 'Quote-and-reply failed', - action: async ({ message, composeBoxRefCurrent }) => { - if (!composeBoxRefCurrent) { + action: async ({ message, composeBoxImperativeHandle }) => { + if (!composeBoxImperativeHandle) { logging.error("quoteAndReply button pressed when it shouldn't have appeared in the UI"); return; } - return composeBoxRefCurrent.doQuoteAndReply(message); + return composeBoxImperativeHandle.doQuoteAndReply(message); }, }; @@ -807,7 +807,7 @@ export const showMessageActionSheet = (args: {| callbacks: {| dispatch: Dispatch, startEditMessage: (editMessage: EditMessage) => void, - composeBoxRefCurrent: React$ElementRef | null, + composeBoxImperativeHandle: ComposeBoxImperativeHandle | null, navigation: AppNavigationMethods, _: GetText, setDoNotMarkMessagesAsRead: boolean => void, @@ -833,7 +833,7 @@ export const showMessageActionSheet = (args: {| backgroundData, message, narrow, - canStartQuoteAndReply: callbacks.composeBoxRefCurrent !== null, + canStartQuoteAndReply: callbacks.composeBoxImperativeHandle !== null, }), args: { ...backgroundData, ...callbacks, message, narrow }, }); diff --git a/src/chat/ChatScreen.js b/src/chat/ChatScreen.js index 8b85454f0c..7e6af9438b 100644 --- a/src/chat/ChatScreen.js +++ b/src/chat/ChatScreen.js @@ -1,5 +1,5 @@ /* @flow strict-local */ -import React, { useCallback, useContext, useState } from 'react'; +import React, { useCallback, useContext } from 'react'; import type { Node } from 'react'; import { useIsFocused } from '@react-navigation/native'; @@ -15,7 +15,9 @@ import NoMessages from '../message/NoMessages'; import FetchError from './FetchError'; import InvalidNarrow from './InvalidNarrow'; import { fetchMessagesInNarrow } from '../message/fetchActions'; -import ComposeBox from '../compose/ComposeBox'; +import ComposeBox, { + type ImperativeHandle as ComposeBoxImperativeHandle, +} from '../compose/ComposeBox'; import UnreadNotice from './UnreadNotice'; import { showComposeBoxOnNarrow, caseNarrowDefault, keyFromNarrow } from '../utils/narrow'; import { getLoading, getSession } from '../directSelectors'; @@ -144,7 +146,7 @@ export default function ChatScreen(props: Props): Node { const sayNoMessages = messages.length === 0 && !isFetching; const showComposeBox = showComposeBoxOnNarrow(narrow) && !showMessagePlaceholders; - const composeBoxRef = React.useRef | null>(null); + const composeBoxRef = React.useRef(null); const auth = useSelector(getAuth); const dispatch = useDispatch(); diff --git a/src/compose/ComposeBox.js b/src/compose/ComposeBox.js index 77dd454753..880412b18b 100644 --- a/src/compose/ComposeBox.js +++ b/src/compose/ComposeBox.js @@ -111,7 +111,7 @@ export type ValidationError = /** * Functions expected to be called using a ref to this component. */ -type ImperativeHandle = {| +export type ImperativeHandle = {| /** * Take a message ID, fetch its raw Markdown content, and put it in the * compose box with proper formatting. diff --git a/src/webview/MessageList.js b/src/webview/MessageList.js index 74b8c1a00a..5e16a335f6 100644 --- a/src/webview/MessageList.js +++ b/src/webview/MessageList.js @@ -41,7 +41,7 @@ import { type BackgroundData, getBackgroundData } from './backgroundData'; import { ensureUnreachable } from '../generics'; import SinglePageWebView from './SinglePageWebView'; import { usePrevious } from '../reactUtils'; -import typeof ComposeBox from '../compose/ComposeBox'; +import { type ImperativeHandle as ComposeBoxImperativeHandle } from '../compose/ComposeBox'; /** * The actual React props for the MessageList component. @@ -54,7 +54,7 @@ type OuterProps = $ReadOnly<{| startEditMessage: (editMessage: EditMessage) => void, // Careful: We expect this prop to be mutable, which is unusual. - composeBoxRef: {| current: React$ElementRef | null |}, + composeBoxRef: {| current: ComposeBoxImperativeHandle | null |}, |}>; /** @@ -320,7 +320,7 @@ export default function MessageList(outerProps: OuterProps): React.Node { handleWebViewOutboundEvent(propsRef.current, navigation, eventData); } }, - [sendInboundEvents], + [sendInboundEvents, navigation], ); // We compute the page contents as an HTML string just once (*), on this diff --git a/src/webview/handleOutboundEvents.js b/src/webview/handleOutboundEvents.js index 1dcb5fff29..c4f00cf0b6 100644 --- a/src/webview/handleOutboundEvents.js +++ b/src/webview/handleOutboundEvents.js @@ -258,7 +258,7 @@ const handleLongPress = (args: {| // that an action-sheet button press will act on values that were // current when the action sheet was opened: // https://github.com/zulip/zulip-mobile/pull/5554#discussion_r1027004559 - composeBoxRefCurrent: composeBoxRef.current, + composeBoxImperativeHandle: composeBoxRef.current, navigation, _, diff --git a/tools/test b/tools/test index b60c8c7d7d..7892630445 100755 --- a/tools/test +++ b/tools/test @@ -68,43 +68,43 @@ EOF exit 2 } -coverage= -files=branch -platform=sloppy -fix= -suites=() +opt_coverage= +opt_files=branch +opt_platform=sloppy +opt_fix= +opt_suites=() while (( $# )); do case "$1" in - --coverage) coverage=1; shift;; - --diff) shift; files=diff:"$1"; shift;; - --all-files) files=all; shift;; + --coverage) opt_coverage=1; shift;; + --diff) shift; opt_files=diff:"$1"; shift;; + --all-files) opt_files=all; shift;; --platform) shift; case "$1" in - ios|android|both|sloppy) platform="$1";; + ios|android|both|sloppy) opt_platform="$1";; *) usage;; esac shift ;; - --all) files=all; platform=both; shift;; - --fix) fix=1; shift;; + --all) opt_files=all; opt_platform=both; shift;; + --fix) opt_fix=1; shift;; native|flow|lint|jest|prettier|deps|tsflower) - suites+=("$1"); shift;; + opt_suites+=("$1"); shift;; *) usage;; esac done -if [ -z "$suites" ]; then +if [ -z "$opt_suites" ]; then # This default doesn't have to be the complete list; just be sure to # document in the usage message any suites that it skips. - suites=(native flow lint jest prettier deps tsflower) + opt_suites=(native flow lint jest prettier deps tsflower) fi files_base_commit= -case "$files" in +case "$opt_files" in all) ;; branch) files_base_commit="$(tools/git base)";; - diff:*) files_base_commit="${files#diff:}";; + diff:*) files_base_commit="${opt_files#diff:}";; esac @@ -115,12 +115,12 @@ cd "$rootdir" PATH=node_modules/.bin:"$PATH" -# Intersect $files with the set of our JS files in src/. +# Intersect $opt_files with the set of our JS files in src/. # # Prints a list of newline-terminated paths; either files, or # directories meaning their whole subtrees. files_js() { - case "$files" in + case "$opt_files" in all) echo src/ ;; @@ -132,7 +132,7 @@ files_js() { # True just if $files intersects the given set of paths. files_check() { - case "$files" in + case "$opt_files" in all) ;; branch | diff:*) @@ -166,12 +166,12 @@ run_native_ios() { } run_native() { - if [[ $platform == android || $platform == both || $platform == sloppy ]]; then + if [[ $opt_platform == android || $opt_platform == both || $opt_platform == sloppy ]]; then echo 'Running Android native tests...'; run_native_android || return fi - if [[ $platform == ios || $platform == both || $platform == sloppy ]]; then + if [[ $opt_platform == ios || $opt_platform == both || $opt_platform == sloppy ]]; then # TODO: Run if on macOS; otherwise, echo that these tests are # skipped because they can't be run. @@ -185,15 +185,15 @@ run_lint() { files=( $(files_js) ) files=( $(apply_eslintignore "${files[@]}") ) (( ${#files[@]} )) || return 0 - eslint ${fix:+--fix} --report-unused-disable-directives --max-warnings=0 "${files[@]}" + eslint ${opt_fix:+--fix} --report-unused-disable-directives --max-warnings=0 "${files[@]}" } run_jest() { - # Unlike some others, this inspects "$files" for itself. + # Unlike some others, this inspects "$opt_files" for itself. local jest_args=() - case "$files" in + case "$opt_files" in all) - if [ -n "$coverage" ]; then + if [ -n "$opt_coverage" ]; then jest_args+=( --coverage ) fi ;; @@ -209,7 +209,7 @@ run_jest() { esac local platforms=( ios android ) - case "$platform" in + case "$opt_platform" in ios) jest_args+=( --selectProjects ios );; android) jest_args+=( --selectProjects android );; both) jest_args+=( --selectProjects ios android );; @@ -225,7 +225,7 @@ run_jest() { run_prettier() { local patterns - case "$files" in + case "$opt_files" in all) # The prettier-eslint CLI won't take directories; # but it's happy to take glob patterns, and supports `**`. @@ -242,7 +242,7 @@ run_prettier() { # Workaround for https://github.com/prettier/prettier-eslint-cli/issues/205 patterns=( "${patterns[@]/#/$rootdir/}" ) prettier-eslint \ - ${fix:+--write} \ + ${opt_fix:+--write} \ --list-different \ --eslint-config-path "${rootdir}"/tools/formatting.eslintrc.yaml \ "${patterns[@]}" @@ -285,7 +285,7 @@ run_tsflower() { } failed=() -for suite in "${suites[@]}"; do +for suite in "${opt_suites[@]}"; do echo "Running $suite..." case "$suite" in native) run_native ;;