mirror of
https://github.com/vector-im/element-call.git
synced 2026-09-10 21:55:19 +00:00
Give the component what the app shell was providing
The component built and typechecked in the previous commit, but only because nothing had rendered it. Everything Element Call needs that `src/main.tsx` side-loads was missing from it. Its stylesheet: only main.tsx imported index.css, so the library build emitted CSS-module styles with every `--cpd-*` and `--font-size-*` unresolved. Split into base.css, which both the app and the component import, and the rules that are about owning a page, which only the app does. The split is a straight move — comment-stripped and sorted, the old file and the two new ones differ by exactly one line — and that line is the deliberate part: `.no-scroll-body` becomes `body.no-scroll-body`. Element Call adds that class to whatever it treats as its root, and since the root can now be a container, `position: fixed` would have taken that container out of the host's layout. Pinning the page is what it always meant. Its translations: `initializeElementCall` called `i18n.init` with neither resources nor a backend, so every key would have rendered as itself. English is bundled in. The app fetches locale files from URLs its own build emits, which a host serving the library from somewhere else could not resolve, so how a host picks a language is left open. And the types a host needs: `HostBridge` alone is not enough to implement `HostBridge` — `HostRequest`, `DeviceMuteState`, `DeviceMuteRequest` and `JoinCallData` all appear in its signatures, and `ConfigOptions` in `initializeElementCall`'s.
This commit is contained in:
@@ -22,3 +22,11 @@ using an iframe. */
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
/* Compound's overlay container, which holds tooltips and popovers, has to fill
|
||||
the container for the elements inside it to be positioned against it. The
|
||||
standalone page does the same for the container under `#root`. */
|
||||
.root > [data-overlay-container] {
|
||||
position: relative;
|
||||
block-size: 100%;
|
||||
}
|
||||
|
||||
+30
-1
@@ -17,6 +17,18 @@ Please see LICENSE in the repository root for full details.
|
||||
* host instead, or is confined to the container it is mounted in.
|
||||
*/
|
||||
|
||||
// The design tokens, fonts and element defaults every Element Call stylesheet
|
||||
// builds on.
|
||||
//
|
||||
// Where these land relative to the component stylesheets is the bundler's
|
||||
// choice — the standalone app puts them first, this build puts them in the
|
||||
// middle — so nothing in base.css may depend on winning or losing against a
|
||||
// component's own rules at equal specificity. It currently does not: what it
|
||||
// declares unlayered is custom properties on Element Call's root, which
|
||||
// components inherit rather than compete with, and everything from Compound
|
||||
// sits in a `@layer`, which loses to unlayered rules either way.
|
||||
import "../src/base.css";
|
||||
|
||||
import { type FC, type JSX, type ReactNode, useMemo, useState } from "react";
|
||||
import { type MatrixClient } from "matrix-js-sdk";
|
||||
import { logger } from "matrix-js-sdk/lib/logger";
|
||||
@@ -26,6 +38,7 @@ import { TooltipProvider } from "@vector-im/compound-web";
|
||||
import { shouldPolyfill as shouldPolyfillSegmenter } from "@formatjs/intl-segmenter/should-polyfill";
|
||||
import { shouldPolyfill as shouldPolyfillDurationFormat } from "@formatjs/intl-durationformat/should-polyfill.js";
|
||||
|
||||
import EN from "../locales/en/app.json";
|
||||
import { ElementCallView } from "../src/ElementCallView";
|
||||
import { ClientProvider } from "../src/ClientContext";
|
||||
import {
|
||||
@@ -50,7 +63,17 @@ import { useTheme } from "../src/useTheme";
|
||||
import { useInitial } from "../src/useInitial";
|
||||
import styles from "./ElementCall.module.css";
|
||||
|
||||
export { type HostBridge } from "../src/HostBridge";
|
||||
// Everything needed to implement a HostBridge, not just the interface itself
|
||||
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
|
||||
// above, which is per call
|
||||
export { type ConfigOptions } from "../src/config/ConfigOptions";
|
||||
|
||||
/**
|
||||
* How Element Call should behave. Everything is optional; anything left out
|
||||
@@ -102,6 +125,12 @@ export async function initializeElementCall(
|
||||
contextSeparator: "|",
|
||||
lng: "en",
|
||||
interpolation: { escapeValue: false },
|
||||
// English only, bundled in. The standalone app fetches its locale files at
|
||||
// runtime from URLs its own build emits, which a host serving the library
|
||||
// from elsewhere could not resolve; bundling one language at least keeps
|
||||
// the component self-contained. Letting a host supply the rest, or its own
|
||||
// translations, is still to do.
|
||||
resources: { en: { app: EN } },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
Copyright 2021-2024 New Vector Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
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 does still reach outside
|
||||
Element Call's container — normalize.css and the typography below use bare
|
||||
element selectors, and the custom properties are declared on `:root` — so a
|
||||
host gets those too. Narrowing them needs a real host to check against, so it
|
||||
waits for the Element Web integration rather than being guessed at here.
|
||||
|
||||
Nothing here should depend on where it lands relative to Element Call's
|
||||
component stylesheets: the bundler decides that, and it decides differently for
|
||||
the app and for the component build. */
|
||||
|
||||
@layer normalize, compound-legacy, compound;
|
||||
|
||||
@import url("@fontsource/inter/400.css");
|
||||
@import url("@fontsource/inter/500.css");
|
||||
@import url("@fontsource/inter/600.css");
|
||||
@import url("@fontsource/inter/700.css");
|
||||
@import url("@fontsource/inconsolata/400.css");
|
||||
@import url("@fontsource/inconsolata/700.css");
|
||||
|
||||
@import url("normalize.css/normalize.css") layer(normalize);
|
||||
@import url("@vector-im/compound-design-tokens/assets/web/css/compound-design-tokens.css") layer(compound);
|
||||
@import url("@vector-im/compound-web/dist/style.css") layer(compound.components);
|
||||
|
||||
:root {
|
||||
--font-scale: 1;
|
||||
--font-size-micro: calc(10px * var(--font-scale));
|
||||
--font-size-caption: calc(12px * var(--font-scale));
|
||||
--font-size-body: calc(15px * var(--font-scale));
|
||||
--font-size-subtitle: calc(18px * var(--font-scale));
|
||||
--font-size-title: calc(24px * var(--font-scale));
|
||||
--font-size-headline: calc(32px * var(--font-scale));
|
||||
|
||||
--cpd-color-border-accent: var(--cpd-color-green-800);
|
||||
/* The distance to inset non-full-width content from the edge of the window
|
||||
along the inline axis. This ramps up from 16px for typical mobile windows, to
|
||||
96px for typical desktop windows, and accounts for the safe area. */
|
||||
--content-inset-left: calc(
|
||||
env(safe-area-inset-left) +
|
||||
min(
|
||||
var(--cpd-space-24x),
|
||||
max(var(--cpd-space-4x), calc((100vw - 900px) / 3))
|
||||
)
|
||||
);
|
||||
--content-inset-right: calc(
|
||||
env(safe-area-inset-right) +
|
||||
min(
|
||||
var(--cpd-space-24x),
|
||||
max(var(--cpd-space-4x), calc((100vw - 900px) / 3))
|
||||
)
|
||||
);
|
||||
--small-drop-shadow: 0px 1.2px 2.4px 0px rgba(0, 0, 0, 0.15);
|
||||
--big-drop-shadow: 0px 0px 24px 0px #1b1d221a;
|
||||
--subtle-drop-shadow: 0px 1px 2px 0px rgba(16, 24, 40, 0.05);
|
||||
|
||||
--call-view-overlay-layer: 1;
|
||||
--call-view-header-footer-layer: 2;
|
||||
}
|
||||
|
||||
:root,
|
||||
[class*="cpd-theme-"] {
|
||||
--video-tile-background: var(--cpd-color-bg-subtle-secondary);
|
||||
}
|
||||
|
||||
.cpd-theme-dark {
|
||||
--cpd-color-border-accent: var(--cpd-color-green-1100);
|
||||
--stopgap-color-on-solid-accent: var(--cpd-color-text-primary);
|
||||
--stopgap-background-85: rgba(16, 19, 23, 0.85);
|
||||
}
|
||||
|
||||
@media (min-height: 330px) {
|
||||
[data-element-call-root][data-background="gradient"]::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
/* Chromium abruptly fades our images to fully transparent at the edge of
|
||||
the element. If we just make the element a little bigger than the viewport,
|
||||
this is no longer visible. */
|
||||
inset: -20px;
|
||||
background-image: url("graphics/mobile-gradient.png");
|
||||
background-size: 1400px 305px;
|
||||
background-position: bottom;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
[data-element-call-root][data-background="gradient"][data-platform="desktop"]::before {
|
||||
background-image: url("graphics/desktop-gradient.png");
|
||||
background-size: max(1440px, 100vw) max(1440px, 100vh);
|
||||
background-position: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* We use this to not render the page at all until we know the theme.*/
|
||||
.no-theme {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* On Android and iOS, prefer native system fonts. The global.css file of
|
||||
Compound Web is where these variables ultimately get consumed to set the page's
|
||||
font-family. */
|
||||
[data-element-call-root][data-platform="android"] {
|
||||
--cpd-font-family-sans: "Roboto", "Noto", "Inter", sans-serif;
|
||||
}
|
||||
|
||||
[data-element-call-root][data-platform="ios"] {
|
||||
--cpd-font-family-sans:
|
||||
-apple-system, BlinkMacSystemFont, "Inter", sans-serif;
|
||||
}
|
||||
|
||||
@layer compound-legacy {
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
p,
|
||||
a {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* Headline Semi Bold */
|
||||
h1 {
|
||||
font-weight: 600;
|
||||
font-size: var(--font-size-headline);
|
||||
}
|
||||
|
||||
/* Title */
|
||||
h2 {
|
||||
font-weight: 600;
|
||||
font-size: var(--font-size-title);
|
||||
}
|
||||
|
||||
/* Subtitle */
|
||||
h3 {
|
||||
font-weight: 600;
|
||||
font-size: var(--font-size-subtitle);
|
||||
}
|
||||
|
||||
/* Body Semi Bold */
|
||||
h4 {
|
||||
font-weight: 600;
|
||||
font-size: var(--font-size-body);
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
/* Body */
|
||||
p {
|
||||
font-size: var(--font-size-body);
|
||||
line-height: var(--font-size-title);
|
||||
}
|
||||
|
||||
hr {
|
||||
width: calc(100% - 24px);
|
||||
border: none;
|
||||
border-top: 1px solid var(--cpd-color-border-interactive-secondary);
|
||||
color: var(--cpd-color-border-interactive-secondary);
|
||||
overflow: visible;
|
||||
text-align: center;
|
||||
height: 5px;
|
||||
font-weight: 600;
|
||||
font-size: var(--font-size-body);
|
||||
line-height: 24px;
|
||||
margin: 0 12px;
|
||||
}
|
||||
|
||||
summary {
|
||||
font-size: var(--font-size-body);
|
||||
}
|
||||
|
||||
details > :not(summary) {
|
||||
margin-left: var(--font-size-body);
|
||||
}
|
||||
|
||||
details[open] > summary {
|
||||
margin-bottom: var(--font-size-body);
|
||||
}
|
||||
}
|
||||
|
||||
/* normalize.css sets the focus rings on buttons in Firefox to an unusual custom
|
||||
outline, which is inconsistent with our other components and is not sufficiently
|
||||
visible to be accessible. This resets it back to 'auto'. */
|
||||
button:-moz-focusring,
|
||||
[type="button"]:-moz-focusring,
|
||||
[type="reset"]:-moz-focusring,
|
||||
[type="submit"]:-moz-focusring {
|
||||
outline: auto;
|
||||
}
|
||||
+9
-182
@@ -5,64 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
@layer normalize, compound-legacy, compound;
|
||||
/* Styles for Element Call as a page of its own. The parts that apply wherever
|
||||
Element Call is shown live in base.css; these are about owning the document,
|
||||
and are not loaded when a host embeds Element Call as a component. */
|
||||
|
||||
@import url("@fontsource/inter/400.css");
|
||||
@import url("@fontsource/inter/500.css");
|
||||
@import url("@fontsource/inter/600.css");
|
||||
@import url("@fontsource/inter/700.css");
|
||||
@import url("@fontsource/inconsolata/400.css");
|
||||
@import url("@fontsource/inconsolata/700.css");
|
||||
|
||||
@import url("normalize.css/normalize.css") layer(normalize);
|
||||
@import url("@vector-im/compound-design-tokens/assets/web/css/compound-design-tokens.css") layer(compound);
|
||||
@import url("@vector-im/compound-web/dist/style.css") layer(compound.components);
|
||||
|
||||
:root {
|
||||
--font-scale: 1;
|
||||
--font-size-micro: calc(10px * var(--font-scale));
|
||||
--font-size-caption: calc(12px * var(--font-scale));
|
||||
--font-size-body: calc(15px * var(--font-scale));
|
||||
--font-size-subtitle: calc(18px * var(--font-scale));
|
||||
--font-size-title: calc(24px * var(--font-scale));
|
||||
--font-size-headline: calc(32px * var(--font-scale));
|
||||
|
||||
--cpd-color-border-accent: var(--cpd-color-green-800);
|
||||
/* The distance to inset non-full-width content from the edge of the window
|
||||
along the inline axis. This ramps up from 16px for typical mobile windows, to
|
||||
96px for typical desktop windows, and accounts for the safe area. */
|
||||
--content-inset-left: calc(
|
||||
env(safe-area-inset-left) +
|
||||
min(
|
||||
var(--cpd-space-24x),
|
||||
max(var(--cpd-space-4x), calc((100vw - 900px) / 3))
|
||||
)
|
||||
);
|
||||
--content-inset-right: calc(
|
||||
env(safe-area-inset-right) +
|
||||
min(
|
||||
var(--cpd-space-24x),
|
||||
max(var(--cpd-space-4x), calc((100vw - 900px) / 3))
|
||||
)
|
||||
);
|
||||
--small-drop-shadow: 0px 1.2px 2.4px 0px rgba(0, 0, 0, 0.15);
|
||||
--big-drop-shadow: 0px 0px 24px 0px #1b1d221a;
|
||||
--subtle-drop-shadow: 0px 1px 2px 0px rgba(16, 24, 40, 0.05);
|
||||
|
||||
--call-view-overlay-layer: 1;
|
||||
--call-view-header-footer-layer: 2;
|
||||
}
|
||||
|
||||
:root,
|
||||
[class*="cpd-theme-"] {
|
||||
--video-tile-background: var(--cpd-color-bg-subtle-secondary);
|
||||
}
|
||||
|
||||
.cpd-theme-dark {
|
||||
--cpd-color-border-accent: var(--cpd-color-green-1100);
|
||||
--stopgap-color-on-solid-accent: var(--cpd-color-text-primary);
|
||||
--stopgap-background-85: rgba(16, 19, 23, 0.85);
|
||||
}
|
||||
@import url("./base.css");
|
||||
|
||||
body {
|
||||
background-color: var(--cpd-color-bg-canvas-default);
|
||||
@@ -74,39 +21,16 @@ body {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
@media (min-height: 330px) {
|
||||
[data-element-call-root][data-background="gradient"]::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
/* Chromium abruptly fades our images to fully transparent at the edge of
|
||||
the element. If we just make the element a little bigger than the viewport,
|
||||
this is no longer visible. */
|
||||
inset: -20px;
|
||||
background-image: url("graphics/mobile-gradient.png");
|
||||
background-size: 1400px 305px;
|
||||
background-position: bottom;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
[data-element-call-root][data-background="gradient"][data-platform="desktop"]::before {
|
||||
background-image: url("graphics/desktop-gradient.png");
|
||||
background-size: max(1440px, 100vw) max(1440px, 100vh);
|
||||
background-position: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* This prohibits the view to scroll for pages smaller than 122px in width
|
||||
we use this for mobile pip webviews */
|
||||
.no-scroll-body {
|
||||
we use this for mobile pip webviews. Element Call adds this class to whatever
|
||||
it treats as its root, but it is only ever the page that should be pinned like
|
||||
this — done to a container inside a host application it would take that
|
||||
container out of the host's layout — so the selector says so. */
|
||||
body.no-scroll-body {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* We use this to not render the page at all until we know the theme.*/
|
||||
.no-theme {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
@@ -123,104 +47,7 @@ body,
|
||||
isolation: isolate;
|
||||
}
|
||||
|
||||
/* On Android and iOS, prefer native system fonts. The global.css file of
|
||||
Compound Web is where these variables ultimately get consumed to set the page's
|
||||
font-family. */
|
||||
[data-element-call-root][data-platform="android"] {
|
||||
--cpd-font-family-sans: "Roboto", "Noto", "Inter", sans-serif;
|
||||
}
|
||||
|
||||
[data-element-call-root][data-platform="ios"] {
|
||||
--cpd-font-family-sans:
|
||||
-apple-system, BlinkMacSystemFont, "Inter", sans-serif;
|
||||
}
|
||||
|
||||
@layer compound-legacy {
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
p,
|
||||
a {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* Headline Semi Bold */
|
||||
h1 {
|
||||
font-weight: 600;
|
||||
font-size: var(--font-size-headline);
|
||||
}
|
||||
|
||||
/* Title */
|
||||
h2 {
|
||||
font-weight: 600;
|
||||
font-size: var(--font-size-title);
|
||||
}
|
||||
|
||||
/* Subtitle */
|
||||
h3 {
|
||||
font-weight: 600;
|
||||
font-size: var(--font-size-subtitle);
|
||||
}
|
||||
|
||||
/* Body Semi Bold */
|
||||
h4 {
|
||||
font-weight: 600;
|
||||
font-size: var(--font-size-body);
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
/* Body */
|
||||
p {
|
||||
font-size: var(--font-size-body);
|
||||
line-height: var(--font-size-title);
|
||||
}
|
||||
|
||||
hr {
|
||||
width: calc(100% - 24px);
|
||||
border: none;
|
||||
border-top: 1px solid var(--cpd-color-border-interactive-secondary);
|
||||
color: var(--cpd-color-border-interactive-secondary);
|
||||
overflow: visible;
|
||||
text-align: center;
|
||||
height: 5px;
|
||||
font-weight: 600;
|
||||
font-size: var(--font-size-body);
|
||||
line-height: 24px;
|
||||
margin: 0 12px;
|
||||
}
|
||||
|
||||
summary {
|
||||
font-size: var(--font-size-body);
|
||||
}
|
||||
|
||||
details > :not(summary) {
|
||||
margin-left: var(--font-size-body);
|
||||
}
|
||||
|
||||
details[open] > summary {
|
||||
margin-bottom: var(--font-size-body);
|
||||
}
|
||||
}
|
||||
|
||||
#root > [data-overlay-container] {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* normalize.css sets the focus rings on buttons in Firefox to an unusual custom
|
||||
outline, which is inconsistent with our other components and is not sufficiently
|
||||
visible to be accessible. This resets it back to 'auto'. */
|
||||
button:-moz-focusring,
|
||||
[type="button"]:-moz-focusring,
|
||||
[type="reset"]:-moz-focusring,
|
||||
[type="submit"]:-moz-focusring {
|
||||
outline: auto;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user