Theme
Customize the design system

Every control starts at the preset. Change one and every preview on the site follows, on this page and the next, until you reset it.

Contrast

Text against what it sits on. Below 4.5:1 fails WCAG AA for body text — the check a reviewer runs on any surface that takes a tone.

Waiting for the first preview to report its palette.

Corners

Sets all three radii at once. The individual values are under Geometry.

Brand 5

The accent seam an app actually brands itself through. Change these and you have made the decision a real `DesignTokens.graphite(...)` call makes.

Geometry 15

Square or rounded, and how heavy every line is. The radius row above the controls sets all three corners at once, because "what does square feel like" is one decision rather than three numbers.

Surfaces 17

Everything the app is painted ON — the ground behind the content (the frame paints it too), the cards over it, the well inset in a card, and the washes that show state.

Bands 10

The rail's head and the view bar beside it (one band across the top at 960 and wider), a pushed screen's bar, the compact bar and the compact nav bar — the band's fill, its rule, its hover and active faces, the resting field box on it, and the ink and accent control that sit on it. The rail's tree and its footer stay on the ground.

Text and controls 11

The ink ramp, the control outlines and the field's focus halo. Every pair the panel can break is watched by a contrast badge above.

Status 7

The three voices that mean something — danger, caution and ok — each as a foreground and a surface wash, danger with a border as well.

Data 5

The default pin head, its glyph and its halo, and the group bands. A pin's category color comes from the palette, named in the theme seed.

Map 11

The basemap's roles — land, water, parks, roads and their casings, buildings, labels — and the pending pin's gray. A raster basemap keeps its own imagery; these paint the map's plate and any kit-drawn map.

Scrollbars 6

Every scroller's bar: the thumb at rest and while hovered or dragged, the strip it rides, and the desk bar's thickness, side gap and corners. The desk half shows only while a fine pointer is attached; at touch the platform's own overlay keeps its size.

Advanced 6

Real controls that are not decisions — motion durations, the focus ring offset, the touch floor. Opens collapsed on purpose.

Take it with you

The Dart that reproduces what you are looking at. It is a real constructor call, because the configurator edits a real preset — what you copy is what an app can paste.

Screens

Add people

Reach for this wherever a user brings people in, scoped to where they stand: invite by pasted email addresses, or make a join link with its expiry, use cap and approval, each with the access it grants. A pattern over the kit's fields, the same on both kits. The host passes the access it may hand out and does the inviting, so it names no access model.

Spec of record: design-system/components/forms/AddPeoplePanel.d.ts

2
Knobs

Live

Real widgets, built from the real kit. Turn a knob and it rebuilds; the theme bar above applies the design system's own tokens — including anything you changed under Customize — and the device selector uses the same sizes the golden baselines gate on, so what you see here is what CI holds the widget to.

Press Focus on any preview to take it to the full window — at a desktop width that renders most devices at 1:1, which is when the widget's own controls become clickable. The bar always states the device and the scale, so a shrunk preview says it is shrunk. Esc leaves.

screen_add_people
Knobs
Theme

Offers the join-link section. A host with no link action passes no `onCreateLink`, and the section is not drawn at all.

Adds optional First name and Last name fields for a single invite. They hide once a second address is entered, and the names are sent only with one address.

Dart for these values
screen_add_people()

What it is made of

The widgets this screen assembles, with their full API below. They used to live on a second entry of their own; one thing you choose gets one page.

AddPeoplePanel widget

"Add people", scoped to where the user stands: invite by email with the access chosen, or make a join link with its access, expiry, use cap and approval. Two LabeledSections; the link section shows only when onCreateLink is given. onInvite receives one AddPeopleInviteRequest: the parsed,…

Full dartdoc

