Enable @typescript-eslint/explicit-function-return-type
in /src (#9788)
* Enable `@typescript-eslint/explicit-member-accessibility` on /src * Prettier * Enable `@typescript-eslint/explicit-function-return-type` in /src * Fix types * tsc strict fixes * Delint * Fix test * Fix bad merge
This commit is contained in:
parent
7a36ba0fde
commit
030b7e90bf
683 changed files with 3459 additions and 3013 deletions
|
@ -26,7 +26,7 @@ import RoomContext from "../../../contexts/RoomContext";
|
|||
|
||||
const MAX_PROVIDER_MATCHES = 20;
|
||||
|
||||
export const generateCompletionDomId = (number) => `mx_Autocomplete_Completion_${number}`;
|
||||
export const generateCompletionDomId = (n: number): string => `mx_Autocomplete_Completion_${n}`;
|
||||
|
||||
interface IProps {
|
||||
// the query string for which to show autocomplete suggestions
|
||||
|
@ -79,7 +79,7 @@ export default class Autocomplete extends React.PureComponent<IProps, IState> {
|
|||
};
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
this.autocompleter = new Autocompleter(this.props.room, this.context.timelineRenderingType);
|
||||
this.applyNewProps();
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ export default class Autocomplete extends React.PureComponent<IProps, IState> {
|
|||
this.complete(this.props.query, this.props.selection);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
this.autocompleter.destroy();
|
||||
}
|
||||
|
||||
|
@ -265,7 +265,7 @@ export default class Autocomplete extends React.PureComponent<IProps, IState> {
|
|||
}
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: IProps) {
|
||||
public componentDidUpdate(prevProps: IProps): void {
|
||||
this.applyNewProps(prevProps.query, prevProps.room);
|
||||
// this is the selected completion, so scroll it into view if needed
|
||||
const selectedCompletion = this.refs[`completion${this.state.selectionOffset}`] as HTMLElement;
|
||||
|
@ -280,7 +280,7 @@ export default class Autocomplete extends React.PureComponent<IProps, IState> {
|
|||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
let position = 1;
|
||||
const renderedCompletions = this.state.completions
|
||||
.map((completionResult, i) => {
|
||||
|
@ -290,7 +290,7 @@ export default class Autocomplete extends React.PureComponent<IProps, IState> {
|
|||
const componentPosition = position;
|
||||
position++;
|
||||
|
||||
const onClick = () => {
|
||||
const onClick = (): void => {
|
||||
this.onCompletionClicked(componentPosition);
|
||||
};
|
||||
|
||||
|
|
|
@ -63,24 +63,24 @@ export default class AuxPanel extends React.Component<IProps, IState> {
|
|||
};
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
const cli = MatrixClientPeg.get();
|
||||
if (SettingsStore.getValue("feature_state_counters")) {
|
||||
cli.on(RoomStateEvent.Events, this.onRoomStateEvents);
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
if (SettingsStore.getValue("feature_state_counters")) {
|
||||
MatrixClientPeg.get()?.removeListener(RoomStateEvent.Events, this.onRoomStateEvents);
|
||||
}
|
||||
}
|
||||
|
||||
public shouldComponentUpdate(nextProps, nextState) {
|
||||
public shouldComponentUpdate(nextProps, nextState): boolean {
|
||||
return objectHasDiff(this.props, nextProps) || objectHasDiff(this.state, nextState);
|
||||
}
|
||||
|
||||
private onRoomStateEvents = (ev: MatrixEvent) => {
|
||||
private onRoomStateEvents = (ev: MatrixEvent): void => {
|
||||
if (ev.getType() === "re.jki.counter") {
|
||||
this.updateCounters();
|
||||
}
|
||||
|
@ -94,8 +94,8 @@ export default class AuxPanel extends React.Component<IProps, IState> {
|
|||
{ leading: true, trailing: true },
|
||||
);
|
||||
|
||||
private computeCounters() {
|
||||
const counters = [];
|
||||
private computeCounters(): Counter[] {
|
||||
const counters: Counter[] = [];
|
||||
|
||||
if (this.props.room && SettingsStore.getValue("feature_state_counters")) {
|
||||
const stateEvs = this.props.room.currentState.getStateEvents("re.jki.counter");
|
||||
|
@ -125,7 +125,7 @@ export default class AuxPanel extends React.Component<IProps, IState> {
|
|||
return counters;
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const callView = (
|
||||
<LegacyCallViewForRoom
|
||||
roomId={this.props.room.roomId}
|
||||
|
|
|
@ -172,7 +172,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
);
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: IProps) {
|
||||
public componentDidUpdate(prevProps: IProps): void {
|
||||
// We need to re-check the placeholder when the enabled state changes because it causes the
|
||||
// placeholder element to remount, which gets rid of the `::before` class. Re-evaluating the
|
||||
// placeholder means we get a proper `::before` with the placeholder.
|
||||
|
@ -676,7 +676,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
this.setState({ showPillAvatar });
|
||||
};
|
||||
|
||||
private surroundWithSettingChanged = () => {
|
||||
private surroundWithSettingChanged = (): void => {
|
||||
const surroundWith = SettingsStore.getValue("MessageComposerInput.surroundWith");
|
||||
this.setState({ surroundWith });
|
||||
};
|
||||
|
@ -686,7 +686,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
if (shouldReplace) this.replaceEmoticon(documentPosition, REGEX_EMOTICON_WHITESPACE);
|
||||
};
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
document.removeEventListener("selectionchange", this.onSelectionChange);
|
||||
this.editorRef.current.removeEventListener("input", this.onInput, true);
|
||||
this.editorRef.current.removeEventListener("compositionstart", this.onCompositionStart, true);
|
||||
|
@ -697,7 +697,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
SettingsStore.unwatchSetting(this.surroundWithHandle);
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
const model = this.props.model;
|
||||
model.setUpdateCallback(this.updateEditorState);
|
||||
const partCreator = model.partCreator;
|
||||
|
@ -746,7 +746,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
formatRange(range, action);
|
||||
};
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
let autoComplete;
|
||||
if (this.state.autoComplete) {
|
||||
const query = this.state.query;
|
||||
|
|
|
@ -27,7 +27,13 @@ interface ICollapsibleButtonProps extends ComponentProps<typeof MenuItem> {
|
|||
iconClassName: string;
|
||||
}
|
||||
|
||||
export const CollapsibleButton = ({ title, children, className, iconClassName, ...props }: ICollapsibleButtonProps) => {
|
||||
export const CollapsibleButton: React.FC<ICollapsibleButtonProps> = ({
|
||||
title,
|
||||
children,
|
||||
className,
|
||||
iconClassName,
|
||||
...props
|
||||
}) => {
|
||||
const inOverflowMenu = !!useContext(OverflowMenuContext);
|
||||
if (inOverflowMenu) {
|
||||
return <IconizedContextMenuOption {...props} iconClassName={iconClassName} label={title} />;
|
||||
|
|
|
@ -88,8 +88,8 @@ const E2EIcon: React.FC<IProps> = ({
|
|||
style = { width: `${size}px`, height: `${size}px` };
|
||||
}
|
||||
|
||||
const onMouseOver = () => setHover(true);
|
||||
const onMouseLeave = () => setHover(false);
|
||||
const onMouseOver = (): void => setHover(true);
|
||||
const onMouseLeave = (): void => setHover(false);
|
||||
|
||||
let tip;
|
||||
if (hover && !hideTooltip) {
|
||||
|
|
|
@ -369,7 +369,7 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
|
|||
}
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
// store caret and serialized parts in the
|
||||
// editorstate so it can be restored when the remote echo event tile gets rendered
|
||||
// in case we're currently editing a pending event
|
||||
|
@ -427,7 +427,7 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
|
|||
});
|
||||
};
|
||||
|
||||
private onAction = (payload: ActionPayload) => {
|
||||
private onAction = (payload: ActionPayload): void => {
|
||||
if (!this.editorRef.current) return;
|
||||
|
||||
if (payload.action === Action.ComposerInsert) {
|
||||
|
@ -446,7 +446,7 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
|
|||
}
|
||||
};
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
return (
|
||||
<div className={classNames("mx_EditMessageComposer", this.props.className)} onKeyDown={this.onKeyDown}>
|
||||
<BasicMessageComposer
|
||||
|
|
|
@ -18,18 +18,18 @@ import classNames from "classnames";
|
|||
import React, { useContext } from "react";
|
||||
|
||||
import { _t } from "../../../languageHandler";
|
||||
import ContextMenu, { aboveLeftOf, AboveLeftOf, useContextMenu } from "../../structures/ContextMenu";
|
||||
import ContextMenu, { aboveLeftOf, MenuProps, useContextMenu } from "../../structures/ContextMenu";
|
||||
import EmojiPicker from "../emojipicker/EmojiPicker";
|
||||
import { CollapsibleButton } from "./CollapsibleButton";
|
||||
import { OverflowMenuContext } from "./MessageComposerButtons";
|
||||
|
||||
interface IEmojiButtonProps {
|
||||
addEmoji: (unicode: string) => boolean;
|
||||
menuPosition: AboveLeftOf;
|
||||
menuPosition: MenuProps;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function EmojiButton({ addEmoji, menuPosition, className }: IEmojiButtonProps) {
|
||||
export function EmojiButton({ addEmoji, menuPosition, className }: IEmojiButtonProps): JSX.Element {
|
||||
const overflowMenuCloser = useContext(OverflowMenuContext);
|
||||
const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu();
|
||||
|
||||
|
|
|
@ -103,7 +103,7 @@ export default class EntityTile extends React.PureComponent<IProps, IState> {
|
|||
};
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const mainClassNames = {
|
||||
mx_EntityTile: true,
|
||||
mx_EntityTile_noHover: this.props.suppressOnHover,
|
||||
|
|
|
@ -335,7 +335,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
return true;
|
||||
}
|
||||
|
||||
private get shouldShowSentReceipt() {
|
||||
private get shouldShowSentReceipt(): boolean {
|
||||
// If we're not even eligible, don't show the receipt.
|
||||
if (!this.isEligibleForSpecialReceipt) return false;
|
||||
|
||||
|
@ -355,7 +355,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
return true;
|
||||
}
|
||||
|
||||
private get shouldShowSendingReceipt() {
|
||||
private get shouldShowSendingReceipt(): boolean {
|
||||
// If we're not even eligible, don't show the receipt.
|
||||
if (!this.isEligibleForSpecialReceipt) return false;
|
||||
|
||||
|
@ -368,7 +368,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
return true;
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
this.suppressReadReceiptAnimation = false;
|
||||
const client = MatrixClientPeg.get();
|
||||
if (!this.props.forExport) {
|
||||
|
@ -435,7 +435,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
}
|
||||
};
|
||||
|
||||
private updateThread = (thread: Thread) => {
|
||||
private updateThread = (thread: Thread): void => {
|
||||
if (thread !== this.state.thread && !this.supportsThreadNotifications) {
|
||||
if (this.threadState) {
|
||||
this.threadState.off(NotificationStateEvents.Update, this.onThreadStateUpdate);
|
||||
|
@ -455,7 +455,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
return !this.propsEqual(this.props, nextProps);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
const client = MatrixClientPeg.get();
|
||||
if (client) {
|
||||
client.removeListener(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
|
||||
|
@ -476,7 +476,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
this.threadState?.off(NotificationStateEvents.Update, this.onThreadStateUpdate);
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: Readonly<EventTileProps>, prevState: Readonly<IState>) {
|
||||
public componentDidUpdate(prevProps: Readonly<EventTileProps>, prevState: Readonly<IState>): void {
|
||||
// If the verification state changed, the height might have changed
|
||||
if (prevState.verified !== this.state.verified && this.props.onHeightChanged) {
|
||||
this.props.onHeightChanged();
|
||||
|
@ -492,7 +492,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
}
|
||||
}
|
||||
|
||||
private onNewThread = (thread: Thread) => {
|
||||
private onNewThread = (thread: Thread): void => {
|
||||
if (thread.id === this.props.mxEvent.getId()) {
|
||||
this.updateThread(thread);
|
||||
const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
|
||||
|
@ -594,7 +594,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
|
||||
/** called when the event is decrypted after we show it.
|
||||
*/
|
||||
private onDecrypted = () => {
|
||||
private onDecrypted = (): void => {
|
||||
// we need to re-verify the sending device.
|
||||
this.verifyEvent();
|
||||
// decryption might, of course, trigger a height change, so call onHeightChanged after the re-render
|
||||
|
@ -614,7 +614,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
};
|
||||
|
||||
/** called when the event is edited after we show it. */
|
||||
private onReplaced = () => {
|
||||
private onReplaced = (): void => {
|
||||
// re-verify the event if it is replaced (the edit may not be verified)
|
||||
this.verifyEvent();
|
||||
};
|
||||
|
@ -735,7 +735,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
return actions.tweaks.highlight;
|
||||
}
|
||||
|
||||
private onSenderProfileClick = () => {
|
||||
private onSenderProfileClick = (): void => {
|
||||
dis.dispatch<ComposerInsertPayload>({
|
||||
action: Action.ComposerInsert,
|
||||
userId: this.props.mxEvent.getSender(),
|
||||
|
@ -743,7 +743,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
});
|
||||
};
|
||||
|
||||
private onPermalinkClicked = (e: MouseEvent) => {
|
||||
private onPermalinkClicked = (e: MouseEvent): void => {
|
||||
// This allows the permalink to be opened in a new tab/window or copied as
|
||||
// matrix.to, but also for it to enable routing within Element when clicked.
|
||||
e.preventDefault();
|
||||
|
@ -757,7 +757,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
});
|
||||
};
|
||||
|
||||
private renderE2EPadlock() {
|
||||
private renderE2EPadlock(): JSX.Element {
|
||||
// if the event was edited, show the verification info for the edit, not
|
||||
// the original
|
||||
const ev = this.props.mxEvent.replacingEvent() ?? this.props.mxEvent;
|
||||
|
@ -808,7 +808,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
return null;
|
||||
}
|
||||
|
||||
private onActionBarFocusChange = (actionBarFocused: boolean) => {
|
||||
private onActionBarFocusChange = (actionBarFocused: boolean): void => {
|
||||
this.setState({ actionBarFocused });
|
||||
};
|
||||
|
||||
|
@ -816,7 +816,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
|
||||
private getReplyChain = (): ReplyChain => this.replyChain.current;
|
||||
|
||||
private getReactions = () => {
|
||||
private getReactions = (): Relations => {
|
||||
if (!this.props.showReactions || !this.props.getRelationsForEvent) {
|
||||
return null;
|
||||
}
|
||||
|
@ -882,7 +882,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
});
|
||||
};
|
||||
|
||||
private setQuoteExpanded = (expanded: boolean) => {
|
||||
private setQuoteExpanded = (expanded: boolean): void => {
|
||||
this.setState({
|
||||
isQuoteExpanded: expanded,
|
||||
});
|
||||
|
@ -924,7 +924,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
);
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const msgtype = this.props.mxEvent.getContent().msgtype;
|
||||
const eventType = this.props.mxEvent.getType();
|
||||
const {
|
||||
|
@ -1476,19 +1476,19 @@ const SafeEventTile = forwardRef((props: EventTileProps, ref: RefObject<Unwrappe
|
|||
});
|
||||
export default SafeEventTile;
|
||||
|
||||
function E2ePadlockUnverified(props: Omit<IE2ePadlockProps, "title" | "icon">) {
|
||||
function E2ePadlockUnverified(props: Omit<IE2ePadlockProps, "title" | "icon">): JSX.Element {
|
||||
return <E2ePadlock title={_t("Encrypted by an unverified session")} icon={E2ePadlockIcon.Warning} {...props} />;
|
||||
}
|
||||
|
||||
function E2ePadlockUnencrypted(props: Omit<IE2ePadlockProps, "title" | "icon">) {
|
||||
function E2ePadlockUnencrypted(props: Omit<IE2ePadlockProps, "title" | "icon">): JSX.Element {
|
||||
return <E2ePadlock title={_t("Unencrypted")} icon={E2ePadlockIcon.Warning} {...props} />;
|
||||
}
|
||||
|
||||
function E2ePadlockUnknown(props: Omit<IE2ePadlockProps, "title" | "icon">) {
|
||||
function E2ePadlockUnknown(props: Omit<IE2ePadlockProps, "title" | "icon">): JSX.Element {
|
||||
return <E2ePadlock title={_t("Encrypted by a deleted session")} icon={E2ePadlockIcon.Normal} {...props} />;
|
||||
}
|
||||
|
||||
function E2ePadlockUnauthenticated(props: Omit<IE2ePadlockProps, "title" | "icon">) {
|
||||
function E2ePadlockUnauthenticated(props: Omit<IE2ePadlockProps, "title" | "icon">): JSX.Element {
|
||||
return (
|
||||
<E2ePadlock
|
||||
title={_t("The authenticity of this encrypted message can't be guaranteed on this device.")}
|
||||
|
@ -1498,7 +1498,7 @@ function E2ePadlockUnauthenticated(props: Omit<IE2ePadlockProps, "title" | "icon
|
|||
);
|
||||
}
|
||||
|
||||
function E2ePadlockDecryptionFailure(props: Omit<IE2ePadlockProps, "title" | "icon">) {
|
||||
function E2ePadlockDecryptionFailure(props: Omit<IE2ePadlockProps, "title" | "icon">): JSX.Element {
|
||||
return (
|
||||
<E2ePadlock
|
||||
title={_t("This message could not be decrypted")}
|
||||
|
@ -1559,7 +1559,7 @@ interface ISentReceiptProps {
|
|||
messageState: string; // TODO: Types for message sending state
|
||||
}
|
||||
|
||||
function SentReceipt({ messageState }: ISentReceiptProps) {
|
||||
function SentReceipt({ messageState }: ISentReceiptProps): JSX.Element {
|
||||
const isSent = !messageState || messageState === "sent";
|
||||
const isFailed = messageState === "not_sent";
|
||||
const receiptClasses = classNames({
|
||||
|
|
|
@ -29,7 +29,7 @@ export function EventTileThreadToolbar({
|
|||
}: {
|
||||
viewInRoom: (evt: ButtonEvent) => void;
|
||||
copyLinkToThread: (evt: ButtonEvent) => void;
|
||||
}) {
|
||||
}): JSX.Element {
|
||||
return (
|
||||
<Toolbar className="mx_MessageActionBar" aria-label={_t("Message Actions")} aria-live="off">
|
||||
<RovingAccessibleTooltipButton
|
||||
|
|
|
@ -44,11 +44,11 @@ export default class ExtraTile extends React.Component<IProps, IState> {
|
|||
};
|
||||
}
|
||||
|
||||
private onTileMouseEnter = () => {
|
||||
private onTileMouseEnter = (): void => {
|
||||
this.setState({ hover: true });
|
||||
};
|
||||
|
||||
private onTileMouseLeave = () => {
|
||||
private onTileMouseLeave = (): void => {
|
||||
this.setState({ hover: false });
|
||||
};
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ import EventTileBubble from "../messages/EventTileBubble";
|
|||
import RoomContext from "../../../contexts/RoomContext";
|
||||
import { _t } from "../../../languageHandler";
|
||||
|
||||
const HistoryTile = () => {
|
||||
const HistoryTile: React.FC = () => {
|
||||
const { room } = useContext(RoomContext);
|
||||
|
||||
const oldState = room.getLiveTimeline().getState(EventTimeline.BACKWARDS);
|
||||
|
|
|
@ -94,7 +94,7 @@ const LinkPreviewGroup: React.FC<IProps> = ({ links, mxEvent, onCancelClick, onH
|
|||
|
||||
const fetchPreviews = (cli: MatrixClient, links: string[], ts: number): Promise<[string, IPreviewUrlResponse][]> => {
|
||||
return Promise.all<[string, IPreviewUrlResponse] | void>(
|
||||
links.map(async (link) => {
|
||||
links.map(async (link): Promise<[string, IPreviewUrlResponse]> => {
|
||||
try {
|
||||
const preview = await cli.getUrlPreview(link, ts);
|
||||
if (preview && Object.keys(preview).length > 0) {
|
||||
|
|
|
@ -38,19 +38,19 @@ export default class LinkPreviewWidget extends React.Component<IProps> {
|
|||
private readonly description = createRef<HTMLDivElement>();
|
||||
private image = createRef<HTMLImageElement>();
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
if (this.description.current) {
|
||||
linkifyElement(this.description.current);
|
||||
}
|
||||
}
|
||||
|
||||
public componentDidUpdate() {
|
||||
public componentDidUpdate(): void {
|
||||
if (this.description.current) {
|
||||
linkifyElement(this.description.current);
|
||||
}
|
||||
}
|
||||
|
||||
private onImageClick = (ev) => {
|
||||
private onImageClick = (ev): void => {
|
||||
const p = this.props.preview;
|
||||
if (ev.button != 0 || ev.metaKey) return;
|
||||
ev.preventDefault();
|
||||
|
@ -83,7 +83,7 @@ export default class LinkPreviewWidget extends React.Component<IProps> {
|
|||
Modal.createDialog(ImageView, params, "mx_Dialog_lightbox", null, true);
|
||||
};
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const p = this.props.preview;
|
||||
if (!p || Object.keys(p).length === 0) {
|
||||
return <div />;
|
||||
|
|
|
@ -101,7 +101,7 @@ export default class MemberList extends React.Component<IProps, IState> {
|
|||
this.updateListNow(true);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
this.mounted = false;
|
||||
const cli = MatrixClientPeg.get();
|
||||
if (cli) {
|
||||
|
@ -321,7 +321,7 @@ export default class MemberList extends React.Component<IProps, IState> {
|
|||
}
|
||||
}
|
||||
|
||||
private makeMemberTiles(members: Array<RoomMember | MatrixEvent>) {
|
||||
private makeMemberTiles(members: Array<RoomMember | MatrixEvent>): JSX.Element[] {
|
||||
return members.map((m) => {
|
||||
if (m instanceof RoomMember) {
|
||||
// Is a Matrix invite
|
||||
|
@ -359,7 +359,7 @@ export default class MemberList extends React.Component<IProps, IState> {
|
|||
return this.state.filteredInvitedMembers.length + (this.getPending3PidInvites() || []).length;
|
||||
};
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
if (this.state.loading) {
|
||||
return (
|
||||
<BaseCard className="mx_MemberList" onClose={this.props.onClose}>
|
||||
|
|
|
@ -60,7 +60,7 @@ export default class MemberTile extends React.Component<IProps, IState> {
|
|||
};
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
const cli = MatrixClientPeg.get();
|
||||
|
||||
const { roomId } = this.props.member;
|
||||
|
@ -80,7 +80,7 @@ export default class MemberTile extends React.Component<IProps, IState> {
|
|||
}
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
const cli = MatrixClientPeg.get();
|
||||
|
||||
if (cli) {
|
||||
|
@ -183,7 +183,7 @@ export default class MemberTile extends React.Component<IProps, IState> {
|
|||
}).trim();
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const member = this.props.member;
|
||||
const name = this.getDisplayName();
|
||||
const presenceState = member.user ? member.user.presence : null;
|
||||
|
|
|
@ -31,7 +31,7 @@ import Stickerpicker from "./Stickerpicker";
|
|||
import { makeRoomPermalink, RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
|
||||
import E2EIcon from "./E2EIcon";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import { aboveLeftOf } from "../../structures/ContextMenu";
|
||||
import { aboveLeftOf, MenuProps } from "../../structures/ContextMenu";
|
||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
||||
import ReplyPreview from "./ReplyPreview";
|
||||
import { UPDATE_EVENT } from "../../../stores/AsyncStore";
|
||||
|
@ -68,7 +68,7 @@ interface ISendButtonProps {
|
|||
title?: string; // defaults to something generic
|
||||
}
|
||||
|
||||
function SendButton(props: ISendButtonProps) {
|
||||
function SendButton(props: ISendButtonProps): JSX.Element {
|
||||
return (
|
||||
<AccessibleTooltipButton
|
||||
className="mx_MessageComposer_sendMessage"
|
||||
|
@ -173,7 +173,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
|||
}
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
this.dispatcherRef = dis.register(this.onAction);
|
||||
this.waitForOwnMember();
|
||||
UIStore.instance.trackElementDimensions(`MessageComposer${this.instanceId}`, this.ref.current!);
|
||||
|
@ -181,7 +181,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
|||
this.updateRecordingState(); // grab any cached recordings
|
||||
}
|
||||
|
||||
private onResize = (type: UI_EVENTS, entry: ResizeObserverEntry) => {
|
||||
private onResize = (type: UI_EVENTS, entry: ResizeObserverEntry): void => {
|
||||
if (type === UI_EVENTS.Resize) {
|
||||
const { narrow } = this.context;
|
||||
this.setState({
|
||||
|
@ -191,7 +191,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
|||
}
|
||||
};
|
||||
|
||||
private onAction = (payload: ActionPayload) => {
|
||||
private onAction = (payload: ActionPayload): void => {
|
||||
switch (payload.action) {
|
||||
case "reply_to_event":
|
||||
if (payload.context === this.context.timelineRenderingType) {
|
||||
|
@ -239,7 +239,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
|||
}
|
||||
};
|
||||
|
||||
private waitForOwnMember() {
|
||||
private waitForOwnMember(): void {
|
||||
// If we have the member already, do that
|
||||
const me = this.props.room.getMember(MatrixClientPeg.get().getUserId());
|
||||
if (me) {
|
||||
|
@ -255,7 +255,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
|||
});
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
VoiceRecordingStore.instance.off(UPDATE_EVENT, this.onVoiceStoreUpdate);
|
||||
dis.unregister(this.dispatcherRef);
|
||||
UIStore.instance.stopTrackingElementDimensions(`MessageComposer${this.instanceId}`);
|
||||
|
@ -265,7 +265,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
|||
this.voiceRecording = null;
|
||||
}
|
||||
|
||||
private onTombstoneClick = (ev) => {
|
||||
private onTombstoneClick = (ev): void => {
|
||||
ev.preventDefault();
|
||||
|
||||
const replacementRoomId = this.context.tombstone.getContent()["replacement_room"];
|
||||
|
@ -292,7 +292,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
|||
});
|
||||
};
|
||||
|
||||
private renderPlaceholderText = () => {
|
||||
private renderPlaceholderText = (): string => {
|
||||
if (this.props.replyToEvent) {
|
||||
const replyingToThread = this.props.relation?.rel_type === THREAD_RELATION_TYPE.name;
|
||||
if (replyingToThread && this.props.e2eStatus) {
|
||||
|
@ -322,7 +322,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
|||
return true;
|
||||
};
|
||||
|
||||
private sendMessage = async () => {
|
||||
private sendMessage = async (): Promise<void> => {
|
||||
if (this.state.haveRecording && this.voiceRecordingButton.current) {
|
||||
// There shouldn't be any text message to send when a voice recording is active, so
|
||||
// just send out the voice recording.
|
||||
|
@ -346,20 +346,20 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
|||
}
|
||||
};
|
||||
|
||||
private onChange = (model: EditorModel) => {
|
||||
private onChange = (model: EditorModel): void => {
|
||||
this.setState({
|
||||
isComposerEmpty: model.isEmpty,
|
||||
});
|
||||
};
|
||||
|
||||
private onWysiwygChange = (content: string) => {
|
||||
private onWysiwygChange = (content: string): void => {
|
||||
this.setState({
|
||||
composerContent: content,
|
||||
isComposerEmpty: content?.length === 0,
|
||||
});
|
||||
};
|
||||
|
||||
private onRichTextToggle = async () => {
|
||||
private onRichTextToggle = async (): Promise<void> => {
|
||||
const { richToPlain, plainToRich } = await getConversionFunctions();
|
||||
|
||||
const { isRichTextEnabled, composerContent } = this.state;
|
||||
|
@ -374,11 +374,11 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
|||
});
|
||||
};
|
||||
|
||||
private onVoiceStoreUpdate = () => {
|
||||
private onVoiceStoreUpdate = (): void => {
|
||||
this.updateRecordingState();
|
||||
};
|
||||
|
||||
private updateRecordingState() {
|
||||
private updateRecordingState(): void {
|
||||
const voiceRecordingId = VoiceRecordingStore.getVoiceRecordingId(this.props.room, this.props.relation);
|
||||
this.voiceRecording = VoiceRecordingStore.instance.getActiveRecording(voiceRecordingId);
|
||||
if (this.voiceRecording) {
|
||||
|
@ -393,7 +393,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
|||
}
|
||||
}
|
||||
|
||||
private onRecordingStarted = () => {
|
||||
private onRecordingStarted = (): void => {
|
||||
// update the recording instance, just in case
|
||||
const voiceRecordingId = VoiceRecordingStore.getVoiceRecordingId(this.props.room, this.props.relation);
|
||||
this.voiceRecording = VoiceRecordingStore.instance.getActiveRecording(voiceRecordingId);
|
||||
|
@ -402,19 +402,19 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
|||
});
|
||||
};
|
||||
|
||||
private onRecordingEndingSoon = ({ secondsLeft }) => {
|
||||
private onRecordingEndingSoon = ({ secondsLeft }): void => {
|
||||
this.setState({ recordingTimeLeftSeconds: secondsLeft });
|
||||
window.setTimeout(() => this.setState({ recordingTimeLeftSeconds: null }), 3000);
|
||||
};
|
||||
|
||||
private setStickerPickerOpen = (isStickerPickerOpen: boolean) => {
|
||||
private setStickerPickerOpen = (isStickerPickerOpen: boolean): void => {
|
||||
this.setState({
|
||||
isStickerPickerOpen,
|
||||
isMenuOpen: false,
|
||||
});
|
||||
};
|
||||
|
||||
private toggleStickerPickerOpen = () => {
|
||||
private toggleStickerPickerOpen = (): void => {
|
||||
this.setStickerPickerOpen(!this.state.isStickerPickerOpen);
|
||||
};
|
||||
|
||||
|
@ -428,7 +428,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
|||
return this.state.showStickersButton && !isLocalRoom(this.props.room);
|
||||
}
|
||||
|
||||
private getMenuPosition() {
|
||||
private getMenuPosition(): MenuProps | undefined {
|
||||
if (this.ref.current) {
|
||||
const hasFormattingButtons = this.state.isWysiwygLabEnabled && this.state.isRichTextEnabled;
|
||||
const contentRect = this.ref.current.getBoundingClientRect();
|
||||
|
@ -461,7 +461,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
|||
}
|
||||
};
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const hasE2EIcon = Boolean(!this.state.isWysiwygLabEnabled && this.props.e2eStatus);
|
||||
const e2eIcon = hasE2EIcon && (
|
||||
<E2EIcon key="e2eIcon" status={this.props.e2eStatus} className="mx_MessageComposer_e2eIcon" />
|
||||
|
|
|
@ -25,7 +25,7 @@ import { THREAD_RELATION_TYPE } from "matrix-js-sdk/src/models/thread";
|
|||
import { _t } from "../../../languageHandler";
|
||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
||||
import { CollapsibleButton } from "./CollapsibleButton";
|
||||
import { AboveLeftOf } from "../../structures/ContextMenu";
|
||||
import { MenuProps } from "../../structures/ContextMenu";
|
||||
import dis from "../../../dispatcher/dispatcher";
|
||||
import ErrorDialog from "../dialogs/ErrorDialog";
|
||||
import LocationButton from "../location/LocationButton";
|
||||
|
@ -46,7 +46,7 @@ interface IProps {
|
|||
haveRecording: boolean;
|
||||
isMenuOpen: boolean;
|
||||
isStickerPickerOpen: boolean;
|
||||
menuPosition?: AboveLeftOf;
|
||||
menuPosition?: MenuProps;
|
||||
onRecordStartEndClick: () => void;
|
||||
relation?: IEventRelation;
|
||||
setStickerPickerOpen: (isStickerPickerOpen: boolean) => void;
|
||||
|
@ -181,7 +181,7 @@ const UploadButtonContextProvider: React.FC<IUploadButtonProps> = ({ roomId, rel
|
|||
const roomContext = useContext(RoomContext);
|
||||
const uploadInput = useRef<HTMLInputElement>();
|
||||
|
||||
const onUploadClick = () => {
|
||||
const onUploadClick = (): void => {
|
||||
if (cli.isGuest()) {
|
||||
dis.dispatch({ action: "require_registration" });
|
||||
return;
|
||||
|
@ -195,7 +195,7 @@ const UploadButtonContextProvider: React.FC<IUploadButtonProps> = ({ roomId, rel
|
|||
}
|
||||
});
|
||||
|
||||
const onUploadFileInputChange = (ev: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const onUploadFileInputChange = (ev: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
if (ev.target.files.length === 0) return;
|
||||
|
||||
// Take a copy, so we can safely reset the value of the form control
|
||||
|
@ -232,11 +232,11 @@ const UploadButtonContextProvider: React.FC<IUploadButtonProps> = ({ roomId, rel
|
|||
};
|
||||
|
||||
// Must be rendered within an UploadButtonContextProvider
|
||||
const UploadButton = () => {
|
||||
const UploadButton: React.FC = () => {
|
||||
const overflowMenuCloser = useContext(OverflowMenuContext);
|
||||
const uploadButtonFn = useContext(UploadButtonContext);
|
||||
|
||||
const onClick = () => {
|
||||
const onClick = (): void => {
|
||||
uploadButtonFn?.();
|
||||
overflowMenuCloser?.(); // close overflow menu
|
||||
};
|
||||
|
@ -302,7 +302,7 @@ class PollButton extends React.PureComponent<IPollButtonProps> {
|
|||
public static contextType = OverflowMenuContext;
|
||||
public context!: React.ContextType<typeof OverflowMenuContext>;
|
||||
|
||||
private onCreateClick = () => {
|
||||
private onCreateClick = (): void => {
|
||||
this.context?.(); // close overflow menu
|
||||
const canSend = this.props.room.currentState.maySendEvent(
|
||||
M_POLL_START.name,
|
||||
|
@ -330,7 +330,7 @@ class PollButton extends React.PureComponent<IPollButtonProps> {
|
|||
}
|
||||
};
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
// do not allow sending polls within threads at this time
|
||||
if (this.props.relation?.rel_type === THREAD_RELATION_TYPE.name) return null;
|
||||
|
||||
|
@ -369,7 +369,7 @@ interface WysiwygToggleButtonProps {
|
|||
onClick: MouseEventHandler<HTMLDivElement>;
|
||||
}
|
||||
|
||||
function ComposerModeButton({ isRichTextEnabled, onClick }: WysiwygToggleButtonProps) {
|
||||
function ComposerModeButton({ isRichTextEnabled, onClick }: WysiwygToggleButtonProps): JSX.Element {
|
||||
const title = isRichTextEnabled ? _t("Hide formatting") : _t("Show formatting");
|
||||
|
||||
return (
|
||||
|
|
|
@ -46,7 +46,7 @@ export default class MessageComposerFormatBar extends React.PureComponent<IProps
|
|||
this.state = { visible: false };
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const classes = classNames("mx_MessageComposerFormatBar", {
|
||||
mx_MessageComposerFormatBar_shown: this.state.visible,
|
||||
});
|
||||
|
@ -124,7 +124,7 @@ interface IFormatButtonProps {
|
|||
}
|
||||
|
||||
class FormatButton extends React.PureComponent<IFormatButtonProps> {
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const className = `mx_MessageComposerFormatBar_button mx_MessageComposerFormatBar_buttonIcon${this.props.icon}`;
|
||||
let shortcut;
|
||||
if (this.props.shortcut) {
|
||||
|
|
|
@ -24,7 +24,7 @@ import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
|||
import RoomContext from "../../../contexts/RoomContext";
|
||||
import DMRoomMap from "../../../utils/DMRoomMap";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
|
||||
import MiniAvatarUploader, { AVATAR_SIZE } from "../elements/MiniAvatarUploader";
|
||||
import RoomAvatar from "../avatars/RoomAvatar";
|
||||
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
||||
|
@ -46,7 +46,7 @@ function hasExpectedEncryptionSettings(matrixClient: MatrixClient, room: Room):
|
|||
return isPublic || !privateShouldBeEncrypted() || isEncrypted;
|
||||
}
|
||||
|
||||
const NewRoomIntro = () => {
|
||||
const NewRoomIntro: React.FC = () => {
|
||||
const cli = useContext(MatrixClientContext);
|
||||
const { room, roomId } = useContext(RoomContext);
|
||||
|
||||
|
@ -100,7 +100,7 @@ const NewRoomIntro = () => {
|
|||
const topic = room.currentState.getStateEvents(EventType.RoomTopic, "")?.getContent()?.topic;
|
||||
const canAddTopic = inRoom && room.currentState.maySendStateEvent(EventType.RoomTopic, cli.getUserId());
|
||||
|
||||
const onTopicClick = () => {
|
||||
const onTopicClick = (): void => {
|
||||
defaultDispatcher.dispatch(
|
||||
{
|
||||
action: "open_room_settings",
|
||||
|
@ -244,7 +244,7 @@ const NewRoomIntro = () => {
|
|||
);
|
||||
}
|
||||
|
||||
function openRoomSettings(event) {
|
||||
function openRoomSettings(event: ButtonEvent): void {
|
||||
event.preventDefault();
|
||||
defaultDispatcher.dispatch({
|
||||
action: "open_room_settings",
|
||||
|
|
|
@ -76,12 +76,12 @@ export default class NotificationBadge extends React.PureComponent<XOR<IProps, I
|
|||
return this.props.roomId || null;
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
SettingsStore.unwatchSetting(this.countWatcherRef);
|
||||
this.props.notification.off(NotificationStateEvents.Update, this.onNotificationUpdate);
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: Readonly<IProps>) {
|
||||
public componentDidUpdate(prevProps: Readonly<IProps>): void {
|
||||
if (prevProps.notification) {
|
||||
prevProps.notification.off(NotificationStateEvents.Update, this.onNotificationUpdate);
|
||||
}
|
||||
|
@ -89,22 +89,22 @@ export default class NotificationBadge extends React.PureComponent<XOR<IProps, I
|
|||
this.props.notification.on(NotificationStateEvents.Update, this.onNotificationUpdate);
|
||||
}
|
||||
|
||||
private countPreferenceChanged = () => {
|
||||
private countPreferenceChanged = (): void => {
|
||||
this.setState({ showCounts: SettingsStore.getValue("Notifications.alwaysShowBadgeCounts", this.roomId) });
|
||||
};
|
||||
|
||||
private onNotificationUpdate = () => {
|
||||
private onNotificationUpdate = (): void => {
|
||||
this.forceUpdate(); // notification state changed - update
|
||||
};
|
||||
|
||||
private onMouseOver = (e: MouseEvent) => {
|
||||
private onMouseOver = (e: MouseEvent): void => {
|
||||
e.stopPropagation();
|
||||
this.setState({
|
||||
showTooltip: true,
|
||||
});
|
||||
};
|
||||
|
||||
private onMouseLeave = () => {
|
||||
private onMouseLeave = (): void => {
|
||||
this.setState({
|
||||
showTooltip: false,
|
||||
});
|
||||
|
|
|
@ -33,7 +33,7 @@ interface Props {
|
|||
label?: string;
|
||||
}
|
||||
|
||||
export function StatelessNotificationBadge({ symbol, count, color, ...props }: Props) {
|
||||
export function StatelessNotificationBadge({ symbol, count, color, ...props }: Props): JSX.Element {
|
||||
const hideBold = useSettingValue("feature_hidebold");
|
||||
|
||||
// Don't show a badge if we don't need to
|
||||
|
|
|
@ -25,7 +25,7 @@ interface Props {
|
|||
threadId?: string;
|
||||
}
|
||||
|
||||
export function UnreadNotificationBadge({ room, threadId }: Props) {
|
||||
export function UnreadNotificationBadge({ room, threadId }: Props): JSX.Element {
|
||||
const { symbol, count, color } = useUnreadNotifications(room, threadId);
|
||||
|
||||
return <StatelessNotificationBadge symbol={symbol} count={count} color={color} />;
|
||||
|
|
|
@ -46,7 +46,7 @@ const AVATAR_SIZE = 24;
|
|||
export default class PinnedEventTile extends React.Component<IProps> {
|
||||
public static contextType = MatrixClientContext;
|
||||
|
||||
private onTileClicked = () => {
|
||||
private onTileClicked = (): void => {
|
||||
dis.dispatch<ViewRoomPayload>({
|
||||
action: Action.ViewRoom,
|
||||
event_id: this.props.event.getId(),
|
||||
|
@ -69,7 +69,7 @@ export default class PinnedEventTile extends React.Component<IProps> {
|
|||
}
|
||||
};
|
||||
|
||||
public async componentDidMount() {
|
||||
public async componentDidMount(): Promise<void> {
|
||||
// Fetch poll responses
|
||||
if (M_POLL_START.matches(this.props.event.getType())) {
|
||||
const eventId = this.props.event.getId();
|
||||
|
@ -79,7 +79,7 @@ export default class PinnedEventTile extends React.Component<IProps> {
|
|||
try {
|
||||
await Promise.all(
|
||||
[M_POLL_RESPONSE.name, M_POLL_RESPONSE.altName, M_POLL_END.name, M_POLL_END.altName].map(
|
||||
async (eventType) => {
|
||||
async (eventType): Promise<void> => {
|
||||
const relations = new Relations(RelationType.Reference, eventType, room);
|
||||
relations.setTargetEvent(this.props.event);
|
||||
|
||||
|
@ -110,7 +110,7 @@ export default class PinnedEventTile extends React.Component<IProps> {
|
|||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const sender = this.props.event.getSender();
|
||||
|
||||
let unpinButton = null;
|
||||
|
|
|
@ -82,7 +82,7 @@ export default class PresenceLabel extends React.Component<IProps> {
|
|||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
return (
|
||||
<div className="mx_PresenceLabel">
|
||||
{this.getPrettyPresence(this.props.presenceState, this.props.activeAgo, this.props.currentlyActive)}
|
||||
|
|
|
@ -89,7 +89,7 @@ export function ReadReceiptGroup({
|
|||
checkUnmounting,
|
||||
suppressAnimation,
|
||||
isTwelveHour,
|
||||
}: Props) {
|
||||
}: Props): JSX.Element {
|
||||
const [menuDisplayed, button, openMenu, closeMenu] = useContextMenu();
|
||||
|
||||
// If we are above MAX_READ_AVATARS, we’ll have to remove a few to have space for the +n count.
|
||||
|
@ -232,7 +232,13 @@ interface ReadReceiptPersonProps extends IReadReceiptProps {
|
|||
onAfterClick?: () => void;
|
||||
}
|
||||
|
||||
function ReadReceiptPerson({ userId, roomMember, ts, isTwelveHour, onAfterClick }: ReadReceiptPersonProps) {
|
||||
function ReadReceiptPerson({
|
||||
userId,
|
||||
roomMember,
|
||||
ts,
|
||||
isTwelveHour,
|
||||
onAfterClick,
|
||||
}: ReadReceiptPersonProps): JSX.Element {
|
||||
const [{ showTooltip, hideTooltip }, tooltip] = useTooltip({
|
||||
alignment: Alignment.Top,
|
||||
tooltipClassName: "mx_ReadReceiptGroup_person--tooltip",
|
||||
|
@ -288,7 +294,7 @@ interface ISectionHeaderProps {
|
|||
className?: string;
|
||||
}
|
||||
|
||||
function SectionHeader({ className, children }: PropsWithChildren<ISectionHeaderProps>) {
|
||||
function SectionHeader({ className, children }: PropsWithChildren<ISectionHeaderProps>): JSX.Element {
|
||||
const ref = useRef<HTMLHeadingElement>();
|
||||
const [onFocus] = useRovingTabIndex(ref);
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar";
|
|||
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
|
||||
import RoomAvatar from "../avatars/RoomAvatar";
|
||||
|
||||
const RecentlyViewedButton = () => {
|
||||
const RecentlyViewedButton: React.FC = () => {
|
||||
const tooltipRef = useRef<InteractiveTooltip>();
|
||||
const crumbs = useEventEmitterState(BreadcrumbsStore.instance, UPDATE_EVENT, () => BreadcrumbsStore.instance.rooms);
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ import ReplyTile from "./ReplyTile";
|
|||
import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
|
||||
function cancelQuoting(context: TimelineRenderingType) {
|
||||
function cancelQuoting(context: TimelineRenderingType): void {
|
||||
dis.dispatch({
|
||||
action: "reply_to_event",
|
||||
event: null,
|
||||
|
|
|
@ -52,13 +52,13 @@ export default class ReplyTile extends React.PureComponent<IProps> {
|
|||
onHeightChanged: () => {},
|
||||
};
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
this.props.mxEvent.on(MatrixEventEvent.Decrypted, this.onDecrypted);
|
||||
this.props.mxEvent.on(MatrixEventEvent.BeforeRedaction, this.onEventRequiresUpdate);
|
||||
this.props.mxEvent.on(MatrixEventEvent.Replaced, this.onEventRequiresUpdate);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
this.props.mxEvent.removeListener(MatrixEventEvent.Decrypted, this.onDecrypted);
|
||||
this.props.mxEvent.removeListener(MatrixEventEvent.BeforeRedaction, this.onEventRequiresUpdate);
|
||||
this.props.mxEvent.removeListener(MatrixEventEvent.Replaced, this.onEventRequiresUpdate);
|
||||
|
@ -104,7 +104,7 @@ export default class ReplyTile extends React.PureComponent<IProps> {
|
|||
}
|
||||
};
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const mxEvent = this.props.mxEvent;
|
||||
const msgType = mxEvent.getContent().msgtype;
|
||||
const evType = mxEvent.getType();
|
||||
|
|
|
@ -43,7 +43,7 @@ interface IState {
|
|||
skipFirst: boolean;
|
||||
}
|
||||
|
||||
const RoomBreadcrumbTile = ({ room, onClick }: { room: Room; onClick: (ev: ButtonEvent) => void }) => {
|
||||
const RoomBreadcrumbTile: React.FC<{ room: Room; onClick: (ev: ButtonEvent) => void }> = ({ room, onClick }) => {
|
||||
const [onFocus, isActive, ref] = useRovingTabIndex();
|
||||
|
||||
return (
|
||||
|
@ -82,12 +82,12 @@ export default class RoomBreadcrumbs extends React.PureComponent<IProps, IState>
|
|||
BreadcrumbsStore.instance.on(UPDATE_EVENT, this.onBreadcrumbsUpdate);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
this.isMounted = false;
|
||||
BreadcrumbsStore.instance.off(UPDATE_EVENT, this.onBreadcrumbsUpdate);
|
||||
}
|
||||
|
||||
private onBreadcrumbsUpdate = () => {
|
||||
private onBreadcrumbsUpdate = (): void => {
|
||||
if (!this.isMounted) return;
|
||||
|
||||
// We need to trick the CSSTransition component into updating, which means we need to
|
||||
|
@ -101,7 +101,7 @@ export default class RoomBreadcrumbs extends React.PureComponent<IProps, IState>
|
|||
window.setTimeout(() => this.setState({ doAnimation: true, skipFirst: false }), 0);
|
||||
};
|
||||
|
||||
private viewRoom = (room: Room, index: number, viaKeyboard = false) => {
|
||||
private viewRoom = (room: Room, index: number, viaKeyboard = false): void => {
|
||||
defaultDispatcher.dispatch<ViewRoomPayload>({
|
||||
action: Action.ViewRoom,
|
||||
room_id: room.roomId,
|
||||
|
|
|
@ -24,7 +24,7 @@ type Props<T extends keyof ReactHTML> = HTMLAttributes<T> & {
|
|||
room: Room;
|
||||
};
|
||||
|
||||
export function RoomContextDetails<T extends keyof ReactHTML>({ room, component, ...other }: Props<T>) {
|
||||
export function RoomContextDetails<T extends keyof ReactHTML>({ room, component, ...other }: Props<T>): JSX.Element {
|
||||
const contextDetails = roomContextDetails(room);
|
||||
if (contextDetails) {
|
||||
return React.createElement(
|
||||
|
|
|
@ -96,7 +96,7 @@ const VoiceCallButton: FC<VoiceCallButtonProps> = ({ room, busy, setBusy, behavi
|
|||
} else {
|
||||
// behavior === "legacy_or_jitsi"
|
||||
return {
|
||||
onClick: async (ev: ButtonEvent) => {
|
||||
onClick: async (ev: ButtonEvent): Promise<void> => {
|
||||
ev.preventDefault();
|
||||
setBusy(true);
|
||||
await LegacyCallHandler.instance.placeCall(room.roomId, CallType.Voice);
|
||||
|
@ -134,7 +134,7 @@ interface VideoCallButtonProps {
|
|||
const VideoCallButton: FC<VideoCallButtonProps> = ({ room, busy, setBusy, behavior }) => {
|
||||
const [menuOpen, buttonRef, openMenu, closeMenu] = useContextMenu();
|
||||
|
||||
const startLegacyCall = useCallback(async () => {
|
||||
const startLegacyCall = useCallback(async (): Promise<void> => {
|
||||
setBusy(true);
|
||||
await LegacyCallHandler.instance.placeCall(room.roomId, CallType.Video);
|
||||
setBusy(false);
|
||||
|
@ -160,7 +160,7 @@ const VideoCallButton: FC<VideoCallButtonProps> = ({ room, busy, setBusy, behavi
|
|||
};
|
||||
} else if (behavior === "legacy_or_jitsi") {
|
||||
return {
|
||||
onClick: async (ev: ButtonEvent) => {
|
||||
onClick: async (ev: ButtonEvent): Promise<void> => {
|
||||
ev.preventDefault();
|
||||
await startLegacyCall();
|
||||
},
|
||||
|
@ -168,7 +168,7 @@ const VideoCallButton: FC<VideoCallButtonProps> = ({ room, busy, setBusy, behavi
|
|||
};
|
||||
} else if (behavior === "element") {
|
||||
return {
|
||||
onClick: async (ev: ButtonEvent) => {
|
||||
onClick: async (ev: ButtonEvent): Promise<void> => {
|
||||
ev.preventDefault();
|
||||
startElementCall();
|
||||
},
|
||||
|
@ -177,7 +177,7 @@ const VideoCallButton: FC<VideoCallButtonProps> = ({ room, busy, setBusy, behavi
|
|||
} else {
|
||||
// behavior === "jitsi_or_element"
|
||||
return {
|
||||
onClick: async (ev: ButtonEvent) => {
|
||||
onClick: async (ev: ButtonEvent): Promise<void> => {
|
||||
ev.preventDefault();
|
||||
openMenu();
|
||||
},
|
||||
|
@ -187,7 +187,7 @@ const VideoCallButton: FC<VideoCallButtonProps> = ({ room, busy, setBusy, behavi
|
|||
}, [behavior, startLegacyCall, startElementCall, openMenu]);
|
||||
|
||||
const onJitsiClick = useCallback(
|
||||
async (ev: ButtonEvent) => {
|
||||
async (ev: ButtonEvent): Promise<void> => {
|
||||
ev.preventDefault();
|
||||
closeMenu();
|
||||
await startLegacyCall();
|
||||
|
@ -503,23 +503,23 @@ export default class RoomHeader extends React.Component<IProps, IState> {
|
|||
};
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
this.client.on(RoomStateEvent.Events, this.onRoomStateEvents);
|
||||
RightPanelStore.instance.on(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
this.client.removeListener(RoomStateEvent.Events, this.onRoomStateEvents);
|
||||
const notiStore = RoomNotificationStateStore.instance.getRoomState(this.props.room);
|
||||
notiStore.removeListener(NotificationStateEvents.Update, this.onNotificationUpdate);
|
||||
RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
||||
}
|
||||
|
||||
private onRightPanelStoreUpdate = () => {
|
||||
private onRightPanelStoreUpdate = (): void => {
|
||||
this.setState({ rightPanelOpen: RightPanelStore.instance.isOpen });
|
||||
};
|
||||
|
||||
private onRoomStateEvents = (event: MatrixEvent) => {
|
||||
private onRoomStateEvents = (event: MatrixEvent): void => {
|
||||
if (!this.props.room || event.getRoomId() !== this.props.room.roomId) {
|
||||
return;
|
||||
}
|
||||
|
@ -528,7 +528,7 @@ export default class RoomHeader extends React.Component<IProps, IState> {
|
|||
this.rateLimitedUpdate();
|
||||
};
|
||||
|
||||
private onNotificationUpdate = () => {
|
||||
private onNotificationUpdate = (): void => {
|
||||
this.forceUpdate();
|
||||
};
|
||||
|
||||
|
@ -540,18 +540,18 @@ export default class RoomHeader extends React.Component<IProps, IState> {
|
|||
{ leading: true, trailing: true },
|
||||
);
|
||||
|
||||
private onContextMenuOpenClick = (ev: ButtonEvent) => {
|
||||
private onContextMenuOpenClick = (ev: ButtonEvent): void => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
const target = ev.target as HTMLButtonElement;
|
||||
this.setState({ contextMenuPosition: target.getBoundingClientRect() });
|
||||
};
|
||||
|
||||
private onContextMenuCloseClick = () => {
|
||||
private onContextMenuCloseClick = (): void => {
|
||||
this.setState({ contextMenuPosition: undefined });
|
||||
};
|
||||
|
||||
private onHideCallClick = (ev: ButtonEvent) => {
|
||||
private onHideCallClick = (ev: ButtonEvent): void => {
|
||||
ev.preventDefault();
|
||||
defaultDispatcher.dispatch<ViewRoomPayload>({
|
||||
action: Action.ViewRoom,
|
||||
|
@ -659,7 +659,7 @@ export default class RoomHeader extends React.Component<IProps, IState> {
|
|||
);
|
||||
}
|
||||
|
||||
private renderName(oobName: string) {
|
||||
private renderName(oobName: string): JSX.Element {
|
||||
let contextMenu: JSX.Element | null = null;
|
||||
if (this.state.contextMenuPosition && this.props.room) {
|
||||
contextMenu = (
|
||||
|
@ -716,7 +716,7 @@ export default class RoomHeader extends React.Component<IProps, IState> {
|
|||
return <div className="mx_RoomHeader_name mx_RoomHeader_name--textonly">{roomName}</div>;
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const isVideoRoom = SettingsStore.getValue("feature_video_rooms") && calcIsVideoRoom(this.props.room);
|
||||
|
||||
let roomAvatar: JSX.Element | null = null;
|
||||
|
@ -788,7 +788,7 @@ export default class RoomHeader extends React.Component<IProps, IState> {
|
|||
|
||||
const topicElement = <RoomTopic room={this.props.room} className="mx_RoomHeader_topic" />;
|
||||
|
||||
const viewLabs = () =>
|
||||
const viewLabs = (): void =>
|
||||
defaultDispatcher.dispatch({
|
||||
action: Action.ViewUserSettings,
|
||||
initialTabId: UserTab.Labs,
|
||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||
import React, { FC } from "react";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
import { JoinRule } from "matrix-js-sdk/src/@types/partials";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
|
||||
import { _t } from "../../../languageHandler";
|
||||
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
||||
|
@ -33,7 +34,7 @@ interface IProps {
|
|||
|
||||
const RoomInfoLine: FC<IProps> = ({ room }) => {
|
||||
// summary will begin as undefined whilst loading and go null if it fails to load or we are not invited.
|
||||
const summary = useAsyncMemo(async () => {
|
||||
const summary = useAsyncMemo(async (): Promise<Awaited<ReturnType<MatrixClient["getRoomSummary"]>> | null> => {
|
||||
if (room.getMyMembership() !== "invite") return null;
|
||||
try {
|
||||
return room.client.getRoomSummary(room.roomId);
|
||||
|
@ -71,7 +72,7 @@ const RoomInfoLine: FC<IProps> = ({ room }) => {
|
|||
);
|
||||
} else if (memberCount && summary !== undefined) {
|
||||
// summary is not still loading
|
||||
const viewMembers = () =>
|
||||
const viewMembers = (): void =>
|
||||
RightPanelStore.instance.setCard({
|
||||
phase: room.isSpaceRoom() ? RightPanelPhases.SpaceMemberList : RightPanelPhases.RoomMemberList,
|
||||
});
|
||||
|
|
|
@ -51,7 +51,7 @@ import { arrayFastClone, arrayHasDiff } from "../../../utils/arrays";
|
|||
import { objectShallowClone, objectWithOnly } from "../../../utils/objects";
|
||||
import ResizeNotifier from "../../../utils/ResizeNotifier";
|
||||
import { shouldShowSpaceInvite, showAddExistingRooms, showCreateNewRoom, showSpaceInvite } from "../../../utils/space";
|
||||
import { ChevronFace, ContextMenuTooltipButton, useContextMenu } from "../../structures/ContextMenu";
|
||||
import { ChevronFace, ContextMenuTooltipButton, MenuProps, useContextMenu } from "../../structures/ContextMenu";
|
||||
import RoomAvatar from "../avatars/RoomAvatar";
|
||||
import { BetaPill } from "../beta/BetaCard";
|
||||
import IconizedContextMenu, {
|
||||
|
@ -107,7 +107,7 @@ interface ITagAestheticsMap {
|
|||
[tagId: TagID]: ITagAesthetics;
|
||||
}
|
||||
|
||||
const auxButtonContextMenuPosition = (handle: RefObject<HTMLDivElement>) => {
|
||||
const auxButtonContextMenuPosition = (handle: RefObject<HTMLDivElement>): MenuProps => {
|
||||
const rect = handle.current.getBoundingClientRect();
|
||||
return {
|
||||
chevronFace: ChevronFace.None,
|
||||
|
@ -116,7 +116,7 @@ const auxButtonContextMenuPosition = (handle: RefObject<HTMLDivElement>) => {
|
|||
};
|
||||
};
|
||||
|
||||
const DmAuxButton = ({ tabIndex, dispatcher = defaultDispatcher }: IAuxButtonProps) => {
|
||||
const DmAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex, dispatcher = defaultDispatcher }) => {
|
||||
const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<HTMLDivElement>();
|
||||
const activeSpace: Room = useEventEmitterState(SpaceStore.instance, UPDATE_SELECTED_SPACE, () => {
|
||||
return SpaceStore.instance.activeSpaceRoom;
|
||||
|
@ -207,7 +207,7 @@ const DmAuxButton = ({ tabIndex, dispatcher = defaultDispatcher }: IAuxButtonPro
|
|||
return null;
|
||||
};
|
||||
|
||||
const UntaggedAuxButton = ({ tabIndex }: IAuxButtonProps) => {
|
||||
const UntaggedAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex }) => {
|
||||
const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<HTMLDivElement>();
|
||||
const activeSpace = useEventEmitterState<Room>(SpaceStore.instance, UPDATE_SELECTED_SPACE, () => {
|
||||
return SpaceStore.instance.activeSpaceRoom;
|
||||
|
@ -466,7 +466,7 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
|
|||
this.updateLists(); // trigger the first update
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
SpaceStore.instance.off(UPDATE_SUGGESTED_ROOMS, this.updateSuggestedRooms);
|
||||
RoomListStore.instance.off(LISTS_UPDATE_EVENT, this.updateLists);
|
||||
SettingsStore.unwatchSetting(this.favouriteMessageWatcher);
|
||||
|
@ -474,13 +474,13 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
|
|||
SdkContextClass.instance.roomViewStore.off(UPDATE_EVENT, this.onRoomViewStoreUpdate);
|
||||
}
|
||||
|
||||
private onRoomViewStoreUpdate = () => {
|
||||
private onRoomViewStoreUpdate = (): void => {
|
||||
this.setState({
|
||||
currentRoomId: SdkContextClass.instance.roomViewStore.getRoomId(),
|
||||
});
|
||||
};
|
||||
|
||||
private onAction = (payload: ActionPayload) => {
|
||||
private onAction = (payload: ActionPayload): void => {
|
||||
if (payload.action === Action.ViewRoomDelta) {
|
||||
const viewRoomDeltaPayload = payload as ViewRoomDeltaPayload;
|
||||
const currentRoomId = SdkContextClass.instance.roomViewStore.getRoomId();
|
||||
|
@ -499,7 +499,7 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
|
|||
}
|
||||
};
|
||||
|
||||
private getRoomDelta = (roomId: string, delta: number, unread = false) => {
|
||||
private getRoomDelta = (roomId: string, delta: number, unread = false): Room => {
|
||||
const lists = RoomListStore.instance.orderedLists;
|
||||
const rooms: Room[] = [];
|
||||
TAG_ORDER.forEach((t) => {
|
||||
|
@ -522,11 +522,11 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
|
|||
return room;
|
||||
};
|
||||
|
||||
private updateSuggestedRooms = (suggestedRooms: ISuggestedRoom[]) => {
|
||||
private updateSuggestedRooms = (suggestedRooms: ISuggestedRoom[]): void => {
|
||||
this.setState({ suggestedRooms });
|
||||
};
|
||||
|
||||
private updateLists = () => {
|
||||
private updateLists = (): void => {
|
||||
const newLists = RoomListStore.instance.orderedLists;
|
||||
const previousListIds = Object.keys(this.state.sublists);
|
||||
const newListIds = Object.keys(newLists);
|
||||
|
@ -573,7 +573,7 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
|
|||
resizeMethod="crop"
|
||||
/>
|
||||
);
|
||||
const viewRoom = (ev) => {
|
||||
const viewRoom = (ev): void => {
|
||||
defaultDispatcher.dispatch<ViewRoomPayload>({
|
||||
action: Action.ViewRoom,
|
||||
room_alias: room.canonical_alias || room.aliases?.[0],
|
||||
|
@ -688,7 +688,7 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
|
|||
[...treeItems].find((e) => e.offsetParent !== null)?.focus();
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const sublists = this.renderSublists();
|
||||
return (
|
||||
<RovingTabIndexProvider handleHomeEnd handleUpDown onKeyDown={this.props.onKeyDown}>
|
||||
|
|
|
@ -45,7 +45,7 @@ import {
|
|||
showCreateNewSubspace,
|
||||
showSpaceInvite,
|
||||
} from "../../../utils/space";
|
||||
import { ChevronFace, ContextMenuTooltipButton, useContextMenu } from "../../structures/ContextMenu";
|
||||
import { ChevronFace, ContextMenuTooltipButton, useContextMenu, MenuProps } from "../../structures/ContextMenu";
|
||||
import { BetaPill } from "../beta/BetaCard";
|
||||
import IconizedContextMenu, {
|
||||
IconizedContextMenuOption,
|
||||
|
@ -56,7 +56,7 @@ import InlineSpinner from "../elements/InlineSpinner";
|
|||
import TooltipTarget from "../elements/TooltipTarget";
|
||||
import { HomeButtonContextMenu } from "../spaces/SpacePanel";
|
||||
|
||||
const contextMenuBelow = (elementRect: DOMRect) => {
|
||||
const contextMenuBelow = (elementRect: DOMRect): MenuProps => {
|
||||
// align the context menu's icons with the icon which opened the context menu
|
||||
const left = elementRect.left + window.scrollX;
|
||||
const top = elementRect.bottom + window.scrollY + 12;
|
||||
|
@ -74,12 +74,12 @@ const usePendingActions = (): Map<PendingActionType, Set<string>> => {
|
|||
const cli = useContext(MatrixClientContext);
|
||||
const [actions, setActions] = useState(new Map<PendingActionType, Set<string>>());
|
||||
|
||||
const addAction = (type: PendingActionType, key: string) => {
|
||||
const addAction = (type: PendingActionType, key: string): void => {
|
||||
const keys = new Set(actions.get(type));
|
||||
keys.add(key);
|
||||
setActions(new Map(actions).set(type, keys));
|
||||
};
|
||||
const removeAction = (type: PendingActionType, key: string) => {
|
||||
const removeAction = (type: PendingActionType, key: string): void => {
|
||||
const keys = new Set(actions.get(type));
|
||||
if (keys.delete(key)) {
|
||||
setActions(new Map(actions).set(type, keys));
|
||||
|
@ -112,7 +112,7 @@ interface IProps {
|
|||
onVisibilityChange?(): void;
|
||||
}
|
||||
|
||||
const RoomListHeader = ({ onVisibilityChange }: IProps) => {
|
||||
const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
|
||||
const cli = useContext(MatrixClientContext);
|
||||
const [mainMenuDisplayed, mainMenuHandle, openMainMenu, closeMainMenu] = useContextMenu<HTMLDivElement>();
|
||||
const [plusMenuDisplayed, plusMenuHandle, openPlusMenu, closePlusMenu] = useContextMenu<HTMLDivElement>();
|
||||
|
|
|
@ -112,17 +112,17 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
|
|||
};
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
this.checkInvitedEmail();
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps, prevState) {
|
||||
public componentDidUpdate(prevProps, prevState): void {
|
||||
if (this.props.invitedEmail !== prevProps.invitedEmail || this.props.inviterName !== prevProps.inviterName) {
|
||||
this.checkInvitedEmail();
|
||||
}
|
||||
}
|
||||
|
||||
private async checkInvitedEmail() {
|
||||
private async checkInvitedEmail(): Promise<void> {
|
||||
// If this is an invite and we've been told what email address was
|
||||
// invited, fetch the user's account emails and discovery bindings so we
|
||||
// can check them against the email that was invited.
|
||||
|
@ -262,15 +262,15 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
|
|||
};
|
||||
}
|
||||
|
||||
private onLoginClick = () => {
|
||||
private onLoginClick = (): void => {
|
||||
dis.dispatch({ action: "start_login", screenAfterLogin: this.makeScreenAfterLogin() });
|
||||
};
|
||||
|
||||
private onRegisterClick = () => {
|
||||
private onRegisterClick = (): void => {
|
||||
dis.dispatch({ action: "start_registration", screenAfterLogin: this.makeScreenAfterLogin() });
|
||||
};
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const brand = SdkConfig.get().brand;
|
||||
const roomName = this.props.room?.name ?? this.props.roomAlias ?? "";
|
||||
const isSpace = this.props.room?.isSpaceRoom() ?? this.props.oobData?.roomType === RoomType.Space;
|
||||
|
|
|
@ -66,7 +66,7 @@ const RoomPreviewCard: FC<IProps> = ({ room, onJoinButtonClicked, onRejectButton
|
|||
const cannotJoin =
|
||||
getEffectiveMembership(myMembership) === EffectiveMembership.Leave && joinRule !== JoinRule.Public;
|
||||
|
||||
const viewLabs = () =>
|
||||
const viewLabs = (): void =>
|
||||
defaultDispatcher.dispatch({
|
||||
action: Action.ViewUserSettings,
|
||||
initialTabId: UserTab.Labs,
|
||||
|
|
|
@ -134,13 +134,13 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
this.state = Object.assign(this.state, { height: this.calculateInitialHeight() });
|
||||
}
|
||||
|
||||
private calculateInitialHeight() {
|
||||
private calculateInitialHeight(): number {
|
||||
const requestedVisibleTiles = Math.max(Math.floor(this.layout.visibleTiles), this.layout.minVisibleTiles);
|
||||
const tileCount = Math.min(this.numTiles, requestedVisibleTiles);
|
||||
return this.layout.tilesToPixelsWithPadding(tileCount, this.padding);
|
||||
}
|
||||
|
||||
private get padding() {
|
||||
private get padding(): number {
|
||||
let padding = RESIZE_HANDLE_HEIGHT;
|
||||
// this is used for calculating the max height of the whole container,
|
||||
// and takes into account whether there should be room reserved for the show more/less button
|
||||
|
@ -170,7 +170,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
return RoomSublist.calcNumTiles(this.state.rooms, this.extraTiles);
|
||||
}
|
||||
|
||||
private static calcNumTiles(rooms: Room[], extraTiles: any[]) {
|
||||
private static calcNumTiles(rooms: Room[], extraTiles: any[]): number {
|
||||
return (rooms || []).length + (extraTiles || []).length;
|
||||
}
|
||||
|
||||
|
@ -182,7 +182,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
return Math.min(nVisible, this.numTiles);
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: Readonly<IProps>, prevState: Readonly<IState>) {
|
||||
public componentDidUpdate(prevProps: Readonly<IProps>, prevState: Readonly<IState>): void {
|
||||
const prevExtraTiles = prevProps.extraTiles;
|
||||
// as the rooms can come in one by one we need to reevaluate
|
||||
// the amount of available rooms to cap the amount of requested visible rooms by the layout
|
||||
|
@ -247,7 +247,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
return false;
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
this.dispatcherRef = defaultDispatcher.register(this.onAction);
|
||||
RoomListStore.instance.on(LISTS_UPDATE_EVENT, this.onListsUpdated);
|
||||
RoomListStore.instance.on(LISTS_LOADING_EVENT, this.onListsLoading);
|
||||
|
@ -257,14 +257,14 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
this.tilesRef.current?.addEventListener("scroll", this.onScrollPrevent, { passive: true });
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
defaultDispatcher.unregister(this.dispatcherRef);
|
||||
RoomListStore.instance.off(LISTS_UPDATE_EVENT, this.onListsUpdated);
|
||||
RoomListStore.instance.off(LISTS_LOADING_EVENT, this.onListsLoading);
|
||||
this.tilesRef.current?.removeEventListener("scroll", this.onScrollPrevent);
|
||||
}
|
||||
|
||||
private onListsLoading = (tagId: TagID, isLoading: boolean) => {
|
||||
private onListsLoading = (tagId: TagID, isLoading: boolean): void => {
|
||||
if (this.props.tagId !== tagId) {
|
||||
return;
|
||||
}
|
||||
|
@ -273,7 +273,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
});
|
||||
};
|
||||
|
||||
private onListsUpdated = () => {
|
||||
private onListsUpdated = (): void => {
|
||||
const stateUpdates = {} as IState;
|
||||
|
||||
const currentRooms = this.state.rooms;
|
||||
|
@ -287,7 +287,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
}
|
||||
};
|
||||
|
||||
private onAction = (payload: ActionPayload) => {
|
||||
private onAction = (payload: ActionPayload): void => {
|
||||
if (payload.action === Action.ViewRoom && payload.show_room_tile && this.state.rooms) {
|
||||
// XXX: we have to do this a tick later because we have incorrect intermediate props during a room change
|
||||
// where we lose the room we are changing from temporarily and then it comes back in an update right after.
|
||||
|
@ -306,7 +306,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
}
|
||||
};
|
||||
|
||||
private applyHeightChange(newHeight: number) {
|
||||
private applyHeightChange(newHeight: number): void {
|
||||
const heightInTiles = Math.ceil(this.layout.pixelsToTiles(newHeight - this.padding));
|
||||
this.layout.visibleTiles = Math.min(this.numTiles, heightInTiles);
|
||||
}
|
||||
|
@ -316,13 +316,13 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
travelDirection: Direction,
|
||||
refToElement: HTMLDivElement,
|
||||
delta: ResizeDelta,
|
||||
) => {
|
||||
): void => {
|
||||
const newHeight = this.heightAtStart + delta.height;
|
||||
this.applyHeightChange(newHeight);
|
||||
this.setState({ height: newHeight });
|
||||
};
|
||||
|
||||
private onResizeStart = () => {
|
||||
private onResizeStart = (): void => {
|
||||
this.heightAtStart = this.state.height;
|
||||
this.setState({ isResizing: true });
|
||||
};
|
||||
|
@ -332,13 +332,13 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
travelDirection: Direction,
|
||||
refToElement: HTMLDivElement,
|
||||
delta: ResizeDelta,
|
||||
) => {
|
||||
): void => {
|
||||
const newHeight = this.heightAtStart + delta.height;
|
||||
this.applyHeightChange(newHeight);
|
||||
this.setState({ isResizing: false, height: newHeight });
|
||||
};
|
||||
|
||||
private onShowAllClick = async () => {
|
||||
private onShowAllClick = async (): Promise<void> => {
|
||||
if (this.slidingSyncMode) {
|
||||
const slidingSyncIndex = SlidingSyncManager.instance.getOrAllocateListIndex(this.props.tagId);
|
||||
const count = RoomListStore.instance.getCount(this.props.tagId);
|
||||
|
@ -356,13 +356,13 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
});
|
||||
};
|
||||
|
||||
private onShowLessClick = () => {
|
||||
private onShowLessClick = (): void => {
|
||||
const newHeight = this.layout.tilesToPixelsWithPadding(this.layout.defaultVisibleTiles, this.padding);
|
||||
this.applyHeightChange(newHeight);
|
||||
this.setState({ height: newHeight });
|
||||
};
|
||||
|
||||
private focusRoomTile = (index: number) => {
|
||||
private focusRoomTile = (index: number): void => {
|
||||
if (!this.sublistRef.current) return;
|
||||
const elements = this.sublistRef.current.querySelectorAll<HTMLDivElement>(".mx_RoomTile");
|
||||
const element = elements && elements[index];
|
||||
|
@ -371,14 +371,14 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
}
|
||||
};
|
||||
|
||||
private onOpenMenuClick = (ev: React.MouseEvent) => {
|
||||
private onOpenMenuClick = (ev: React.MouseEvent): void => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
const target = ev.target as HTMLButtonElement;
|
||||
this.setState({ contextMenuPosition: target.getBoundingClientRect() });
|
||||
};
|
||||
|
||||
private onContextMenu = (ev: React.MouseEvent) => {
|
||||
private onContextMenu = (ev: React.MouseEvent): void => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
this.setState({
|
||||
|
@ -390,28 +390,28 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
});
|
||||
};
|
||||
|
||||
private onCloseMenu = () => {
|
||||
private onCloseMenu = (): void => {
|
||||
this.setState({ contextMenuPosition: null });
|
||||
};
|
||||
|
||||
private onUnreadFirstChanged = () => {
|
||||
private onUnreadFirstChanged = (): void => {
|
||||
const isUnreadFirst = RoomListStore.instance.getListOrder(this.props.tagId) === ListAlgorithm.Importance;
|
||||
const newAlgorithm = isUnreadFirst ? ListAlgorithm.Natural : ListAlgorithm.Importance;
|
||||
RoomListStore.instance.setListOrder(this.props.tagId, newAlgorithm);
|
||||
this.forceUpdate(); // because if the sublist doesn't have any changes then we will miss the list order change
|
||||
};
|
||||
|
||||
private onTagSortChanged = async (sort: SortAlgorithm) => {
|
||||
private onTagSortChanged = async (sort: SortAlgorithm): Promise<void> => {
|
||||
RoomListStore.instance.setTagSorting(this.props.tagId, sort);
|
||||
this.forceUpdate();
|
||||
};
|
||||
|
||||
private onMessagePreviewChanged = () => {
|
||||
private onMessagePreviewChanged = (): void => {
|
||||
this.layout.showPreviews = !this.layout.showPreviews;
|
||||
this.forceUpdate(); // because the layout doesn't trigger a re-render
|
||||
};
|
||||
|
||||
private onBadgeClick = (ev: React.MouseEvent) => {
|
||||
private onBadgeClick = (ev: React.MouseEvent): void => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
|
||||
|
@ -438,7 +438,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
}
|
||||
};
|
||||
|
||||
private onHeaderClick = () => {
|
||||
private onHeaderClick = (): void => {
|
||||
const possibleSticky = this.headerButton.current.parentElement;
|
||||
const sublist = possibleSticky.parentElement.parentElement;
|
||||
const list = sublist.parentElement.parentElement;
|
||||
|
@ -465,7 +465,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
}
|
||||
};
|
||||
|
||||
private toggleCollapsed = () => {
|
||||
private toggleCollapsed = (): void => {
|
||||
if (this.props.forceExpanded) return;
|
||||
this.layout.isCollapsed = this.state.isExpanded;
|
||||
this.setState({ isExpanded: !this.layout.isCollapsed });
|
||||
|
@ -474,7 +474,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
}
|
||||
};
|
||||
|
||||
private onHeaderKeyDown = (ev: React.KeyboardEvent) => {
|
||||
private onHeaderKeyDown = (ev: React.KeyboardEvent): void => {
|
||||
const action = getKeyBindingsManager().getRoomListAction(ev);
|
||||
switch (action) {
|
||||
case KeyBindingAction.CollapseRoomListSection:
|
||||
|
@ -501,7 +501,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
}
|
||||
};
|
||||
|
||||
private onKeyDown = (ev: React.KeyboardEvent) => {
|
||||
private onKeyDown = (ev: React.KeyboardEvent): void => {
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(ev);
|
||||
switch (action) {
|
||||
// On ArrowLeft go to the sublist header
|
||||
|
@ -733,7 +733,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
|||
);
|
||||
}
|
||||
|
||||
private onScrollPrevent(e: Event) {
|
||||
private onScrollPrevent(e: Event): void {
|
||||
// the RoomTile calls scrollIntoView and the browser may scroll a div we do not wish to be scrollable
|
||||
// this fixes https://github.com/vector-im/element-web/issues/14413
|
||||
(e.target as HTMLDivElement).scrollTop = 0;
|
||||
|
|
|
@ -25,7 +25,7 @@ import AccessibleButton, { ButtonEvent } from "../../views/elements/AccessibleBu
|
|||
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
||||
import { Action } from "../../../dispatcher/actions";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import { ChevronFace, ContextMenuTooltipButton } from "../../structures/ContextMenu";
|
||||
import { ChevronFace, ContextMenuTooltipButton, MenuProps } from "../../structures/ContextMenu";
|
||||
import { DefaultTagID, TagID } from "../../../stores/room-list/models";
|
||||
import { MessagePreviewStore } from "../../../stores/room-list/MessagePreviewStore";
|
||||
import DecoratedRoomAvatar from "../avatars/DecoratedRoomAvatar";
|
||||
|
@ -71,9 +71,9 @@ interface State {
|
|||
messagePreview?: string;
|
||||
}
|
||||
|
||||
const messagePreviewId = (roomId: string) => `mx_RoomTile_messagePreview_${roomId}`;
|
||||
const messagePreviewId = (roomId: string): string => `mx_RoomTile_messagePreview_${roomId}`;
|
||||
|
||||
export const contextMenuBelow = (elementRect: PartialDOMRect) => {
|
||||
export const contextMenuBelow = (elementRect: PartialDOMRect): MenuProps => {
|
||||
// align the context menu's icons with the icon which opened the context menu
|
||||
const left = elementRect.left + window.scrollX - 9;
|
||||
const top = elementRect.bottom + window.scrollY + 17;
|
||||
|
@ -104,15 +104,15 @@ export class RoomTile extends React.PureComponent<ClassProps, State> {
|
|||
this.roomProps = EchoChamber.forRoom(this.props.room);
|
||||
}
|
||||
|
||||
private onRoomNameUpdate = (room: Room) => {
|
||||
private onRoomNameUpdate = (room: Room): void => {
|
||||
this.forceUpdate();
|
||||
};
|
||||
|
||||
private onNotificationUpdate = () => {
|
||||
private onNotificationUpdate = (): void => {
|
||||
this.forceUpdate(); // notification state changed - update
|
||||
};
|
||||
|
||||
private onRoomPropertyUpdate = (property: CachedRoomKey) => {
|
||||
private onRoomPropertyUpdate = (property: CachedRoomKey): void => {
|
||||
if (property === CachedRoomKey.NotificationVolume) this.onNotificationUpdate();
|
||||
// else ignore - not important for this tile
|
||||
};
|
||||
|
@ -125,7 +125,7 @@ export class RoomTile extends React.PureComponent<ClassProps, State> {
|
|||
return !this.props.isMinimized && this.props.showMessagePreview;
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: Readonly<Props>, prevState: Readonly<State>) {
|
||||
public componentDidUpdate(prevProps: Readonly<Props>, prevState: Readonly<State>): void {
|
||||
const showMessageChanged = prevProps.showMessagePreview !== this.props.showMessagePreview;
|
||||
const minimizedChanged = prevProps.isMinimized !== this.props.isMinimized;
|
||||
if (showMessageChanged || minimizedChanged) {
|
||||
|
@ -145,7 +145,7 @@ export class RoomTile extends React.PureComponent<ClassProps, State> {
|
|||
}
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
// when we're first rendered (or our sublist is expanded) make sure we are visible if we're active
|
||||
if (this.state.selected) {
|
||||
this.scrollIntoView();
|
||||
|
@ -167,7 +167,7 @@ export class RoomTile extends React.PureComponent<ClassProps, State> {
|
|||
this.setState({ call: CallStore.instance.getCall(this.props.room.roomId) });
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
SdkContextClass.instance.roomViewStore.removeRoomListener(this.props.room.roomId, this.onActiveRoomUpdate);
|
||||
MessagePreviewStore.instance.off(
|
||||
MessagePreviewStore.getPreviewChangedEventName(this.props.room),
|
||||
|
@ -180,7 +180,7 @@ export class RoomTile extends React.PureComponent<ClassProps, State> {
|
|||
CallStore.instance.off(CallStoreEvent.Call, this.onCallChanged);
|
||||
}
|
||||
|
||||
private onAction = (payload: ActionPayload) => {
|
||||
private onAction = (payload: ActionPayload): void => {
|
||||
if (
|
||||
payload.action === Action.ViewRoom &&
|
||||
payload.room_id === this.props.room.roomId &&
|
||||
|
@ -192,17 +192,17 @@ export class RoomTile extends React.PureComponent<ClassProps, State> {
|
|||
}
|
||||
};
|
||||
|
||||
private onRoomPreviewChanged = (room: Room) => {
|
||||
private onRoomPreviewChanged = (room: Room): void => {
|
||||
if (this.props.room && room.roomId === this.props.room.roomId) {
|
||||
this.generatePreview();
|
||||
}
|
||||
};
|
||||
|
||||
private onCallChanged = (call: Call, roomId: string) => {
|
||||
private onCallChanged = (call: Call, roomId: string): void => {
|
||||
if (roomId === this.props.room?.roomId) this.setState({ call });
|
||||
};
|
||||
|
||||
private async generatePreview() {
|
||||
private async generatePreview(): Promise<void> {
|
||||
if (!this.showMessagePreview) {
|
||||
return null;
|
||||
}
|
||||
|
@ -211,7 +211,7 @@ export class RoomTile extends React.PureComponent<ClassProps, State> {
|
|||
this.setState({ messagePreview });
|
||||
}
|
||||
|
||||
private scrollIntoView = () => {
|
||||
private scrollIntoView = (): void => {
|
||||
if (!this.roomTileRef.current) return;
|
||||
this.roomTileRef.current.scrollIntoView({
|
||||
block: "nearest",
|
||||
|
@ -219,7 +219,7 @@ export class RoomTile extends React.PureComponent<ClassProps, State> {
|
|||
});
|
||||
};
|
||||
|
||||
private onTileClick = async (ev: React.KeyboardEvent) => {
|
||||
private onTileClick = async (ev: React.KeyboardEvent): Promise<void> => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
|
||||
|
@ -238,11 +238,11 @@ export class RoomTile extends React.PureComponent<ClassProps, State> {
|
|||
});
|
||||
};
|
||||
|
||||
private onActiveRoomUpdate = (isActive: boolean) => {
|
||||
private onActiveRoomUpdate = (isActive: boolean): void => {
|
||||
this.setState({ selected: isActive });
|
||||
};
|
||||
|
||||
private onNotificationsMenuOpenClick = (ev: ButtonEvent) => {
|
||||
private onNotificationsMenuOpenClick = (ev: ButtonEvent): void => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
const target = ev.target as HTMLButtonElement;
|
||||
|
@ -251,18 +251,18 @@ export class RoomTile extends React.PureComponent<ClassProps, State> {
|
|||
PosthogTrackers.trackInteraction("WebRoomListRoomTileNotificationsMenu", ev);
|
||||
};
|
||||
|
||||
private onCloseNotificationsMenu = () => {
|
||||
private onCloseNotificationsMenu = (): void => {
|
||||
this.setState({ notificationsMenuPosition: null });
|
||||
};
|
||||
|
||||
private onGeneralMenuOpenClick = (ev: ButtonEvent) => {
|
||||
private onGeneralMenuOpenClick = (ev: ButtonEvent): void => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
const target = ev.target as HTMLButtonElement;
|
||||
this.setState({ generalMenuPosition: target.getBoundingClientRect() });
|
||||
};
|
||||
|
||||
private onContextMenu = (ev: React.MouseEvent) => {
|
||||
private onContextMenu = (ev: React.MouseEvent): void => {
|
||||
// If we don't have a context menu to show, ignore the action.
|
||||
if (!this.showContextMenu) return;
|
||||
|
||||
|
@ -276,7 +276,7 @@ export class RoomTile extends React.PureComponent<ClassProps, State> {
|
|||
});
|
||||
};
|
||||
|
||||
private onCloseGeneralMenu = () => {
|
||||
private onCloseGeneralMenu = (): void => {
|
||||
this.setState({ generalMenuPosition: null });
|
||||
};
|
||||
|
||||
|
|
|
@ -51,15 +51,15 @@ export default class SearchBar extends React.Component<IProps, IState> {
|
|||
};
|
||||
}
|
||||
|
||||
private onThisRoomClick = () => {
|
||||
private onThisRoomClick = (): void => {
|
||||
this.setState({ scope: SearchScope.Room }, () => this.searchIfQuery());
|
||||
};
|
||||
|
||||
private onAllRoomsClick = () => {
|
||||
private onAllRoomsClick = (): void => {
|
||||
this.setState({ scope: SearchScope.All }, () => this.searchIfQuery());
|
||||
};
|
||||
|
||||
private onSearchChange = (e: React.KeyboardEvent) => {
|
||||
private onSearchChange = (e: React.KeyboardEvent): void => {
|
||||
const action = getKeyBindingsManager().getAccessibilityAction(e);
|
||||
switch (action) {
|
||||
case KeyBindingAction.Enter:
|
||||
|
@ -82,7 +82,7 @@ export default class SearchBar extends React.Component<IProps, IState> {
|
|||
this.props.onSearch(this.searchTerm.current.value, this.state.scope);
|
||||
};
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const searchButtonClasses = classNames("mx_SearchBar_searchButton", {
|
||||
mx_SearchBar_searching: this.props.searchInProgress,
|
||||
});
|
||||
|
|
|
@ -58,7 +58,7 @@ export default class SearchResultTile extends React.Component<IProps> {
|
|||
this.callEventGroupers = buildLegacyCallEventGroupers(this.callEventGroupers, events);
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const timeline = this.props.timeline;
|
||||
const resultEvent = timeline[this.props.ourEventsIndexes[0]];
|
||||
const eventId = resultEvent.getId();
|
||||
|
|
|
@ -462,13 +462,13 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
|
|||
}
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
dis.unregister(this.dispatcherRef);
|
||||
window.removeEventListener("beforeunload", this.saveStoredEditorState);
|
||||
this.saveStoredEditorState();
|
||||
}
|
||||
|
||||
private get editorStateKey() {
|
||||
private get editorStateKey(): string {
|
||||
let key = `mx_cider_state_${this.props.room.roomId}`;
|
||||
if (this.props.relation?.rel_type === THREAD_RELATION_TYPE.name) {
|
||||
key += `_${this.props.relation.event_id}`;
|
||||
|
@ -572,7 +572,7 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
|
|||
this.editorRef.current?.focus();
|
||||
};
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
const threadId =
|
||||
this.props.relation?.rel_type === THREAD_RELATION_TYPE.name ? this.props.relation.event_id : null;
|
||||
return (
|
||||
|
|
|
@ -213,7 +213,7 @@ export default class Stickerpicker extends React.PureComponent<IProps, IState> {
|
|||
}
|
||||
};
|
||||
|
||||
private onRightPanelStoreUpdate = () => {
|
||||
private onRightPanelStoreUpdate = (): void => {
|
||||
this.props.setStickerPickerOpen(false);
|
||||
};
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ export default class ThirdPartyMemberInfo extends React.Component<IProps, IState
|
|||
}
|
||||
}
|
||||
|
||||
public onRoomStateEvents = (ev: MatrixEvent) => {
|
||||
public onRoomStateEvents = (ev: MatrixEvent): void => {
|
||||
if (ev.getType() === EventType.RoomThirdPartyInvite && ev.getStateKey() === this.state.stateKey) {
|
||||
const newDisplayName = ev.getContent().display_name;
|
||||
const isInvited = isValid3pidInvite(ev);
|
||||
|
@ -91,14 +91,14 @@ export default class ThirdPartyMemberInfo extends React.Component<IProps, IState
|
|||
}
|
||||
};
|
||||
|
||||
public onCancel = () => {
|
||||
public onCancel = (): void => {
|
||||
dis.dispatch({
|
||||
action: "view_3pid_invite",
|
||||
event: null,
|
||||
});
|
||||
};
|
||||
|
||||
public onKickClick = () => {
|
||||
public onKickClick = (): void => {
|
||||
MatrixClientPeg.get()
|
||||
.sendStateEvent(this.state.roomId, "m.room.third_party_invite", {}, this.state.stateKey)
|
||||
.catch((err) => {
|
||||
|
@ -120,7 +120,7 @@ export default class ThirdPartyMemberInfo extends React.Component<IProps, IState
|
|||
this.setState({ invited: false });
|
||||
};
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
let adminTools = null;
|
||||
if (this.state.canKick && this.state.invited) {
|
||||
adminTools = (
|
||||
|
|
|
@ -37,7 +37,7 @@ interface IProps {
|
|||
thread: Thread;
|
||||
}
|
||||
|
||||
const ThreadSummary = ({ mxEvent, thread, ...props }: IProps) => {
|
||||
const ThreadSummary: React.FC<IProps> = ({ mxEvent, thread, ...props }) => {
|
||||
const roomContext = useContext(RoomContext);
|
||||
const cardContext = useContext(CardContext);
|
||||
const count = useTypedEventEmitterState(thread, ThreadEvent.Update, () => thread.length);
|
||||
|
@ -74,7 +74,7 @@ interface IPreviewProps {
|
|||
showDisplayname?: boolean;
|
||||
}
|
||||
|
||||
export const ThreadMessagePreview = ({ thread, showDisplayname = false }: IPreviewProps) => {
|
||||
export const ThreadMessagePreview: React.FC<IPreviewProps> = ({ thread, showDisplayname = false }) => {
|
||||
const cli = useContext(MatrixClientContext);
|
||||
|
||||
const lastReply = useTypedEventEmitterState(thread, ThreadEvent.Update, () => thread.replyToEvent);
|
||||
|
@ -88,7 +88,7 @@ export const ThreadMessagePreview = ({ thread, showDisplayname = false }: IPrevi
|
|||
setContent(lastReply.getContent());
|
||||
});
|
||||
|
||||
const preview = useAsyncMemo(async () => {
|
||||
const preview = useAsyncMemo(async (): Promise<string> => {
|
||||
if (!lastReply) return;
|
||||
await cli.decryptEventIfNeeded(lastReply);
|
||||
return MessagePreviewStore.instance.generatePreviewForEvent(lastReply);
|
||||
|
|
|
@ -77,7 +77,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
|
|||
this.voiceRecordingId = VoiceRecordingStore.getVoiceRecordingId(this.props.room, this.props.relation);
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
const recorder = VoiceRecordingStore.instance.getActiveRecording(this.voiceRecordingId);
|
||||
if (recorder) {
|
||||
if (recorder.isRecording || !recorder.hasRecording) {
|
||||
|
@ -88,7 +88,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
|
|||
}
|
||||
}
|
||||
|
||||
public async componentWillUnmount() {
|
||||
public async componentWillUnmount(): Promise<void> {
|
||||
// Stop recording, but keep the recording memory (don't dispose it). This is to let the user
|
||||
// come back and finish working with it.
|
||||
const recording = VoiceRecordingStore.instance.getActiveRecording(this.voiceRecordingId);
|
||||
|
@ -99,7 +99,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
|
|||
}
|
||||
|
||||
// called by composer
|
||||
public async send() {
|
||||
public async send(): Promise<void> {
|
||||
if (!this.state.recorder) {
|
||||
throw new Error("No recording started - cannot send anything");
|
||||
}
|
||||
|
@ -159,25 +159,25 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
|
|||
await this.disposeRecording();
|
||||
}
|
||||
|
||||
private async disposeRecording() {
|
||||
private async disposeRecording(): Promise<void> {
|
||||
await VoiceRecordingStore.instance.disposeRecording(this.voiceRecordingId);
|
||||
|
||||
// Reset back to no recording, which means no phase (ie: restart component entirely)
|
||||
this.setState({ recorder: null, recordingPhase: null, didUploadFail: false });
|
||||
}
|
||||
|
||||
private onCancel = async () => {
|
||||
private onCancel = async (): Promise<void> => {
|
||||
await this.disposeRecording();
|
||||
};
|
||||
|
||||
public onRecordStartEndClick = async () => {
|
||||
public onRecordStartEndClick = async (): Promise<void> => {
|
||||
if (this.state.recorder) {
|
||||
await this.state.recorder.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
// The "microphone access error" dialogs are used a lot, so let's functionify them
|
||||
const accessError = () => {
|
||||
const accessError = (): void => {
|
||||
Modal.createDialog(ErrorDialog, {
|
||||
title: _t("Unable to access your microphone"),
|
||||
description: (
|
||||
|
@ -236,7 +236,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
|
|||
}
|
||||
};
|
||||
|
||||
private bindNewRecorder(recorder: Optional<VoiceMessageRecording>) {
|
||||
private bindNewRecorder(recorder: Optional<VoiceMessageRecording>): void {
|
||||
if (this.state.recorder) {
|
||||
this.state.recorder.off(UPDATE_EVENT, this.onRecordingUpdate);
|
||||
}
|
||||
|
@ -245,7 +245,7 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
|
|||
}
|
||||
}
|
||||
|
||||
private onRecordingUpdate = (ev: RecordingState) => {
|
||||
private onRecordingUpdate = (ev: RecordingState): void => {
|
||||
if (ev === RecordingState.EndingSoon) return; // ignore this state: it has no UI purpose here
|
||||
this.setState({ recordingPhase: ev });
|
||||
};
|
||||
|
|
|
@ -56,12 +56,12 @@ export default class WhoIsTypingTile extends React.Component<IProps, IState> {
|
|||
delayedStopTypingTimers: {},
|
||||
};
|
||||
|
||||
public componentDidMount() {
|
||||
public componentDidMount(): void {
|
||||
MatrixClientPeg.get().on(RoomMemberEvent.Typing, this.onRoomMemberTyping);
|
||||
MatrixClientPeg.get().on(RoomEvent.Timeline, this.onRoomTimeline);
|
||||
}
|
||||
|
||||
public componentDidUpdate(_, prevState) {
|
||||
public componentDidUpdate(_, prevState): void {
|
||||
const wasVisible = WhoIsTypingTile.isVisible(prevState);
|
||||
const isVisible = WhoIsTypingTile.isVisible(this.state);
|
||||
if (this.props.onShown && !wasVisible && isVisible) {
|
||||
|
@ -71,7 +71,7 @@ export default class WhoIsTypingTile extends React.Component<IProps, IState> {
|
|||
}
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
public componentWillUnmount(): void {
|
||||
// we may have entirely lost our client as we're logging out before clicking login on the guest bar...
|
||||
const client = MatrixClientPeg.get();
|
||||
if (client) {
|
||||
|
@ -199,7 +199,7 @@ export default class WhoIsTypingTile extends React.Component<IProps, IState> {
|
|||
return avatars;
|
||||
}
|
||||
|
||||
public render() {
|
||||
public render(): JSX.Element {
|
||||
let usersTyping = this.state.usersTyping;
|
||||
const stoppedUsersOnTimer = Object.keys(this.state.delayedStopTypingTimers).map((userId) =>
|
||||
this.props.room.getMember(userId),
|
||||
|
|
|
@ -31,6 +31,6 @@ export interface ComposerContextState {
|
|||
export const ComposerContext = createContext<ComposerContextState>(getDefaultContextValue());
|
||||
ComposerContext.displayName = "ComposerContext";
|
||||
|
||||
export function useComposerContext() {
|
||||
export function useComposerContext(): ComposerContextState {
|
||||
return useContext(ComposerContext);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import React, { ComponentProps, lazy, Suspense } from "react";
|
||||
import { ISendEventResponse } from "matrix-js-sdk/src/@types/requests";
|
||||
|
||||
// we need to import the types for TS, but do not import the sendMessage
|
||||
// function to avoid importing from "@matrix-org/matrix-wysiwyg"
|
||||
|
@ -23,19 +24,26 @@ import { SendMessageParams } from "./utils/message";
|
|||
const SendComposer = lazy(() => import("./SendWysiwygComposer"));
|
||||
const EditComposer = lazy(() => import("./EditWysiwygComposer"));
|
||||
|
||||
export const dynamicImportSendMessage = async (message: string, isHTML: boolean, params: SendMessageParams) => {
|
||||
export const dynamicImportSendMessage = async (
|
||||
message: string,
|
||||
isHTML: boolean,
|
||||
params: SendMessageParams,
|
||||
): Promise<ISendEventResponse> => {
|
||||
const { sendMessage } = await import("./utils/message");
|
||||
|
||||
return sendMessage(message, isHTML, params);
|
||||
};
|
||||
|
||||
export const dynamicImportConversionFunctions = async () => {
|
||||
export const dynamicImportConversionFunctions = async (): Promise<{
|
||||
richToPlain(rich: string): Promise<string>;
|
||||
plainToRich(plain: string): Promise<string>;
|
||||
}> => {
|
||||
const { richToPlain, plainToRich } = await import("@matrix-org/matrix-wysiwyg");
|
||||
|
||||
return { richToPlain, plainToRich };
|
||||
};
|
||||
|
||||
export function DynamicImportSendWysiwygComposer(props: ComponentProps<typeof SendComposer>) {
|
||||
export function DynamicImportSendWysiwygComposer(props: ComponentProps<typeof SendComposer>): JSX.Element {
|
||||
return (
|
||||
<Suspense fallback={<div />}>
|
||||
<SendComposer {...props} />
|
||||
|
@ -43,7 +51,7 @@ export function DynamicImportSendWysiwygComposer(props: ComponentProps<typeof Se
|
|||
);
|
||||
}
|
||||
|
||||
export function DynamicImportEditWysiwygComposer(props: ComponentProps<typeof EditComposer>) {
|
||||
export function DynamicImportEditWysiwygComposer(props: ComponentProps<typeof EditComposer>): JSX.Element {
|
||||
return (
|
||||
<Suspense fallback={<div />}>
|
||||
<EditComposer {...props} />
|
||||
|
|
|
@ -47,7 +47,11 @@ interface EditWysiwygComposerProps {
|
|||
}
|
||||
|
||||
// Default needed for React.lazy
|
||||
export default function EditWysiwygComposer({ editorStateTransfer, className, ...props }: EditWysiwygComposerProps) {
|
||||
export default function EditWysiwygComposer({
|
||||
editorStateTransfer,
|
||||
className,
|
||||
...props
|
||||
}: EditWysiwygComposerProps): JSX.Element {
|
||||
const defaultContextValue = useRef(getDefaultContextValue());
|
||||
const initialContent = useInitialContent(editorStateTransfer);
|
||||
const isReady = !editorStateTransfer || initialContent !== undefined;
|
||||
|
|
|
@ -22,7 +22,7 @@ import { PlainTextComposer } from "./components/PlainTextComposer";
|
|||
import { ComposerFunctions } from "./types";
|
||||
import { E2EStatus } from "../../../../utils/ShieldUtils";
|
||||
import E2EIcon from "../E2EIcon";
|
||||
import { AboveLeftOf } from "../../../structures/ContextMenu";
|
||||
import { MenuProps } from "../../../structures/ContextMenu";
|
||||
import { Emoji } from "./components/Emoji";
|
||||
import { ComposerContext, getDefaultContextValue } from "./ComposerContext";
|
||||
|
||||
|
@ -47,7 +47,7 @@ interface SendWysiwygComposerProps {
|
|||
e2eStatus?: E2EStatus;
|
||||
onChange: (content: string) => void;
|
||||
onSend: () => void;
|
||||
menuPosition: AboveLeftOf;
|
||||
menuPosition: MenuProps;
|
||||
}
|
||||
|
||||
// Default needed for React.lazy
|
||||
|
@ -56,7 +56,7 @@ export default function SendWysiwygComposer({
|
|||
e2eStatus,
|
||||
menuPosition,
|
||||
...props
|
||||
}: SendWysiwygComposerProps) {
|
||||
}: SendWysiwygComposerProps): JSX.Element {
|
||||
const Composer = isRichTextEnabled ? WysiwygComposer : PlainTextComposer;
|
||||
const defaultContextValue = useRef(getDefaultContextValue());
|
||||
|
||||
|
|
|
@ -25,7 +25,11 @@ interface EditionButtonsProps {
|
|||
isSaveDisabled?: boolean;
|
||||
}
|
||||
|
||||
export function EditionButtons({ onCancelClick, onSaveClick, isSaveDisabled = false }: EditionButtonsProps) {
|
||||
export function EditionButtons({
|
||||
onCancelClick,
|
||||
onSaveClick,
|
||||
isSaveDisabled = false,
|
||||
}: EditionButtonsProps): JSX.Element {
|
||||
return (
|
||||
<div className="mx_EditWysiwygComposer_buttons">
|
||||
<AccessibleButton kind="secondary" onClick={onCancelClick}>
|
||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
|
||||
import React from "react";
|
||||
|
||||
import { AboveLeftOf } from "../../../../structures/ContextMenu";
|
||||
import { MenuProps } from "../../../../structures/ContextMenu";
|
||||
import { EmojiButton } from "../../EmojiButton";
|
||||
import dis from "../../../../../dispatcher/dispatcher";
|
||||
import { ComposerInsertPayload } from "../../../../../dispatcher/payloads/ComposerInsertPayload";
|
||||
|
@ -24,10 +24,10 @@ import { Action } from "../../../../../dispatcher/actions";
|
|||
import { useRoomContext } from "../../../../../contexts/RoomContext";
|
||||
|
||||
interface EmojiProps {
|
||||
menuPosition: AboveLeftOf;
|
||||
menuPosition: MenuProps;
|
||||
}
|
||||
|
||||
export function Emoji({ menuPosition }: EmojiProps) {
|
||||
export function Emoji({ menuPosition }: EmojiProps): JSX.Element {
|
||||
const roomContext = useRoomContext();
|
||||
|
||||
return (
|
||||
|
|
|
@ -38,7 +38,7 @@ interface TooltipProps {
|
|||
keyCombo?: KeyCombo;
|
||||
}
|
||||
|
||||
function Tooltip({ label, keyCombo }: TooltipProps) {
|
||||
function Tooltip({ label, keyCombo }: TooltipProps): JSX.Element {
|
||||
return (
|
||||
<div className="mx_FormattingButtons_Tooltip">
|
||||
{label}
|
||||
|
@ -55,7 +55,7 @@ interface ButtonProps extends TooltipProps {
|
|||
onClick: MouseEventHandler<HTMLButtonElement>;
|
||||
}
|
||||
|
||||
function Button({ label, keyCombo, onClick, isActive, icon }: ButtonProps) {
|
||||
function Button({ label, keyCombo, onClick, isActive, icon }: ButtonProps): JSX.Element {
|
||||
return (
|
||||
<AccessibleTooltipButton
|
||||
element="button"
|
||||
|
@ -78,9 +78,8 @@ interface FormattingButtonsProps {
|
|||
actionStates: AllActionStates;
|
||||
}
|
||||
|
||||
export function FormattingButtons({ composer, actionStates }: FormattingButtonsProps) {
|
||||
export function FormattingButtons({ composer, actionStates }: FormattingButtonsProps): JSX.Element {
|
||||
const composerContext = useComposerContext();
|
||||
|
||||
return (
|
||||
<div className="mx_FormattingButtons">
|
||||
<Button
|
||||
|
|
|
@ -29,7 +29,7 @@ export function openLinkModal(
|
|||
composer: FormattingFunctions,
|
||||
composerContext: ComposerContextState,
|
||||
isEditing: boolean,
|
||||
) {
|
||||
): void {
|
||||
const modal = Modal.createDialog(
|
||||
LinkModal,
|
||||
{
|
||||
|
@ -45,7 +45,7 @@ export function openLinkModal(
|
|||
);
|
||||
}
|
||||
|
||||
function isEmpty(text: string) {
|
||||
function isEmpty(text: string): boolean {
|
||||
return text.length < 1;
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,13 @@ interface LinkModalProps {
|
|||
isEditing: boolean;
|
||||
}
|
||||
|
||||
export function LinkModal({ composer, isTextEnabled, onClose, composerContext, isEditing }: LinkModalProps) {
|
||||
export function LinkModal({
|
||||
composer,
|
||||
isTextEnabled,
|
||||
onClose,
|
||||
composerContext,
|
||||
isEditing,
|
||||
}: LinkModalProps): JSX.Element {
|
||||
const [hasLinkChanged, setHasLinkChanged] = useState(false);
|
||||
const [fields, setFields] = useState({ text: "", link: isEditing ? composer.getLink() : "" });
|
||||
const hasText = !isEditing && isTextEnabled;
|
||||
|
|
|
@ -47,7 +47,7 @@ export function PlainTextComposer({
|
|||
initialContent,
|
||||
leftComponent,
|
||||
rightComponent,
|
||||
}: PlainTextComposerProps) {
|
||||
}: PlainTextComposerProps): JSX.Element {
|
||||
const { ref, onInput, onPaste, onKeyDown, content, setContent } = usePlainTextListeners(
|
||||
initialContent,
|
||||
onChange,
|
||||
|
|
|
@ -18,7 +18,13 @@ import { RefObject, useMemo } from "react";
|
|||
|
||||
import { setSelection } from "../utils/selection";
|
||||
|
||||
export function useComposerFunctions(ref: RefObject<HTMLDivElement>, setContent: (content: string) => void) {
|
||||
export function useComposerFunctions(
|
||||
ref: RefObject<HTMLDivElement>,
|
||||
setContent: (content: string) => void,
|
||||
): {
|
||||
clear(): void;
|
||||
insertText(text: string): void;
|
||||
} {
|
||||
return useMemo(
|
||||
() => ({
|
||||
clear: () => {
|
||||
|
|
|
@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { ISendEventResponse } from "matrix-js-sdk/src/@types/requests";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
import { useMatrixClientContext } from "../../../../../contexts/MatrixClientContext";
|
||||
|
@ -22,7 +23,15 @@ import EditorStateTransfer from "../../../../../utils/EditorStateTransfer";
|
|||
import { endEditing } from "../utils/editing";
|
||||
import { editMessage } from "../utils/message";
|
||||
|
||||
export function useEditing(editorStateTransfer: EditorStateTransfer, initialContent?: string) {
|
||||
export function useEditing(
|
||||
editorStateTransfer: EditorStateTransfer,
|
||||
initialContent?: string,
|
||||
): {
|
||||
isSaveDisabled: boolean;
|
||||
onChange(content: string): void;
|
||||
editMessage(): Promise<ISendEventResponse>;
|
||||
endEditing(): void;
|
||||
} {
|
||||
const roomContext = useRoomContext();
|
||||
const mxClient = useMatrixClientContext();
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ function parseEditorStateTransfer(
|
|||
// this.saveStoredEditorState();
|
||||
}
|
||||
|
||||
export function useInitialContent(editorStateTransfer: EditorStateTransfer) {
|
||||
export function useInitialContent(editorStateTransfer: EditorStateTransfer): string {
|
||||
const roomContext = useRoomContext();
|
||||
const mxClient = useMatrixClientContext();
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ import { useCallback } from "react";
|
|||
|
||||
import { useSettingValue } from "../../../../../hooks/useSettings";
|
||||
|
||||
export function useInputEventProcessor(onSend: () => void) {
|
||||
export function useInputEventProcessor(onSend: () => void): (event: WysiwygEvent) => WysiwygEvent | null {
|
||||
const isCtrlEnter = useSettingValue<boolean>("MessageComposerInput.ctrlEnterToSend");
|
||||
return useCallback(
|
||||
(event: WysiwygEvent) => {
|
||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
|
||||
import { MutableRefObject, useEffect, useState } from "react";
|
||||
|
||||
export function useIsExpanded(ref: MutableRefObject<HTMLElement | null>, breakingPoint: number) {
|
||||
export function useIsExpanded(ref: MutableRefObject<HTMLElement | null>, breakingPoint: number): boolean {
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
useEffect(() => {
|
||||
if (ref.current) {
|
||||
|
|
|
@ -16,7 +16,10 @@ limitations under the License.
|
|||
|
||||
import { FocusEvent, useCallback, useEffect, useRef, useState } from "react";
|
||||
|
||||
export function useIsFocused() {
|
||||
export function useIsFocused(): {
|
||||
isFocused: boolean;
|
||||
onFocus(event: FocusEvent<HTMLElement>): void;
|
||||
} {
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
const timeoutIDRef = useRef<number>();
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
|
||||
import { RefObject, useEffect } from "react";
|
||||
|
||||
export function usePlainTextInitialization(initialContent = "", ref: RefObject<HTMLElement>) {
|
||||
export function usePlainTextInitialization(initialContent = "", ref: RefObject<HTMLElement>): void {
|
||||
useEffect(() => {
|
||||
if (ref.current) {
|
||||
ref.current.innerText = initialContent;
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { KeyboardEvent, SyntheticEvent, useCallback, useRef, useState } from "react";
|
||||
import { KeyboardEvent, RefObject, SyntheticEvent, useCallback, useRef, useState } from "react";
|
||||
|
||||
import { useSettingValue } from "../../../../../hooks/useSettings";
|
||||
import { IS_MAC, Key } from "../../../../../Keyboard";
|
||||
|
@ -26,7 +26,7 @@ function isDivElement(target: EventTarget): target is HTMLDivElement {
|
|||
// Hitting enter inside the editor inserts an editable div, initially containing a <br />
|
||||
// For correct display, first replace this pattern with a newline character and then remove divs
|
||||
// noting that they are used to delimit paragraphs
|
||||
function amendInnerHtml(text: string) {
|
||||
function amendInnerHtml(text: string): string {
|
||||
return text
|
||||
.replace(/<div><br><\/div>/g, "\n") // this is pressing enter then not typing
|
||||
.replace(/<div>/g, "\n") // this is from pressing enter, then typing inside the div
|
||||
|
@ -37,7 +37,14 @@ export function usePlainTextListeners(
|
|||
initialContent?: string,
|
||||
onChange?: (content: string) => void,
|
||||
onSend?: () => void,
|
||||
) {
|
||||
): {
|
||||
ref: RefObject<HTMLDivElement | null>;
|
||||
content?: string;
|
||||
onInput(event: SyntheticEvent<HTMLDivElement, InputEvent | ClipboardEvent>): void;
|
||||
onPaste(event: SyntheticEvent<HTMLDivElement, InputEvent | ClipboardEvent>): void;
|
||||
onKeyDown(event: KeyboardEvent<HTMLDivElement>): void;
|
||||
setContent(text: string): void;
|
||||
} {
|
||||
const ref = useRef<HTMLDivElement | null>(null);
|
||||
const [content, setContent] = useState<string | undefined>(initialContent);
|
||||
const send = useCallback(() => {
|
||||
|
|
|
@ -19,7 +19,7 @@ import { useCallback, useEffect } from "react";
|
|||
import useFocus from "../../../../../hooks/useFocus";
|
||||
import { useComposerContext, ComposerContextState } from "../ComposerContext";
|
||||
|
||||
function setSelectionContext(composerContext: ComposerContextState) {
|
||||
function setSelectionContext(composerContext: ComposerContextState): void {
|
||||
const selection = document.getSelection();
|
||||
|
||||
if (selection) {
|
||||
|
@ -32,12 +32,14 @@ function setSelectionContext(composerContext: ComposerContextState) {
|
|||
}
|
||||
}
|
||||
|
||||
export function useSelection() {
|
||||
export function useSelection(): ReturnType<typeof useFocus>[1] & {
|
||||
onInput(): void;
|
||||
} {
|
||||
const composerContext = useComposerContext();
|
||||
const [isFocused, focusProps] = useFocus();
|
||||
|
||||
useEffect(() => {
|
||||
function onSelectionChange() {
|
||||
function onSelectionChange(): void {
|
||||
setSelectionContext(composerContext);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ import { RefObject, useEffect } from "react";
|
|||
|
||||
import { setCursorPositionAtTheEnd } from "./utils";
|
||||
|
||||
export function useSetCursorPosition(disabled: boolean, ref: RefObject<HTMLElement>) {
|
||||
export function useSetCursorPosition(disabled: boolean, ref: RefObject<HTMLElement>): void {
|
||||
useEffect(() => {
|
||||
if (ref.current && !disabled) {
|
||||
setCursorPositionAtTheEnd(ref.current);
|
||||
|
|
|
@ -31,7 +31,7 @@ export function useWysiwygEditActionHandler(
|
|||
disabled: boolean,
|
||||
composerElement: RefObject<HTMLElement>,
|
||||
composerFunctions: ComposerFunctions,
|
||||
) {
|
||||
): void {
|
||||
const roomContext = useRoomContext();
|
||||
const composerContext = useComposerContext();
|
||||
const timeoutId = useRef<number | null>(null);
|
||||
|
|
|
@ -31,7 +31,7 @@ export function useWysiwygSendActionHandler(
|
|||
disabled: boolean,
|
||||
composerElement: MutableRefObject<HTMLElement>,
|
||||
composerFunctions: ComposerFunctions,
|
||||
) {
|
||||
): void {
|
||||
const roomContext = useRoomContext();
|
||||
const composerContext = useComposerContext();
|
||||
const timeoutId = useRef<number | null>(null);
|
||||
|
|
|
@ -24,7 +24,7 @@ export function focusComposer(
|
|||
renderingType: TimelineRenderingType,
|
||||
roomContext: IRoomState,
|
||||
timeoutId: MutableRefObject<number | null>,
|
||||
) {
|
||||
): void {
|
||||
if (renderingType === roomContext.timelineRenderingType) {
|
||||
// Immediately set the focus, so if you start typing it
|
||||
// will appear in the composer
|
||||
|
@ -41,7 +41,7 @@ export function focusComposer(
|
|||
}
|
||||
}
|
||||
|
||||
export function setCursorPositionAtTheEnd(element: HTMLElement) {
|
||||
export function setCursorPositionAtTheEnd(element: HTMLElement): void {
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(element);
|
||||
range.collapse(false);
|
||||
|
|
|
@ -21,7 +21,7 @@ import dis from "../../../../../dispatcher/dispatcher";
|
|||
import { Action } from "../../../../../dispatcher/actions";
|
||||
import EditorStateTransfer from "../../../../../utils/EditorStateTransfer";
|
||||
|
||||
export function endEditing(roomContext: IRoomState) {
|
||||
export function endEditing(roomContext: IRoomState): void {
|
||||
// todo local storage
|
||||
// localStorage.removeItem(this.editorRoomKey);
|
||||
// localStorage.removeItem(this.editorStateKey);
|
||||
|
@ -38,7 +38,7 @@ export function endEditing(roomContext: IRoomState) {
|
|||
});
|
||||
}
|
||||
|
||||
export function cancelPreviousPendingEdit(mxClient: MatrixClient, editorStateTransfer: EditorStateTransfer) {
|
||||
export function cancelPreviousPendingEdit(mxClient: MatrixClient, editorStateTransfer: EditorStateTransfer): void {
|
||||
const originalEvent = editorStateTransfer.getEvent();
|
||||
const previousEdit = originalEvent.replacingEvent();
|
||||
if (previousEdit && (previousEdit.status === EventStatus.QUEUED || previousEdit.status === EventStatus.NOT_SENT)) {
|
||||
|
|
|
@ -47,7 +47,7 @@ export async function sendMessage(
|
|||
message: string,
|
||||
isHTML: boolean,
|
||||
{ roomContext, mxClient, ...params }: SendMessageParams,
|
||||
) {
|
||||
): Promise<ISendEventResponse> {
|
||||
const { relation, replyToEvent } = params;
|
||||
const { room } = roomContext;
|
||||
const roomId = room?.roomId;
|
||||
|
@ -143,7 +143,10 @@ interface EditMessageParams {
|
|||
editorStateTransfer: EditorStateTransfer;
|
||||
}
|
||||
|
||||
export async function editMessage(html: string, { roomContext, mxClient, editorStateTransfer }: EditMessageParams) {
|
||||
export async function editMessage(
|
||||
html: string,
|
||||
{ roomContext, mxClient, editorStateTransfer }: EditMessageParams,
|
||||
): Promise<ISendEventResponse> {
|
||||
const editedEvent = editorStateTransfer.getEvent();
|
||||
|
||||
PosthogAnalytics.instance.trackEvent<ComposerEvent>({
|
||||
|
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
|
||||
import { SubSelection } from "../types";
|
||||
|
||||
export function setSelection(selection: SubSelection) {
|
||||
export function setSelection(selection: SubSelection): Promise<void> {
|
||||
if (selection.anchorNode && selection.focusNode) {
|
||||
const range = new Range();
|
||||
range.setStart(selection.anchorNode, selection.anchorOffset);
|
||||
|
@ -30,7 +30,7 @@ export function setSelection(selection: SubSelection) {
|
|||
return new Promise((resolve) => setTimeout(resolve, 0));
|
||||
}
|
||||
|
||||
export function isSelectionEmpty() {
|
||||
export function isSelectionEmpty(): boolean {
|
||||
const selection = document.getSelection();
|
||||
return Boolean(selection?.isCollapsed);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue