@softize/opus 18.1.1 → 18.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/package.json +1 -1
- package/registry/skills/build-opus-ui/SKILL.md +3 -2
- package/registry/skills/build-opus-ui/references/ui-patterns.md +4 -3
- package/src/core/errors.ts +0 -1
- package/src/core/presentation.ts +143 -58
- package/src/core/types.ts +4 -0
- package/src/ui/components/patterns/data-state.tsx +1 -1
- package/src/ui/components/patterns/list.tsx +606 -251
- package/src/ui/components/patterns/page.tsx +16 -5
- package/src/ui/components/patterns/presentation.tsx +228 -63
- package/src/ui/components/patterns/split.tsx +5 -2
- package/src/ui/components/patterns/surface-assistant.tsx +74 -0
- package/src/ui/components/primitives/field.tsx +23 -2
- package/src/ui/components/primitives/metric-card.tsx +64 -5
- package/src/ui/components/primitives/select.tsx +27 -23
- package/src/ui/components/primitives/table.tsx +4 -1
- package/src/ui/docs/content/action-list.md +84 -46
- package/src/ui/docs/content/field.md +6 -1
- package/src/ui/docs/content/metric-card.md +43 -0
- package/src/ui/docs/content/presentation.md +40 -14
- package/src/ui/docs/content/select.md +4 -0
- package/src/ui/docs/content/split.md +80 -19
- package/src/ui/meta.ts +2 -2
- package/src/ui/react.tsx +6 -0
|
@@ -32,11 +32,20 @@ shell que efetivamente hospeda a rota.
|
|
|
32
32
|
O exemplo declara a Presentation sobre um contrato de formulário e alterna a superfície. O
|
|
33
33
|
`DocBrowserActionProvider` simula o cliente de actions; na aplicação, esse papel é do provider real.
|
|
34
34
|
|
|
35
|
+
Quando o recurso aceita assistência contextual, declare somente o gatilho serializável em
|
|
36
|
+
`assistant`. O renderer coloca esse gatilho no cabeçalho e abre o painel à direita do body da
|
|
37
|
+
própria Page, Dialog ou Drawer. Cabeçalho e rodapé continuam ocupando toda a largura da superfície;
|
|
38
|
+
enquanto o painel está aberto, o gatilho sai do cabeçalho e o próprio painel assume sua identidade
|
|
39
|
+
visual. O dado vivo do recurso não entra na definição: a página que o carregou fornece
|
|
40
|
+
`assistant.render`, captura identidade, nome e demais dados autorizados e monta o chat. Assim,
|
|
41
|
+
contexto de conversa não vira autorização nem dado persistido no manifest.
|
|
42
|
+
|
|
35
43
|
```tsx live
|
|
36
44
|
const workspacePresentation = definePresentation({
|
|
37
45
|
schemaVersion: 1,
|
|
38
46
|
id: "workspace.create",
|
|
39
47
|
title: "Criar workspace",
|
|
48
|
+
assistant: { triggerLabel: "Conversar sobre este workspace" },
|
|
40
49
|
body: { action: docWorkspaceCreate.name },
|
|
41
50
|
});
|
|
42
51
|
|
|
@@ -81,6 +90,22 @@ function Example() {
|
|
|
81
90
|
if (next) setInvocation(next);
|
|
82
91
|
else setOpen(false);
|
|
83
92
|
}}
|
|
93
|
+
assistant={{
|
|
94
|
+
render: ({ close }) => (
|
|
95
|
+
<div className="flex h-full flex-col p-3">
|
|
96
|
+
<p className="text-sm">
|
|
97
|
+
Conversa vinculada ao workspace carregado pela página.
|
|
98
|
+
</p>
|
|
99
|
+
<Button
|
|
100
|
+
className="mt-3 self-start"
|
|
101
|
+
variant="ghost"
|
|
102
|
+
onClick={close}
|
|
103
|
+
>
|
|
104
|
+
Fechar
|
|
105
|
+
</Button>
|
|
106
|
+
</div>
|
|
107
|
+
),
|
|
108
|
+
}}
|
|
84
109
|
/>
|
|
85
110
|
</div>
|
|
86
111
|
</DocBrowserActionProvider>
|
|
@@ -164,21 +189,22 @@ no manifest e concentre a inspeção na Lens em vez de criar um launcher flutuan
|
|
|
164
189
|
|
|
165
190
|
## Propriedades de Presentation
|
|
166
191
|
|
|
167
|
-
| Propriedade | Tipo | Padrão | Descrição
|
|
168
|
-
| -------------------- | ------------------------------------------------ | ------ |
|
|
169
|
-
| `definition` | `PresentationDefinition` | | Artefato estático que descreve o recurso.
|
|
170
|
-
| `definitions` | `PresentationDefinition[]` | | Registry alcançável por navegação, abertura e retorno.
|
|
171
|
-
| `actions` | `PresentationActionRegistry` | | Contratos compartilháveis referenciados pelo artefato.
|
|
172
|
-
| `invocation` | `PresentationInvocation` | | Surface, input e pilha da exibição atual.
|
|
173
|
-
| `bindingContext` | `PresentationBindingContext` | | Rota, item, seleção, sessão e resultado disponíveis.
|
|
174
|
-
| `
|
|
175
|
-
| `
|
|
176
|
-
| `
|
|
192
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
193
|
+
| -------------------- | ------------------------------------------------ | ------ | --------------------------------------------------------------------------------------------------- |
|
|
194
|
+
| `definition` | `PresentationDefinition` | | Artefato estático que descreve o recurso. |
|
|
195
|
+
| `definitions` | `PresentationDefinition[]` | | Registry alcançável por navegação, abertura e retorno. |
|
|
196
|
+
| `actions` | `PresentationActionRegistry` | | Contratos compartilháveis referenciados pelo artefato. |
|
|
197
|
+
| `invocation` | `PresentationInvocation` | | Surface, input e pilha da exibição atual. |
|
|
198
|
+
| `bindingContext` | `PresentationBindingContext` | | Rota, item, seleção, sessão e resultado disponíveis. |
|
|
199
|
+
| `assistant` | `PresentationAssistantRuntime` | | Painel contextual fornecido pela superfície hospedeira. |
|
|
200
|
+
| `onInvocationChange` | `(next: PresentationInvocation \| null) => void` | | Recebe navegação, retorno e fechamento. |
|
|
201
|
+
| `onRefresh` | `(action: string \| null) => void` | | Recebe invalidações declaradas após sucesso. |
|
|
202
|
+
| `listState` | `ActionListState` | | Recorte controlado da action `list` do body, quando a aplicação o sincroniza com a URL. |
|
|
177
203
|
| `onListStateChange` | `(state: ActionListState) => void` | | Recebe cada mudança de recorte ou exibição da lista do body, como busca, filtros, período e página. |
|
|
178
|
-
| `open` | `boolean` | `true` | Estado controlado de Dialog ou Drawer.
|
|
179
|
-
| `onOpenChange` | `(open: boolean) => void` | | Notifica abertura e fechamento da superfície modal.
|
|
180
|
-
| `className` | `string` | | Classes adicionais da superfície.
|
|
181
|
-
| `bodyClassName` | `string` | | Classes adicionais do body, aplicadas uma única vez.
|
|
204
|
+
| `open` | `boolean` | `true` | Estado controlado de Dialog ou Drawer. |
|
|
205
|
+
| `onOpenChange` | `(open: boolean) => void` | | Notifica abertura e fechamento da superfície modal. |
|
|
206
|
+
| `className` | `string` | | Classes adicionais da superfície. |
|
|
207
|
+
| `bodyClassName` | `string` | | Classes adicionais do body, aplicadas uma única vez. |
|
|
182
208
|
|
|
183
209
|
## Propriedades de PresentationInspector
|
|
184
210
|
|
|
@@ -24,6 +24,10 @@ render(
|
|
|
24
24
|
)
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
O gatilho respeita a largura definida pelo contexto. Ao abrir, a lista usa essa largura como mínimo
|
|
28
|
+
e pode crescer até `32rem` para preservar rótulos maiores sem alterar o layout do formulário ou da
|
|
29
|
+
toolbar. Rótulos que ultrapassarem esse limite continuam truncados como proteção de layout.
|
|
30
|
+
|
|
27
31
|
## Lista pesquisável
|
|
28
32
|
|
|
29
33
|
Use `searchable` quando a quantidade ou os rótulos dificultarem encontrar uma opção. O gatilho
|
|
@@ -12,11 +12,13 @@ render(
|
|
|
12
12
|
<div className="p-4 text-sm">Navegação</div>
|
|
13
13
|
</Pane>
|
|
14
14
|
<Pane grow inset="lg">
|
|
15
|
-
<p className="text-sm text-muted-foreground">
|
|
15
|
+
<p className="text-sm text-muted-foreground">
|
|
16
|
+
Conteúdo. Arraste a divisória.
|
|
17
|
+
</p>
|
|
16
18
|
</Pane>
|
|
17
19
|
</Split>
|
|
18
20
|
</div>,
|
|
19
|
-
)
|
|
21
|
+
);
|
|
20
22
|
```
|
|
21
23
|
|
|
22
24
|
## Espaçamento interno
|
|
@@ -30,8 +32,12 @@ Quando uma área precisa continuar legível em telas largas, use uma unidade abs
|
|
|
30
32
|
|
|
31
33
|
```tsx
|
|
32
34
|
<Split resizable>
|
|
33
|
-
<Pane grow inset="none"
|
|
34
|
-
|
|
35
|
+
<Pane grow inset="none">
|
|
36
|
+
<Main />
|
|
37
|
+
</Pane>
|
|
38
|
+
<Pane initialSize="28rem" minSize="20rem" inset="none">
|
|
39
|
+
<Inspector />
|
|
40
|
+
</Pane>
|
|
35
41
|
</Split>
|
|
36
42
|
```
|
|
37
43
|
|
|
@@ -75,23 +81,78 @@ const defaultLayout = readLayout('workspace-layout')
|
|
|
75
81
|
|
|
76
82
|
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
83
|
|
|
84
|
+
## Assistência dentro da superfície
|
|
85
|
+
|
|
86
|
+
`SurfaceAssistant` especializa o split usado por uma Page, Dialog ou Drawer que abre assistência
|
|
87
|
+
contextual. O conteúdo principal permanece montado e o painel aparece à direita com largura
|
|
88
|
+
redimensionável. A superfície hospedeira controla o gatilho, o estado aberto e os dados passados ao
|
|
89
|
+
painel; o pattern cuida apenas da relação espacial. Envolva somente o body da superfície com
|
|
90
|
+
`SurfaceAssistant`: cabeçalho e rodapé devem permanecer fora do split e ocupar toda a largura.
|
|
91
|
+
|
|
92
|
+
```tsx preview
|
|
93
|
+
function Example() {
|
|
94
|
+
const [open, setOpen] = React.useState(true);
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<div className="h-72 overflow-hidden rounded-lg border border-border">
|
|
98
|
+
<SurfaceAssistant
|
|
99
|
+
open={open}
|
|
100
|
+
assistantLabel="Assistente do pedido"
|
|
101
|
+
assistant={
|
|
102
|
+
<div className="h-full p-3">
|
|
103
|
+
<p className="text-sm">Conversa vinculada ao pedido carregado.</p>
|
|
104
|
+
<Button
|
|
105
|
+
className="mt-3"
|
|
106
|
+
variant="ghost"
|
|
107
|
+
onClick={() => setOpen(false)}
|
|
108
|
+
>
|
|
109
|
+
Fechar
|
|
110
|
+
</Button>
|
|
111
|
+
</div>
|
|
112
|
+
}
|
|
113
|
+
>
|
|
114
|
+
<div className="h-full p-3">
|
|
115
|
+
<Button variant="outline" onClick={() => setOpen(true)}>
|
|
116
|
+
Abrir assistente
|
|
117
|
+
</Button>
|
|
118
|
+
</div>
|
|
119
|
+
</SurfaceAssistant>
|
|
120
|
+
</div>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
render(<Example />);
|
|
125
|
+
```
|
|
126
|
+
|
|
78
127
|
## Propriedades de Split
|
|
79
128
|
|
|
80
|
-
| Propriedade
|
|
81
|
-
|
|
82
|
-
| `direction`
|
|
83
|
-
| `resizable`
|
|
84
|
-
| `handle`
|
|
85
|
-
| `id`
|
|
86
|
-
| `defaultLayout`
|
|
87
|
-
| `onLayoutChanged` | `(layout, { isUserInteraction }) => void` |
|
|
129
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
130
|
+
| ----------------- | ----------------------------------------- | -------------- | ----------------------------------------------------------------------- |
|
|
131
|
+
| `direction` | `'horizontal' \| 'vertical'` | `'horizontal'` | Sentido em que os panes se alinham. |
|
|
132
|
+
| `resizable` | `boolean` | `false` | Cada fronteira ganha um separador acessível e arrastável. |
|
|
133
|
+
| `handle` | `boolean` | `false` | Mostra a alça visual no separador. |
|
|
134
|
+
| `id` | `string` | | Identidade estável do grupo redimensionável. |
|
|
135
|
+
| `defaultLayout` | `Record<string, number>` | | Layout percentual restaurado, indexado pelos ids dos panes. |
|
|
136
|
+
| `onLayoutChanged` | `(layout, { isUserInteraction }) => void` | | Chamado ao concluir uma mudança de layout; persista onde fizer sentido. |
|
|
88
137
|
|
|
89
138
|
## Propriedades de Pane
|
|
90
139
|
|
|
91
|
-
| Propriedade
|
|
92
|
-
|
|
93
|
-
| `id`
|
|
94
|
-
| `initialSize`
|
|
95
|
-
| `minSize` / `maxSize` | `number \| string`
|
|
96
|
-
| `grow`
|
|
97
|
-
| `inset`
|
|
140
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
141
|
+
| --------------------- | -------------------------------- | ------- | ----------------------------------------------------------------------------------------- |
|
|
142
|
+
| `id` | `string` | | Identidade estável usada pelo layout redimensionável e persistido. |
|
|
143
|
+
| `initialSize` | `number \| string` | | Tamanho inicial; número é porcentagem, string aceita `%`, `rem`, `em`, `vh`, `vw` e `px`. |
|
|
144
|
+
| `minSize` / `maxSize` | `number \| string` | | Limites quando o split é redimensionável. |
|
|
145
|
+
| `grow` | `boolean` | `false` | Ocupa o espaço remanescente no layout simples. |
|
|
146
|
+
| `inset` | `'none' \| 'sm' \| 'md' \| 'lg'` | `'md'` | Respiro interno; `none` para chrome, navegação ou conteúdo com inset próprio. |
|
|
147
|
+
|
|
148
|
+
## Propriedades de SurfaceAssistant
|
|
149
|
+
|
|
150
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
151
|
+
| ---------------- | ----------- | ------- | ------------------------------------------------------- |
|
|
152
|
+
| `open` | `boolean` | | Exibe o painel complementar à direita. |
|
|
153
|
+
| `assistantLabel` | `string` | | Nome acessível da região complementar. |
|
|
154
|
+
| `children` | `ReactNode` | | Conteúdo principal que permanece montado. |
|
|
155
|
+
| `assistant` | `ReactNode` | | Painel fornecido pela superfície que conhece o recurso. |
|
|
156
|
+
| `initialSize` | `PaneSize` | `28rem` | Largura inicial do painel. |
|
|
157
|
+
| `minSize` | `PaneSize` | `20rem` | Largura mínima durante o redimensionamento. |
|
|
158
|
+
| `maxSize` | `PaneSize` | `40rem` | Largura máxima durante o redimensionamento. |
|
package/src/ui/meta.ts
CHANGED
|
@@ -81,7 +81,7 @@ export const componentMeta = {
|
|
|
81
81
|
name: "metric-card",
|
|
82
82
|
ancestry: "opus",
|
|
83
83
|
whenToUse:
|
|
84
|
-
"Medida resumida com rótulo, valor em destaque e descrição opcional. `context` realça semanticamente somente o ícone; aceita ação relacionada e estado de carregamento. O consumidor calcula e formata
|
|
84
|
+
"Medida resumida com rótulo, valor em destaque e descrição opcional. Use `secondaryMetric` para uma segunda leitura diretamente relacionada, exibida como lâmina posterior com explicação própria. `context` realça semanticamente somente o ícone; aceita ação relacionada e estado de carregamento. O consumidor calcula e formata os valores; para conteúdo geral ou estrutura livre, use Card.",
|
|
85
85
|
},
|
|
86
86
|
chat: {
|
|
87
87
|
name: "chat",
|
|
@@ -321,7 +321,7 @@ export const componentMeta = {
|
|
|
321
321
|
name: "split",
|
|
322
322
|
ancestry: "opus",
|
|
323
323
|
whenToUse:
|
|
324
|
-
"Divide uma área em panes em sequência horizontal ou vertical. Use `resizable` quando a pessoa deve ajustar a fronteira; o mesmo `<Split>` vira flex simples sem ele. Cada `<Pane>` declara tamanho inicial/mínimo e inset.
|
|
324
|
+
"Divide uma área em panes em sequência horizontal ou vertical. Use `resizable` quando a pessoa deve ajustar a fronteira; o mesmo `<Split>` vira flex simples sem ele. Cada `<Pane>` declara tamanho inicial/mínimo e inset. SurfaceAssistant especializa esse layout para assistência contextual dentro de Page, Dialog ou Drawer.",
|
|
325
325
|
},
|
|
326
326
|
sidebar: {
|
|
327
327
|
name: "sidebar",
|
package/src/ui/react.tsx
CHANGED
|
@@ -105,6 +105,7 @@ export { MetricCard } from "./components/primitives/metric-card.tsx";
|
|
|
105
105
|
export type {
|
|
106
106
|
MetricCardProps,
|
|
107
107
|
MetricCardContext,
|
|
108
|
+
MetricCardSecondaryMetric,
|
|
108
109
|
MetricCardTone,
|
|
109
110
|
} from "./components/primitives/metric-card.tsx";
|
|
110
111
|
|
|
@@ -424,6 +425,7 @@ export {
|
|
|
424
425
|
PresentationInspector,
|
|
425
426
|
} from "./components/patterns/presentation.tsx";
|
|
426
427
|
export type {
|
|
428
|
+
PresentationAssistantRuntime,
|
|
427
429
|
PresentationProps,
|
|
428
430
|
PresentationInspectorProps,
|
|
429
431
|
} from "./components/patterns/presentation.tsx";
|
|
@@ -483,6 +485,10 @@ export type {
|
|
|
483
485
|
SplitLayoutChange,
|
|
484
486
|
} from "./components/patterns/split.tsx";
|
|
485
487
|
|
|
488
|
+
// Assistência contextual: mantém o recurso visível e abre um painel redimensionável na superfície.
|
|
489
|
+
export { SurfaceAssistant } from "./components/patterns/surface-assistant.tsx";
|
|
490
|
+
export type { SurfaceAssistantProps } from "./components/patterns/surface-assistant.tsx";
|
|
491
|
+
|
|
486
492
|
// A barra de ferramentas que flutua sobre uma superfície de trabalho (canvas, editor, preview).
|
|
487
493
|
export {
|
|
488
494
|
Dock,
|