@seniorsistemas/angular-components 19.3.3 → 19.3.4

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 (76) hide show
  1. package/accordion/README.md +166 -0
  2. package/alert/README.md +92 -0
  3. package/autocomplete/README.md +162 -0
  4. package/badge/README.md +126 -0
  5. package/bignumber-input/README.md +122 -0
  6. package/breadcrumb/README.md +144 -0
  7. package/button/README.md +159 -0
  8. package/calendar-mask/README.md +89 -0
  9. package/card/README.md +133 -0
  10. package/chat/README.md +130 -0
  11. package/checkbox/README.md +108 -0
  12. package/checkbox-list/README.md +149 -0
  13. package/chips/README.md +152 -0
  14. package/code-editor/README.md +149 -0
  15. package/collapse-link/README.md +128 -0
  16. package/confirm-dialog/README.md +105 -0
  17. package/content-generator/README.md +111 -0
  18. package/control-errors/README.md +92 -0
  19. package/country-phone-picker/README.md +121 -0
  20. package/currency/README.md +90 -0
  21. package/custom-fields/README.md +142 -0
  22. package/dialog/README.md +152 -0
  23. package/dynamic-form/README.md +176 -0
  24. package/editable-overlay/README.md +98 -0
  25. package/empty-state/README.md +134 -0
  26. package/esm2022/loading-state/lib/loading-state/loading-state.component.mjs +4 -4
  27. package/fesm2022/seniorsistemas-angular-components-loading-state.mjs +3 -3
  28. package/fesm2022/seniorsistemas-angular-components-loading-state.mjs.map +1 -1
  29. package/fieldset/README.md +135 -0
  30. package/file-picker/README.md +162 -0
  31. package/file-upload/README.md +23 -7
  32. package/gantt/README.md +173 -0
  33. package/global-search/README.md +151 -0
  34. package/grid-menu/README.md +123 -0
  35. package/help-popover/README.md +134 -0
  36. package/ia-insight/README.md +24 -6
  37. package/image-cropper/README.md +140 -0
  38. package/infinite-scroll/README.md +130 -0
  39. package/info-sign/README.md +111 -0
  40. package/inline-edit/README.md +139 -0
  41. package/insights/README.md +159 -0
  42. package/interactive-content/README.md +120 -0
  43. package/kanban/README.md +184 -0
  44. package/label-value/README.md +154 -0
  45. package/loading-state/README.md +141 -0
  46. package/localized-number-input/README.md +128 -0
  47. package/mouse-events/README.md +157 -0
  48. package/navigation-button/README.md +160 -0
  49. package/numeric/README.md +147 -0
  50. package/numeric-mask/README.md +170 -0
  51. package/object-card/README.md +158 -0
  52. package/package.json +1 -1
  53. package/paginator/README.md +121 -0
  54. package/panel/README.md +147 -0
  55. package/password-strength/README.md +144 -0
  56. package/picklist/README.md +170 -0
  57. package/pin-code-field/README.md +137 -0
  58. package/product-header/README.md +33 -6
  59. package/profile-picture-picker/README.md +159 -0
  60. package/progressbar/README.md +136 -0
  61. package/radio-button/README.md +117 -0
  62. package/rating-scale/README.md +154 -0
  63. package/select/README.md +147 -0
  64. package/select-button/README.md +137 -0
  65. package/sidebar/README.md +117 -0
  66. package/slide-in-bar/README.md +122 -0
  67. package/slider/README.md +127 -0
  68. package/speech-recognition/README.md +104 -0
  69. package/split-button/README.md +126 -0
  70. package/spotlight/README.md +200 -0
  71. package/star-rating/README.md +127 -0
  72. package/stats-card/README.md +135 -0
  73. package/stepper/README.md +164 -0
  74. package/switch/README.md +125 -0
  75. package/table/README.md +185 -0
  76. package/text-area-ia/README.md +17 -6
