Skip to content
weftGitHub

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/warp

Usage

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

PropTypeDefaultDescription
openState<boolean>—Whether it shows. You own this state.
titlestring—What is being shared.
membersLive<ShareMember[]>—Who has access.
peopleShareContact[]—People the invite field suggests. Any email works too.
linkLive<ShareLink>—The link's access and role.
urlstring—What Copy link writes.
EventTypeDefaultDescription
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