@cool-ai/beach-a2ui-patterns
v0.1.3
Published
Curated surface-composition helpers for Beach A2UI — productCard, narrativePanel, searchResultList, and more. Returns SurfaceCommand[] against the A2UI v0.9 basic catalog.
Downloads
301
Readme
@cool-ai/beach-a2ui-patterns
Pre-built A2UI surface patterns for Beach agents. Each pattern returns a SurfaceCommand[] ready to send via context.routeEvent — no manual createSurface/updateComponents wiring needed.
Home: cool-ai.org · Documentation: cool-ai.org/docs
Install
npm install @cool-ai/beach-a2ui-patterns @cool-ai/beach-a2ui@cool-ai/beach-a2ui is a peer dependency.
Patterns
productCard
A titled card with labelled line items and a bold total row, separated by a divider. Renders identically via A2UI browser renderer, renderToHtml (email), and renderToText (WhatsApp / SMS).
import { productCard } from '@cool-ai/beach-a2ui-patterns';
const cmds = productCard({
surfaceId: 'order-123',
title: 'Your Order',
items: [
{ label: 'Flight LHR-FCO', amount: '£299' },
{ label: 'Hotel Centro', amount: '$1,200' },
],
total: { label: 'Total', amount: '£1,499' },
});| Option | Type | Description |
|---|---|---|
| surfaceId | string | Unique surface id. |
| title | string | Card heading. |
| items | ProductCardLine[] | Line items shown above the divider. |
| total | ProductCardLine | Total row shown below the divider in bold. |
ProductCardLine has label: string and amount: string.
narrativePanel
A heading plus prose body. The simplest pattern: one card, one heading, one paragraph. Channel-neutral.
import { narrativePanel } from '@cool-ai/beach-a2ui-patterns';
const cmds = narrativePanel({
surfaceId: 'summary-panel',
heading: 'Your trip summary',
body: 'Your Paris flights are confirmed. Check in opens 24 hours before departure.',
level: 2, // optional, defaults to 2
});| Option | Type | Description |
|---|---|---|
| surfaceId | string | Unique surface id. |
| heading | string | Panel heading. |
| body | string | Prose body text. |
| level | 1 \| 2 \| 3 \| 4 | Heading level. Defaults to 2. |
searchResultList
A ranked list of results. Each result renders as a card with a heading-styled title, optional caption-styled subtitle, and an optional star-rating Text (★/☆ characters). An empty-state Text is shown when the results array is empty.
import { searchResultList } from '@cool-ai/beach-a2ui-patterns';
const cmds = searchResultList({
surfaceId: 'hotel-results',
results: [
{ id: 'hotel-1', title: 'Hotel Centro', subtitle: 'Florence, IT', score: 4.5 },
{ id: 'hotel-2', title: 'Pensione Canova', subtitle: 'Florence, IT' },
],
emptyText: 'No hotels found for your dates.', // optional
});| Option | Type | Description |
|---|---|---|
| surfaceId | string | Unique surface id. |
| results | SearchResult[] | Ordered results. |
| emptyText | string | Empty-state text. Defaults to "No results found." |
SearchResult fields:
| Field | Type | Description |
|---|---|---|
| id | string | Stable per-result key. Used as the component-id segment for the result's card and its descendants (e.g. ${surfaceId}/result/${id}), so ids stay stable across re-renders even if the list reorders. |
| title | string | Primary title. |
| subtitle | string? | Optional secondary line, rendered as a caption-variant Text. |
| score | number? | Optional numeric score (0–5). A2UI v0.9's basic catalog has no Rating component, so the score is rendered as a caption-variant Text containing ★/☆ characters rounded to the nearest integer. |
Testing patterns
Use @cool-ai/beach-a2ui-test to assert on pattern output without reaching into raw message JSON:
import { surfaceOf } from '@cool-ai/beach-a2ui-test';
import { productCard } from '@cool-ai/beach-a2ui-patterns';
const s = surfaceOf(productCard({ ... }));
expect(s.find('Card')).toMatchObject({ title: 'Your Order' });
expect(s.findAll('Row')).toHaveLength(3); // 2 items + 1 total
expect(s.find('Divider')).toBeDefined();Constants
import { A2UI_BASIC_CATALOG_ID } from '@cool-ai/beach-a2ui-patterns';
// 'https://a2ui.org/specification/v0_9/basic_catalog.json'All patterns use the A2UI v0.9 basic catalog. Pass A2UI_BASIC_CATALOG_ID whenever you need the catalog id string directly.
