@seniorsistemas/angular-components 19.9.0 → 19.9.2

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 (35) hide show
  1. package/bignumber-input/lib/bignumber-input/bignumber-input.directive.d.ts +7 -1
  2. package/control-errors/lib/control-errors/control-errors.component.d.ts +11 -2
  3. package/esm2022/bignumber-input/lib/bignumber-input/bignumber-input.directive.mjs +8 -2
  4. package/esm2022/control-errors/lib/control-errors/control-errors.component.mjs +21 -1
  5. package/esm2022/drawer/lib/drawer/drawer.component.mjs +3 -3
  6. package/esm2022/dynamic-form/dynamic-form/form-field/fields/bignumber/bignumber-field.component.mjs +2 -2
  7. package/esm2022/inline-edit/lib/inline-edit/components/fields/inline-edit-number/inline-edit-number.component.mjs +1 -1
  8. package/esm2022/numeric-mask/lib/numeric-mask/numeric-mask.directive.mjs +62 -6
  9. package/esm2022/sidebar/public-api.mjs +12 -1
  10. package/esm2022/spotlight/lib/spotlight/spotlight-overlay/rect-stability.mjs +61 -0
  11. package/esm2022/spotlight/lib/spotlight/spotlight-overlay/spotlight-overlay.component.mjs +91 -21
  12. package/fesm2022/seniorsistemas-angular-components-bignumber-input.mjs +7 -1
  13. package/fesm2022/seniorsistemas-angular-components-bignumber-input.mjs.map +1 -1
  14. package/fesm2022/seniorsistemas-angular-components-control-errors.mjs +20 -0
  15. package/fesm2022/seniorsistemas-angular-components-control-errors.mjs.map +1 -1
  16. package/fesm2022/seniorsistemas-angular-components-drawer.mjs +2 -2
  17. package/fesm2022/seniorsistemas-angular-components-drawer.mjs.map +1 -1
  18. package/fesm2022/seniorsistemas-angular-components-dynamic-form.mjs +1 -1
  19. package/fesm2022/seniorsistemas-angular-components-dynamic-form.mjs.map +1 -1
  20. package/fesm2022/seniorsistemas-angular-components-inline-edit.mjs +1 -1
  21. package/fesm2022/seniorsistemas-angular-components-inline-edit.mjs.map +1 -1
  22. package/fesm2022/seniorsistemas-angular-components-numeric-mask.mjs +61 -5
  23. package/fesm2022/seniorsistemas-angular-components-numeric-mask.mjs.map +1 -1
  24. package/fesm2022/seniorsistemas-angular-components-sidebar.mjs +12 -1
  25. package/fesm2022/seniorsistemas-angular-components-sidebar.mjs.map +1 -1
  26. package/fesm2022/seniorsistemas-angular-components-spotlight.mjs +150 -20
  27. package/fesm2022/seniorsistemas-angular-components-spotlight.mjs.map +1 -1
  28. package/numeric-mask/README.md +164 -60
  29. package/numeric-mask/lib/numeric-mask/numeric-mask.directive.d.ts +29 -2
  30. package/package.json +13 -13
  31. package/sidebar/README.md +3 -3
  32. package/sidebar/public-api.d.ts +10 -0
  33. package/spotlight/README.md +28 -0
  34. package/spotlight/lib/spotlight/spotlight-overlay/rect-stability.d.ts +32 -0
  35. package/spotlight/lib/spotlight/spotlight-overlay/spotlight-overlay.component.d.ts +33 -0
@@ -22,11 +22,11 @@ Diretiva Angular para formatação de valores numéricos em campos de input com
22
22
  import { NumericMaskDirective } from '@seniorsistemas/angular-components/numeric-mask';
23
23
 
24
24
  @Component({
25
- standalone: true,
26
- imports: [NumericMaskDirective, FormsModule],
25
+ standalone: true,
26
+ imports: [NumericMaskDirective, FormsModule],
27
27
  })
28
28
  export class MeuComponent {
29
- valor: string | null = null;
29
+ valor: string | null = null;
30
30
  }
31
31
  ```
32
32
 
@@ -34,12 +34,12 @@ export class MeuComponent {
34
34
 
35
35
  ```html
36
36
  <input
37
- type="text"
38
- sNumericMask
39
- [locale]="'pt-BR'"
40
- [minDecimalPlaces]="2"
41
- [maxDecimalPlaces]="2"
42
- [(ngModel)]="valor"
37
+ type="text"
38
+ sNumericMask
39
+ [locale]="'pt-BR'"
40
+ [minDecimalPlaces]="2"
41
+ [maxDecimalPlaces]="2"
42
+ [(ngModel)]="valor"
43
43
  />
