Merge remote-tracking branch 'origin/main' into dbkr/widget-toggles-api

This commit is contained in:
David Baker
2026-03-09 15:58:35 +00:00
6 changed files with 201 additions and 3 deletions
@@ -5,8 +5,9 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
import type { JSX } from "react";
import type { JSX, ReactNode } from "react";
import type { MatrixEvent } from "../models/event";
import type { AccountAuthInfo } from "./auth.ts";
/**
* Properties for all message components.
@@ -91,6 +92,71 @@ export type CustomRoomPreviewBarRenderFunction = (
originalComponent: (props: CustomRoomPreviewBarComponentProps) => JSX.Element,
) => JSX.Element;
/**
* Authentication server config object.
* @alpha Subject to change.
*/
export interface CustomLoginComponentPropsServerConfig {
/**
* The URL of the homeserver's client-server API
*/
hsUrl: string;
/**
* The name of the homeserver to present to the user
*/
hsName: string;
}
/**
* Properties for login component.
* @alpha Subject to change.
*/
export type CustomLoginComponentProps = {
/**
* The details of the currently chosen Matrix homeserver
*/
serverConfig: CustomLoginComponentPropsServerConfig;
/**
* The URL fragment to send the user to after authentication is complete
*/
fragmentAfterLogin?: string;
/**
* Additional components to render as children
*/
children?: ReactNode;
/**
* Function to complete login
* @param data - the data to authenticate the user with
*/
onLoggedIn(data: AccountAuthInfo): void;
/**
* Function to change the selected server
* @param config - new server configuration details
*/
onServerConfigChange(config: CustomLoginComponentPropsServerConfig): void;
};
/**
* Function used to render a component with a superset of the known props.
* @alpha Unlikely to change
*/
export type ExtendablePropsRenderFunction<BaseProps> = <P extends BaseProps>(
/**
* Properties for the component to be rendered.
*/
props: P,
/**
* Render function for the original component.
*/
originalComponent: (props: P) => JSX.Element,
) => JSX.Element;
/**
* Function used to render a login component.
* @alpha Unlikely to change
*/
export type CustomLoginRenderFunction = ExtendablePropsRenderFunction<CustomLoginComponentProps>;
/**
* API for inserting custom components into Element.
* @alpha Subject to change.
@@ -143,4 +209,19 @@ export interface CustomComponentsApi {
* ```
*/
registerRoomPreviewBar(renderer: CustomRoomPreviewBarRenderFunction): void;
/**
* Register a renderer for the login component.
*
* The render function should return a rendered component.
*
* @param renderer - The render function for the login component.
* @example
* ```
* customComponents.registerLoginComponent((props, OriginalComponent) => {
* return <YourCustomComponent onLoggedIn={props.onLoggedIn} />;
* });
* ```
*/
registerLoginComponent(renderer: CustomLoginRenderFunction): void;
}
@@ -0,0 +1,65 @@
/*
Copyright 2026 Element Creations Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/
/**
* Enum of UI components which can have their behaviour tweaked
* @alpha
*/
export const enum UIComponent {
/**
* Components that lead to a user being invited.
*/
InviteUsers = "UIComponent.sendInvites",
/**
* Components that lead to a room being created that aren't already
* guarded by some other condition (ie: "only if you can edit this
* space" is *not* guarded by this component, but "start DM" is).
*/
CreateRooms = "UIComponent.roomCreation",
/**
* Components that lead to a Space being created that aren't already
* guarded by some other condition (ie: "only if you can add subspaces"
* is *not* guarded by this component, but "create new space" is).
*/
CreateSpaces = "UIComponent.spaceCreation",
/**
* Components that lead to the public room directory.
*/
ExploreRooms = "UIComponent.exploreRooms",
/**
* Components that lead to the user being able to easily add widgets
* and integrations to the room, such as from the room information card.
*/
AddIntegrations = "UIComponent.addIntegrations",
/**
* Component that lead to the user being able to search, dial, explore rooms
*/
FilterContainer = "UIComponent.filterContainer",
/**
* Components that lead the user to room options menu.
*/
RoomOptionsMenu = "UIComponent.roomOptionsMenu",
}
/**
* API for customising Element Web's components
* @alpha Subject to change.
*/
export interface CustomisationsApi {
/**
* Method to register a callback which can affect whether a given component is drawn or not.
* @param fn - the callback, if it returns true the component will be rendered, if false it will not be.
* If undefined will defer to next callback, ultimately falling through to `true` if none return false.
*/
registerShouldShowComponent(fn: (this: void, component: UIComponent) => boolean | void): void;
}
@@ -22,6 +22,7 @@ import { type StoresApi } from "./stores.ts";
import { type ClientApi } from "./client.ts";
import { type WidgetLifecycleApi } from "./widget-lifecycle.ts";
import { type WidgetApi } from "./widget.ts";
import { type CustomisationsApi } from "./customisations.ts";
/**
* Module interface for modules to implement.
@@ -152,6 +153,12 @@ export interface Api
*/
readonly widget: WidgetApi;
/**
* Allows modules to customise behaviour of app's components.
* @alpha Subject to change.
*/
readonly customisations: CustomisationsApi;
/**
* Create a ReactDOM root for rendering React components.
* Exposed to allow modules to avoid needing to bundle their own ReactDOM.
@@ -24,5 +24,7 @@ export type * from "./api/stores";
export type * from "./api/client";
export type * from "./api/widget-lifecycle";
export type * from "./api/widget";
export type * from "./api/customisations";
export { UIComponent } from "./api/customisations";
export * from "./api/watchable";
export type * from "./utils";