@@ -0,0 +1,130 @@
1
+ # InfiniteScroll
2
+
3
+ ![Status](https://img.shields.io/badge/status-stable-brightgreen)
4
+
5
+ Diretiva de scroll infinito que detecta quando o usuário chega ao final de um elemento com scroll e emite o evento `scrolled`. Deve ser aplicada a um elemento com `overflow` e scroll habilitado.
6
+
7
+ ## Quando usar
8
+
9
+ - Listas longas carregadas de API com paginação progressiva
10
+ - Feeds de conteúdo (notícias, posts, cards) com carregamento sob demanda
11
+ - Tabelas ou listas com muitos registros onde a paginação clássica é indesejada
12
+
13
+ ## Quando não usar
14
+
15
+ - Listas curtas onde todos os itens podem ser carregados de uma vez — carregue tudo e exiba diretamente
16
+ - Quando o usuário precisa navegar para uma página específica — prefira paginação com controles numéricos
17
+
18
+ ## Instalação
19
+
20
+ ```typescript
21
+ import { InfiniteScrollModule } from '@seniorsistemas/angular-components/infinite-scroll';
22
+
23
+ @NgModule({
24
+ imports: [InfiniteScrollModule],
25
+ })
26
+ export class MeuModule {}
27
+ ```
28
+
29
+ ## Uso básico
30
+
31
+ ```html
32
+ <div
33
+ sInfiniteScroll
34
+ (scrolled)="carregarMais()"
35
+ style="overflow-y: auto; height: 400px;"
36
+ >
37
+ <!-- itens da lista -->
38
+ </div>
39
+ ```
40
+
41
+ ## API
42
+
43
+ ### Inputs
44
+
45
+ Esta diretiva não possui inputs configuráveis.
46
+
47
+ ### Outputs
48
+
49
+ | Evento | Tipo | Descrição |
50
+ |--------|------|-----------|
51
+ | `scrolled` | `EventEmitter<number>` | Emitido quando o usuário atinge o final do elemento com scroll. |
52
+
53
+ ## Exemplos
54
+
55
+ ### Lista com carregamento progressivo
56
+
57
+ ```html
58
+ <div
59
+ sInfiniteScroll
60
+ (scrolled)="carregarMais()"
61
+ style="height: 300px; overflow-y: auto;"
62
+ >
63
+ @for (item of itens; track item.id) {
64
+ <div>{{ item.nome }}</div>
65
+ }
66
+ @if (carregando) {
67
+ <div>Carregando...</div>
68
+ }
69
+ </div>
70
+ ```
71
+
72
+ ```typescript
73
+ carregarMais() {
74
+ if (this.carregando) return;
75
+ this.carregando = true;
76
+ this.api.buscarItens(this.pagina++).subscribe(novosItens => {
77
+ this.itens = [...this.itens, ...novosItens];
78
+ this.carregando = false;
79
+ });
80
+ }
81
+ ```
82
+
83
+ ### Com indicador de fim de lista
84
+
85
+ ```html
86
+ <div sInfiniteScroll (scrolled)="carregarMais()" style="height: 300px; overflow-y: auto;">
87
+ @for (item of itens; track item) {
88
+ <div>{{ item }}</div>
89
+ }
90
+ @if (carregando) {
91
+ <div>Carregando...</div>
92
+ }
93
+ @if (!temMais && !carregando) {
94
+ <div>Todos os registros foram carregados.</div>
95
+ }
96
+ </div>
97
+ ```
98
+
99
+ ### Com debounce no callback (recomendado para APIs)
100
+
101
+ ```typescript
102
+ import { Subject } from 'rxjs';
103
+ import { debounceTime } from 'rxjs/operators';
104
+
105
+ private scroll$ = new Subject<void>();
106
+
107
+ ngOnInit() {
108
+ this.scroll$.pipe(debounceTime(300)).subscribe(() => this.buscarProximaPagina());
109
+ }
110
+
111
+ onScrolled() {
112
+ this.scroll$.next();
113
+ }
114
+ ```
115
+
116
+ ```html
117
+ <div sInfiniteScroll (scrolled)="onScrolled()" style="height: 400px; overflow-y: auto;">
118
+ <!-- itens -->
119
+ </div>
120
+ ```
121
+
122
+ ## Acessibilidade
123
+
124
+ - O elemento hospedeiro deve ter altura definida e `overflow-y: auto` ou `overflow-y: scroll`
125
+ - A diretiva não possui debounce interno — implemente no callback quando necessário para evitar múltiplas requisições simultâneas
126
+ - O evento `scrolled` é disparado quando `scrollTop > scrollHeight - offsetHeight - 2`
127
+
128
+ ## Componentes relacionados
129
+
130
+ - [`LoadingState`](../loading-state/README.md) — indicador de carregamento a ser exibido durante o scroll
@@ -0,0 +1,111 @@
1
+ # InfoSign
2
+
3
+ ![Status](https://img.shields.io/badge/status-stable-brightgreen)
4
+
5
+ Diretiva estrutural que exibe um ícone de informação (ⓘ) ao lado do elemento hospedeiro. Ao interagir com o ícone, um tooltip com a mensagem configurada é exibido temporariamente.
6
+
7
+ ## Quando usar
8
+
9
+ - Labels de campos de formulário com regras de preenchimento específicas (CPF, CNPJ, CEP)
10
+ - Títulos de seções que necessitam de explicação adicional
11
+ - Qualquer elemento de texto que precise de contexto sem sobrecarregar o layout
12
+
13
+ ## Quando não usar
14
+
15
+ - Quando a informação é crítica e deve estar sempre visível — use texto de ajuda abaixo do campo
16
+ - Para ações com conteúdo rico (listas, links, templates) — prefira [`HelpPopover`](../help-popover/README.md)
17
+
18
+ ## Instalação
19
+
20
+ ```typescript
21
+ import { InfoSignModule } from '@seniorsistemas/angular-components/info-sign';
22
+
23
+ @NgModule({
24
+ imports: [InfoSignModule],
25
+ })
26
+ export class MeuModule {}
27
+ ```
28
+
29
+ ## Uso básico
30
+
31
+ Como diretiva estrutural, substitui o elemento hospedeiro por um wrapper com o ícone ⓘ ao lado:
32
+
33
+ ```html
34
+ <label *sInfoSign="'Informe o CPF sem pontos e traços'">CPF</label>
35
+ ```
36
+
37
+ ## API
38
+
39
+ ### Inputs
40
+
41
+ | Propriedade | Sintaxe no template | Tipo | Padrão | Obrigatório | Descrição |
42
+ |-------------|---------------------|------|--------|:-----------:|-----------|
43
+ | `sInfoSign` | `*sInfoSign="'mensagem'"` | `string` | — | Sim | Mensagem exibida no tooltip. Aceita HTML. |
44
+ | `sInfoSignDisplayTime` | `; displayTime: 5000` | `number` | `5000` | Não | Tempo em ms que o tooltip permanece visível após ser exibido. |
45
+ | `sInfoSignFocusedInputRef` | `; focusedInputRef: ref` | `HTMLInputElement \| HTMLElement \| null` | `null` | Não | Referência a um input. O tooltip aparece ao focar o input quando fornecido. |
46
+ | `sInfoSignUseFocusedInputRef` | `; useFocusedInputRef: true` | `boolean` | `true` | Não | Quando `true`, usa `focusedInputRef` para calcular o posicionamento do ícone. |
47
+
48
+ ## Exemplos
49
+
50
+ ### Em um label de formulário
51
+
52
+ ```html
53
+ <div style="display: flex; flex-direction: column; gap: 4px;">
54
+ <label *sInfoSign="'Informe o CPF sem pontos e traços. Apenas números.'">
55
+ CPF
56
+ </label>
57
+ <input type="text" placeholder="000.000.000-00" />
58
+ </div>
59
+ ```
60
+
61
+ ### Com tempo de exibição customizado
62
+
63
+ ```html
64
+ <span *sInfoSign="'Esta mensagem some em 2 segundos.'; displayTime: 2000">
65
+ Passe o mouse no ícone
66
+ </span>
67
+ ```
68
+
69
+ ### Com conteúdo HTML no tooltip
70
+
71
+ ```html
72
+ <label *sInfoSign="'<strong>Requisitos:</strong><br>• Mínimo 8 caracteres<br>• Letras e números'; displayTime: 8000">
73
+ Senha
74
+ </label>
75
+ ```
76
+
77
+ ### Com referência a um input (tooltip ao focar)
78
+
79
+ ```html
80
+ <label *sInfoSign="'Dica do campo'; focusedInputRef: meuInput">
81
+ Campo com foco
82
+ </label>
83
+ <input #meuInput type="text" />
84
+ ```
85
+
86
+ ### Em múltiplos campos de formulário
87
+
88
+ ```html
89
+ <div style="display: flex; flex-direction: column; gap: 16px;">
90
+ <div>
91
+ <label *sInfoSign="'Informe o CPF sem pontos e traços.'">CPF</label>
92
+ <input type="text" placeholder="000.000.000-00" />
93
+ </div>
94
+ <div>
95
+ <label *sInfoSign="'Data no formato DD/MM/AAAA.'">Data de nascimento</label>
96
+ <input type="text" placeholder="DD/MM/AAAA" />
97
+ </div>
98
+ </div>
99
+ ```
100
+
101
+ ## Acessibilidade
102
+
103
+ - É uma diretiva estrutural — o elemento hospedeiro é envolvido por um wrapper com o ícone ao lado
104
+ - O tooltip aparece ao passar o mouse sobre o ícone (padrão) ou ao focar o input referenciado
105
+ - O tooltip some automaticamente após `displayTime` ms (padrão: 5000ms)
106
+ - Aceita HTML no conteúdo do tooltip para mensagens formatadas
107
+
108
+ ## Componentes relacionados
109
+
110
+ - [`HelpPopover`](../help-popover/README.md) — popover de ajuda com mais opções de conteúdo (header, footer, template)
111
+ - [`Tooltip`](../tooltip/README.md) — tooltip standalone aplicado diretamente em qualquer elemento
@@ -0,0 +1,139 @@
1
+ # InlineEdit
2
+
3
+ ![Status](https://img.shields.io/badge/status-stable-brightgreen)
4
+
5
+ Componente de edição inline que renderiza dinamicamente campos editáveis a partir de uma lista de configurações. Cada campo exibe o valor atual e permite edição ao clicar, integrando-se a um `FormGroup` Angular.
6
+
7
+ ## Quando usar
8
+
9
+ - Formulários de detalhes onde o usuário edita campos individualmente sem abrir modal
10
+ - Telas de visualização com edição rápida diretamente no contexto
11
+ - Painéis de configuração onde poucos campos precisam ser editados por vez
12
+
13
+ ## Quando não usar
14
+
15
+ - Formulários completos com muitos campos obrigatórios simultâneos — use um formulário convencional
16
+ - Quando todos os campos são editados ao mesmo tempo — prefira Dynamic Form
17
+
18
+ ## Instalação
19
+
20
+ ```typescript
21
+ import { InlineEditModule } from '@seniorsistemas/angular-components/inline-edit';
22
+
23
+ @NgModule({
24
+ imports: [InlineEditModule],
25
+ })
26
+ export class MeuModule {}
27
+ ```
28
+
29
+ ## Uso básico
30
+
31
+ ```html
32
+ <s-inline-edit [formGroup]="form" [fields]="campos" />
33
+ ```
34
+
35
+ ## API
36
+
37
+ ### Inputs
38
+
39
+ | Propriedade | Tipo | Padrão | Obrigatório | Descrição |
40
+ |-------------|------|--------|:-----------:|-----------|
41
+ | `formGroup` | `FormGroup` | `new FormGroup({})` | Não | `FormGroup` Angular ao qual os campos inline serão vinculados. |
42
+ | `fields` | `InlineEditField[]` | `[]` | Não | Lista de configurações dos campos inline a serem renderizados. |
43
+ | `errorMessages` | `any` | `undefined` | Não | Mapa de mensagens de erro customizadas por nome de validador. |
44
+
45
+ ### Tipos
46
+
47
+ ```typescript
48
+ // Classe base — todos os tipos de campo estendem InlineEditField
49
+ abstract class InlineEditField {
50
+ label: string; // Rótulo exibido ao lado do campo
51
+ name: string; // Nome do FormControl correspondente no FormGroup
52
+ tooltip?: string; // Tooltip exibido ao passar o mouse sobre o rótulo
53
+ errorMessages?: {} | (() => {}); // Mensagens de erro customizadas
54
+ }
55
+
56
+ // Tipos de campo disponíveis:
57
+ class InlineEditTextField extends InlineEditField {} // Campo de texto simples
58
+ class InlineEditNumberField extends InlineEditField {} // Campo numérico
59
+ class InlineEditTextAreaField extends InlineEditField {} // Área de texto multilinha
60
+ class InlineEditCalendarField extends InlineEditField {} // Seletor de data
61
+ class InlineEditLookupField extends InlineEditField {} // Campo de busca avançada
62
+ class InlineEditContentGeneratorField extends InlineEditField {} // Gerador de conteúdo com IA
63
+ ```
64
+
65
+ ## Exemplos
66
+
67
+ ### Campos de texto, número e área de texto
68
+
69
+ ```typescript
70
+ import {
71
+ InlineEditTextField,
72
+ InlineEditNumberField,
73
+ InlineEditTextAreaField,
74
+ } from '@seniorsistemas/angular-components/inline-edit';
75
+
76
+ @Component({ ... })
77
+ export class MeuComponent implements OnInit {
78
+ form!: FormGroup;
79
+ campos: InlineEditField[] = [];
80
+
81
+ ngOnInit() {
82
+ this.form = new FormGroup({
83
+ nome: new FormControl('João Silva'),
84
+ valor: new FormControl(1500),
85
+ observacao: new FormControl('Observação inicial'),
86
+ });
87
+
88
+ this.campos = [
89
+ new InlineEditTextField({ name: 'nome', label: 'Nome', tooltip: 'Nome completo' }),
90
+ new InlineEditNumberField({ name: 'valor', label: 'Valor', tooltip: 'Valor numérico' }),
91
+ new InlineEditTextAreaField({ name: 'observacao', label: 'Observação' }),
92
+ ];
93
+ }
94
+ }
95
+ ```
96
+
97
+ ```html
98
+ <s-inline-edit [formGroup]="form" [fields]="campos"></s-inline-edit>
99
+ ```
100
+
101
+ ### Com campo de data
102
+
103
+ ```typescript
104
+ import { InlineEditCalendarField } from '@seniorsistemas/angular-components/inline-edit';
105
+
106
+ this.form = new FormGroup({
107
+ dataAdmissao: new FormControl(new Date()),
108
+ });
109
+
110
+ this.campos = [
111
+ new InlineEditCalendarField({ name: 'dataAdmissao', label: 'Data de admissão' }),
112
+ ];
113
+ ```
114
+
115
+ ### Com mensagens de erro customizadas
116
+
117
+ ```typescript
118
+ this.campos = [
119
+ new InlineEditTextField({
120
+ name: 'email',
121
+ label: 'E-mail',
122
+ errorMessages: {
123
+ required: 'O e-mail é obrigatório.',
124
+ email: 'Informe um e-mail válido.',
125
+ },
126
+ }),
127
+ ];
128
+ ```
129
+
130
+ ## Acessibilidade
131
+
132
+ - Cada campo exibe seu rótulo (`label`) visualmente associado ao controle
133
+ - O `tooltip` opcional fornece contexto adicional ao passar o mouse
134
+ - A edição é ativada por clique e confirmada com Enter ou clique fora do campo
135
+ - Mensagens de validação são exibidas abaixo do campo em caso de erro
136
+
137
+ ## Componentes relacionados
138
+
139
+ - [`DynamicForm`](../dynamic-form/README.md) — formulário dinâmico completo com todos os campos habilitados simultaneamente
@@ -0,0 +1,159 @@
1
+ # Insights
2
+
3
+ ![Status](https://img.shields.io/badge/status-stable-brightgreen)
4
+
5
+ Componente de painel lateral de insights com IA. Exibe uma lista de itens de insights em um sidebar, com carregamento assíncrono via `Observable`, feedback de like/dislike, cópia e recarregamento. Suporta templates customizáveis para introdução, estado vazio e sem permissão.
6
+
7
+ > **Nota:** O seletor `s-ia-insight` e o pacote `ia-insight` estão descontinuados. Use `s-insights` e o pacote `insights` em novos projetos. O seletor antigo será removido na versão 20.0.0.
8
+
9
+ ## Quando usar
10
+
11
+ - Dashboards que precisam exibir análises geradas por IA em um painel lateral
12
+ - Telas de gestão de RH, financeiro ou operacional com insights contextuais
13
+ - Qualquer interface que precise de análises assíncronas com feedback do usuário
14
+
15
+ ## Quando não usar
16
+
17
+ - Quando os insights são estáticos e não precisam de carregamento assíncrono — use cards simples
18
+ - Quando não há controle de permissão ou o conteúdo é sempre acessível — simplifique o componente
19
+
20
+ ## Instalação
21
+
22
+ ```typescript
23
+ import { InsightsModule } from '@seniorsistemas/angular-components/insights';
24
+
25
+ @NgModule({
26
+ imports: [InsightsModule],
27
+ })
28
+ export class MeuModule {}
29
+ ```
30
+
31
+ ## Uso básico
32
+
33
+ ```html
34
+ <s-insights
35
+ #insightsRef
36
+ [insights]="listaInsights"
37
+ (openInsights)="onAbrir()"
38
+ (closedInsights)="onFechar()"
39
+ ></s-insights>
40
+
41
+ <s-button label="Abrir Insights" (clicked)="insightsRef.open()"></s-button>
42
+ ```
43
+
44
+ ## API
45
+
46
+ ### Inputs
47
+
48
+ | Propriedade | Tipo | Padrão | Obrigatório | Descrição |
49
+ |-------------|------|--------|:-----------:|-----------|
50
+ | `insights` | `InsightsItem[]` | `[]` | Não | Lista de itens de insight a serem exibidos no painel. |
51
+ | `hasPermission` | `boolean` | `true` | Não | Indica se o usuário tem permissão para ver os insights. Quando `false`, exibe o template de sem permissão. |
52
+ | `introText` | `string` | `undefined` | Não | Texto de introdução exibido no topo do painel (quando sem template customizado). |
53
+ | `emptyText` | `string` | `undefined` | Não | Texto exibido quando não há insights disponíveis. |
54
+ | `noPermissionText` | `string` | `undefined` | Não | Texto exibido quando o usuário não tem permissão. |
55
+
56
+ ### Outputs
57
+
58
+ | Evento | Tipo | Descrição |
59
+ |--------|------|-----------|
60
+ | `openInsights` | `OutputEmitterRef<void>` | Emitido quando o painel de insights é aberto. |
61
+ | `closedInsights` | `OutputEmitterRef<void>` | Emitido quando o painel de insights é fechado. |
62
+
63
+ ### Tipos
64
+
65
+ ```typescript
66
+ interface InsightsItem {
67
+ title: string; // Título do insight (obrigatório)
68
+ request$: Observable<string>; // Observable que retorna o texto do insight (obrigatório)
69
+ onLikeSelected?: VoidFunction; // Callback ao clicar em "gostei"
70
+ onDislikeSelected?: VoidFunction; // Callback ao clicar em "não gostei"
71
+ onCopy?: (content: string) => void; // Callback ao copiar o conteúdo
72
+ onReload?: VoidFunction; // Callback ao recarregar o insight
73
+ onOpenSidebar?: VoidFunction; // Callback ao abrir o sidebar
74
+ onCloseSideBar?: VoidFunction; // Callback ao fechar o sidebar
75
+ onContentLoaded?: VoidFunction; // Callback quando o conteúdo é carregado
76
+ }
77
+ ```
78
+
79
+ ## Exemplos
80
+
81
+ ### Insights com múltiplos itens
82
+
83
+ ```typescript
84
+ import { timer } from 'rxjs';
85
+ import { first, switchMap } from 'rxjs/operators';
86
+ import { of } from 'rxjs';
87
+ import { InsightsItem } from '@seniorsistemas/angular-components/insights';
88
+
89
+ insights: InsightsItem[] = [
90
+ {
91
+ title: 'Turnover mensal',
92
+ request$: timer(1000).pipe(first(), switchMap(() =>
93
+ of('O índice de turnover foi de 4,2%, acima da média do setor (2,8%).')
94
+ )),
95
+ onLikeSelected: () => console.log('Gostei'),
96
+ onCopy: (content) => navigator.clipboard.writeText(content),
97
+ },
98
+ ];
99
+ ```
100
+
101
+ ```html
102
+ <s-insights
103
+ #insightsRef
104
+ [insights]="insights"
105
+ [hasPermission]="true"
106
+ introText="Análises geradas por IA com base nos dados do sistema."
107
+ (openInsights)="onAbrir()"
108
+ (closedInsights)="onFechar()"
109
+ ></s-insights>
110
+
111
+ <s-button label="Abrir Insights" priority="primary" (clicked)="insightsRef.open()"></s-button>
112
+ ```
113
+
114
+ ### Sem permissão
115
+
116
+ ```html
117
+ <s-insights
118
+ #insightsRef
119
+ [insights]="insights"
120
+ [hasPermission]="false"
121
+ noPermissionText="Você não tem permissão para visualizar os insights."
122
+ ></s-insights>
123
+ <s-button label="Abrir" (clicked)="insightsRef.open()"></s-button>
124
+ ```
125
+
126
+ ### Com template customizado de introdução
127
+
128
+ ```html
129
+ <s-insights #insightsRef [insights]="insights" [hasPermission]="true">
130
+ <ng-template sTemplate="intro">
131
+ <div style="padding: 12px; background: #eff6ff; border-radius: 6px;">
132
+ <p style="font-weight: 600; color: #1d4ed8;">Análises com IA</p>
133
+ <p>Insights gerados automaticamente com base nos dados do último trimestre.</p>
134
+ </div>
135
+ </ng-template>
136
+ </s-insights>
137
+ <s-button label="Abrir" (clicked)="insightsRef.open()"></s-button>
138
+ ```
139
+
140
+ ### Templates customizáveis
141
+
142
+ Use `sTemplate` para customizar seções do painel:
143
+
144
+ | Valor | Descrição |
145
+ |-------|-----------|
146
+ | `sTemplate="intro"` | Conteúdo de introdução no topo do painel |
147
+ | `sTemplate="empty"` | Exibido quando não há insights disponíveis |
148
+ | `sTemplate="no-permission"` | Exibido quando `hasPermission` é `false` |
149
+
150
+ ## Acessibilidade
151
+
152
+ - O painel é aberto/fechado via métodos `open()` e `close()` na referência do componente (`#ref`)
153
+ - Enquanto o `Observable` não emite, exibe um estado de carregamento animado
154
+ - As ações de like, dislike, cópia e recarregamento estão acessíveis por clique
155
+
156
+ ## Componentes relacionados
157
+
158
+ - [`LoadingState`](../loading-state/README.md) — indicador de carregamento utilizado internamente
159
+ - [`SlideInBar`](../slide-in-bar/README.md) — painel lateral genérico para outros casos de uso
@@ -0,0 +1,120 @@
1
+ # InteractiveContent
2
+
3
+ ![Status](https://img.shields.io/badge/status-stable-brightgreen)
4
+
5
+ Diretiva de acessibilidade que torna qualquer elemento HTML interativo, adicionando suporte a eventos de foco e navegação por teclado (Enter e Espaço) além do clique padrão. Gerencia automaticamente o atributo `tabindex`.
6
+
7
+ ## Quando usar
8
+
9
+ - Tornar elementos não-interativos (`div`, `span`, imagens) acessíveis via teclado
10
+ - Implementar cards clicáveis, itens de lista selecionáveis ou grids interativos
11
+ - Garantir conformidade com WCAG para elementos customizados que simulam botões ou links
12
+
13
+ ## Quando não usar
14
+
15
+ - Elementos que já são naturalmente interativos (`button`, `a`, `input`) — use os elementos nativos
16
+ - Quando apenas o clique de mouse é necessário e a acessibilidade via teclado não é requisito
17
+
18
+ ## Instalação
19
+
20
+ ```typescript
21
+ import { InteractiveContentDirective } from '@seniorsistemas/angular-components/interactive-content';
22
+
23
+ @Component({
24
+ standalone: true,
25
+ imports: [InteractiveContentDirective],
26
+ })
27
+ export class MeuComponent {}
28
+ ```
29
+
30
+ ## Uso básico
31
+
32
+ ```html
33
+ <div (sInteractiveContent)="onAtivar($event)" [focusable]="true">
34
+ Conteúdo clicável e acessível via teclado
35
+ </div>
36
+ ```
37
+
38
+ ## API
39
+
40
+ ### Inputs
41
+
42
+ | Propriedade | Tipo | Padrão | Obrigatório | Descrição |
43
+ |-------------|------|--------|:-----------:|-----------|
44
+ | `focusable` | `boolean` | `true` | Não | Habilita o foco via teclado adicionando `tabindex="0"` ao elemento. |
45
+ | `disabled` | `boolean` | `false` | Não | Desabilita todos os eventos de interação do elemento. |
46
+ | `stopPropagation` | `boolean` | `false` | Não | Quando `true`, chama `event.stopPropagation()` ao ativar o elemento. |
47
+
48
+ ### Outputs
49
+
50
+ | Evento | Tipo | Descrição |
51
+ |--------|------|-----------|
52
+ | `sInteractiveContent` | `OutputEmitterRef<PointerEvent \| KeyboardEvent>` | Emitido quando o usuário clica ou pressiona Enter/Espaço no elemento. |
53
+
54
+ ## Exemplos
55
+
56
+ ### Card clicável e acessível
57
+
58
+ ```html
59
+ <div
60
+ (sInteractiveContent)="onAtivar($event)"
61
+ [focusable]="true"
62
+ style="padding: 16px; border: 2px solid #e5e7eb; border-radius: 8px; cursor: pointer;"
63
+ >
64
+ <p>Elemento interativo</p>
65
+ <p>Clique ou pressione Enter/Espaço</p>
66
+ </div>
67
+ ```
68
+
69
+ ### Cards selecionáveis com destaque visual
70
+
71
+ ```html
72
+ @for (card of cards; track card.id) {
73
+ <div
74
+ (sInteractiveContent)="cardSelecionado = card"
75
+ [focusable]="true"
76
+ [style.border-color]="cardSelecionado === card ? '#3b82f6' : '#e5e7eb'"
77
+ style="padding: 16px; border: 2px solid; border-radius: 8px; cursor: pointer;"
78
+ >
79
+ {{ card.titulo }}
80
+ </div>
81
+ }
82
+ ```
83
+
84
+ ### Elemento desabilitado
85
+
86
+ ```html
87
+ <div
88
+ (sInteractiveContent)="onAtivar($event)"
89
+ [disabled]="!temPermissao"
90
+ style="padding: 16px; cursor: not-allowed; opacity: 0.6;"
91
+ >
92
+ Elemento desabilitado
93
+ </div>
94
+ ```
95
+
96
+ ### Impedindo propagação de eventos
97
+
98
+ ```html
99
+ <div (click)="onClickExterno()">
100
+ <div
101
+ (sInteractiveContent)="onAtivarInterno($event)"
102
+ [stopPropagation]="true"
103
+ style="padding: 8px; border: 1px solid #ccc;"
104
+ >
105
+ Clique interno (não propaga)
106
+ </div>
107
+ </div>
108
+ ```
109
+
110
+ ## Acessibilidade
111
+
112
+ - Adiciona `tabindex="0"` automaticamente ao elemento quando `focusable` é `true`
113
+ - Emite o evento `sInteractiveContent` ao clicar ou pressionar Enter/Espaço
114
+ - Com `disabled: true`, o `tabindex` é definido como `-1` e eventos são ignorados
115
+ - Remove os event listeners automaticamente ao destruir o componente
116
+
117
+ ## Componentes relacionados
118
+
119
+ - [`Button`](../button/README.md) — botão nativo com acessibilidade integrada; prefira quando a semântica de botão é adequada
120
+ - [`MouseEvents`](../mouse-events/README.md) — diretivas para eventos de mouse avançados (long press, double click)