44
44
  ```
45
45
 
@@ -47,15 +47,17 @@ export class MeuComponent {
47
47
 
48
48
  ### Inputs
49
49
 
50
- | Propriedade | Tipo | Padrão | Obrigatório | Descrição |
51
- |-------------|------|--------|:-----------:|-----------|
52
- | `locale` | `string \| undefined` | Locale do `LocaleService` | Não | Locale para formatação (ex: `'pt-BR'`, `'en-US'`). Se omitido, usa o locale do `LocaleService` |
53
- | `minDecimalPlaces` | `number` | `0` | Não | Número mínimo de casas decimais a exibir |
54
- | `maxDecimalPlaces` | `number` | `10` | Não | Número máximo de casas decimais permitidas |
55
- | `allowNegative` | `boolean` | `false` | Não | Permite valores negativos. Use as teclas `+` ou `-` para alternar o sinal |
56
- | `allowScientificNotation` | `boolean` | `true` | Não | Habilita suporte a notação científica (ex: `1.5e10`) |
57
- | `min` | `number \| undefined` | `undefined` | Não | Valor mínimo permitido (validação de formulário) |
58
- | `max` | `number \| undefined` | `undefined` | Não | Valor máximo permitido (validação de formulário) |
50
+ | Propriedade | Tipo | Padrão | Obrigatório | Descrição |
51
+ | ------------------------- | ------------------------------------------------------ | ------------------------- | :---------: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
52
+ | `locale` | `string \| undefined` | Locale do `LocaleService` | Não | Locale para formatação (ex: `'pt-BR'`, `'en-US'`). Se omitido, usa o locale do `LocaleService` |
53
+ | `minDecimalPlaces` | `number` | `0` | Não | Número mínimo de casas decimais a exibir |
54
+ | `maxDecimalPlaces` | `number` | `10` | Não | Número máximo de casas decimais permitidas |
55
+ | `allowNegative` | `boolean` | `false` | Não | Permite valores negativos. Use as teclas `+` ou `-` para alternar o sinal |
56
+ | `allowScientificNotation` | `boolean` | `true` | Não | Habilita suporte a notação científica (ex: `1.5e10`) |
57
+ | `min` | `number \| undefined` | `undefined` | Não | Valor mínimo permitido (validação de formulário) |
58
+ | `max` | `number \| undefined` | `undefined` | Não | Valor máximo permitido (validação de formulário) |
59
+ | `blockDecimalOverflow` | `boolean` | `true` | Não | Bloqueia a digitação e a colagem de casas decimais além de `maxDecimalPlaces`. Quando `maxDecimalPlaces` é `0`, o próprio separador decimal não pode ser digitado |
60
+ | `decimalRoundingMode` | `'preserve' \| 'truncate' \| 'roundUp' \| 'roundDown'` | `'preserve'` | Não | Estratégia aplicada no `blur` quando `blockDecimalOverflow` é `false`. Sem efeito enquanto `blockDecimalOverflow` for `true` |
59
61
 
60
62
  ### Tipos
61
63
 
@@ -69,16 +71,96 @@ type NumericMaskModelValue = string | null;
69
71
 
70
72
  ```typescript
71
73
  // Valor negativo quando allowNegative = false
72
- { negativeNotAllowed: true }
74
+ {
75
+ negativeNotAllowed: true;
76
+ }
73
77
 
74
78
  // Valor abaixo do mínimo
75
- { min: { min: number; actual: number } }
79
+ {
80
+ min: {
81
+ min: number;
82
+ actual: number;
83
+ }
84
+ }
76
85
 
77
86
  // Valor acima do máximo
78
- { max: { max: number; actual: number } }
87
+ {
88
+ max: {
89
+ max: number;
90
+ actual: number;
91
+ }
92
+ }
79
93
 
80
94
  // Casas decimais acima do máximo
