@softize/opus 13.0.0 → 14.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 (164) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/PROMOTED.md +46 -0
  3. package/README.md +28 -19
  4. package/bin/cli.mjs +87 -216
  5. package/bin/lib/cli-shared.mjs +131 -0
  6. package/bin/lib/copy.mjs +276 -6
  7. package/bin/lib/db.mjs +16 -74
  8. package/bin/lib/gen-openapi.mjs +3 -3
  9. package/bin/lib/gen-runner.mjs +1 -1
  10. package/bin/lib/gen.mjs +14 -69
  11. package/bin/lib/mcp.mjs +3 -1
  12. package/bin/lib/seed.mjs +5 -62
  13. package/docs/code-style.md +4 -1
  14. package/docs/ownership-vs-shadcn-lock.md +2 -3
  15. package/docs/protocol.md +7 -7
  16. package/docs/releasing.md +8 -2
  17. package/package.json +7 -3
  18. package/registry/instructions/opus.md +3 -3
  19. package/registry/templates/app/package.json +1 -1
  20. package/registry/templates/app/src/App.tsx +11 -6
  21. package/registry/templates/app/src/main.tsx +4 -4
  22. package/src/audit/drivers/console.ts +1 -0
  23. package/src/auth/drivers/better-auth.ts +1 -0
  24. package/src/auth/drivers/jwt.ts +1 -0
  25. package/src/cache/drivers/memory.ts +1 -0
  26. package/src/client/drivers/fetch.ts +2 -1
  27. package/src/core/actions.ts +6 -1
  28. package/src/core/audit.ts +9 -3
  29. package/src/core/contracts.ts +7 -0
  30. package/src/core/domain.ts +1 -1
  31. package/src/core/errors.ts +18 -15
  32. package/src/core/index.ts +4 -2
  33. package/src/core/package-version.ts +26 -0
  34. package/src/core/reactions.ts +1 -1
  35. package/src/core/runtime.ts +33 -23
  36. package/src/core/schedules.ts +1 -1
  37. package/src/core/types.ts +5 -6
  38. package/src/dsl/eval.ts +2 -2
  39. package/src/dsl/kysely.ts +2 -2
  40. package/src/dsl/loads.ts +1 -1
  41. package/src/dsl/parser.ts +5 -5
  42. package/src/events/drivers/mitt.ts +1 -0
  43. package/src/mcp/index.ts +2 -1
  44. package/src/observability/drivers/opentelemetry.ts +1 -0
  45. package/src/queue/drivers/bullmq.ts +3 -3
  46. package/src/scheduler/drivers/node-cron.ts +3 -2
  47. package/src/scheduler/every.ts +7 -7
  48. package/src/schema/openapi.ts +3 -3
  49. package/src/seed/index.ts +29 -0
  50. package/src/server/drivers/fastify.ts +5 -2
  51. package/src/server/drivers/node.ts +9 -6
  52. package/src/server/index.ts +3 -1
  53. package/src/storage/drivers/fs.ts +1 -0
  54. package/src/testing/index.ts +3 -3
  55. package/src/ui/components/patterns/action-list-dialog.tsx +10 -3
  56. package/src/ui/components/patterns/confirm.tsx +2 -31
  57. package/src/ui/components/patterns/content-header.tsx +44 -137
  58. package/src/ui/components/patterns/data-state.tsx +42 -68
  59. package/src/ui/components/patterns/dock.tsx +20 -3
  60. package/src/ui/components/patterns/form.tsx +26 -22
  61. package/src/ui/components/patterns/list.tsx +18 -12
  62. package/src/ui/components/patterns/page-state.tsx +39 -51
  63. package/src/ui/components/patterns/page.tsx +37 -54
  64. package/src/ui/components/patterns/sidebar.tsx +17 -6
  65. package/src/ui/components/patterns/state-surface.tsx +148 -0
  66. package/src/ui/components/patterns/surface-header.tsx +119 -0
  67. package/src/ui/components/patterns/trigger.tsx +21 -25
  68. package/src/ui/components/patterns/view.tsx +29 -22
  69. package/src/ui/components/primitives/alert.tsx +1 -27
  70. package/src/ui/components/primitives/ask.tsx +3 -3
  71. package/src/ui/components/primitives/avatar.tsx +15 -5
  72. package/src/ui/components/primitives/badge.tsx +5 -41
  73. package/src/ui/components/primitives/breadcrumb.tsx +2 -2
  74. package/src/ui/components/primitives/button.tsx +39 -30
  75. package/src/ui/components/primitives/calendar.tsx +28 -2
  76. package/src/ui/components/primitives/carousel.tsx +3 -3
  77. package/src/ui/components/primitives/chat.tsx +1 -1
  78. package/src/ui/components/primitives/checkbox.tsx +1 -1
  79. package/src/ui/components/primitives/command.tsx +2 -2
  80. package/src/ui/components/primitives/control.ts +72 -0
  81. package/src/ui/components/primitives/copyable.tsx +1 -1
  82. package/src/ui/components/primitives/dialog.tsx +12 -7
  83. package/src/ui/components/primitives/dot.tsx +1 -25
  84. package/src/ui/components/primitives/drawer.tsx +10 -3
  85. package/src/ui/components/primitives/field.tsx +3 -3
  86. package/src/ui/components/primitives/icon-picker.tsx +3 -1
  87. package/src/ui/components/primitives/input-group.tsx +12 -9
  88. package/src/ui/components/primitives/input-otp.tsx +1 -1
  89. package/src/ui/components/primitives/input.tsx +2 -2
  90. package/src/ui/components/primitives/item.tsx +3 -1
  91. package/src/ui/components/primitives/menu.tsx +1 -7
  92. package/src/ui/components/primitives/pagination.tsx +16 -8
  93. package/src/ui/components/primitives/progress.tsx +32 -3
  94. package/src/ui/components/primitives/radio-group.tsx +1 -1
  95. package/src/ui/components/primitives/resizable.tsx +3 -1
  96. package/src/ui/components/primitives/select.tsx +6 -6
  97. package/src/ui/components/primitives/slider.tsx +5 -1
  98. package/src/ui/components/primitives/sonner.tsx +3 -0
  99. package/src/ui/components/primitives/spinner.tsx +13 -16
  100. package/src/ui/components/primitives/switch.tsx +5 -1
  101. package/src/ui/components/primitives/tabs.tsx +6 -3
  102. package/src/ui/components/primitives/textarea.tsx +1 -1
  103. package/src/ui/components/primitives/toggle.tsx +9 -4
  104. package/src/ui/components/primitives/tooltip.tsx +1 -0
  105. package/src/ui/docs/changelog.tsx +1 -1
  106. package/src/ui/docs/content/action-form.md +36 -3
  107. package/src/ui/docs/content/action-list-dialog.md +2 -2
  108. package/src/ui/docs/content/action-list.md +13 -2
  109. package/src/ui/docs/content/action-trigger.md +12 -5
  110. package/src/ui/docs/content/action-view.md +11 -3
  111. package/src/ui/docs/content/ask.md +11 -0
  112. package/src/ui/docs/content/avatar.md +7 -3
  113. package/src/ui/docs/content/button.md +30 -14
  114. package/src/ui/docs/content/calendar.md +13 -0
  115. package/src/ui/docs/content/card.md +26 -0
  116. package/src/ui/docs/content/chat.md +20 -0
  117. package/src/ui/docs/content/cli.md +71 -19
  118. package/src/ui/docs/content/communication.md +36 -0
  119. package/src/ui/docs/content/composer.md +15 -0
  120. package/src/ui/docs/content/content.md +17 -1
  121. package/src/ui/docs/content/copyable.md +8 -0
  122. package/src/ui/docs/content/data-state.md +17 -13
  123. package/src/ui/docs/content/detail.md +19 -1
  124. package/src/ui/docs/content/dialog.md +1 -4
  125. package/src/ui/docs/content/dictionary-value.md +9 -2
  126. package/src/ui/docs/content/dock.md +8 -0
  127. package/src/ui/docs/content/dot.md +8 -0
  128. package/src/ui/docs/content/empty.md +2 -2
  129. package/src/ui/docs/content/getting-started.md +2 -2
  130. package/src/ui/docs/content/icon-picker.md +11 -0
  131. package/src/ui/docs/content/input.md +1 -1
  132. package/src/ui/docs/content/item.md +1 -1
  133. package/src/ui/docs/content/label.md +7 -0
  134. package/src/ui/docs/content/menu.md +6 -0
  135. package/src/ui/docs/content/metric-card.md +13 -0
  136. package/src/ui/docs/content/page.md +20 -4
  137. package/src/ui/docs/content/pagination.md +11 -9
  138. package/src/ui/docs/content/popover.md +6 -0
  139. package/src/ui/docs/content/progress.md +8 -11
  140. package/src/ui/docs/content/select.md +5 -5
  141. package/src/ui/docs/content/semantic-context.md +5 -4
  142. package/src/ui/docs/content/sidebar.md +13 -47
  143. package/src/ui/docs/content/skeleton.md +6 -0
  144. package/src/ui/docs/content/spinner.md +9 -6
  145. package/src/ui/docs/content/split.md +21 -0
  146. package/src/ui/docs/content/switch.md +1 -1
  147. package/src/ui/docs/content/tabs.md +1 -1
  148. package/src/ui/docs/content/textarea.md +7 -0
  149. package/src/ui/docs/content/toggle.md +1 -1
  150. package/src/ui/docs/content/tokens.md +4 -4
  151. package/src/ui/docs/content/truncate.md +8 -0
  152. package/src/ui/docs/content/ui.md +14 -0
  153. package/src/ui/docs/doc-client.tsx +5 -5
  154. package/src/ui/docs/doc.tsx +26 -14
  155. package/src/ui/docs/registry.tsx +5 -5
  156. package/src/ui/docs/standalone.tsx +2 -2
  157. package/src/ui/drivers/react.tsx +12 -12
  158. package/src/ui/lib/action-errors.ts +45 -0
  159. package/src/ui/lib/zod-pt-br.ts +31 -4
  160. package/src/ui/meta.ts +8 -8
  161. package/src/ui/react.tsx +10 -16
  162. package/src/ui/theme.css +10 -8
  163. package/src/vite/design.ts +6 -18
  164. package/src/ui/components/patterns/shell-nav.tsx +0 -147
