@softize/opus 27.1.0 → 28.0.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.
Files changed (37) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/bin/lib/check.mjs +139 -30
  3. package/docs/adr/0015-action-size-follows-interaction-density.md +2 -0
  4. package/docs/adr/0029-page-header-is-the-single-page-introduction.md +3 -1
  5. package/docs/adr/0060-surface-composition-separates-chrome-and-intro.md +161 -0
  6. package/docs/adr/README.md +2 -0
  7. package/package.json +1 -1
  8. package/registry/skills/build-opus-ui/SKILL.md +11 -11
  9. package/registry/skills/build-opus-ui/references/evaluations.md +10 -0
  10. package/registry/skills/build-opus-ui/references/ui-patterns.md +17 -15
  11. package/src/ui/components/patterns/list.tsx +62 -53
  12. package/src/ui/components/patterns/page.tsx +146 -38
  13. package/src/ui/components/patterns/presentation.tsx +44 -59
  14. package/src/ui/components/patterns/structural-header.tsx +42 -6
  15. package/src/ui/components/patterns/surface-anatomy.ts +52 -22
  16. package/src/ui/components/patterns/surface.tsx +2 -3
  17. package/src/ui/components/primitives/control.ts +2 -2
  18. package/src/ui/components/primitives/dialog.tsx +7 -2
  19. package/src/ui/components/primitives/drawer.tsx +7 -2
  20. package/src/ui/components/primitives/icon-picker.tsx +271 -34
  21. package/src/ui/components/primitives/pagination.tsx +5 -4
  22. package/src/ui/components/primitives/tabs.tsx +15 -2
  23. package/src/ui/components/primitives/toggle.tsx +1 -1
  24. package/src/ui/docs/content/action-list.md +11 -2
  25. package/src/ui/docs/content/button.md +7 -7
  26. package/src/ui/docs/content/compositions.md +35 -23
  27. package/src/ui/docs/content/dialog.md +18 -6
  28. package/src/ui/docs/content/drawer.md +17 -5
  29. package/src/ui/docs/content/icon-picker.md +37 -19
  30. package/src/ui/docs/content/input.md +1 -1
  31. package/src/ui/docs/content/page.md +169 -69
  32. package/src/ui/docs/content/pagination.md +7 -8
  33. package/src/ui/docs/content/presentation.md +4 -3
  34. package/src/ui/docs/content/surface.md +8 -5
  35. package/src/ui/docs/content/tabs.md +12 -4
  36. package/src/ui/meta.ts +1 -1
  37. package/src/ui/react.tsx +9 -1
@@ -24,8 +24,8 @@ Cada família dá um nome próprio a cada região. A tabela mostra a correspond
24
24
  | Navegação | `PageNavigation` ou `PageBack` | `DialogNavigation` | `DrawerNavigation` | Não existe |
25
25
  | Título no cabeçalho | `PageTitle` | `DialogTitle` | `DrawerTitle` | `SurfaceTitle` |
26
26
  | Ações do cabeçalho | `PageActions` | `DialogActions` | `DrawerActions` | `SurfaceActions` |
27
- | Intro | `Surface level={1}` no início do `PageBody` | `DialogIntro` | `DrawerIntro` | Não existe |
28
- | Ações da intro | Ações da `Surface level={1}` | `DialogIntroActions` | `DrawerIntroActions` | Não existe |
27
+ | Intro | `PageIntro` no início do `PageBody` | `DialogIntro` | `DrawerIntro` | Não existe |
28
+ | Ações da intro | `PageIntroActions` | `DialogIntroActions` | `DrawerIntroActions` | Não existe |
29
29
  | Corpo | `PageBody` | `DialogBody` | `DrawerBody` | `SurfaceBody` |
30
30
  | Rodapé | `PageFooter` | `DialogFooter` | `DrawerFooter` | `SurfaceFooter` |
31
31
  | Divisores | Antes do `PageFooter` | `sectioned` (padrão) | `sectioned` (padrão) | `sectioned` |
