Will Hunt 0edaef3f7c
Support for custom message components via Module API (#30074)
* Add new custom component api.

* Remove context menu, refactor

* fix types

* Add a test for custom modules.

* tidy

* Rewrite for new API

* Update tests

* lint

* Allow passing in props to original component

* Add hinting

* Update tests to be complete

* lint a bit more

* update docstring

* update @element-hq/element-web-module-api to 1.1.0

* fix types

* updates

* hide jump to bottom button that was causing flakes

* lint

* lint

* Use module matrix event interface instead.

* update to new module sdk

* adapt custom module sample

* Issues caught by Sonar

* lint

* fix issues

* make the comment make sense

* fix import
2025-06-23 11:55:22 +00:00

76 lines
3.7 KiB
TypeScript

/*
Copyright 2025 New Vector 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 { createRoot, type Root } from "react-dom/client";
import { type Api, type RuntimeModuleConstructor } from "@element-hq/element-web-module-api";
import { ModuleRunner } from "./ModuleRunner.ts";
import AliasCustomisations from "../customisations/Alias.ts";
import { RoomListCustomisations } from "../customisations/RoomList.ts";
import ChatExportCustomisations from "../customisations/ChatExport.ts";
import { ComponentVisibilityCustomisations } from "../customisations/ComponentVisibility.ts";
import DirectoryCustomisations from "../customisations/Directory.ts";
import LifecycleCustomisations from "../customisations/Lifecycle.ts";
import * as MediaCustomisations from "../customisations/Media.ts";
import UserIdentifierCustomisations from "../customisations/UserIdentifier.ts";
import { WidgetPermissionCustomisations } from "../customisations/WidgetPermissions.ts";
import { WidgetVariableCustomisations } from "../customisations/WidgetVariables.ts";
import { ConfigApi } from "./ConfigApi.ts";
import { I18nApi } from "./I18nApi.ts";
import { CustomComponentsApi } from "./customComponentApi.ts";
const legacyCustomisationsFactory = <T extends object>(baseCustomisations: T) => {
let used = false;
return (customisations: T) => {
if (used) throw new Error("Legacy customisations can only be registered by one module");
Object.assign(baseCustomisations, customisations);
used = true;
};
};
/**
* Implementation of the @element-hq/element-web-module-api runtime module API.
*/
class ModuleApi implements Api {
/* eslint-disable @typescript-eslint/naming-convention */
public async _registerLegacyModule(LegacyModule: RuntimeModuleConstructor): Promise<void> {
ModuleRunner.instance.registerModule((api) => new LegacyModule(api));
}
public readonly _registerLegacyAliasCustomisations = legacyCustomisationsFactory(AliasCustomisations);
public readonly _registerLegacyChatExportCustomisations = legacyCustomisationsFactory(ChatExportCustomisations);
public readonly _registerLegacyComponentVisibilityCustomisations = legacyCustomisationsFactory(
ComponentVisibilityCustomisations,
);
public readonly _registerLegacyDirectoryCustomisations = legacyCustomisationsFactory(DirectoryCustomisations);
public readonly _registerLegacyLifecycleCustomisations = legacyCustomisationsFactory(LifecycleCustomisations);
public readonly _registerLegacyMediaCustomisations = legacyCustomisationsFactory(MediaCustomisations);
public readonly _registerLegacyRoomListCustomisations = legacyCustomisationsFactory(RoomListCustomisations);
public readonly _registerLegacyUserIdentifierCustomisations =
legacyCustomisationsFactory(UserIdentifierCustomisations);
public readonly _registerLegacyWidgetPermissionsCustomisations =
legacyCustomisationsFactory(WidgetPermissionCustomisations);
public readonly _registerLegacyWidgetVariablesCustomisations =
legacyCustomisationsFactory(WidgetVariableCustomisations);
/* eslint-enable @typescript-eslint/naming-convention */
public readonly config = new ConfigApi();
public readonly i18n = new I18nApi();
public readonly customComponents = new CustomComponentsApi();
public readonly rootNode = document.getElementById("matrixchat")!;
public createRoot(element: Element): Root {
return createRoot(element);
}
}
export type ModuleApiType = ModuleApi;
if (!window.mxModuleApi) {
window.mxModuleApi = new ModuleApi();
}
export default window.mxModuleApi;