What kind of request is this
A variant or option on an existing component
The problem
The composer can show attachments but offers no way to add them. FlowComposer.attachments renders the strip, remove and preview work, and that is the whole story: there is no attach button, no drag and drop, no paste. Hosts wedge an "Add" option into a FlowMenu (the playground does exactly this) and build the rest themselves. Attaching a file is a core chat gesture, and the package is silent on it.
The constraint to design around: file picking and OS drop events live in platform plugins (file_picker, image_picker, desktop_drop), and the package ships zero third-party dependencies. So flow_ui cannot pick files. It can own the affordances, the drop-state visuals, and the intent seams, and let the host own the platform work. State in, intent out, as everywhere.
What you'd like
Three pieces, each independently useful:
1. An attach affordance on the composer. A first-class paperclip in the action bar that reports intent. The host opens whatever picker it likes and passes the result back as attachments.
FlowComposer(
onSend: send,
onAttach: pickFiles, // null hides the affordance, as with onStop
attachTooltip: 'Add files', // host-localized, doubles as the accessible name
attachments: picked, // state in, as today
)
2. The drop-target treatment on the chat surface. The visual half of drag and drop: a highlight state over the composer (or the whole FlowChatView) with a host-written label ("Drop files to attach"). Driven by host state, so it works with whatever drop detection the host has:
FlowChatView(
dropActive: dragging, // host flips it from its drop region
dropLabel: 'Drop files to attach',
composer: ...,
)
3. Native drop and paste where the SDK allows. If Flutter's own APIs can detect OS file drops or clipboard images on a given platform without a plugin, wire them to an onDropFiles / onPasteFiles intent so the host only handles the data. Where the SDK cannot, pieces 1 and 2 still make the host's plugin integration a few lines.
Decisions to settle
- Where the drop treatment lives: composer-only (files land in the input) or the whole chat surface (the larger target every desktop chat app uses). Leaning whole surface, rendered by
FlowChatView.
- What crosses the intent seam for drops and paste: platform file handles are plugin territory, so probably nothing. The host detects the drop, reads the files, and passes
FlowAttachments in. Piece 3 is only worth building if the SDK genuinely covers a platform.
- Whether the attach affordance joins
leadingActions as a packaged widget (FlowAttachButton) or becomes a built-in slot on the composer like send/stop. Leaning built-in: it should sit in the design's position without host layout work.
- Style: fold the affordance's colors into
FlowComposerStyle, and the drop overlay's into a couple of new fields there or on the chat view. No new style class unless the overlay grows.
Accessibility
The attach affordance takes attachTooltip as its accessible name. The drop overlay announces when it appears. Keyboard users get the same path as everyone: the affordance is focusable and the picker flow never depends on dragging.
Definition of done
What you're doing instead
An "Add to Chat" FlowMenu in leadingActions plus a hand-rolled picker and drop region in the host, with no drop-state visuals. Works, but every host rebuilds the same affordance and overlay, and the composer looks incomplete next to any production chat app. For reference: assistant-ui, ChatGPT, and Claude all ship the paperclip plus a full-surface drop target.
What kind of request is this
A variant or option on an existing component
The problem
The composer can show attachments but offers no way to add them.
FlowComposer.attachmentsrenders the strip, remove and preview work, and that is the whole story: there is no attach button, no drag and drop, no paste. Hosts wedge an "Add" option into aFlowMenu(the playground does exactly this) and build the rest themselves. Attaching a file is a core chat gesture, and the package is silent on it.The constraint to design around: file picking and OS drop events live in platform plugins (
file_picker,image_picker,desktop_drop), and the package ships zero third-party dependencies. So flow_ui cannot pick files. It can own the affordances, the drop-state visuals, and the intent seams, and let the host own the platform work. State in, intent out, as everywhere.What you'd like
Three pieces, each independently useful:
1. An attach affordance on the composer. A first-class paperclip in the action bar that reports intent. The host opens whatever picker it likes and passes the result back as
attachments.2. The drop-target treatment on the chat surface. The visual half of drag and drop: a highlight state over the composer (or the whole
FlowChatView) with a host-written label ("Drop files to attach"). Driven by host state, so it works with whatever drop detection the host has:3. Native drop and paste where the SDK allows. If Flutter's own APIs can detect OS file drops or clipboard images on a given platform without a plugin, wire them to an
onDropFiles/onPasteFilesintent so the host only handles the data. Where the SDK cannot, pieces 1 and 2 still make the host's plugin integration a few lines.Decisions to settle
FlowChatView.FlowAttachments in. Piece 3 is only worth building if the SDK genuinely covers a platform.leadingActionsas a packaged widget (FlowAttachButton) or becomes a built-in slot on the composer like send/stop. Leaning built-in: it should sit in the design's position without host layout work.FlowComposerStyle, and the drop overlay's into a couple of new fields there or on the chat view. No new style class unless the overlay grows.Accessibility
The attach affordance takes
attachTooltipas its accessible name. The drop overlay announces when it appears. Keyboard users get the same path as everyone: the affordance is focusable and the picker flow never depends on dragging.Definition of done
FlowComposer.onAttach+attachTooltip, affordance hidden when nulldropActive+dropLabel) on the agreed surfacedropActivefile_pickerand a drop plugin through the seamsWhat you're doing instead
An "Add to Chat"
FlowMenuinleadingActionsplus a hand-rolled picker and drop region in the host, with no drop-state visuals. Works, but every host rebuilds the same affordance and overlay, and the composer looks incomplete next to any production chat app. For reference: assistant-ui, ChatGPT, and Claude all ship the paperclip plus a full-surface drop target.