Add Module Composer API (#33284)
* Spec composer API * Add composer api implementation * Tests * Copyright * update sigs * cleanup * a snap * cleanup * linting * Tidy up * Adjust
This commit is contained in:
@@ -1293,23 +1293,30 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||
}
|
||||
|
||||
case Action.ComposerInsert: {
|
||||
if (payload.composerType) break;
|
||||
const composerInsertPayload = payload as ComposerInsertPayload;
|
||||
if (composerInsertPayload.composerType) break;
|
||||
|
||||
let timelineRenderingType: TimelineRenderingType = payload.timelineRenderingType;
|
||||
let timelineRenderingType: TimelineRenderingType | undefined;
|
||||
// ThreadView handles Action.ComposerInsert itself due to it having its own editState
|
||||
if (timelineRenderingType === TimelineRenderingType.Thread) break;
|
||||
if (composerInsertPayload.timelineRenderingType === TimelineRenderingType.Thread) break;
|
||||
if (
|
||||
this.state.timelineRenderingType === TimelineRenderingType.Search &&
|
||||
payload.timelineRenderingType === TimelineRenderingType.Search
|
||||
composerInsertPayload.timelineRenderingType === TimelineRenderingType.Search
|
||||
) {
|
||||
// we don't have the composer rendered in this state, so bring it back first
|
||||
await this.onCancelSearchClick();
|
||||
timelineRenderingType = TimelineRenderingType.Room;
|
||||
}
|
||||
|
||||
// If the dispatchee didn't request a timeline rendering type, use the current one.
|
||||
timelineRenderingType =
|
||||
timelineRenderingType ??
|
||||
composerInsertPayload.timelineRenderingType ??
|
||||
this.state.timelineRenderingType;
|
||||
|
||||
// re-dispatch to the correct composer
|
||||
defaultDispatcher.dispatch<ComposerInsertPayload>({
|
||||
...(payload as ComposerInsertPayload),
|
||||
...composerInsertPayload,
|
||||
timelineRenderingType,
|
||||
composerType: this.state.editState ? ComposerType.Edit : ComposerType.Send,
|
||||
});
|
||||
|
||||
@@ -167,12 +167,14 @@ export default class ThreadView extends React.Component<IProps, IState> {
|
||||
}
|
||||
switch (payload.action) {
|
||||
case Action.ComposerInsert: {
|
||||
if (payload.composerType) break;
|
||||
if (payload.timelineRenderingType !== TimelineRenderingType.Thread) break;
|
||||
const insertPayload = payload as ComposerInsertPayload;
|
||||
if (insertPayload.composerType) break;
|
||||
if (insertPayload.timelineRenderingType !== TimelineRenderingType.Thread) break;
|
||||
|
||||
// re-dispatch to the correct composer
|
||||
dis.dispatch<ComposerInsertPayload>({
|
||||
...(payload as ComposerInsertPayload),
|
||||
...insertPayload,
|
||||
timelineRenderingType: TimelineRenderingType.Thread,
|
||||
composerType: this.state.editState ? ComposerType.Edit : ComposerType.Send,
|
||||
});
|
||||
break;
|
||||
|
||||
@@ -17,7 +17,7 @@ export enum ComposerType {
|
||||
|
||||
interface IBaseComposerInsertPayload extends ActionPayload {
|
||||
action: Action.ComposerInsert;
|
||||
timelineRenderingType: TimelineRenderingType;
|
||||
timelineRenderingType?: TimelineRenderingType; // undefined if this should just use the current in-focus type.
|
||||
composerType?: ComposerType; // falsy if should be re-dispatched to the correct composer
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ import { StoresApi } from "./StoresApi.ts";
|
||||
import { WidgetLifecycleApi } from "./WidgetLifecycleApi.ts";
|
||||
import { WidgetApi } from "./WidgetApi.ts";
|
||||
import { CustomisationsApi } from "./customisationsApi.ts";
|
||||
import { ComposerApi } from "./ComposerApi.ts";
|
||||
import defaultDispatcher from "../dispatcher/dispatcher.ts";
|
||||
|
||||
const legacyCustomisationsFactory = <T extends object>(baseCustomisations: T) => {
|
||||
let used = false;
|
||||
@@ -94,6 +96,7 @@ export class ModuleApi implements Api {
|
||||
public readonly rootNode = document.getElementById("matrixchat")!;
|
||||
public readonly client = new ClientApi();
|
||||
public readonly stores = new StoresApi();
|
||||
public readonly composer = new ComposerApi(defaultDispatcher);
|
||||
|
||||
public createRoot(element: Element): Root {
|
||||
return createRoot(element);
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
|
||||
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 { type ComposerApi as ModuleComposerApi } from "@element-hq/element-web-module-api";
|
||||
|
||||
import type { MatrixDispatcher } from "../dispatcher/dispatcher";
|
||||
import { Action } from "../dispatcher/actions";
|
||||
import type { ComposerInsertPayload } from "../dispatcher/payloads/ComposerInsertPayload";
|
||||
|
||||
export class ComposerApi implements ModuleComposerApi {
|
||||
public constructor(private readonly dispatcher: MatrixDispatcher) {}
|
||||
|
||||
public insertPlaintextIntoComposer(plaintext: string): void {
|
||||
this.dispatcher.dispatch({
|
||||
action: Action.ComposerInsert,
|
||||
text: plaintext,
|
||||
} satisfies ComposerInsertPayload);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user