/* Copyright 2024 New Vector Ltd. Copyright 2021 The Matrix.org Foundation C.I.C. SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial Please see LICENSE files in the repository root for full details. */ import React, { FormEvent } from "react"; import { MatrixClient } from "matrix-js-sdk/src/matrix"; import FocusLock from "react-focus-lock"; 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"; export interface IScrollableBaseState { canSubmit: boolean; title: string; actionLabel: string; cancelLabel?: string; } /** * Scrollable dialog base from Compound (Web Components). */ export default abstract class ScrollableBaseModal< TProps extends { onFinished?: (...args: any[]) => void }, TState extends IScrollableBaseState, > extends React.PureComponent { 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()!; } private onKeyDown = (e: KeyboardEvent | React.KeyboardEvent): void => { const action = getKeyBindingsManager().getAccessibilityAction(e); switch (action) { case KeyBindingAction.Escape: e.stopPropagation(); e.preventDefault(); this.cancel(); break; } }; private onCancel = (): void => { this.cancel(); }; private onSubmit = (e: MouseEvent | FormEvent): void => { 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 { return (

{this.state.title}

{this.renderContent()}
{this.state.cancelLabel ?? _t("action|cancel")} {this.state.actionLabel}
); } }