81
- { excessiveDecimalPlaces: { max: number; actual: number } }
95
+ {
96
+ excessiveDecimalPlaces: {
97
+ max: number;
98
+ actual: number;
99
+ }
100
+ }
101
+ ```
102
+
103
+ ## Comportamento de excesso de casas decimais
104
+
105
+ Por padrão (`blockDecimalOverflow = true`), a digitação e a colagem de valores com mais casas decimais que `maxDecimalPlaces` são bloqueadas no momento da entrada: dígitos excedentes são ignorados imediatamente (sem esperar o `blur`) e, quando `maxDecimalPlaces` é `0`, o próprio separador decimal não pode ser digitado.
106
+
107
+ Desligando o bloqueio (`[blockDecimalOverflow]="false"`), a digitação volta a ser livre e o input `decimalRoundingMode` passa a controlar o que acontece ao perder o foco (`blur`):
108
+
109
+ | `decimalRoundingMode` | Comportamento no `blur` |
110
+ | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
111
+ | `'preserve'` (padrão) | Comportamento legado: a exibição é truncada, mas o modelo mantém a precisão total do que foi digitado |
112
+ | `'truncate'` | Corta as casas excedentes tanto na exibição quanto no modelo, sem arredondar (sempre em direção a zero) |
113
+ | `'roundUp'` | Arredonda sempre para o próximo valor representável **acima** (ceiling), mesmo que o excedente seja mínimo — não é arredondamento para o valor mais próximo |
114
+ | `'roundDown'` | Arredonda sempre para o próximo valor representável **abaixo** (floor), pelo mesmo motivo |
115
+
116
+ ```html
117
+ <!-- Padrão: bloqueia a digitação acima de 2 casas decimais -->
118
+ <input
119
+ type="text"
120
+ sNumericMask
121
+ [maxDecimalPlaces]="2"
122
+ [(ngModel)]="valor"
123
+ />
124
+
125
+ <!-- Comportamento legado explícito (digitação livre, modelo com precisão total) -->
126
+ <input
127
+ type="text"
128
+ sNumericMask
129
+ [maxDecimalPlaces]="2"
130
+ [blockDecimalOverflow]="false"
131
+ decimalRoundingMode="preserve"
132
+ [(ngModel)]="valor"
133
+ />
134
+
135
+ <!-- Trunca no blur (corta sem arredondar) -->
136
+ <input
137
+ type="text"
138
+ sNumericMask
139
+ [maxDecimalPlaces]="2"
140
+ [blockDecimalOverflow]="false"
141
+ decimalRoundingMode="truncate"
142
+ [(ngModel)]="valor"
143
+ />
144
+
145
+ <!-- Arredonda sempre para cima no blur -->
146
+ <input
147
+ type="text"
148
+ sNumericMask
149
+ [maxDecimalPlaces]="2"
150
+ [blockDecimalOverflow]="false"
151
+ decimalRoundingMode="roundUp"
152
+ [(ngModel)]="valor"
153
+ />
154
+
155
+ <!-- Arredonda sempre para baixo no blur -->
156
+ <input
157
+ type="text"
158
+ sNumericMask
159
+ [maxDecimalPlaces]="2"
160
+ [blockDecimalOverflow]="false"
161
+ decimalRoundingMode="roundDown"
162
+ [(ngModel)]="valor"
163
+ />
82
164
  ```
83
165
 
84
166
  ## Exemplos
@@ -87,13 +169,13 @@ type NumericMaskModelValue = string | null;
87
169
 
88
170
  ```html
89
171
  <input
90
- type="text"
91
- sNumericMask
92
- locale="pt-BR"
93
- [minDecimalPlaces]="2"
94
- [maxDecimalPlaces]="2"
95
- placeholder="0,00"
96
- [(ngModel)]="valorMonetario"
172
+ type="text"
173
+ sNumericMask
174
+ locale="pt-BR"
175
+ [minDecimalPlaces]="2"
176
+ [maxDecimalPlaces]="2"
177
+ placeholder="0,00"
178
+ [(ngModel)]="valorMonetario"
97
179
  />
98
180
  ```
99
181
 
@@ -101,14 +183,14 @@ type NumericMaskModelValue = string | null;
101
183
 
102
184
  ```html
103
185
  <input
104
- type="text"
105
- sNumericMask
106
- locale="pt-BR"
107
- [minDecimalPlaces]="2"
108
- [maxDecimalPlaces]="2"
109
- [allowNegative]="true"
110
- placeholder="-0,00"
111
- [(ngModel)]="variacao"
186
+ type="text"
187
+ sNumericMask
188
+ locale="pt-BR"
189
+ [minDecimalPlaces]="2"
190
+ [maxDecimalPlaces]="2"
191
+ [allowNegative]="true"
192
+ placeholder="-0,00"
193
+ [(ngModel)]="variacao"
112
194
  />
113
195
  <!-- Pressione + ou - para alternar entre positivo e negativo -->
114
196
  ```
@@ -117,15 +199,15 @@ type NumericMaskModelValue = string | null;
117
199
 
118
200
  ```html
