Files
ThreadNet-Web/src/components/views/dialogs/ScrollableBaseModal.tsx
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

118 lines
4.6 KiB
TypeScript
Raw Normal View History

2021-11-01 23:44:42 -06:00
/*
2024-09-09 14:57:16 +01:00
Copyright 2024 New Vector Ltd.
2021-11-01 23:44:42 -06:00
Copyright 2021 The Matrix.org Foundation C.I.C.
2024-09-09 14:57:16 +01:00
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
2021-11-01 23:44:42 -06:00
*/
import React, { FormEvent } from "react";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
2021-12-09 09:10:23 +00:00
import FocusLock from "react-focus-lock";
2021-11-01 23:44:42 -06:00
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { _t } from "../../../languageHandler";
import AccessibleButton from "../elements/AccessibleButton";
import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
2021-11-01 23:44:42 -06:00
export interface IScrollableBaseState {
canSubmit: boolean;
title: string;
actionLabel: string;
cancelLabel?: string;
2021-11-01 23:44:42 -06:00
}
/**
* Scrollable dialog base from Compound (Web Components).
*/
export default abstract class ScrollableBaseModal<
TProps extends { onFinished?: (...args: any[]) => void },
2021-11-01 23:44:42 -06:00
TState extends IScrollableBaseState,
> extends React.PureComponent<TProps, TState> {
protected constructor(props: TProps) {
super(props);
}
protected get matrixClient(): MatrixClient {
// XXX: The contract on MatrixClientContext says it is only available within a LoggedInView subtree,
// given that modals function outside the MatrixChat React tree this simulates that. We don't want to
// use safeGet as it throwing would mean we cannot use modals whilst the user isn't logged in.
// The longer term solution is to move our ModalManager into the React tree to inherit contexts properly.
return MatrixClientPeg.get()!;
2021-11-01 23:44:42 -06:00
}
private onKeyDown = (e: KeyboardEvent | React.KeyboardEvent): void => {
const action = getKeyBindingsManager().getAccessibilityAction(e);
switch (action) {
case KeyBindingAction.Escape:
e.stopPropagation();
e.preventDefault();
this.cancel();
break;
2021-11-01 23:44:42 -06:00
}
};
private onCancel = (): void => {
2021-11-01 23:44:42 -06:00
this.cancel();
};
private onSubmit = (e: MouseEvent | FormEvent): void => {
2021-11-01 23:44:42 -06:00
e.stopPropagation();
e.preventDefault();
if (!this.state.canSubmit) return; // pretend the submit button was disabled
this.submit();
};
protected abstract cancel(): void;
protected abstract submit(): void;
protected abstract renderContent(): React.ReactNode;
public render(): React.ReactNode {
2021-11-01 23:44:42 -06:00
return (
<MatrixClientContext.Provider value={this.matrixClient}>
<FocusLock
returnFocus={true}
lockProps={{
onKeyDown: this.onKeyDown,
role: "dialog",
["aria-labelledby"]: "mx_CompoundDialog_title",
// Like BaseDialog, we'll just point this at the whole content
["aria-describedby"]: "mx_CompoundDialog_content",
}}
className="mx_CompoundDialog mx_ScrollableBaseDialog"
>
<div className="mx_CompoundDialog_header">
<h1>{this.state.title}</h1>
</div>
<AccessibleButton
onClick={this.onCancel}
className="mx_CompoundDialog_cancelButton"
aria-label={_t("dialog_close_label")}
/>
2023-01-06 17:24:13 +01:00
<form onSubmit={this.onSubmit} className="mx_CompoundDialog_form">
2021-11-01 23:44:42 -06:00
<div className="mx_CompoundDialog_content">{this.renderContent()}</div>
<div className="mx_CompoundDialog_footer">
<AccessibleButton onClick={this.onCancel} kind="primary_outline">
{this.state.cancelLabel ?? _t("action|cancel")}
2021-11-01 23:44:42 -06:00
</AccessibleButton>
<AccessibleButton
onClick={this.onSubmit}
kind="primary"
disabled={!this.state.canSubmit}
type="submit"
element="button"
className="mx_Dialog_nonDialogButton"
>
{this.state.actionLabel}
</AccessibleButton>
</div>
</form>
</FocusLock>
</MatrixClientContext.Provider>
);
}
}