ShareDialog
Invite people, set their roles, and choose who a link works for.
SourcePackage @weft-js/warp
Preview
tsx
import { state } from '@weft-js/core'import { Button, PresenceStack, ShareDialog, Stack, Toaster } from '@weft-js/warp'import type { ShareLink, ShareMember, ShareRole, Peer } from '@weft-js/warp'import type { ShareContact } from '@weft-js/warp'export function Runbook() { const open = state(false) const members = state<ShareMember[]>(SHARE_MEMBERS) const link = state<ShareLink>({ access: 'restricted', role: 'viewer' }) const invite = (emails: string[], role: ShareRole) => { const added = emails.map(email => ({ id: email, name: email.split('@')[0]!, email, role })) members.value = [...members.value, ...added] } const change = (m: ShareMember, role: ShareRole | null) => { members.value = role ? members.value.map(x => (x.id === m.id ? { ...x, role } : x)) : members.value.filter(x => x !== m) } return ( <> <Stack gap="related" align="center"> <PresenceStack peers={members.value} /> <Button icon="share" onClick={() => (open.value = true)}>Share</Button> </Stack> <ShareDialog open={open} title="Rollback runbook" members={members} people={SHARE_PEOPLE} link={link} url="https://weft.dev/d/rollback-runbook" onInvite={invite} onRoleChange={change} onLinkAccess={v => (link.value = v)} /> <Toaster /> </> )}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 SHARE_MEMBERS: ShareMember[] = [ { ...MARA, email: 'mara@weft.dev', role: 'owner' }, { ...JUN, email: 'jun@weft.dev', role: 'editor' }, { ...LENA, email: 'lena@weft.dev', role: 'commenter' },]const SHARE_PEOPLE: ShareContact[] = [{ ...PRIYA, email: 'priya@weft.dev' }, { ...TOMAS, email: 'tomas@weft.dev' }, { ...SAM, email: 'sam@weft.dev' }]Installation
npm install @weft-js/warpUsage
tsx
import { ShareDialog } from '@weft-js/warp'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 |
|---|---|---|---|
open | State<boolean> | — | Whether it shows. You own this state. |
title | string | — | What is being shared. |
members | Live<ShareMember[]> | — | Who has access. |
people | ShareContact[] | — | People the invite field suggests. Any email works too. |
link | Live<ShareLink> | — | The link's access and role. |
url | string | — | What Copy link writes. |
| Event | Type | Default | Description |
|---|---|---|---|
onInvite | (emails: string[], role: ShareRole) => void | — | Called with the emails and role. |
onRoleChange | (m: ShareMember, role: ShareRole | null) => void | — | Called with a role, or null to remove the person. |
onLinkAccess | (link: ShareLink) => void | — | Called when the link changes. |
Parts
Every element carries a stable name, so you can style it from your own CSS: [data-scope="share"] [data-part="person"]
personlinkspacer
RelatedInvite dialogPresence stack