Skip to content
kerfjsGitHub

MeetingRoom

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

SourcePackage @kerf-js/veneer

Preview

tsx
import { state } from '@kerf-js/core'import {  Button,  Card,  Inset,  MeetingRoom,  Text} from '@kerf-js/veneer'import type { Participant } from '@kerf-js/veneer'import type { Invite } from '@kerf-js/veneer'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 @kerf-js/veneer

Usage

tsx
import { MeetingRoom } from '@kerf-js/veneer'

On a phone

compact shows the speaker, and icons only.

tsx
import { Inset, MeetingRoom, Text } from '@kerf-js/veneer'import type { Participant } from '@kerf-js/veneer'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.
  • Veneer 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)—The room's connection.
compactbooleanfalseFor a phone. Unset, it follows the room's width.
theme"dark" | "light"—Dark unless you say otherwise.
videoVideo—Return the <video> for a participant.
share(() => unknown)—The shared screen.
presenterstring—Who is sharing.
shareTitlestring—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.

RelatedTileControl barPrejoin