119
201
  <input
120
- type="text"
121
- sNumericMask
122
- locale="pt-BR"
123
- [minDecimalPlaces]="2"
124
- [maxDecimalPlaces]="2"
125
- [min]="0"
126
- [max]="100"
127
- placeholder="0,00"
128
- [(ngModel)]="percentual"
202
+ type="text"
203
+ sNumericMask
204
+ locale="pt-BR"
205
+ [minDecimalPlaces]="2"
206
+ [maxDecimalPlaces]="2"
207
+ [min]="0"
208
+ [max]="100"
209
+ placeholder="0,00"
210
+ [(ngModel)]="percentual"
129
211
  />
130
212
  ```
131
213
 
@@ -133,13 +215,13 @@ type NumericMaskModelValue = string | null;
133
215
 
134
216
  ```html
135
217
  <input
136
- type="text"
137
- sNumericMask
138
- locale="en-US"
139
- [minDecimalPlaces]="2"
140
- [maxDecimalPlaces]="2"
141
- placeholder="0.00"
142
- [(ngModel)]="valor"
218
+ type="text"
219
+ sNumericMask
220
+ locale="en-US"
221
+ [minDecimalPlaces]="2"
222
+ [maxDecimalPlaces]="2"
223
+ placeholder="0.00"
224
+ [(ngModel)]="valor"
143
225
  />
144
226
  ```
145
227
 
@@ -147,13 +229,13 @@ type NumericMaskModelValue = string | null;
147
229
 
148
230
  ```html
149
231
  <input
150
- type="text"
151
- sNumericMask
152
- locale="pt-BR"
153
- [minDecimalPlaces]="0"
154
- [maxDecimalPlaces]="4"
155
- placeholder="0"
156
- [(ngModel)]="quantidade"
232
+ type="text"
233
+ sNumericMask
234
+ locale="pt-BR"
235
+ [minDecimalPlaces]="0"
236
+ [maxDecimalPlaces]="4"
237
+ placeholder="0"
238
+ [(ngModel)]="quantidade"
157
239
  />
