mirror of
https://github.com/vector-im/element-call.git
synced 2026-09-10 21:55:19 +00:00
Talk to a component host in callbacks, not observables
The component exposed the internal HostBridge to hosts as-is, which carried the host's requests as rxjs observables. That made rxjs part of the public API of a package that bundles its own copy of it, so a host would build bridges with a different rxjs than the one Element Call consumed them with — and asked every host to learn rxjs to change the theme. A component host now implements plain async callbacks for what Element Call tells it (`ElementCallHostBridge`, all optional), and makes its own requests through an imperative handle on the component's `ref` (`ElementCallHandle`: setTheme, join, hangUp, setDeviceMute), each resolving once Element Call has acted and rejecting when nothing in Element Call can. `component/host.ts` adapts that to the HostBridge the rest of Element Call still speaks, with a bridge whose identity never changes, so a host re-creating its callbacks on render restarts nothing. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
d18e82c546
commit
8e8bc5ddde
+20
-30
@@ -36,6 +36,7 @@ import {
|
||||
type FC,
|
||||
type JSX,
|
||||
type ReactNode,
|
||||
type Ref,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
@@ -53,11 +54,7 @@ import EN from "../locales/en/app.json";
|
||||
import { ElementCallView } from "../src/ElementCallView";
|
||||
import { ErrorPage } from "../src/FullScreenView";
|
||||
import { ClientProvider } from "../src/ClientContext";
|
||||
import {
|
||||
type HostBridge,
|
||||
HostBridgeProvider,
|
||||
nullHostBridge,
|
||||
} from "../src/HostBridge";
|
||||
import { HostBridgeProvider } from "../src/HostBridge";
|
||||
import { RootElementProvider } from "../src/RootElementContext";
|
||||
import {
|
||||
configurationForIntent,
|
||||
@@ -76,13 +73,17 @@ import { i18n } from "../src/utils/i18n";
|
||||
import { useTheme } from "../src/useTheme";
|
||||
import { useStableValue } from "../src/useStableValue";
|
||||
import styles from "./ElementCall.module.css";
|
||||
import {
|
||||
type ElementCallHandle,
|
||||
type ElementCallHostBridge,
|
||||
useComponentHostBridge,
|
||||
} from "./host";
|
||||
|
||||
// Everything needed to implement a HostBridge, not just the interface itself
|
||||
// How the host and Element Call talk to each other, and what they say
|
||||
export { type ElementCallHandle, type ElementCallHostBridge } from "./host";
|
||||
export {
|
||||
type DeviceMuteRequest,
|
||||
type DeviceMuteState,
|
||||
type HostBridge,
|
||||
type HostRequest,
|
||||
} from "../src/HostBridge";
|
||||
export { type JoinCallData } from "../src/widget";
|
||||
// The deployment-wide configuration, as distinct from ElementCallConfiguration
|
||||
@@ -102,14 +103,6 @@ export {
|
||||
*/
|
||||
export type ElementCallConfiguration = Partial<UrlParams>;
|
||||
|
||||
/**
|
||||
* What a host embedding Element Call implements to talk to it. This is the
|
||||
* {@link HostBridge} less what Element Call already knows about such a host:
|
||||
* the account is the host's, since the client is, so the profile is not
|
||||
* Element Call's to change.
|
||||
*/
|
||||
export type ElementCallHostBridge = Omit<HostBridge, "supportsProfileChanges">;
|
||||
|
||||
export interface ElementCallProps {
|
||||
/**
|
||||
* The client to place the call with. Element Call does not authenticate
|
||||
@@ -138,11 +131,16 @@ export interface ElementCallProps {
|
||||
*/
|
||||
config?: ElementCallConfiguration;
|
||||
/**
|
||||
* How to reach the host while the call is running — to be told the user has
|
||||
* joined or hung up, to be asked to keep the call on screen, and so on.
|
||||
* Without one, Element Call assumes it has no host to talk to.
|
||||
* What Element Call tells the host while the call is running: that the user
|
||||
* has joined or hung up, that it would like to be kept on screen, and so on.
|
||||
* Without one, Element Call assumes nobody is listening.
|
||||
*/
|
||||
hostBridge?: ElementCallHostBridge;
|
||||
/**
|
||||
* What the host tells Element Call: to change theme, to hang up, to mute.
|
||||
* Available once the component has rendered.
|
||||
*/
|
||||
ref?: Ref<ElementCallHandle>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,18 +189,10 @@ export const ElementCall: FC<ElementCallProps> = ({
|
||||
roomId,
|
||||
intent = UserIntent.JoinExistingCall,
|
||||
config,
|
||||
hostBridge: suppliedHostBridge = nullHostBridge,
|
||||
hostBridge: suppliedHostBridge,
|
||||
ref,
|
||||
}): ReactNode => {
|
||||
// Whatever the host says or does not say, the account is its own: it signed
|
||||
// the user in and handed us the client. So Element Call never offers to edit
|
||||
// the profile from inside a component.
|
||||
const hostBridge = useMemo(
|
||||
(): HostBridge => ({
|
||||
...suppliedHostBridge,
|
||||
supportsProfileChanges: false,
|
||||
}),
|
||||
[suppliedHostBridge],
|
||||
);
|
||||
const hostBridge = useComponentHostBridge(suppliedHostBridge, ref);
|
||||
|
||||
// The container is what Element Call decorates and portals into, so nothing
|
||||
// inside can render until we have it.
|
||||
|
||||
Reference in New Issue
Block a user