@@ -53,3 +53,14 @@ render(
53
53
  />,
54
54
  )
55
55
  ```
56
+
57
+ ## Propriedades de IconPicker
58
+
59
+ | Propriedade | Tipo | Padrão | Descrição |
60
+ |---|---|---|---|
61
+ | `value` | `string` | | Nome do ícone selecionado (chave da paleta); `''` é nenhum. |
62
+ | `onChange` | `(name: string) => void` | | Recebe o nome escolhido. |
63
+ | `icons` | `Record<string, LucideIcon>` | `iconPickerIcons` | Paleta nome → componente. |
64
+ | `placeholder` | `string` | `'Selecione um ícone…'` | Texto do gatilho sem seleção. |
65
+ | `disabled` | `boolean` | | Desabilita o gatilho. |
66
+ | `id`, `aria-invalid`, `aria-describedby` | | | Integração com `Field`/`ActionForm`: o gatilho recebe a identidade e o estado de erro do campo. |
@@ -166,7 +166,7 @@ Com `InputGroupTextarea`, um addon em `block-end` forma uma região de ações a
166
166
 
167
167
  | Propriedade | Tipo | Padrão | Descrição |
168
168
  |---|---|---|---|
169
- | `size` | `'xs' \| 'sm' \| 'icon-xs' \| 'icon-sm'` | `'xs'` | Tamanho do botão embutido; as variantes `icon-*` são quadradas. |
169
+ | `size` | `'xs' \| 'sm' \| 'icon-xs' \| 'icon-sm'` | `'xs'` | O subconjunto da escala única que cabe num campo (1.5 · 2 · 1.5 · 1.75rem); os `icon-*` são quadrados. |
170
170
  | `context` | `'neutral' \| 'primary' \| 'danger'` | `'primary'` | Contexto semântico herdado de Button. |
171
171
  | `variant` | `'solid' \| 'subtle' \| 'outline' \| 'ghost' \| 'link'` | `'ghost'` | Tratamento visual; use `solid` quando a ação precisar de ênfase. |
172
172
 
@@ -105,7 +105,7 @@ usa `ItemHeader` ou `ItemBody` conforme o papel do conteúdo.
105
105
  | Propriedade | Tipo | Padrão | Descrição |
106
106
  |---|---|---|---|
107
107
  | `variant` | `'default' \| 'outline' \| 'muted'` | `'default'` | O fundo da linha: transparente, com borda ou levemente tingido. |
108
- | `size` | `'default' \| 'sm'` | `'default'` | O respiro interno; `sm` atende listas densas. |
108
+ | `size` | `'default' \| 'sm'` | `'default'` | O respiro interno, com os nomes da escala única; `sm` atende listas densas. |
109
109
  | `asChild` | `boolean` | `false` | Funde o Item no filho para que a linha inteira assuma sua semântica. |
110
110
 
111
111
  ## Propriedades de ItemGroup
@@ -32,3 +32,10 @@ uma classe adicional.
32
32
  <Label htmlFor="archive-workspace">Arquivar o workspace</Label>
33
33
  </div>
34
34
  ```
