@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.
- package/accordion/README.md +166 -0
- package/alert/README.md +92 -0
- package/autocomplete/README.md +162 -0
- package/badge/README.md +126 -0
- package/bignumber-input/README.md +122 -0
- package/breadcrumb/README.md +144 -0
- package/button/README.md +159 -0
- package/calendar-mask/README.md +89 -0
- package/card/README.md +133 -0
- package/chat/README.md +130 -0
- package/checkbox/README.md +108 -0
- package/checkbox-list/README.md +149 -0
- package/chips/README.md +152 -0
- package/code-editor/README.md +149 -0
- package/collapse-link/README.md +128 -0
- package/confirm-dialog/README.md +105 -0
- package/content-generator/README.md +111 -0
- package/control-errors/README.md +92 -0
- package/country-phone-picker/README.md +121 -0
- package/currency/README.md +90 -0
- package/custom-fields/README.md +142 -0
- package/dialog/README.md +152 -0
- package/dynamic-form/README.md +176 -0
- package/editable-overlay/README.md +98 -0
- package/empty-state/README.md +134 -0
- package/esm2022/loading-state/lib/loading-state/loading-state.component.mjs +4 -4
- package/fesm2022/seniorsistemas-angular-components-loading-state.mjs +3 -3
- package/fesm2022/seniorsistemas-angular-components-loading-state.mjs.map +1 -1
- package/fieldset/README.md +135 -0
- package/file-picker/README.md +162 -0
- package/file-upload/README.md +23 -7
- package/gantt/README.md +173 -0
- package/global-search/README.md +151 -0
- package/grid-menu/README.md +123 -0
- package/help-popover/README.md +134 -0
- package/ia-insight/README.md +24 -6
- package/image-cropper/README.md +140 -0
- package/infinite-scroll/README.md +130 -0
- package/info-sign/README.md +111 -0
- package/inline-edit/README.md +139 -0
- package/insights/README.md +159 -0
- package/interactive-content/README.md +120 -0
- package/kanban/README.md +184 -0
- package/label-value/README.md +154 -0
- package/loading-state/README.md +141 -0
- package/localized-number-input/README.md +128 -0
- package/mouse-events/README.md +157 -0
- package/navigation-button/README.md +160 -0
- package/numeric/README.md +147 -0
- package/numeric-mask/README.md +170 -0
- package/object-card/README.md +158 -0
- package/package.json +1 -1
- package/paginator/README.md +121 -0
- package/panel/README.md +147 -0
- package/password-strength/README.md +144 -0
- package/picklist/README.md +170 -0
- package/pin-code-field/README.md +137 -0
- package/product-header/README.md +33 -6
- package/profile-picture-picker/README.md +159 -0
- package/progressbar/README.md +136 -0
- package/radio-button/README.md +117 -0
- package/rating-scale/README.md +154 -0
- package/select/README.md +147 -0
- package/select-button/README.md +137 -0
- package/sidebar/README.md +117 -0
- package/slide-in-bar/README.md +122 -0
- package/slider/README.md +127 -0
- package/speech-recognition/README.md +104 -0
- package/split-button/README.md +126 -0
- package/spotlight/README.md +200 -0
- package/star-rating/README.md +127 -0
- package/stats-card/README.md +135 -0
- package/stepper/README.md +164 -0
- package/switch/README.md +125 -0
- package/table/README.md +185 -0
- package/text-area-ia/README.md +17 -6
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# SlideInBar
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
Componente de painel deslizante lateral que expande e colapsa ao clicar em um botão de toggle. Em telas pequenas (largura <= 420px), entra automaticamente em modo overlay, sobrepondo o conteúdo.
|
|
6
|
+
|
|
7
|
+
> **Nota:** O seletor `s-slide-panel` e o pacote `slide-panel` estão descontinuados. Use `s-slide-in-bar` e o pacote `slide-in-bar` em novos projetos. O seletor antigo será removido na versão 20.0.0.
|
|
8
|
+
|
|
9
|
+
## Quando usar
|
|
10
|
+
|
|
11
|
+
- Filtros laterais em listas e tabelas que podem ser ocultados para dar mais espaço ao conteúdo
|
|
12
|
+
- Painéis de detalhes ou configurações que coexistem com o conteúdo principal
|
|
13
|
+
- Propriedades ou atributos de um elemento selecionado na área principal
|
|
14
|
+
- Quando o painel deve empurrar o layout adjacente (`noOverlap`) ou flutuar sobre ele
|
|
15
|
+
|
|
16
|
+
## Quando não usar
|
|
17
|
+
|
|
18
|
+
- Painéis que precisam de overlay com backdrop — prefira `Sidebar`
|
|
19
|
+
- Conteúdo que deve aparecer temporariamente em resposta a uma ação — prefira `Dialog` ou `Sidebar`
|
|
20
|
+
|
|
21
|
+
## Instalação
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { SlideInBarModule, SlideInBarService } from '@seniorsistemas/angular-components/slide-in-bar';
|
|
25
|
+
|
|
26
|
+
@NgModule({
|
|
27
|
+
imports: [SlideInBarModule],
|
|
28
|
+
providers: [SlideInBarService],
|
|
29
|
+
})
|
|
30
|
+
export class MeuModule {}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Uso básico
|
|
34
|
+
|
|
35
|
+
```html
|
|
36
|
+
<s-slide-in-bar (panelOpened)="onAbrir()" (panelClosed)="onFechar()">
|
|
37
|
+
<div slide-content>
|
|
38
|
+
<!-- conteúdo do painel deslizante -->
|
|
39
|
+
</div>
|
|
40
|
+
<div side-content>
|
|
41
|
+
<!-- conteúdo principal ao lado do painel -->
|
|
42
|
+
</div>
|
|
43
|
+
</s-slide-in-bar>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## API
|
|
47
|
+
|
|
48
|
+
### Inputs
|
|
49
|
+
|
|
50
|
+
| Propriedade | Tipo | Padrão | Obrigatório | Descrição |
|
|
51
|
+
|-------------|------|--------|:-----------:|-----------|
|
|
52
|
+
| `id` | `string` | `slide-panel-{n}` | Não | Identificador único do painel. Usado pelo `SlideInBarService` para fechar programaticamente |
|
|
53
|
+
| `openIcon` | `string` | `'fas fa-chevron-right'` | Não | Classe Font Awesome do ícone no botão de abertura |
|
|
54
|
+
| `closeIcon` | `string` | `'fas fa-chevron-left'` | Não | Classe Font Awesome do ícone no botão de fechamento |
|
|
55
|
+
| `cache` | `boolean` | `false` | Não | Mantém o conteúdo no DOM quando fechado, preservando estado interno |
|
|
56
|
+
| `createOpen` | `boolean` | `false` | Não | Inicia o painel já aberto |
|
|
57
|
+
| `noOverlap` | `boolean` | `false` | Não | O painel empurra o layout adjacente em vez de sobrepor o conteúdo |
|
|
58
|
+
|
|
59
|
+
### Outputs
|
|
60
|
+
|
|
61
|
+
| Evento | Tipo | Descrição |
|
|
62
|
+
|--------|------|-----------|
|
|
63
|
+
| `panelOpened` | `EventEmitter<void>` | Emitido quando o painel é aberto pelo usuário |
|
|
64
|
+
| `panelClosed` | `EventEmitter<void>` | Emitido quando o painel é fechado pelo usuário |
|
|
65
|
+
|
|
66
|
+
## Exemplos
|
|
67
|
+
|
|
68
|
+
### Painel de filtros
|
|
69
|
+
|
|
70
|
+
```html
|
|
71
|
+
<div style="display: flex; height: 400px;">
|
|
72
|
+
<s-slide-in-bar [cache]="true" (panelOpened)="onAbrir()">
|
|
73
|
+
<div slide-content style="padding: 16px; min-width: 200px;">
|
|
74
|
+
<h4>Filtros</h4>
|
|
75
|
+
<!-- inputs de filtro -->
|
|
76
|
+
</div>
|
|
77
|
+
<div side-content style="padding: 16px; flex: 1;">
|
|
78
|
+
<!-- conteúdo principal (tabela, lista) -->
|
|
79
|
+
</div>
|
|
80
|
+
</s-slide-in-bar>
|
|
81
|
+
</div>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Iniciando aberto com ícones customizados
|
|
85
|
+
|
|
86
|
+
```html
|
|
87
|
+
<s-slide-in-bar
|
|
88
|
+
[createOpen]="true"
|
|
89
|
+
openIcon="fas fa-plus"
|
|
90
|
+
closeIcon="fas fa-minus"
|
|
91
|
+
>
|
|
92
|
+
<div slide-content>Conteúdo do painel</div>
|
|
93
|
+
<div side-content>Conteúdo principal</div>
|
|
94
|
+
</s-slide-in-bar>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Fechando programaticamente via serviço
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
constructor(private slideInBarService: SlideInBarService) {}
|
|
101
|
+
|
|
102
|
+
fecharPainel(): void {
|
|
103
|
+
this.slideInBarService.closeModal('meu-painel-id');
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
```html
|
|
108
|
+
<s-slide-in-bar id="meu-painel-id">
|
|
109
|
+
<div slide-content>Painel</div>
|
|
110
|
+
<div side-content>Conteúdo</div>
|
|
111
|
+
</s-slide-in-bar>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Acessibilidade
|
|
115
|
+
|
|
116
|
+
- O botão de toggle é focável via teclado e pode ser acionado com `Enter` ou `Espaço`
|
|
117
|
+
- Em telas com largura <= 420px, o painel entra automaticamente em modo overlay
|
|
118
|
+
- A animação de abertura/fechamento tem duração de 200ms para não prejudicar a experiência de usuários sensíveis a movimento
|
|
119
|
+
|
|
120
|
+
## Componentes relacionados
|
|
121
|
+
|
|
122
|
+
- [`Sidebar`](../sidebar/README.md) — painel lateral com backdrop e suporte a templates customizados
|
package/slider/README.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Slider
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
Componente de controle deslizante para seleção de valores numéricos dentro de um intervalo definido. Suporta modo simples (um valor) e modo de intervalo (dois valores: início e fim). Implementa `ControlValueAccessor` para integração com Angular Forms.
|
|
6
|
+
|
|
7
|
+
## Quando usar
|
|
8
|
+
|
|
9
|
+
- Seleção de um valor dentro de um intervalo contínuo (volume, brilho, porcentagem)
|
|
10
|
+
- Filtros de faixa de valores (faixa de preço, temperatura, população)
|
|
11
|
+
- Controles onde a posição relativa é mais relevante que o valor exato
|
|
12
|
+
|
|
13
|
+
## Quando não usar
|
|
14
|
+
|
|
15
|
+
- Entrada de valores numéricos precisos — prefira `NumberInput` com campo de texto
|
|
16
|
+
- Intervalos com muitos passos discretos onde a precisão é crítica — prefira um campo com máscara numérica
|
|
17
|
+
- Valores que não se encaixam em uma progressão linear
|
|
18
|
+
|
|
19
|
+
## Instalação
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { SliderModule } from '@seniorsistemas/angular-components/slider';
|
|
23
|
+
|
|
24
|
+
@NgModule({ imports: [SliderModule] })
|
|
25
|
+
export class MeuModule {}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Uso básico
|
|
29
|
+
|
|
30
|
+
```html
|
|
31
|
+
<!-- Slider simples -->
|
|
32
|
+
<s-slider formControlName="volume" [min]="0" [max]="100" [step]="5" />
|
|
33
|
+
|
|
34
|
+
<!-- Slider de intervalo -->
|
|
35
|
+
<s-slider formControlName="faixa" [multiple]="true" [min]="0" [max]="1000" />
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## API
|
|
39
|
+
|
|
40
|
+
### Inputs
|
|
41
|
+
|
|
42
|
+
| Propriedade | Tipo | Padrão | Obrigatório | Descrição |
|
|
43
|
+
|-------------|------|--------|:-----------:|-----------|
|
|
44
|
+
| `value` | `number \| [number, number]` | `0` | Não | Valor atual. No modo range é `[inicio, fim]` |
|
|
45
|
+
| `multiple` | `boolean` | `false` | Não | Habilita modo de intervalo (dois thumbs) |
|
|
46
|
+
| `min` | `number` | `0` | Não | Valor mínimo do intervalo |
|
|
47
|
+
| `max` | `number` | `100` | Não | Valor máximo do intervalo |
|
|
48
|
+
| `step` | `number` | `1` | Não | Incremento aplicado a cada movimento do thumb |
|
|
49
|
+
| `minValueLabel` | `string` | `undefined` | Não | Label exibido abaixo do valor mínimo |
|
|
50
|
+
| `maxValueLabel` | `string` | `undefined` | Não | Label exibido abaixo do valor máximo |
|
|
51
|
+
| `disabled` | `boolean` | `false` | Não | Desabilita a interação do usuário |
|
|
52
|
+
| `hiddenThumb` | `boolean` | `false` | Não | Oculta visualmente o thumb (exibe apenas a barra de progresso) |
|
|
53
|
+
| `tabindex` | `number` | `0` | Não | Ordem de tabulação do elemento |
|
|
54
|
+
|
|
55
|
+
### Outputs
|
|
56
|
+
|
|
57
|
+
| Evento | Tipo | Descrição |
|
|
58
|
+
|--------|------|-----------|
|
|
59
|
+
| `valueChange` | `EventEmitter<number \| [number, number]>` | Emitido quando o valor é alterado pelo usuário |
|
|
60
|
+
|
|
61
|
+
## Exemplos
|
|
62
|
+
|
|
63
|
+
### Slider simples com labels
|
|
64
|
+
|
|
65
|
+
```html
|
|
66
|
+
<s-slider
|
|
67
|
+
[(ngModel)]="populacao"
|
|
68
|
+
[min]="0"
|
|
69
|
+
[max]="220"
|
|
70
|
+
[step]="5"
|
|
71
|
+
minValueLabel="0M"
|
|
72
|
+
maxValueLabel="220M"
|
|
73
|
+
(valueChange)="onMudanca($event)"
|
|
74
|
+
></s-slider>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Slider de intervalo
|
|
78
|
+
|
|
79
|
+
```html
|
|
80
|
+
<s-slider
|
|
81
|
+
[(ngModel)]="faixaTemperatura"
|
|
82
|
+
[multiple]="true"
|
|
83
|
+
[min]="-20"
|
|
84
|
+
[max]="50"
|
|
85
|
+
[step]="1"
|
|
86
|
+
minValueLabel="-20°C"
|
|
87
|
+
maxValueLabel="50°C"
|
|
88
|
+
></s-slider>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Integração com Reactive Forms
|
|
92
|
+
|
|
93
|
+
```html
|
|
94
|
+
<form [formGroup]="form">
|
|
95
|
+
<s-slider
|
|
96
|
+
formControlName="desconto"
|
|
97
|
+
[min]="0"
|
|
98
|
+
[max]="100"
|
|
99
|
+
[step]="5"
|
|
100
|
+
minValueLabel="0%"
|
|
101
|
+
maxValueLabel="100%"
|
|
102
|
+
></s-slider>
|
|
103
|
+
</form>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Slider desabilitado (somente leitura)
|
|
107
|
+
|
|
108
|
+
```html
|
|
109
|
+
<s-slider [value]="45" [min]="0" [max]="100" [disabled]="true"></s-slider>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Apenas barra de progresso (sem thumb)
|
|
113
|
+
|
|
114
|
+
```html
|
|
115
|
+
<s-slider [value]="65" [min]="0" [max]="100" [hiddenThumb]="true"></s-slider>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Acessibilidade
|
|
119
|
+
|
|
120
|
+
- Navegação por teclado: `ArrowLeft`/`ArrowRight` para decrementar/incrementar o valor em `step` unidades
|
|
121
|
+
- No modo de intervalo (`multiple`), as setas movem o intervalo inteiro mantendo a largura
|
|
122
|
+
- O atributo `tabindex` controla a ordem de tabulação
|
|
123
|
+
- Tooltips sobre os thumbs exibem os valores atuais visualmente
|
|
124
|
+
|
|
125
|
+
## Componentes relacionados
|
|
126
|
+
|
|
127
|
+
- [`NumberInput`](../number-input/README.md) — entrada numérica precisa com campo de texto
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# SpeechRecognition
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
Componente de reconhecimento de voz que integra a Web Speech API para transcrever a fala do usuário em texto, inserida diretamente em um `<textarea>` fornecido. Suporta também text-to-speech para leitura em voz alta do conteúdo do campo.
|
|
6
|
+
|
|
7
|
+
> **Nota:** Este componente é utilizado internamente pelo `TextAreaComponent` quando `speechRecognition: true`. Para uso em campos de texto simples, prefira o `TextAreaComponent`.
|
|
8
|
+
|
|
9
|
+
## Quando usar
|
|
10
|
+
|
|
11
|
+
- Campos de texto onde o usuário pode preferir ditar em vez de digitar
|
|
12
|
+
- Acessibilidade para usuários com dificuldade de digitação
|
|
13
|
+
- Formulários de observações ou descrições longas
|
|
14
|
+
- Ditado de textos longos em múltiplas sessões (`keepContext: true`)
|
|
15
|
+
|
|
16
|
+
## Quando não usar
|
|
17
|
+
|
|
18
|
+
- Ambientes sem suporte à Web Speech API (Firefox, Safari) — o componente não renderiza nesses browsers
|
|
19
|
+
- Campos de texto curtos onde a digitação é mais eficiente
|
|
20
|
+
- Contextos sem acesso ao microfone do dispositivo
|
|
21
|
+
|
|
22
|
+
## Instalação
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { SpeechRecognitionModule } from '@seniorsistemas/angular-components/speech-recognition';
|
|
26
|
+
|
|
27
|
+
@NgModule({ imports: [SpeechRecognitionModule] })
|
|
28
|
+
export class MeuModule {}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Uso básico
|
|
32
|
+
|
|
33
|
+
```html
|
|
34
|
+
<textarea #meuTextArea rows="5" placeholder="Digite ou use o microfone..."></textarea>
|
|
35
|
+
<s-speech-recognition
|
|
36
|
+
[textAreaElement]="meuTextArea"
|
|
37
|
+
(recognizedText)="onTextoReconhecido($event)"
|
|
38
|
+
></s-speech-recognition>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## API
|
|
42
|
+
|
|
43
|
+
### Inputs
|
|
44
|
+
|
|
45
|
+
| Propriedade | Tipo | Padrão | Obrigatório | Descrição |
|
|
46
|
+
|-------------|------|--------|:-----------:|-----------|
|
|
47
|
+
| `textAreaElement` | `HTMLTextAreaElement` | — | Sim | Referência ao elemento `<textarea>` nativo que receberá o texto transcrito |
|
|
48
|
+
| `keepContext` | `boolean` | `false` | Não | Quando `true`, o texto reconhecido é adicionado ao texto existente em vez de substituí-lo |
|
|
49
|
+
| `speechRecognitionPlaceholder` | `string` | `''` | Não | Placeholder exibido no textarea durante o reconhecimento de voz |
|
|
50
|
+
|
|
51
|
+
### Outputs
|
|
52
|
+
|
|
53
|
+
| Evento | Tipo | Descrição |
|
|
54
|
+
|--------|------|-----------|
|
|
55
|
+
| `recognizedText` | `EventEmitter<string>` | Emitido quando o reconhecimento é concluído e aprovado pelo usuário. Emite o texto transcrito |
|
|
56
|
+
|
|
57
|
+
## Exemplos
|
|
58
|
+
|
|
59
|
+
### Uso padrão com textarea
|
|
60
|
+
|
|
61
|
+
```html
|
|
62
|
+
<div style="display: flex; align-items: flex-start; gap: 8px;">
|
|
63
|
+
<textarea
|
|
64
|
+
#textAreaRef
|
|
65
|
+
rows="5"
|
|
66
|
+
placeholder="Digite ou use o microfone..."
|
|
67
|
+
style="flex: 1;"
|
|
68
|
+
></textarea>
|
|
69
|
+
<s-speech-recognition
|
|
70
|
+
[textAreaElement]="textAreaRef"
|
|
71
|
+
[keepContext]="false"
|
|
72
|
+
speechRecognitionPlaceholder="Ouvindo..."
|
|
73
|
+
(recognizedText)="onReconhecido($event)"
|
|
74
|
+
></s-speech-recognition>
|
|
75
|
+
</div>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Ditado acumulativo (keepContext)
|
|
79
|
+
|
|
80
|
+
```html
|
|
81
|
+
<div style="display: flex; align-items: flex-start; gap: 8px;">
|
|
82
|
+
<textarea
|
|
83
|
+
#textAreaRef
|
|
84
|
+
rows="5"
|
|
85
|
+
placeholder="Cada reconhecimento adiciona ao texto existente..."
|
|
86
|
+
style="flex: 1;"
|
|
87
|
+
></textarea>
|
|
88
|
+
<s-speech-recognition
|
|
89
|
+
[textAreaElement]="textAreaRef"
|
|
90
|
+
[keepContext]="true"
|
|
91
|
+
></s-speech-recognition>
|
|
92
|
+
</div>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Acessibilidade
|
|
96
|
+
|
|
97
|
+
- Requer suporte do browser à Web Speech API (compatível com Chrome e Edge)
|
|
98
|
+
- Ao iniciar o reconhecimento, o textarea é bloqueado para edição até o usuário aprovar ou descartar o texto reconhecido
|
|
99
|
+
- Após o reconhecimento, botões de **Aprovar** e **Descartar** são exibidos, permitindo confirmação antes de aplicar o texto
|
|
100
|
+
- O botão de text-to-speech lê o conteúdo atual do textarea em voz alta, com controles de velocidade (0.5x, 1x, 1.5x, 2x)
|
|
101
|
+
|
|
102
|
+
## Componentes relacionados
|
|
103
|
+
|
|
104
|
+
- [`TextArea`](../text-area/README.md) — área de texto com Speech Recognition integrado via prop `speechRecognition`
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# SplitButton
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
Botão composto com ação principal e dropdown de opções adicionais. Ao clicar no botão principal emite `buttonClicked`; ao clicar no ícone de seta abre ou fecha o dropdown com a lista de `options`.
|
|
6
|
+
|
|
7
|
+
## Quando usar
|
|
8
|
+
|
|
9
|
+
- Ação dominante (ex.: Adicionar) com variantes relacionadas (Atualizar, Alterar, Remover)
|
|
10
|
+
- Toolbars com uma ação principal e ações secundárias no mesmo botão
|
|
11
|
+
- Exportação de dados em múltiplos formatos (PDF, Excel, CSV)
|
|
12
|
+
|
|
13
|
+
## Quando não usar
|
|
14
|
+
|
|
15
|
+
- Todas as ações têm igual relevância — prefira múltiplos botões separados
|
|
16
|
+
- Há uma única ação — prefira um `Button` simples
|
|
17
|
+
- As ações secundárias são navigacionais — prefira `TieredMenu` separado
|
|
18
|
+
|
|
19
|
+
## Instalação
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { SplitButtonModule } from '@seniorsistemas/angular-components/split-button';
|
|
23
|
+
|
|
24
|
+
@NgModule({ imports: [SplitButtonModule] })
|
|
25
|
+
export class MeuModule {}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Uso básico
|
|
29
|
+
|
|
30
|
+
```html
|
|
31
|
+
<s-split-button
|
|
32
|
+
label="Adicionar"
|
|
33
|
+
iconClass="far fa-plus"
|
|
34
|
+
[options]="opcoes"
|
|
35
|
+
(buttonClicked)="onAdicionar()"
|
|
36
|
+
/>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## API
|
|
40
|
+
|
|
41
|
+
### Inputs
|
|
42
|
+
|
|
43
|
+
| Propriedade | Tipo | Padrão | Obrigatório | Descrição |
|
|
44
|
+
|-------------|------|--------|:-----------:|-----------|
|
|
45
|
+
| `label` | `string` | — | Sim | Rótulo do botão principal |
|
|
46
|
+
| `iconClass` | `string` | — | Sim | Classe Font Awesome do ícone exibido no botão principal |
|
|
47
|
+
| `options` | `SplitButtonOption[]` | — | Sim | Lista de opções exibidas no dropdown |
|
|
48
|
+
| `type` | `SplitButtonType` | `'primary'` | Não | Estilo visual do botão: `'primary'`, `'secondary'` ou `'default'` |
|
|
49
|
+
| `disabled` | `boolean` | `false` | Não | Desabilita o botão principal e o dropdown |
|
|
50
|
+
|
|
51
|
+
### Outputs
|
|
52
|
+
|
|
53
|
+
| Evento | Tipo | Descrição |
|
|
54
|
+
|--------|------|-----------|
|
|
55
|
+
| `buttonClicked` | `EventEmitter<void>` | Emitido quando o usuário clica no botão principal (não no dropdown) |
|
|
56
|
+
|
|
57
|
+
### Tipos
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
interface SplitButtonOption {
|
|
61
|
+
title: string; // Texto exibido no dropdown
|
|
62
|
+
action: () => void; // Função executada ao clicar na opção
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
type SplitButtonType = 'primary' | 'secondary' | 'default';
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Exemplos
|
|
69
|
+
|
|
70
|
+
### Botão primário com operações CRUD
|
|
71
|
+
|
|
72
|
+
```html
|
|
73
|
+
<s-split-button
|
|
74
|
+
label="Adicionar"
|
|
75
|
+
iconClass="far fa-plus"
|
|
76
|
+
type="primary"
|
|
77
|
+
[options]="opcoesCrud"
|
|
78
|
+
(buttonClicked)="onAdicionar()"
|
|
79
|
+
></s-split-button>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
opcoesCrud: SplitButtonOption[] = [
|
|
84
|
+
{ title: 'Atualizar', action: () => this.atualizar() },
|
|
85
|
+
{ title: 'Alterar', action: () => this.alterar() },
|
|
86
|
+
{ title: 'Remover', action: () => this.remover() },
|
|
87
|
+
];
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Exportação em múltiplos formatos
|
|
91
|
+
|
|
92
|
+
```html
|
|
93
|
+
<s-split-button
|
|
94
|
+
label="Exportar"
|
|
95
|
+
iconClass="fa fa-download"
|
|
96
|
+
type="primary"
|
|
97
|
+
[options]="opcoesExportar"
|
|
98
|
+
></s-split-button>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
opcoesExportar: SplitButtonOption[] = [
|
|
103
|
+
{ title: 'Exportar PDF', action: () => this.exportarPDF() },
|
|
104
|
+
{ title: 'Exportar Excel', action: () => this.exportarExcel() },
|
|
105
|
+
{ title: 'Exportar CSV', action: () => this.exportarCSV() },
|
|
106
|
+
];
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Visão geral dos tipos
|
|
110
|
+
|
|
111
|
+
```html
|
|
112
|
+
<s-split-button label="Adicionar" iconClass="far fa-plus" type="primary" [options]="opcoes"></s-split-button>
|
|
113
|
+
<s-split-button label="Alterar" iconClass="far fa-pencil" type="secondary" [options]="opcoes"></s-split-button>
|
|
114
|
+
<s-split-button label="Remover" iconClass="far fa-trash" type="default" [options]="opcoes"></s-split-button>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Acessibilidade
|
|
118
|
+
|
|
119
|
+
- O botão principal é focável via teclado e pode ser acionado com `Enter` ou `Espaço`
|
|
120
|
+
- Clicar fora do componente fecha o dropdown automaticamente via `HostListener`
|
|
121
|
+
- O estado desabilitado impede interação tanto no botão principal quanto no dropdown e nas opções
|
|
122
|
+
|
|
123
|
+
## Componentes relacionados
|
|
124
|
+
|
|
125
|
+
- [`Button`](../button/README.md) — botão de ação individual com suporte a menu via `menuOptions`
|
|
126
|
+
- [`TieredMenu`](../tiered-menu/README.md) — menu dropdown com submenus aninhados
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Spotlight
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
Sistema de destaque guiado que combina máscara de fundo semitransparente com um popover informativo posicionado ao lado de um elemento alvo. Suporta destaque simples (passo único) e tours guiados com múltiplos passos e navegação sequencial.
|
|
6
|
+
|
|
7
|
+
## Quando usar
|
|
8
|
+
|
|
9
|
+
- Onboarding de novos usuários apresentando funcionalidades pela primeira vez
|
|
10
|
+
- Destacar um campo ou ação importante em resposta a uma regra de negócio
|
|
11
|
+
- Tours guiados para apresentar uma tela complexa em sequência lógica
|
|
12
|
+
- Dicas contextuais disparadas por clique ou por lógica da aplicação
|
|
13
|
+
|
|
14
|
+
## Quando não usar
|
|
15
|
+
|
|
16
|
+
- Ajuda contextual estática sempre visível — prefira `HelpPopover`
|
|
17
|
+
- Dicas simples ao passar o mouse — prefira `Tooltip`
|
|
18
|
+
- Mensagens de alerta críticas que exigem uma ação imediata — prefira `Dialog`
|
|
19
|
+
|
|
20
|
+
## Instalação
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import {
|
|
24
|
+
SpotlightTourService,
|
|
25
|
+
SpotlightStepDirective,
|
|
26
|
+
} from '@seniorsistemas/angular-components/spotlight';
|
|
27
|
+
|
|
28
|
+
@Component({
|
|
29
|
+
standalone: true,
|
|
30
|
+
imports: [SpotlightStepDirective],
|
|
31
|
+
providers: [SpotlightTourService],
|
|
32
|
+
})
|
|
33
|
+
export class MeuComponent {
|
|
34
|
+
private readonly tourService = inject(SpotlightTourService);
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Uso básico
|
|
39
|
+
|
|
40
|
+
```html
|
|
41
|
+
<!-- Marque os elementos alvo com a diretiva -->
|
|
42
|
+
<button [sSpotlightStep]="'meu-botao'">Clique aqui</button>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// Destaque simples em um elemento
|
|
47
|
+
this.tourService.spotlight('meu-botao', {
|
|
48
|
+
title: 'Novo recurso',
|
|
49
|
+
message: 'Este botão agora tem uma função adicional.',
|
|
50
|
+
position: 'bottom-center',
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Tour guiado com múltiplos passos
|
|
54
|
+
this.tourService.start([
|
|
55
|
+
{ stepId: 'passo-1', title: 'Início', message: 'Descrição do passo 1' },
|
|
56
|
+
{ stepId: 'passo-2', title: 'Configuração', message: 'Descrição do passo 2' },
|
|
57
|
+
]);
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## API
|
|
61
|
+
|
|
62
|
+
### Diretiva `[sSpotlightStep]`
|
|
63
|
+
|
|
64
|
+
| Propriedade | Tipo | Obrigatório | Descrição |
|
|
65
|
+
|-------------|------|:-----------:|-----------|
|
|
66
|
+
| `sSpotlightStep` | `string` | Sim | ID único do passo do tour ao qual este elemento está associado |
|
|
67
|
+
|
|
68
|
+
### SpotlightComponent (popover isolado)
|
|
69
|
+
|
|
70
|
+
| Propriedade | Tipo | Padrão | Obrigatório | Descrição |
|
|
71
|
+
|-------------|------|--------|:-----------:|-----------|
|
|
72
|
+
| `title` | `string \| TemplateRef<any>` | `''` | Não | Título exibido no cabeçalho do popover |
|
|
73
|
+
| `message` | `string \| TemplateRef<any>` | `undefined` | Não | Mensagem principal do popover |
|
|
74
|
+
| `content` | `TemplateRef<any> \| null` | `null` | Não | Template para área de mídia/conteúdo customizado |
|
|
75
|
+
| `position` | `SpotlightPosition` | `'bottom-center'` | Não | Posição do popover em relação ao elemento alvo |
|
|
76
|
+
| `currentStep` | `number` | `1` | Não | Número do passo atual (1-based) |
|
|
77
|
+
| `totalSteps` | `number` | `1` | Não | Total de passos do tour |
|
|
78
|
+
| `showDoNotShowAgain` | `boolean` | `true` | Não | Exibe o checkbox "Não mostrar novamente" (apenas em modo simples) |
|
|
79
|
+
| `actions` | `SpotlightStepAction[]` | `[]` | Não | Botões adicionais no rodapé do popover |
|
|
80
|
+
| `arrowOffsetPx` | `number \| null` | `null` | Não | Deslocamento em pixels para posicionar a seta manualmente |
|
|
81
|
+
|
|
82
|
+
### Outputs do SpotlightComponent
|
|
83
|
+
|
|
84
|
+
| Evento | Tipo | Descrição |
|
|
85
|
+
|--------|------|-----------|
|
|
86
|
+
| `closed` | `OutputEmitterRef<void>` | Emitido ao clicar no botão de fechar (X) |
|
|
87
|
+
| `next` | `OutputEmitterRef<void>` | Emitido ao clicar em "Próximo" |
|
|
88
|
+
| `previous` | `OutputEmitterRef<void>` | Emitido ao clicar em "Voltar" |
|
|
89
|
+
| `understand` | `OutputEmitterRef<void>` | Emitido ao clicar em "Entendido" (modo simples) |
|
|
90
|
+
|
|
91
|
+
### Tipos
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
type SpotlightPosition =
|
|
95
|
+
| 'top-start' | 'top-center' | 'top-end'
|
|
96
|
+
| 'right-start' | 'right-center' | 'right-end'
|
|
97
|
+
| 'bottom-start' | 'bottom-center' | 'bottom-end'
|
|
98
|
+
| 'left-start' | 'left-center' | 'left-end';
|
|
99
|
+
|
|
100
|
+
interface SpotlightStep {
|
|
101
|
+
stepId: string;
|
|
102
|
+
title?: string | TemplateRef<any>;
|
|
103
|
+
message?: string | TemplateRef<any>;
|
|
104
|
+
position?: SpotlightPosition;
|
|
105
|
+
showDoNotShowAgain?: boolean;
|
|
106
|
+
dismissible?: boolean;
|
|
107
|
+
actions?: SpotlightStepAction[];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
interface SpotlightStepAction {
|
|
111
|
+
label: string;
|
|
112
|
+
handler: () => void;
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### SpotlightTourService — API pública
|
|
117
|
+
|
|
118
|
+
| Método/Propriedade | Descrição |
|
|
119
|
+
|---|---|
|
|
120
|
+
| `spotlight(stepId, config)` | Exibe destaque simples em um elemento |
|
|
121
|
+
| `start(steps)` | Inicia tour guiado com múltiplos passos |
|
|
122
|
+
| `next()` | Avança para o próximo passo |
|
|
123
|
+
| `previous()` | Retorna ao passo anterior |
|
|
124
|
+
| `stop(event?)` | Encerra o tour |
|
|
125
|
+
| `isActive` | Signal: indica se o tour está ativo |
|
|
126
|
+
| `currentIndex` | Signal: índice (0-based) do passo atual |
|
|
127
|
+
| `totalSteps` | Signal computado: total de passos |
|
|
128
|
+
| `stopped$` | Observable emitido ao encerrar o tour |
|
|
129
|
+
| `stepChanged$` | Observable emitido ao mudar de passo |
|
|
130
|
+
|
|
131
|
+
## Exemplos
|
|
132
|
+
|
|
133
|
+
### Destaque simples
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
this.tourService.spotlight('campo-obrigatorio', {
|
|
137
|
+
title: 'Campo obrigatório',
|
|
138
|
+
message: 'Este campo deve ser preenchido antes de continuar.',
|
|
139
|
+
position: 'bottom-center',
|
|
140
|
+
showDoNotShowAgain: true,
|
|
141
|
+
dismissible: true,
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Tour guiado com 3 passos
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
this.tourService.start([
|
|
149
|
+
{
|
|
150
|
+
stepId: 'btn-novo',
|
|
151
|
+
title: 'Passo 1 — Criar',
|
|
152
|
+
message: 'Use este botão para criar um novo registro.',
|
|
153
|
+
position: 'bottom-center',
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
stepId: 'filtro-data',
|
|
157
|
+
title: 'Passo 2 — Filtrar',
|
|
158
|
+
message: 'Filtre por período usando este campo de data.',
|
|
159
|
+
position: 'bottom-start',
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
stepId: 'btn-exportar',
|
|
163
|
+
title: 'Passo 3 — Exportar',
|
|
164
|
+
message: 'Exporte os dados filtrados em diferentes formatos.',
|
|
165
|
+
position: 'top-center',
|
|
166
|
+
},
|
|
167
|
+
]);
|
|
168
|
+
|
|
169
|
+
// Reagir ao encerramento
|
|
170
|
+
this.tourService.stopped$.subscribe(event => {
|
|
171
|
+
if (event.doNotShowAgain) {
|
|
172
|
+
// salvar preferência do usuário
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Spotlight bloqueado (não pode ser fechado pelo backdrop)
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
this.tourService.spotlight('elemento-alvo', {
|
|
181
|
+
title: 'Ação obrigatória',
|
|
182
|
+
message: 'Você deve completar esta ação antes de continuar.',
|
|
183
|
+
position: 'bottom-center',
|
|
184
|
+
dismissible: false,
|
|
185
|
+
showDoNotShowAgain: false,
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Acessibilidade
|
|
190
|
+
|
|
191
|
+
- O popover utiliza `role="dialog"` com `aria-labelledby` e `aria-describedby` referenciando título e mensagem
|
|
192
|
+
- O foco é gerenciado via CDK FocusTrap: ao abrir, o foco vai para o primeiro elemento interativo do popover
|
|
193
|
+
- Pressionar `Escape` fecha o spotlight quando `dismissible !== false`
|
|
194
|
+
- A posição do popover se ajusta automaticamente quando há pouco espaço na viewport
|
|
195
|
+
- Suporte completo à navegação por teclado (Tab, Shift+Tab, Enter, Escape)
|
|
196
|
+
|
|
197
|
+
## Componentes relacionados
|
|
198
|
+
|
|
199
|
+
- [`HelpPopover`](../help-popover/README.md) — popover de ajuda contextual fixo em elementos de formulário
|
|
200
|
+
- [`Tooltip`](../tooltip/README.md) — dica de conteúdo simples ao passar o mouse
|