@seniorsistemas/angular-components-mcp 1.0.0-beta.3 → 1.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 (44) hide show
  1. package/dist/data/component-rules/button.md +37 -0
  2. package/dist/data/component-rules/checkbox.md +30 -0
  3. package/dist/data/component-rules/confirm-dialog.md +86 -0
  4. package/dist/data/component-rules/index.json +3 -0
  5. package/dist/data/component-rules/radio-button.md +0 -0
  6. package/dist/data/component-technical/confirm-dialog.md +117 -0
  7. package/dist/data/component-technical/dialog.md +202 -0
  8. package/dist/data/component-technical/dynamic-form.md +292 -0
  9. package/dist/data/component-technical/index.json +4 -0
  10. package/dist/data/component-technical/kanban.md +116 -0
  11. package/dist/data/component-technical/loading-state.md +96 -0
  12. package/dist/data/component-technical/sidebar.md +82 -0
  13. package/dist/data/component-technical/table.md +19 -0
  14. package/dist/data/component-technical/toast.md +63 -0
  15. package/dist/data/components-metadata.json +4402 -0
  16. package/dist/data/dynamic-form-metadata.json +2281 -0
  17. package/dist/data/ux-rules.md +45 -0
  18. package/dist/handlers/handleDetectRequiredProviders.d.ts +12 -0
  19. package/dist/handlers/handleDetectRequiredProviders.d.ts.map +1 -0
  20. package/dist/handlers/handleGetComponentDetails.d.ts +13 -0
  21. package/dist/handlers/handleGetComponentDetails.d.ts.map +1 -0
  22. package/dist/handlers/handleGetComponentRules.d.ts +13 -0
  23. package/dist/handlers/handleGetComponentRules.d.ts.map +1 -0
  24. package/dist/handlers/handleGetComponentRulesIndex.d.ts +11 -0
  25. package/dist/handlers/handleGetComponentRulesIndex.d.ts.map +1 -0
  26. package/dist/handlers/handleGetComponentTechnicalGuide.d.ts +13 -0
  27. package/dist/handlers/handleGetComponentTechnicalGuide.d.ts.map +1 -0
  28. package/dist/handlers/handleGetComponentTechnicalIndex.d.ts +11 -0
  29. package/dist/handlers/handleGetComponentTechnicalIndex.d.ts.map +1 -0
  30. package/dist/handlers/handleGetComponents.d.ts +14 -0
  31. package/dist/handlers/handleGetComponents.d.ts.map +1 -0
  32. package/dist/handlers/handleGetDynamicFormTypes.d.ts +13 -0
  33. package/dist/handlers/handleGetDynamicFormTypes.d.ts.map +1 -0
  34. package/dist/handlers/handleGetUxRules.d.ts +10 -0
  35. package/dist/handlers/handleGetUxRules.d.ts.map +1 -0
  36. package/dist/handlers.d.ts +112 -0
  37. package/dist/handlers.d.ts.map +1 -0
  38. package/dist/index.cjs +16703 -0
  39. package/dist/index.cjs.map +1 -0
  40. package/dist/index.d.ts +3 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.mjs +16700 -0
  43. package/dist/index.mjs.map +1 -0
  44. package/package.json +1 -1