35
+
36
+ ## Propriedades de Label
37
+
38
+ | Propriedade | Tipo | Padrão | Descrição |
39
+ |---|---|---|---|
40
+ | `htmlFor` | `string` | | O `id` do controle rotulado; clicar no rótulo foca o controle. |
41
+ | `className` | `string` | | Compõe sobre o estilo padrão; o rótulo esmaece com `peer-disabled` e dentro de `group[data-disabled]`. |
@@ -111,6 +111,12 @@ MenuSub aninha um nível; inset alinha itens sem ícone com os que têm.
111
111
  | `context` | `'neutral' \| 'danger'` | `'neutral'` | `danger` sinaliza uma ação com consequência perigosa. |
112
112
  | `inset` | `boolean` | | Alinha um item sem ícone com os itens que possuem ícone. |
113
113
 
114
+ ## Propriedades de MenuGroup
115
+
116
+ `MenuGroup` agrupa itens relacionados para leitores de tela (`role="group"`); combine com
117
+ `MenuLabel` para nomear o grupo e `MenuSeparator` para separá-lo do próximo. Não tem props
118
+ próprias além das de DOM.
119
+
114
120
  ## Propriedades de MenuContent
115
121
 
116
122
  | Propriedade | Tipo | Padrão | Descrição |
@@ -39,3 +39,16 @@ tecnologias assistivas. O contêiner da coleção continua responsável pela men
39
39
  ```tsx preview col
40
40
  <MetricCard loading />
41
41
  ```
42
+
43
+ ## Propriedades de MetricCard
44
+
45
+ | Propriedade | Tipo | Padrão | Descrição |
46
+ |---|---|---|---|
47
+ | `label` | `ReactNode` | | O nome da medida. |
48
+ | `value` | `ReactNode` | | O valor já formatado pelo consumidor. |
49
+ | `loading` | `boolean` | `false` | Substitui rótulo e valor por skeletons e marca `aria-busy`. |
50
+ | `labelAction` | `ReactNode` | | Controle ao lado do rótulo, como uma explicação em tooltip. |
51
+ | `description` | `ReactNode` | | Contexto que explica recorte, proporção ou significado do valor. |
52
+ | `icon` | `ReactNode` | | Ícone decorativo que identifica a natureza da medida. |
53
+ | `context` | `'neutral' \| 'info' \| 'success' \| 'warning' \| 'danger'` | `'neutral'` | Contexto semântico do ícone; não altera a superfície do card. |
54
+ | `action` | `ReactNode` | | Ação relacionada diretamente à medida. |
@@ -8,7 +8,9 @@ contexto. O container é centralizado e ocupa a largura disponível até `80rem`
8
8
  abaixo do cabeçalho permanece livre para tabelas, cards ou outras composições.
9
9
 
10
10
  A forma curta é o padrão para páginas comuns. Ela cria internamente `PageHeader` e `PageBody`;
11
- portanto, não produz uma estrutura visual ou semântica diferente da forma explícita.
11
+ portanto, não produz uma estrutura visual ou semântica diferente da forma explícita. O cabeçalho é a
12
+ mesma anatomia de `Content` (título, contador, descrição e ações): o que muda entre os dois é o nível
13
+ do heading e a hierarquia visual.
12
14
 
13
15
  `Page` é o esqueleto de páginas e recursos delimitados. Ele também pode ocupar o painel principal
14
16
  de um shell com sidebar; a navegação lateral não exige remover o teto nem reconstruir o cabeçalho.
@@ -41,6 +43,14 @@ render(
41
43
  )
42
44
  ```
43
45
 
46
+ ## Ações no chrome do shell
47
+
48
+ Quando o shell reserva uma barra própria para contexto e ações, envolva sua região de conteúdo com
49
+ `PageActionsTarget` e passe o elemento de destino em `target`. As ações declaradas em `Page`
50
+ continuam pertencendo semanticamente ao cabeçalho da página, mas são projetadas nesse elemento.
51
+ Com `target={null}`, elas permanecem na posição padrão; isso permite montar o alvo por `ref` sem
52
+ uma renderização intermediária inconsistente.
53
+
44
54
  ## Composição explícita
45
55
 
46
56
  Use os slots quando a página precisar compor o header diretamente. Não misture propriedades da
@@ -82,8 +92,10 @@ altura e semântica acessível consistentes.
82
92
  </Page>
83
93
  ```
84
94
 
85
- `loading` centraliza o `Spinner`; `error` compõe `Alert`; `empty` compõe `Empty`; e `ready` entrega
86
- os filhos sem acrescentar uma superfície.
95
+ `loading` centraliza o `Spinner` num contêiner `role="status"`; `error` compõe `Alert` com o botão
96
+ de recuperação quando há `onRetry`; `empty` compõe `Empty`; e `ready` entrega os filhos sem
97
+ acrescentar uma superfície. São as mesmas superfícies de `DataState`, na escala da página: `title`
98
+ e `description` nomeiam a situação e, sem `title`, valem `errorMessage` e `emptyMessage`.
87
99
 
