Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,12 @@ Status legend: ⬜ Todo · ✅ Done
| 21 | Code block | built-in synchronous highlighter; languages host-extensible | ✅ |
| 22 | Thinking indicator | turning, breathing asterisk + shimmer label; active & settled | ✅ |
| 23 | Shimmer | text only; sweeping highlight, static when settled | ✅ |
| 24 | Pill | removable tool/mode pill for the composer's action row; label auto-drops on phones | ✅ |

### Surfaces

| # | Component | Variants / notes | Status |
|---|-----------|------------------|--------|
| 24 | Chat View | centred 760 rail; zero state (greeting, lifted composer, starters); jump to latest | ✅ |
| 25 | SidePanel | | ⬜ |
| 26 | Modal | | ⬜ |
| 25 | Chat View | centred 760 rail; zero state (greeting, lifted composer, starters); jump to latest | ✅ |
| 26 | SidePanel | | ⬜ |
| 27 | Modal | | ⬜ |
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
retry pill) and a `FlowErrorPart` message part, with
`onRetry`/`errorTitle`/`retryLabel` threaded through `FlowMessage` and
`FlowThread`.
- **Pill** — `FlowPill`, a removable pill showing an enabled tool or mode
in the composer's action row: host-passed icon, label and tooltips,
removal intent on `onRemove`, and a label that auto-drops to the
icon-only form on phones (`showLabel` forces either).
- **Breaking**: `FlowChatScreen` is renamed to `FlowChatView`. The widget
was never a screen — it is body-only and embeddable, and upcoming
surfaces (side panel, modal) will host it — so the name now follows
Expand Down
7 changes: 4 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,12 @@ Values come from the Flow UI Figma file. Role names follow Material 3's `ColorSc
| 21 | Code block | built-in synchronous highlighter; languages host-extensible | ✅ |
| 22 | Thinking indicator | turning, breathing asterisk + shimmer label; active & settled | ✅ |
| 23 | Shimmer | text only; sweeping highlight, static when settled | ✅ |
| 24 | Pill | removable tool/mode pill for the composer's action row; label auto-drops on phones | ✅ |

### Surfaces

