Prepare for switching AccessibleButton and derivatives to forwardRef (#12072)
* Improve AccessibleButton props & docs Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Improve AccessibleTooltipButton props docs Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Simplify roving tab index hook usage Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Ditch RefObject type casts Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Convert AccessibleTooltipButton to a Functional Component Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
parent
2212fbadd0
commit
bf61d93bf4
13 changed files with 140 additions and 103 deletions
|
@ -26,7 +26,10 @@ import {
|
|||
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
import getEntryComponentForLoginType, { IStageComponent } from "../views/auth/InteractiveAuthEntryComponents";
|
||||
import getEntryComponentForLoginType, {
|
||||
ContinueKind,
|
||||
IStageComponent,
|
||||
} from "../views/auth/InteractiveAuthEntryComponents";
|
||||
import Spinner from "../views/elements/Spinner";
|
||||
|
||||
export const ERROR_USER_CANCELLED = new Error("User cancelled auth session");
|
||||
|
@ -59,7 +62,7 @@ export interface InteractiveAuthProps<T> {
|
|||
continueIsManaged?: boolean;
|
||||
// continueText and continueKind are passed straight through to the AuthEntryComponent.
|
||||
continueText?: string;
|
||||
continueKind?: string;
|
||||
continueKind?: ContinueKind;
|
||||
// callback
|
||||
makeRequest(auth: IAuthDict | null): Promise<T>;
|
||||
// callback called when the auth process has finished,
|
||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
|
||||
import { EventType, RoomType, JoinRule, Preset, Room, RoomEvent } from "matrix-js-sdk/src/matrix";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import React, { RefObject, useCallback, useContext, useRef, useState } from "react";
|
||||
import React, { useCallback, useContext, useRef, useState } from "react";
|
||||
|
||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||
import createRoom, { IOpts } from "../../createRoom";
|
||||
|
@ -499,7 +499,7 @@ const SpaceSetupPrivateInvite: React.FC<{
|
|||
const [busy, setBusy] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const numFields = 3;
|
||||
const fieldRefs = [useRef(), useRef(), useRef()] as RefObject<Field>[];
|
||||
const fieldRefs = [useRef<Field>(null), useRef<Field>(null), useRef<Field>(null)];
|
||||
const [emailAddresses, setEmailAddress] = useStateArray(numFields, "");
|
||||
const fields = new Array(numFields).fill(0).map((x, i) => {
|
||||
const name = "emailAddress" + i;
|
||||
|
|
|
@ -25,7 +25,7 @@ import { _t } from "../../../languageHandler";
|
|||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import { LocalisedPolicy, Policies } from "../../../Terms";
|
||||
import { AuthHeaderModifier } from "../../structures/auth/header/AuthHeaderModifier";
|
||||
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
|
||||
import AccessibleButton, { AccessibleButtonKind, ButtonEvent } from "../elements/AccessibleButton";
|
||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
||||
import Field from "../elements/Field";
|
||||
import Spinner from "../elements/Spinner";
|
||||
|
@ -780,9 +780,12 @@ export class RegistrationTokenAuthEntry extends React.Component<IAuthEntryProps,
|
|||
}
|
||||
}
|
||||
|
||||
// Subset of AccessibleButtonKind which can be specified for the continue button
|
||||
export type ContinueKind = Extract<AccessibleButtonKind, "primary" | "danger">;
|
||||
|
||||
interface ISSOAuthEntryProps extends IAuthEntryProps {
|
||||
continueText?: string;
|
||||
continueKind?: string;
|
||||
continueKind?: ContinueKind;
|
||||
onCancel?: () => void;
|
||||
}
|
||||
|
||||
|
@ -866,7 +869,7 @@ export class SSOAuthEntry extends React.Component<ISSOAuthEntryProps, ISSOAuthEn
|
|||
const cancelButton = (
|
||||
<AccessibleButton
|
||||
onClick={this.props.onCancel ?? null}
|
||||
kind={this.props.continueKind ? this.props.continueKind + "_outline" : "primary_outline"}
|
||||
kind={this.props.continueKind ? `${this.props.continueKind}_outline` : "primary_outline"}
|
||||
>
|
||||
{_t("action|cancel")}
|
||||
</AccessibleButton>
|
||||
|
@ -985,7 +988,7 @@ export interface IStageComponentProps extends IAuthEntryProps {
|
|||
inputs?: IInputs;
|
||||
stageState?: IStageStatus;
|
||||
continueText?: string;
|
||||
continueKind?: string;
|
||||
continueKind?: ContinueKind;
|
||||
setEmailSid?(sid: string): void;
|
||||
onCancel?(): void;
|
||||
requestEmailToken?(): Promise<void>;
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { ReactElement, ReactNode, RefObject, useContext, useMemo, useRef, useState } from "react";
|
||||
import React, { ReactElement, ReactNode, useContext, useMemo, useRef, useState } from "react";
|
||||
import classNames from "classnames";
|
||||
import { Room, EventType } from "matrix-js-sdk/src/matrix";
|
||||
import { sleep } from "matrix-js-sdk/src/utils";
|
||||
|
@ -144,7 +144,7 @@ export const AddExistingToSpace: React.FC<IAddExistingToSpaceProps> = ({
|
|||
[cli, msc3946ProcessDynamicPredecessor],
|
||||
);
|
||||
|
||||
const scrollRef = useRef() as RefObject<AutoHideScrollbar<"div">>;
|
||||
const scrollRef = useRef<AutoHideScrollbar<"div">>(null);
|
||||
const [scrollState, setScrollState] = useState<IScrollState>({
|
||||
// these are estimates which update as soon as it mounts
|
||||
scrollTop: 0,
|
||||
|
|
|
@ -23,7 +23,7 @@ import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
|||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import InteractiveAuth, { ERROR_USER_CANCELLED, InteractiveAuthCallback } from "../../structures/InteractiveAuth";
|
||||
import { DEFAULT_PHASE, PasswordAuthEntry, SSOAuthEntry } from "../auth/InteractiveAuthEntryComponents";
|
||||
import { ContinueKind, DEFAULT_PHASE, PasswordAuthEntry, SSOAuthEntry } from "../auth/InteractiveAuthEntryComponents";
|
||||
import StyledCheckbox from "../elements/StyledCheckbox";
|
||||
import BaseDialog from "./BaseDialog";
|
||||
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
||||
|
@ -34,7 +34,7 @@ type DialogAesthetics = Partial<{
|
|||
[x: number]: {
|
||||
body: string;
|
||||
continueText?: string;
|
||||
continueKind?: string;
|
||||
continueKind?: ContinueKind;
|
||||
};
|
||||
};
|
||||
}>;
|
||||
|
@ -53,7 +53,7 @@ interface IState {
|
|||
// next to the InteractiveAuth component.
|
||||
bodyText?: string;
|
||||
continueText?: string;
|
||||
continueKind?: string;
|
||||
continueKind?: ContinueKind;
|
||||
}
|
||||
|
||||
export default class DeactivateAccountDialog extends React.Component<IProps, IState> {
|
||||
|
@ -98,7 +98,7 @@ export default class DeactivateAccountDialog extends React.Component<IProps, ISt
|
|||
const aesthetics = DEACTIVATE_AESTHETICS[stage];
|
||||
let bodyText: string | undefined;
|
||||
let continueText: string | undefined;
|
||||
let continueKind: string | undefined;
|
||||
let continueKind: ContinueKind | undefined;
|
||||
if (aesthetics) {
|
||||
const phaseAesthetics = aesthetics[phase];
|
||||
if (phaseAesthetics) {
|
||||
|
|
|
@ -27,7 +27,7 @@ import InteractiveAuth, {
|
|||
InteractiveAuthCallback,
|
||||
InteractiveAuthProps,
|
||||
} from "../../structures/InteractiveAuth";
|
||||
import { SSOAuthEntry } from "../auth/InteractiveAuthEntryComponents";
|
||||
import { ContinueKind, SSOAuthEntry } from "../auth/InteractiveAuthEntryComponents";
|
||||
import BaseDialog from "./BaseDialog";
|
||||
|
||||
type DialogAesthetics = Partial<{
|
||||
|
@ -36,7 +36,7 @@ type DialogAesthetics = Partial<{
|
|||
title: string;
|
||||
body: string;
|
||||
continueText: string;
|
||||
continueKind: string;
|
||||
continueKind: ContinueKind;
|
||||
};
|
||||
};
|
||||
}>;
|
||||
|
@ -146,7 +146,7 @@ export default class InteractiveAuthDialog<T> extends React.Component<Interactiv
|
|||
let title = this.state.authError ? "Error" : this.props.title || _t("common|authentication");
|
||||
let body = this.state.authError ? null : this.props.body;
|
||||
let continueText: string | undefined;
|
||||
let continueKind: string | undefined;
|
||||
let continueKind: ContinueKind | undefined;
|
||||
const dialogAesthetics = this.props.aestheticsForStagePhases || this.getDefaultDialogAesthetics();
|
||||
if (!this.state.authError && dialogAesthetics) {
|
||||
if (
|
||||
|
|
|
@ -33,7 +33,7 @@ import {
|
|||
|
||||
import BaseDialog from "./BaseDialog";
|
||||
import { _t, getUserLanguage } from "../../../languageHandler";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
import AccessibleButton, { AccessibleButtonKind } from "../elements/AccessibleButton";
|
||||
import { StopGapWidgetDriver } from "../../../stores/widgets/StopGapWidgetDriver";
|
||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
import { OwnProfileStore } from "../../../stores/OwnProfileStore";
|
||||
|
@ -158,7 +158,7 @@ export default class ModalWidgetDialog extends React.PureComponent<IProps, IStat
|
|||
.slice(0, MAX_BUTTONS)
|
||||
.reverse()
|
||||
.map((def) => {
|
||||
let kind = "secondary";
|
||||
let kind: AccessibleButtonKind = "secondary";
|
||||
switch (def.kind) {
|
||||
case ModalButtonKind.Primary:
|
||||
kind = "primary";
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { HTMLAttributes, InputHTMLAttributes, ReactNode } from "react";
|
||||
import React, { HTMLAttributes, InputHTMLAttributes } from "react";
|
||||
import classnames from "classnames";
|
||||
|
||||
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
|
||||
|
@ -22,7 +22,10 @@ import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
|||
|
||||
export type ButtonEvent = React.MouseEvent<Element> | React.KeyboardEvent<Element> | React.FormEvent<Element>;
|
||||
|
||||
type AccessibleButtonKind =
|
||||
/**
|
||||
* The kind of button, similar to how Bootstrap works.
|
||||
*/
|
||||
export type AccessibleButtonKind =
|
||||
| "primary"
|
||||
| "primary_outline"
|
||||
| "primary_sm"
|
||||
|
@ -58,25 +61,31 @@ type DynamicElementProps<T extends keyof JSX.IntrinsicElements> = Partial<
|
|||
Omit<InputHTMLAttributes<Element>, "onClick">;
|
||||
|
||||
/**
|
||||
* children: React's magic prop. Represents all children given to the element.
|
||||
* element: (optional) The base element type. "div" by default.
|
||||
* onClick: (required) Event handler for button activation. Should be
|
||||
* implemented exactly like a normal onClick handler.
|
||||
* Type of props accepted by {@link AccessibleButton}.
|
||||
*
|
||||
* Extends props accepted by the underlying element specified using the `element` prop.
|
||||
*/
|
||||
type IProps<T extends keyof JSX.IntrinsicElements> = DynamicHtmlElementProps<T> & {
|
||||
type Props<T extends keyof JSX.IntrinsicElements> = DynamicHtmlElementProps<T> & {
|
||||
inputRef?: React.Ref<Element>;
|
||||
/**
|
||||
* The base element type. "div" by default.
|
||||
*/
|
||||
element?: T;
|
||||
children?: ReactNode;
|
||||
// The kind of button, similar to how Bootstrap works.
|
||||
// See available classes for AccessibleButton for options.
|
||||
kind?: AccessibleButtonKind | string;
|
||||
// The ARIA role
|
||||
role?: string;
|
||||
// The tabIndex
|
||||
tabIndex?: number;
|
||||
/**
|
||||
* The kind of button, similar to how Bootstrap works.
|
||||
*/
|
||||
kind?: AccessibleButtonKind;
|
||||
/**
|
||||
* Whether the button should be disabled.
|
||||
*/
|
||||
disabled?: boolean;
|
||||
className?: string;
|
||||
/**
|
||||
* Whether the button should trigger on mousedown event instead of on click event. Defaults to false (click event).
|
||||
*/
|
||||
triggerOnMouseDown?: boolean;
|
||||
/**
|
||||
* Event handler for button activation. Should be implemented exactly like a normal `onClick` handler.
|
||||
*/
|
||||
onClick: ((e: ButtonEvent) => void | Promise<void>) | null;
|
||||
};
|
||||
|
||||
|
@ -104,7 +113,7 @@ export default function AccessibleButton<T extends keyof JSX.IntrinsicElements>(
|
|||
onKeyUp,
|
||||
triggerOnMouseDown,
|
||||
...restProps
|
||||
}: IProps<T>): JSX.Element {
|
||||
}: Props<T>): JSX.Element {
|
||||
const newProps: IAccessibleButtonProps = restProps;
|
||||
if (disabled) {
|
||||
newProps["aria-disabled"] = true;
|
||||
|
|
|
@ -15,85 +15,105 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { SyntheticEvent, FocusEvent } from "react";
|
||||
import React, { SyntheticEvent, FocusEvent, useEffect, useState } from "react";
|
||||
|
||||
import AccessibleButton from "./AccessibleButton";
|
||||
import Tooltip, { Alignment } from "./Tooltip";
|
||||
|
||||
interface IProps extends React.ComponentProps<typeof AccessibleButton> {
|
||||
/**
|
||||
* Type of props accepted by {@link AccessibleTooltipButton}.
|
||||
*
|
||||
* Extends that of {@link AccessibleButton}.
|
||||
*/
|
||||
interface Props extends React.ComponentProps<typeof AccessibleButton> {
|
||||
/**
|
||||
* Title to show in the tooltip and use as aria-label
|
||||
*/
|
||||
title?: string;
|
||||
/**
|
||||
* Tooltip node to show in the tooltip, takes precedence over `title`
|
||||
*/
|
||||
tooltip?: React.ReactNode;
|
||||
/**
|
||||
* Trigger label to render
|
||||
*/
|
||||
label?: string;
|
||||
/**
|
||||
* Classname to apply to the tooltip
|
||||
*/
|
||||
tooltipClassName?: string;
|
||||
/**
|
||||
* Force the tooltip to be hidden
|
||||
*/
|
||||
forceHide?: boolean;
|
||||
/**
|
||||
* Alignment to render the tooltip with
|
||||
*/
|
||||
alignment?: Alignment;
|
||||
/**
|
||||
* Function to call when the children are hovered over
|
||||
*/
|
||||
onHover?: (hovering: boolean) => void;
|
||||
/**
|
||||
* Function to call when the tooltip goes from shown to hidden.
|
||||
*/
|
||||
onHideTooltip?(ev: SyntheticEvent): void;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
hover: boolean;
|
||||
}
|
||||
function AccessibleTooltipButton({
|
||||
title,
|
||||
tooltip,
|
||||
children,
|
||||
forceHide,
|
||||
alignment,
|
||||
onHideTooltip,
|
||||
tooltipClassName,
|
||||
...props
|
||||
}: Props): JSX.Element {
|
||||
const [hover, setHover] = useState(false);
|
||||
|
||||
export default class AccessibleTooltipButton extends React.PureComponent<IProps, IState> {
|
||||
public constructor(props: IProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
hover: false,
|
||||
};
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: Readonly<IProps>): void {
|
||||
if (!prevProps.forceHide && this.props.forceHide && this.state.hover) {
|
||||
this.setState({
|
||||
hover: false,
|
||||
});
|
||||
useEffect(() => {
|
||||
// If forceHide is set then force hover to off to hide the tooltip
|
||||
if (forceHide && hover) {
|
||||
setHover(false);
|
||||
}
|
||||
}
|
||||
}, [forceHide, hover]);
|
||||
|
||||
private showTooltip = (): void => {
|
||||
if (this.props.onHover) this.props.onHover(true);
|
||||
if (this.props.forceHide) return;
|
||||
this.setState({
|
||||
hover: true,
|
||||
});
|
||||
const showTooltip = (): void => {
|
||||
props.onHover?.(true);
|
||||
if (forceHide) return;
|
||||
setHover(true);
|
||||
};
|
||||
|
||||
private hideTooltip = (ev: SyntheticEvent): void => {
|
||||
if (this.props.onHover) this.props.onHover(false);
|
||||
this.setState({
|
||||
hover: false,
|
||||
});
|
||||
this.props.onHideTooltip?.(ev);
|
||||
const hideTooltip = (ev: SyntheticEvent): void => {
|
||||
props.onHover?.(false);
|
||||
setHover(false);
|
||||
onHideTooltip?.(ev);
|
||||
};
|
||||
|
||||
private onFocus = (ev: FocusEvent): void => {
|
||||
const onFocus = (ev: FocusEvent): void => {
|
||||
// We only show the tooltip if focus arrived here from some other
|
||||
// element, to avoid leaving tooltips hanging around when a modal closes
|
||||
if (ev.relatedTarget) this.showTooltip();
|
||||
if (ev.relatedTarget) showTooltip();
|
||||
};
|
||||
|
||||
public render(): React.ReactNode {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { title, tooltip, children, tooltipClassName, forceHide, alignment, onHideTooltip, ...props } =
|
||||
this.props;
|
||||
|
||||
const tip = this.state.hover && (title || tooltip) && (
|
||||
<Tooltip tooltipClassName={tooltipClassName} label={tooltip || title} alignment={alignment} />
|
||||
);
|
||||
return (
|
||||
<AccessibleButton
|
||||
{...props}
|
||||
onMouseOver={this.showTooltip || props.onMouseOver}
|
||||
onMouseLeave={this.hideTooltip || props.onMouseLeave}
|
||||
onFocus={this.onFocus || props.onFocus}
|
||||
onBlur={this.hideTooltip || props.onBlur}
|
||||
aria-label={title || props["aria-label"]}
|
||||
>
|
||||
{children}
|
||||
{this.props.label}
|
||||
{(tooltip || title) && tip}
|
||||
</AccessibleButton>
|
||||
);
|
||||
}
|
||||
const tip = hover && (title || tooltip) && (
|
||||
<Tooltip tooltipClassName={tooltipClassName} label={tooltip || title} alignment={alignment} />
|
||||
);
|
||||
return (
|
||||
<AccessibleButton
|
||||
{...props}
|
||||
onMouseOver={showTooltip}
|
||||
onMouseLeave={hideTooltip}
|
||||
onFocus={onFocus}
|
||||
onBlur={hideTooltip}
|
||||
aria-label={title || props["aria-label"]}
|
||||
>
|
||||
{children}
|
||||
{props.label}
|
||||
{(tooltip || title) && tip}
|
||||
</AccessibleButton>
|
||||
);
|
||||
}
|
||||
|
||||
export default AccessibleTooltipButton;
|
||||
|
|
|
@ -28,13 +28,14 @@ import {
|
|||
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
||||
import type { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
|
||||
import { Action } from "../../../dispatcher/actions";
|
||||
import type { ButtonEvent } from "../elements/AccessibleButton";
|
||||
import { AccessibleButtonKind, ButtonEvent } from "../elements/AccessibleButton";
|
||||
import MemberAvatar from "../avatars/MemberAvatar";
|
||||
import { LiveContentSummary, LiveContentType } from "../rooms/LiveContentSummary";
|
||||
import FacePile from "../elements/FacePile";
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
import { CallDuration, SessionDuration } from "../voip/CallDuration";
|
||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
||||
import { ContinueKind } from "../auth/InteractiveAuthEntryComponents";
|
||||
|
||||
const MAX_FACES = 8;
|
||||
|
||||
|
@ -43,7 +44,7 @@ interface ActiveCallEventProps {
|
|||
call: ElementCall | null;
|
||||
participatingMembers: RoomMember[];
|
||||
buttonText: string;
|
||||
buttonKind: string;
|
||||
buttonKind: AccessibleButtonKind;
|
||||
buttonDisabledTooltip?: string;
|
||||
onButtonClick: ((ev: ButtonEvent) => void) | null;
|
||||
}
|
||||
|
@ -125,7 +126,9 @@ const ActiveLoadedCallEvent = forwardRef<any, ActiveLoadedCallEventProps>(({ mxE
|
|||
[call],
|
||||
);
|
||||
|
||||
const [buttonText, buttonKind, onButtonClick] = useMemo(() => {
|
||||
const [buttonText, buttonKind, onButtonClick] = useMemo<
|
||||
[string, ContinueKind, null | ((ev: ButtonEvent) => void)]
|
||||
>(() => {
|
||||
switch (connectionState) {
|
||||
case ConnectionState.Disconnected:
|
||||
return [_t("action|join"), "primary", connect];
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { PropsWithChildren, useRef } from "react";
|
||||
import React, { PropsWithChildren } from "react";
|
||||
import { User } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import ReadReceiptMarker, { IReadReceiptInfo } from "./ReadReceiptMarker";
|
||||
|
@ -284,8 +284,7 @@ interface ISectionHeaderProps {
|
|||
}
|
||||
|
||||
function SectionHeader({ className, children }: PropsWithChildren<ISectionHeaderProps>): JSX.Element {
|
||||
const ref = useRef<HTMLHeadingElement>(null);
|
||||
const [onFocus] = useRovingTabIndex(ref);
|
||||
const [onFocus, , ref] = useRovingTabIndex<HTMLHeadingElement>();
|
||||
|
||||
return (
|
||||
<h3 className={className} role="menuitem" onFocus={onFocus} tabIndex={-1} ref={ref}>
|
||||
|
|
|
@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { createRef, RefObject } from "react";
|
||||
import React, { createRef } from "react";
|
||||
import { RoomMember } from "matrix-js-sdk/src/matrix";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
|
@ -73,7 +73,7 @@ interface IReadReceiptMarkerStyle {
|
|||
}
|
||||
|
||||
export default class ReadReceiptMarker extends React.PureComponent<IProps, IState> {
|
||||
private avatar: React.RefObject<HTMLDivElement | HTMLImageElement | HTMLSpanElement> = createRef();
|
||||
private avatar = createRef<HTMLDivElement>();
|
||||
|
||||
public constructor(props: IProps) {
|
||||
super(props);
|
||||
|
@ -199,7 +199,7 @@ export default class ReadReceiptMarker extends React.PureComponent<IProps, IStat
|
|||
|
||||
public render(): React.ReactNode {
|
||||
if (this.state.suppressDisplay) {
|
||||
return <div ref={this.avatar as RefObject<HTMLDivElement>} />;
|
||||
return <div ref={this.avatar} />;
|
||||
}
|
||||
|
||||
const style = {
|
||||
|
|
|
@ -20,7 +20,7 @@ import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
|||
|
||||
import Field from "../elements/Field";
|
||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
import AccessibleButton, { AccessibleButtonKind } from "../elements/AccessibleButton";
|
||||
import Spinner from "../elements/Spinner";
|
||||
import withValidation, { IFieldState, IValidationResult } from "../elements/Validation";
|
||||
import { UserFriendlyError, _t, _td } from "../../../languageHandler";
|
||||
|
@ -45,7 +45,7 @@ interface IProps {
|
|||
onError: (error: Error) => void;
|
||||
rowClassName?: string;
|
||||
buttonClassName?: string;
|
||||
buttonKind?: string;
|
||||
buttonKind?: AccessibleButtonKind;
|
||||
buttonLabel?: string;
|
||||
confirm?: boolean;
|
||||
// Whether to autoFocus the new password input
|
||||
|
|
Loading…
Reference in a new issue