@@ -97,7 +97,7 @@ function DialogWithIntro({ layout, label }) {
97
97
  <DialogContent layout={layout}>
98
98
  <DialogHeader>
99
99
  <DialogActions>
100
- <Button variant="ghost" size="icon" aria-label="Abrir conversa">
100
+ <Button variant="ghost" size="icon-sm" aria-label="Abrir conversa">
101
101
  <MessageCircle />
102
102
  </Button>
103
103
  </DialogActions>
@@ -142,7 +142,7 @@ function CompactDialog({ layout, label }) {
142
142
  <Button variant="outline" size="sm">
143
143
  Ver histórico
144
144
  </Button>
145
- <Button variant="ghost" size="icon" aria-label="Abrir conversa">
145
+ <Button variant="ghost" size="icon-sm" aria-label="Abrir conversa">
146
146
  <MessageCircle />
147
147
  </Button>
148
148
  </DialogActions>
@@ -197,7 +197,7 @@ function OrderField() {
197
197
  function CollapseButton() {
198
198
  return (
199
199
  <DrawerClose asChild>
200
- <Button variant="ghost" size="icon" aria-label="Recolher painel">
200
+ <Button variant="ghost" size="icon-sm" aria-label="Recolher painel">
201
201
  <ChevronsRight />
202
202
  </Button>
203
203
  </DrawerClose>
@@ -216,7 +216,7 @@ function DrawerWithIntro({ layout, label }) {
216
216
  <CollapseButton />
217
217
  </DrawerNavigation>
218
218
  <DrawerActions>
219
- <Button variant="ghost" size="icon" aria-label="Abrir conversa">
219
+ <Button variant="ghost" size="icon-sm" aria-label="Abrir conversa">
220
220
  <MessageCircle />
221
221
  </Button>
222
222
  </DrawerActions>
@@ -261,7 +261,7 @@ function CompactDrawer({ layout, label }) {
261
261
  <Button variant="outline" size="sm">
262
262
  Ver histórico
263
263
  </Button>
264
- <Button variant="ghost" size="icon" aria-label="Abrir conversa">
264
+ <Button variant="ghost" size="icon-sm" aria-label="Abrir conversa">
265
265
  <MessageCircle />
266
266
  </Button>
267
267
  </DrawerActions>
@@ -300,8 +300,8 @@ painel.
300
300
 
301
301
  ## Page
302
302
 
303
- A `Page` não tem um slot de intro. Com intro, o `PageHeader` guarda a navegação e as ações da
304
- página, e uma `Surface level={1}` abre o `PageBody` com o título e as ações do conteúdo. A página
303
+ Na composição com intro, o `PageHeader` guarda a navegação e as ações da
304
+ página, e uma `PageIntro` abre o `PageBody` com o título e as ações do conteúdo. A página
305
305
  precisa de exatamente um heading principal, por isso o `PageHeader` dessa composição não leva
306
306
  `PageTitle`.
307
307
 
@@ -322,27 +322,20 @@ render(
322
322
  </Breadcrumb>
323
323
  </PageNavigation>
324
324
  <PageActions>
325
- <Button variant="ghost" size="icon" aria-label="Abrir conversa">
325
+ <Button variant="ghost" size="icon-sm" aria-label="Abrir conversa">
326
326
  <MessageCircle />
327
327
  </Button>
328
328
  </PageActions>
329
329
  </PageHeader>
330
330
  <PageBody>
331
- <Surface
332
- as="section"
333
- level={1}
334
- title="Editar ordem de serviço"
335
- actions={
336
- <Button variant="outline" size="sm">
337
- Ver histórico
338
- </Button>
339
- }
340
- >
331
+ <PageIntro>
332
+ <PageTitle>Editar ordem de serviço</PageTitle>
333
+ <PageIntroActions><Button variant="outline" size="sm">Ver histórico</Button></PageIntroActions>
334
+ </PageIntro>
341
335
  <div className="space-y-2">
342
336
  <Label htmlFor="page-intro-owner">Responsável</Label>
343
337
  <Input id="page-intro-owner" defaultValue="Marina Alves" />
344
338
  </div>
345
- </Surface>
346
339
  </PageBody>
347
340
  <PageFooter>
348
341
  <ButtonGroup mode="spaced">
@@ -380,7 +373,7 @@ render(
380
373
  <Button variant="outline" size="sm">
381
374
  Ver histórico
382
375
  </Button>
383
- <Button variant="ghost" size="icon" aria-label="Abrir conversa">
376
+ <Button variant="ghost" size="icon-sm" aria-label="Abrir conversa">
384
377
  <MessageCircle />
385
378
  </Button>
386
379
  </PageActions>
@@ -449,7 +442,7 @@ render(
449
442
  <Button variant="outline" size="sm">
450
443
  Ver histórico
451
444
  </Button>
452
- <Button variant="ghost" size="icon" aria-label="Abrir conversa">
445
+ <Button variant="ghost" size="icon-sm" aria-label="Abrir conversa">
453
446
  <MessageCircle />
454
447
  </Button>
455
448
  </SurfaceActions>
@@ -477,3 +470,22 @@ Os dois panes recebem conteúdos diferentes sem mudar de componente: o primeiro
477
470
  [`Sidebar`](/ui/sidebar), que já tem anatomia própria, e o segundo, uma `Surface` completa. A
478
471
  rolagem também pertence ao conteúdo: a `Surface` ocupa a altura do pane com `flex h-full flex-col`,
479
472
  e o `SurfaceBody` declara `min-h-0 flex-1 overflow-y-auto` para rolar entre o cabeçalho e o rodapé.
473
+
474
+ ## Ritmo entre regiões e blocos
475
+
476
+ Surface (incluindo cards e seções), Page, Dialog, Drawer e Tabs organizam o conteúdo
477
+ com intervalos de `1rem`. Os bodies separam seus blocos diretos; grupos internos podem
478
+ ter densidade própria. DetailGroup e Separator não criam margens externas.
479
+
480
+ Sem delimitação, Surface e Tabs não adicionam padding inferior. Uma Surface com moldura
481
+ ou elevação, assim como Dialog e Drawer, reserva `1rem` até a borda. No layout contínuo,
482
+ o intervalo vem da região anterior. No seccionado, há `1rem` entre cada divisória e o
483
+ conteúdo adjacente. Não some padding e gap para expressar o mesmo intervalo.
484
+
485
+ Page conserva os recuos laterais e a largura de leitura. Seu body não acrescenta padding
486
+ inferior quando termina a página; antes de um footer seccionado, reserva `1rem` até a linha.
487
+ O modo `flush` remove recuos do body para uma lista ou tabela controlar sua própria borda,
488
+ mas mantém o intervalo entre blocos.
489
+
490
+ Ao migrar, remova `space-y`, `gap`, `pt` e `pb` locais que apenas reconstruíam esses defaults
491
+ nos slots. Preserve classes de layout internas, como uma grade ou um grupo de campos compacto.
@@ -48,7 +48,7 @@ distinta da página.
48
48
  ```
49
49
 
50
50
  O corpo cresce até o limite da janela e passa a rolar; cabeçalho e rodapé permanecem visíveis.
51
- Seus filhos diretos recebem o ritmo estrutural de `1.5rem`. Um grupo compacto, uma grade ou uma
51
+ Seus filhos diretos recebem o ritmo estrutural de `1rem`. Um grupo compacto, uma grade ou uma
52
52
  linha declara a própria relação em um wrapper filho; `flush` fica reservado ao conteúdo que
53
53
  controla todo o inset.
54
54
  O backdrop escurece a página sem aplicar desfoque.
@@ -126,13 +126,13 @@ fluxo modal encadeado, em que a superfície permanece aberta e troca de etapa.
126
126
  <DialogContent>
127
127
  <DialogHeader>
128
128
  <DialogNavigation>
129
- <Button variant="ghost" size="icon" aria-label="Voltar para a lista">
129
+ <Button variant="ghost" size="icon-sm" aria-label="Voltar para a lista">
130
130
  <ArrowLeft />
131
131
  </Button>
132
132
  </DialogNavigation>
133
133
  <DialogTitle>Evento 4821</DialogTitle>
134
134
  <DialogActions>
135
- <Button variant="ghost" size="icon" aria-label="Mais ações">
135
+ <Button variant="ghost" size="icon-sm" aria-label="Mais ações">
136
136
  <Ellipsis />
137
137
  </Button>
138
138
  </DialogActions>
@@ -146,9 +146,10 @@ fluxo modal encadeado, em que a superfície permanece aberta e troca de etapa.
146
146
  </Dialog>
147
147
  ```
148
148
 
149
- Voltar e ações do cabeçalho usam `Button` `ghost` no tamanho `icon` (2.25rem), o mesmo que a
150
- [`Presentation`](/ui/presentation) usa no voltar. O botão de fechar é menor: um `CloseButton` no
151
- quadrado `icon-sm` (1.75rem) por padrão.
149
+ O header compartilha a geometria de Page e Surface delimitada: padding de `1rem` e
150
+ linha mínima de `2rem`, nos dois layouts. Declare `size="sm"` nos botões textuais e
151
+ `size="icon-sm"` nos de ícone (`2rem`), incluindo o retorno. `CloseButton` já usa
152
+ `icon-sm` por padrão. Conteúdo maior pode expandir a linha; rodapés preservam sua escala.
152
153
 
153
154
  O cabeçalho aceita `DialogDescription` como subheading opcional para orientar sobre a finalidade.
154
155
  Omita quando repetir o título. Condições, regras de negócio e consequências necessárias à decisão
@@ -656,3 +657,14 @@ comparar as duas formas em cada `layout`, abra [Composições](/ui/compositions)
656
657
  | `id` | `string` | | Identificador para associação acessível explícita. |
657
658
  | `className` | `string` | | Ajusta a apresentação do parágrafo. |
658
659
  | `…props` | `ComponentProps<"p">` | | Atributos nativos. |
660
+
661
+ ## Espaçamento do corpo
662
+
663
+ O body separa os blocos diretos por `1rem`. Dialog e Drawer são superfícies delimitadas:
664
+ o conteúdo mantém `1rem` até a borda inferior, mesmo sem uma propriedade `framed`.
665
+ Em `sectioned`, o corpo tem `1rem` entre o conteúdo e cada divisória. Em `continuous`,
666
+ o cabeçalho fornece o intervalo superior; sem cabeçalho, o próprio corpo abre esse recuo.
667
+ Use `flush` quando o conteúdo controlar seus próprios recuos.
668
+
669
+ Na intro, `DialogTitle` usa a mesma escala de `PageTitle` (`1.875rem`). No header
670
+ compacto, o título conserva a escala de `1.125rem`. O nível semântico não altera essas medidas.
@@ -119,7 +119,7 @@ retorno de um fluxo encadeado, em que o painel permanece aberto e troca de etapa
119
119
  <DrawerContent side="right">
120
120
  <DrawerHeader>
121
121
  <DrawerNavigation>
122
- <Button variant="ghost" size="icon" aria-label="Voltar para a lista">
122
+ <Button variant="ghost" size="icon-sm" aria-label="Voltar para a lista">
123
123
  <ArrowLeft />
124
124
  </Button>
125
125
  </DrawerNavigation>
@@ -130,7 +130,7 @@ retorno de um fluxo encadeado, em que o painel permanece aberto e troca de etapa
130
130
  </DrawerMedia>
131
131
  <DrawerTitle>ABC-1D23</DrawerTitle>
132
132
  <DrawerActions>
133
- <Button variant="ghost" size="icon" aria-label="Mais ações">
133
+ <Button variant="ghost" size="icon-sm" aria-label="Mais ações">
134
134
  <Ellipsis />
135
135
  </Button>
136
136
  </DrawerActions>
@@ -144,9 +144,10 @@ retorno de um fluxo encadeado, em que o painel permanece aberto e troca de etapa
144
144
  </Drawer>
145
145
  ```
146
146
 
147
- Voltar e ações do cabeçalho usam `Button` `ghost` no tamanho `icon` (2.25rem), o mesmo que a
148
- [`Presentation`](/ui/presentation) usa no voltar. O botão de fechar é menor: um `CloseButton` no
149
- quadrado `icon-sm` (1.75rem) por padrão.
147
+ O header compartilha a geometria de Page e Surface delimitada: padding de `1rem` e
148
+ linha mínima de `2rem`, nos dois layouts. Declare `size="sm"` nos botões textuais e
149
+ `size="icon-sm"` nos de ícone (`2rem`), incluindo o retorno. `CloseButton` já usa
150
+ `icon-sm` por padrão. Conteúdo maior pode expandir a linha; rodapés preservam sua escala.
150
151
 
151
152
  O cabeçalho aceita `DrawerDescription` como subheading opcional para orientar sobre a finalidade.
152
153
  Omita quando repetir o título. Condições, regras de negócio e consequências necessárias à decisão
@@ -323,3 +324,14 @@ comparar as duas formas em cada `layout`, abra [Composições](/ui/compositions)
323
324
  | `id` | `string` | | Identificador para associação acessível explícita. |
324
325
  | `className` | `string` | | Ajusta a apresentação do parágrafo. |
325
326
  | `…props` | `ComponentProps<"p">` | | Atributos nativos. |
327
+
328
+ ## Espaçamento do corpo
329
+
330
+ O body separa os blocos diretos por `1rem`. Dialog e Drawer são superfícies delimitadas:
331
+ o conteúdo mantém `1rem` até a borda inferior, mesmo sem uma propriedade `framed`.
332
+ Em `sectioned`, o corpo tem `1rem` entre o conteúdo e cada divisória. Em `continuous`,
333
+ o cabeçalho fornece o intervalo superior; sem cabeçalho, o próprio corpo abre esse recuo.
334
+ Use `flush` quando o conteúdo controlar seus próprios recuos.
335
+
336
+ Na intro, `DrawerTitle` usa a mesma escala de `PageTitle` (`1.875rem`). No header
337
+ compacto, o título conserva a escala de `1.125rem`. O nível semântico não altera essas medidas.
@@ -1,18 +1,18 @@
1
1
  ## Escolher na paleta padrão
2
2
 
3
3
  Use `IconPicker` quando a pessoa puder escolher o ícone que identifica um registro, como um
4
- relatório ou um painel. A lista abre em um popover com busca, e o valor guardado é o nome do ícone em
5
- kebab-case, como `chart-line`. Selecionar novamente o ícone atual limpa o valor.
4
+ relatório ou um painel. A grade de ícones abre em um popover com busca em português, e o valor guardado é o nome do ícone em
5
+ kebab-case, como `chart-line`. Selecionar novamente o ícone atual limpa o valor. A grade exibe somente ícones; os nomes ficam disponíveis para leitores de tela e busca. A busca aceita o identificador técnico, o nome em português e sinônimos. `searchTerms` permite definir rótulos e termos de busca para uma paleta própria, sem alterar o valor salvo.
6
6
 
7
7
  ```tsx preview col md
8
- const [icon, setIcon] = useState('chart-line')
8
+ const [icon, setIcon] = useState("chart-line");
9
9
 
10
10
  render(
11
11
  <div className="grid gap-2">
12
12
  <Label htmlFor="report-icon">Ícone do relatório</Label>
13
13
  <IconPicker id="report-icon" value={icon} onChange={setIcon} />
14
14
  </div>,
15
- )
15
+ );
16
16
  ```
17
17
 
18
18
  ## Apresentar o ícone escolhido
@@ -22,8 +22,8 @@ padrão é exportada como `iconPickerIcons`; use-a em listas, cards e árvores,
22
22
  para nomes que não existam mais, como em `iconPickerIcons[name] ?? FileText`.
23
23
 
24
24
  ```tsx preview col md
25
- const [icon, setIcon] = useState('store')
26
- const SelectedIcon = iconPickerIcons[icon] ?? FileText
25
+ const [icon, setIcon] = useState("store");
26
+ const SelectedIcon = iconPickerIcons[icon] ?? FileText;
27
27
 
28
28
  render(
29
29
  <div className="flex items-center gap-3">
@@ -37,7 +37,7 @@ render(
37
37
  </ItemHeader>
38
38
  </Item>
39
39
  </div>,
40
- )
40
+ );
41
41
  ```
42
42
 
43
43
  ## Paleta própria
@@ -46,27 +46,45 @@ render(
46
46
  domínio, pois cada importação participa do bundle.
47
47
 
48
48
  ```tsx preview col md
49
- const [icon, setIcon] = useState('')
49
+ const [icon, setIcon] = useState("");
50
50
 
51
51
  render(
52
52
  <IconPicker
53
53
  value={icon}
54
54
  onChange={setIcon}
55
- icons={{ 'zap': Zap, 'star': Star, 'flag': Flag, 'heart': Heart }}
55
+ icons={{ zap: Zap, star: Star, flag: Flag, heart: Heart }}
56
56
  placeholder="Selecione um ícone…"
57
57
  className="w-56"
58
58
  />,
59
- )
59
+ );
60
60
  ```
61
61
 
62
62
  ## Propriedades de IconPicker
63
63
 
64
- | Propriedade | Tipo | Padrão | Descrição |
65
- |---|---|---|---|
66
- | `value` | `string` | | Nome do ícone selecionado (chave da paleta); `''` é nenhum. |
67
- | `onChange` | `(name: string) => void` | | Recebe o nome escolhido. |
68
- | `icons` | `Record<string, LucideIcon>` | `iconPickerIcons` | Paleta nome → componente. |
69
- | `placeholder` | `string` | `'Selecione um ícone…'` | Texto do gatilho sem seleção. |
70
- | `disabled` | `boolean` | `false` | Desabilita o gatilho. |
71
- | `className` | `string` | | Classes do gatilho, em geral para ajustar a largura. Sem elas, o gatilho ocupa toda a largura disponível. |
72
- | `id`, `aria-invalid`, `aria-describedby` | `string`, `boolean`, `string` | | Integração com `Field` e `ActionForm`: o gatilho recebe a identidade do campo, o estado inválido e a mensagem associada. Com `aria-invalid`, a moldura assume o contexto de erro, como no `Input`. |
64
+ | Propriedade | Tipo | Padrão | Descrição |
65
+ | ---------------------------------------- | ------------------------------------------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
66
+ | `value` | `string` | | Nome do ícone selecionado (chave da paleta); `''` é nenhum. |
67
+ | `onChange` | `(name: string) => void` | | Recebe o nome escolhido. |
68
+ | `icons` | `Record<string, LucideIcon>` | `iconPickerIcons` | Paleta nome → componente. |
69
+ | `searchTerms` | `Record<string, { label: string; keywords: string[] }>` | Mapa interno em português | Rótulos acessíveis e sinônimos de busca. |
70
+ | `placeholder` | `string` | `'Selecione um ícone…'` | Texto do gatilho sem seleção. |
71
+ | `disabled` | `boolean` | `false` | Desabilita o gatilho. |
72
+ | `className` | `string` | | Classes do gatilho, em geral para ajustar a largura. Sem elas, o gatilho ocupa toda a largura disponível. |
73
+ | `id`, `aria-invalid`, `aria-describedby` | `string`, `boolean`, `string` | | Integração com `Field` e `ActionForm`: o gatilho recebe a identidade do campo, o estado inválido e a mensagem associada. Com `aria-invalid`, a moldura assume o contexto de erro, como no `Input`. |
74
+
75
+ ## Catálogo sob demanda
76
+
77
+ `IconCatalogProvider` recebe um objeto `catalog` com `load` e `render`. Declare esse objeto
78
+ como constante de módulo ou com `useMemo`, preservando sua identidade entre renders. `load` retorna uma promessa com
79
+ `{ name, label, keywords }[]` e só é chamado ao abrir o picker. O consumidor pode reutilizar a
80
+ promessa para cache, mas deve descartá-la em caso de falha para permitir tentar novamente.
81
+ `render(name, className)` apresenta o ícone salvo sem precisar carregar o índice.
82
+
83
+ O picker começa com 64 resultados e carrega mais automaticamente ao se aproximar do fim do scroll.
84
+ A grade tem oito colunas; a busca sempre percorre o índice inteiro. Erros no carregamento oferecem nova tentativa.
85
+ O consumidor deve carregar imagens conforme entram na região visível e fornecer fallback.
86
+ Uma paleta explícita por `icons` prevalece sobre o provider, preservando seletores especializados.
87
+ Sem provider, o catálogo curado continua funcionando sem requisições externas.
88
+
89
+ Antes da primeira abertura, um ícone externo salvo é anunciado como “Ícone selecionado”;
90
+ após carregar o índice, o gatilho usa o rótulo do catálogo. O desenho não depende desse carregamento.
@@ -200,7 +200,7 @@ controle ativo, declare `data-disabled="true"` no `InputGroup`.
200
200
 
201
201
  | Propriedade | Tipo | Padrão | Descrição |
202
202
  | ----------- | ------------------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------- |
203
- | `size` | `'xs' \| 'sm' \| 'icon-xs' \| 'icon-sm'` | `'xs'` | O subconjunto da escala única que cabe em um campo (1.5 · 2 · 1.5 · 1.75rem); os `icon-*` são quadrados. |
203
+ | `size` | `'xs' \| 'sm' \| 'icon-xs' \| 'icon-sm'` | `'xs'` | O subconjunto da escala única que cabe em um campo (1.5 · 2 · 1.5 · 2rem); os `icon-*` são quadrados. |
204
204
  | `context` | `'neutral' \| 'primary' \| 'warning' \| 'danger'` | `'neutral'` | Contexto semântico herdado de Button. Com `variant` `solid` ou `subtle` sem contexto declarado, o padrão passa a `'primary'`. |
205
205
  | `variant` | `'solid' \| 'subtle' \| 'outline' \| 'ghost' \| 'link'` | `'ghost'` | Tratamento visual; use `solid` quando a ação precisar de ênfase. |
206
206