| # | Component | Variants / notes | Status |
|---|-----------|------------------|--------|
| 24 | Chat View | centred 760 rail; zero state (greeting, lifted composer, starters); jump to latest | ✅ |
| 25 | SidePanel | | ⬜ |
| 26 | Modal | | ⬜ |
| 25 | Chat View | centred 760 rail; zero state (greeting, lifted composer, starters); jump to latest | ✅ |
| 26 | SidePanel | | ⬜ |
| 27 | Modal | | ⬜ |
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
| [`FlowComposer`](https://flowui.stac.dev/components/composer) | Multiline input with send/stop, attachments strip, and leading/trailing action slots |
| [`FlowMenu`](https://flowui.stac.dev/components/menu) | Icon-triggered menu with groups, submenus, and toggles — anchored card on desktop, bottom sheet on phones |
| [`FlowModelSelector`](https://flowui.stac.dev/components/model-selector) | Model picker with effort and overflow submenus, sheet on phones |
| [`FlowPill`](https://flowui.stac.dev/components/pill) | Removable pill for an enabled tool or mode in the composer's action row — label auto-drops on phones |
| [`FlowAttachmentGroup`](https://flowui.stac.dev/components/attachments) | Image and file tiles with a type pill |
| [`FlowAttachmentPreview`](https://flowui.stac.dev/components/attachments) | Full-screen image viewer with zoom and paging |
| [`FlowSuggestion`](https://flowui.stac.dev/components/suggestions) / [`FlowSuggestionGroup`](https://flowui.stac.dev/components/suggestions) | Prompt starters — plain or outlined; scroll, wrap, or column layouts |
Expand Down
97 changes: 97 additions & 0 deletions docs/src/content/docs/components/pill.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
title: Pill
description: A removable pill for an enabled tool or mode — icon, label, and an X that reports removal.
sidebar:
order: 15
---

import FlowDemo from '../../../components/FlowDemo.astro';

`FlowPill` is the composer's tool token: while the host has Research or
Web Search switched on, a pill says so — an icon and label on the faint
fill, with an X that reports removal through `onRemove`. Presence *is*
the state: render a pill while its tool is on, and actually turning the
tool off is the host's move. The package ships no strings, so `label`
and both tooltips are host-localized.

## Removable

<FlowDemo demo="pill" variant="default" height={180} title="Removable pills" />

```dart title="A pill per enabled tool"
FlowComposer(
onSend: send,
leadingActions: [
FlowMenu(...),
if (researchOn)
FlowPill(
icon: Icons.school_outlined,
label: 'Research',
removeTooltip: 'Turn off Research',
onRemove: () => setResearch(false),
),
],
)
```

Pass a `removeTooltip` whenever `onRemove` is set — it is the X's
tooltip *and* its accessible name, so without one assistive tech
announces an unnamed button.

## Icon-only on phones

On iOS and Android the label drops away to the design's compact form —
icon and X alone. The check reads the theme's platform rather than the
real one, like the menus' sheet resolution, so hosts and tests can steer
it without a device. `showLabel` forces either form outright; a host
forcing icon-only on a hovering device can pass `tooltip` so the tool's
name survives as a hover:

<FlowDemo demo="pill" variant="icon" height={180} title="The compact form" />

```dart title="Forcing the compact form"
FlowPill(
icon: Icons.language,
label: 'Web Search', // still the accessible name
showLabel: false,
tooltip: 'Web Search',
removeTooltip: 'Turn off Web Search',
onRemove: () => setWebSearch(false),
)
```

## Static and disabled

A pill without `onRemove` is a static status token in full ink — not a
disabled control, which is a deliberate difference from the suggestion
row, where a null tap reads disabled. Disabling here is explicit:
`enabled: false` fades the ink and inerts the targets, keeping the fill
and hairline in place:

<FlowDemo demo="pill" variant="static" height={180} title="Static, and disabled" />

## In the composer

The pill is drawn 32 tall to sit flush in `FlowComposer.leadingActions`,
next to the add menu that toggles it. The action row doesn't scroll, so
keep concurrent pills few:

<FlowDemo demo="pill" variant="composer" height={260} title="Toggled from the add menu" />

## Key API

- `icon` — always drawn; the pill's whole identity in the icon-only
form.
- `label` — always the pill's accessible name, painted only in the
labeled form.
- `onRemove` — removal intent from the X; null leaves the X off
entirely.
- `onTap` — optional tap on the pill's body, e.g. reopening the tool's
options; null leaves the body inert.
- `removeTooltip`, `tooltip` — host-localized; the X's name, and the
body's hover.
- `showLabel` — null resolves by platform; `true`/`false` forces.
- `enabled` — explicit disabling; static and disabled are different
states.
- `padding` (the design's 8 horizontally) and `borderRadius` (8)
override the metrics.
1 change: 1 addition & 0 deletions docs/src/content/docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ elements and the remaining AI states are on the way.
| Code block | <span class="badge-done">Shipped</span> |
| Thinking indicator | <span class="badge-done">Shipped</span> |
| Shimmer | <span class="badge-done">Shipped</span> |
| Pill | <span class="badge-done">Shipped</span> |

## Surfaces

Expand Down
1 change: 1 addition & 0 deletions lib/flow_ui.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export 'src/widgets/flow_menu_style.dart';
export 'src/widgets/flow_message.dart';
export 'src/widgets/flow_model_selector.dart';
export 'src/widgets/flow_message_actions.dart';
export 'src/widgets/flow_pill.dart';
export 'src/widgets/flow_shimmer_text.dart';
export 'src/widgets/flow_streaming_text.dart';
export 'src/widgets/flow_suggestion.dart';
Expand Down
Loading