88
100
  ```tsx preview col
89
101
  <Page title="Relatórios">
@@ -118,5 +130,9 @@ estado na própria seção com `DataState`, `ActionView`, `ActionList` ou `Alert
118
130
  | `title` | `ReactNode` | Texto seguro por estado | Situação reconhecível pela pessoa. |
119
131
  | `description` | `ReactNode` | | Impacto ou próximo passo aplicável. |
120
132
  | `icon` | `ReactNode` | Alerta no erro | Ícone decorativo do estado. |
121
- | `action` | `ReactNode` | | Recuperação, seleção ou criação aplicável. |
133
+ | `action` | `ReactNode` | | Seleção ou criação aplicável ao estado. |
134
+ | `emptyMessage` | `string` | `'Nada por aqui'` | Título do vazio quando `title` não é informado. |
135
+ | `errorMessage` | `string` | `'Não foi possível carregar esta página'` | Título do erro quando `title` não é informado. |
136
+ | `onRetry` | `() => void \| Promise<void>` | | Recuperação do erro: acrescenta o botão de tentar de novo ao lado de `action`. |
137
+ | `retryLabel` | `string` | `'Tentar de novo'` | Rótulo do botão de recuperação. |
122
138
  | `children` | `ReactNode` | | Conteúdo renderizado somente em `ready`. |
@@ -29,21 +29,21 @@ rodapé.
29
29
 
30
30
  ## Números longos
31
31
 
32
- A largura mínima é quadrada e cresce conforme o conteúdo. Na escala densa de um rodapé, ajuste por
33
- `className` (`h-7 min-w-7 text-xs` nos números; `size-7` mais `iconClassName="size-3.5"` nas
34
- setas com `iconOnly`).
32
+ A largura mínima é quadrada e cresce conforme o conteúdo. Na escala densa de um rodapé, as setas e a
33
+ elipse usam `size="icon-sm"` (o quadrado de 1.75rem da escala única, com o glifo de 0.875rem); os
34
+ números, que não têm um degrau de 1.75rem na escala, ajustam por `className` (`h-7 min-w-7 text-xs`).
35
35
 
36
36
  ```tsx preview
37
37
  <Pagination>
38
38
  <PaginationContent className="gap-0.5">
39
39
  <PaginationItem>
40
- <PaginationPrevious href="#" iconOnly className="size-7" iconClassName="size-3.5" />
40
+ <PaginationPrevious href="#" iconOnly size="icon-sm" />
41
41
  </PaginationItem>
42
42
  <PaginationItem>
43
43
  <PaginationLink href="#" page={1} className="h-7 min-w-7 text-xs" />
44
44
  </PaginationItem>
45
45
  <PaginationItem>
46
- <PaginationEllipsis className="size-7" />
46
+ <PaginationEllipsis size="icon-sm" />
47
47
  </PaginationItem>
48
48
  <PaginationItem>
49
49
  <PaginationLink href="#" page={5726} className="h-7 min-w-7 text-xs" />
@@ -52,7 +52,7 @@ setas com `iconOnly`).
52
52
  <PaginationLink href="#" page={5727} isActive className="h-7 min-w-7 text-xs" />
53
53
  </PaginationItem>
54
54
  <PaginationItem>
55
- <PaginationNext href="#" iconOnly className="size-7" iconClassName="size-3.5" />
55
+ <PaginationNext href="#" iconOnly size="icon-sm" />
56
56
  </PaginationItem>
57
57
  </PaginationContent>
58
58
  </Pagination>
@@ -61,7 +61,8 @@ setas com `iconOnly`).
61
61
  ## Com elipse
62
62
 
63
63
  `PaginationEllipsis` marca, de forma decorativa e com `aria-hidden`, uma sequência de páginas que
64
- não cabe na barra.
64
+ não cabe na barra. `size` aceita os quadrados da escala (`icon-xs`, `icon-sm`, `icon`, `icon-lg`) para
65
+ parear com as setas.
65
66
 
66
67
  ```tsx preview
67
68
  <Pagination>
@@ -130,7 +131,7 @@ render(
130
131
  | `page` | `number` | | Número usado como conteúdo, quando `children` não é informado, e no nome acessível “Página N”. |
131
132
  | `isActive` | `boolean` | `false` | Marca a página atual com `aria-current="page"` e tratamento `outline`. |
132
133
  | `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
+ | `size` | `ButtonProps['size']` | `'default'` | A escala única, via `Button`. A largura mínima cresce para acomodar números longos; os `icon-*` são quadrados. |
134
135
 
135
136
  ## Propriedades de PaginationPrevious e PaginationNext
136
137
 
@@ -138,4 +139,5 @@ render(
138
139
  |---|---|---|---|
139
140
  | `label` | `string` | `'Página anterior'` ou `'Próxima página'` | Nome acessível e texto visível da ação. |
140
141
  | `iconOnly` | `boolean` | `false` | Exibe somente a seta; `label` continua disponível para leitura assistiva. |
141
- | `iconClassName` | `string` | | Classes aplicadas ao ícone da seta. |
142
+ | `size` | `ButtonProps['size']` | `'default'`; `'icon'` com `iconOnly` | A escala única; `icon-sm` para o rodapé denso. |
143
+ | `iconClassName` | `string` | | Classes aplicadas ao ícone da seta, quando o glifo da escala não servir. |
@@ -49,6 +49,12 @@ detalhes.
49
49
  | `open` | `boolean` | | Estado no modo controlado. |
50
50
  | `onOpenChange` | `(open: boolean) => void` | | Atualiza o estado para permitir abertura ou fechamento por código. |
51
51
 
52
+ ## Propriedades de PopoverAnchor
53
+
54
+ `PopoverAnchor` posiciona o painel em relação a um elemento que não é o gatilho — útil quando o
55
+ clique acontece num item de linha, mas o painel deve alinhar-se ao contêiner. Aceita `asChild` para
56
+ não introduzir um nó extra; sem ele, o `PopoverTrigger` é a âncora.
57
+
52
58
  ## Propriedades de PopoverContent
53
59
 
54
60
  | Propriedade | Tipo | Padrão | Descrição |
@@ -40,25 +40,21 @@ render(
40
40
  )
41
41
  ```
42
42
 
43
- ## Altura e cor
43
+ ## Altura e contexto
44
44
 
45
- className compõe sobre o padrão: ajuste a altura no Progress e tinja o preenchimento mirando o slot do indicador (&_[data-slot=progress-indicator]) para sinalizar bom/atenção.
45
+ `context` diz o que o andamento comunica `success` para meta atingida, `warning` ou `danger`
46
+ para atenção — e tinge trilha e preenchimento com a família semântica. `className` compõe sobre o
47
+ padrão para ajustar a altura.
46
48
 
47
49
  ```tsx preview col
48
50
  <div className="w-full max-w-sm space-y-4">
49
51
  <div className="space-y-1.5">
50
52
  <span className="text-sm">Cobertura de testes</span>
51
- <Progress
52
- value={92}
53
- className="h-1.5 [&_[data-slot=progress-indicator]]:bg-emerald-500"
54
- />
53
+ <Progress value={92} context="success" className="h-1.5" />
55
54
  </div>
56
55
  <div className="space-y-1.5">
57
56
  <span className="text-sm">Skills cobertas pelo revisor</span>
58
- <Progress
59
- value={45}
60
- className="h-3 [&_[data-slot=progress-indicator]]:bg-amber-500"
61
- />
57
+ <Progress value={45} context="warning" className="h-3" />
62
58
  </div>
63
59
  </div>
64
60
  ```
@@ -68,4 +64,5 @@ className compõe sobre o padrão: ajuste a altura no Progress e tinja o preench
68
64
  | Propriedade | Tipo | Padrão | Descrição |
69
65
  |---|---|---|---|
70
66
  | `value` | `number \| null` | | O progresso de 0 a 100. O preenchimento anima a cada mudança; null/ausente deixa a barra vazia. |
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-*. |
67
+ | `context` | `'neutral' \| 'primary' \| 'info' \| 'success' \| 'warning' \| 'danger'` | `'primary'` | O que o andamento comunica; tinge trilha e preenchimento pela família `--context-*`. |
68
+ | `className` | `string` | | Compõe sobre o padrão — ajuste a altura (h-1.5/h-3). |
@@ -40,7 +40,7 @@ render(
40
40
  id="issue"
41
41
  value={issue}
42
42
  onChange={setIssue}
43
- placeholder="Buscar issue…"
43
+ placeholder="Buscar item…"
44
44
  options={[
45
45
  { value: '412', label: 'Ajustar microcopy do handoff', hint: 'SOF-412' },
46
46
  { value: '418', label: 'Preview da sessão cai após deploy', hint: 'SOF-418' },
@@ -69,7 +69,7 @@ render(
69
69
  id="agent-skills"
70
70
  value={skills}
71
71
  onChange={setSkills}
72
- placeholder="Adicionar skill…"
72
+ placeholder="Adicionar habilidade…"
73
73
  options={[
74
74
  { value: 'clean-code', label: 'clean-code' },
75
75
  { value: 'code-style', label: 'code-style' },
@@ -181,7 +181,7 @@ render(
181
181
  icon={<Ticket />}
182
182
  value={task}
183
183
  onChange={setTask}
184
- placeholder="Vincular task"
184
+ placeholder="Vincular tarefa"
185
185
  options={[
186
186
  { value: 'gra-2', label: 'Nova tela anotações', hint: 'GRA-2' },
187
187
  { value: 'gra-7', label: 'Filtro por filial', hint: 'GRA-7' },
@@ -227,8 +227,8 @@ function Demo() {
227
227
  value={values}
228
228
  onChange={setValues}
229
229
  options={[
230
- { value: 'developer', label: 'Developer' },
231
- { value: 'reviewer', label: 'Reviewer' },
230
+ { value: 'developer', label: 'Desenvolvedor' },
231
+ { value: 'reviewer', label: 'Revisor' },
232
232
  { value: 'designer', label: 'Designer' },
233
233
  ]}
234
234
  placeholder="Papéis…"
@@ -1,8 +1,8 @@
1
1
  ---
2
- title: Contexto & Variante
2
+ title: Contexto e variante
3
3
  ---
4
4
 
5
- # Contexto & Variante
5
+ # Contexto e variante
6
6
 
7
7
  Componentes semânticos separam significado de aparência. `context` responde por que o elemento
8
8
  recebe destaque; `variant` escolhe como esse significado aparece. Essa ordem evita que nomes como
@@ -59,5 +59,6 @@ const status = t.dict(
59
59
 
60
60
  ## Compatibilidade
61
61
 
62
- `tone` em dicionários e variantes semânticas antigas continuam aceitos durante a migração. Código
63
- novo usa `context`; não misture o contrato antigo e o novo na mesma ocorrência.
62
+ `tone` em dicionários continua aceito durante a migração; código novo usa `context`. As variantes
63
+ semânticas antigas dos componentes (`default`, `secondary`, `destructive`, `success`, `warning`,
64
+ `info`) saíram na 14.0.0: `variant` só descreve tratamento visual e o significado é sempre `context`.
@@ -61,7 +61,7 @@ uma sidebar fixa, redimensionável ou recolhida.
61
61
  | `PaneHeader` | Mantém identidade, contexto ou ações no topo. |
62
62
  | `PaneBody` | Ocupa o espaço restante e concentra a rolagem vertical. |
63
63
  | `PaneFooter` | Mantém ações persistentes no rodapé. |
64
- | `SidebarNav` ou `ShellNav` | Apresenta e controla os destinos de navegação. |
64
+ | `SidebarNav` | Apresenta e controla os destinos de navegação. |
65
65
 
66
66
  `PaneContent` permanece como alias temporário de `PaneBody` durante a versão 12. Código novo usa
67
67
  `PaneBody`.
@@ -134,28 +134,16 @@ render(
134
134
  Esse é o padrão usado pelo `DocBrowser`: seções são rótulos, grupos nomeados são nós expansíveis e
135
135
  páginas são folhas. Um grupo começa aberto e volta a abrir quando contém a página ativa.
136
136
 
137
- Use `ShellNav` para uma navegação plana que precisa de cabeçalho próprio e grupos ancorados no
138
- rodapé. Ele gerencia a rolagem internamente e se adapta quando estiver dentro de uma `Sidebar`
139
- recolhida.
140
-
141
- ```tsx
142
- <Sidebar collapsed={collapsed}>
143
- <ShellNav
144
- heading={<ShellNavHeading title="Relatórios" action={<CreateReportButton />} />}
145
- groups={reportGroups}
146
- footer={settingsGroups}
147
- activeId={activeId}
148
- onSelect={navigateToReport}
149
- />
150
- </Sidebar>
151
- ```
152
-
153
137
  ## Recolher a coluna
154
138
 
155
- `collapsed` pertence à `Sidebar`. Nesse estado, `SidebarItem`, `SidebarNav` e `ShellNav` mantêm
139
+ `collapsed` pertence à `Sidebar`. Nesse estado, `SidebarItem` e `SidebarNav` mantêm
156
140
  somente os ícones e expõem os rótulos em tooltips. Por isso, todo destino que aparece no modo
157
141
  recolhido precisa de um ícone reconhecível e de um `label` completo.
158
142
 
143
+ O slot de ícone do `SidebarItem` ocupa `1rem` nos dois estados e normaliza SVGs para essa medida.
144
+ O consumidor escolhe o símbolo e sua cor sem precisar repetir largura ou altura em ícones SVG.
145
+ Outros tipos de `ReactNode` continuam responsáveis pelas próprias dimensões.
146
+
159
147
  ```tsx preview
160
148
  const [collapsed, setCollapsed] = useState(false)
161
149
 
@@ -216,12 +204,13 @@ estrutura evita botões aninhados e permite que cada controle receba foco de for
216
204
  }
217
205
  onClick={() => {}}
218
206
  />
219
- <SidebarItem
220
- label="Criar workspace"
221
- icon={<FilePlus2 />}
222
- className="pl-6"
223
- onClick={() => {}}
224
- />
207
+ <SidebarTreeGroup>
208
+ <SidebarItem
209
+ label="Criar workspace"
210
+ icon={<FilePlus2 />}
211
+ onClick={() => {}}
212
+ />
213
+ </SidebarTreeGroup>
225
214
  </div>
226
215
  ```
227
216
 
@@ -323,26 +312,3 @@ O driver de drag-and-drop continua externo e fornece seus atributos por `dragPro
323
312
  |---|---|---|---|
324
313
  | `className` | `string` | | Ajusta o grupo sem substituir o recuo, o espaçamento e a guia vertical padrão. |
325
314
  | `children` | `ReactNode` | | Itens ou grupos que descendem do nó anterior. |
326
-
327
- ## Propriedades de ShellNav
328
-
329
- | Propriedade | Tipo | Padrão | Descrição |
330
- |---|---|---|---|
331
- | `groups` | `ShellNavGroup[]` | | Grupos planos exibidos na região rolável. Grupos vazios são omitidos. |
332
- | `activeId` | `string` | | Identificador do destino atual. |
333
- | `onSelect` | `(id: string) => void` | | Recebe o identificador selecionado. |
334
- | `heading` | `ReactNode` | | Conteúdo fixo acima da navegação; fica oculto no modo recolhido. |
335
- | `footer` | `ShellNavGroup[]` | | Grupos ancorados abaixo da região rolável. |
336
- | `navLabel` | `string` | `'Navegação'` | Nome acessível da landmark `nav`. |
337
- | `className` | `string` | | Ajusta a coluna da navegação. A largura vem do contêiner. |
338
-
339
- Cada `ShellNavGroup` recebe `label` opcional e `items`. Um `ShellNavItem` declara `id`, `label`,
340
- `icon`, `badge` e `disabled`.
341
-
342
- ## Propriedades de ShellNavHeading
343
-
344
- | Propriedade | Tipo | Padrão | Descrição |
345
- |---|---|---|---|
346
- | `title` | `ReactNode` | | Título da navegação. |
347
- | `action` | `ReactNode` | | Ação relacionada apresentada no extremo oposto. |
348
- | `className` | `string` | | Ajusta a faixa de cabeçalho. |
@@ -33,3 +33,9 @@ O esqueleto reproduz o layout final do card — título, descrição, conteúdo
33
33
  </CardFooter>
34
34
  </Card>
35
35
  ```
36
+
37
+ ## Propriedades de Skeleton
38
+
39
+ | Propriedade | Tipo | Padrão | Descrição |
40
+ |---|---|---|---|
41
+ | `className` | `string` | | Dá forma ao placeholder (`h-4 w-40`, `size-10 rounded-full`); o componente só traz o pulso e o fundo. |
@@ -1,9 +1,12 @@
1
1
  ## Carregamento sem progresso conhecido
2
2
 
3
- Use `Spinner` quando a duração ou o progresso da espera não forem conhecidos. `sm` atende ações
4
- compactas; `lg`, estados mais amplos. O componente possui o nome acessível “Carregando”.
3
+ Use `Spinner` quando a duração ou o progresso da espera não forem conhecidos. `size` usa os nomes da
4
+ escala dos controles e mede o glifo do controle homônimo: `sm` é o ícone de um `Button` `sm`, `lg` o
5
+ de um `lg`. O ícone é decorativo; quem nomeia a espera é o contêiner (`role="status"`, como fazem
6
+ `DataState` e `PageState`) ou o texto ao lado.
5
7
 
6
8
  ```tsx preview
9
+ <Spinner size="xs" />
7
10
  <Spinner size="sm" />
8
11
  <Spinner />
9
12
  <Spinner size="lg" />
@@ -20,11 +23,11 @@ andamento.
20
23
 
21
24
  ## Em carga de conteúdo
22
25
 
23
- Espera curta sem forma definida. Quando o conteúdo tem forma conhecida (lista, card), prefira
24
- Skeleton.
26
+ Espera curta sem forma definida; o contêiner nomeia o estado. Para uma consulta inteira, `DataState`
27
+ já monta esse contêiner. Quando o conteúdo tem forma conhecida (lista, card), prefira Skeleton.
25
28
 
26
29
  ```tsx preview
27
- <div className="flex items-center gap-2 text-sm text-muted-foreground">
30
+ <div role="status" className="flex items-center gap-2 text-sm text-muted-foreground">
28
31
  <Spinner />
29
32
  <span>Carregando sessões…</span>
30
33
  </div>
@@ -34,4 +37,4 @@ Skeleton.
34
37
 
35
38
  | Propriedade | Tipo | Padrão | Descrição |
36
39
  |---|---|---|---|
37
- | `size` | `'sm' \| 'default' \| 'lg'` | `'default'` | O tamanho sm para dentro de botão, lg para estados de página. |
40
+ | `size` | `'xs' \| 'sm' \| 'default' \| 'lg'` | `'default'` | O glifo do controle homônimo na escala única (0.875 · 0.875 · 1 · 1.25rem). |
@@ -74,3 +74,24 @@ const defaultLayout = readLayout('workspace-layout')
74
74
  ```
75
75
 
76
76
  Em aplicações renderizadas no servidor, leia o armazenamento somente no cliente. `onLayoutChanged` também permite usar `sessionStorage` ou uma camada própria quando o layout precisa acompanhar outro escopo.
77
+
78
+ ## Propriedades de Split
79
+
80
+ | Propriedade | Tipo | Padrão | Descrição |
81
+ |---|---|---|---|
82
+ | `direction` | `'horizontal' \| 'vertical'` | `'horizontal'` | Sentido em que os panes se alinham. |
83
+ | `resizable` | `boolean` | `false` | Cada fronteira ganha um separador acessível e arrastável. |
84
+ | `handle` | `boolean` | `false` | Mostra a alça visual no separador. |
85
+ | `id` | `string` | | Identidade estável do grupo redimensionável. |
86
+ | `defaultLayout` | `Record<string, number>` | | Layout percentual restaurado, indexado pelos ids dos panes. |
87
+ | `onLayoutChanged` | `(layout, { isUserInteraction }) => void` | | Chamado ao concluir uma mudança de layout; persista onde fizer sentido. |
88
+
89
+ ## Propriedades de Pane
90
+
91
+ | Propriedade | Tipo | Padrão | Descrição |
92
+ |---|---|---|---|
93
+ | `id` | `string` | | Identidade estável usada pelo layout redimensionável e persistido. |
94
+ | `initialSize` | `number \| string` | | Tamanho inicial; número é porcentagem, string aceita `%`, `rem`, `em`, `vh`, `vw` e `px`. |
95
+ | `minSize` / `maxSize` | `number \| string` | | Limites quando o split é redimensionável. |
96
+ | `grow` | `boolean` | `false` | Ocupa o espaço remanescente no layout simples. |
97
+ | `inset` | `'none' \| 'sm' \| 'md' \| 'lg'` | `'md'` | Respiro interno; `none` para chrome, navegação ou conteúdo com inset próprio. |
@@ -66,5 +66,5 @@ disabled esmaece e bloqueia a chave — ligada ou desligada — e o rótulo em p
66
66
  | `checked` | `boolean` | | O estado, no modo controlado — parear com onCheckedChange. |
67
67
  | `onCheckedChange` | `(checked: boolean) => void` | | Chamado a cada alternância, com o novo estado. |
68
68
  | `defaultChecked` | `boolean` | `false` | Estado inicial no modo não controlado. |
69
- | `size` | `'sm' \| 'default'` | `'default'` | Tamanho da chave — sm para densidade em linha de lista. |
69
+ | `size` | `'sm' \| 'default'` | `'default'` | Tamanho da chave, com os nomes da escala única — sm para densidade em linha de lista. |
70
70
  | `disabled` | `boolean` | `false` | Esmaece e bloqueia — o Label em par esmaece junto (peer-disabled). |
@@ -92,7 +92,7 @@ lateral do gatilho.
92
92
  | `defaultValue` | `string` | | Aba inicial no modo não controlado. |
93
93
  | `value` | `string` | | Aba ativa no modo controlado. Use com `onValueChange`. |
94
94
  | `onValueChange` | `(value: string) => void` | | Chamado quando a pessoa seleciona outra aba. |
95
- | `size` | `'default' \| 'sm'` | `'default'` | Escala de altura compartilhada com `TabsList`. |
95
+ | `size` | `'default' \| 'sm'` | `'default'` | Altura da lista na escala única dos controles (2.25 e 2rem), aplicada em `TabsList`. |
96
96
  | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Direção da lista de abas. |
97
97
 
98
98
  ## Propriedades de TabsList
@@ -29,3 +29,10 @@ Associe `htmlFor` no `Label` ao `id` do campo para manter o rótulo acessível.
29
29
  <Textarea aria-invalid placeholder="Conte o contexto da mudança." />
30
30
  <Textarea disabled defaultValue="Sessão encerrada — o brief não pode mais ser editado." />
31
31
  ```
32
+
33
+ ## Propriedades de Textarea
34
+
35
+ | Propriedade | Tipo | Padrão | Descrição |
36
+ |---|---|---|---|
37
+ | `…props` | `ComponentProps<'textarea'>` | | Todos os atributos nativos (`value`, `defaultValue`, `rows`, `disabled`, `aria-invalid`…). A altura acompanha o conteúdo (`field-sizing-content`) a partir de `min-h-16`. |
38
+ | `className` | `string` | | Compõe sobre o estilo padrão. |
@@ -70,7 +70,7 @@ disabled esmaece e bloqueia o clique — o estado pressed permanece visível.
70
70
  | `onPressedChange` | `(pressed: boolean) => void` | | Chamado a cada alternância, com o novo estado. |
71
71
  | `defaultPressed` | `boolean` | `false` | Estado inicial no modo não controlado. |
72
72
  | `variant` | `'default' \| 'outline'` | `'default'` | default não tem borda (fundo só quando ativo); outline carrega a borda. |
73
- | `size` | `'sm' \| 'default' \| 'lg'` | `'default'` | Altura do botão — sm para toolbar densa, lg para alvo mais confortável. |
73
+ | `size` | `'sm' \| 'default' \| 'lg'` | `'default'` | Altura na escala única dos controles (2 · 2.25 · 2.5rem) — sm para toolbar densa, lg para alvo mais confortável. |
74
74
  | `disabled` | `boolean` | `false` | Esmaece e bloqueia o clique, preservando o estado visual. |
75
75
 
76
76
  ## ToggleGroup
@@ -1,8 +1,8 @@
1
1
  ---
2
- title: Tokens & Tema
2
+ title: Tokens e tema
3
3
  ---
4
4
 
5
- # Tokens & Tema
5
+ # Tokens e tema
6
6
 
7
7
  O tema canônico vive no Opus (`theme.css`): tokens com a cor inteira na var, mapeados para o
8
8
  Tailwind via `@theme inline`. Os swatches abaixo leem as vars **ao vivo** — troque o tema do app
@@ -73,8 +73,8 @@ render(
73
73
 
74
74
  ## Linhas e foco
75
75
 
76
- > Bordas e o anel de foco também são tokens — nada de cinza hardcoded. A aresta de superfície
77
- > elevada (`--edge`) mora na seção Elevação por papel.
76
+ > Bordas e o anel de foco também são tokens — nada de cinza hardcoded. Superfícies elevadas usam
77
+ > a mesma `border-border`; o que muda entre elas é a sombra, descrita na seção Escala de elevação.
78
78
 
79
79
  ```tsx preview
80
80
  const LINES = [
@@ -60,3 +60,11 @@ quando o texto completo ainda não oferecer contexto suficiente.
60
60
 
61
61
  Requer `TooltipProvider` na raiz (o esqueleto do `opus create` já monta). Largura vem do
62
62
  container ou de `className` (`max-w-*`) — o span é `block truncate`.
63
+
64
+ ## Propriedades de Truncate
65
+
66
+ | Propriedade | Tipo | Padrão | Descrição |
67
+ |---|---|---|---|
68
+ | `tooltip` | `ReactNode` | os próprios `children` | Conteúdo da dica quando o texto transborda. |
69
+ | `fade` | `boolean` | `false` | Sinaliza o corte esmaecendo o fim da linha, no lugar das reticências. |
70
+ | `className` | `string` | | Largura (`max-w-*`) e demais ajustes; o span é `block truncate`. |
@@ -30,6 +30,20 @@ import { Button, Dialog, useAction } from '@softize/opus/ui/react'
30
30
  @source '../node_modules/@softize/opus/src/ui';
31
31
  ```
32
32
 
33
+ ## Prebundle do Vite
34
+
35
+ A entrada `@softize/opus/ui/react` é um `.tsx`, e o prebundle do Vite só considera entradas
36
+ `.js`/`.ts`. Sem ajuste, o dev server avisa `Cannot optimize dependency` e serve a árvore do Opus
37
+ arquivo a arquivo na carga fria. Há duas saídas, cada uma com um custo conhecido:
38
+
39
+ - `optimizeDeps.include: ['@softize/opus/ui/react']` com `extensions: ['.tsx']` pré-empacota o
40
+ Opus, mas pode duplicar `@tanstack/react-query` quando o app também o importa direto (dois
41
+ `QueryClient`, hooks fora do provider).
42
+ - `optimizeDeps.exclude: ['@softize/opus/ui/react']` evita a duplicação e infla a carga fria.
43
+
44
+ Escolha pelo sintoma que aparece no seu app e registre a decisão no `vite.config.ts`. A saída
45
+ definitiva (entrada `.ts` no pacote) está no radar do Opus.
46
+
33
47
  ## Origem e anti-drift
34
48
 
35
49
  > Cada componente declara de onde veio — e a regra de sincronização vem junto.
@@ -8,7 +8,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
8
8
  import { z } from 'zod'
9
9
  import { attachLogicalType, defineContract, error } from '../../core/index.ts'
10
10
  import type { ActionDef, ActionResult, ClientAdapter, LogicalTypeMeta, Paginated } from '../../core/index.ts'
11
- import { TbdlibProvider } from '../react.tsx'
11
+ import { OpusProvider } from '../react.tsx'
12
12
 
13
13
  // — Dados enlatados (domínio da casa) —
14
14
  export interface DocBrowserWorkspace {
@@ -37,7 +37,7 @@ export const docWorkspaceStatus: LogicalTypeMeta = {
37
37
  keys: [...STATUS],
38
38
  entries: {
39
39
  active: { label: 'Ativo', context: 'success', description: 'Agentes em operação para o cliente.' },
40
- onboarding: { label: 'Onboarding', context: 'warning' },
40
+ onboarding: { label: 'Em integração', context: 'warning' },
41
41
  paused: { label: 'Pausado' },
42
42
  },
43
43
  presentation: 'status',
@@ -59,7 +59,7 @@ export const docWorkspaceCreate = defineContract({
59
59
  }),
60
60
  output: z.object({ id: z.string() }),
61
61
  fields: {
62
- name: { label: 'Nome', placeholder: 'Ex.: Empresa X', hint: 'Digite "Softize" pra ver o erro de servidor.' },
62
+ name: { label: 'Nome', placeholder: 'Ex.: Empresa X', help: 'Digite Softize para ver o erro de servidor.' },
63
63
  status: { label: 'Status' },
64
64
  contact: { label: 'Contato', placeholder: 'email@cliente.com' },
65
65
  notes: { label: 'Observações', placeholder: 'Contexto do onboarding…' },
@@ -100,7 +100,7 @@ export const docWorkspaceList = defineContract({
100
100
  kind: 'static',
101
101
  items: [
102
102
  { value: 'active', label: 'Ativo' },
103
- { value: 'onboarding', label: 'Onboarding' },
103
+ { value: 'onboarding', label: 'Em integração' },
104
104
  { value: 'paused', label: 'Pausado' },
105
105
  ],
106
106
  },
@@ -225,7 +225,7 @@ const queryClient = new QueryClient()
225
225
  export function DocBrowserActionProvider({ children }: { children: React.ReactNode }): React.ReactElement {
226
226
  return (
227
227
  <QueryClientProvider client={queryClient}>
228
- <TbdlibProvider client={docClient}>{children}</TbdlibProvider>
228
+ <OpusProvider client={docClient}>{children}</OpusProvider>
229
229
  </QueryClientProvider>
230
230
  )
231
231
  }