@softize/opus 12.11.0 → 13.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 (119) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/bin/lib/check.mjs +2 -7
  3. package/bin/lib/copy.mjs +1 -5
  4. package/docs/adr/0005-structural-surfaces-share-an-explicit-anatomy.md +93 -10
  5. package/docs/adr/0007-toast-actions-form-an-ordered-collection.md +63 -0
  6. package/docs/adr/0008-hierarchical-navigation-is-composed-at-the-consumer-boundary.md +71 -0
  7. package/docs/radius-scale.md +1 -1
  8. package/package.json +1 -1
  9. package/registry/skills/maintain-opus-docs/SKILL.md +83 -0
  10. package/registry/skills/maintain-opus-docs/agents/openai.yaml +4 -0
  11. package/registry/skills/maintain-opus-docs/references/editorial-standard.md +85 -0
  12. package/registry/skills/maintain-opus-docs/references/evaluations.md +34 -0
  13. package/registry/skills/maintain-opus-docs/scripts/audit-docs.mjs +81 -0
  14. package/src/ui/components/patterns/confirm.tsx +140 -40
  15. package/src/ui/components/patterns/list.tsx +35 -40
  16. package/src/ui/components/patterns/page-state.tsx +2 -2
  17. package/src/ui/components/patterns/sidebar.tsx +26 -26
  18. package/src/ui/components/patterns/trigger.tsx +25 -22
  19. package/src/ui/components/primitives/alert.tsx +3 -3
  20. package/src/ui/components/primitives/dialog.tsx +196 -39
  21. package/src/ui/components/primitives/drawer.tsx +8 -5
  22. package/src/ui/components/primitives/empty.tsx +3 -3
  23. package/src/ui/components/primitives/item.tsx +3 -3
  24. package/src/ui/components/primitives/sonner.tsx +187 -8
  25. package/src/ui/docs/DocBrowser.tsx +102 -23
  26. package/src/ui/docs/content/accordion.md +22 -16
  27. package/src/ui/docs/content/action-form-card.md +8 -8
  28. package/src/ui/docs/content/action-form-dialog.md +9 -9
  29. package/src/ui/docs/content/action-form.md +28 -34
  30. package/src/ui/docs/content/action-list-dialog.md +11 -6
  31. package/src/ui/docs/content/action-list.md +64 -39
  32. package/src/ui/docs/content/action-trigger.md +21 -14
  33. package/src/ui/docs/content/action-view.md +8 -8
  34. package/src/ui/docs/content/actions.md +9 -9
  35. package/src/ui/docs/content/ai.md +3 -3
  36. package/src/ui/docs/content/alert.md +14 -12
  37. package/src/ui/docs/content/aspect-ratio.md +4 -4
  38. package/src/ui/docs/content/audit.md +2 -2
  39. package/src/ui/docs/content/auth.md +3 -3
  40. package/src/ui/docs/content/avatar.md +34 -14
  41. package/src/ui/docs/content/badge.md +3 -3
  42. package/src/ui/docs/content/breadcrumb.md +13 -8
  43. package/src/ui/docs/content/button.md +81 -6
  44. package/src/ui/docs/content/calendar.md +5 -5
  45. package/src/ui/docs/content/card.md +1 -1
  46. package/src/ui/docs/content/carousel.md +16 -11
  47. package/src/ui/docs/content/chat.md +3 -3
  48. package/src/ui/docs/content/checkbox.md +7 -7
  49. package/src/ui/docs/content/cli.md +5 -5
  50. package/src/ui/docs/content/collapsible.md +8 -8
  51. package/src/ui/docs/content/command.md +16 -8
  52. package/src/ui/docs/content/composer.md +2 -2
  53. package/src/ui/docs/content/content.md +2 -2
  54. package/src/ui/docs/content/copyable.md +4 -3
  55. package/src/ui/docs/content/customization.md +5 -5
  56. package/src/ui/docs/content/cycle.md +3 -3
  57. package/src/ui/docs/content/data-state.md +11 -12
  58. package/src/ui/docs/content/data.md +26 -33
  59. package/src/ui/docs/content/detail.md +3 -3
  60. package/src/ui/docs/content/dialog.md +339 -31
  61. package/src/ui/docs/content/dictionary-value.md +8 -8
  62. package/src/ui/docs/content/dock.md +3 -3
  63. package/src/ui/docs/content/drawer.md +27 -14
  64. package/src/ui/docs/content/empty-value.md +2 -2
  65. package/src/ui/docs/content/empty.md +19 -12
  66. package/src/ui/docs/content/events.md +4 -4
  67. package/src/ui/docs/content/field.md +34 -12
  68. package/src/ui/docs/content/getting-started.md +1 -1
  69. package/src/ui/docs/content/icon-picker.md +8 -4
  70. package/src/ui/docs/content/input-otp.md +20 -12
  71. package/src/ui/docs/content/input.md +121 -9
  72. package/src/ui/docs/content/item.md +27 -13
  73. package/src/ui/docs/content/kbd.md +19 -11
  74. package/src/ui/docs/content/label.md +5 -3
  75. package/src/ui/docs/content/log.md +4 -4
  76. package/src/ui/docs/content/markdown.md +7 -6
  77. package/src/ui/docs/content/mcp.md +13 -15
  78. package/src/ui/docs/content/menu.md +34 -16
  79. package/src/ui/docs/content/observability.md +2 -2
  80. package/src/ui/docs/content/page.md +51 -6
  81. package/src/ui/docs/content/pagination.md +22 -17
  82. package/src/ui/docs/content/popover.md +16 -8
  83. package/src/ui/docs/content/progress.md +7 -5
  84. package/src/ui/docs/content/queue.md +5 -5
  85. package/src/ui/docs/content/radio-group.md +20 -12
  86. package/src/ui/docs/content/router.md +11 -6
  87. package/src/ui/docs/content/scheduler.md +4 -5
  88. package/src/ui/docs/content/scroll-area.md +12 -7
  89. package/src/ui/docs/content/select.md +42 -29
  90. package/src/ui/docs/content/separator.md +5 -5
  91. package/src/ui/docs/content/sidebar.md +323 -54
  92. package/src/ui/docs/content/skeleton.md +3 -2
  93. package/src/ui/docs/content/slider.md +8 -7
  94. package/src/ui/docs/content/spinner.md +8 -8
  95. package/src/ui/docs/content/split.md +8 -5
  96. package/src/ui/docs/content/storage.md +6 -8
  97. package/src/ui/docs/content/switch.md +8 -7
  98. package/src/ui/docs/content/table.md +13 -3
  99. package/src/ui/docs/content/tabs.md +28 -14
  100. package/src/ui/docs/content/testing.md +9 -11
  101. package/src/ui/docs/content/textarea.md +5 -4
  102. package/src/ui/docs/content/toast.md +47 -13
  103. package/src/ui/docs/content/toggle.md +75 -7
  104. package/src/ui/docs/content/tokens.md +3 -3
  105. package/src/ui/docs/content/tooltip.md +19 -11
  106. package/src/ui/docs/content/truncate.md +7 -8
  107. package/src/ui/docs/content/ui.md +10 -9
  108. package/src/ui/docs/content/upgrading.md +7 -8
  109. package/src/ui/docs/registry.tsx +20 -37
  110. package/src/ui/meta.ts +64 -94
  111. package/src/ui/react.tsx +15 -16
  112. package/src/ui/theme.css +50 -0
  113. package/src/ui/components/primitives/alert-dialog.tsx +0 -192
  114. package/src/ui/docs/content/alert-dialog.md +0 -73
  115. package/src/ui/docs/content/button-group.md +0 -71
  116. package/src/ui/docs/content/confirm.md +0 -120
  117. package/src/ui/docs/content/input-group.md +0 -79
  118. package/src/ui/docs/content/page-state.md +0 -45
  119. package/src/ui/docs/content/toggle-group.md +0 -81
@@ -1,13 +1,14 @@
1
1
  ## Fonte e resultado
2
2
 
3
- Uso: <Markdown content={fonte} />. No palco, o resultado; no bloco abaixo, a fonte markdown que o produziu. O componente recebe só content: string.
3
+ Passe o texto em `content`. O exemplo mostra primeiro o resultado renderizado e, depois, o Markdown
4
+ que o produziu.
4
5
 
5
6
  ```tsx preview col 2xl
6
7
  const sample = [
7
8
  '# Markdown na Softize',
8
9
  '',
9
10
  'Renderiza **doc técnica** e mensagem de chat — `SKILL.md`, síntese de papel, resposta de agente.',
10
- 'O motor é o markdown-it, o MESMO que renderiza estas páginas.',
11
+ 'O motor é o markdown-it, o mesmo que renderiza estas páginas.',
11
12
  '',
12
13
  '## Sintaxe coberta',
13
14
  '',
@@ -18,7 +19,7 @@ const sample = [
18
19
  '1. Primeiro passo',
19
20
  '2. Segundo passo',
20
21
  '',
21
- '> Citação calma, pro tom certo.',
22
+ '> Citação calma, para o tom certo.',
22
23
  '',
23
24
  '---',
24
25
  '',
@@ -33,9 +34,9 @@ render(<Markdown content={sample} />)
33
34
  ```
34
35
 
35
36
 
36
- ## Props
37
+ ## Propriedades de Markdown
37
38
 
38
- | Prop | Tipo | Default | Descrição |
39
+ | Propriedade | Tipo | Padrão | Descrição |
39
40
  |---|---|---|---|
40
- | `content` | `string` | | O markdown cru (CommonMark + tabela GFM, via markdown-it). HTML no fonte é **escapado**, não interpretado — por isso serve pra texto vindo de gente ou de modelo. |
41
+ | `content` | `string` | | O markdown cru (CommonMark + tabela GFM, via markdown-it). HTML no fonte é **escapado**, não interpretado — por isso serve para texto vindo de gente ou de modelo. |
41
42
  | `className` | `string` | | Classes do wrapper. |
@@ -4,10 +4,9 @@ title: MCP
4
4
 
5
5
  # MCP
6
6
 
7
- Expõe as actions `ai:enabled` do runtime como **tools MCP** — a porta pra uma IA de **fora**
8
- (Claude Desktop, o agente de um parceiro, um hub próprio) alcançar o app pelo protocolo. É o
9
- mesmo bridge do agente co-locado (`runtime.aiTools`) e a mesma execução (`runtime.execute`,
10
- como o usuário resolvido). O MCP é só o transporte.
7
+ Use o servidor MCP para disponibilizar actions `ai:enabled` a agentes que executam fora da
8
+ aplicação. A chamada continua passando por `runtime.execute`, com a mesma validação, autorização e
9
+ auditoria; o MCP fornece apenas o transporte.
11
10
 
12
11
  ## Montar
13
12
 
@@ -22,23 +21,22 @@ const server = createOpusMcpServer(runtime, {
22
21
  resolveContext: async (extra) => auth.resolveFromMcp(extra),
23
22
  })
24
23
 
25
- await server.connect(new StdioServerTransport()) // local; HTTP/SSE pra remoto
24
+ await server.connect(new StdioServerTransport()) // local; HTTP/SSE para remoto
26
25
  ```
27
26
 
28
27
  `ListTools` devolve as actions `ai:enabled` (nome + descrição + JSON Schema do input);
29
28
  `CallTool` executa a action pelo `runtime.execute` — validação, auth (`ctx.can`) e audit,
30
29
  tudo igual a uma chamada normal. Read-only? Marque só actions de leitura com `ai:enabled`.
31
30
 
32
- ## Interno × MCP
31
+ ## Escolher entre integração interna e MCP
33
32
 
34
- - **Monolito / chat co-locado:** não precisa de MCP — `runtime.aiFor(base).run()` chama as
35
- actions direto, in-process (ver o recurso **IA generativa**).
36
- - **IA por fora / ecossistema:** o agente vive num serviço próprio e alcança N apps pela
37
- mesma porta MCP. É aqui que ele se paga.
33
+ - **Agente dentro da aplicação:** use `runtime.aiFor(base).run()` para chamar as actions no mesmo
34
+ processo.
35
+ - **Agente em outro serviço:** use MCP para oferecer a mesma coleção de ferramentas por uma
36
+ interface interoperável.
38
37
 
39
- Mesmas tools, transportes diferentes.
38
+ ## Limites atuais
40
39
 
41
- ## Limites (por enquanto)
42
-
43
- Você monta o transporte (stdio/HTTP) — o server é agnóstico. A confirmação de action
44
- `destructive` sobre MCP (elicitation) entra quando um caso real cobrar; comece read-only.
40
+ O consumidor escolhe e monta o transporte, como stdio ou HTTP. A confirmação de actions destrutivas
41
+ ainda não faz parte desta integração; até que esse fluxo exista, exponha somente operações de
42
+ leitura.
@@ -1,7 +1,7 @@
1
1
  ## Menu de ações
2
2
 
3
- Ícone à esquerda, atalho à direita (MenuShortcut), separador antes da zona perigosa e
4
- `context="danger"` na ação que destrói.
3
+ Use `Menu` para reunir ações relacionadas em um painel ancorado. `MenuShortcut` posiciona o atalho à
4
+ direita; separe ações perigosas e declare `context="danger"` nelas.
5
5
 
6
6
  ```tsx preview
7
7
  <Menu>
@@ -17,11 +17,10 @@
17
17
  </Menu>
18
18
  ```
19
19
 
20
- ## Contexto: clique direito
20
+ ## Abrir pelo menu de contexto
21
21
 
22
- O papel do ContextMenu (aposentado na 5.0.0) com o MESMO componente muda o
23
- gatilho: controlado, ancorado no ponteiro. `onContextMenu` guarda a posição e abre;
24
- um gatilho invisível `position: fixed` naquele ponto ancora o conteúdo.
22
+ Para abrir pelo clique direito, controle o estado do menu e use a posição do ponteiro como âncora.
23
+ Esse padrão substitui o antigo `ContextMenu` sem introduzir outra família de componentes.
25
24
 
26
25
  ```tsx preview
27
26
  const [pos, setPos] = useState(null)
@@ -52,9 +51,10 @@ render(
52
51
  )
53
52
  ```
54
53
 
55
- ## Seleção: checkbox e radio
54
+ ## Seleção por checkbox ou radio
56
55
 
57
- CheckboxItem pra liga/desliga, RadioGroup pra escolha exclusiva estado fica no consumidor (controlado).
56
+ Use `MenuCheckboxItem` para opções independentes e `MenuRadioGroup` para escolhas mutuamente
57
+ exclusivas. O consumidor controla o estado nos dois casos.
58
58
 
59
59
  ```tsx preview
60
60
  const [showArchived, setShowArchived] = useState(false)
@@ -93,7 +93,7 @@ MenuSub aninha um nível; inset alinha itens sem ícone com os que têm.
93
93
  <MenuContent align="start">
94
94
  <MenuItem><ExternalLink /> Abrir preview</MenuItem>
95
95
  <MenuSub>
96
- <MenuSubTrigger><ArrowDownAZ /> Mover pra</MenuSubTrigger>
96
+ <MenuSubTrigger><ArrowDownAZ /> Mover para</MenuSubTrigger>
97
97
  <MenuSubContent>
98
98
  <MenuItem>Empresa X</MenuItem>
99
99
  <MenuItem>Softize</MenuItem>
@@ -104,12 +104,30 @@ MenuSub aninha um nível; inset alinha itens sem ícone com os que têm.
104
104
  </Menu>
105
105
  ```
106
106
 
107
- ## Props
107
+ ## Propriedades de MenuItem
108
108
 
109
- | Prop | Tipo | Default | Descrição |
109
+ | Propriedade | Tipo | Padrão | Descrição |
110
110
  |---|---|---|---|
111
- | `MenuItem.context` | `'neutral' \| 'danger'` | `'neutral'` | `danger` sinaliza uma consequência perigosa. |
112
- | `MenuItem.inset` | `boolean` | | Recuo à esquerda pra alinhar item sem ícone com os que têm. |
113
- | `MenuContent.align / sideOffset` | `'start' \| 'center' \| 'end' / number` | `'center' / 4` | Alinhamento e distância em relação ao gatilho (Radix). |
114
- | `MenuCheckboxItem.checked / onCheckedChange` | `boolean / (checked: boolean) => void` | | Estado do liga/desliga — controlado pelo consumidor. |
115
- | `MenuRadioGroup.value / onValueChange` | `string / (value: string) => void` | | Escolha exclusiva entre os MenuRadioItem filhos. |
111
+ | `context` | `'neutral' \| 'danger'` | `'neutral'` | `danger` sinaliza uma ação com consequência perigosa. |
112
+ | `inset` | `boolean` | | Alinha um item sem ícone com os itens que possuem ícone. |
113
+
114
+ ## Propriedades de MenuContent
115
+
116
+ | Propriedade | Tipo | Padrão | Descrição |
117
+ |---|---|---|---|
118
+ | `align` | `'start' \| 'center' \| 'end'` | `'center'` | Alinhamento do painel em relação ao gatilho. |
119
+ | `sideOffset` | `number` | `4` | Distância entre o gatilho e o painel. |
120
+
121
+ ## Propriedades de MenuCheckboxItem
122
+
123
+ | Propriedade | Tipo | Padrão | Descrição |
124
+ |---|---|---|---|
125
+ | `checked` | `boolean` | | Estado controlado do item. |
126
+ | `onCheckedChange` | `(checked: boolean) => void` | | Chamado quando a pessoa alterna o item. |
127
+
128
+ ## Propriedades de MenuRadioGroup
129
+
130
+ | Propriedade | Tipo | Padrão | Descrição |
131
+ |---|---|---|---|
132
+ | `value` | `string` | | Valor selecionado no grupo. |
133
+ | `onValueChange` | `(value: string) => void` | | Chamado quando a pessoa seleciona outro `MenuRadioItem`. |
@@ -4,8 +4,8 @@ title: Observabilidade
4
4
 
5
5
  # Observabilidade
6
6
 
7
- O core expõe uma porta vendor-neutral; o driver OpenTelemetry cria spans ativos para actions
8
- e reactions sem escolher backend, exporter ou Collector.
7
+ Use `ObservabilityAdapter` para envolver actions e reactions em spans sem acoplar o core a um
8
+ fornecedor. O driver OpenTelemetry deixa backend, exporter e Collector sob controle do aplicativo.
9
9
 
10
10
  ## Driver OpenTelemetry
11
11
 
@@ -16,10 +16,9 @@ Uma navegação contextual para outra página pode ocupar `actions`, e tabs fica
16
16
  recortes da mesma superfície. Canvas e outros workspaces espaciais imersivos podem usar um shell
17
17
  próprio quando o cabeçalho reduzir a área útil ou duplicar controles persistentes da superfície.
18
18
 
19
- Quando carregamento, falha ou ausência substituírem toda a área de conteúdo, use `PageState`. Na
20
- forma curta ele pode ser escrito como filho direto, pois `Page` cria o `PageBody`; na composição
21
- explícita, coloque-o dentro de `PageBody`. `Page` não recebe flags de dados: uma página pode agregar
22
- fontes independentes e uma falha parcial não deve ocultar as demais seções.
19
+ Estados integrais de carregamento, falha ou ausência são compostos no body com `PageState`,
20
+ detalhado abaixo. `Page` não recebe flags de dados: uma página pode agregar fontes independentes e
21
+ uma falha parcial não deve ocultar as demais seções.
23
22
 
24
23
  ```tsx preview col
25
24
  render(
@@ -65,9 +64,44 @@ render(
65
64
  )
66
65
  ```
67
66
 
68
- ## Props
67
+ ## Estados integrais
69
68
 
70
- | Prop | Tipo | Default | Descrição |
69
+ Use `PageState` quando carregamento, falha ou ausência substituírem todo o conteúdo principal. Na
70
+ forma curta ele pode ser escrito como filho direto de `Page`, que cria o `PageBody`; na forma
71
+ explícita, coloque-o dentro de `PageBody`. O cabeçalho continua visível e o estado recebe composição,
72
+ altura e semântica acessível consistentes.
73
+
74
+ ```tsx preview col
75
+ <Page title="Relatório">
76
+ <PageState
77
+ status="error"
78
+ title="Não foi possível carregar o relatório"
79
+ description="Tente novamente. Se o problema continuar, volte mais tarde."
80
+ action={<Button>Tentar novamente</Button>}
81
+ />
82
+ </Page>
83
+ ```
84
+
85
+ `loading` centraliza o `Spinner`; `error` compõe `Alert`; `empty` compõe `Empty`; e `ready` entrega
86
+ os filhos sem acrescentar uma superfície.
87
+
88
+ ```tsx preview col
89
+ <Page title="Relatórios">
90
+ <PageState
91
+ status="empty"
92
+ title="Nenhum relatório"
93
+ description="Crie o primeiro relatório para começar."
94
+ action={<Button>Novo relatório</Button>}
95
+ />
96
+ </Page>
97
+ ```
98
+
99
+ Não use `PageState` para uma falha parcial. Se outra parte da página continua utilizável, mantenha o
100
+ estado na própria seção com `DataState`, `ActionView`, `ActionList` ou `Alert`.
101
+
102
+ ## Propriedades de Page
103
+
104
+ | Propriedade | Tipo | Padrão | Descrição |
71
105
  | ------------- | ----------- | ----------- | ----------------------------------------------------------------------------------------------- |
72
106
  | `title` | `string` | | O h1 da página. |
73
107
  | `count` | `number` | | Total de itens ao lado do título (mono, esmaecido). |
@@ -75,3 +109,14 @@ render(
75
109
  | `actions` | `ReactNode` | | Ações contextuais no extremo oposto do cabeçalho; em telas estreitas, ficam abaixo do contexto. |
76
110
  | `className` | `string` | `max-w-7xl` | Classes do container para substituir o teto padrão de `80rem`. |
77
111
  | `children` | `ReactNode` | | O body da página — espaçamento e diagramação são seus. |
112
+
113
+ ## Propriedades de PageState
114
+
115
+ | Propriedade | Tipo | Padrão | Descrição |
116
+ |---|---|---|---|
117
+ | `status` | `'loading' \| 'error' \| 'empty' \| 'ready'` | | Estado integral do conteúdo. |
118
+ | `title` | `ReactNode` | Texto seguro por estado | Situação reconhecível pela pessoa. |
119
+ | `description` | `ReactNode` | | Impacto ou próximo passo aplicável. |
120
+ | `icon` | `ReactNode` | Alerta no erro | Ícone decorativo do estado. |
121
+ | `action` | `ReactNode` | | Recuperação, seleção ou criação aplicável. |
122
+ | `children` | `ReactNode` | | Conteúdo renderizado somente em `ready`. |
@@ -1,10 +1,9 @@
1
- ## Básico
1
+ ## Navegação entre páginas
2
2
 
3
- É composição: Pagination embrulha PaginationContent, e cada PaginationItem segura um link. `page`
4
- dá o número e o nome acessível (“Página N”); `isActive` marca a página atual (vira outline). Cada
5
- número tem altura fixa e largura mínima quadrada que cresce com os dígitos 5726 e 5727 nunca se
6
- colam. As setas seguem quadradas e já falam pt-BR; `label` localiza, `iconOnly` deixa só a seta.
7
- É o único paginador da casa: `ActionList` compõe esta primitiva no rodapé, na escala densa.
3
+ Componha `Pagination`, `PaginationContent` e um `PaginationItem` para cada link. `page` fornece o
4
+ número e o nome acessível; `isActive` identifica a página atual. Os controles mantêm altura fixa e
5
+ a largura cresce quando o número precisa de mais espaço. `ActionList` usa esta mesma primitiva no
6
+ rodapé.
8
7
 
9
8
  ```tsx preview
10
9
  <Pagination>
@@ -30,7 +29,7 @@ colam. As setas seguem quadradas e já falam pt-BR; `label` localiza, `iconOnly`
30
29
 
31
30
  ## Números longos
32
31
 
33
- A largura mínima é quadrada; o número manda no resto. Na escala densa de um rodapé, ajuste por
32
+ A largura mínima é quadrada e cresce conforme o conteúdo. Na escala densa de um rodapé, ajuste por
34
33
  `className` (`h-7 min-w-7 text-xs` nos números; `size-7` mais `iconClassName="size-3.5"` nas
35
34
  setas com `iconOnly`).
36
35
 
@@ -61,7 +60,8 @@ setas com `iconOnly`).
61
60
 
62
61
  ## Com elipse
63
62
 
64
- PaginationEllipsis é o atalho decorativo (aria-hidden) entre blocos de páginas distantes — útil quando a lista de sessões do workspace tem páginas demais pra caber na barra.
63
+ `PaginationEllipsis` marca, de forma decorativa e com `aria-hidden`, uma sequência de páginas que
64
+ não cabe na barra.
65
65
 
66
66
  ```tsx preview
67
67
  <Pagination>
@@ -123,14 +123,19 @@ render(
123
123
  )
124
124
  ```
125
125
 
126
- ## Props
126
+ ## Propriedades de PaginationLink
127
127
 
128
- | Prop | Tipo | Default | Descrição |
128
+ | Propriedade | Tipo | Padrão | Descrição |
129
129
  |---|---|---|---|
130
- | `page (PaginationLink)` | `number` | | Número da página: vira o conteúdo (quando não há `children`) e o nome acessível “Página N”. |
131
- | `isActive (PaginationLink)` | `boolean` | `false` | Marca a página atual: vira outline e ganha aria-current="page". Os demais ficam ghost. |
132
- | `href (PaginationLink)` | `string` | | Com `href` o link é um `<a>`; sem `href` é um `<button>` controlado por `onClick`, com `disabled`. |
133
- | `size (PaginationLink)` | `'default' \| 'sm' \| 'lg' \| 'icon' \| 'icon-sm' \| 'icon-xs'` | `'default'` | Escala do Button. Números usam `default` (largura mínima quadrada que cresce); as setas com `iconOnly` usam `icon`. |
134
- | `label (Previous/Next)` | `string` | `'Página anterior'` / `'Próxima página'` | Nome acessível e texto visível das setas. |
135
- | `iconOnly (Previous/Next)` | `boolean` | `false` | Só a seta, quadrada (`size="icon"`); o `label` continua como nome acessível. |
136
- | `iconClassName (Previous/Next)` | `string` | | Classe do svg da seta, para a escala densa (`size-3.5`). |
130
+ | `page` | `number` | | Número usado como conteúdo, quando `children` não é informado, e no nome acessível “Página N”. |
131
+ | `isActive` | `boolean` | `false` | Marca a página atual com `aria-current="page"` e tratamento `outline`. |
132
+ | `href` | `string` | | Renderiza um `<a>`. Sem `href`, o componente usa `<button>` e aceita `onClick` e `disabled`. |
133
+ | `size` | `'default' \| 'sm' \| 'lg' \| 'icon' \| 'icon-sm' \| 'icon-xs'` | `'default'` | Escala herdada de `Button`. A largura mínima cresce para acomodar números longos. |
134
+
135
+ ## Propriedades de PaginationPrevious e PaginationNext
136
+
137
+ | Propriedade | Tipo | Padrão | Descrição |
138
+ |---|---|---|---|
139
+ | `label` | `string` | `'Página anterior'` ou `'Próxima página'` | Nome acessível e texto visível da ação. |
140
+ | `iconOnly` | `boolean` | `false` | Exibe somente a seta; `label` continua disponível para leitura assistiva. |
141
+ | `iconClassName` | `string` | | Classes aplicadas ao ícone da seta. |
@@ -1,6 +1,8 @@
1
- ## Estrutura
1
+ ## Painel ancorado
2
2
 
3
- PopoverHeader agrupa título e descrição; o corpo é livre (form curto, detalhes). Superfície bg-popover — a elevação da casa.
3
+ Use `Popover` para apresentar conteúdo livre junto a um gatilho, sem abrir um modal.
4
+ `PopoverHeader` agrupa título e descrição; o restante do painel aceita formulários curtos ou
5
+ detalhes.
4
6
 
5
7
  ```tsx preview
6
8
  <Popover>
@@ -23,7 +25,7 @@ PopoverHeader agrupa título e descrição; o corpo é livre (form curto, detalh
23
25
 
24
26
  ## Alinhamento
25
27
 
26
- align posiciona o painel em relação ao gatilho; sideOffset afasta. O padrão (center) serve pra quase tudo.
28
+ `align` posiciona o painel em relação ao gatilho e `sideOffset` define a distância entre eles.
27
29
 
28
30
  ```tsx preview
29
31
  <Popover>
@@ -40,10 +42,16 @@ align posiciona o painel em relação ao gatilho; sideOffset afasta. O padrão (
40
42
  </Popover>
41
43
  ```
42
44
 
43
- ## Props
45
+ ## Propriedades de Popover
44
46
 
45
- | Prop | Tipo | Default | Descrição |
47
+ | Propriedade | Tipo | Padrão | Descrição |
46
48
  |---|---|---|---|
47
- | `PopoverContent.align` | `'start' \| 'center' \| 'end'` | `'center'` | Alinhamento do painel em relação ao gatilho. |
48
- | `PopoverContent.sideOffset` | `number` | `4` | Distância (px) entre gatilho e painel. |
49
- | `Popover.open / onOpenChange` | `boolean / (open: boolean) => void` | | Modo controlado (Radix) — pra fechar por código depois de salvar. |
49
+ | `open` | `boolean` | | Estado no modo controlado. |
50
+ | `onOpenChange` | `(open: boolean) => void` | | Atualiza o estado para permitir abertura ou fechamento por código. |
51
+
52
+ ## Propriedades de PopoverContent
53
+
54
+ | Propriedade | Tipo | Padrão | Descrição |
55
+ |---|---|---|---|
56
+ | `align` | `'start' \| 'center' \| 'end'` | `'center'` | Alinhamento do painel em relação ao gatilho. |
57
+ | `sideOffset` | `number` | `4` | Distância entre o gatilho e o painel. |
@@ -1,6 +1,7 @@
1
- ## Básico
1
+ ## Progresso determinado
2
2
 
3
- value vai de 0 a 100 o preenchimento anima a cada mudança. Sem value (ou null) a barra fica vazia.
3
+ Use `Progress` quando a tarefa informar uma porcentagem de conclusão. `value` aceita valores de 0 a
4
+ 100 e anima o preenchimento a cada mudança. Sem valor, a barra permanece vazia.
4
5
 
5
6
  ```tsx preview col
6
7
  <div className="w-full max-w-sm space-y-2">
@@ -14,7 +15,8 @@ value vai de 0 a 100 — o preenchimento anima a cada mudança. Sem value (ou nu
14
15
 
15
16
  ## Controlado
16
17
 
17
- Guarde o value no estado e atualize conforme a tarefa avança aqui cada clique soma um passo na sincronização do workspace Empresa X.
18
+ Controle `value` externamente quando o progresso acompanhar uma tarefa em andamento. No exemplo,
19
+ cada clique avança uma etapa da sincronização.
18
20
 
19
21
  ```tsx preview col
20
22
  const [step, setStep] = useState(40)
@@ -61,9 +63,9 @@ className compõe sobre o padrão: ajuste a altura no Progress e tinja o preench
61
63
  </div>
62
64
  ```
63
65
 
64
- ## Props
66
+ ## Propriedades de Progress
65
67
 
66
- | Prop | Tipo | Default | Descrição |
68
+ | Propriedade | Tipo | Padrão | Descrição |
67
69
  |---|---|---|---|
68
70
  | `value` | `number \| null` | | O progresso de 0 a 100. O preenchimento anima a cada mudança; null/ausente deixa a barra vazia. |
69
71
  | `className` | `string` | | Compõe sobre o padrão — ajuste a altura (h-1.5/h-3) ou tinja o indicador via [&_[data-slot=progress-indicator]]:bg-*. |
@@ -4,8 +4,8 @@ title: Filas
4
4
 
5
5
  # Filas
6
6
 
7
- Action pesada não segura o request: marcada como background, ela é enfileirada e processada
8
- fora da linha, e o cliente acompanha por um handle. O contrato é o `QueueAdapter`.
7
+ Use uma action em background quando a operação não puder manter a requisição aberta. O
8
+ `QueueAdapter` enfileira o trabalho e devolve um `JobHandle` para acompanhamento pelo cliente.
9
9
 
10
10
  ## O contrato
11
11
 
@@ -44,7 +44,7 @@ const queue = bullmqQueue({ queue: new Queue('opus', { connection: { host: 'loca
44
44
  ```
45
45
 
46
46
  Redis-backed (durável, entre-processos, retries). Peers opcionais (`bullmq`, `ioredis`) só
47
- pra quem usa o driver.
47
+ para quem usa o driver.
48
48
 
49
49
  ## No runtime
50
50
 
@@ -82,7 +82,7 @@ Multiplicador exponencial diferente de 2 ou `maxMs` exige `backoffStrategy` cust
82
82
  é rejeitado pelo driver em vez de ser silenciosamente ignorado. `timeout` permanece no
83
83
  envelope para o worker aplicar, pois não é uma opção de execução do `Queue.add`.
84
84
 
85
- ## Limites (por enquanto)
85
+ ## Limites atuais
86
86
 
87
- Driver hoje: `bullmq` (Redis). In-memory pra dev e outros backends (SQS, pg-boss…) entram
87
+ Driver hoje: `bullmq` (Redis). In-memory para dev e outros backends (SQS, pg-boss…) entram
88
88
  por reincidência.
@@ -1,6 +1,8 @@
1
- ## Básico
1
+ ## Escolha única
2
2
 
3
- Cada RadioGroupItem tem um value; o item escolhido é o value do RadioGroup. defaultValue deixa o estado com o componente. Pareie cada item com um Label (htmlFor↔id).
3
+ Use `RadioGroup` quando todas as opções mutuamente exclusivas precisarem permanecer visíveis. Cada
4
+ `RadioGroupItem` declara um `value` e deve estar associado a um `Label`. `defaultValue` define a
5
+ opção inicial no modo não controlado.
4
6
 
5
7
  ```tsx preview col-start
6
8
  <RadioGroup defaultValue="balanced">
@@ -21,7 +23,7 @@ Cada RadioGroupItem tem um value; o item escolhido é o value do RadioGroup. def
21
23
 
22
24
  ## Controlado
23
25
 
24
- value + onValueChange no RadioGroup levam o estado pra fora o padrão pra escolher quem recebe o handoff de uma task.
26
+ Use `value` e `onValueChange` quando outro estado da aplicação também precisar acompanhar a escolha.
25
27
 
26
28
  ```tsx preview col-start
27
29
  const [agent, setAgent] = useState('reviewer')
@@ -46,7 +48,8 @@ render(
46
48
 
47
49
  ## Item desabilitado
48
50
 
49
- disabled num RadioGroupItem esmaece e tira a opção da escolha; o Label em par esmaece junto (peer-disabled). Pra bloquear o grupo inteiro, ponha disabled no RadioGroup.
51
+ `disabled` em `RadioGroupItem` bloqueia somente aquela opção e atualiza o `Label` associado. Para
52
+ bloquear todas as opções, aplique `disabled` ao `RadioGroup`.
50
53
 
51
54
  ```tsx preview col-start
52
55
  <RadioGroup defaultValue="empresa-x-web">
@@ -65,13 +68,18 @@ disabled num RadioGroupItem esmaece e tira a opção da escolha; o Label em par
65
68
  </RadioGroup>
66
69
  ```
67
70
 
68
- ## Props
71
+ ## Propriedades de RadioGroup
69
72
 
70
- | Prop | Tipo | Default | Descrição |
73
+ | Propriedade | Tipo | Padrão | Descrição |
71
74
  |---|---|---|---|
72
- | `value (RadioGroup)` | `string` | | A opção escolhida, no modo controlado pareie com onValueChange. |
73
- | `onValueChange (RadioGroup)` | `(value: string) => void` | | Chamado quando o usuário escolhe outra opção. |
74
- | `defaultValue (RadioGroup)` | `string` | | A opção inicial no modo não controlado. |
75
- | `disabled (RadioGroup)` | `boolean` | `false` | Bloqueia e esmaece o grupo inteiro. |
76
- | `value (RadioGroupItem)` | `string` | | O valor que este item representa — vira o value do grupo quando escolhido. |
77
- | `disabled (RadioGroupItem)` | `boolean` | `false` | Esmaece e tira só este item da escolha — o Label em par esmaece junto. |
75
+ | `value` | `string` | | Opção escolhida no modo controlado. Use com `onValueChange`. |
76
+ | `onValueChange` | `(value: string) => void` | | Chamado quando a pessoa escolhe outra opção. |
77
+ | `defaultValue` | `string` | | Opção inicial no modo não controlado. |
78
+ | `disabled` | `boolean` | `false` | Desabilita todo o grupo. |
79
+
80
+ ## Propriedades de RadioGroupItem
81
+
82
+ | Propriedade | Tipo | Padrão | Descrição |
83
+ |---|---|---|---|
84
+ | `value` | `string` | | Valor que o item atribui ao grupo quando selecionado. |
85
+ | `disabled` | `boolean` | `false` | Desabilita somente este item; o `Label` associado acompanha o estado. |
@@ -1,6 +1,8 @@
1
- ## O pathname É o estado
1
+ ## A URL como estado
2
2
 
3
- Roteamento history-based, sem dependência: `pushState` + `popstate` + `useSyncExternalStore`. Páginas orientadas a URL deep-link, reload e o botão voltar funcionam de graça, porque não há um segundo lugar guardando "onde estou".
3
+ Use o router do Opus em aplicações pequenas que precisam reagir à URL sem uma tabela de rotas.
4
+ `pushState`, `popstate` e `useSyncExternalStore` preservam links diretos, recarregamento e o botão
5
+ Voltar sem manter uma segunda cópia do destino atual.
4
6
 
5
7
  ```tsx
6
8
  import { navigate, useSegments } from '@softize/opus/ui/react'
@@ -12,9 +14,10 @@ function App() {
12
14
  }
13
15
  ```
14
16
 
15
- ## O escopo é pequeno de propósito
17
+ ## Limite do router
16
18
 
17
- Não tabela de rotas, `<Route>`, params tipados nem carregamento de dados. Isto é a **leitura reativa da URL + um `navigate`** quem decide o que renderizar é o app, com `if`/`switch` sobre os segmentos.
19
+ O router oferece leitura reativa da URL e `navigate`; o aplicativo decide o que renderizar. Ele não
20
+ inclui tabela de rotas, parâmetros tipados nem carregamento de dados.
18
21
 
19
22
  A régua: se a sua tela precisa de casamento de padrão (`/users/:id/posts/:postId`), params tipados ou data loaders, o caso pede uma biblioteca de rotas, não isto. Um app de back-office com uma dúzia de destinos quase nunca precisa.
20
23
 
@@ -27,13 +30,15 @@ A régua: se a sua tela precisa de casamento de padrão (`/users/:id/posts/:post
27
30
  | `useSearchParams()` | A querystring reativa — o lar natural do estado interno de uma seção (qual relatório está aberto, o recorte de uma lista). |
28
31
  | `navigate(path, opts?)` | `pushState` + notifica. `{ replace: true }` troca a entrada corrente. |
29
32
 
30
- ## Dois detalhes que custaram caro nas cópias à mão
33
+ ## Comportamentos preservados
31
34
 
32
35
  **Destino igual é no-op.** `navigate` resolve o destino com `new URL` e compara o `href` inteiro — não faz nada se você já está exatamente lá. Sem isso, clicar duas vezes no mesmo item do menu empilha entradas idênticas e o botão "voltar" não sai do lugar.
33
36
 
34
37
  Comparar strings cruas parece bastar e não basta, em duas frentes. O **hash**: estando em `/a#secao`, `navigate('/a')` pareceria destino repetido e a âncora nunca sairia da URL. E o **encoding**: `window.location` devolve `/relatórios` como `/relat%C3%B3rios`, então a comparação crua nunca casa e cada clique empilha — bem no caso pt-BR, e no ``navigate(`/reports?report=${arquivo}`)`` com nome de arquivo acentuado.
35
38
 
36
- **A notificação é um evento, não uma lista.** `pushState` não dispara `popstate`, então `navigate` dispara — e é `window.dispatchEvent`, não um `Set` de assinantes em escopo de módulo. A diferença aparece nas bordas: código que ainda escuta `popstate` na unha continua acompanhando, e duas cópias do pacote no `node_modules` continuam se enxergando. Uma lista privada mora numa instância do bundle; o `window` é um só.
39
+ **A notificação usa um evento do navegador.** Como `pushState` não dispara `popstate`, `navigate`
40
+ emite o evento explicitamente. Isso mantém listeners existentes e cópias diferentes do pacote
41
+ sincronizados pela mesma janela.
37
42
 
38
43
  **`useSyncExternalStore`, não `useState`.** Ler `window.location` dentro de `useState`/`useEffect` sofre *tearing* no modo concurrent: dois componentes podem renderizar o mesmo commit com URLs diferentes. As cópias que este módulo substituiu faziam isso.
39
44
 
@@ -4,9 +4,8 @@ title: Agendador
4
4
 
5
5
  # Agendador
6
6
 
7
- Rodar uma action no tempo — cron ou intervalo. Você declara o schedule (qual action, quando)
8
- e o runtime dispara na hora, com provenance `schedule` (rastreável no audit como qualquer
9
- execução). O contrato é o `SchedulerAdapter`.
7
+ Use um schedule para executar uma action por cron ou intervalo. O `SchedulerAdapter` registra o
8
+ agendamento e o runtime executa a action com provenance `schedule`, preservando sua rastreabilidade.
10
9
 
11
10
  ## O contrato
12
11
 
@@ -59,8 +58,8 @@ const runtime = createRuntime({
59
58
  O runtime registra os schedules do domínio no `start()` e chama a action quando o tempo bate
60
59
  — nada de disparar no handler.
61
60
 
62
- ## Limites (por enquanto)
61
+ ## Limites atuais
63
62
 
64
- Driver hoje: `node-cron` (in-process — some se o processo cair; num cluster, cada nó
63
+ Driver hoje: `node-cron` (in-process — some se o processo cair; em um cluster, cada nó
65
64
  dispararia). Backends duráveis/distribuídos (BullMQ repeatable, Temporal…) entram por
66
65
  reincidência.
@@ -4,7 +4,7 @@ Dê a altura ao ScrollArea (h-48) e ponha o conteúdo dentro — a barra vertica
4
4
 
5
5
  ```tsx preview col
6
6
  const sessions = [
7
- { id: 'empresa-x-1842', title: 'Migrar billing pro novo schema', agent: 'developer' },
7
+ { id: 'empresa-x-1842', title: 'Migrar billing para o novo schema', agent: 'developer' },
8
8
  { id: 'empresa-x-1839', title: 'Revisar handoff do checkout', agent: 'reviewer' },
9
9
  { id: 'empresa-x-1835', title: 'Redesenhar o painel de rotas', agent: 'designer' },
10
10
  { id: 'empresa-x-1830', title: 'Corrigir flaky no teste de webhook', agent: 'developer' },
@@ -30,7 +30,7 @@ render(
30
30
 
31
31
  ## Trilho horizontal
32
32
 
33
- Pra rolar na horizontal, acrescente <ScrollBar orientation="horizontal" /> como filho e deixe o conteúdo numa linha que não quebra (flex + w-max).
33
+ Para rolar na horizontal, acrescente <ScrollBar orientation="horizontal" /> como filho e deixe o conteúdo em uma linha que não quebra (flex + w-max).
34
34
 
35
35
  ```tsx preview col
36
36
  const skills = ['implement-opus-change', 'create-opus-action', 'test-opus-action', 'build-opus-ui', 'upgrade-opus']
@@ -80,10 +80,15 @@ render(
80
80
  )
81
81
  ```
82
82
 
83
- ## Props
83
+ ## Propriedades de ScrollArea
84
84
 
85
- | Prop | Tipo | Default | Descrição |
85
+ | Propriedade | Tipo | Padrão | Descrição |
86
86
  |---|---|---|---|
87
- | `className (ScrollArea)` | `string` | | Onde a altura (h-48) ou a largura mora — é o que define a janela rolável. Sem dimensão, não há o que rolar. |
88
- | `children (ScrollArea)` | `React.ReactNode` | | O conteúdo da janela. Inclua um <ScrollBar orientation="horizontal" /> entre os filhos pra habilitar a rolagem lateral. |
89
- | `orientation (ScrollBar)` | `'vertical' \| 'horizontal'` | `'vertical'` | A direção da barra. A vertical já vem embutida; adicione a horizontal só quando precisar. |
87
+ | `className` | `string` | | Classes que definem as dimensões da janela rolável. Sem uma dimensão limitada, não há conteúdo a recortar. |
88
+ | `children` | `React.ReactNode` | | Conteúdo da janela, incluindo uma `ScrollBar` horizontal quando necessária. |
89
+
90
+ ## Propriedades de ScrollBar
91
+
92
+ | Propriedade | Tipo | Padrão | Descrição |
93
+ |---|---|---|---|
94
+ | `orientation` | `'vertical' \| 'horizontal'` | `'vertical'` | Direção da barra. A barra vertical já faz parte de `ScrollArea`. |