ViewportRail
A thin map of a document, showing where each person is looking.
SourcePackage @weft-js/warp
Preview
tsx
import { ViewportRail } from '@weft-js/warp'import type { Peer } from '@weft-js/warp'import type { ViewportPeer } from '@weft-js/warp'export function Document() { return ( <RailHeight><ViewportRail peers={VIEWPORT_PEERS} self={{ top: 0.02, height: 0.3 }} /></RailHeight> )}const PEOPLE = [ { id: 'mara', name: 'Mara Lindqvist', email: 'mara@weft.dev', role: 'Owner', team: 'Platform', initials: 'ML' }, { id: 'jun', name: 'Jun Tanaka', email: 'jun@weft.dev', role: 'Admin', team: 'Platform', initials: 'JT' }, { id: 'priya', name: 'Priya Raman', email: 'priya@weft.dev', role: 'Member', team: 'Web', initials: 'PR' }, { id: 'tomas', name: 'Tomás Oliveira', email: 'tomas@weft.dev', role: 'Member', team: 'Web', initials: 'TO' }, { id: 'lena', name: 'Lena Fischer', email: 'lena@weft.dev', role: 'Member', team: 'Data', initials: 'LF' }, { id: 'noor', name: 'Noor Haddad', email: 'noor@weft.dev', role: 'Viewer', team: 'Data', initials: 'NH' }, { id: 'sam', name: 'Sam Okafor', email: 'sam@weft.dev', role: 'Member', team: 'Mobile', initials: 'SO' }, { id: 'ines', name: 'Inés Vidal', email: 'ines@weft.dev', role: 'Viewer', team: 'Mobile', initials: 'IV' },]const PEERS: Peer[] = PEOPLE.map((p, i) => ({ id: p.id, name: p.name, color: i + 1 }))const [MARA, JUN, PRIYA, TOMAS, LENA, NOOR, SAM, INES] = PEERS as [Peer, Peer, Peer, Peer, Peer, Peer, Peer, Peer]const VIEWPORT_PEERS: ViewportPeer[] = [{ ...JUN, top: 0.12, height: 0.3 }, { ...LENA, top: 0.55, height: 0.3 }]const RailHeight = ({ children }: { children: unknown }) => <div style="display:grid;block-size:180px">{children}</div>Installation
npm install @weft-js/warpUsage
tsx
import { ViewportRail } from '@weft-js/warp'<RailHeight><ViewportRail peers={VIEWPORT_PEERS} self={{ top: 0.02, height: 0.3 }} /></RailHeight>Jump to someone
onJump turns each box into a button.
tsx
import { state } from '@weft-js/core'import { Row, Text, ViewportRail } from '@weft-js/warp'import type { Peer } from '@weft-js/warp'import type { ViewportPeer } from '@weft-js/warp'export function Jump() { const seen = state('Press a box to jump to that person.') return ( <Row gap="group"> <RailHeight><ViewportRail peers={VIEWPORT_PEERS} self={{ top: 0.02, height: 0.3 }} onJump={p => (seen.value = `Jumped to ${p.name}.`)} /></RailHeight> <Text subtle>{seen.value}</Text> </Row> )}const PEOPLE = [ { id: 'mara', name: 'Mara Lindqvist', email: 'mara@weft.dev', role: 'Owner', team: 'Platform', initials: 'ML' }, { id: 'jun', name: 'Jun Tanaka', email: 'jun@weft.dev', role: 'Admin', team: 'Platform', initials: 'JT' }, { id: 'priya', name: 'Priya Raman', email: 'priya@weft.dev', role: 'Member', team: 'Web', initials: 'PR' }, { id: 'tomas', name: 'Tomás Oliveira', email: 'tomas@weft.dev', role: 'Member', team: 'Web', initials: 'TO' }, { id: 'lena', name: 'Lena Fischer', email: 'lena@weft.dev', role: 'Member', team: 'Data', initials: 'LF' }, { id: 'noor', name: 'Noor Haddad', email: 'noor@weft.dev', role: 'Viewer', team: 'Data', initials: 'NH' }, { id: 'sam', name: 'Sam Okafor', email: 'sam@weft.dev', role: 'Member', team: 'Mobile', initials: 'SO' }, { id: 'ines', name: 'Inés Vidal', email: 'ines@weft.dev', role: 'Viewer', team: 'Mobile', initials: 'IV' },]const PEERS: Peer[] = PEOPLE.map((p, i) => ({ id: p.id, name: p.name, color: i + 1 }))const [MARA, JUN, PRIYA, TOMAS, LENA, NOOR, SAM, INES] = PEERS as [Peer, Peer, Peer, Peer, Peer, Peer, Peer, Peer]const VIEWPORT_PEERS: ViewportPeer[] = [{ ...JUN, top: 0.12, height: 0.3 }, { ...LENA, top: 0.55, height: 0.3 }]const RailHeight = ({ children }: { children: unknown }) => <div style="display:grid;block-size:180px">{children}</div>Accessibility
- This has no shortcuts of its own: controls inside it use Tab, Enter and Space as usual, and warp's parts keep their roles and labels.
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
peers | Live<ViewportPeer[]> | — | People and their viewports, from 0 to 1 of the document. |
self | { top: number; height: number; } | — | Your own viewport. |
label | string | 'Where people are looking' | Names the rail. |
| Event | Type | Default | Description |
|---|---|---|---|
onJump | ((p: ViewportPeer) => void) | — | Makes each box a button. |
RelatedSection peersFollowing