@seniorsistemas/angular-components 19.2.0 → 19.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/dynamic-form/dynamic-form/dynamic-form.directive.d.ts +3 -0
- package/dynamic-form/dynamic-form/form-field/configurations/fields/field.d.ts +7 -0
- package/dynamic-form/public-api.d.ts +2 -3
- package/esm2022/dynamic-form/dynamic-form/dynamic-form.directive.mjs +17 -1
- package/esm2022/dynamic-form/dynamic-form/form-field/configurations/fields/field.mjs +1 -1
- package/esm2022/dynamic-form/public-api.mjs +3 -4
- package/esm2022/lib/locale/fallback.mjs +10 -2
- package/esm2022/spotlight/lib/spotlight/spotlight-overlay/spotlight-overlay.component.mjs +460 -0
- package/esm2022/spotlight/lib/spotlight/spotlight-step.directive.mjs +50 -0
- package/esm2022/spotlight/lib/spotlight/spotlight-tour.service.mjs +251 -0
- package/esm2022/spotlight/lib/spotlight/spotlight.component.mjs +193 -0
- package/esm2022/spotlight/lib/spotlight/types/spotlight-position.mjs +2 -0
- package/esm2022/spotlight/lib/spotlight/types/spotlight-step.mjs +2 -0
- package/esm2022/spotlight/lib/spotlight/types/spotlight-stop-event.mjs +2 -0
- package/esm2022/spotlight/public-api.mjs +4 -0
- package/esm2022/spotlight/seniorsistemas-angular-components-spotlight.mjs +5 -0
- package/fesm2022/seniorsistemas-angular-components-dynamic-form.mjs +16 -0
- package/fesm2022/seniorsistemas-angular-components-dynamic-form.mjs.map +1 -1
- package/fesm2022/seniorsistemas-angular-components-spotlight.mjs +947 -0
- package/fesm2022/seniorsistemas-angular-components-spotlight.mjs.map +1 -0
- package/fesm2022/seniorsistemas-angular-components.mjs +9 -1
- package/fesm2022/seniorsistemas-angular-components.mjs.map +1 -1
- package/package.json +13 -7
- package/spotlight/README.md +311 -0
- package/spotlight/index.d.ts +5 -0
- package/spotlight/lib/spotlight/spotlight-overlay/spotlight-overlay.component.d.ts +70 -0
- package/spotlight/lib/spotlight/spotlight-step.directive.d.ts +28 -0
- package/spotlight/lib/spotlight/spotlight-tour.service.d.ts +146 -0
- package/spotlight/lib/spotlight/spotlight.component.d.ts +82 -0
- package/spotlight/lib/spotlight/types/spotlight-position.d.ts +1 -0
- package/spotlight/lib/spotlight/types/spotlight-step.d.ts +21 -0
- package/spotlight/lib/spotlight/types/spotlight-stop-event.d.ts +13 -0
- package/spotlight/public-api.d.ts +6 -0
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
# Spotlight
|
|
2
|
+
|
|
3
|
+
## Descrição
|
|
4
|
+
|
|
5
|
+
O Spotlight é uma biblioteca para criação de **tours guiados** (onboarding com múltiplos passos) e **destaques simples** (dicas únicas sobre um elemento). O posicionamento do popover é gerenciado automaticamente pelo Angular CDK, com fallbacks inteligentes para manter o popover sempre visível.
|
|
6
|
+
|
|
7
|
+
Dois modos de operação:
|
|
8
|
+
|
|
9
|
+
- **Tour**: sequência de passos com navegação Próximo / Voltar / Concluído, contador de progresso, focus trap e bloqueio de scroll.
|
|
10
|
+
- **Destaque simples**: popover único com botão "Entendi" e opção de "Não mostrar novamente".
|
|
11
|
+
|
|
12
|
+
## Instalação
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @seniorsistemas/angular-components/spotlight
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Conceitos
|
|
19
|
+
|
|
20
|
+
### Diretiva `sSpotlightStep`
|
|
21
|
+
|
|
22
|
+
Registra um elemento do DOM como alvo de um passo do tour. Deve ser aplicada ao elemento que receberá o destaque.
|
|
23
|
+
|
|
24
|
+
```html
|
|
25
|
+
<button sSpotlightStep="meu-botao">Salvar</button>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
O valor do atributo é o `stepId`, que deve corresponder ao `stepId` definido nos passos do tour.
|
|
29
|
+
Quando o valor do binding muda dinamicamente, a diretiva desregistra o ID anterior e registra o novo automaticamente.
|
|
30
|
+
|
|
31
|
+
### `SpotlightTourService`
|
|
32
|
+
|
|
33
|
+
Serviço singleton que controla o estado do tour. Injete-o no componente que inicia o tour.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Tour (múltiplos passos)
|
|
38
|
+
|
|
39
|
+
### 1. Marque os elementos no template
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<input sSpotlightStep="produto-nome" ... />
|
|
43
|
+
<select sSpotlightStep="produto-categoria" ... />
|
|
44
|
+
<button sSpotlightStep="salvar-btn">Salvar</button>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 2. Inicie o tour pelo serviço
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { SpotlightTourService, SpotlightStep } from '@seniorsistemas/angular-components/spotlight';
|
|
51
|
+
|
|
52
|
+
@Component({ ... })
|
|
53
|
+
export class MeuComponent {
|
|
54
|
+
private readonly tourService = inject(SpotlightTourService);
|
|
55
|
+
|
|
56
|
+
private readonly passos: SpotlightStep[] = [
|
|
57
|
+
{
|
|
58
|
+
stepId: 'produto-nome',
|
|
59
|
+
title: 'Nome do produto',
|
|
60
|
+
message: 'Informe o nome completo do produto.',
|
|
61
|
+
position: 'bottom-center',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
stepId: 'produto-categoria',
|
|
65
|
+
title: 'Categoria',
|
|
66
|
+
message: 'Selecione a categoria correta.',
|
|
67
|
+
position: 'bottom-end',
|
|
68
|
+
beforeNext: () => {
|
|
69
|
+
// Executado antes de avançar — útil para trocar abas, expandir seções, etc.
|
|
70
|
+
this.activeTab.set('detalhes');
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
stepId: 'salvar-btn',
|
|
75
|
+
title: 'Salvar',
|
|
76
|
+
message: 'Clique aqui para salvar as alterações.',
|
|
77
|
+
position: 'top-center',
|
|
78
|
+
},
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
public iniciarTour(): void {
|
|
82
|
+
this.tourService.start(this.passos);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 3. Reaja aos eventos do tour
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
private readonly destroyRef = inject(DestroyRef);
|
|
91
|
+
|
|
92
|
+
public constructor() {
|
|
93
|
+
this.tourService.stopped$
|
|
94
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
95
|
+
.subscribe((event) => {
|
|
96
|
+
// Salve o estado para persistência
|
|
97
|
+
localStorage.setItem('tour-onboarding', JSON.stringify({
|
|
98
|
+
reason: event.reason, // 'completed' | 'interrupted'
|
|
99
|
+
doNotShowAgain: event.doNotShowAgain,
|
|
100
|
+
stepIndex: event.stepIndex,
|
|
101
|
+
}));
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Destaque Simples
|
|
109
|
+
|
|
110
|
+
Use `tourService.spotlight()` para exibir um destaque em um único elemento.
|
|
111
|
+
|
|
112
|
+
```html
|
|
113
|
+
<div sSpotlightStep="novo-recurso">...</div>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
import { SpotlightTourService, SpotlightConfig } from '@seniorsistemas/angular-components/spotlight';
|
|
118
|
+
|
|
119
|
+
@Component({ ... })
|
|
120
|
+
export class MeuComponent {
|
|
121
|
+
private readonly tourService = inject(SpotlightTourService);
|
|
122
|
+
|
|
123
|
+
public mostrarDica(): void {
|
|
124
|
+
const config: SpotlightConfig = {
|
|
125
|
+
title: 'Novidade!',
|
|
126
|
+
message: 'Este recurso foi adicionado recentemente.',
|
|
127
|
+
position: 'bottom-center',
|
|
128
|
+
// showDoNotShowAgain é true por padrão — passe false para suprimir o checkbox
|
|
129
|
+
dismissible: true,
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
this.tourService.spotlight('novo-recurso', config);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Ao encerrar, `stopped$` emite com `reason: 'dismissed'` (usuário fechou) ou `reason: 'completed'` (clicou em "Entendi"). Quando `doNotShowAgain` é `true`, salve essa preferência para não exibir novamente.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## `SpotlightStep`
|
|
142
|
+
|
|
143
|
+
| Propriedade | Tipo | Obrigatório | Descrição |
|
|
144
|
+
|---|---|---|---|
|
|
145
|
+
| `stepId` | `string` | ✓ | Identificador único do passo. Deve corresponder ao valor do `sSpotlightStep` no template. |
|
|
146
|
+
| `title` | `string \| TemplateRef<any>` | ✓ | Título do popover (máx. recomendado: 30 caracteres). |
|
|
147
|
+
| `message` | `string \| TemplateRef<any>` | ✓ | Texto descritivo (máx. recomendado: 75 caracteres). |
|
|
148
|
+
| `position` | `SpotlightPosition` | — | Posição preferida do popover. Padrão: `'bottom-center'`. |
|
|
149
|
+
| `content` | `TemplateRef<any> \| null` | — | Conteúdo visual customizado (imagem, gif, vídeo) exibido acima da mensagem. |
|
|
150
|
+
| `actions` | `SpotlightStepAction[]` | — | Botões de ação customizados exibidos antes dos botões de navegação. |
|
|
151
|
+
| `showBackdrop` | `boolean` | — | Exibe o backdrop escurecido ao redor do elemento destacado. Padrão: `true`. |
|
|
152
|
+
| `dismissible` | `boolean` | — | Permite fechar o spotlight clicando fora ou pressionando Escape. Padrão: `true`. |
|
|
153
|
+
| `beforeNext` | `() => void \| Promise<void>` | — | Callback executado antes de avançar para o próximo passo. Suporta async/await. |
|
|
154
|
+
| `beforePrevious` | `() => void \| Promise<void>` | — | Callback executado antes de voltar ao passo anterior. Suporta async/await. |
|
|
155
|
+
|
|
156
|
+
## `SpotlightConfig`
|
|
157
|
+
|
|
158
|
+
Equivalente ao `SpotlightStep` sem `stepId`, `beforeNext` e `beforePrevious`. Usado exclusivamente com `tourService.spotlight()`. Inclui a propriedade adicional:
|
|
159
|
+
|
|
160
|
+
| Propriedade | Tipo | Descrição |
|
|
161
|
+
|---|---|---|
|
|
162
|
+
| `showDoNotShowAgain` | `boolean` | Exibe o checkbox "Não mostrar novamente". Padrão: `true`. Passe `false` para suprimir. |
|
|
163
|
+
|
|
164
|
+
## `SpotlightStepAction`
|
|
165
|
+
|
|
166
|
+
| Propriedade | Tipo | Descrição |
|
|
167
|
+
|---|---|---|
|
|
168
|
+
| `label` | `string` | Texto do botão. |
|
|
169
|
+
| `handler` | `() => void` | Função executada ao clicar no botão. |
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## `SpotlightTourService`
|
|
174
|
+
|
|
175
|
+
### Propriedades
|
|
176
|
+
|
|
177
|
+
| Propriedade | Tipo | Descrição |
|
|
178
|
+
|---|---|---|
|
|
179
|
+
| `isActive` | `Signal<boolean>` | `true` enquanto o tour estiver ativo. |
|
|
180
|
+
| `currentStep` | `Signal<SpotlightStep \| undefined>` | Passo atualmente exibido. |
|
|
181
|
+
| `currentIndex` | `Signal<number>` | Índice do passo atual (base 0). |
|
|
182
|
+
| `totalSteps` | `Signal<number>` | Total de passos do tour. |
|
|
183
|
+
| `stopped$` | `Observable<SpotlightStopEvent>` | Emite quando o tour é encerrado. |
|
|
184
|
+
| `stepChanged$` | `Observable<SpotlightStepChangedEvent>` | Emite ao mudar de passo (incluindo o primeiro). |
|
|
185
|
+
|
|
186
|
+
### Métodos
|
|
187
|
+
|
|
188
|
+
| Método | Descrição |
|
|
189
|
+
|---|---|
|
|
190
|
+
| `start(steps: SpotlightStep[])` | Inicia o tour com a lista de passos fornecida. Ignora arrays vazios. Se houver um tour ativo, encerra-o (emitindo `stopped$`) antes de iniciar o novo. |
|
|
191
|
+
| `spotlight(stepId, config: SpotlightConfig)` | Exibe um destaque simples em um único elemento. |
|
|
192
|
+
| `next(doNotShowAgain?: boolean)` | Avança para o próximo passo ou conclui o tour. |
|
|
193
|
+
| `previous()` | Volta ao passo anterior. |
|
|
194
|
+
| `stop(event?: Partial<SpotlightStopEvent>)` | Encerra o tour programaticamente. |
|
|
195
|
+
| `registerElement(stepId, el)` | Registra um elemento (usado internamente pela diretiva). |
|
|
196
|
+
| `unregisterElement(stepId)` | Remove o registro de um elemento. |
|
|
197
|
+
| `getElement(stepId)` | Retorna o `ElementRef` registrado para o `stepId`. |
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Eventos (`SpotlightStopEvent`)
|
|
202
|
+
|
|
203
|
+
Emitido por `stopped$` ao encerrar o tour.
|
|
204
|
+
|
|
205
|
+
| Campo | Tipo | Descrição |
|
|
206
|
+
|---|---|---|
|
|
207
|
+
| `reason` | `SpotlightStopReason` | Razão do encerramento. |
|
|
208
|
+
| `doNotShowAgain` | `boolean` | `true` se o usuário marcou "Não mostrar novamente". |
|
|
209
|
+
| `stepId` | `string` | `stepId` do passo em que o tour foi encerrado. |
|
|
210
|
+
| `stepIndex` | `number` | Índice (base 0) do passo em que o tour foi encerrado. |
|
|
211
|
+
| `totalSteps` | `number` | Total de passos do tour. |
|
|
212
|
+
|
|
213
|
+
### `SpotlightStopReason`
|
|
214
|
+
|
|
215
|
+
| Valor | Quando ocorre | Comportamento recomendado |
|
|
216
|
+
|---|---|---|
|
|
217
|
+
| `'completed'` | Usuário clicou em "Concluído" ou "Entendi" | Nunca reexibir |
|
|
218
|
+
| `'interrupted'` | Usuário fechou o tour antes de concluir (X, Escape, clique fora) | Reexibir na próxima sessão |
|
|
219
|
+
| `'dismissed'` | Usuário fechou um destaque simples | Reexibir após cooldown |
|
|
220
|
+
|
|
221
|
+
### `SpotlightStepChangedEvent`
|
|
222
|
+
|
|
223
|
+
Emitido por `stepChanged$` a cada mudança de passo.
|
|
224
|
+
|
|
225
|
+
| Campo | Tipo | Descrição |
|
|
226
|
+
|---|---|---|
|
|
227
|
+
| `stepId` | `string` | `stepId` do novo passo. |
|
|
228
|
+
| `stepIndex` | `number` | Índice (base 0) do novo passo. |
|
|
229
|
+
| `totalSteps` | `number` | Total de passos do tour. |
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Posições Disponíveis (`SpotlightPosition`)
|
|
234
|
+
|
|
235
|
+
| Valor | Descrição |
|
|
236
|
+
|---|---|
|
|
237
|
+
| `'top-start'` | Acima do elemento, alinhado à esquerda |
|
|
238
|
+
| `'top-center'` | Acima do elemento, centralizado |
|
|
239
|
+
| `'top-end'` | Acima do elemento, alinhado à direita |
|
|
240
|
+
| `'bottom-start'` | Abaixo do elemento, alinhado à esquerda |
|
|
241
|
+
| `'bottom-center'` | Abaixo do elemento, centralizado |
|
|
242
|
+
| `'bottom-end'` | Abaixo do elemento, alinhado à direita |
|
|
243
|
+
| `'left-start'` | À esquerda do elemento, alinhado ao topo |
|
|
244
|
+
| `'left-center'` | À esquerda do elemento, centralizado |
|
|
245
|
+
| `'left-end'` | À esquerda do elemento, alinhado à base |
|
|
246
|
+
| `'right-start'` | À direita do elemento, alinhado ao topo |
|
|
247
|
+
| `'right-center'` | À direita do elemento, centralizado |
|
|
248
|
+
| `'right-end'` | À direita do elemento, alinhado à base |
|
|
249
|
+
|
|
250
|
+
> O CDK ajusta automaticamente a posição quando não há espaço suficiente, garantindo que o popover sempre permaneça visível.
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Persistência
|
|
255
|
+
|
|
256
|
+
A persistência do estado (se o tour já foi visto, preferência "Não mostrar novamente", etc.) é responsabilidade do produto consumidor. Use os dados emitidos por `stopped$` para implementar a estratégia adequada:
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
this.tourService.stopped$.subscribe((event) => {
|
|
260
|
+
const estado = {
|
|
261
|
+
reason: event.reason,
|
|
262
|
+
doNotShowAgain: event.doNotShowAgain,
|
|
263
|
+
contentVersion: 'v2', // versão do conteúdo do tour, controlada pelo produto
|
|
264
|
+
};
|
|
265
|
+
localStorage.setItem('tour-onboarding', JSON.stringify(estado));
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
// Na inicialização:
|
|
269
|
+
const salvo = JSON.parse(localStorage.getItem('tour-onboarding') ?? 'null');
|
|
270
|
+
const deveExibir =
|
|
271
|
+
!salvo ||
|
|
272
|
+
salvo.contentVersion !== 'v2' || // novo conteúdo → reexibir
|
|
273
|
+
salvo.reason === 'interrupted'; // não concluiu → reexibir
|
|
274
|
+
|
|
275
|
+
if (deveExibir && !salvo?.doNotShowAgain) {
|
|
276
|
+
// Chamar tourService.start(passos) no momento adequado
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## Telemetria
|
|
283
|
+
|
|
284
|
+
Use os observables do serviço para enviar eventos ao seu sistema de analytics:
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
// Tour iniciado (step 0)
|
|
288
|
+
this.tourService.stepChanged$
|
|
289
|
+
.pipe(filter((e) => e.stepIndex === 0 && e.totalSteps > 1))
|
|
290
|
+
.subscribe(() => analytics.track('tour_viewed'));
|
|
291
|
+
|
|
292
|
+
// Tour concluído
|
|
293
|
+
this.tourService.stopped$
|
|
294
|
+
.pipe(filter((e) => e.reason === 'completed' && e.totalSteps > 1))
|
|
295
|
+
.subscribe(() => analytics.track('tour_completed'));
|
|
296
|
+
|
|
297
|
+
// Tour interrompido
|
|
298
|
+
this.tourService.stopped$
|
|
299
|
+
.pipe(filter((e) => e.reason === 'interrupted'))
|
|
300
|
+
.subscribe(() => analytics.track('tour_interrupted'));
|
|
301
|
+
|
|
302
|
+
// Destaque simples fechado
|
|
303
|
+
this.tourService.stopped$
|
|
304
|
+
.pipe(filter((e) => e.reason === 'dismissed'))
|
|
305
|
+
.subscribe(() => analytics.track('spotlight_dismissed'));
|
|
306
|
+
|
|
307
|
+
// "Não mostrar novamente" marcado
|
|
308
|
+
this.tourService.stopped$
|
|
309
|
+
.pipe(filter((e) => e.doNotShowAgain))
|
|
310
|
+
.subscribe(() => analytics.track('spotlight_do_not_show_again_checked'));
|
|
311
|
+
```
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { OnDestroy, OnInit } from '@angular/core';
|
|
2
|
+
import { SpotlightStep } from '../types/spotlight-step';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare class SpotlightOverlayComponent implements OnInit, OnDestroy {
|
|
5
|
+
private readonly tourService;
|
|
6
|
+
private readonly destroyRef;
|
|
7
|
+
private readonly zone;
|
|
8
|
+
private readonly cdkOverlay;
|
|
9
|
+
private readonly environmentInjector;
|
|
10
|
+
private readonly focusTrapFactory;
|
|
11
|
+
/** @internal */
|
|
12
|
+
readonly isActive: import("@angular/core").Signal<boolean>;
|
|
13
|
+
/** @internal */
|
|
14
|
+
readonly currentStep: import("@angular/core").Signal<(SpotlightStep & {
|
|
15
|
+
showDoNotShowAgain?: boolean;
|
|
16
|
+
}) | undefined>;
|
|
17
|
+
/** @internal */
|
|
18
|
+
readonly currentIndex: import("@angular/core").Signal<number>;
|
|
19
|
+
/** @internal */
|
|
20
|
+
readonly totalSteps: import("@angular/core").Signal<number>;
|
|
21
|
+
/** @internal*/
|
|
22
|
+
readonly targetRect: import("@angular/core").WritableSignal<DOMRect | null>;
|
|
23
|
+
/** @internal */
|
|
24
|
+
readonly topMaskStyle: import("@angular/core").Signal<Record<string, string>>;
|
|
25
|
+
/** @internal */
|
|
26
|
+
readonly leftMaskStyle: import("@angular/core").Signal<Record<string, string>>;
|
|
27
|
+
/** @internal */
|
|
28
|
+
readonly rightMaskStyle: import("@angular/core").Signal<Record<string, string>>;
|
|
29
|
+
/** @internal */
|
|
30
|
+
readonly bottomMaskStyle: import("@angular/core").Signal<Record<string, string>>;
|
|
31
|
+
/** @internal */
|
|
32
|
+
readonly transparentBlockerStyle: import("@angular/core").Signal<Record<string, string>>;
|
|
33
|
+
private resizeObserver;
|
|
34
|
+
private popoverOverlayRef;
|
|
35
|
+
private popoverComponentRef;
|
|
36
|
+
private popoverSubs;
|
|
37
|
+
private focusTrap;
|
|
38
|
+
private previouslyFocusedElement;
|
|
39
|
+
constructor();
|
|
40
|
+
ngOnInit(): void;
|
|
41
|
+
ngOnDestroy(): void;
|
|
42
|
+
/** @internal */
|
|
43
|
+
onNext(): void;
|
|
44
|
+
/** @internal */
|
|
45
|
+
onPrevious(): void;
|
|
46
|
+
/** @internal */
|
|
47
|
+
onClose(): void;
|
|
48
|
+
/** @internal */
|
|
49
|
+
onDismiss(): void;
|
|
50
|
+
private updatePopoverOverlay;
|
|
51
|
+
private setPopoverZIndex;
|
|
52
|
+
private attachPopoverPortal;
|
|
53
|
+
private updatePopoverInputs;
|
|
54
|
+
private scheduleSync;
|
|
55
|
+
private activateTourMode;
|
|
56
|
+
/**
|
|
57
|
+
* After a step change, moves focus back to the first tabbable element inside the
|
|
58
|
+
* popover so the user does not lose keyboard position.
|
|
59
|
+
* No-op when there is no active focus trap (simple spotlight mode).
|
|
60
|
+
*/
|
|
61
|
+
private scheduleFocusTrapRefocus;
|
|
62
|
+
private syncDirectionAndArrow;
|
|
63
|
+
private destroyPopoverOverlay;
|
|
64
|
+
private updateTargetRect;
|
|
65
|
+
private refreshRect;
|
|
66
|
+
private observeElement;
|
|
67
|
+
private disconnectResizeObserver;
|
|
68
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SpotlightOverlayComponent, never>;
|
|
69
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<SpotlightOverlayComponent, "s-spotlight-overlay", never, {}, {}, never, never, true, never>;
|
|
70
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { OnDestroy } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
/**
|
|
4
|
+
* Diretiva que registra um elemento do DOM como alvo de um passo do Spotlight Tour.
|
|
5
|
+
*
|
|
6
|
+
* Aplique a diretiva em qualquer elemento e forneça um ID único que corresponda
|
|
7
|
+
* ao `stepId` configurado no `SpotlightTourService`. O elemento será automaticamente
|
|
8
|
+
* registrado ao ser criado e atualizado caso o ID mude dinamicamente.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```html
|
|
12
|
+
* <button [sSpotlightStep]="'meu-botao'">Clique aqui</button>
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare class SpotlightStepDirective implements OnDestroy {
|
|
16
|
+
/**
|
|
17
|
+
* ID único do passo do tour ao qual este elemento está associado.
|
|
18
|
+
* Deve corresponder ao `stepId` definido em `SpotlightStep`.
|
|
19
|
+
*/
|
|
20
|
+
sSpotlightStep: import("@angular/core").InputSignal<string>;
|
|
21
|
+
private readonly el;
|
|
22
|
+
private readonly tourService;
|
|
23
|
+
private currentId;
|
|
24
|
+
constructor();
|
|
25
|
+
ngOnDestroy(): void;
|
|
26
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SpotlightStepDirective, never>;
|
|
27
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<SpotlightStepDirective, "[sSpotlightStep]", never, { "sSpotlightStep": { "alias": "sSpotlightStep"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { ElementRef } from '@angular/core';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import { SpotlightConfig, SpotlightStep } from './types/spotlight-step';
|
|
4
|
+
import { SpotlightStepChangedEvent, SpotlightStopEvent } from './types/spotlight-stop-event';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
/** @internal */
|
|
7
|
+
type SpotlightStepInternal = SpotlightStep & {
|
|
8
|
+
showDoNotShowAgain?: boolean;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Serviço central do Spotlight Tour.
|
|
12
|
+
*
|
|
13
|
+
* Gerencia o estado do tour (passos, índice atual, ativo/inativo), a navegação entre
|
|
14
|
+
* passos e o registro de elementos do DOM associados a cada `stepId`.
|
|
15
|
+
*
|
|
16
|
+
* Use `start()` para iniciar um tour com múltiplos passos ou `spotlight()` para
|
|
17
|
+
* exibir um destaque simples em um único elemento.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* // Tour com múltiplos passos
|
|
22
|
+
* this.tourService.start([
|
|
23
|
+
* { stepId: 'passo-1', title: 'Título', message: 'Mensagem' },
|
|
24
|
+
* { stepId: 'passo-2', title: 'Título', message: 'Mensagem' },
|
|
25
|
+
* ]);
|
|
26
|
+
*
|
|
27
|
+
* // Destaque simples
|
|
28
|
+
* this.tourService.spotlight('meu-elemento', { title: 'Dica', message: 'Detalhes' });
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare class SpotlightTourService {
|
|
32
|
+
private readonly overlay;
|
|
33
|
+
private readonly environmentInjector;
|
|
34
|
+
private overlayRef;
|
|
35
|
+
private readonly _steps;
|
|
36
|
+
private readonly _currentIndex;
|
|
37
|
+
private readonly _isActive;
|
|
38
|
+
private readonly _registrationVersion;
|
|
39
|
+
private readonly _registeredElements;
|
|
40
|
+
private _pendingDoNotShowAgain;
|
|
41
|
+
private readonly _stopped$;
|
|
42
|
+
private readonly _stepChanged$;
|
|
43
|
+
/** Signal somente-leitura que indica se o tour está ativo no momento. */
|
|
44
|
+
readonly isActive: import("@angular/core").Signal<boolean>;
|
|
45
|
+
/** Signal somente-leitura com o índice (0-based) do passo exibido atualmente. */
|
|
46
|
+
readonly currentIndex: import("@angular/core").Signal<number>;
|
|
47
|
+
/** Signal computado com o total de passos do tour em andamento. */
|
|
48
|
+
readonly totalSteps: import("@angular/core").Signal<number>;
|
|
49
|
+
/** Signal computado com os dados do passo atualmente exibido. */
|
|
50
|
+
readonly currentStep: import("@angular/core").Signal<SpotlightStepInternal | undefined>;
|
|
51
|
+
/**
|
|
52
|
+
* Observable emitido quando o tour é encerrado, seja por conclusão, interrupção
|
|
53
|
+
* ou descarte. Carrega um `SpotlightStopEvent` com o motivo e o estado final.
|
|
54
|
+
*/
|
|
55
|
+
readonly stopped$: Observable<SpotlightStopEvent>;
|
|
56
|
+
/**
|
|
57
|
+
* Observable emitido sempre que o passo exibido muda, incluindo o início do tour.
|
|
58
|
+
* Carrega um `SpotlightStepChangedEvent` com o `stepId` e o índice do novo passo.
|
|
59
|
+
*/
|
|
60
|
+
readonly stepChanged$: Observable<SpotlightStepChangedEvent>;
|
|
61
|
+
/**
|
|
62
|
+
* Signal somente-leitura incrementado a cada chamada de `registerElement` ou
|
|
63
|
+
* `unregisterElement`. Permite que outros componentes reajam a mudanças no
|
|
64
|
+
* registro de elementos sem polling.
|
|
65
|
+
*/
|
|
66
|
+
readonly registrationVersion: import("@angular/core").Signal<number>;
|
|
67
|
+
/**
|
|
68
|
+
* Inicia um tour com a lista de passos fornecida.
|
|
69
|
+
*
|
|
70
|
+
* O tour começa pelo primeiro passo da lista. Emite `stepChanged$` para o passo inicial.
|
|
71
|
+
* Se `steps` for um array vazio, o método não faz nada.
|
|
72
|
+
* Se já houver um tour ativo, ele é encerrado (emitindo `stopped$` com `reason: 'interrupted'`)
|
|
73
|
+
* antes de o novo tour começar.
|
|
74
|
+
*
|
|
75
|
+
* @param steps Lista de passos a percorrer em ordem.
|
|
76
|
+
*/
|
|
77
|
+
start(steps: SpotlightStep[]): void;
|
|
78
|
+
/**
|
|
79
|
+
* Exibe um destaque simples (passo único) no elemento identificado por `stepId`.
|
|
80
|
+
*
|
|
81
|
+
* Equivalente a chamar `start()` com um array de um único passo.
|
|
82
|
+
* O checkbox "Não mostrar novamente" é exibido por padrão (`showDoNotShowAgain: true`);
|
|
83
|
+
* passe `showDoNotShowAgain: false` em `config` para suprimi-lo.
|
|
84
|
+
*
|
|
85
|
+
* @param stepId ID do elemento registrado via `sSpotlightStep` ou `registerElement`.
|
|
86
|
+
* @param config Configuração visual e comportamental do destaque.
|
|
87
|
+
*/
|
|
88
|
+
spotlight(stepId: string, config: SpotlightConfig): void;
|
|
89
|
+
/**
|
|
90
|
+
* Avança para o próximo passo do tour.
|
|
91
|
+
*
|
|
92
|
+
* Se o passo atual definir `beforeNext`, aguarda sua resolução antes de avançar.
|
|
93
|
+
* No último passo, encerra o tour com `reason: 'completed'`.
|
|
94
|
+
*
|
|
95
|
+
* @param doNotShowAgain Quando `true`, o evento `stopped$` será emitido com
|
|
96
|
+
* `doNotShowAgain: true` ao concluir o tour. Relevante apenas no último passo.
|
|
97
|
+
*/
|
|
98
|
+
next(doNotShowAgain?: boolean): void;
|
|
99
|
+
/**
|
|
100
|
+
* Retorna ao passo anterior do tour.
|
|
101
|
+
*
|
|
102
|
+
* Se o passo atual definir `beforePrevious`, aguarda sua resolução antes de voltar.
|
|
103
|
+
* Não faz nada se o tour estiver no primeiro passo.
|
|
104
|
+
*/
|
|
105
|
+
previous(): void;
|
|
106
|
+
/**
|
|
107
|
+
* Encerra o tour imediatamente e emite o evento `stopped$`.
|
|
108
|
+
*
|
|
109
|
+
* @param event Dados parciais do evento de parada. Valores não fornecidos são
|
|
110
|
+
* preenchidos com os defaults: `reason: 'interrupted'`, `doNotShowAgain: false`
|
|
111
|
+
* e o `stepId`/`stepIndex`/`totalSteps` do momento atual.
|
|
112
|
+
*/
|
|
113
|
+
stop(event?: Partial<SpotlightStopEvent>): void;
|
|
114
|
+
/**
|
|
115
|
+
* Registra um elemento do DOM como alvo do passo identificado por `stepId`.
|
|
116
|
+
*
|
|
117
|
+
* Normalmente chamado pela diretiva `sSpotlightStep`. Use diretamente apenas
|
|
118
|
+
* quando precisar registrar elementos criados programaticamente.
|
|
119
|
+
*
|
|
120
|
+
* @param stepId ID único do passo ao qual o elemento pertence.
|
|
121
|
+
* @param el Referência ao elemento do DOM.
|
|
122
|
+
*/
|
|
123
|
+
registerElement(stepId: string, el: ElementRef): void;
|
|
124
|
+
/**
|
|
125
|
+
* Remove o registro do elemento associado a `stepId`.
|
|
126
|
+
*
|
|
127
|
+
* Normalmente chamado pela diretiva `sSpotlightStep` no `ngOnDestroy`.
|
|
128
|
+
*
|
|
129
|
+
* @param stepId ID do passo cujo elemento deve ser removido.
|
|
130
|
+
*/
|
|
131
|
+
unregisterElement(stepId: string): void;
|
|
132
|
+
/**
|
|
133
|
+
* Retorna o `ElementRef` registrado para o `stepId` informado,
|
|
134
|
+
* ou `undefined` se nenhum elemento estiver registrado.
|
|
135
|
+
*
|
|
136
|
+
* @param stepId ID do passo a buscar.
|
|
137
|
+
*/
|
|
138
|
+
getElement(stepId: string): ElementRef | undefined;
|
|
139
|
+
private advance;
|
|
140
|
+
private retreat;
|
|
141
|
+
private attachOverlay;
|
|
142
|
+
private detachOverlay;
|
|
143
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SpotlightTourService, never>;
|
|
144
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<SpotlightTourService>;
|
|
145
|
+
}
|
|
146
|
+
export {};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { TemplateRef } from '@angular/core';
|
|
2
|
+
import { SpotlightPosition } from './types/spotlight-position';
|
|
3
|
+
import { SpotlightStepAction } from './types/spotlight-step';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/**
|
|
6
|
+
* Componente de popover do Spotlight.
|
|
7
|
+
*
|
|
8
|
+
* Exibe o card de destaque com título, mensagem, seta direcional, contador de passos,
|
|
9
|
+
* botões de navegação e, em modo simples (passo único), o checkbox "não mostrar novamente".
|
|
10
|
+
*
|
|
11
|
+
* Este componente é instanciado programaticamente pelo `SpotlightOverlayComponent`
|
|
12
|
+
* via CDK Overlay. Normalmente não é usado diretamente no template.
|
|
13
|
+
*/
|
|
14
|
+
export declare class SpotlightComponent {
|
|
15
|
+
/** Título do popover. Aceita string ou `TemplateRef` para conteúdo dinâmico. */
|
|
16
|
+
title: import("@angular/core").InputSignal<string | TemplateRef<any>>;
|
|
17
|
+
/** Mensagem principal do popover. Aceita string ou `TemplateRef` para conteúdo dinâmico. */
|
|
18
|
+
message: import("@angular/core").InputSignal<string | TemplateRef<any> | undefined>;
|
|
19
|
+
/** Template opcional para área de mídia/conteúdo customizado acima da mensagem. */
|
|
20
|
+
content: import("@angular/core").InputSignal<TemplateRef<any> | null>;
|
|
21
|
+
/** Posição do popover em relação ao elemento alvo. @default 'bottom-center' */
|
|
22
|
+
position: import("@angular/core").InputSignal<SpotlightPosition>;
|
|
23
|
+
/** Número do passo atual (1-based) exibido no contador. @default 1 */
|
|
24
|
+
currentStep: import("@angular/core").InputSignal<number>;
|
|
25
|
+
/** Total de passos do tour, usado no contador e para controle de botões. @default 1 */
|
|
26
|
+
totalSteps: import("@angular/core").InputSignal<number>;
|
|
27
|
+
/**
|
|
28
|
+
* Exibe o checkbox "não mostrar novamente" (apenas em passo único).
|
|
29
|
+
* Passe `false` para suprimir o checkbox quando não for necessário persistir a preferência.
|
|
30
|
+
* @default true
|
|
31
|
+
*/
|
|
32
|
+
showDoNotShowAgain: import("@angular/core").InputSignal<boolean>;
|
|
33
|
+
/** Lista de botões de ação adicionais exibidos na área de rodapé. */
|
|
34
|
+
actions: import("@angular/core").InputSignal<SpotlightStepAction[]>;
|
|
35
|
+
/**
|
|
36
|
+
* Deslocamento em pixels para posicionar a seta manualmente no eixo principal.
|
|
37
|
+
* Quando `null`, o alinhamento é controlado pela `position`. @default null
|
|
38
|
+
*/
|
|
39
|
+
arrowOffsetPx: import("@angular/core").InputSignal<number | null>;
|
|
40
|
+
/** Emitido ao clicar no botão de fechar (X). */
|
|
41
|
+
closed: import("@angular/core").OutputEmitterRef<void>;
|
|
42
|
+
/** Emitido ao clicar em "Próximo". */
|
|
43
|
+
next: import("@angular/core").OutputEmitterRef<void>;
|
|
44
|
+
/** Emitido ao clicar em "Voltar". */
|
|
45
|
+
previous: import("@angular/core").OutputEmitterRef<void>;
|
|
46
|
+
/** Emitido ao clicar em "Entendido" (modo simples, passo único). */
|
|
47
|
+
understand: import("@angular/core").OutputEmitterRef<void>;
|
|
48
|
+
/** Estado atual do checkbox "não mostrar novamente". */
|
|
49
|
+
isDoNotShowAgainChecked: import("@angular/core").WritableSignal<boolean>;
|
|
50
|
+
private static instanceCount;
|
|
51
|
+
/** @internal */
|
|
52
|
+
protected readonly instanceId: string;
|
|
53
|
+
/** @internal */
|
|
54
|
+
readonly titleId: string;
|
|
55
|
+
/** @internal */
|
|
56
|
+
readonly descId: string;
|
|
57
|
+
get titleTemplate(): TemplateRef<any> | null;
|
|
58
|
+
get titleString(): string;
|
|
59
|
+
get messageTemplate(): TemplateRef<any> | null;
|
|
60
|
+
get messageString(): string;
|
|
61
|
+
get arrowPosition(): SpotlightPosition;
|
|
62
|
+
get isArrowTop(): boolean;
|
|
63
|
+
get isArrowBottom(): boolean;
|
|
64
|
+
get isArrowLeft(): boolean;
|
|
65
|
+
get isArrowRight(): boolean;
|
|
66
|
+
get arrowRotation(): string;
|
|
67
|
+
get arrowAlignmentClass(): string;
|
|
68
|
+
get arrowPaddingStyle(): Record<string, string>;
|
|
69
|
+
/** Emite o evento `closed`. Chamado pelo botão de fechar no template. */
|
|
70
|
+
onClose(): void;
|
|
71
|
+
/** Emite o evento `next`. Chamado pelo botão "Próximo" no template. */
|
|
72
|
+
onNext(): void;
|
|
73
|
+
/** Emite o evento `previous`. Chamado pelo botão "Voltar" no template. */
|
|
74
|
+
onPrevious(): void;
|
|
75
|
+
/** Emite o evento `understand`. Chamado pelo botão "Entendido" no template. */
|
|
76
|
+
onUnderstand(): void;
|
|
77
|
+
/** Alterna o estado de `isDoNotShowAgainChecked`. */
|
|
78
|
+
toggleDoNotShowAgain(): void;
|
|
79
|
+
private getOppositeDirection;
|
|
80
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SpotlightComponent, never>;
|
|
81
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<SpotlightComponent, "s-spotlight", never, { "title": { "alias": "title"; "required": false; "isSignal": true; }; "message": { "alias": "message"; "required": false; "isSignal": true; }; "content": { "alias": "content"; "required": false; "isSignal": true; }; "position": { "alias": "position"; "required": false; "isSignal": true; }; "currentStep": { "alias": "currentStep"; "required": false; "isSignal": true; }; "totalSteps": { "alias": "totalSteps"; "required": false; "isSignal": true; }; "showDoNotShowAgain": { "alias": "showDoNotShowAgain"; "required": false; "isSignal": true; }; "actions": { "alias": "actions"; "required": false; "isSignal": true; }; "arrowOffsetPx": { "alias": "arrowOffsetPx"; "required": false; "isSignal": true; }; }, { "closed": "closed"; "next": "next"; "previous": "previous"; "understand": "understand"; }, never, never, true, never>;
|
|
82
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type SpotlightPosition = 'top-start' | 'top-center' | 'top-end' | 'right-start' | 'right-center' | 'right-end' | 'bottom-start' | 'bottom-center' | 'bottom-end' | 'left-start' | 'left-center' | 'left-end';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { TemplateRef } from '@angular/core';
|
|
2
|
+
import { SpotlightPosition } from './spotlight-position';
|
|
3
|
+
export interface SpotlightStepAction {
|
|
4
|
+
label: string;
|
|
5
|
+
handler: () => void;
|
|
6
|
+
}
|
|
7
|
+
export interface SpotlightStep {
|
|
8
|
+
stepId: string;
|
|
9
|
+
title: string | TemplateRef<any>;
|
|
10
|
+
message: string | TemplateRef<any>;
|
|
11
|
+
position?: SpotlightPosition;
|
|
12
|
+
content?: TemplateRef<any> | null;
|
|
13
|
+
actions?: SpotlightStepAction[];
|
|
14
|
+
showBackdrop?: boolean;
|
|
15
|
+
dismissible?: boolean;
|
|
16
|
+
beforeNext?: () => void | Promise<void>;
|
|
17
|
+
beforePrevious?: () => void | Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
export type SpotlightConfig = Omit<SpotlightStep, 'stepId' | 'beforeNext' | 'beforePrevious'> & {
|
|
20
|
+
showDoNotShowAgain?: boolean;
|
|
21
|
+
};
|