158
240
  ```
159
241
 
@@ -168,3 +250,25 @@ type NumericMaskModelValue = string | null;
168
250
 
169
251
  - [`NumericPipe`](../numeric/README.md) — formatação de valores numéricos para exibição somente leitura
170
252
  - [`NumberInput`](../number-input/src/lib/number-input/README.md) — diretiva descontinuada, use `sNumericMask` em seu lugar
253
+
254
+ ## Migração
255
+
256
+ ### Mudança de comportamento padrão
257
+
258
+ A partir desta versão, `blockDecimalOverflow` passa a ser `true` por padrão: a digitação e a colagem de valores com mais casas decimais que `maxDecimalPlaces` passam a ser bloqueadas no momento da entrada, em vez de aceitas livremente e truncadas apenas na exibição ao perder o foco.
259
+
260
+ Para restaurar o comportamento anterior (digitação livre, modelo com precisão total, exibição truncada no `blur`):
261
+
262
+ ```html
263
+ <input
264
+ type="text"
265
+ sNumericMask
266
+ [maxDecimalPlaces]="2"
267
+ [blockDecimalOverflow]="false"
268
+ decimalRoundingMode="preserve"
269
+ [(ngModel)]="valor"
270
+ />
271
+ ```
272
+
273
+ `decimalRoundingMode="preserve"` já é o padrão — pode ser omitido, mas deixá-lo explícito reforça a intenção do comportamento legado.
274
+
@@ -56,6 +56,22 @@ export declare class NumericMaskDirective implements OnInit, OnChanges, ControlV
56
56
  * Maximum value allowed
57
57
  */
58
58
  max: import("@angular/core").InputSignal<number | undefined>;
59
+ /**
60
+ * Blocks typing/pasting decimal digits beyond maxDecimalPlaces.
61
+ * When maxDecimalPlaces is 0, the decimal separator itself cannot be entered.
62
+ * @default true
63
+ */
64
+ blockDecimalOverflow: import("@angular/core").InputSignal<boolean>;
65
+ /**
66
+ * Strategy applied on blur when blockDecimalOverflow is false.
67
+ * 'preserve' keeps the model at full precision; only the display is truncated (legacy behavior).
68
+ * 'truncate' cuts the excess decimals without rounding (towards zero), updating the model too.
69
+ * 'roundUp' always rounds to the next representable value above (ceiling), updating the model too.
70
+ * 'roundDown' always rounds to the next representable value below (floor), updating the model too.
71
+ * Has no effect while blockDecimalOverflow is true.
72
+ * @default 'preserve'
73
+ */
74
+ decimalRoundingMode: import("@angular/core").InputSignal<"preserve" | "truncate" | "roundUp" | "roundDown">;
59
75
  private readonly elementRef;
60
76
  private readonly renderer;
61
77
  private readonly localeService;
@@ -127,10 +143,21 @@ export declare class NumericMaskDirective implements OnInit, OnChanges, ControlV
127
143
  */
128
144
  private escapeRegex;
129
145
  /**
130
- * Truncates a number to the specified decimal places (never rounds)
146
+ * Truncates (or rounds, depending on roundingMode) a number to the specified decimal places
131
147
  * @private
132
148
  */
133
149
  private truncateToDecimalPlaces;
150
+ /**
151
+ * Maps decimalRoundingMode to the corresponding BigNumber rounding mode
152
+ * @private
153
+ */
154
+ private resolveRoundingMode;
155
+ /**
156
+ * Limits the decimal part of a value being typed/pasted to maxDecimalPlaces,
157
+ * preserving any scientific notation exponent untouched
158
+ * @private
159
+ */
160
+ private applyBlockLimit;
134
161
  /**
135
162
  * Parses a string value to its numeric representation, handling separators and sign
136
163
  * Returns BigNumber to preserve full precision and optional number conversion
@@ -172,5 +199,5 @@ export declare class NumericMaskDirective implements OnInit, OnChanges, ControlV
172
199
  setDisabledState(isDisabled: boolean): void;
173
200
  validate(control: AbstractControl): ValidationErrors | null;
174
201
  static ɵfac: i0.ɵɵFactoryDeclaration<NumericMaskDirective, never>;
175
- static ɵdir: i0.ɵɵDirectiveDeclaration<NumericMaskDirective, "[sNumericMask]", never, { "locale": { "alias": "locale"; "required": false; "isSignal": true; }; "minDecimalPlaces": { "alias": "minDecimalPlaces"; "required": false; "isSignal": true; }; "maxDecimalPlaces": { "alias": "maxDecimalPlaces"; "required": false; "isSignal": true; }; "allowNegative": { "alias": "allowNegative"; "required": false; "isSignal": true; }; "allowScientificNotation": { "alias": "allowScientificNotation"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "decimalSeparator": { "alias": "decimalSeparator"; "required": false; "isSignal": true; }; "thousandSeparator": { "alias": "thousandSeparator"; "required": false; "isSignal": true; }; }, { "decimalSeparator": "decimalSeparatorChange"; "thousandSeparator": "thousandSeparatorChange"; }, never, never, true, never>;
202
+ static ɵdir: i0.ɵɵDirectiveDeclaration<NumericMaskDirective, "[sNumericMask]", never, { "locale": { "alias": "locale"; "required": false; "isSignal": true; }; "minDecimalPlaces": { "alias": "minDecimalPlaces"; "required": false; "isSignal": true; }; "maxDecimalPlaces": { "alias": "maxDecimalPlaces"; "required": false; "isSignal": true; }; "allowNegative": { "alias": "allowNegative"; "required": false; "isSignal": true; }; "allowScientificNotation": { "alias": "allowScientificNotation"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "max": { "alias": "max"; "required": false; "isSignal": true; }; "blockDecimalOverflow": { "alias": "blockDecimalOverflow"; "required": false; "isSignal": true; }; "decimalRoundingMode": { "alias": "decimalRoundingMode"; "required": false; "isSignal": true; }; "decimalSeparator": { "alias": "decimalSeparator"; "required": false; "isSignal": true; }; "thousandSeparator": { "alias": "thousandSeparator"; "required": false; "isSignal": true; }; }, { "decimalSeparator": "decimalSeparatorChange"; "thousandSeparator": "thousandSeparatorChange"; }, never, never, true, never>;
176
203
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seniorsistemas/angular-components",
3
- "version": "19.9.0",
3
+ "version": "19.9.2",
4
4
  "peerDependencies": {
5
5
  "@angular/cdk": "^18.2.14",
6
6
  "@angular/common": "^18.2.0",
@@ -97,36 +97,36 @@
97
97
  "esm": "./esm2022/accordion/seniorsistemas-angular-components-accordion.mjs",
98
98
  "default": "./fesm2022/seniorsistemas-angular-components-accordion.mjs"
99
99
  },
100
- "./autocomplete": {
101
- "types": "./autocomplete/index.d.ts",
102
- "esm2022": "./esm2022/autocomplete/seniorsistemas-angular-components-autocomplete.mjs",
103
- "esm": "./esm2022/autocomplete/seniorsistemas-angular-components-autocomplete.mjs",
104
- "default": "./fesm2022/seniorsistemas-angular-components-autocomplete.mjs"
105
- },
106
100
  "./alert": {
107
101
  "types": "./alert/index.d.ts",
108
102
  "esm2022": "./esm2022/alert/seniorsistemas-angular-components-alert.mjs",
109
103
  "esm": "./esm2022/alert/seniorsistemas-angular-components-alert.mjs",
110
104
  "default": "./fesm2022/seniorsistemas-angular-components-alert.mjs"
111
105
  },
106
+ "./autocomplete": {
107
+ "types": "./autocomplete/index.d.ts",
108
+ "esm2022": "./esm2022/autocomplete/seniorsistemas-angular-components-autocomplete.mjs",
109
+ "esm": "./esm2022/autocomplete/seniorsistemas-angular-components-autocomplete.mjs",
110
+ "default": "./fesm2022/seniorsistemas-angular-components-autocomplete.mjs"
111
+ },
112
112
  "./badge": {
113
113
  "types": "./badge/index.d.ts",
114
114
  "esm2022": "./esm2022/badge/seniorsistemas-angular-components-badge.mjs",
115
115
  "esm": "./esm2022/badge/seniorsistemas-angular-components-badge.mjs",
116
116
  "default": "./fesm2022/seniorsistemas-angular-components-badge.mjs"
117
117
  },
118
- "./bignumber-input": {
119
- "types": "./bignumber-input/index.d.ts",
120
- "esm2022": "./esm2022/bignumber-input/seniorsistemas-angular-components-bignumber-input.mjs",
121
- "esm": "./esm2022/bignumber-input/seniorsistemas-angular-components-bignumber-input.mjs",
122
- "default": "./fesm2022/seniorsistemas-angular-components-bignumber-input.mjs"
123
- },
124
118
  "./breadcrumb": {
125
119
  "types": "./breadcrumb/index.d.ts",
126
120
  "esm2022": "./esm2022/breadcrumb/seniorsistemas-angular-components-breadcrumb.mjs",
127
121
  "esm": "./esm2022/breadcrumb/seniorsistemas-angular-components-breadcrumb.mjs",
128
122
  "default": "./fesm2022/seniorsistemas-angular-components-breadcrumb.mjs"
129
123
  },
124
+ "./bignumber-input": {
125
+ "types": "./bignumber-input/index.d.ts",
126
+ "esm2022": "./esm2022/bignumber-input/seniorsistemas-angular-components-bignumber-input.mjs",
127
+ "esm": "./esm2022/bignumber-input/seniorsistemas-angular-components-bignumber-input.mjs",
128
+ "default": "./fesm2022/seniorsistemas-angular-components-bignumber-input.mjs"
129
+ },
130
130
  "./button": {
131
131
  "types": "./button/index.d.ts",
132
132
  "esm2022": "./esm2022/button/seniorsistemas-angular-components-button.mjs",
package/sidebar/README.md CHANGED
@@ -4,11 +4,11 @@
4
4
 
5
5
  > **Descontinuado** — Este pacote é um alias de compatibilidade para o componente `Drawer` e será removido na versão 20.0.0.
6
6
 
7
- O pacote `sidebar` re-exporta `DrawerComponent` e `DrawerModule` do pacote `@seniorsistemas/angular-components/drawer`.
7
+ O pacote `sidebar` re-exporta `DrawerComponent` e `DrawerModule` do pacote `@seniorsistemas/angular-components/drawer` — tanto sob os nomes novos (`DrawerComponent`/`DrawerModule`) quanto sob os nomes antigos (`SidebarComponent`/`SidebarModule`), para manter compatibilidade com quem já importava por qualquer um dos dois nomes a partir deste pacote.
8
8
 
9
9
  ## Quando usar
10
10
 
11
- - Apenas para manutenção de código legado que já usa `DrawerComponent` ou `DrawerModule` a partir deste pacote
11
+ - Apenas para manutenção de código legado que já usa `SidebarComponent`/`SidebarModule` (ou `DrawerComponent`/`DrawerModule`) a partir deste pacote
12
12
 
13
13
  ## Quando não usar
14
14
 
@@ -18,7 +18,7 @@ O pacote `sidebar` re-exporta `DrawerComponent` e `DrawerModule` do pacote `@sen
18
18
 
