Implement new renderNotificationDecoration from module API (#31389)
* Upgrade module api package * Add a wrapper component So that we can render the decoration component with just the room. * Implement module API method * Add more tests
This commit is contained in:
@@ -10,6 +10,7 @@ import { type RoomViewProps, type BuiltinsApi } from "@element-hq/element-web-mo
|
||||
|
||||
import { MatrixClientPeg } from "../MatrixClientPeg";
|
||||
import type { Room } from "matrix-js-sdk/src/matrix";
|
||||
import type { ModuleNotificationDecorationProps } from "./components/ModuleNotificationDecoration";
|
||||
|
||||
interface RoomViewPropsWithRoomId extends RoomViewProps {
|
||||
/**
|
||||
@@ -26,11 +27,14 @@ interface RoomAvatarProps {
|
||||
interface Components {
|
||||
roomView: React.ComponentType<RoomViewPropsWithRoomId>;
|
||||
roomAvatar: React.ComponentType<RoomAvatarProps>;
|
||||
notificationDecoration: React.ComponentType<ModuleNotificationDecorationProps>;
|
||||
}
|
||||
|
||||
export class ElementWebBuiltinsApi implements BuiltinsApi {
|
||||
private _roomView?: Components["roomView"];
|
||||
private _roomAvatar?: Components["roomAvatar"];
|
||||
private _notificationDecoration?: Components["notificationDecoration"];
|
||||
|
||||
/**
|
||||
* Sets the components used by the API.
|
||||
*
|
||||
@@ -43,13 +47,13 @@ export class ElementWebBuiltinsApi implements BuiltinsApi {
|
||||
public setComponents(components: Components): void {
|
||||
this._roomView = components.roomView;
|
||||
this._roomAvatar = components.roomAvatar;
|
||||
this._notificationDecoration = components.notificationDecoration;
|
||||
}
|
||||
|
||||
public getRoomViewComponent(): React.ComponentType<RoomViewPropsWithRoomId> {
|
||||
if (!this._roomView) {
|
||||
throw new Error("No RoomView component has been set");
|
||||
}
|
||||
|
||||
return this._roomView;
|
||||
}
|
||||
|
||||
@@ -57,10 +61,16 @@ export class ElementWebBuiltinsApi implements BuiltinsApi {
|
||||
if (!this._roomAvatar) {
|
||||
throw new Error("No RoomAvatar component has been set");
|
||||
}
|
||||
|
||||
return this._roomAvatar;
|
||||
}
|
||||
|
||||
public getNotificationDecorationComponent(): React.ComponentType<ModuleNotificationDecorationProps> {
|
||||
if (!this._notificationDecoration) {
|
||||
throw new Error("No NotificationDecoration component has been set");
|
||||
}
|
||||
return this._notificationDecoration;
|
||||
}
|
||||
|
||||
public renderRoomView(roomId: string, props?: RoomViewProps): React.ReactNode {
|
||||
const Component = this.getRoomViewComponent();
|
||||
return <Component roomId={roomId} {...props} />;
|
||||
@@ -74,4 +84,13 @@ export class ElementWebBuiltinsApi implements BuiltinsApi {
|
||||
const Component = this.getRoomAvatarComponent();
|
||||
return <Component room={room} size={size} />;
|
||||
}
|
||||
|
||||
public renderNotificationDecoration(roomId: string): React.ReactNode {
|
||||
const room = MatrixClientPeg.safeGet().getRoom(roomId);
|
||||
if (!room) {
|
||||
throw new Error(`No room such room: ${roomId}`);
|
||||
}
|
||||
const Component = this.getNotificationDecorationComponent();
|
||||
return <Component room={room} />;
|
||||
}
|
||||
}
|
||||
|
||||
29
src/modules/components/ModuleNotificationDecoration.tsx
Normal file
29
src/modules/components/ModuleNotificationDecoration.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
Copyright 2025 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 React, { useMemo } from "react";
|
||||
|
||||
import type { Room } from "matrix-js-sdk/src/matrix";
|
||||
import { RoomNotificationStateStore } from "../../stores/notifications/RoomNotificationStateStore";
|
||||
import { useCall } from "../../hooks/useCall";
|
||||
import { NotificationDecoration } from "../../components/views/rooms/NotificationDecoration";
|
||||
|
||||
export interface ModuleNotificationDecorationProps {
|
||||
/**
|
||||
* The room for which the decoration is rendered.
|
||||
*/
|
||||
room: Room;
|
||||
}
|
||||
|
||||
/**
|
||||
* React component that takes a room as prop and renders {@link NotificationDecoration} with it.
|
||||
* Used by the module API to render notification decoration without having to expose a bunch of stores.
|
||||
*/
|
||||
export const ModuleNotificationDecoration: React.FC<ModuleNotificationDecorationProps> = ({ room }) => {
|
||||
const notificationState = useMemo(() => RoomNotificationStateStore.instance.getRoomState(room), [room]);
|
||||
const call = useCall(room.roomId);
|
||||
return <NotificationDecoration notificationState={notificationState} callType={call?.callType} />;
|
||||
};
|
||||
@@ -33,6 +33,7 @@ import { UserFriendlyError } from "../languageHandler";
|
||||
import { ModuleApi } from "../modules/Api";
|
||||
import { RoomView } from "../components/structures/RoomView";
|
||||
import RoomAvatar from "../components/views/avatars/RoomAvatar";
|
||||
import { ModuleNotificationDecoration } from "../modules/components/ModuleNotificationDecoration";
|
||||
|
||||
logger.log(`Application is running in ${process.env.NODE_ENV} mode`);
|
||||
|
||||
@@ -58,7 +59,11 @@ function onTokenLoginCompleted(): void {
|
||||
export async function loadApp(fragParams: QueryDict, matrixChatRef: React.Ref<MatrixChat>): Promise<ReactElement> {
|
||||
// XXX: This lives here because certain components import so many things that importing it in a sensible place (eg.
|
||||
// the builtins module or init.tsx) causes a circular dependency.
|
||||
ModuleApi.instance.builtins.setComponents({ roomView: RoomView, roomAvatar: RoomAvatar });
|
||||
ModuleApi.instance.builtins.setComponents({
|
||||
roomView: RoomView,
|
||||
roomAvatar: RoomAvatar,
|
||||
notificationDecoration: ModuleNotificationDecoration,
|
||||
});
|
||||
|
||||
initRouting();
|
||||
const platform = PlatformPeg.get();
|
||||
|
||||
Reference in New Issue
Block a user