diff --git a/src/events/EventTileFactory.tsx b/src/events/EventTileFactory.tsx index b7edc4d1a7..dc77ffddea 100644 --- a/src/events/EventTileFactory.tsx +++ b/src/events/EventTileFactory.tsx @@ -258,10 +258,14 @@ export function renderTile( cli = cli ?? MatrixClientPeg.safeGet(); // because param defaults don't do the correct thing const factory = pickFactory(props.mxEvent, cli, showHiddenEvents); - if (!factory) + if (!factory) { + // If we don't have a factory for this event, attempt + // to find a custom component that can render it. + // Will return null if no custom component can render it. return ModuleApi.customComponents.renderMessage({ mxEvent: props.mxEvent, }); + } // Note that we split off the ones we actually care about here just to be sure that we're // not going to accidentally send things we shouldn't from lazy callers. Eg: EventTile's @@ -288,13 +292,13 @@ export function renderTile( case TimelineRenderingType.File: case TimelineRenderingType.Notification: case TimelineRenderingType.Thread: - // We only want a subset of props, so we don't end up causing issues for downstream components. return ModuleApi.customComponents.renderMessage( { mxEvent: props.mxEvent, }, (origProps) => factory(props.ref, { + // We only want a subset of props, so we don't end up causing issues for downstream components. mxEvent, highlights, highlightLink, @@ -348,10 +352,14 @@ export function renderReplyTile( cli = cli ?? MatrixClientPeg.safeGet(); // because param defaults don't do the correct thing const factory = pickFactory(props.mxEvent, cli, showHiddenEvents); - if (!factory) + if (!factory) { + // If we don't have a factory for this event, attempt + // to find a custom component that can render it. + // Will return null if no custom component can render it. return ModuleApi.customComponents.renderMessage({ mxEvent: props.mxEvent, }); + } // See renderTile() for why we split off so much const { @@ -411,6 +419,11 @@ export function haveRendererForEvent( return false; } + // Check to see if a renderer is registered for this event + if (ModuleApi.customComponents.getHintsForMessage(mxEvent)) { + return true; + } + // No tile for replacement events since they update the original tile if (mxEvent.isRelation(RelationType.Replace)) return false; diff --git a/src/modules/customComponentApi.tsx b/src/modules/customComponentApi.ts similarity index 90% rename from src/modules/customComponentApi.tsx rename to src/modules/customComponentApi.ts index fdeebd8903..ce75a70507 100644 --- a/src/modules/customComponentApi.tsx +++ b/src/modules/customComponentApi.ts @@ -18,8 +18,10 @@ import type { } from "@element-hq/element-web-module-api"; import type React from "react"; +type EventTypeOrFilter = Parameters[0]; + type EventRenderer = { - eventTypeOrFilter: string | ((mxEvent: ModuleMatrixEvent) => boolean); + eventTypeOrFilter: EventTypeOrFilter; renderer: CustomMessageRenderFunction; hints: CustomMessageRenderHints; }; @@ -59,7 +61,7 @@ export class CustomComponentsApi implements ICustomComponentsApi { private readonly registeredMessageRenderers: EventRenderer[] = []; public registerMessageRenderer( - eventTypeOrFilter: string | ((mxEvent: ModuleMatrixEvent) => boolean), + eventTypeOrFilter: EventTypeOrFilter, renderer: CustomMessageRenderFunction, hints: CustomMessageRenderHints = {}, ): void { @@ -71,12 +73,12 @@ export class CustomComponentsApi implements ICustomComponentsApi { * @returns The registered renderer. */ private selectRenderer(mxEvent: ModuleMatrixEvent): EventRenderer | undefined { - return this.registeredMessageRenderers.find((rdr) => { - if (typeof rdr.eventTypeOrFilter === "string") { - return rdr.eventTypeOrFilter === mxEvent.type; + return this.registeredMessageRenderers.find((renderer) => { + if (typeof renderer.eventTypeOrFilter === "string") { + return renderer.eventTypeOrFilter === mxEvent.type; } else { try { - return rdr.eventTypeOrFilter(mxEvent); + return renderer.eventTypeOrFilter(mxEvent); } catch (ex) { logger.warn("Message renderer failed to process filter", ex); return false; // Skip erroring renderers. @@ -113,12 +115,12 @@ export class CustomComponentsApi implements ICustomComponentsApi { * @param mxEvent The message event being rendered. * @returns A component if a custom renderer exists, or originalComponent returns a value. Otherwise null. */ - public getHintsForMessage(mxEvent: MatrixEvent): CustomMessageRenderHints { + public getHintsForMessage(mxEvent: MatrixEvent): CustomMessageRenderHints | null { const moduleEv = CustomComponentsApi.getModuleMatrixEvent(mxEvent); const renderer = moduleEv && this.selectRenderer(moduleEv); if (renderer) { return renderer.hints; } - return {}; + return null; } } diff --git a/src/utils/EventUtils.ts b/src/utils/EventUtils.ts index 73d4ffebec..ecaa7e06ec 100644 --- a/src/utils/EventUtils.ts +++ b/src/utils/EventUtils.ts @@ -78,7 +78,7 @@ export function canEditContent(matrixClient: MatrixClient, mxEvent: MatrixEvent) return false; } - if (ModuleApi.customComponents.getHintsForMessage(mxEvent).allowEditingEvent === false) { + if (ModuleApi.customComponents.getHintsForMessage(mxEvent)?.allowEditingEvent === false) { return false; }