19
19
  ```typescript
20
20
  // Antes (descontinuado)
21
- import { DrawerModule } from '@seniorsistemas/angular-components/sidebar';
21
+ import { SidebarModule } from '@seniorsistemas/angular-components/sidebar';
22
22
 
23
23
  // Depois (recomendado)
24
24
  import { DrawerModule } from '@seniorsistemas/angular-components/drawer';
@@ -9,3 +9,13 @@ export declare const DrawerComponent: typeof DrawerComponentOriginal;
9
9
  * O pacote sidebar será removido na versão 20.0.0.
10
10
  */
11
11
  export declare const DrawerModule: typeof DrawerModuleOriginal;
12
+ /**
13
+ * @deprecated Use DrawerComponent from '@seniorsistemas/angular-components/drawer'.
14
+ * O pacote sidebar será removido na versão 20.0.0.
15
+ */
16
+ export declare const SidebarComponent: typeof DrawerComponentOriginal;
17
+ /**
18
+ * @deprecated Use DrawerModule from '@seniorsistemas/angular-components/drawer'.
19
+ * O pacote sidebar será removido na versão 20.0.0.
20
+ */
21
+ export declare const SidebarModule: typeof DrawerModuleOriginal;
@@ -88,6 +88,32 @@ this.tourService.start([
88
88
  | `previous` | `OutputEmitterRef<void>` | Emitido ao clicar em "Voltar" |
89
89
  | `understand` | `OutputEmitterRef<void>` | Emitido ao clicar em "Entendido" (modo simples) |
90
90
 
91
+ ### Hooks `beforeNext` / `beforePrevious`
92
+
93
+ Cada passo pode definir `beforeNext?: () => void | Promise<void>` e `beforePrevious?: () => void | Promise<void>`, executados antes de avançar/retroceder. Se retornarem uma `Promise`, o Spotlight aguarda sua resolução antes de trocar de passo.
94
+
95
+ Isso é útil quando o próximo passo aponta para um elemento que só existe (ou só chega à posição final) depois de uma ação disparada pelo `beforeNext` — por exemplo, abrir um menu ou uma aba:
96
+
97
+ ```typescript
98
+ this.tourService.start([
99
+ {
100
+ stepId: 'abrir-menu',
101
+ title: 'Abra o menu',
102
+ message: 'Clique aqui para abrir as opções.',
103
+ beforeNext: () => this.menuService.open(), // abre um menu com animação CSS
104
+ },
105
+ {
106
+ stepId: 'item-do-menu', // elemento dentro do menu recém-aberto
107
+ title: 'Selecione aqui',
108
+ message: 'Este item concentra as opções mais usadas.',
109
+ },
110
+ ]);
111
+ ```
112
+
113
+ **Não é necessário esperar manualmente a animação terminar.** O Spotlight aguarda internamente até que a posição do elemento-alvo do próximo passo se estabilize, tolerando transições CSS típicas de abertura de menus, abas e painéis. Não adicione `setTimeout`/delays artificiais dentro de `beforeNext` — eles são redundantes e, no melhor caso, apenas adicionam espera desnecessária.
114
+
115
+ Se o elemento do próximo passo ainda não existir no DOM no momento da troca (por exemplo, criado dinamicamente pelo `beforeNext` via `@if`/troca de aba), o Spotlight aguarda brevemente pelo registro automático via `[sSpotlightStep]` antes de recorrer a um popover centralizado sem destaque. Em ambos os casos de espera esgotada, um aviso é emitido no console citando o `stepId` — útil para diagnosticar um `stepId` incorreto ou uma animação anormalmente longa.
116
+
91
117
  ### Tipos
92
118
 
93
119
  ```typescript