@@ -0,0 +1,292 @@
1
+ # DynamicForm — Guia Técnico
2
+
3
+ **Seletor:** `s-dynamic-form`
4
+ **Package:** `@seniorsistemas/angular-components/dynamic-form`
5
+
6
+ ## Exports e Imports
7
+
8
+ | Tipo | Símbolo |
9
+ | ---------- | ---------------------------------------------------------------------------------------- |
10
+ | Components | `DynamicFormComponent`, `DynamicFormDirective`, `FieldLabelComponent`, `LookupComponent` |
11
+ | Classes | `DynamicFormRegistry` |
12
+ | Types | `DynamicStructure`, `FieldConfig`, `DynamicType`, `FieldType`, `FieldTypeMap` |
13
+
14
+ ```typescript
15
+ import { DynamicFormComponent } from '@seniorsistemas/angular-components/dynamic-form';
16
+ import { DynamicFormModule } from '@seniorsistemas/angular-components/dynamic-form';
17
+ import type { DynamicStructure } from '@seniorsistemas/angular-components/dynamic-form';
18
+ ```
19
+
20
+ ---
21
+
22
+ ## Regra de estruturas
23
+
24
+ - Use `row` quando os campos não precisam de título visual agrupando-os. É o tipo padrão.
25
+ - **TODOS** os campos do formulário devem ir na **mesma `row`**. Só crie uma estrutura adicional se for necessário separar campos em um agrupamento com título próprio.
26
+ - `section` **OBRIGATORIAMENTE** deve ter `header`. Nunca use `section` sem `header`.
27
+ - Dentro de `section` **SEMPRE** deve haver outra `DynamicStructure` (`row` ou `fieldset`). Campos diretos em `section` não são permitidos.
28
+ - **NUNCA** aninhe `section` dentro de `section`.
29
+ - **Antes de agrupar campos**, pergunte ao usuário qual estrutura ele quer usar para organizar o formulário: `row` (sem título), `section` (nova seção com título), ou `fieldset` (agrupamento semântico com título).
30
+
31
+ ### Exemplo comum (sem seção)
32
+
33
+ ```typescript
34
+ protected configs: DynamicStructure[] = [
35
+ {
36
+ type: 'row',
37
+ fields: [
38
+ { name: 'name', type: 'string', label: 'Nome', required: () => true, size: { xl: 6 } },
39
+ { name: 'email', type: 'string', label: 'E-mail', required: () => true, size: { xl: 6 } },
40
+ ],
41
+ },
42
+ ];
43
+ ```
44
+
45
+ > **OBRIGATÓRIO:** Para cada campo em `fields`, o `FormGroup` **deve ter um `FormControl` declarado explicitamente com o mesmo valor de `name`**. O DynamicForm usa esse nome internamente como `formControlName` para fazer o vínculo — ele NÃO cria os controles automaticamente.
46
+ > No exemplo acima, o `FormGroup` deve ser criado com: `this.fb.group({ name: [], email: [] })`.
47
+
48
+ ### Exemplo com seção (quando há nova seção)
49
+
50
+ ```typescript
51
+ protected configs: DynamicStructure[] = [
52
+ {
53
+ type: 'section',
54
+ header: 'Dados Pessoais',
55
+ configs: [
56
+ {
57
+ type: 'row',
58
+ fields: [
59
+ { name: 'name', type: 'string', label: 'Nome', required: () => true, size: { xl: 6 } },
60
+ { name: 'email', type: 'string', label: 'E-mail', required: () => true, size: { xl: 6 } },
61
+ ],
62
+ },
63
+ ],
64
+ },
65
+ ];
66
+ ```
67
+
68
+ ### Exemplo com `fieldset` para agrupamento
69
+
70
+ ```typescript
71
+ protected configs: DynamicStructure[] = [
72
+ {
73
+ type: 'row',
74
+ fields: [
75
+ { name: 'fullName', type: 'string', label: 'Nome completo', size: { xl: 12 } },
76
+ ],
77
+ },
78
+ {
79
+ type: 'fieldset',
80
+ header: 'Endereço',
81
+ configs: [
82
+ {
83
+ type: 'row',
84
+ fields: [
85
+ { name: 'zipCode', type: 'string', label: 'CEP', size: { xl: 4 }, mask: '000000-000' },
86
+ { name: 'street', type: 'string', label: 'Rua', size: { xl: 8 } },
87
+ ],
88
+ },
89
+ ],
90
+ },
91
+ ];
92
+ ```
93
+
94
+ ---
95
+
96
+ ## Padrão 1: Com `FormGroup` externo ✅ PADRÃO OBRIGATÓRIO
97
+
98
+ O DynamicForm **NÃO cria nem gerencia seu próprio FormGroup**. O `FormGroup` deve ser criado externamente no componente e passado via `[form]`. **Para cada campo declarado em `configs`, deve existir um `FormControl` no `FormGroup` com o mesmo valor de `name`** — o DynamicForm usa esse nome como `formControlName` internamente.
99
+
100
+ ### Exemplo
101
+
102
+ ```typescript
103
+ import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';
104
+ import { DynamicFormModule, DynamicStructure } from '@seniorsistemas/angular-components/dynamic-form';
105
+
106
+ @Component({
107
+ imports: [DynamicFormModule, ReactiveFormsModule],
108
+ template: `
109
+ <s-dynamic-form
110
+ [form]="form"
111
+ [configs]="configs"
112
+ />
113
+ <s-button
114
+ label="Salvar"
115
+ priority="primary"
116
+ [disabled]="form.invalid"
117
+ (clicked)="save()"
118
+ />
119
+ `,
120
+ })
121
+ export class MyComponent implements OnInit {
122
+ private readonly fb = inject(FormBuilder);
123
+
124
+ protected form!: FormGroup;
125
+ protected configs: DynamicStructure[] = [
126
+ {
127
+ type: 'row',
128
+ fields: [
129
+ { name: 'name', type: 'string', label: 'Nome', required: () => true, size: { xl: 6 } },
130
+ { name: 'email', type: 'string', label: 'E-mail', required: () => true, size: { xl: 6 } },
131
+ { name: 'birthDate', type: 'date', label: 'Data de Nascimento', size: { xl: 4 } },
132
+ ],
133
+ },
134
+ ];
135
+
136
+ public ngOnInit(): void {
137
+ // Cada FormControl deve ter o mesmo nome que o `name` do campo em configs
138
+ this.form = this.fb.group({
139
+ name: [],
140
+ email: [],
141
+ birthDate: [],
142
+ });
143
+ }
144
+
145
+ protected save(): void {
146
+ if (this.form.valid) {
147
+ console.log(this.form.value);
148
+ }
149
+ }
150
+ }
151
+ ```
152
+
153
+ ---
154
+
155
+ ## Notas de integração
156
+
157
+ - O `FormGroup` **DEVE** ser criado antes do DynamicForm renderizar, com um `FormControl` para cada campo. Exemplo: `this.fb.group({ fieldName: [], otherField: [] })`.
158
+ - Cada campo em `fields` **DEVE** ter `name` definido. Para cada `name`, **declare explicitamente um `FormControl` no `FormGroup` com o mesmo nome** — o DynamicForm usa esse nome como `formControlName` internamente e não cria controles automaticamente.
159
+ - Exemplo: campos com `name: 'name'` e `name: 'email'` exigem `this.fb.group({ name: [], email: [] })`.
160
+ - No array `fields`, a propriedade `required` deve ser uma função que retorna boolean (`() => boolean`).
161
+ - Para campos opcionais com providers específicos (ex: `editor`), use a tool `detect_required_providers` para identificar o provider necessário e onde adicioná-lo.
162
+ - Use `size` com breakpoints customizados (`xs`, `sm`, `md`, `lg`, `xl`, `xxl`, `big`) — **NÃO use breakpoints padrão do Tailwind**.
163
+ - **NUNCA** use `s-select`, `s-checkbox`, `s-text-area` ou outros campos individualmente — sempre prefira `s-dynamic-form`.
164
+
165
+ ---
166
+
167
+ ## Criando um tipo de campo customizado
168
+
169
+ > ⚠️ **ATENÇÃO: uso pouco frequente.** Criar um tipo custom do zero é trabalhoso e só deve ser feito quando não existe nenhum tipo nativo que atenda à necessidade e nenhuma lib externa com provider já disponível. **Antes de criar, pergunte ao usuário:**
170
+ >
171
+ > 1. Já existe algum tipo custom implementado no projeto (ex: em `optional-fields/` ou equivalente)?
172
+ > 2. Existe alguma biblioteca/pacote que o projeto já usa que fornece um provider pronto para o DynamicForm?
173
+
174
+ ### Passo 1 — Criar a interface de configuração e o provider
175
+
176
+ Crie um arquivo `<nome>-field.ts` no diretório do seu campo customizado.
177
+ A interface deve estender `FieldConfig`, fazer o module augmentation registrando o novo tipo em `FieldTypeMap`, e exportar uma função `provide<Nome>Field()` que registra o componente no `DynamicFormRegistry`.
178
+
179
+ ```typescript
180
+ // my-custom-field.ts
181
+ import { APP_INITIALIZER, EnvironmentProviders, makeEnvironmentProviders } from '@angular/core';
182
+ import { FieldConfig, DynamicFormRegistry } from '@seniorsistemas/angular-components/dynamic-form';
183
+ import { MyCustomFieldComponent } from './my-custom-field/my-custom-field.component';
184
+
185
+ /** Configuração do campo customizado. */
186
+ export interface MyCustomFieldConfig extends FieldConfig {
187
+ type: 'myCustom';
188
+ // adicione aqui as propriedades específicas do seu campo
189
+ someOption?: string;
190
+ }
191
+
192
+ // Augmentation: registra o novo tipo no mapa do DynamicForm
193
+ declare module '@seniorsistemas/angular-components/dynamic-form' {
194
+ export interface FieldTypeMap {
195
+ myCustom: MyCustomFieldConfig;
196
+ }
197
+ }
198
+
199
+ /** Registra o componente do campo customizado no DynamicForm. */
200
+ export function provideMyCustomField(): EnvironmentProviders {
201
+ return makeEnvironmentProviders([
202
+ {
203
+ provide: APP_INITIALIZER,
204
+ useFactory: () => () => {
205
+ DynamicFormRegistry.registerField(MyCustomFieldComponent, 'myCustom');
206
+ },
207
+ multi: true,
208
+ },
209
+ ]);
210
+ }
211
+ ```
212
+
213
+ ### Passo 2 — Criar o componente Angular
214
+
215
+ Crie um componente standalone que implementa `BaseFieldComponentConfig`.
216
+ Requisitos obrigatórios:
217
+
218
+ - Ser `standalone: true`
219
+ - Implementar `BaseFieldComponentConfig`
220
+ - Ter o `input` de `field` (tipado com a interface criada no passo 1)
221
+ - Ter o `input` de `formControl` (necessário quando o campo modifica o `FormGroup`, que é quase sempre)
222
+ - Importar e **renderizar `FieldLabelComponent` como primeira tag no template** — responsável por exibir o label, tooltip e infoSign do campo
223
+
224
+ ```typescript
225
+ // my-custom-field/my-custom-field.component.ts
226
+ import { Component, input } from '@angular/core';
227
+ import { FormControl, ReactiveFormsModule } from '@angular/forms';
228
+ import { BaseFieldComponentConfig, FieldLabelComponent } from '@seniorsistemas/angular-components/dynamic-form';
229
+ import { MyCustomFieldConfig } from '../my-custom-field';
230
+
231
+ @Component({
232
+ standalone: true,
233
+ imports: [ReactiveFormsModule, FieldLabelComponent /* + outros imports necessários */],
234
+ templateUrl: './my-custom-field.component.html',
235
+ })
236
+ export class MyCustomFieldComponent implements BaseFieldComponentConfig {
237
+ /** Config do campo injetada pelo DynamicForm. */
238
+ field = input.required<MyCustomFieldConfig>();
239
+
240
+ /** FormControl associado ao campo no FormGroup pai. */
241
+ formControl = input.required<FormControl>();
242
+ }
243
+ ```
244
+
245
+ ```html
246
+ <!-- my-custom-field/my-custom-field.component.html -->
247
+ @let _field = field();
248
+
249
+ <!-- OBRIGATÓRIO: sempre a primeira tag do template -->
250
+ <s-field-label [field]="_field"></s-field-label>
251
+
252
+ <!-- Implemente aqui o input/controle visual do campo -->
253
+ <input
254
+ [formControl]="formControl()"
255
+ [placeholder]="_field.placeholder ?? ''"
256
+ />
257
+ ```
258
+
259
+ ### Passo 3 — Registrar o provider no AppConfig ou AppModule
260
+
261
+ O provider gerado no Passo 1 deve ser adicionado ao `providers` do `app.config.ts` (projetos standalone) ou ao `providers` do `AppModule` (projetos com módulos).
262
+
263
+ ```typescript
264
+ // app.config.ts (projetos standalone)
265
+ import { provideMyCustomField } from './my-custom-field/my-custom-field';
266
+
267
+ export const appConfig: ApplicationConfig = {
268
+ providers: [
269
+ // ... outros providers
270
+ provideMyCustomField(),
271
+ ],
272
+ };
273
+ ```
274
+
275
+ Após registrar o provider, o tipo `'myCustom'` estará disponível na configuração do DynamicForm:
276
+
277
+ ```typescript
278
+ configs: DynamicStructure[] = [
279
+ {
280
+ type: 'section',
281
+ configs: [
282
+ {
283
+ type: 'row',
284
+ fields: [
285
+ { type: 'myCustom', name: 'meuCampo', label: 'Meu Campo', someOption: 'valor' }
286
+ ]
287
+ }
288
+ ]
289
+ }
290
+ ];
291
+ ```
292
+
@@ -0,0 +1,4 @@
1
+ {
2
+ "components": ["dialog", "confirm-dialog", "toast", "sidebar", "loading-state", "dynamic-form", "kanban", "table"]
3
+ }
4
+
@@ -0,0 +1,116 @@
1
+ # Kanban — Guia Técnico
2
+
3
+ **Seletor:** `s-kanban`
4
+ **Package:** `@seniorsistemas/angular-components/kanban`
5
+
6
+ ## Exports e Imports
7
+
8
+ | Tipo | Símbolo |
9
+ | --------- | ---------------------------------------------------------------------------------------- |
10
+ | Component | `KanbanComponent` |
11
+ | Module | `KanbanModule` |
12
+ | Types | `KanbanData`, `KanbanColumn`, `KanbanItem`, `KanbanItemMovedData`, `KanbanTemplateTypes` |
13
+
14
+ ```typescript
15
+ import { KanbanComponent } from '@seniorsistemas/angular-components/kanban';
16
+ import { KanbanModule } from '@seniorsistemas/angular-components/kanban';
17
+ import type { KanbanData, KanbanColumn, KanbanItem } from '@seniorsistemas/angular-components/kanban';
18
+ ```
19
+
20
+ ---
21
+
22
+ ## Estruturas de dados
23
+
24
+ ### `KanbanData`
25
+
26
+ Estrutura raiz passada ao input `[data]` do componente. Contém um array de colunas.
27
+
28
+ ```typescript
29
+ const data: KanbanData = {
30
+ columns: [
31
+ { id: 'todo', title: 'A Fazer', items: [] },
32
+ { id: 'doing', title: 'Em Progresso', items: [] },
33
+ { id: 'done', title: 'Concluído', items: [] },
34
+ ],
35
+ };
36
+ ```
37
+
38
+ ### `KanbanColumn`
39
+
40
+ | Propriedade | Tipo | Obrigatório | Descrição |
41
+ | ----------- | ---------------------- | ----------- | ------------------------------------- |
42
+ | `id` | `string` | Não | Identificador único da coluna |
43
+ | `title` | `string` | Sim | Título exibido no cabeçalho da coluna |
44
+ | `items` | `KanbanItem[]` | Sim | Array de itens dentro da coluna |
45
+ | `options` | `KanbanColumnOption[]` | Não | Menu de opções da coluna |
46
+
47
+ ### `KanbanItem`
48
+
49
+ | Propriedade | Tipo | Obrigatório | Descrição |
50
+ | ----------- | -------------------- | ----------- | ------------------------------------------------------------------------------ |
51
+ | `data` | `any` | Sim | Dados customizados do item (acessados via `item.data.propriedade` no template) |
52
+ | `options` | `KanbanItemOption[]` | Não | Menu de opções do item |
53
+ | `disabled` | `boolean` | Não | Quando `true`, o item não pode ser arrastado |
54
+ | `frozen` | `boolean` | Não | Quando `true`, o item fica fixo no topo da coluna |
55
+
56
+ > O template do item acessa os dados via `item.data.propriedade` — ex: `{{ item.data.title }}`
57
+
58
+ ---
59
+
60
+ ## Templates (`KanbanTemplateTypes`)
61
+
62
+ O Kanban aceita **exatamente 5 tipos de template**, identificados pelo atributo `sTemplate`. Qualquer outro valor é silenciosamente ignorado.
63
+
64
+ | Tipo | Onde é renderizado |
65
+ | ---------------------- | ----------------------------------- |
66
+ | `column-header` | Cabeçalho de cada coluna |
67
+ | `column-empty-message` | Corpo da coluna quando não há itens |
68
+ | `item-header` | Cabeçalho do card (item) |
69
+ | `item-body` | Corpo do card (item) |
70
+ | `item-footer` | Rodapé do card (item) |
71
+
72
+ ### Exemplo de uso
73
+
74
+ ```html
75
+ <s-kanban [data]="kanbanData">
76
+ <!-- Cabeçalho customizado da coluna -->
77
+ <ng-template
78
+ sTemplate="column-header"
79
+ let-column
80
+ >
81
+ <strong>{{ column.title }}</strong>
82
+ </ng-template>
83
+
84
+ <!-- Mensagem quando a coluna está vazia -->
85
+ <ng-template sTemplate="column-empty-message">
86
+ <span>Nenhum item nesta coluna</span>
87
+ </ng-template>
88
+
89
+ <!-- Cabeçalho do card -->
90
+ <ng-template
91
+ sTemplate="item-header"
92
+ let-item
93
+ >
94
+ <span>{{ item.data.title }}</span>
95
+ </ng-template>
96
+
97
+ <!-- Corpo do card -->
98
+ <ng-template
99
+ sTemplate="item-body"
100
+ let-item
101
+ >
102
+ <p>{{ item.data.description }}</p>
103
+ </ng-template>
104
+
105
+ <!-- Rodapé do card -->
106
+ <ng-template
107
+ sTemplate="item-footer"
108
+ let-item
109
+ >
110
+ <small>{{ item.data.status }}</small>
111
+ </ng-template>
112
+ </s-kanban>
113
+ ```
114
+
115
+ > **ATENÇÃO:** Use **apenas** os 5 tipos listados acima como valor de `sTemplate`. Valores fora deste conjunto (`KanbanTemplateTypes`) são ignorados sem erro — o template simplesmente não será renderizado.
116
+
@@ -0,0 +1,96 @@
1
+ # LoadingState — Guia Técnico
2
+
3
+ **Seletor:** `s-loading-state` / `[sLoadingState]`
4
+ **Package:** `@seniorsistemas/angular-components/loading-state`
5
+
6
+ O LoadingState pode ser usado de duas formas: como **componente wrapper** que envolve o conteúdo a ser bloqueado, ou como **diretiva estrutural** `[sLoadingState]` aplicada diretamente a um elemento existente.
7
+
8
+ ---
9
+
10
+ ## Padrão 1: Como componente wrapper ✅ PREFERIDO
11
+
12
+ Envolve o conteúdo que deve ser bloqueado durante o carregamento. Quando `loading` é `true`, exibe o indicador animado sobre o conteúdo projetado.
13
+
14
+ ### Exemplo
15
+
16
+ ```typescript
17
+ import { LoadingStateModule } from '@seniorsistemas/angular-components/loading-state';
18
+
19
+ @Component({
20
+ imports: [LoadingStateModule],
21
+ template: `
22
+ <s-loading-state [loading]="isLoading">
23
+ <s-card>
24
+ <!-- conteúdo que será bloqueado durante o carregamento -->
25
+ <p>{{ data }}</p>
26
+ </s-card>
27
+ </s-loading-state>
28
+ `
29
+ })
30
+ export class MyComponent {
31
+ protected isLoading = false;
32
+ protected data = '';
33
+
34
+ protected async loadData(): Promise<void> {
35
+ this.isLoading = true;
36
+ try {
37
+ this.data = await this.api.fetchData();
38
+ } finally {
39
+ this.isLoading = false; // SEMPRE usar finally para garantir reset
40
+ }
41
+ }
42
+ }
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Padrão 2: Como diretiva estrutural `[sLoadingState]`
48
+
49
+ Aplica o comportamento de loading diretamente a um elemento existente sem adicionar um elemento DOM extra ao layout.
50
+
51
+ ### Exemplo
52
+
53
+ ```typescript
54
+ import { LoadingStateModule } from '@seniorsistemas/angular-components/loading-state';
55
+
56
+ @Component({
57
+ imports: [LoadingStateModule],
58
+ template: `
59
+ <div [sLoadingState]="isLoading">
60
+ <p>{{ data }}</p>
61
+ </div>
62
+ `
63
+ })
64
+ export class MyComponent {
65
+ protected isLoading = false;
66
+ protected data = '';
67
+ }
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Padrão 3: Bloqueio de tela inteira
73
+
74
+ Bloqueia a tela inteira durante operações globais.
75
+
76
+ ### Exemplo
77
+
78
+ ```typescript
79
+ @Component({
80
+ imports: [LoadingStateModule],
81
+ template: `
82
+ <s-loading-state [loading]="isLoading" [blockWindow]="true">
83
+ <router-outlet />
84
+ </s-loading-state>
85
+ `
86
+ })
87
+ export class AppComponent {
88
+ protected isLoading = false;
89
+ }
90
+ ```
91
+
92
+ ---
93
+
94
+ ## Notas de integração
95
+
96
+ - **Sempre use `finally`** ao resetar `isLoading` para garantir que o loading seja removido mesmo em caso de erro.
@@ -0,0 +1,82 @@
1
+ # Sidebar — Guia Técnico
2
+
3
+ **Seletor:** `s-sidebar`
4
+ **Package:** `@seniorsistemas/angular-components/sidebar`
5
+
6
+ O Sidebar é controlado via binding bidirecional `[(visible)]`. Suporta templates customizáveis para cabeçalho, corpo e rodapé, bloqueio de scroll automático e confirmação antes de fechar.
7
+
8
+ ---
9
+
10
+ ## Padrão 1: Declarativo via `[(visible)]` ✅ PREFERIDO
11
+
12
+ Controla a abertura e fechamento do sidebar via two-way binding da propriedade `visible`.
13
+
14
+ ### Exemplo
15
+
16
+ ```typescript
17
+ import { SidebarModule } from '@seniorsistemas/angular-components/sidebar';
18
+
19
+ @Component({
20
+ imports: [SidebarModule],
21
+ template: `
22
+ <s-button label="Abrir painel" (clicked)="isOpen = true" />
23
+
24
+ <s-sidebar [(visible)]="isOpen" header="Detalhes">
25
+ <ng-template sTemplate="body">
26
+ <!-- conteúdo do painel -->
27
+ </ng-template>
28
+ <ng-template sTemplate="footer">
29
+ <s-button label="Fechar" (clicked)="isOpen = false" />
30
+ <s-button label="Salvar" priority="primary" (clicked)="save()" />
31
+ </ng-template>
32
+ </s-sidebar>
33
+ `
34
+ })
35
+ export class MyComponent {
36
+ protected isOpen = false;
37
+
38
+ protected save(): void {
39
+ // lógica de salvamento
40
+ this.isOpen = false;
41
+ }
42
+ }
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Padrão 2: Com confirmação de fechamento
48
+
49
+ Usa a propriedade `closeConfirmation` para exibir um dialog de confirmação antes de fechar o sidebar, evitando perda de dados não salvos.
50
+
51
+ ### Exemplo
52
+
53
+ ```typescript
54
+ import { SidebarModule } from '@seniorsistemas/angular-components/sidebar';
55
+
56
+ @Component({
57
+ imports: [SidebarModule],
58
+ template: `
59
+ <s-sidebar
60
+ [(visible)]="isOpen"
61
+ header="Editar registro"
62
+ [closeConfirmation]="formDirty"
63
+ closeConfirmationMessage="Existem alterações não salvas. Deseja sair mesmo assim?"
64
+ >
65
+ <ng-template sTemplate="body">
66
+ <!-- formulário -->
67
+ </ng-template>
68
+ </s-sidebar>
69
+ `
70
+ })
71
+ export class MyComponent {
72
+ protected isOpen = false;
73
+ protected formDirty = false;
74
+ }
75
+ ```
76
+
77
+ ---
78
+
79
+ ## Notas de integração
80
+
81
+ - Use `sTemplate` com os valores `'header'`, `'body'` e `'footer'` para projetar conteúdo em cada seção.
82
+ - Para formulários no sidebar, sempre considere usar `closeConfirmation` quando o formulário estiver sujo (`dirty`).
@@ -0,0 +1,19 @@
1
+ # Table — Guia Técnico
2
+
3
+ **Seletor:** `s-table` / `s-table-columns` / `s-table-paging`
4
+ **Package:** `@seniorsistemas/angular-components/table`
5
+
6
+ ## Exports e Imports
7
+
8
+ | Tipo | Símbolo |
9
+ | ---------- | ---------------------------------------------------------------------------------------------------------------------- |
10
+ | Components | `TableColumnsComponent`, `TablePagingComponent` |
11
+ | Module | `TableModule` |
12
+ | Directives | `NavigationDirective`, `RowTogllerDirective` |
13
+ | Types | `Column`, `BadgeConfigs`, `BadgeColumn`, `ColumnValues`, `DynamicEditableGrid`, `LocaleOptions`, `NumberLocaleOptions` |
14
+
15
+ ```typescript
16
+ import { TableModule } from '@seniorsistemas/angular-components/table';
17
+ import type { Column } from '@seniorsistemas/angular-components/table';
18
+ ```
19
+
@@ -0,0 +1,63 @@
1
+ # Toast — Guia Técnico
2
+
3
+ **Seletor:** `s-toast`
4
+ **Package:** `@seniorsistemas/angular-components/toast`
5
+
6
+ Toasts são **SEMPRE** exibidos via `ToastService`. O componente `s-toast` individual **não deve ser instanciado manualmente** para exibir notificações — o serviço gerencia a criação, empilhamento e remoção automaticamente.
7
+
8
+ ---
9
+
10
+ ## Padrão único: Via `ToastService` ✅ PADRÃO RECOMENDADO
11
+
12
+ Exibe notificações temporárias na tela injetando `ToastService` de qualquer componente ou serviço.
13
+
14
+ ### Exemplo
15
+
16
+ ```typescript
17
+ import { ToastModule, ToastService } from '@seniorsistemas/angular-components/toast';
18
+
19
+ // No componente raiz (AppComponent ou layout principal)
20
+ // O <s-toast> deve existir UMA VEZ na aplicação, no nível mais alto
21
+ @Component({
22
+ imports: [ToastModule],
23
+ template: `
24
+ <s-toast />
25
+ <router-outlet />
26
+ `,
27
+ })
28
+ export class AppComponent {}
29
+
30
+ // Em qualquer componente ou serviço
31
+ @Injectable({ providedIn: 'root' })
32
+ export class MyService {
33
+ private readonly toast = inject(ToastService);
34
+
35
+ async save(data: unknown): Promise<void> {
36
+ try {
37
+ await this.api.save(data);
38
+ this.toast.success('Registro salvo com sucesso!');
39
+ } catch {
40
+ this.toast.error('Falha ao salvar. Tente novamente.');
41
+ }
42
+ }
43
+ }
44
+ ```
45
+
46
+ ---
47
+
48
+ ## Métodos disponíveis no `ToastService`
49
+
50
+ | Método | Uso |
51
+ | -------------------- | ---------------------------------- |
52
+ | `toast.success(msg)` | Operação concluída com sucesso |
53
+ | `toast.error(msg)` | Falha ou erro |
54
+ | `toast.warning(msg)` | Aviso, situação que merece atenção |
55
+ | `toast.info(msg)` | Informação neutra |
56
+
57
+ ---
58
+
59
+ ## Notas de integração
60
+
61
+ - O componente `<s-toast>` deve estar presente no template do componente raiz (`AppComponent`) para que os toasts sejam exibidos na aplicação.
62
+ - Por padrão os toasts são removidos automaticamente após alguns segundos. Use `sticky: true` para manter o toast até o usuário fechar manualmente.
63
+