@terreno/mcp 57.8.0 → 57.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/docs/upgrades/57.10.1.md +54 -0
- package/dist/docs/upgrades/57.9.0.md +28 -0
- package/dist/docs/versioned/next/README.md +1 -0
- package/dist/docs/versioned/next/explanation/README.md +4 -0
- package/dist/docs/versioned/next/explanation/admin-plugin-frontend.md +2 -2
- package/dist/docs/versioned/next/explanation/agent-ui-asks.md +299 -0
- package/dist/docs/versioned/next/explanation/agent-ui-blocks.md +67 -0
- package/dist/docs/versioned/next/explanation/ai-observability.md +101 -0
- package/dist/docs/versioned/next/explanation/charts.md +12 -0
- package/dist/docs/versioned/next/explanation/durable-agent-harness.md +531 -0
- package/dist/docs/versioned/next/explanation/example-coverage.md +4 -2
- package/dist/docs/versioned/next/explanation/loop-engineering.md +1 -1
- package/dist/docs/versioned/next/explanation/roadmap-seed-issues.md +49 -1
- package/dist/docs/versioned/next/explanation/typescript-configuration.md +1 -1
- package/dist/docs/versioned/next/explanation/versioning-policy.md +1 -1
- package/dist/docs/versioned/next/how-to/README.md +7 -1
- package/dist/docs/versioned/next/how-to/admin-import-prebuilt.md +1 -1
- package/dist/docs/versioned/next/how-to/agent-ui-asks.md +730 -0
- package/dist/docs/versioned/next/how-to/agent-ui-blocks.md +104 -0
- package/dist/docs/versioned/next/how-to/ai-feature-development.md +156 -0
- package/dist/docs/versioned/next/how-to/build-a-durable-workflow.md +232 -0
- package/dist/docs/versioned/next/how-to/charts-and-dashboards.md +7 -0
- package/dist/docs/versioned/next/how-to/circleci.md +9 -6
- package/dist/docs/versioned/next/how-to/compare-chart-rendered-snapshots.md +8 -0
- package/dist/docs/versioned/next/how-to/install-agent-skills.md +1 -1
- package/dist/docs/versioned/next/how-to/observe-llm-calls.md +197 -0
- package/dist/docs/versioned/next/how-to/run-tests-locally.md +2 -1
- package/dist/docs/versioned/next/how-to/ship-a-new-task-version.md +76 -0
- package/dist/docs/versioned/next/how-to/upgrade-terreno.md +1 -1
- package/dist/docs/versioned/next/implementationPlans/agent-ui-asks.md +688 -0
- package/dist/docs/versioned/next/implementationPlans/agent-ui-blocks.md +10 -6
- package/dist/docs/versioned/next/implementationPlans/ai-observability.md +475 -157
- package/dist/docs/versioned/next/implementationPlans/b2b-platform-program.md +1 -1
- package/dist/docs/versioned/next/implementationPlans/charts-and-dashboards.md +3 -2
- package/dist/docs/versioned/next/implementationPlans/dashboard-chart-parity.md +275 -0
- package/dist/docs/versioned/next/implementationPlans/durable-agent-harness.md +340 -0
- package/dist/docs/versioned/next/implementationPlans/terreno-langfuse-integration.md +1 -1
- package/dist/docs/versioned/next/reference/README.md +3 -0
- package/dist/docs/versioned/next/reference/admin-config.md +2 -0
- package/dist/docs/versioned/next/reference/admin-frontend.md +216 -0
- package/dist/docs/versioned/next/reference/agent-ui-asks.md +1059 -0
- package/dist/docs/versioned/next/reference/ai-harness.md +1881 -0
- package/dist/docs/versioned/next/reference/ai.md +283 -28
- package/dist/docs/versioned/next/reference/api.md +46 -0
- package/dist/docs/versioned/next/reference/blocks.md +178 -0
- package/dist/docs/versioned/next/reference/environment-variables.md +2 -1
- package/dist/docs/versioned/next/reference/feature-flags.md +1 -1
- package/dist/docs/versioned/next/reference/mcp-server.md +17 -0
- package/dist/docs/versioned/next/reference/test.md +11 -2
- package/dist/docs/versioned/next/reference/ui.md +418 -11
- package/dist/docs/versioned/next/tasks/agent-ui-asks.md +213 -0
- package/dist/docs/versioned/next/tasks/agent-ui-blocks.md +2 -1
- package/dist/docs/versioned/next/tasks/ai-observability.md +233 -104
- package/dist/docs/versioned/next/tasks/dashboard-chart-parity.md +145 -0
- package/dist/docs/versioned/next/tasks/durable-agent-harness.md +183 -0
- package/dist/tools.d.ts +4 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +37 -0
- package/dist/tools.js.map +1 -1
- package/package.json +3 -2
- package/src/docs/upgrades/57.10.1.md +54 -0
- package/src/docs/upgrades/57.9.0.md +28 -0
- package/src/docs/versioned/next/README.md +1 -0
- package/src/docs/versioned/next/explanation/README.md +4 -0
- package/src/docs/versioned/next/explanation/admin-plugin-frontend.md +2 -2
- package/src/docs/versioned/next/explanation/agent-ui-asks.md +299 -0
- package/src/docs/versioned/next/explanation/agent-ui-blocks.md +67 -0
- package/src/docs/versioned/next/explanation/ai-observability.md +101 -0
- package/src/docs/versioned/next/explanation/charts.md +12 -0
- package/src/docs/versioned/next/explanation/durable-agent-harness.md +531 -0
- package/src/docs/versioned/next/explanation/example-coverage.md +4 -2
- package/src/docs/versioned/next/explanation/loop-engineering.md +1 -1
- package/src/docs/versioned/next/explanation/roadmap-seed-issues.md +49 -1
- package/src/docs/versioned/next/explanation/typescript-configuration.md +1 -1
- package/src/docs/versioned/next/explanation/versioning-policy.md +1 -1
- package/src/docs/versioned/next/how-to/README.md +7 -1
- package/src/docs/versioned/next/how-to/admin-import-prebuilt.md +1 -1
- package/src/docs/versioned/next/how-to/agent-ui-asks.md +730 -0
- package/src/docs/versioned/next/how-to/agent-ui-blocks.md +104 -0
- package/src/docs/versioned/next/how-to/ai-feature-development.md +156 -0
- package/src/docs/versioned/next/how-to/build-a-durable-workflow.md +232 -0
- package/src/docs/versioned/next/how-to/charts-and-dashboards.md +7 -0
- package/src/docs/versioned/next/how-to/circleci.md +9 -6
- package/src/docs/versioned/next/how-to/compare-chart-rendered-snapshots.md +8 -0
- package/src/docs/versioned/next/how-to/install-agent-skills.md +1 -1
- package/src/docs/versioned/next/how-to/observe-llm-calls.md +197 -0
- package/src/docs/versioned/next/how-to/run-tests-locally.md +2 -1
- package/src/docs/versioned/next/how-to/ship-a-new-task-version.md +76 -0
- package/src/docs/versioned/next/how-to/upgrade-terreno.md +1 -1
- package/src/docs/versioned/next/implementationPlans/agent-ui-asks.md +688 -0
- package/src/docs/versioned/next/implementationPlans/agent-ui-blocks.md +10 -6
- package/src/docs/versioned/next/implementationPlans/ai-observability.md +475 -157
- package/src/docs/versioned/next/implementationPlans/b2b-platform-program.md +1 -1
- package/src/docs/versioned/next/implementationPlans/charts-and-dashboards.md +3 -2
- package/src/docs/versioned/next/implementationPlans/dashboard-chart-parity.md +275 -0
- package/src/docs/versioned/next/implementationPlans/durable-agent-harness.md +340 -0
- package/src/docs/versioned/next/implementationPlans/terreno-langfuse-integration.md +1 -1
- package/src/docs/versioned/next/reference/README.md +3 -0
- package/src/docs/versioned/next/reference/admin-config.md +2 -0
- package/src/docs/versioned/next/reference/admin-frontend.md +216 -0
- package/src/docs/versioned/next/reference/agent-ui-asks.md +1059 -0
- package/src/docs/versioned/next/reference/ai-harness.md +1881 -0
- package/src/docs/versioned/next/reference/ai.md +283 -28
- package/src/docs/versioned/next/reference/api.md +46 -0
- package/src/docs/versioned/next/reference/blocks.md +178 -0
- package/src/docs/versioned/next/reference/environment-variables.md +2 -1
- package/src/docs/versioned/next/reference/feature-flags.md +1 -1
- package/src/docs/versioned/next/reference/mcp-server.md +17 -0
- package/src/docs/versioned/next/reference/test.md +11 -2
- package/src/docs/versioned/next/reference/ui.md +418 -11
- package/src/docs/versioned/next/tasks/agent-ui-asks.md +213 -0
- package/src/docs/versioned/next/tasks/agent-ui-blocks.md +2 -1
- package/src/docs/versioned/next/tasks/ai-observability.md +233 -104
- package/src/docs/versioned/next/tasks/dashboard-chart-parity.md +145 -0
- package/src/docs/versioned/next/tasks/durable-agent-harness.md +183 -0
|
@@ -4,12 +4,13 @@ React Native UI component library (a large component library). Layout (Box, Page
|
|
|
4
4
|
|
|
5
5
|
## Key exports
|
|
6
6
|
|
|
7
|
-
- Layout: `Box`, `Page`, `SplitPage`, `Card`, `DashboardGrid`
|
|
7
|
+
- Layout: `Box`, `Page`, `SplitPage`, `Card`, `ChartCard`, `DashboardGrid`, `DashboardGridItem`
|
|
8
8
|
- Forms: `TextField`, `SelectField`, `DateTimeField`, `CheckBox`
|
|
9
|
-
- Display: `Text`, `Heading`, `Badge`, `DataTable`, `LineChart`, `BarChart`, `AreaChart`, `DonutChart`
|
|
9
|
+
- Display: `Text`, `Heading`, `Badge`, `DataTable`, `Scorecard`, `SparklineChart`, `LineChart`, `BarChart`, `AreaChart`, `DonutChart`
|
|
10
10
|
- Actions: `Button`, `IconButton`, `Link`
|
|
11
11
|
- Feedback: `Spinner`, `Modal`, `Toast`
|
|
12
12
|
- Notifications: `NotificationBell`, `NotificationInbox`, `NotificationPreferences`
|
|
13
|
+
- AI chat: `GPTChat`, `AskCard` (agent asks in the transcript), `SimpleAskCard` (an ask's simple card for narrow layouts), `BlocksView` (a whole-reply YAML document)
|
|
13
14
|
- Authentication: `SocialLoginButton`, `LoginScreen`, `SignUpScreen`
|
|
14
15
|
- Theming: `TerrenoProvider`, `useTheme`, custom icon registry (`icons` prop)
|
|
15
16
|
- **Type re-exports:** `StyleProp`, `ViewStyle` (re-exported from react-native to avoid version conflicts)
|
|
@@ -32,11 +33,11 @@ supported and is convenient when startup cost is not material:
|
|
|
32
33
|
import {Box, DataTable, Icon} from "@terreno/ui";
|
|
33
34
|
```
|
|
34
35
|
|
|
35
|
-
Heavy optional widgets (`GPTChat`, `EmojiSelector`, `MarkdownEditor`, consent flows, `LineChart`, `BarChart`, `AreaChart`, `DonutChart`, and related admin tools) are
|
|
36
|
+
Heavy optional widgets (`GPTChat`, `AskCard`, `BlocksView`, `EmojiSelector`, `MarkdownEditor`, consent flows, `ChartCard`, `Scorecard`, `SparklineChart`, `LineChart`, `BarChart`, `AreaChart`, `DonutChart`, and related admin tools) are
|
|
36
37
|
re-exported from the root entry through lazy boundaries. Importing them from `@terreno/ui` stays type-compatible, but
|
|
37
38
|
their implementation modules load on first render instead of during the initial root import. `DashboardGrid` stays eager.
|
|
38
|
-
|
|
39
|
-
`
|
|
39
|
+
`MarkdownView` and `DataTable` header info defer `react-native-markdown-display`;
|
|
40
|
+
`EmojiSelector` defers `emoji-datasource` until open.
|
|
40
41
|
|
|
41
42
|
For the smallest cold-start graph, keep using subpaths for screens that only need a few primitives (for example
|
|
42
43
|
`import {Button} from "@terreno/ui/Button"`).
|
|
@@ -60,21 +61,72 @@ const customStyle: StyleProp<ViewStyle> = {
|
|
|
60
61
|
- Ensures type compatibility when passing styles to @terreno/ui components
|
|
61
62
|
- Simplifies imports (one package instead of two)
|
|
62
63
|
|
|
63
|
-
### DashboardGrid
|
|
64
|
+
### DashboardGrid and DashboardGridItem
|
|
64
65
|
|
|
65
66
|
Eager layout-only wrapping grid. Default columns `{sm: 1, md: 2, lg: 3}`. Children stay caller-supplied `Card`s. Cell width is `(rowWidth - gap × (columns - 1)) / columns` so flex `gap` does not wrap extra columns.
|
|
67
|
+
Wrap a child in `DashboardGridItem` when it must span more than one responsive column.
|
|
68
|
+
Plain children remain one column.
|
|
66
69
|
|
|
67
70
|
```tsx
|
|
68
|
-
<DashboardGrid>
|
|
71
|
+
<DashboardGrid columns={{sm: 1, md: 2, lg: 4}}>
|
|
72
|
+
<DashboardGridItem span={{sm: 1, md: 2, lg: 2}}>
|
|
73
|
+
<Card>
|
|
74
|
+
<LineChart data={points} legendLabel="Signups" />
|
|
75
|
+
</Card>
|
|
76
|
+
</DashboardGridItem>
|
|
69
77
|
<Card>
|
|
70
78
|
<LineChart data={points} legendLabel="Signups" />
|
|
71
79
|
</Card>
|
|
72
80
|
</DashboardGrid>
|
|
73
81
|
```
|
|
74
82
|
|
|
83
|
+
### ChartCard
|
|
84
|
+
|
|
85
|
+
Card chrome for a chart or table: title, optional filter summary, and an optional period
|
|
86
|
+
badge. Pass `onPeriodPress` to make the badge a button; omit it for display-only copy.
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
<ChartCard title="Cost by Device" periodLabel="Last 30 days">
|
|
90
|
+
<DonutChart data={points} />
|
|
91
|
+
</ChartCard>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Scorecard
|
|
95
|
+
|
|
96
|
+
Compact KPI tile with a title, formatted value, and optional current/comparison
|
|
97
|
+
sparkline. Numeric values use `formatValue`; string values render unchanged.
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
<Scorecard
|
|
101
|
+
title="Cost"
|
|
102
|
+
value={569}
|
|
103
|
+
formatValue={(value) => `$${value}`}
|
|
104
|
+
sparklineData={current}
|
|
105
|
+
comparisonData={previous}
|
|
106
|
+
/>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### SparklineChart
|
|
110
|
+
|
|
111
|
+
Plot-only line chart for compact metrics. `data` draws the current solid line;
|
|
112
|
+
`comparisonData` draws a dotted previous-period line on the same scale. It has no axes,
|
|
113
|
+
grid, legend, tooltip row, or empty-state copy.
|
|
114
|
+
|
|
115
|
+
```tsx
|
|
116
|
+
<SparklineChart
|
|
117
|
+
data={[{label: "Mon", value: 3}, {label: "Tue", value: 5}]}
|
|
118
|
+
comparisonData={[{label: "Mon", value: 4}, {label: "Tue", value: 4}]}
|
|
119
|
+
/>
|
|
120
|
+
```
|
|
121
|
+
|
|
75
122
|
### LineChart
|
|
76
123
|
|
|
77
|
-
|
|
124
|
+
Line chart drawn with `react-native-svg`. Keep the simple `data` + `legendLabel` path for
|
|
125
|
+
one series, or pass named `series` for multiple lines and legend items.
|
|
126
|
+
`comparisonData` adds a dotted previous-period overlay on the shared scale. Empty data
|
|
127
|
+
shows `emptyText` (default `"No data"`). `loading` shows a `Spinner`.
|
|
128
|
+
Set `xTickPolicy` to `auto` (default), `rotate`, or `truncate`. `title`,
|
|
129
|
+
`periodLabel`, and `onPeriodPress` use the same header chrome as `ChartCard`.
|
|
78
130
|
|
|
79
131
|
```tsx
|
|
80
132
|
<LineChart
|
|
@@ -88,7 +140,10 @@ Hit targets use `Box` `onClick`, so testIDs are `{testID}.point.{index}-clickabl
|
|
|
88
140
|
|
|
89
141
|
### BarChart
|
|
90
142
|
|
|
91
|
-
|
|
143
|
+
Bar chart on the same owned-SVG contract as `LineChart` (empty, loading, legend,
|
|
144
|
+
tooltip, tick policy, and header shortcuts). `comparisonData` paints lighter bars behind
|
|
145
|
+
the current period. When `series` is passed in this facade, its first entry supplies the
|
|
146
|
+
bars and legend; grouped bars remain future work.
|
|
92
147
|
|
|
93
148
|
```tsx
|
|
94
149
|
<BarChart
|
|
@@ -101,6 +156,8 @@ Single-series bar chart on the same owned-SVG contract as `LineChart` (empty, lo
|
|
|
101
156
|
### AreaChart
|
|
102
157
|
|
|
103
158
|
Filled area plus line on the same owned-SVG contract as `LineChart`.
|
|
159
|
+
Named `series` render one fill/line pair and legend item each; `comparisonData` stays a
|
|
160
|
+
dotted line rather than a filled area.
|
|
104
161
|
|
|
105
162
|
```tsx
|
|
106
163
|
<AreaChart
|
|
@@ -112,11 +169,16 @@ Filled area plus line on the same owned-SVG contract as `LineChart`.
|
|
|
112
169
|
|
|
113
170
|
### DonutChart
|
|
114
171
|
|
|
115
|
-
One slice per `{label, value}` point. Per-slice `color` overrides the theme paint.
|
|
172
|
+
One slice per `{label, value}` point. Per-slice `color` overrides the theme paint.
|
|
173
|
+
Legend rows show label + percent by default; customize with `formatShare`.
|
|
174
|
+
`centerValue` and `centerTitle` put an aggregate in the donut hole. `title` /
|
|
175
|
+
`periodLabel` use `ChartCard` chrome (`legendLabel` remains ignored).
|
|
116
176
|
|
|
117
177
|
```tsx
|
|
118
178
|
<DonutChart
|
|
119
179
|
data={[{label: "Open", value: 3}, {color: "#112233", label: "Closed", value: 5}]}
|
|
180
|
+
centerValue="8"
|
|
181
|
+
centerTitle="Total"
|
|
120
182
|
testID="status-donut"
|
|
121
183
|
/>
|
|
122
184
|
```
|
|
@@ -189,6 +251,26 @@ Buttons automatically size to their content unless `fullWidth` is specified:
|
|
|
189
251
|
|
|
190
252
|
Internally, Button sets `alignSelf: 'flex-start'` when `fullWidth={false}` to prevent stretching in column layouts.
|
|
191
253
|
|
|
254
|
+
A label stays on one line by default, so a long label can make the button wider than its container.
|
|
255
|
+
Set `wrapText` to keep the button inside its container instead: the label wraps onto centered lines
|
|
256
|
+
and the button grows taller. A `size="sm"` button grows from its 28px height instead of clipping the
|
|
257
|
+
second line. `SimpleAskCard` and `AskCard` set `wrapText` on their answer buttons, because their
|
|
258
|
+
labels come from the agent.
|
|
259
|
+
|
|
260
|
+
```tsx
|
|
261
|
+
<Box direction="row" width={160}>
|
|
262
|
+
<Button onClick={handleSave} text="Save all changes now" wrapText />
|
|
263
|
+
</Box>
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### TextField grow and maxHeight
|
|
267
|
+
|
|
268
|
+
`grow` makes a multiline field expand with its content. Pair it with `maxHeight` (pixels) to cap the expansion; past the cap the content scrolls.
|
|
269
|
+
|
|
270
|
+
```tsx
|
|
271
|
+
<TextArea grow maxHeight={200} onChange={setNotes} value={notes} />
|
|
272
|
+
```
|
|
273
|
+
|
|
192
274
|
### TextField password visibility
|
|
193
275
|
|
|
194
276
|
`type="password"` masks the value and renders a show/hide eye control at the end of the field.
|
|
@@ -295,7 +377,15 @@ Streaming chat surface for `@terreno/ai`. Histories, messages, submit, and optio
|
|
|
295
377
|
|
|
296
378
|
Pass `mascot` when the app owns a character. Terreno ships none. The node renders only while `currentMessages` is empty, centered in the chat panel above the suggested prompts. The empty hero uses the message viewport height as a minimum so short content stays centered, while taller mascots still scroll. Streaming feedback shares that centered hero instead of creating a second pane. Omit the prop for the default empty chat.
|
|
297
379
|
|
|
298
|
-
The composer row (attachment picker, tools, input, Send) is vertically centered, so controls stay aligned with the input as it grows. The attachment cell is omitted when `onAttachFiles` is not provided.
|
|
380
|
+
The composer row (attachment picker, tools, input, Send) is vertically centered, so controls stay aligned with the input as it grows. The composer input grows with its text up to 200px, then scrolls. The attachment cell is omitted when `onAttachFiles` is not provided.
|
|
381
|
+
|
|
382
|
+
Each history row keeps rename and delete in a three-dot overflow menu (`gpt-history-menu-{id}`), anchored with `DropdownPanel`. Rename uses an outlined pencil in the dark secondary text color. Titles truncate before the menu trigger, so the trigger stays aligned at any sidebar width.
|
|
383
|
+
|
|
384
|
+
"Scroll to bottom" appears only when content sits more than 100px below the viewport. It never shows in an empty chat.
|
|
385
|
+
|
|
386
|
+
Image content parts render copy-image and (web) download actions. The message copy button on an image-only reply copies the image, not text. On web the image is written to the clipboard as PNG; on native it uses `expo-clipboard` `setImageAsync` for `data:` URLs.
|
|
387
|
+
|
|
388
|
+
The attach control (`FilePickerButton`) opens an anchored dropdown with **Photo Library** and **Document**. On web both open a browser file input from the press itself and return `data:` URLs, so attachments survive a reload; on native they use `expo-image-picker` and `expo-document-picker`.
|
|
299
389
|
|
|
300
390
|
```tsx
|
|
301
391
|
<GPTChat
|
|
@@ -313,10 +403,321 @@ The composer row (attachment picker, tools, input, Send) is vertically centered,
|
|
|
313
403
|
/>
|
|
314
404
|
```
|
|
315
405
|
|
|
406
|
+
Pass `uiBlocks` to render each assistant message through `BlocksView`. A streaming message
|
|
407
|
+
shows each finished top-level block and a spinner for the block still arriving. `reply`
|
|
408
|
+
calls `onSubmit` with the button text. `open` and `select` call `onBlockAction`. `callback`
|
|
409
|
+
calls `onBlockCallback` and the button stays loading until that promise settles. Return
|
|
410
|
+
`{replace: "block", blocks}` to swap that block, or `{text}` to place an assistant message
|
|
411
|
+
immediately after the message that started the callback. A result that arrives after
|
|
412
|
+
`currentHistoryId` changes is dropped. `hostActions` disables callback names the host did
|
|
413
|
+
not list. `resolveDataset` loads `ref` datasets. `resolveImage` turns a `file:` image id
|
|
414
|
+
into a URL.
|
|
415
|
+
|
|
416
|
+
```tsx
|
|
417
|
+
<GPTChat
|
|
418
|
+
currentMessages={messages}
|
|
419
|
+
histories={histories}
|
|
420
|
+
hostActions={["export_csv"]}
|
|
421
|
+
onBlockAction={handleBlockAction}
|
|
422
|
+
onBlockCallback={handleBlockCallback}
|
|
423
|
+
onCreateHistory={onCreateHistory}
|
|
424
|
+
onDeleteHistory={onDeleteHistory}
|
|
425
|
+
onSelectHistory={onSelectHistory}
|
|
426
|
+
onSubmit={onSubmit}
|
|
427
|
+
uiBlocks
|
|
428
|
+
/>
|
|
429
|
+
```
|
|
430
|
+
|
|
316
431
|
Operator steps: [Add a GPT chat mascot](../how-to/add-gpt-chat-mascot.md). Demo story: `GPTChat` → `Mascot`.
|
|
432
|
+
Blocks playground: `BlocksPlayground`.
|
|
317
433
|
The example AI screen demonstrates a consumer selecting one of four bundled mascot
|
|
318
434
|
images once per mount.
|
|
319
435
|
|
|
436
|
+
#### Asks
|
|
437
|
+
|
|
438
|
+
`GPTChat` shows an [agent ask](agent-ui-asks.md) as an `AskCard` in the transcript. Set `ask` on
|
|
439
|
+
the ask's `tool-call` message and pass `onAskSubmit`:
|
|
440
|
+
|
|
441
|
+
```tsx
|
|
442
|
+
<GPTChat
|
|
443
|
+
askErrors={askErrors}
|
|
444
|
+
currentMessages={currentMessages}
|
|
445
|
+
histories={histories}
|
|
446
|
+
onAskSubmit={handleAskSubmit}
|
|
447
|
+
onCreateHistory={onCreateHistory}
|
|
448
|
+
onDeleteHistory={onDeleteHistory}
|
|
449
|
+
onSelectHistory={onSelectHistory}
|
|
450
|
+
onSubmit={onSubmit}
|
|
451
|
+
/>
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
| Prop or field | Type | Description |
|
|
455
|
+
| --- | --- | --- |
|
|
456
|
+
| `GPTChatMessage.ask` | `ChatAsk` | On a `tool-call` message: the ask (`kind`, `input`), its `toolCallId`, `status` (`pending`, `answered`, or `cancelled`), and optional `response` and `simple` card. The chat shows an `AskCard` instead of the tool call. |
|
|
457
|
+
| `onAskSubmit` | `(submission: {toolCallId, response}) => void \| Promise<void>` | Called when the user answers a pending ask. `response` is the answer envelope. The pressed control shows a loading state until the promise settles. Without it, asks show but cannot be answered. |
|
|
458
|
+
| `askErrors` | `Record<string, AskValidationError[]>` | Errors for the last answer to each ask, keyed by tool call id, such as the `fields` of a 400 `Invalid askResponse`. Shown inside the card. |
|
|
459
|
+
| `resolveAskFiles` | `AskFilesResolver` | Turns the files picked for a `files` ask into the refs its answer sends. Defaults to `resolveAskFilesAsDataUrls`. Pass an uploader to send `{fileId}` refs; see [Accept uploads with or without GCS](../how-to/agent-ui-asks.md#accept-uploads-with-or-without-gcs). |
|
|
460
|
+
|
|
461
|
+
- The ask's `tool-result` message stays in `currentMessages` but is not shown. Keep it: message
|
|
462
|
+
indexes must match the stored `prompts` rows that ratings use. When `ask.response` is unset, the
|
|
463
|
+
card reads the answer from that message.
|
|
464
|
+
- A pending ask takes focus when it appears: DOM focus on the card, labelled with the ask's
|
|
465
|
+
`title`, on web; accessibility focus on the question, an accessibility header, on native.
|
|
466
|
+
- Answered and cancelled asks collapse to a one-line summary.
|
|
467
|
+
|
|
468
|
+
The example AI screen, `example-frontend/app/(tabs)/ai.tsx`, handles the stream events, saved
|
|
469
|
+
rows, answers, and errors. Steps: [Add agent asks to a chat](../how-to/agent-ui-asks.md).
|
|
470
|
+
|
|
471
|
+
### BlocksView
|
|
472
|
+
|
|
473
|
+
`BlocksView` paints a whole-reply document from `@terreno/blocks`. Pass the assistant text
|
|
474
|
+
as `document`. Leaf blocks in this slice are `heading`, `text`, `metric`, `badge`,
|
|
475
|
+
`divider`, and `context`. `columns` is a row from the `md` breakpoint and a stack on `sm`.
|
|
476
|
+
`card` groups children under an optional title. A `callout` draws `Banner` and is not dismissible. An `image` draws `Image` and requires `alt`; pass `imageHosts` to allow `https` hosts. A `details` block draws `Accordion`. A `chart` draws `LineChart`, `BarChart`,
|
|
477
|
+
`AreaChart`, or `DonutChart` from an inline dataset or from `points`. The series is only
|
|
478
|
+
`{label, value}` — a point color in the document is not passed through. A `table` draws
|
|
479
|
+
`DataTable`. A `ref` dataset stays empty until `resolveDataset` returns its rows, and the
|
|
480
|
+
chart shows `loading` while that promise is in flight. A rejected fetch clears that
|
|
481
|
+
loading state. A segmented control highlights the option whose `data` matches the target
|
|
482
|
+
chart or table. A `select` action switches a table the same way it switches a chart.
|
|
483
|
+
An image `file:` ref is not passed to `Image` until `resolveImage` returns a URL; the
|
|
484
|
+
alt text still shows.
|
|
485
|
+
|
|
486
|
+
A string that is not a document becomes one `text` block. A document that fails
|
|
487
|
+
`validateBlocks` shows a `Banner` with the first three errors and the raw text inside a
|
|
488
|
+
collapsed `Accordion`.
|
|
489
|
+
|
|
490
|
+
An `actions` block draws `Button` and `SegmentedControl`. `onAction` receives
|
|
491
|
+
`{action, blockId, elementId}` for reply, open, select, and callback. A `select`
|
|
492
|
+
action also stores the chosen dataset on the target chart for this view. Pass
|
|
493
|
+
`hostActions` to disable callback buttons whose names are not in that list. Omit
|
|
494
|
+
`hostActions` and every callback stays enabled. `pendingElementIds` shows those
|
|
495
|
+
buttons as loading. `overrides` replaces a block by id.
|
|
496
|
+
|
|
497
|
+
```tsx
|
|
498
|
+
<BlocksView
|
|
499
|
+
document={reply}
|
|
500
|
+
hostActions={["export_csv"]}
|
|
501
|
+
onAction={handleAction}
|
|
502
|
+
testID="assistant-blocks"
|
|
503
|
+
/>
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
Demo story: `BlocksView`.
|
|
507
|
+
|
|
508
|
+
### HtmlFrame
|
|
509
|
+
|
|
510
|
+
`HtmlFrame` paints one `html` block. On web it is an `<iframe sandbox="" referrerpolicy="no-referrer">` whose `srcdoc` starts with a Content-Security-Policy meta tag (`default-src 'none'`). On native it is a WebView with JavaScript off, and navigation after the first load is rejected. `BlocksView` renders that frame only when `allowHtml` is true and `streaming` is false. Otherwise the block is a card that says the preview is off or still arriving. `GPTChat` passes `allowHtml` through.
|
|
511
|
+
|
|
512
|
+
```tsx
|
|
513
|
+
<HtmlFrame height="md" html="<h1>Invoice</h1>" title="Invoice preview" />
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### AskCard
|
|
517
|
+
|
|
518
|
+
One agent ask in a chat transcript: controls while it is pending, a summary line after. `GPTChat`
|
|
519
|
+
renders it for messages with `ask`. Render it directly in a custom transcript. A saved ask whose
|
|
520
|
+
input no longer validates, or whose `accept` answer has no `content` object, shows the generic
|
|
521
|
+
line ("You answered this question.") and no sent values.
|
|
522
|
+
|
|
523
|
+
```tsx
|
|
524
|
+
<AskCard ask={ask} errors={errors} onSubmit={handleAskSubmit} testID="plan-ask" />
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
| Prop | Type | Description |
|
|
528
|
+
| --- | --- | --- |
|
|
529
|
+
| `ask` | `ChatAsk` | The ask. Pending asks are interactive. Answered and cancelled asks show a summary. |
|
|
530
|
+
| `errors` | `AskValidationError[]` | Errors for the last answer, shown under the controls |
|
|
531
|
+
| `onSubmit` | `AskSubmitHandler` | Called with `{toolCallId, response}`. Without it, the card cannot be answered: buttons and the select are disabled, and radio and checkbox options show as plain text. When the promise it returns rejects, the ask stays open and the card shows "Your answer could not be sent. Try again." until the next answer. |
|
|
532
|
+
| `promptRef` | `React.Ref<Text>` (React Native) | Receives the question's native text, which is an accessibility header. `GPTChat` uses it to move screen reader focus to a pending ask on native. |
|
|
533
|
+
| `resolveAskFiles` | `AskFilesResolver` | For a `files` ask: turns the picked files into refs on Submit. Defaults to data URLs. `GPTChat` passes its own `resolveAskFiles`. |
|
|
534
|
+
| `testID` | string | Defaults to `ask-card`. `GPTChat` passes `gpt-ask-<toolCallId>`. |
|
|
535
|
+
|
|
536
|
+
A saved ask whose input no longer passes `validateAskInput` shows "This question cannot be shown.
|
|
537
|
+
Send a message to continue." while pending, and "You answered this question." once answered.
|
|
538
|
+
|
|
539
|
+
`choice` controls:
|
|
540
|
+
|
|
541
|
+
| Ask | Controls |
|
|
542
|
+
| --- | --- |
|
|
543
|
+
| The simple card has a button for every option (`handoff: false`), and every option label is at most 20 characters | The card's buttons as quick replies, then Skip unless `allowDecline` is `false`. A tap answers. |
|
|
544
|
+
| Up to 8 options | `RadioField`, then Submit (`submitLabel`) and Skip |
|
|
545
|
+
| More than 8 options | Searchable `SelectField`, then Submit and Skip |
|
|
546
|
+
| `select: "many"` | `MultiselectField` with a hint such as "Choose 1 to 3.", then a `TextField` titled `otherLabel` (default "Other") when `allowOther` is `true`, then Submit and Skip |
|
|
547
|
+
|
|
548
|
+
The selection starts on the ask's `default`. Submit is enabled only when `validateAskResponse`
|
|
549
|
+
accepts the selection. For `select: "many"`, the answer lists the checked ids in option order and
|
|
550
|
+
sends the Other text trimmed, leaving `other` out when the field is blank. When the checked
|
|
551
|
+
options and the Other text add up to more than `maxSelected`, the checkboxes say so ("You chose
|
|
552
|
+
4. Choose at most 3."). An Other text over 500 characters, or a server error at `content.other`,
|
|
553
|
+
shows on the Other field. When `ask.simple` is absent, the card derives it with `toSimpleCard`. An
|
|
554
|
+
ask whose input fails `validateAskInput` shows "This question cannot be shown. Send a message to
|
|
555
|
+
continue." instead of controls.
|
|
556
|
+
|
|
557
|
+
`confirm` controls: the simple card's two buttons in its order, the approve button (`confirmLabel`,
|
|
558
|
+
default "Confirm") first and the deny button (`denyLabel`, default "Cancel") last. The approve
|
|
559
|
+
button uses the `destructive` variant when the ask sets `destructive: true`, else `primary`; the
|
|
560
|
+
deny button uses `ghost`. Skip follows only when `allowDecline` is `true`. A tap answers
|
|
561
|
+
`{"confirmed": true}` or `{"confirmed": false}`. Without `onSubmit`, both buttons are disabled.
|
|
562
|
+
|
|
563
|
+
`markdown` controls: a `MarkdownEditorField` (edit and preview, at most 320 pt tall) that starts
|
|
564
|
+
on the ask's `initial` draft and shows `placeholder` while empty, then Submit (`submitLabel`) and
|
|
565
|
+
Skip unless `allowDecline` is `false`. Under the editor a hint gives the length and the bounds,
|
|
566
|
+
such as "1,240 / 2,000 characters. At least 20." Submit is enabled only when
|
|
567
|
+
`validateAskResponse` accepts the text, and it sends `{markdown, changed}` with `changed` true
|
|
568
|
+
when the text differs from `initial`. Text over `maxLength`, or a server error at
|
|
569
|
+
`content.markdown`, shows on the editor. Without `onSubmit`, the editor and both buttons are
|
|
570
|
+
disabled. An answered markdown ask shows the sent text under its summary; text over 280
|
|
571
|
+
characters shows a preview cut at a word, with Show all and Show less.
|
|
572
|
+
|
|
573
|
+
`form` controls: one field per entry in `fields`, in order, titled with the field's `label`
|
|
574
|
+
("(required)" appended for required fields) and its `helperText`, then Submit (`submitLabel`) and
|
|
575
|
+
Skip unless `allowDecline` is `false`. Each field uses the `@terreno/ui` control for its type:
|
|
576
|
+
|
|
577
|
+
| Field `type` | Control | Sends |
|
|
578
|
+
| --- | --- | --- |
|
|
579
|
+
| `text`, `email`, `url` | `TextField` (`text`, `email`, `url`) | The trimmed text |
|
|
580
|
+
| `phone` | `TextField` (`phoneNumber`) | E.164, such as `+14155552671`, when the number parses (as a US number without a country code); else the trimmed text |
|
|
581
|
+
| `number` | `TextField` | A number when the text is plain decimal notation; else the text, so validation says why |
|
|
582
|
+
| `textarea` | `TextArea` | The trimmed text |
|
|
583
|
+
| `date` | `DateTimeField` (`date`) | `YYYY-MM-DD` |
|
|
584
|
+
| `time` | `DateTimeField` (`time`) with its time zone picker (the device's zone to start) | 24-hour `HH:mm` as shown; the zone is not sent |
|
|
585
|
+
| `datetime` | `DateTimeField` (`datetime`) with a time zone picker | An ISO datetime with the chosen zone's offset, such as `2026-10-01T09:30:00-07:00` |
|
|
586
|
+
| `boolean` | `BooleanField` | `true` or `false`, always |
|
|
587
|
+
| `select` | `SelectField` | The option id |
|
|
588
|
+
| `multiselect` | `MultiselectField` | The checked option ids |
|
|
589
|
+
|
|
590
|
+
Fields start on their `default`. Blank fields are left out of `values`. Submit is enabled only
|
|
591
|
+
when `validateAskResponse` accepts the values and no date, time, or datetime field holds an
|
|
592
|
+
unfinished entry. `DateTimeField` reports that through `onEntryStatusChange`, such as
|
|
593
|
+
"0 / 5 / 026": the field says "Enter a complete date, or clear it." until the user finishes it,
|
|
594
|
+
and clearing every part leaves the field out. After the user edits a field, it says what is
|
|
595
|
+
wrong in plain words, such as "Enter a number from 1 to 500." or "This field is required." A
|
|
596
|
+
server error whose path is `content.values.<id>` (or an item under it) shows on that field until
|
|
597
|
+
the user edits it; other errors show under the form. Without `onSubmit`, every field and both
|
|
598
|
+
buttons are disabled. An answered form lists each sent field as its label and a readable value
|
|
599
|
+
(Yes or No, option labels, "Oct 1, 2026", "9:30 AM", text shortened to one line of 80
|
|
600
|
+
characters) under its summary.
|
|
601
|
+
|
|
602
|
+
`files` controls: a hint built from the counts and types, such as "Up to 3 files: images, PDFs or
|
|
603
|
+
text files.", then a "Choose files" `FilePickerButton` ("Add files" once some are picked), the
|
|
604
|
+
picked files as an `AttachmentPreview` with a remove control on each, then Submit (`submitLabel`,
|
|
605
|
+
default "Submit") and Skip unless `allowDecline` is `false`. The picker offers Photo Library only
|
|
606
|
+
when `accept` has `image`, and its document picker offers only the accepted MIME types. It allows
|
|
607
|
+
several files when `maxFiles` is more than 1 and is disabled once `maxFiles` files are picked.
|
|
608
|
+
Submit is enabled only when `validateAskResponse` accepts the picked names, types, and sizes. On
|
|
609
|
+
Submit, the card calls `resolveAskFiles` with the picked files and sends `{files: refs}`; Submit
|
|
610
|
+
shows a spinner and Skip is disabled until the answer is sent. When the ask ends another way while
|
|
611
|
+
the resolver runs, such as an answer from another tab, its refs are not sent. If the resolver throws, the ask
|
|
612
|
+
stays open and the card shows "The files could not be sent. Try again, or pick them again." Server
|
|
613
|
+
errors, such as `MIME_MISMATCH`, show under the picked files. Each file's type is
|
|
614
|
+
`selectedFileMimeType(file)`, so a CSV a picker reports as `application/vnd.ms-excel` is sent as
|
|
615
|
+
`text/csv`.
|
|
616
|
+
|
|
617
|
+
| How the ask ended | Summary |
|
|
618
|
+
| --- | --- |
|
|
619
|
+
| `files` `accept` | You sent `<n>` files: `<filenames>`, or You sent 1 file: `<filename>` |
|
|
620
|
+
| `form` `accept` | You sent the form (`<n>` fields) |
|
|
621
|
+
| `markdown` `accept` | You approved the draft as is (`changed: false`), or You edited the draft (`<n>` characters) |
|
|
622
|
+
| `confirm` `accept` | You confirmed: `<confirmLabel>`, or You declined: `<denyLabel>`, with the default labels when the ask sets none |
|
|
623
|
+
| `choice` `accept` | You chose: `<option labels>`. With Other text, it adds "`<otherLabel>`: `<text>`" (the label defaults to "Other"), or shows only that when no option was checked. An empty `select: "many"` answer shows "You chose none of the options." |
|
|
624
|
+
| `decline` | You skipped this question. |
|
|
625
|
+
| `cancel` with `user_sent_message` | Not answered: you sent a message instead. |
|
|
626
|
+
| `cancel` with `one_ask_at_a_time` | Not asked: the assistant asked another question first. |
|
|
627
|
+
| Any other `cancel`, or status `cancelled` without a response | This question was cancelled. |
|
|
628
|
+
| Status `answered` without a response | You answered this question. |
|
|
629
|
+
|
|
630
|
+
| Element | testID |
|
|
631
|
+
| --- | --- |
|
|
632
|
+
| Card | `{testID}` |
|
|
633
|
+
| Quick reply row | `{testID}-quick-replies` |
|
|
634
|
+
| Quick reply or Skip button | `{testID}-button-<button id>`, such as `{testID}-button-option:team` or `{testID}-button-skip` |
|
|
635
|
+
| Confirm button row | `{testID}-confirm-buttons` |
|
|
636
|
+
| Confirm approve or deny button | `{testID}-button-approve`, `{testID}-button-deny` |
|
|
637
|
+
| Radio options (up to 8) | `{testID}-radio` |
|
|
638
|
+
| Select | `{testID}-select` |
|
|
639
|
+
| Checkboxes (`select: "many"`) | `{testID}-multiselect` |
|
|
640
|
+
| Other text field | `{testID}-other` |
|
|
641
|
+
| Markdown editor, and its text input | `{testID}-editor`, `{testID}-editor-input` |
|
|
642
|
+
| Sent markdown under an answered ask, and its Show all toggle | `{testID}-answer`, `{testID}-answer-toggle` |
|
|
643
|
+
| Form field, and its wrapper | `{testID}-field-<field id>` (a `BooleanField` switch is `{testID}-field-<field id>.switch`), `{testID}-form-field-<field id>` |
|
|
644
|
+
| Sent form values under an answered ask | `{testID}-answer` |
|
|
645
|
+
| Files hint, picker, and picked files | `{testID}-hint`, `{testID}-picker`, `{testID}-selected` |
|
|
646
|
+
| Files that could not be sent | `{testID}-resolve-error` |
|
|
647
|
+
| Radio or checkbox options as plain text, without `onSubmit` | `{testID}-options` |
|
|
648
|
+
| Submit | `{testID}-submit` |
|
|
649
|
+
| Answer errors | `{testID}-errors` |
|
|
650
|
+
| Summary | `{testID}-summary` |
|
|
651
|
+
| Ask that cannot be shown | `{testID}-invalid` |
|
|
652
|
+
| Answer that could not be sent | `{testID}-submit-error` |
|
|
653
|
+
|
|
654
|
+
Types: `AskCardProps`, `ChatAsk`, `ChatAskState`, `ChatAskStatus`, `AskSubmission`,
|
|
655
|
+
`AskSubmitHandler`, `AskFilesResolver`. Demo story: `AskCard`.
|
|
656
|
+
|
|
657
|
+
File ref helpers:
|
|
658
|
+
|
|
659
|
+
| Export | Description |
|
|
660
|
+
| --- | --- |
|
|
661
|
+
| `AskFilesResolver` | `(files: SelectedFile[]) => Promise<AskFileRef[]>`. Throw to keep the ask open. |
|
|
662
|
+
| `resolveAskFilesAsDataUrls` | The default resolver: every file as a `{url}` data URL |
|
|
663
|
+
| `selectedFileToDataUrlRef(file)` | One picked file as `{filename, mimeType, size, url}`. The data URL's media type is `selectedFileMimeType(file)`, and `size` is the decoded byte count. |
|
|
664
|
+
| `selectedFileMimeType(file)` | The picked file's normalized type. When the picker reports none, `application/octet-stream`, or `application/vnd.ms-excel` (Windows reports CSV files so), the type comes from the extension: `.csv`, `.gif`, `.jpeg`, `.jpg`, `.json`, `.pdf`, `.png`, `.txt`, `.webp`. Otherwise the reported type is kept. |
|
|
665
|
+
| `normalizeMimeType(mimeType)` | Drops parameters and lowercases: `Text/CSV; charset=utf-8` becomes `text/csv` |
|
|
666
|
+
|
|
667
|
+
`FilePickerButton` props used by the files card, also available to any caller:
|
|
668
|
+
|
|
669
|
+
| Prop | Type | Description |
|
|
670
|
+
| --- | --- | --- |
|
|
671
|
+
| `documentTypes` | `string[]` | MIME types the document picker offers. Defaults to PDF, text, CSV, and JSON. An empty list hides Document. |
|
|
672
|
+
| `includeImages` | boolean | Offer Photo Library. Defaults to `true`. When `false`, the button opens the document picker directly. |
|
|
673
|
+
| `text` | string | Shows an outline button with this label instead of the paperclip icon |
|
|
674
|
+
|
|
675
|
+
`SelectedFile.size` is the file's size in bytes when the picker reports it.
|
|
676
|
+
|
|
677
|
+
### SimpleAskCard
|
|
678
|
+
|
|
679
|
+
Any agent ask as its [simple card](agent-ui-asks.md#simple-cards): the title, the question, and up
|
|
680
|
+
to three full-width buttons that each send an exact answer. Use it in narrow layouts, such as a
|
|
681
|
+
watch-sized preview. It reads the card's `kind` only to word the handoff line.
|
|
682
|
+
|
|
683
|
+
```tsx
|
|
684
|
+
const [runTurn] = useGpthistoriesTurnMutation();
|
|
685
|
+
|
|
686
|
+
<SimpleAskCard
|
|
687
|
+
card={pendingAsk.simple}
|
|
688
|
+
onPress={(button) =>
|
|
689
|
+
runTurn({
|
|
690
|
+
body: {buttonId: button.id, surface: "compact", toolCallId: pendingAsk.toolCallId},
|
|
691
|
+
id: historyId,
|
|
692
|
+
})
|
|
693
|
+
}
|
|
694
|
+
pendingButtonId={sendingButtonId}
|
|
695
|
+
/>
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
| Prop | Type | Description |
|
|
699
|
+
| --- | --- | --- |
|
|
700
|
+
| `card` | `SimpleCard` | `pendingAsk.simple` from the server, or `simple` on an `{ask}` event |
|
|
701
|
+
| `onPress` | `(button: SimpleCardButton) => void \| Promise<void>` | Called with the pressed button. Send `{toolCallId: card.toolCallId, buttonId: button.id}` to the history's [`turn` action](agent-ui-asks.md#headless-endpoints), or send `button.response` as the answer. |
|
|
702
|
+
| `pendingButtonId` | string? | The button whose answer is still sending. It shows a spinner, the other buttons are disabled, and presses are ignored. |
|
|
703
|
+
| `testID` | string? | Defaults to `simple-ask-card` |
|
|
704
|
+
|
|
705
|
+
- A card with `handoff: true` shows "Continue on your phone" under the question, because its
|
|
706
|
+
buttons cannot give every answer. A `markdown` card shows "Edit on your phone" instead, a
|
|
707
|
+
`form` card "Fill it in on your phone", and a `files` card "Upload on your phone".
|
|
708
|
+
- Button styles map to `Button` variants the same way as `AskCard` quick replies: `primary` to
|
|
709
|
+
`primary`, `default` to `outline`, `destructive` to `destructive`, and `cancel` to `ghost`.
|
|
710
|
+
|
|
711
|
+
| Element | testID |
|
|
712
|
+
| --- | --- |
|
|
713
|
+
| Card | `{testID}` |
|
|
714
|
+
| Continue on your phone, or Edit on your phone | `{testID}-handoff` |
|
|
715
|
+
| Button | `{testID}-button-<button id>`, such as `{testID}-button-option:team` |
|
|
716
|
+
|
|
717
|
+
Types: `SimpleAskCardProps`, and `SimpleCard` and `SimpleCardButton` from `@terreno/blocks`. Demo
|
|
718
|
+
story: `SimpleAskCard`. Its demo answers a plan card on a watch-sized 198×242 pt screen, and its
|
|
719
|
+
"Every fixture" story draws every valid fixture's card at that size.
|
|
720
|
+
|
|
320
721
|
### SplitPage
|
|
321
722
|
|
|
322
723
|
Master-detail layout. Pass `listViewData` plus `renderListViewItem` for the list, and
|
|
@@ -362,6 +763,12 @@ Buttons use a scale animation by default. Set `pressAnimation="opacity"` for an
|
|
|
362
763
|
|
|
363
764
|
Disabled and loading buttons use a non-interactive pressable regardless of the selected animation.
|
|
364
765
|
|
|
766
|
+
### Toast
|
|
767
|
+
|
|
768
|
+
`TerrenoProvider` mounts the toast container. Call `useToast()` for `success`, `info`, `warn`, `error`, `show`, `hide`, and `catch`.
|
|
769
|
+
|
|
770
|
+
On web, that container is portaled to `document.body` (`position: fixed`, `z-index: 999999`, `pointerEvents: "box-none"`), so a toast stays above an open `Modal` and its backdrop. The web container is sized with `100%` rather than the measured window, so statically exported pages (where `Dimensions` reports 0×0 at build time) still center the toast on screen. Native iOS and Android keep the in-tree absolute container sized to the window.
|
|
771
|
+
|
|
365
772
|
## Authentication Components
|
|
366
773
|
|
|
367
774
|
### SocialLoginButton
|