mirror of
https://github.com/vector-im/element-call.git
synced 2026-09-10 21:55:19 +00:00
Say "component" for the component
"Embedded" already means something here: the embedded package is the widget build. Where a comment meant Element Call running as a React component inside a host application, it now says so, and the params it starts from are `componentProperties`. "Host" stays the word for the application on the other side, whether that is a widget container or an application rendering the component. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
f70fba1dd6
commit
3dc7cfe10b
@@ -17,8 +17,8 @@ they are meant to cover the page — resolve against the viewport and appear in
|
||||
the middle of the host's window rather than in the middle of the call.
|
||||
|
||||
The clipping cuts both ways: a menu near the edge of a small container is
|
||||
trimmed rather than overflowing into the host. That is the trade being an
|
||||
embedded component makes. */
|
||||
trimmed rather than overflowing into the host. That is the trade being a
|
||||
component rather than a page makes. */
|
||||
.root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -41,7 +41,7 @@ const IS_ROOT = `:where(${ROOT_SELECTOR})`;
|
||||
*
|
||||
* As a page of its own, Element Call can style the document: normalize.css and
|
||||
* Compound speak of `html`, `body` and bare elements, and the design tokens are
|
||||
* declared on `:root`. Embedded in a host, all of that would land on the host's
|
||||
* declared on `:root`. As a component, all of that would land on the host's
|
||||
* document too. This rewrites every selector so that it matches only the root
|
||||
* or its descendants:
|
||||
*
|
||||
|
||||
@@ -83,7 +83,7 @@ interface LogEntry {
|
||||
}
|
||||
|
||||
/**
|
||||
* One embedded Element Call, with the controls a host would have over it: the
|
||||
* One Element Call component, with the controls a host would have over it: the
|
||||
* requests it can make of Element Call, and the ability to take it off screen
|
||||
* altogether.
|
||||
*/
|
||||
@@ -198,9 +198,9 @@ const HostChrome: FC = (): ReactNode => (
|
||||
);
|
||||
|
||||
/**
|
||||
* A dialog of the host's own, over the top of the calls. Element Call embedded
|
||||
* in a host has to sit underneath this — being unable to is one of the reasons
|
||||
* for embedding it rather than putting it in an iframe.
|
||||
* A dialog of the host's own, over the top of the calls. Element Call as a
|
||||
* component has to sit underneath this — being unable to is one of the reasons
|
||||
* for a component rather than an iframe.
|
||||
*/
|
||||
const HostDialog: FC<{ onClose: () => void }> = ({ onClose }): ReactNode => (
|
||||
<div className={styles.dialogScrim}>
|
||||
@@ -213,7 +213,7 @@ const HostDialog: FC<{ onClose: () => void }> = ({ onClose }): ReactNode => (
|
||||
);
|
||||
|
||||
/**
|
||||
* Stands in for a host application embedding Element Call: it owns the Matrix
|
||||
* Stands in for a host application using the Element Call component: it owns the Matrix
|
||||
* clients, the page and the space each call is given, and reaches Element Call
|
||||
* only through the component's public interface.
|
||||
*
|
||||
@@ -299,8 +299,8 @@ export const Harness: FC = (): ReactNode => {
|
||||
<form className={styles.credentials} onSubmit={start}>
|
||||
<h1>Element Call component harness</h1>
|
||||
<p>
|
||||
Signs in twice and shows Element Call embedded twice, in a page that
|
||||
is not Element Call's own.
|
||||
Signs in twice and shows the Element Call component twice, in a page
|
||||
that is not Element Call's own.
|
||||
</p>
|
||||
{field("homeserver", "Homeserver")}
|
||||
{field("username", "Username")}
|
||||
|
||||
+2
-2
@@ -31,8 +31,8 @@ import { useInitial } from "../src/useInitial";
|
||||
import { useLatest } from "../src/useLatest";
|
||||
|
||||
/**
|
||||
* What Element Call tells the application embedding it. Everything is
|
||||
* optional: a host implements what it wants to hear about.
|
||||
* What Element Call tells the application hosting it as a component.
|
||||
* Everything is optional: a host implements what it wants to hear about.
|
||||
*
|
||||
* Compared by nothing — Element Call always calls whichever one it was most
|
||||
* recently given, so this may be written inline.
|
||||
|
||||
+4
-4
@@ -58,7 +58,7 @@ import { HostBridgeProvider } from "../src/HostBridge";
|
||||
import { RootElementProvider } from "../src/RootElementContext";
|
||||
import {
|
||||
configurationForIntent,
|
||||
hostedProperties,
|
||||
componentProperties,
|
||||
type UrlParams,
|
||||
UrlParamsProvider,
|
||||
UserIntent,
|
||||
@@ -209,7 +209,7 @@ export const ElementCall: FC<ElementCallProps> = ({
|
||||
const stableConfig = useStableValue(config);
|
||||
const params = useMemo(
|
||||
(): UrlParams => ({
|
||||
...hostedProperties,
|
||||
...componentProperties,
|
||||
roomId,
|
||||
...configurationForIntent(intent),
|
||||
...stableConfig,
|
||||
@@ -249,8 +249,8 @@ export const ElementCall: FC<ElementCallProps> = ({
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<HostBridgeProvider value={hostBridge}>
|
||||
<UrlParamsProvider value={params}>
|
||||
{/* Element Call's own navigation stays in memory, so that being
|
||||
embedded cannot disturb the host's URL. */}
|
||||
{/* Element Call's own navigation stays in memory, so that the
|
||||
component cannot disturb the host's URL. */}
|
||||
<MemoryRouter>
|
||||
<div ref={setContainer} className={styles.root}>
|
||||
{container !== null &&
|
||||
|
||||
@@ -136,9 +136,9 @@ interface Props {
|
||||
/**
|
||||
* The client Element Call should use.
|
||||
*
|
||||
* When a host embeds Element Call it already has a client, and owns the
|
||||
* user's session; supplying it here means Element Call neither authenticates
|
||||
* anyone nor manages their session. Left out, Element Call finds a client
|
||||
* An application hosting Element Call as a component already has a client,
|
||||
* and owns the user's session; supplying it here means Element Call neither
|
||||
* authenticates anyone nor manages their session. Left out, Element Call finds a client
|
||||
* itself — from the widget API, or by restoring or creating a session of its
|
||||
* own.
|
||||
*/
|
||||
|
||||
+3
-3
@@ -51,7 +51,7 @@ export interface HostRequest<Data, Reply = void> {
|
||||
* Element Call's view of the application hosting it.
|
||||
*
|
||||
* Element Call can run as its own page, as a widget inside a Matrix client, or
|
||||
* embedded directly into one. Only the last two give it a host, and each of
|
||||
* as a component inside one. Only the last two give it a host, and each of
|
||||
* them reaches it by a different route — so everything Element Call needs from
|
||||
* whatever is hosting it goes through this interface, rather than being
|
||||
* expressed in terms of the widget API.
|
||||
@@ -101,8 +101,8 @@ export interface HostBridge {
|
||||
/**
|
||||
* Whether Element Call may offer to change the user's profile — their
|
||||
* display name and avatar. Only when the account is Element Call's own,
|
||||
* which is to say standalone: a widget's host and an application embedding
|
||||
* Element Call both signed the user in themselves, so the profile is theirs
|
||||
* which is to say standalone: a widget's host and an application hosting
|
||||
* the component both signed the user in themselves, so the profile is theirs
|
||||
* to manage and Element Call must not offer to edit it.
|
||||
*/
|
||||
readonly supportsProfileChanges: boolean;
|
||||
|
||||
@@ -12,9 +12,9 @@ import { createContext, use } from "react";
|
||||
*
|
||||
* Element Call decorates this element with the theme, layout and background
|
||||
* attributes its stylesheets key off, and portals its modals into it. When
|
||||
* Element Call owns the page this is simply the document body; the intent is
|
||||
* that when embedded in a host application it becomes the container the host
|
||||
* mounted it into, so that Element Call does not reach outside its own subtree.
|
||||
* Element Call owns the page this is simply the document body; as a component
|
||||
* it is the container the host mounted it into, so that Element Call does not
|
||||
* reach outside its own subtree.
|
||||
*
|
||||
* The stylesheets find this element by its `data-element-call-root` attribute,
|
||||
* which {@link useTheme} sets along with the platform and theme, so they no
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
computeUrlParams,
|
||||
HeaderStyle,
|
||||
getUrlParams,
|
||||
hostedProperties,
|
||||
componentProperties,
|
||||
UserIntent,
|
||||
} from "../src/UrlParams";
|
||||
import { mockConfig } from "./utils/test";
|
||||
@@ -433,7 +433,7 @@ describe("UrlParams", () => {
|
||||
// has no URL of its own for any of this to come from
|
||||
describe("hosted defaults", () => {
|
||||
it("assume nothing about a session or a page", () => {
|
||||
expect(hostedProperties).toMatchObject({
|
||||
expect(componentProperties).toMatchObject({
|
||||
// The host is not a widget host, and supplies the client itself, so
|
||||
// none of the widget or session plumbing applies
|
||||
isWidget: false,
|
||||
|
||||
+8
-6
@@ -446,7 +446,8 @@ export function configurationForIntent(intent: UserIntent): UrlConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link UrlProperties} for Element Call embedded in a host application.
|
||||
* The {@link UrlProperties} for Element Call running as a component inside a
|
||||
* host application.
|
||||
*
|
||||
* It has no URL of its own to read these from, and it does not need most of
|
||||
* them: the widget plumbing does not apply, the Matrix client and the analytics
|
||||
@@ -454,7 +455,7 @@ export function configurationForIntent(intent: UserIntent): UrlConfiguration {
|
||||
* the host's to state through the component's props or Element Call's own
|
||||
* default.
|
||||
*/
|
||||
export const hostedProperties: UrlProperties = {
|
||||
export const componentProperties: UrlProperties = {
|
||||
widgetId: null,
|
||||
parentUrl: null,
|
||||
isWidget: false,
|
||||
@@ -594,8 +595,9 @@ const UrlParamsContext = createContext<UrlParams | null>(null);
|
||||
/**
|
||||
* Supplies the parameters Element Call should run with.
|
||||
*
|
||||
* The standalone and widget builds derive these from the URL, but an embedder
|
||||
* has no URL of its own to put them in, so it provides them directly instead.
|
||||
* The standalone and widget builds derive these from the URL, but the
|
||||
* component has no URL of its own to read them from, so its host provides them
|
||||
* directly instead.
|
||||
*
|
||||
* TODO: `UrlParams` is no longer an accurate name now that these need not come
|
||||
* from a URL. Renaming it touches every consumer, so it is left until the rest
|
||||
@@ -615,8 +617,8 @@ export const useUrlParams = (): UrlParams =>
|
||||
/**
|
||||
* Derives {@link UrlParams} from the current router location.
|
||||
*
|
||||
* Only meaningful when Element Call owns the URL; embedders provide the params
|
||||
* directly through {@link UrlParamsProvider}.
|
||||
* Only meaningful when Element Call owns the URL; the component is given its
|
||||
* params directly through {@link UrlParamsProvider}.
|
||||
*/
|
||||
export const useUrlParamsFromLocation = (): UrlParams => {
|
||||
const { search, hash } = useLocation();
|
||||
|
||||
+3
-3
@@ -8,9 +8,9 @@ Please see LICENSE in the repository root for full details.
|
||||
/* The styles Element Call needs wherever it is shown: the design tokens, fonts
|
||||
and element defaults its own stylesheets build on top of.
|
||||
|
||||
Split out from index.css so that Element Call embedded in a host application
|
||||
can have these without also being given the standalone page's layout, which
|
||||
would style the host's own document. What remains here still speaks of the
|
||||
Split out from index.css so that Element Call as a component can have these
|
||||
without also being given the standalone page's layout, which would style the
|
||||
host's own document. What remains here still speaks of the
|
||||
document — normalize.css and the typography below use bare element selectors,
|
||||
and the custom properties are declared on `:root` — which is right for the
|
||||
page, and is why the component build rewrites it: there every selector is
|
||||
|
||||
@@ -36,7 +36,7 @@ export class Config {
|
||||
*
|
||||
* Does nothing if the config has already been initialized, including by
|
||||
* {@link Config.initWith}, so that the regular startup path can run unchanged
|
||||
* when an embedder has already supplied the config.
|
||||
* when a component host has already supplied the config.
|
||||
*/
|
||||
public static async init(): Promise<void> {
|
||||
if (!Config.internalInstance?.initPromise) {
|
||||
@@ -66,16 +66,15 @@ export class Config {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the config from an object supplied by the embedder, instead of
|
||||
* fetching `config.json`.
|
||||
* Initializes the config from an object supplied by the application hosting
|
||||
* the component, instead of fetching `config.json`.
|
||||
*
|
||||
* {@link Config.init} derives the location of `config.json` from
|
||||
* `window.location`, which only makes sense while Element Call owns the page.
|
||||
* When it is embedded in a host application the host owns the configuration
|
||||
* and passes it in here.
|
||||
* As a component, the host owns the configuration and passes it in here.
|
||||
*
|
||||
* The config goes through the same validation and defaulting as a fetched
|
||||
* one, so that an injected config behaves identically to a hosted one.
|
||||
* one, so that a supplied config behaves identically to a fetched one.
|
||||
*
|
||||
* Replaces any config initialized earlier.
|
||||
*/
|
||||
|
||||
@@ -229,7 +229,7 @@ export interface CallViewModelOptions {
|
||||
*
|
||||
* Callers share this rather than picking the fields out themselves. The
|
||||
* defaults on {@link CallViewModelOptions} describe a standalone Element Call,
|
||||
* so a widget or embedded caller that misses one does not get an error — it
|
||||
* so a widget or component caller that misses one does not get an error — it
|
||||
* quietly gets standalone behaviour instead.
|
||||
*
|
||||
* Note `autoLeaveWhenOthersLeft` and `waitForCallPickup` are deliberately not
|
||||
|
||||
+4
-4
@@ -13,10 +13,10 @@ export const i18nKey = (key: string): string => key;
|
||||
/**
|
||||
* Element Call's own i18next instance.
|
||||
*
|
||||
* We deliberately do not use the global i18next singleton: when Element Call is
|
||||
* embedded in a host application (rather than running as its own page), that
|
||||
* singleton belongs to the host, and configuring it would clobber the host's
|
||||
* translations.
|
||||
* We deliberately do not use the global i18next singleton: when Element Call
|
||||
* runs as a component inside a host application (rather than as its own page),
|
||||
* that singleton belongs to the host, and configuring it would clobber the
|
||||
* host's translations.
|
||||
*
|
||||
* It is configured by `Initializer.initBeforeReact` and made available to
|
||||
* components via `<I18nextProvider>`; tests and stories configure it directly.
|
||||
|
||||
Reference in New Issue
Block a user