@softize/opus 19.0.0 → 20.1.0
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/CHANGELOG.md +239 -0
- package/bin/cli.mjs +5 -0
- package/bin/lib/check.mjs +198 -10
- package/bin/lib/copy.mjs +29 -0
- package/bin/lib/mcp.mjs +1 -1
- package/docs/adr/0020-icon-tiles-are-explicitly-composed.md +8 -0
- package/docs/adr/0021-content-carries-structure-and-semantic-element.md +7 -0
- package/docs/adr/0023-surfaces-share-one-anatomy-and-two-layouts.md +19 -1
- package/docs/adr/0024-fill-height-propagates-by-context.md +118 -0
- package/docs/adr/0025-content-frame-treatment-does-not-change-semantics.md +134 -0
- package/docs/data-products.md +15 -9
- package/docs/protocol.md +3 -4
- package/docs/releasing.md +2 -2
- package/package.json +2 -2
- package/registry/skills/create-opus-action/scripts/scaffold.mjs +2 -1
- package/registry/templates/app/package.json +1 -1
- package/src/core/runtime.ts +96 -8
- package/src/core/types.ts +5 -2
- package/src/ui/components/patterns/action-form-card.tsx +11 -1
- package/src/ui/components/patterns/content-header.tsx +109 -18
- package/src/ui/components/patterns/fill-region.ts +150 -0
- package/src/ui/components/patterns/list.tsx +91 -92
- package/src/ui/components/patterns/page.tsx +20 -4
- package/src/ui/components/patterns/presentation.tsx +52 -37
- package/src/ui/components/patterns/split.tsx +44 -4
- package/src/ui/components/patterns/surface-anatomy.ts +35 -8
- package/src/ui/components/patterns/surface-header.tsx +58 -25
- package/src/ui/components/patterns/trigger.tsx +12 -2
- package/src/ui/components/primitives/alert.tsx +9 -1
- package/src/ui/components/primitives/avatar.tsx +7 -3
- package/src/ui/components/primitives/card.tsx +1 -1
- package/src/ui/components/primitives/carousel.tsx +34 -5
- package/src/ui/components/primitives/checkbox.tsx +11 -3
- package/src/ui/components/primitives/command.tsx +2 -1
- package/src/ui/components/primitives/copyable.tsx +120 -10
- package/src/ui/components/primitives/dialog.tsx +42 -11
- package/src/ui/components/primitives/drawer.tsx +10 -2
- package/src/ui/components/primitives/empty.tsx +1 -1
- package/src/ui/components/primitives/icon-picker.tsx +6 -2
- package/src/ui/components/primitives/icon-tile.tsx +7 -0
- package/src/ui/components/primitives/input-group.tsx +9 -2
- package/src/ui/components/primitives/input-otp.tsx +1 -1
- package/src/ui/components/primitives/kbd.tsx +1 -1
- package/src/ui/components/primitives/label.tsx +3 -0
- package/src/ui/components/primitives/menu.tsx +5 -0
- package/src/ui/components/primitives/popover.tsx +1 -1
- package/src/ui/components/primitives/progress.tsx +9 -1
- package/src/ui/components/primitives/slider.tsx +62 -11
- package/src/ui/components/primitives/truncate.tsx +10 -1
- package/src/ui/docs/content/accordion.md +74 -27
- package/src/ui/docs/content/action-form-card.md +24 -15
- package/src/ui/docs/content/action-form-dialog.md +17 -7
- package/src/ui/docs/content/action-form.md +92 -77
- package/src/ui/docs/content/action-list-dialog.md +75 -38
- package/src/ui/docs/content/action-list.md +141 -58
- package/src/ui/docs/content/action-trigger.md +27 -10
- package/src/ui/docs/content/action-view.md +14 -14
- package/src/ui/docs/content/actions.md +161 -66
- package/src/ui/docs/content/ai.md +43 -44
- package/src/ui/docs/content/alert.md +83 -29
- package/src/ui/docs/content/ask.md +51 -26
- package/src/ui/docs/content/aspect-ratio.md +22 -24
- package/src/ui/docs/content/audit.md +23 -19
- package/src/ui/docs/content/auth.md +38 -19
- package/src/ui/docs/content/avatar.md +54 -5
- package/src/ui/docs/content/badge.md +29 -9
- package/src/ui/docs/content/breadcrumb.md +21 -8
- package/src/ui/docs/content/button.md +73 -43
- package/src/ui/docs/content/calendar.md +134 -26
- package/src/ui/docs/content/card.md +41 -15
- package/src/ui/docs/content/carousel.md +37 -6
- package/src/ui/docs/content/chat.md +118 -37
- package/src/ui/docs/content/checkbox.md +73 -7
- package/src/ui/docs/content/cli.md +94 -55
- package/src/ui/docs/content/collapsible.md +43 -19
- package/src/ui/docs/content/command.md +30 -8
- package/src/ui/docs/content/composer.md +23 -8
- package/src/ui/docs/content/content.md +119 -27
- package/src/ui/docs/content/copyable.md +39 -8
- package/src/ui/docs/content/customization.md +55 -46
- package/src/ui/docs/content/cycle.md +33 -18
- package/src/ui/docs/content/data-products.md +115 -0
- package/src/ui/docs/content/data-state.md +20 -6
- package/src/ui/docs/content/data.md +20 -19
- package/src/ui/docs/content/detail.md +12 -5
- package/src/ui/docs/content/dialog.md +107 -24
- package/src/ui/docs/content/dictionary-value.md +4 -4
- package/src/ui/docs/content/dock.md +54 -19
- package/src/ui/docs/content/dot.md +35 -5
- package/src/ui/docs/content/drawer.md +63 -19
- package/src/ui/docs/content/empty-value.md +20 -6
- package/src/ui/docs/content/empty.md +24 -3
- package/src/ui/docs/content/events.md +76 -16
- package/src/ui/docs/content/executions.md +9 -9
- package/src/ui/docs/content/field.md +21 -6
- package/src/ui/docs/content/getting-started.md +44 -34
- package/src/ui/docs/content/icon-picker.md +19 -13
- package/src/ui/docs/content/icon-tile.md +38 -15
- package/src/ui/docs/content/input-otp.md +58 -7
- package/src/ui/docs/content/input.md +22 -3
- package/src/ui/docs/content/item.md +53 -6
- package/src/ui/docs/content/kbd.md +5 -1
- package/src/ui/docs/content/label.md +13 -4
- package/src/ui/docs/content/log.md +5 -5
- package/src/ui/docs/content/markdown.md +5 -4
- package/src/ui/docs/content/mcp.md +49 -23
- package/src/ui/docs/content/menu.md +95 -10
- package/src/ui/docs/content/metric-card.md +12 -4
- package/src/ui/docs/content/observability.md +10 -9
- package/src/ui/docs/content/page.md +118 -12
- package/src/ui/docs/content/pagination.md +13 -5
- package/src/ui/docs/content/pane.md +55 -5
- package/src/ui/docs/content/popover.md +42 -5
- package/src/ui/docs/content/presentation.md +91 -47
- package/src/ui/docs/content/progress.md +27 -14
- package/src/ui/docs/content/queue.md +39 -21
- package/src/ui/docs/content/radio-group.md +26 -4
- package/src/ui/docs/content/router.md +29 -10
- package/src/ui/docs/content/runtime.md +90 -54
- package/src/ui/docs/content/scheduler.md +53 -21
- package/src/ui/docs/content/scroll-area.md +42 -35
- package/src/ui/docs/content/select.md +78 -33
- package/src/ui/docs/content/semantic-context.md +21 -2
- package/src/ui/docs/content/separator.md +15 -9
- package/src/ui/docs/content/sidebar.md +3 -2
- package/src/ui/docs/content/skeleton.md +6 -1
- package/src/ui/docs/content/slider.md +37 -9
- package/src/ui/docs/content/spinner.md +4 -3
- package/src/ui/docs/content/split.md +19 -0
- package/src/ui/docs/content/storage.md +8 -9
- package/src/ui/docs/content/switch.md +10 -7
- package/src/ui/docs/content/table.md +46 -8
- package/src/ui/docs/content/tabs.md +14 -4
- package/src/ui/docs/content/testing.md +76 -31
- package/src/ui/docs/content/textarea.md +5 -4
- package/src/ui/docs/content/toast.md +48 -7
- package/src/ui/docs/content/toggle.md +3 -3
- package/src/ui/docs/content/tokens.md +15 -26
- package/src/ui/docs/content/tooltip.md +18 -2
- package/src/ui/docs/content/truncate.md +36 -6
- package/src/ui/docs/content/ui.md +74 -22
- package/src/ui/docs/content/upgrading.md +45 -36
- package/src/ui/docs/plugin.ts +36 -2
- package/src/ui/docs/registry.tsx +6 -0
- package/src/ui/drivers/react.tsx +16 -8
- package/src/ui/meta.ts +32 -32
- package/src/ui/react.tsx +1 -0
- package/src/vite/design.ts +16 -4
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
O calendário fala pt-BR por padrão: nomes de mês e de dia vêm do `locale` (`ptBR` de
|
|
2
|
-
`date-fns/locale`) e os controles de navegação têm rótulos acessíveis em português. Passe outro
|
|
3
|
-
`locale` para trocar o idioma; `labels` sobrescreve rótulos individualmente.
|
|
4
|
-
|
|
5
1
|
## Dia único
|
|
6
2
|
|
|
7
|
-
|
|
3
|
+
Use `Calendar` quando a pessoa precisar escolher datas vendo o mês inteiro, como a data de uma
|
|
4
|
+
entrega ou a janela de um relatório. Para abrir o calendário a partir de um campo, ancore-o em um
|
|
5
|
+
[`Popover`](/ui/popover).
|
|
6
|
+
|
|
7
|
+
Com `mode="single"`, a seleção é uma `Date`, controlada por `selected` e `onSelect`. `defaultMonth`
|
|
8
|
+
abre o calendário no mês desejado sem alterar a seleção.
|
|
8
9
|
|
|
9
10
|
```tsx preview
|
|
10
11
|
const [day, setDay] = useState<Date | undefined>(new Date(2026, 5, 22))
|
|
@@ -19,9 +20,14 @@ render(
|
|
|
19
20
|
)
|
|
20
21
|
```
|
|
21
22
|
|
|
23
|
+
O calendário usa pt-BR por padrão: os nomes de mês e de dia vêm do `locale` (`ptBR`, de
|
|
24
|
+
`date-fns/locale`) e os controles de navegação têm nomes acessíveis em português. Passe outro
|
|
25
|
+
`locale` para trocar o idioma; `labels` substitui nomes acessíveis individualmente.
|
|
26
|
+
|
|
22
27
|
## Intervalo
|
|
23
28
|
|
|
24
|
-
mode=range
|
|
29
|
+
Com `mode="range"`, a seleção é um intervalo `{ from, to }`, o formato comum para filtrar registros
|
|
30
|
+
por período. O primeiro clique define o início e o segundo, o fim.
|
|
25
31
|
|
|
26
32
|
```tsx preview
|
|
27
33
|
const [week, setWeek] = useState<DateRange | undefined>({
|
|
@@ -39,9 +45,73 @@ render(
|
|
|
39
45
|
)
|
|
40
46
|
```
|
|
41
47
|
|
|
42
|
-
|
|
48
|
+
Para um intervalo que atravessa meses, `numberOfMonths` mostra meses lado a lado.
|
|
49
|
+
|
|
50
|
+
```tsx preview
|
|
51
|
+
const [range, setRange] = useState<DateRange | undefined>({
|
|
52
|
+
from: new Date(2026, 5, 24),
|
|
53
|
+
to: new Date(2026, 6, 8),
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
render(
|
|
57
|
+
<Calendar
|
|
58
|
+
mode="range"
|
|
59
|
+
numberOfMonths={2}
|
|
60
|
+
selected={range}
|
|
61
|
+
onSelect={setRange}
|
|
62
|
+
defaultMonth={new Date(2026, 5, 1)}
|
|
63
|
+
/>,
|
|
64
|
+
)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Vários dias
|
|
43
68
|
|
|
44
|
-
|
|
69
|
+
Com `mode="multiple"`, a seleção é uma lista de datas, e cada clique marca ou desmarca um dia. Use
|
|
70
|
+
esse modo quando os dias escolhidos não formarem um intervalo contínuo, como os plantões de uma
|
|
71
|
+
equipe.
|
|
72
|
+
|
|
73
|
+
```tsx preview
|
|
74
|
+
const [days, setDays] = useState<Date[] | undefined>([
|
|
75
|
+
new Date(2026, 5, 3),
|
|
76
|
+
new Date(2026, 5, 10),
|
|
77
|
+
new Date(2026, 5, 17),
|
|
78
|
+
])
|
|
79
|
+
|
|
80
|
+
render(
|
|
81
|
+
<Calendar
|
|
82
|
+
mode="multiple"
|
|
83
|
+
selected={days}
|
|
84
|
+
onSelect={setDays}
|
|
85
|
+
defaultMonth={new Date(2026, 5, 1)}
|
|
86
|
+
/>,
|
|
87
|
+
)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Datas indisponíveis
|
|
91
|
+
|
|
92
|
+
`disabled` impede a escolha de datas específicas. Ele aceita uma data, uma lista, um intervalo
|
|
93
|
+
`{ from, to }`, um predicado ou combinações como `{ before: data }` e `{ dayOfWeek: [0, 6] }`. No
|
|
94
|
+
exemplo, dias anteriores a 10 de junho e fins de semana ficam indisponíveis.
|
|
95
|
+
|
|
96
|
+
```tsx preview
|
|
97
|
+
const [day, setDay] = useState<Date | undefined>()
|
|
98
|
+
|
|
99
|
+
render(
|
|
100
|
+
<Calendar
|
|
101
|
+
mode="single"
|
|
102
|
+
selected={day}
|
|
103
|
+
onSelect={setDay}
|
|
104
|
+
defaultMonth={new Date(2026, 5, 1)}
|
|
105
|
+
disabled={[{ before: new Date(2026, 5, 10) }, { dayOfWeek: [0, 6] }]}
|
|
106
|
+
/>,
|
|
107
|
+
)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Navegação por seletores
|
|
111
|
+
|
|
112
|
+
`captionLayout="dropdown"` troca o título do mês por seletores de mês e ano. Use essa forma quando a
|
|
113
|
+
pessoa precisar chegar a um período distante, como o histórico de anos anteriores, sem avançar mês
|
|
114
|
+
a mês.
|
|
45
115
|
|
|
46
116
|
```tsx preview
|
|
47
117
|
<Calendar
|
|
@@ -51,25 +121,63 @@ captionLayout=dropdown troca o título do mês por seletores de mês e ano — b
|
|
|
51
121
|
/>
|
|
52
122
|
```
|
|
53
123
|
|
|
124
|
+
## Personalizar o dia
|
|
125
|
+
|
|
126
|
+
Cada dia é um `CalendarDayButton`: um `Button` `ghost` quadrado que recebe os modificadores do dia,
|
|
127
|
+
como `selected`, `range_start` e `today`, e cuida do foco e dos estados de seleção. Para decorar o
|
|
128
|
+
dia, como marcar datas com evento, substitua o componente por `components={{ DayButton: … }}` e
|
|
129
|
+
renderize `CalendarDayButton` por dentro, em vez de reimplementar esse comportamento.
|
|
130
|
+
|
|
131
|
+
```tsx preview
|
|
132
|
+
const eventDays = [5, 12, 26]
|
|
133
|
+
|
|
134
|
+
render(
|
|
135
|
+
<Calendar
|
|
136
|
+
mode="single"
|
|
137
|
+
defaultMonth={new Date(2026, 5, 1)}
|
|
138
|
+
components={{
|
|
139
|
+
DayButton: ({ children, ...props }) => (
|
|
140
|
+
<CalendarDayButton {...props}>
|
|
141
|
+
{children}
|
|
142
|
+
{eventDays.includes(props.day.date.getDate()) &&
|
|
143
|
+
props.day.date.getMonth() === 5 && (
|
|
144
|
+
<span aria-hidden="true" className="size-1 rounded-full bg-primary" />
|
|
145
|
+
)}
|
|
146
|
+
</CalendarDayButton>
|
|
147
|
+
),
|
|
148
|
+
}}
|
|
149
|
+
/>,
|
|
150
|
+
)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
O marcador do exemplo é decorativo. Quando a informação importar para a decisão, inclua-a também
|
|
154
|
+
no nome acessível do dia por `labels.labelDayButton`.
|
|
155
|
+
|
|
54
156
|
## Propriedades de Calendar
|
|
55
157
|
|
|
56
158
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
57
159
|
|---|---|---|---|
|
|
58
|
-
| `mode` | `'single' \| 'multiple' \| 'range'` | |
|
|
59
|
-
| `selected` | `Date \| Date[] \| DateRange` | |
|
|
60
|
-
| `onSelect` | `(selected) => void` | | Chamado quando
|
|
61
|
-
| `defaultMonth` | `Date` | |
|
|
62
|
-
| `captionLayout` | `'label' \| 'dropdown' \| 'dropdown-months' \| 'dropdown-years'` | `'label'` |
|
|
63
|
-
| `numberOfMonths` | `number` | `1` |
|
|
64
|
-
| `disabled` | `Matcher` | | Datas não
|
|
65
|
-
| `buttonVariant` | `
|
|
66
|
-
| `showOutsideDays` | `boolean` | `true` | Mostra os dias
|
|
67
|
-
| `locale` | `Locale` | `ptBR` | Idioma dos nomes de mês e de dia
|
|
68
|
-
| `labels` | `Partial<Labels>` |
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
160
|
+
| `mode` | `'single' \| 'multiple' \| 'range'` | | Tipo de seleção. Define o formato de `selected` e `onSelect`: `Date`, `Date[]` ou `{ from, to }`. |
|
|
161
|
+
| `selected` | `Date \| Date[] \| DateRange` | | Seleção atual no modo controlado, no formato do `mode`. Use com `onSelect`. |
|
|
162
|
+
| `onSelect` | `(selected) => void` | | Chamado quando a pessoa escolhe uma data. O argumento segue o formato do `mode`. |
|
|
163
|
+
| `defaultMonth` | `Date` | | Mês exibido ao montar, sem afetar a seleção. |
|
|
164
|
+
| `captionLayout` | `'label' \| 'dropdown' \| 'dropdown-months' \| 'dropdown-years'` | `'label'` | Apresentação do título do mês: texto fixo ou seletores de mês, de ano ou de ambos. |
|
|
165
|
+
| `numberOfMonths` | `number` | `1` | Quantidade de meses exibidos lado a lado. |
|
|
166
|
+
| `disabled` | `Matcher \| Matcher[]` | | Datas que não podem ser escolhidas: uma data, uma lista, um intervalo, um predicado ou regras como `{ before }` e `{ dayOfWeek }`. |
|
|
167
|
+
| `buttonVariant` | `ButtonVariant` | `'ghost'` | Variante dos botões de mês anterior e próximo mês. |
|
|
168
|
+
| `showOutsideDays` | `boolean` | `true` | Mostra os dias dos meses vizinhos que completam a primeira e a última semana. |
|
|
169
|
+
| `locale` | `Locale` | `ptBR` | Idioma dos nomes de mês e de dia, como um locale do date-fns. |
|
|
170
|
+
| `labels` | `Partial<Labels>` | nomes em pt-BR | Nomes acessíveis da navegação, dos seletores e dos dias; mesclados sobre o padrão. |
|
|
171
|
+
| `components` | `Partial<CustomComponents>` | | Substitui partes da grade, como `DayButton`. |
|
|
172
|
+
|
|
173
|
+
`Calendar` repassa as demais propriedades ao `DayPicker` do react-day-picker.
|
|
174
|
+
|
|
175
|
+
## Propriedades de CalendarDayButton
|
|
176
|
+
|
|
177
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
178
|
+
|---|---|---|---|
|
|
179
|
+
| `day` | `CalendarDay` | | O dia renderizado; `day.date` é a data. Recebido do `Calendar`. |
|
|
180
|
+
| `modifiers` | `Modifiers` | | Estados do dia, como `selected`, `today`, `disabled`, `range_start` e `range_end`. Recebido do `Calendar`. |
|
|
181
|
+
| `className` | `string` | | Classes somadas ao botão do dia. |
|
|
182
|
+
|
|
183
|
+
`CalendarDayButton` aceita também as props nativas de `<button>`, repassadas pelo `Calendar`.
|
|
@@ -6,7 +6,7 @@ usa. Nesse formato o recuo vem do `className`.
|
|
|
6
6
|
|
|
7
7
|
```tsx preview col
|
|
8
8
|
<Card className="p-4">
|
|
9
|
-
<p className="text-sm text-muted-foreground">3
|
|
9
|
+
<p className="text-sm text-muted-foreground">3 veículos aguardando retirada.</p>
|
|
10
10
|
</Card>
|
|
11
11
|
```
|
|
12
12
|
|
|
@@ -23,15 +23,15 @@ slots são escritos não altera a posição.
|
|
|
23
23
|
```tsx preview col
|
|
24
24
|
<Card>
|
|
25
25
|
<CardHeader>
|
|
26
|
-
<CardTitle>
|
|
27
|
-
<CardDescription>
|
|
26
|
+
<CardTitle>Oficina Centro</CardTitle>
|
|
27
|
+
<CardDescription>4 boxes · 2 consultores de plantão.</CardDescription>
|
|
28
28
|
</CardHeader>
|
|
29
29
|
<CardBody>
|
|
30
|
-
<p className="text-sm text-muted-foreground"
|
|
30
|
+
<p className="text-sm text-muted-foreground">Próximo horário livre hoje, às 14h.</p>
|
|
31
31
|
</CardBody>
|
|
32
32
|
<CardFooter>
|
|
33
|
-
<Button size="sm" variant="outline">Ver
|
|
34
|
-
<Button size="sm">
|
|
33
|
+
<Button size="sm" variant="outline">Ver agenda</Button>
|
|
34
|
+
<Button size="sm">Agendar revisão</Button>
|
|
35
35
|
</CardFooter>
|
|
36
36
|
</Card>
|
|
37
37
|
```
|
|
@@ -59,7 +59,7 @@ com ações — ou quando ele precisar conviver com um [`Dialog`](/ui/dialog), u
|
|
|
59
59
|
|
|
60
60
|
```tsx preview col
|
|
61
61
|
render(
|
|
62
|
-
<div className="grid
|
|
62
|
+
<div className="grid grid-cols-2 gap-4">
|
|
63
63
|
<Card>
|
|
64
64
|
<CardHeader>
|
|
65
65
|
<CardTitle>Contínuo</CardTitle>
|
|
@@ -94,12 +94,15 @@ Em `sectioned`, cada região desenha a própria linha quando existe uma região
|
|
|
94
94
|
Um cabeçalho sozinho não fecha nada, um rodapé que é a única região também não, e um cabeçalho
|
|
95
95
|
seguido direto de um rodapé produz uma linha só, em vez de duas encostadas.
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
Por isso, não escreva `border-b` no cabeçalho nem `border-t` no rodapé: a regra depende da presença
|
|
98
|
+
das regiões irmãs, que o componente conhece e a tela não. Uma borda escrita à mão ignora quais
|
|
99
|
+
regiões estão presentes: `border-b` num cabeçalho sozinho desenha uma linha encostada na borda do
|
|
100
|
+
card, e `border-t` no corpo duplica a linha que o cabeçalho já desenha. Da mesma forma,
|
|
101
|
+
`border-b-0` não apaga a linha derivada. Para um card sem divisores, use `layout="continuous"`.
|
|
99
102
|
|
|
100
103
|
## Mídia e ações no cabeçalho
|
|
101
104
|
|
|
102
|
-
`CardMedia` abre a linha com a moldura de ícone
|
|
105
|
+
`CardMedia` abre a linha com a moldura de ícone do Opus — o mesmo [`IconTile`](/ui/icon-tile), na
|
|
103
106
|
escala `sm`, com `context` e `variant` para declarar o significado da cor. `CardAction` fica no
|
|
104
107
|
extremo oposto ao título, sem precisar de classe de alinhamento.
|
|
105
108
|
|
|
@@ -137,17 +140,35 @@ estrutura do documento não muda a aparência.
|
|
|
137
140
|
</Card>
|
|
138
141
|
```
|
|
139
142
|
|
|
140
|
-
|
|
143
|
+
Quando o título leva a outra tela, coloque o link dentro dele. O heading continua sendo o
|
|
144
|
+
`CardTitle`, e o link fica no seu conteúdo:
|
|
145
|
+
|
|
146
|
+
```tsx preview col
|
|
147
|
+
<Card>
|
|
148
|
+
<CardHeader>
|
|
149
|
+
<CardTitle>
|
|
150
|
+
<a href="#" className="hover:underline">Revisão dos 20.000 km</a>
|
|
151
|
+
</CardTitle>
|
|
152
|
+
<CardDescription>Agendada para 12 de maio, às 9h.</CardDescription>
|
|
153
|
+
</CardHeader>
|
|
154
|
+
</Card>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Use `asChild` só quando outro componente já renderiza o próprio heading e precisa receber a escala do
|
|
158
|
+
título. Com `asChild`, o elemento é o filho: `level` deixa de valer, e um link passado ali substitui
|
|
159
|
+
o heading em vez de ficar dentro dele.
|
|
141
160
|
|
|
142
161
|
## A matriz de slots
|
|
143
162
|
|
|
144
163
|
As regiões são independentes: o cabeçalho existe sem corpo, o corpo existe sem cabeçalho e o rodapé
|
|
145
|
-
entra apenas quando há ações persistentes.
|
|
146
|
-
|
|
164
|
+
entra apenas quando há ações persistentes. Os divisores acompanham as regiões presentes, e o corpo
|
|
165
|
+
reassume o respiro de cima ou de baixo quando é a primeira ou a última região. No layout contínuo, o
|
|
166
|
+
cabeçalho só se aproxima da região seguinte quando ela existe: sozinho, ele fecha o card com o mesmo
|
|
167
|
+
respiro que tem em cima.
|
|
147
168
|
|
|
148
169
|
```tsx preview col
|
|
149
170
|
render(
|
|
150
|
-
<div className="grid
|
|
171
|
+
<div className="grid grid-cols-2 gap-4">
|
|
151
172
|
<Card>
|
|
152
173
|
<CardHeader>
|
|
153
174
|
<CardMedia>
|
|
@@ -199,6 +220,11 @@ render(
|
|
|
199
220
|
);
|
|
200
221
|
```
|
|
201
222
|
|
|
223
|
+
No layout contínuo, o respiro de baixo de um cabeçalho sem corpo nem rodapé segue o de cima. Essa
|
|
224
|
+
regra só vale quando o cabeçalho é a última região e tem precedência sobre o `className`, então um
|
|
225
|
+
`pb-*` no `CardHeader` não altera esse recuo. Para um recuo diferente, escolha o `layout`: no
|
|
226
|
+
`sectioned`, as regiões usam o recuo simétrico e mais contido das superfícies de operação.
|
|
227
|
+
|
|
202
228
|
## Propriedades de Card
|
|
203
229
|
|
|
204
230
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
@@ -231,7 +257,7 @@ As demais propriedades são as propriedades nativas de `div`.
|
|
|
231
257
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
232
258
|
|---|---|---|---|
|
|
233
259
|
| `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | `3` | Hierarquia do documento. O tamanho vem do `layout`, nunca do nível. |
|
|
234
|
-
| `asChild` | `boolean` | `false` | Usa o filho como
|
|
260
|
+
| `asChild` | `boolean` | `false` | Usa o filho como elemento do título, com a escala do layout. Reserve para um componente que já renderiza um heading; com `asChild`, `level` não se aplica. |
|
|
235
261
|
| `className` | `string` | | Ajusta o título. |
|
|
236
262
|
|
|
237
263
|
## Propriedades de CardDescription
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
## Um slide por vez
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Use `Carousel` para percorrer uma sequência de itens do mesmo tipo em um espaço limitado, um ou
|
|
4
|
+
alguns de cada vez. Para consultar e comparar muitos itens, prefira uma lista, como
|
|
5
|
+
[`ActionList`](/ui/action-list), que mostra tudo de uma vez.
|
|
6
|
+
|
|
7
|
+
Componha `Carousel` > `CarouselContent` > `CarouselItem` e acrescente `CarouselPrevious` e
|
|
8
|
+
`CarouselNext` para navegar. As setas ficam `3rem` fora da área dos slides, então reserve essa
|
|
9
|
+
margem lateral no entorno, como o `mx-12` do exemplo. Dê um nome ao carrossel com `aria-label`:
|
|
10
|
+
ele é anunciado como uma região.
|
|
4
11
|
|
|
5
12
|
```tsx preview
|
|
6
|
-
<Carousel className="mx-12 w-full max-w-xs">
|
|
13
|
+
<Carousel className="mx-12 w-full max-w-xs" aria-label="Sessões recentes">
|
|
7
14
|
<CarouselContent>
|
|
8
15
|
<CarouselItem>
|
|
9
16
|
<div className="flex h-32 items-center justify-center rounded-lg border bg-card text-sm">
|
|
@@ -28,10 +35,11 @@ Compõe Carousel>CarouselContent>CarouselItem, com CarouselPrevious/CarouselNext
|
|
|
28
35
|
|
|
29
36
|
## Vários por vista
|
|
30
37
|
|
|
31
|
-
|
|
38
|
+
A largura de cada `CarouselItem` decide quantos slides cabem na área visível: `basis-1/3` mostra
|
|
39
|
+
três por vez. `opts={{ align: 'start' }}` alinha o primeiro slide à borda inicial.
|
|
32
40
|
|
|
33
41
|
```tsx preview
|
|
34
|
-
<Carousel className="mx-12 w-full max-w-sm" opts={{ align: 'start' }}>
|
|
42
|
+
<Carousel className="mx-12 w-full max-w-sm" opts={{ align: 'start' }} aria-label="Sessões da semana">
|
|
35
43
|
<CarouselContent>
|
|
36
44
|
{['Sessão #128', 'Sessão #131', 'Sessão #134', 'Sessão #137', 'Sessão #140'].map((session) => (
|
|
37
45
|
<CarouselItem key={session} className="basis-1/3">
|
|
@@ -48,10 +56,11 @@ O basis do CarouselItem decide quantos cabem na vista — basis-1/3 mostra três
|
|
|
48
56
|
|
|
49
57
|
## Vertical
|
|
50
58
|
|
|
51
|
-
orientation=vertical empilha os slides
|
|
59
|
+
`orientation="vertical"` empilha os slides, e as setas passam para cima e para baixo, também
|
|
60
|
+
`3rem` fora da área dos slides. Dê uma altura ao `CarouselContent` para delimitar a área visível.
|
|
52
61
|
|
|
53
62
|
```tsx preview
|
|
54
|
-
<Carousel className="w-full max-w-xs" orientation="vertical">
|
|
63
|
+
<Carousel className="my-12 w-full max-w-xs" orientation="vertical" aria-label="Agentes">
|
|
55
64
|
<CarouselContent className="h-48">
|
|
56
65
|
<CarouselItem>
|
|
57
66
|
<div className="flex h-24 items-center justify-center rounded-lg border bg-card text-sm">
|
|
@@ -74,6 +83,20 @@ orientation=vertical empilha os slides; as setas migram para cima e para baixo (
|
|
|
74
83
|
</Carousel>
|
|
75
84
|
```
|
|
76
85
|
|
|
86
|
+
## Teclado
|
|
87
|
+
|
|
88
|
+
Com o foco dentro do carrossel, as setas do teclado mostram o slide anterior e o próximo. Na
|
|
89
|
+
orientação horizontal, use as setas esquerda e direita; na vertical, as setas para cima e para
|
|
90
|
+
baixo. Os botões de navegação ficam desabilitados nas pontas, a menos que `opts` declare
|
|
91
|
+
`{ loop: true }`.
|
|
92
|
+
|
|
93
|
+
Em um campo editável dentro de um slide, como `input`, `textarea`, `select` ou um elemento
|
|
94
|
+
`contenteditable`, as setas continuam movendo o cursor ou mudando a opção, sem trocar de slide. O
|
|
95
|
+
mesmo vale para controles que navegam pelas setas, como [`Slider`](/ui/slider),
|
|
96
|
+
[`RadioGroup`](/ui/radio-group), [`Tabs`](/ui/tabs), [`Toggle`](/ui/toggle) em grupo,
|
|
97
|
+
[`Accordion`](/ui/accordion), listas e menus. Um carrossel colocado dentro de uma barra de
|
|
98
|
+
ferramentas ou de uma grade continua respondendo às setas.
|
|
99
|
+
|
|
77
100
|
## Propriedades de Carousel
|
|
78
101
|
|
|
79
102
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
@@ -83,6 +106,14 @@ orientation=vertical empilha os slides; as setas migram para cima e para baixo (
|
|
|
83
106
|
| `setApi` | `(api: EmblaCarouselType \| undefined) => void` | | Recebe a instância do Embla para controle externo, como navegar com `scrollTo` ou ler o slide ativo. |
|
|
84
107
|
| `plugins` | `EmblaPluginType[]` | | Plugins do Embla associados ao carrossel, como autoplay. |
|
|
85
108
|
|
|
109
|
+
Os demais atributos, como `aria-label` e `className`, vão para o elemento raiz.
|
|
110
|
+
|
|
111
|
+
## Propriedades de CarouselContent
|
|
112
|
+
|
|
113
|
+
`CarouselContent` delimita a área visível e recorta o que passa dela. Não tem props próprias;
|
|
114
|
+
`className` e os demais atributos de `div` vão para a faixa interna que se desloca e contém os
|
|
115
|
+
slides. Na orientação vertical, é nela que entra a altura, como `h-48`.
|
|
116
|
+
|
|
86
117
|
## Propriedades de CarouselItem
|
|
87
118
|
|
|
88
119
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
## Conversa com resposta integral
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Use `Chat` para uma conversa completa: transcript, composer, indicador de atividade e rolagem
|
|
4
|
+
automática até a última mensagem. No modo mais simples, o componente guarda as mensagens e chama
|
|
5
|
+
`send` com o histórico a cada envio; o texto devolvido entra no transcript como resposta. Dê altura
|
|
6
|
+
ao contêiner, porque o transcript rola dentro dele.
|
|
4
7
|
|
|
5
8
|
```tsx preview
|
|
6
9
|
<div className="h-96 rounded-lg border">
|
|
7
10
|
<Chat
|
|
8
|
-
greeting="
|
|
11
|
+
greeting="Pergunte sobre os workspaces da sua equipe."
|
|
9
12
|
send={async (messages) => {
|
|
10
13
|
await new Promise((r) => setTimeout(r, 500))
|
|
11
14
|
const last = messages[messages.length - 1]
|
|
@@ -15,12 +18,17 @@ Um chat mínimo: lista de mensagens + composer. A conversa é gerenciada por den
|
|
|
15
18
|
</div>
|
|
16
19
|
```
|
|
17
20
|
|
|
21
|
+
**Enter** envia e **Shift+Enter** quebra a linha. Com o composer vazio, **↑** recupera as mensagens
|
|
22
|
+
anteriores da pessoa e **↓** volta em direção ao rascunho; durante a edição, as setas continuam
|
|
23
|
+
movendo o cursor. `greeting` ocupa o transcript vazio, some quando a conversa começa e não entra no
|
|
24
|
+
histórico enviado a `send`.
|
|
25
|
+
|
|
18
26
|
## Estado vazio composto
|
|
19
27
|
|
|
20
28
|
Quando uma frase não basta — marca, nome do agente e saudação administrável, por exemplo — o
|
|
21
29
|
app compõe o vazio com os slots de `Empty` e entrega em `empty`. O nó ocupa o mesmo lugar do
|
|
22
|
-
`greeting`, vence quando os dois existem e some quando a conversa começa.
|
|
23
|
-
|
|
30
|
+
`greeting`, vence quando os dois existem e some quando a conversa começa. Não envolva o conteúdo em
|
|
31
|
+
`Empty`: o chat já é a estrutura, e a moldura tracejada é para região de criação.
|
|
24
32
|
|
|
25
33
|
```tsx preview
|
|
26
34
|
<div className="h-72 rounded-lg border">
|
|
@@ -30,8 +38,8 @@ em volta: o chat já é a estrutura, e a moldura tracejada é para região de cr
|
|
|
30
38
|
<EmptyMedia variant="icon">
|
|
31
39
|
<Sparkles />
|
|
32
40
|
</EmptyMedia>
|
|
33
|
-
<EmptyTitle>
|
|
34
|
-
<EmptyDescription>Pergunte sobre
|
|
41
|
+
<EmptyTitle>Assistente da equipe</EmptyTitle>
|
|
42
|
+
<EmptyDescription>Pergunte sobre os workspaces, os membros e as atividades da equipe.</EmptyDescription>
|
|
35
43
|
</EmptyHeader>
|
|
36
44
|
}
|
|
37
45
|
send={async () => 'Pronto.'}
|
|
@@ -39,40 +47,52 @@ em volta: o chat já é a estrutura, e a moldura tracejada é para região de cr
|
|
|
39
47
|
</div>
|
|
40
48
|
```
|
|
41
49
|
|
|
42
|
-
## O backend
|
|
50
|
+
## O backend
|
|
43
51
|
|
|
44
|
-
O `send` posta a conversa no
|
|
52
|
+
O `send` posta a conversa no endpoint do aplicativo, que resolve o usuário e executa o agente
|
|
53
|
+
sobre as actions expostas à IA, com a autorização desse usuário:
|
|
45
54
|
|
|
46
55
|
```ts
|
|
47
56
|
// Rota do app (server): recebe { messages }, devolve { reply }.
|
|
48
57
|
async function chatRoute(req) {
|
|
49
|
-
const base = await auth.resolveContext(req) //
|
|
58
|
+
const base = await auth.resolveContext(req) // Quem é o usuário.
|
|
50
59
|
const { messages } = req.body
|
|
51
|
-
const { text } = await runtime.aiFor(base)!.run(messages) //
|
|
60
|
+
const { text } = await runtime.aiFor(base)!.run(messages) // O agente usa as actions.
|
|
52
61
|
return { reply: text }
|
|
53
62
|
}
|
|
54
63
|
```
|
|
55
64
|
|
|
56
65
|
```tsx
|
|
57
|
-
// No cliente, o send
|
|
66
|
+
// No cliente, o send chama essa rota:
|
|
58
67
|
<Chat send={async (messages) => (await api.post('/chat', { messages })).reply} />
|
|
59
68
|
```
|
|
60
69
|
|
|
61
|
-
O agente só executa actions
|
|
70
|
+
O agente só executa actions expostas à IA (`ai: true` ou um objeto `ai` sem `enabled: false`) e,
|
|
71
|
+
nelas, aplica o `authorize` com o contexto do usuário; uma action sem `authorize` fica aberta a qualquer usuário autenticado. Actions com
|
|
72
|
+
`ai.destructive` ou `ai.requiresConfirmation` são recusadas nesse exemplo, porque ele não passa
|
|
73
|
+
`confirm`; para aprovar essas chamadas, use `run(messages, { confirm })`. Para expor uma action ao
|
|
74
|
+
agente e conhecer as demais opções do runtime, consulte a página de [IA generativa](/docs/ai).
|
|
75
|
+
|
|
76
|
+
## Streaming de eventos
|
|
77
|
+
|
|
78
|
+
`send` também pode devolver um `AsyncIterable<ChatEvent>`. Assim, a resposta chega aos poucos e a
|
|
79
|
+
conversa mostra o que o agente está fazendo. O protocolo tem quatro eventos:
|
|
62
80
|
|
|
63
|
-
|
|
81
|
+
- `{ type: 'text', delta }` acrescenta um trecho à resposta em andamento.
|
|
82
|
+
- `{ type: 'tool', name, detail? }` informa a ferramenta em uso. O Chat mostra esse passo no
|
|
83
|
+
indicador de atividade, com o rótulo de `humanizeTool`, e não o grava no transcript.
|
|
84
|
+
- `{ type: 'artifact', kind, ref, title? }` acrescenta ao transcript algo produzido na conversa,
|
|
85
|
+
apresentado por `renderArtifact` ou, sem ele, como link.
|
|
86
|
+
- `{ type: 'done', ok, error? }` encerra o turno; com `ok: false`, o transcript recebe a mensagem de
|
|
87
|
+
erro.
|
|
64
88
|
|
|
65
|
-
|
|
66
|
-
`
|
|
67
|
-
**indicador vivo** (pontinhos + rótulo humano — nunca uma mensagem no transcript) e
|
|
68
|
-
artefatos produzidos na conversa rendem pelo `renderArtifact` do app. O backend liga em
|
|
69
|
-
`runtime.aiFor(base).runStream(...)` e streama por SSE; o `Promise<string>` de sempre
|
|
70
|
-
continua valendo — é o caso degenerado do protocolo.
|
|
89
|
+
No backend, `runtime.aiFor(base).runStream(...)` emite esses eventos, que podem seguir por SSE.
|
|
90
|
+
Devolver `Promise<string>` continua válido: equivale a um único `text` seguido de `done`.
|
|
71
91
|
|
|
72
92
|
```tsx preview
|
|
73
93
|
<div className="h-96 rounded-lg border">
|
|
74
94
|
<Chat
|
|
75
|
-
greeting="
|
|
95
|
+
greeting="Pergunte algo e acompanhe a resposta chegando aos poucos."
|
|
76
96
|
send={async function* (messages) {
|
|
77
97
|
yield { type: 'tool', name: 'query' }
|
|
78
98
|
await new Promise((r) => setTimeout(r, 600))
|
|
@@ -88,32 +108,93 @@ continua valendo — é o caso degenerado do protocolo.
|
|
|
88
108
|
</div>
|
|
89
109
|
```
|
|
90
110
|
|
|
91
|
-
|
|
92
|
-
componente ao trocar de conversa.
|
|
93
|
-
|
|
111
|
+
Para retomar uma conversa salva, passe `initialMessages` com o histórico persistido e troque a
|
|
112
|
+
`key` do componente ao trocar de conversa. `kickoff` inicia a conversa pelo assistente, uma vez,
|
|
113
|
+
quando o transcript nasce vazio.
|
|
94
114
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
115
|
+
## Conversa controlada pelo aplicativo
|
|
116
|
+
|
|
117
|
+
Quando o aplicativo já é dono do transcript — por exemplo, porque o servidor mantém a conversa e a
|
|
118
|
+
reenvia a cada reconexão —, passe `messages` em vez de `send`. Nesse modo, `onSend` recebe o texto
|
|
119
|
+
enviado, `busy` bloqueia novos envios enquanto o turno corre e `activity` controla o indicador.
|
|
120
|
+
`busy` não bloqueia a digitação: a pessoa pode escrever a próxima mensagem enquanto espera.
|
|
121
|
+
Retornar `false` em `onSend` devolve o texto ao composer, para que nada se perca em uma falha de
|
|
122
|
+
envio.
|
|
123
|
+
|
|
124
|
+
Os itens podem carregar `id` e `createdAt`. `renderMessageActions` acrescenta ações discretas às
|
|
125
|
+
mensagens enviadas e recebidas, visíveis em hover ou foco. O slot não busca dados: carregue
|
|
126
|
+
informação complementar somente depois da interação da pessoa e aplique novamente a autorização.
|
|
127
|
+
No exemplo, `activity=""` mostra somente os pontos, sem rótulo, e cada mensagem oferece a cópia do
|
|
128
|
+
texto.
|
|
129
|
+
|
|
130
|
+
```tsx preview
|
|
131
|
+
const nextId = useRef(3)
|
|
132
|
+
const [items, setItems] = useState<ChatTranscriptItem[]>([
|
|
133
|
+
{ id: '1', role: 'user', content: 'Qual é o status da Empresa X?' },
|
|
134
|
+
{ id: '2', role: 'assistant', content: 'A Empresa X está **ativa**, com 3 agentes.' },
|
|
135
|
+
])
|
|
136
|
+
const [busy, setBusy] = useState(false)
|
|
137
|
+
|
|
138
|
+
render(
|
|
139
|
+
<div className="h-96 rounded-lg border">
|
|
140
|
+
<Chat
|
|
141
|
+
messages={items}
|
|
142
|
+
busy={busy}
|
|
143
|
+
activity={busy ? '' : undefined}
|
|
144
|
+
onSend={async (text) => {
|
|
145
|
+
setItems((list) => [...list, { id: String(nextId.current++), role: 'user', content: text }])
|
|
146
|
+
setBusy(true)
|
|
147
|
+
await new Promise((r) => setTimeout(r, 800))
|
|
148
|
+
setItems((list) => [
|
|
149
|
+
...list,
|
|
150
|
+
{ id: String(nextId.current++), role: 'assistant', content: 'Mensagem registrada.' },
|
|
151
|
+
])
|
|
152
|
+
setBusy(false)
|
|
153
|
+
}}
|
|
154
|
+
renderMessageActions={(message) => (
|
|
155
|
+
<Copyable
|
|
156
|
+
value={message.content}
|
|
157
|
+
aria-label="Copiar mensagem"
|
|
158
|
+
className="text-muted-foreground hover:text-foreground"
|
|
159
|
+
/>
|
|
160
|
+
)}
|
|
161
|
+
/>
|
|
162
|
+
</div>,
|
|
163
|
+
)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
`activity` aceita `undefined`, que esconde o indicador; `null`, que mostra “Pensando…”; uma string
|
|
167
|
+
com o rótulo já humanizado pelo aplicativo; ou `''`, que mostra somente os pontos e mantém
|
|
168
|
+
“Pensando…” como nome acessível. No modo autogerenciado, o Chat decide o indicador sozinho e ignora
|
|
169
|
+
`busy` e `activity`.
|
|
99
170
|
|
|
100
171
|
## Propriedades de Chat
|
|
101
172
|
|
|
102
173
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
103
174
|
|---|---|---|---|
|
|
104
|
-
| `send` | `(messages: ChatMessage[]) => Promise<string> \| AsyncIterable<ChatEvent>` | | Modo autogerenciado:
|
|
105
|
-
| `messages` | `ChatTranscriptItem[]` | | Modo controlado: o transcript vem do
|
|
175
|
+
| `send` | `(messages: ChatMessage[]) => Promise<string> \| AsyncIterable<ChatEvent>` | | Modo autogerenciado: recebe o histórico com a nova mensagem e devolve a resposta inteira ou um stream de eventos. Ignorado no modo controlado. |
|
|
176
|
+
| `messages` | `ChatTranscriptItem[]` | | Modo controlado: o transcript vem do aplicativo. Com ele, `onSend`, `busy` e `activity` passam a valer. |
|
|
106
177
|
| `onSend` | `(text: string) => void \| boolean \| Promise<void \| boolean>` | | Modo controlado: recebe o texto enviado; retornar `false` devolve o texto ao composer. |
|
|
107
|
-
| `busy` | `boolean` | | Modo controlado:
|
|
108
|
-
| `activity` | `string \| null` | `undefined` |
|
|
109
|
-
| `notice` | `ReactNode` | | Aviso do
|
|
110
|
-
| `composerActions` | `ReactNode` | | Seletores discretos na barra do composer
|
|
178
|
+
| `busy` | `boolean` | `false` | Modo controlado: bloqueia o envio enquanto o turno corre; a digitação continua liberada. |
|
|
179
|
+
| `activity` | `string \| null` | `undefined` | Modo controlado: indicador de atividade. `undefined` esconde, `null` mostra “Pensando…”, uma string mostra o rótulo e `''` mostra somente os pontos. |
|
|
180
|
+
| `notice` | `ReactNode` | | Aviso do aplicativo acima do composer, como credencial expirada ou agente desatualizado. |
|
|
181
|
+
| `composerActions` | `ReactNode` | | Seletores discretos na barra do composer, como agente, aplicativo ou escopo. |
|
|
111
182
|
| `composerClassName` | `string` | | Ajusta o contêiner externo do composer sem alcançar o DOM interno. |
|
|
112
183
|
| `greeting` | `string` | | Texto do estado vazio; some quando a conversa começa. |
|
|
113
|
-
| `empty` | `ReactNode` | | Estado vazio composto pelo
|
|
184
|
+
| `empty` | `ReactNode` | | Estado vazio composto pelo aplicativo; vence `greeting` quando os dois existem. |
|
|
114
185
|
| `initialMessages` | `ChatMessage[]` | | Histórico inicial do modo autogerenciado; troque a `key` ao trocar de conversa. |
|
|
115
186
|
| `kickoff` | `() => Promise<string> \| AsyncIterable<ChatEvent>` | | Conversa que começa pelo assistente, uma vez, quando o transcript nasce vazio. |
|
|
116
|
-
| `renderArtifact` | `(artifact: ChatArtifact) => ReactNode` | link com o título |
|
|
117
|
-
| `renderMessageActions` | `(message: ChatTranscriptMessage) => ReactNode` | | Ações contextuais
|
|
118
|
-
| `humanizeTool` | `(name: string, detail?: string) => string` | pt-BR
|
|
187
|
+
| `renderArtifact` | `(artifact: ChatArtifact) => ReactNode` | link com o título | Apresentação do evento `artifact`. |
|
|
188
|
+
| `renderMessageActions` | `(message: ChatTranscriptMessage) => ReactNode` | | Ações contextuais de mensagens enviadas e recebidas; ficam visíveis em hover ou foco. |
|
|
189
|
+
| `humanizeTool` | `(name: string, detail?: string) => string` | rótulos em pt-BR | Rótulo do indicador para o evento `tool` no modo autogerenciado. |
|
|
119
190
|
| `placeholder` | `string` | `'Escreva uma mensagem…'` | Placeholder do composer. |
|
|
191
|
+
| `className` | `string` | | Classes da raiz, que ocupa a altura do contêiner (`h-full`). |
|
|
192
|
+
|
|
193
|
+
## Tipos do transcript
|
|
194
|
+
|
|
195
|
+
| Tipo | Forma | Uso |
|
|
196
|
+
|---|---|---|
|
|
197
|
+
| `ChatMessage` | `{ id?, createdAt?, role: 'user' \| 'assistant', content }` | Histórico enviado a `send` e aceito por `initialMessages`. `createdAt` é um instante ISO-8601. |
|
|
198
|
+
| `ChatTranscriptItem` | `ChatMessage` com `role` também `'error'`, ou `{ id?, createdAt?, role: 'artifact', artifact: ChatArtifact }` | Itens de `messages` no modo controlado. Mensagens `error` aparecem destacadas no transcript. |
|
|
199
|
+
| `ChatTranscriptMessage` | Os itens de `ChatTranscriptItem` que têm `content` | Argumento de `renderMessageActions`. |
|
|
200
|
+
| `ChatArtifact` | `{ kind, ref, title? }` | Algo produzido na conversa, como um link ou um relatório; `ref` é o endereço ou identificador. |
|