@@ -105,6 +131,8 @@ interface SpotlightStep {
105
131
  showDoNotShowAgain?: boolean;
106
132
  dismissible?: boolean;
107
133
  actions?: SpotlightStepAction[];
134
+ beforeNext?: () => void | Promise<void>;
135
+ beforePrevious?: () => void | Promise<void>;
108
136
  }
109
137
 
110
138
  interface SpotlightStepAction {
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Utilitário puro (sem dependência de Angular/NgZone) para aguardar até que a posição
3
+ * e o tamanho de um elemento parem de mudar — usado para medir corretamente elementos
4
+ * que podem estar em transição/animação (ex: um menu abrindo) no momento em que o
5
+ * Spotlight precisa apontar para eles.
6
+ */
7
+ export interface RectStabilityOptions {
8
+ /** Quantas amostras consecutivas dentro da tolerância definem "estável". */
9
+ requiredStableSamples: number;
10
+ /** Diferença máxima (px) entre duas amostras para serem consideradas iguais. */
11
+ tolerancePx: number;
12
+ /** Teto de segurança (ms) — nunca esperar além disso. */
13
+ maxWaitMs: number;
14
+ }
15
+ export declare const DEFAULT_RECT_STABILITY_OPTIONS: RectStabilityOptions;
16
+ export interface StableRectResult {
17
+ rect: DOMRect;
18
+ timedOut: boolean;
19
+ }
20
+ export interface StabilizeHandle {
21
+ readonly promise: Promise<StableRectResult>;
22
+ cancel(): void;
23
+ }
24
+ /**
25
+ * Faz polling de `el.getBoundingClientRect()` em frames sucessivos até que
26
+ * `requiredStableSamples` amostras consecutivas sejam iguais (dentro de `tolerancePx`),
27
+ * ou até que `maxWaitMs` seja atingido — o que ocorrer primeiro.
28
+ *
29
+ * `scheduleFrame`/`cancelFrame`/`now` são injetáveis para permitir testes determinísticos;
30
+ * por padrão usam as APIs nativas do navegador.
31
+ */
32
+ export declare function waitForStableRect(el: HTMLElement, options?: RectStabilityOptions, scheduleFrame?: (cb: FrameRequestCallback) => number, cancelFrame?: (handle: number) => void, now?: () => number): StabilizeHandle;
@@ -20,6 +20,13 @@ export declare class SpotlightOverlayComponent implements OnInit, OnDestroy {
20
20
  readonly totalSteps: import("@angular/core").Signal<number>;
21
21
  /** @internal*/
22
22
  readonly targetRect: import("@angular/core").WritableSignal<DOMRect | null>;
23
+ /**
24
+ * Controla se a máscara deve animar a transição entre retângulos (reposicionamento
25
+ * em vivo, ex: scroll/resize) ou saltar instantaneamente (chegada/saída de um passo).
26
+ * Ver `setTargetRectImmediate`.
27
+ */
28
+ private readonly maskTransitionEnabled;
29
+ private readonly maskTransitionStyle;
23
30
  /** @internal */
24
31
  readonly topMaskStyle: import("@angular/core").Signal<Record<string, string>>;
25
32
  /** @internal */
@@ -36,7 +43,25 @@ export declare class SpotlightOverlayComponent implements OnInit, OnDestroy {
36
43
  private popoverSubs;
37
44
  private focusTrap;
38
45
  private previouslyFocusedElement;
46
+ private pendingArrival;
47
+ private elementWaitTimerId;
48
+ private stabilizeGeneration;
39
49
  constructor();
50
+ /**
51
+ * Aguarda o layout do elemento-alvo estabilizar (ex: animação de abertura de um menu
52
+ * disparada pelo `beforeNext` do passo anterior) antes de medir sua posição definitiva
53
+ * e posicionar a máscara/popover. Substitui a antiga espera de um único frame, que
54
+ * capturava o retângulo no meio de animações de terceiros na tela.
55
+ */
56
+ private beginArrivalSequence;
57
+ /**
58
+ * Aguarda até `ELEMENT_WAIT_TIMEOUT_MS` pelo registro do elemento-alvo via
59
+ * `[sSpotlightStep]` (útil quando o `beforeNext` do passo anterior cria o elemento
60
+ * dinamicamente, ex: abrindo uma aba) antes de recorrer ao popover centralizado.
61
+ * Mantém o último quadro renderizado durante a espera para evitar um flash.
62
+ */
63
+ private awaitElementRegistration;
64
+ private cancelPendingArrival;
40
65
  ngOnInit(): void;
41
66
  ngOnDestroy(): void;
42
67
  /** @internal */
@@ -62,6 +87,14 @@ export declare class SpotlightOverlayComponent implements OnInit, OnDestroy {
62
87
  private syncDirectionAndArrow;
63
88
  private destroyPopoverOverlay;
64
89
  private updateTargetRect;
90
+ /**
91
+ * Aplica um novo `targetRect` sem animação de transição na máscara — usado ao
92
+ * chegar/saltar para um alvo novo, onde animar a partir da posição do passo
93
+ * anterior criaria a falsa impressão de "apontou errado e corrigiu depois".
94
+ * A transição é reabilitada no frame seguinte para reposicionamentos legítimos
95
+ * (scroll/resize de um alvo já visível).
96
+ */
97
+ private setTargetRectImmediate;
65
98
  private refreshRect;
66
99
  private observeElement;
67
100
  private disconnectResizeObserver;