"Add people", scoped to where the user stands: invite by email with the access chosen, or make a join link with its access, expiry, use cap and approval. Two LabeledSections; the link section shows only when onCreateLink is given. onInvite receives one AddPeopleInviteRequest: the parsed, deduplicated addresses, the chosen access value and, under names, the names; onCreateLink receives the link's settings and returns the link to show and copy. A throw from either shows AddPeopleCopy.failed, never the error itself, unless failureText words it: the host reads its own error (a route's refusal code, say) and the panel shows the host's words.

AddPeoplePaneldefault constructor

Knob Type Default What it does
accessOptions * List<AppSelectOption<String>> — The access the user may hand out here, in display order.
copy AddPeopleCopy AddPeopleCopy.standard The copy shown. AddPeopleCopy.standard by default.
expiryOptions List<AppSegmentOption<int>> defaultExpiryOptions The link lifetimes offered, in days, 2 to 5; the last is the default.
failureText String? Function(Object error)? null Words a failure of onInvite or onCreateLink: given what the action threw, the host's text for the person, or null for AddPeopleCopy.failed. The host writes the text (for example from a route's refusal code); it never passes the error's own message, and never an address.
maxInvites int 50 The most addresses one invite takes.
maxLinkUses int 500 The most uses a link may allow.
names bool false Draws optional first- and last-name fields for a single invite (`AddPeoplePanel.d.ts` THE NAMES). They show only while the addresses hold at most one entry and hide from a second; what was typed is kept while hidden and never sent. Each name reaches onInvite trimmed, null when blank, and both are…
onCreateLink Future<String> Function(AddPeopleLinkRequest request)? null Makes a join link and returns it; null hides the link section.
onInvite * Future<void> Function(AddPeopleInviteRequest request) — Sends the invite.

Types its knobs take

These are not things you choose — they are the shapes the knobs above expect. They live under this entry rather than in the navigation for exactly that reason.

AddPeopleCopy support

The copy an AddPeoplePanel shows: the app's product voice. Every refusal is fixed copy; an address is never echoed back.

Field Type Default What it does
accessLabel * String — The access select's label, in both sections.
approvalLabel * String — The approval switch's label.
copied * String — The copy action, just after it copied.
copyLink * String — The copy action.
createLink * String — The link action.
emailsHint * String — The address field's hint.
emailsLabel * String — The address field's label.
expiresLabel * String — The expiry choice's label.
failed * String — The notice when the host's action failed.
familyNameLabel * String — The last-name field's label, under AddPeoplePanel.names.
givenNameLabel * String — The first-name field's label, under AddPeoplePanel.names.
invite * String — The invite action.
inviteSection * String — The invite section's heading.
invited * String Function(int count) — The notice after an invite, for `count` people.
linkLabel * String — The made link's label.
linkSection * String — The link section's heading.
maxUsesError * String Function(int max) — The error for a use cap outside 1 to `max`.
maxUsesLabel * String — The use cap's label.
noAccess * String — The error for an action with no access chosen.
noAddress * String — The error for an invite with no address.
notAnAddress * String Function(int count) — The error for `count` entries that are not addresses.
tooMany * String Function(int max) — The error for more than `max` addresses in one go.

AddPeopleInviteRequest support

An invite, as the user made it in an AddPeoplePanel (`AddPeoplePanel.d.ts` THE HAND-OVER).

Field Type Default What it does
access * String — The access option's value: what the invite grants.
emails * List<String> — The parsed, deduplicated addresses, in first-seen order.
familyName String? null The last name, by the same rule as givenName.
givenName String? null The first name, trimmed; null when blank, without AddPeoplePanel.names, or when more than one address is sent.

AddPeopleLinkRequest support

A join link's settings, as the user chose them in an AddPeoplePanel.

Field Type Default What it does
access * String — The access option's value: what joining grants.
approvalRequired * bool — Whether each join waits for approval.
expiresInDays * int — How long the link works, in days.
maxUses * int — How many people may join through it.

Where it lives

Class File
AddPeoplePanel packages/app_widgets/lib/src/patterns/add_people_panel.dart