Skip to content
weftGitHub

MeetingRoom

A whole video call: tiles, layouts, people, chat and controls.

SourcePackage @weft-js/warp

Preview

tsx
import { state } from '@weft-js/core'import { Button, Card, Inset, MeetingRoom, Text } from '@weft-js/warp'import type { Participant } from '@weft-js/warp'import type { Invite } from '@weft-js/warp'export function Incident() {  const left = state(false)  return (    <div style="block-size:560px">      {left.value        ? <Card title="You left the incident review" sweep={false}><Button onClick={() => (left.value = false)}>Rejoin</Button></Card>        : <MeetingRoom title="Incident review" timer="12:48" recording participants={CALL} self={CALL_SELF} presenter="Sam" shareTitle="Incident timeline" share={SLIDE} chat={CHAT} invite={INVITE} onLeave={() => (left.value = true)} />}    </div>  )}const CALL: Participant[] = [  { id: 'sam', name: 'Sam Okafor', role: 'host', isSpeaking: true },  { id: 'jun', name: 'Jun Tanaka', isMuted: true },  { id: 'ines', name: 'Inés Vidal' },  { id: 'mara', name: 'Mara Lindqvist', handRaised: true },  { id: 'lena', name: 'Lena Fischer', isMuted: true, network: 'poor' },  { id: 'tomas', name: 'Tomás Oliveira', isCamOn: false },]const CALL_SELF: Participant = { id: 'priya', name: 'Priya Raman' }const CHAT = () => <Inset pad="group"><Text subtle>Sam: the rollback finished at 15:41.</Text></Inset>const SLIDE = () => <Inset pad="section"><Text role="heading">mobile-bff timeline</Text></Inset>const INVITE = () => <Button emphasis="outline" tone="neutral" size="sm" full>Invite people</Button>

Installation

npm install @weft-js/warp

Usage

tsx
import { MeetingRoom } from '@weft-js/warp'

On a phone

compact shows the speaker, and icons only.

tsx
import { Inset, MeetingRoom, Text } from '@weft-js/warp'import type { Participant } from '@weft-js/warp'export function Phone() {  return (    <div style="block-size:620px">      <MeetingRoom compact title="Incident review" timer="12:48" participants={CALL} self={CALL_SELF} chat={CHAT} />    </div>  )}const CALL: Participant[] = [  { id: 'sam', name: 'Sam Okafor', role: 'host', isSpeaking: true },  { id: 'jun', name: 'Jun Tanaka', isMuted: true },  { id: 'ines', name: 'Inés Vidal' },  { id: 'mara', name: 'Mara Lindqvist', handRaised: true },  { id: 'lena', name: 'Lena Fischer', isMuted: true, network: 'poor' },  { id: 'tomas', name: 'Tomás Oliveira', isCamOn: false },]const CALL_SELF: Participant = { id: 'priya', name: 'Priya Raman' }const CHAT = () => <Inset pad="group"><Text subtle>Sam: the rollback finished at 15:41.</Text></Inset>

Accessibility

  • Raised hands are announced. Who is speaking is not, or it would never stop.
  • warp never touches the camera or microphone: media is yours.

API Reference

PropTypeDefaultDescription
titlestring—The heading.
participantsParticipant[] | { value: Participant[]; } | (() => Participant[])—Everyone but you.
selfParticipant—You.
layoutMeetingLayout | State<MeetingLayout>—gallery, speaker, presentation or board.
timerunknown—Elapsed time, already formatted.
recordingbooleanfalseShows a Rec badge in the header.
livestring | (() => string)'live'The room's connection.
compactbooleanfalseFor a phone. Unset, it follows the room's width.
theme"dark" | "light"'dark'Dark unless you say otherwise.
videoVideo—Return the <video> for a participant.
share(() => unknown)—The shared screen.
presenterstring—Who is sharing.
shareTitlestring'Shared screen'What is being shared, in the presentation header. Default "Shared screen".
board(() => unknown)—The whiteboard.
chat(() => unknown)—The Chat panel.
invite(() => unknown)—Below People.
micboolean | State<boolean>—Whether your mic is on: a state the room writes, or a value with onMic.
cameraboolean | State<boolean>—Whether your camera is on: a state the room writes, or a value with onCamera.
handboolean | State<boolean>—Whether your hand is raised: a state the room writes, or a value with onHand.
sharingboolean | State<boolean>—Whether you are sharing your screen: a state the room writes, or a value with onShare.
sidebar"chat" | "people" | State<"chat" | "people" | null> | null—The open side panel, people or chat, or null for none.
reactionstring'🎉'The emoji the React button sends. Default 🎉.
EventTypeDefaultDescription
onLayoutChange((l: MeetingLayout) => void)—Called with the layout picked in the switcher.
onMic((on: boolean) => void)—Called with the mic's new state. Start or stop the track here.
onCamera((on: boolean) => void)—Called with the camera's new state. Start or stop the track here.
onHand((on: boolean) => void)—Called with true when you raise your hand and false when you lower it.
onShare((on: boolean) => void)—Called with true to start sharing your screen and false to stop.
onReact((emoji: string) => void)—Called with the emoji when you react.
onLeave(() => void)—Called when Leave is pressed.
onMore(() => void)—More: replaces the phone's default, which opens the People and Chat panel.

Parts

Every element carries a stable name, so you can style it from your own CSS: [data-scope="call-controls"] [data-part="control"]

controlrootheaderrecspacerstagetilesstripsharerailsidebarapp-barpeople

RelatedTileControl barPrejoin