ComponentsAgent patterns

Canvas

Shows results next to the chat: tables, calendar reads, plans, charts, and web pages. Each result gets a tab. When the split is narrower than 720px, or the screen is phone-sized, the canvas opens as a full sheet instead.

Canvas playgroundChat with results open beside it.

Launch week planning

Pull this week’s new customers, my calendar, and the pipeline for launch week.

Here is what I found. Open a result to see the details.

Customers

Table2 added and 1 updated

Calendar events

CalendarSaved read · Not a pending action

Weekly pipeline

FilePreparing

Usage

Chat with a canvasTSX
import {
  CanvasPanel,
  CanvasSection,
  CanvasToggle,
  ChatSplit,
} from "@tulipfarm/sprout/canvas";
import { Database } from "reicon-react/icons/Database";

<header>
  <h1>Launch week planning</h1>
  <CanvasToggle open={open} count={items.length} onToggle={() => setOpen(!open)} />
</header>
<ChatSplit
  open={open}
  onOpenChange={setOpen}
  layoutId="launch-week"
  chat={<Conversation />}
  canvas={
    <CanvasPanel
      tabs={items.map((item) => ({
        id: item.id,
        title: item.title,
        icon: Database,
        busy: item.loading,
      }))}
      activeId={activeId}
      onSelect={setActiveId}
      onCloseTab={closeItem}
      onClose={() => setOpen(false)}
    >
      {items.map((item) => (
        <div key={item.id} hidden={item.id !== activeId}>
          <CanvasSection title={item.title} meta="3 rows">
            <RowsTable rows={item.rows} />
          </CanvasSection>
        </div>
      ))}
    </CanvasPanel>
  }
/>

  • ChatSplit: open, onOpenChange,chat, canvas, and an optionallayoutId that saves the split size per screen. The canvas can be null or false while nothing is open.
  • CanvasPanel: tabs (id,title, optional icon and busy),activeId, onSelect, onCloseTab,onClose, and an optional activity strip under the header. With no tabs the header reads “Canvas”.
  • CanvasToggle: open, count, andonToggle. It reads “View results” or “Hide results”, and shows the count when results are open.
  • CanvasSection: optional title,meta, and actions. Leave all three out to just pad and stack content.
  • CanvasFrame: src and title. The page runs in a sandbox with scripts and popups only, and sends no referrer.
  • canvasSplitMinWidth is 720. Compare it with the width of [data-slot="chat-split"] to know whether the canvas is a sheet.

Toggle

Sits in the screen header. Each state below is from a TulipFarm screen.

Canvas toggleBelow 640px only the icon and count show.
Closed, nothing open

New chat

Closed, 3 results

Launch week planning

Open, 1 result

Add customer storage

Interactive

Review a workflow

Sections

Every section shape a TulipFarm result uses: with and without a title, meta, and actions, plus loading, empty, unavailable, and error content.

Title, meta, and one action · calendar read

Google Calendar

  • Mon 9:30 AMLaunch stand-upGoogle Meet
  • Tue 2:00 PMPricing review with financeRoom 4B
  • Thu 11:00 AMPress briefing dry runGoogle Meet

Events may have changed since this read. Ask in chat to read the calendar again.

Title and two actions · changed rows
  • 2 added
  • 1 updated
ChangeNameEmailCompanyStatus
AddedAda Parkada@northwind.coNorthwindProspect
AddedRui Costarui@lumen.studioLumen StudioActive
UpdatedMia Chenmia@harbor.ioHarborInactive
Title and meta · schema proposal

Customer storage

Not yet applied
Long meta that wraps · recorded activity

Recorded activity

Google Drive

  • Completed:Searched Drive for “Q3 launch”

Slack

  • Completed:Posted the launch summary to #marketing
  • Unconfirmed:Reply in the press thread
Title only · table changed

Table changed

These fields have changed

This saved query uses an older table definition. Open the current table, or ask for these rows again.

Loading · preparing a result

Weekly pipeline

No title · plan or code wrapper

Launch checklist

2 of 4 done
  1. Draft the announcement post, done
  2. Book the press briefing, done
  3. Update the pricing page, to do
  4. Email the beta customers, to do
No title · state panel
Empty read

Google Calendar

No events in this read

This completed read returned no events. Ask in chat to read a different date range.

Events may have changed since this read. Ask in chat to read the calendar again.

Bare error, without a section

Ask again in the chat.

Browser frame

Shows a web page inside the canvas with a link to open it in a new tab.

Browser previewA sandboxed frame inside a section with the URL as meta.

Pricing page

In TulipFarm

Approval review, workflow review, result cards, and a two-tab example. Each keeps its own saved split size.

Approval reviewOne fixed tab whose title follows the outcome. A custom body, without a section.

Add customer storage

Create a Customers table with Name, Email, Company, Phone, and Status.

Here are the changes for your review.

Workflow reviewClose the tab: the canvas stays open with no tabs and an empty state.

Review a workflow

Notify #engineering whenever a pull request is opened. Include its title, author, and link.

The workflow is ready to review. Select a step in Canvas to see what it does.

New pull request alert

3 steps / view only

Result cardsThe canvas exists only while a result is selected. Closing clears it.

App result cards

Show me the results for the pitch and the investor update.

Your work is ready. Open a result to see the details.

Investor pitch

FileSaved in Google Slides

Investor update

ActionSent from Gmail
Cards in a sectionTwo closable tabs. Reset brings them back.

A fictional conversation. The canvas shows a visual result, not another transcript.

Keyboard and accessibility

  • Tabs use one tab stop. ← and → move between tabs and wrap. Home and End jump to the first and last tab. Delete closes the focused tab and moves focus to the next one.
  • Esc anywhere in the canvas closes it. On a sheet, focus returns to whatever opened it.
  • The resize handle is a focusable separator labelled “Resize canvas”. Arrow keys resize it.
  • A busy tab shows a spinner and reads “loading”. The spinner stops when reduced motion is on.
  • On touch screens the close buttons stay visible and grow to 32px.