@scania-nl/tegel-angular-extensions 0.0.5 → 0.0.7

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/README.md CHANGED
@@ -21,7 +21,8 @@ Provides simple wrappers for toast and modal (TBC) functionality using Angular 1
21
21
  - Drop-in UI integrations for Tegel Angular
22
22
  - Signal-based `ToastService` for displaying toasts
23
23
  - Customizable toast appearance and behavior
24
- 3. **Default Nginx config**
24
+ 3. **Standalone components and directives**
25
+ 4. **Default Nginx config**
25
26
 
26
27
  - Zero boilerplate - no Angular modules required
27
28
  - Fully typed and configurable via DI
@@ -33,27 +34,33 @@ Provides simple wrappers for toast and modal (TBC) functionality using Angular 1
33
34
 
34
35
  1. [Installation](#-installation)
35
36
  2. [Environment Configuration Overview](#-environment-configuration-overview)
36
- 2.1. [Defining your schema with createEnvKit](#defining-your-schema-with-createenvkit)
37
- 2.2. [Defining Static Environments (Dev/Prod)](#defining-static-environments-devprod)
38
- 2.3. [Providing Runtime Configuration](#providing-runtime-configuration)
39
- 2.4. [Using the ENV_CONFIG Token](#using-the-env_config-token)
40
- 2.5. [Runtime Configuration Binaries](#runtime-configuration-binaries)
41
-     2.5.1. [`docker-entrypoint.sh`](#docker-entrypointsh)
42
-     2.5.2. [`extract-env-vars.sh`](#extract-env-varssh)
43
-     2.5.3. [`nginx.conf`](#nginxconf)
44
-     2.5.4. [Example Docker Commands](#example-docker-commands)
37
+ 1. [Defining your schema with createEnvKit](#defining-your-schema-with-createenvkit)
38
+ 2. [Defining Static Environments (Dev/Prod)](#defining-static-environments-devprod)
39
+ 3. [Providing Runtime Configuration](#providing-runtime-configuration)
40
+ 4. [Using the ENV_CONFIG Token](#using-the-env_config-token)
41
+ 5. [Runtime Configuration Binaries](#runtime-configuration-binaries)
42
+ 1. [`docker-entrypoint.sh`](#docker-entrypointsh)
43
+ 2. [`extract-env-vars.sh`](#extract-env-varssh)
44
+ 3. [`nginx.conf`](#nginxconf)
45
+ 4. [Example Docker Commands](#example-docker-commands)
45
46
  3. [Toasts](#-toasts)
46
- 3.1. [Quick Start](#-quick-start)
47
-     3.1.1. [Add Providers](#add-providers)
48
-     3.1.2. [Use in components](#use-in-components)
49
- 3.2. [Configuration Options](#️-configuration-options)
50
- 3.3. [ToastService API](#-toastservice-api)
51
-     3.3.1. [ToastService Properties](#-toastservice-properties)
52
-     3.3.2. [ToastService Methods](#-toastservice-methods)
53
-     3.3.3. [Toast Lifecycle Hooks](#-toast-lifecycle-hooks)
54
- 4. [Appendix](#appendix)
55
- 4.1. [Dockerfile Example](#runtime-config-dockerfile-example)
56
- 5. [License](#-license)
47
+ 1. [Quick Start](#-quick-start)
48
+ 1. [Add Providers](#add-providers)
49
+ 2. [Use in components](#use-in-components)
50
+ 2. [Configuration Options](#️-configuration-options)
51
+ 3. [ToastService API](#-toastservice-api)
52
+ 1. [ToastService Properties](#-toastservice-properties)
53
+ 2. [ToastService Methods](#-toastservice-methods)
54
+ 3. [Toast Lifecycle Hooks](#-toast-lifecycle-hooks)
55
+ 4. [Components & Directives](#-components--directives)
56
+ 1. [Components](#-components)
57
+ 1. [Footer](#footer-component-tae-footer)
58
+ 2. [Directives](#-directives)
59
+ 1. [Hard Refresh](#hard-refresh-directive-taehardrefresh)
60
+ 2. [Barcode Scanner](#barcode-scanner-directive-taebarcodescanner)
61
+ 5. [Appendix](#appendix)
62
+ 1. [Dockerfile Example](#runtime-config-dockerfile-example)
63
+ 6. [License](#-license)
57
64
 
58
65
  ---
59
66
 
@@ -115,28 +122,33 @@ export type StaticEnv = typeof EnvKit.types.StaticEnv;
115
122
  // Injection Token for EnvConfig
116
123
  export const ENV_CONFIG = new InjectionToken<EnvConfig>('ENV_CONFIG');
117
124
  ```
125
+
118
126
  &nbsp;
119
127
 
120
128
  ## Defining Static Environments (Dev/Prod)
121
129
 
122
130
  Initialize the environments using Nx:
131
+
123
132
  ```bash
124
133
  nx g environments
125
134
  ```
126
- This will create two files: `environment.ts` for production environment configuration and `environment.development.ts` for the local development environment configuration.
135
+
136
+ This will create two files: `environment.ts` for the production environment configuration and `environment.development.ts` for the local development environment configuration.
127
137
 
128
138
  `environment.development.ts`:
139
+
129
140
  ```ts
130
141
  import { StaticEnv } from './environment-config';
131
142
 
132
143
  export const environment: StaticEnv = {
133
144
  envType: 'dev',
134
145
  production: false,
135
- apiUrl: 'https://www.company.com/api/'
146
+ apiUrl: 'https://www.company.com/api/',
136
147
  } satisfies StaticEnv;
137
148
  ```
138
149
 
139
150
  `environment.ts`:
151
+
140
152
  ```ts
141
153
  import { StaticEnv } from './environment-config';
142
154
 
@@ -146,6 +158,7 @@ export const environment: StaticEnv = {
146
158
  // apiUrl: 'https://www.company.com/api/' // apiUrl cannot be defined here
147
159
  } satisfies StaticEnv;
148
160
  ```
161
+
149
162
  &nbsp;
150
163
 
151
164
  ## Providing Runtime Configuration
@@ -169,6 +182,7 @@ export const appConfig: ApplicationConfig = {
169
182
  ],
170
183
  };
171
184
  ```
185
+
172
186
  &nbsp;
173
187
 
174
188
  ## Using the ENV_CONFIG Token
@@ -186,6 +200,7 @@ export class ApiService {
186
200
  }
187
201
  }
188
202
  ```
203
+
189
204
  &nbsp;
190
205
  This setup involves several key steps:
191
206
 
@@ -197,22 +212,27 @@ This setup involves several key steps:
197
212
  > The `/env/runtime.env` file must be generated by the container during startup.
198
213
  > Shell script binaries to support this are included the package.
199
214
 
215
+ &nbsp;
216
+
200
217
  ## Runtime Configuration Binaries
201
218
 
202
219
  This package ships with two lightweight shell scripts used to generate a runtime configuration file inside the container. They enable true runtime configurability without rebuilding the Angular image. Additionally, the package contains a default `nginx.conf` optimized for Angular application. The files are located in the `/docker` directory.
203
220
 
204
221
  ### `docker-entrypoint.sh`
222
+
205
223
  - Entry point executed every time the container starts
206
224
  - Calls the `extract-env-vars.sh` to generate a fresh `runtime.env`
207
225
  - Lastly, executes the provided Dockerfile `CMD`
208
226
 
209
227
  ### `extract-env-vars.sh`
228
+
210
229
  - Reads all container environment variables matching a prefix (default: `NG__`)
211
230
  - Strips the prefix and writes cleaned `KEY=VALUE` pairs to `runtime.env`
212
- - Supports nested keys via __ (e.g., `NG__myFeature__myThreshold`)
231
+ - Supports nested keys via ** (e.g., `NG**myFeature\_\_myThreshold`)
213
232
  - Defaults output to `/usr/share/nginx/html/env/runtime.env`
214
233
 
215
234
  ### `nginx.conf`
235
+
216
236
  A default Nginx configuration optimized for Angular applications. It provides:
217
237
 
218
238
  - Performance tuning for static file serving
@@ -235,10 +255,14 @@ CMD ["nginx", "-g", "daemon off;"]
235
255
 
236
256
  For a complete Dockerfile example with the shipped `nginx.conf` config, refer to [Runtime Config Dockerfile Example](#runtime-config-dockerfile-example)
237
257
 
258
+ &nbsp;
259
+
238
260
  ---
239
261
 
240
262
  # 🔔 Toasts
241
263
 
264
+ A lightweight, standalone toast system that integrates seamlessly with Tegel Angular. Provides configurable, signal-driven notifications for success, error, warning, and information messages.
265
+
242
266
  ## 🚀 Quick Start
243
267
 
244
268
  ### Add Providers
@@ -289,6 +313,8 @@ export class MyToastDemoComponent {
289
313
 
290
314
  ---
291
315
 
316
+ &nbsp;
317
+
292
318
  ## ⚙️ Configuration Options
293
319
 
294
320
  You can configure the default appearance and behavior of toasts by passing a `ToastConfig` object to `provideToast()` in your `app.config.ts`.
@@ -308,6 +334,8 @@ All options are optional. Defaults will be applied if values are not provided.
308
334
 
309
335
  ---
310
336
 
337
+ &nbsp;
338
+
311
339
  ## 🧩 ToastService API
312
340
 
313
341
  The `ToastService` provides a signal-based API to create, manage, and dismiss toast notifications in Angular standalone apps. It is automatically available after registering `provideToast()` in your `app.config.ts`.
@@ -342,7 +370,7 @@ toastService.create({
342
370
 
343
371
  Returns the unique toast ID.
344
372
 
345
- ---
373
+ &nbsp;
346
374
 
347
375
  #### Convenience Methods
348
376
 
@@ -355,13 +383,13 @@ toastService.warning({ title: 'Heads up!' });
355
383
  toastService.info({ title: 'FYI' });
356
384
  ```
357
385
 
358
- ---
386
+ &nbsp;
359
387
 
360
388
  #### `getToast(id: number): Toast | undefined`
361
389
 
362
390
  Gets a toast by its ID.
363
391
 
364
- ---
392
+ &nbsp;
365
393
 
366
394
  #### `createRandomToast(props?: Partial<ToastOptions>): number`
367
395
 
@@ -371,25 +399,25 @@ Creates a random toast with random type and title. Useful for testing. Returns t
371
399
  toastService.createRandomToast();
372
400
  ```
373
401
 
374
- ---
402
+ &nbsp;
375
403
 
376
404
  #### `close(id: number): void`
377
405
 
378
406
  Triggers the fade-out animation and schedules removal.
379
407
 
380
- ---
408
+ &nbsp;
381
409
 
382
410
  #### `closeAll(): void`
383
411
 
384
412
  Closes all currently open toasts.
385
413
 
386
- ---
414
+ &nbsp;
387
415
 
388
416
  #### `remove(id: number): void`
389
417
 
390
418
  Immediately removes a toast (no animation).
391
419
 
392
- ---
420
+ &nbsp;
393
421
 
394
422
  #### `removeAll(): void`
395
423
 
@@ -417,6 +445,106 @@ toastService.success({
417
445
  });
418
446
  ```
419
447
 
448
+ ---
449
+
450
+ &nbsp;
451
+
452
+ # 🧩 Components & Directives
453
+
454
+ This library includes a set of standalone UI components and utility directives, all prefixed with **`tae`**, designed to extend and complement the Tegel Angular ecosystem. Each piece is lightweight, fully typed, and easy to import into any Angular 19+ application.
455
+ &nbsp;
456
+
457
+ ## 🧱 Components
458
+
459
+ ### Footer Component (`tae-footer`)
460
+
461
+ `TaeFooterComponent` is an enhanced footer based on the Tegel `TdsFooterComponent`. It preserves the same visual appearance while adding two key improvements:
462
+
463
+ - A **compact “small” variant** for constrained layouts.
464
+ - An optional **version display**, allowing applications to show their build or release version directly in the footer.
465
+
466
+ This makes it ideal for full-viewport layouts that benefit from space efficiency and clear version visibility.
467
+
468
+ **Inputs:**
469
+
470
+ | Input | Type | Default | Description |
471
+ | ------- | --------------------- | ------- | ------------------------------------------------------------------------------------------ |
472
+ | variant | `'normal' \| 'small'` | normal | Layout style of the footer. `'small'` produces a more compact version. |
473
+ | version | `string \| undefined` | — | Optional application version string. If provided, it is displayed left of the Scania logo. |
474
+
475
+ **Example:**
476
+
477
+ ```html
478
+ <tae-footer variant="small" version="v1.0.0" />
479
+ ```
480
+
481
+ &nbsp;
482
+
483
+ ## ⚡ Directives
484
+
485
+ ### Hard Refresh Directive (`taeHardRefresh`)
486
+
487
+ The `HardRefreshDirective` provides a small UX shortcut: it performs a **full page reload** when the host element is clicked **N times in rapid succession**, where each click must occur within `clickWindowMs` milliseconds of the previous one.
488
+
489
+ This is especially useful for hard-reloading tablet or mobile applications which are locked in full-screen mode, and thus have no browser buttons like refresh.
490
+
491
+ **Inputs:**
492
+
493
+ | Property | Type | Default | Description |
494
+ | ---------------- | -------- | --------- | ---------------------------------------------------------------------- |
495
+ | `clicksRequired` | `number` | `3` | Number of clicks required within the window to trigger a hard refresh. |
496
+ | `clickWindowMs` | `number` | `500` | Time window in milliseconds between two subsequent clicks. |
497
+
498
+ **Example:**
499
+
500
+ ```html
501
+ <tds-header-brand-symbol
502
+ taeHardRefresh
503
+ [clicksRequired]="3"
504
+ [clickWindowMs]="500"
505
+ >
506
+ <a aria-label="Scania - red gryphon on blue shield"></a>
507
+ </tds-header-brand-symbol>
508
+ ```
509
+
510
+ &nbsp;
511
+
512
+ ### Barcode Scanner Directive (`taeBarcodeScanner`)
513
+
514
+ The `BarcodeScannerDirective` enables global barcode scanning by listening for rapid character input sequences (typically from a hardware scanner) that terminate with a specific key (default is `Enter`).
515
+
516
+ It operates outside of Angular's zone to prevent unnecessary change detection cycles on every keypress and includes built-in filtering to ignore modifier keys like `Shift`, `Ctrl`, or `Alt`, ensuring only the actual barcode data is captured.
517
+
518
+ **Inputs:**
519
+
520
+ | Input | Type | Default | Description |
521
+ | ---------------- | ---------------- | --------- | ------------------------------------------------------------------ |
522
+ | `inputWindowMs` | `number` | `100` | Max time allowed between consecutive keypresses before discarding. |
523
+ | `terminatorKey` | `string` | `'Enter'` | The key that signals the end of a barcode sequence. |
524
+
525
+ **Outputs:**
526
+
527
+ | Output | Type | Description |
528
+ | ---------------- | ---------------- | ------------------------------------------------------------------ |
529
+ | `barcodeScanned` | `string` | **Required**. Emits the full barcode string once completed. |
530
+
531
+ **Example:**
532
+
533
+ ```html
534
+ <ng-container
535
+ taeBarcodeScanner
536
+ (barcodeScanned)="handleScan($event)"
537
+ [inputWindowMs]="100"
538
+ terminatorKey="Enter"
539
+ >
540
+ <p>Scanner is active. Please scan a barcode...</p>
541
+ </ng-container>
542
+ ```
543
+
544
+ ---
545
+
546
+ &nbsp;
547
+
420
548
  # Appendix
421
549
 
422
550
  ## Runtime Config Dockerfile Example
package/esm2022/index.mjs CHANGED
@@ -13,4 +13,13 @@ export { parseEnvFile } from './lib/env/core/parse-env-file';
13
13
  // Angular
14
14
  export { provideRuntimeConfig } from './lib/env/angular/provide-runtime-config';
15
15
  export { provideStaticConfig } from './lib/env/angular/provide-static-config';
16
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9saWJzL3RlZ2VsLWFuZ3VsYXItZXh0ZW5zaW9ucy9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEscURBQXFEO0FBQ3JELHVCQUF1QjtBQUN2QixxREFBcUQ7QUFDckQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3pELE9BQU8sRUFDTCxvQkFBb0IsRUFDcEIsWUFBWSxHQUViLE1BQU0sMEJBQTBCLENBQUM7QUFDbEMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBS3pELHFEQUFxRDtBQUNyRCxxQkFBcUI7QUFDckIscURBQXFEO0FBQ3JELE9BQU87QUFDUCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDN0QsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBRTdELFVBQVU7QUFDVixPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSwwQ0FBMEMsQ0FBQztBQUNoRixPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx5Q0FBeUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBUb2FzdCBNb2R1bGUgRXhwb3J0c1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbmV4cG9ydCB7IHByb3ZpZGVUb2FzdCB9IGZyb20gJy4vbGliL3RvYXN0L3Byb3ZpZGUtdG9hc3QnO1xuZXhwb3J0IHtcbiAgREVGQVVMVF9UT0FTVF9DT05GSUcsXG4gIFRPQVNUX0NPTkZJRyxcbiAgVG9hc3RDb25maWcsXG59IGZyb20gJy4vbGliL3RvYXN0L3RvYXN0LmNvbmZpZyc7XG5leHBvcnQgeyBUb2FzdFNlcnZpY2UgfSBmcm9tICcuL2xpYi90b2FzdC90b2FzdC5zZXJ2aWNlJztcblxuLy8gTW9kZWxzXG5leHBvcnQgeyBUb2FzdCwgVG9hc3RPcHRpb25zIH0gZnJvbSAnLi9saWIvdG9hc3QvbW9kZWxzL3RvYXN0Lm1vZGVsJztcblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIEVudiBNb2R1bGUgRXhwb3J0c1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIENvcmVcbmV4cG9ydCB7IGNyZWF0ZUVudktpdCB9IGZyb20gJy4vbGliL2Vudi9jb3JlL2NyZWF0ZS1lbnYta2l0JztcbmV4cG9ydCB7IHBhcnNlRW52RmlsZSB9IGZyb20gJy4vbGliL2Vudi9jb3JlL3BhcnNlLWVudi1maWxlJztcblxuLy8gQW5ndWxhclxuZXhwb3J0IHsgcHJvdmlkZVJ1bnRpbWVDb25maWcgfSBmcm9tICcuL2xpYi9lbnYvYW5ndWxhci9wcm92aWRlLXJ1bnRpbWUtY29uZmlnJztcbmV4cG9ydCB7IHByb3ZpZGVTdGF0aWNDb25maWcgfSBmcm9tICcuL2xpYi9lbnYvYW5ndWxhci9wcm92aWRlLXN0YXRpYy1jb25maWcnO1xuIl19
16
+ // --------------------------------------------------
17
+ // Directive Module Exports
18
+ // --------------------------------------------------
19
+ export { BarcodeScannerDirective } from './lib/directives/barcode-scanner.directive';
20
+ export { HardRefreshDirective } from './lib/directives/hard-refresh.directive';
21
+ // --------------------------------------------------
22
+ // Component Module Exports
23
+ // --------------------------------------------------
24
+ export { TaeFooterComponent } from './lib/components/tae-footer/tae-footer.component';
25
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9saWJzL3RlZ2VsLWFuZ3VsYXItZXh0ZW5zaW9ucy9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEscURBQXFEO0FBQ3JELHVCQUF1QjtBQUN2QixxREFBcUQ7QUFDckQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3pELE9BQU8sRUFDTCxvQkFBb0IsRUFDcEIsWUFBWSxHQUViLE1BQU0sMEJBQTBCLENBQUM7QUFDbEMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBS3pELHFEQUFxRDtBQUNyRCxxQkFBcUI7QUFDckIscURBQXFEO0FBQ3JELE9BQU87QUFDUCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDN0QsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBRTdELFVBQVU7QUFDVixPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSwwQ0FBMEMsQ0FBQztBQUNoRixPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx5Q0FBeUMsQ0FBQztBQUU5RSxxREFBcUQ7QUFDckQsMkJBQTJCO0FBQzNCLHFEQUFxRDtBQUNyRCxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSw0Q0FBNEMsQ0FBQztBQUNyRixPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSx5Q0FBeUMsQ0FBQztBQUUvRSxxREFBcUQ7QUFDckQsMkJBQTJCO0FBQzNCLHFEQUFxRDtBQUNyRCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxrREFBa0QsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBUb2FzdCBNb2R1bGUgRXhwb3J0c1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbmV4cG9ydCB7IHByb3ZpZGVUb2FzdCB9IGZyb20gJy4vbGliL3RvYXN0L3Byb3ZpZGUtdG9hc3QnO1xuZXhwb3J0IHtcbiAgREVGQVVMVF9UT0FTVF9DT05GSUcsXG4gIFRPQVNUX0NPTkZJRyxcbiAgVG9hc3RDb25maWcsXG59IGZyb20gJy4vbGliL3RvYXN0L3RvYXN0LmNvbmZpZyc7XG5leHBvcnQgeyBUb2FzdFNlcnZpY2UgfSBmcm9tICcuL2xpYi90b2FzdC90b2FzdC5zZXJ2aWNlJztcblxuLy8gTW9kZWxzXG5leHBvcnQgeyBUb2FzdCwgVG9hc3RPcHRpb25zIH0gZnJvbSAnLi9saWIvdG9hc3QvbW9kZWxzL3RvYXN0Lm1vZGVsJztcblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIEVudiBNb2R1bGUgRXhwb3J0c1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIENvcmVcbmV4cG9ydCB7IGNyZWF0ZUVudktpdCB9IGZyb20gJy4vbGliL2Vudi9jb3JlL2NyZWF0ZS1lbnYta2l0JztcbmV4cG9ydCB7IHBhcnNlRW52RmlsZSB9IGZyb20gJy4vbGliL2Vudi9jb3JlL3BhcnNlLWVudi1maWxlJztcblxuLy8gQW5ndWxhclxuZXhwb3J0IHsgcHJvdmlkZVJ1bnRpbWVDb25maWcgfSBmcm9tICcuL2xpYi9lbnYvYW5ndWxhci9wcm92aWRlLXJ1bnRpbWUtY29uZmlnJztcbmV4cG9ydCB7IHByb3ZpZGVTdGF0aWNDb25maWcgfSBmcm9tICcuL2xpYi9lbnYvYW5ndWxhci9wcm92aWRlLXN0YXRpYy1jb25maWcnO1xuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gRGlyZWN0aXZlIE1vZHVsZSBFeHBvcnRzXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuZXhwb3J0IHsgQmFyY29kZVNjYW5uZXJEaXJlY3RpdmUgfSBmcm9tICcuL2xpYi9kaXJlY3RpdmVzL2JhcmNvZGUtc2Nhbm5lci5kaXJlY3RpdmUnO1xuZXhwb3J0IHsgSGFyZFJlZnJlc2hEaXJlY3RpdmUgfSBmcm9tICcuL2xpYi9kaXJlY3RpdmVzL2hhcmQtcmVmcmVzaC5kaXJlY3RpdmUnO1xuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gQ29tcG9uZW50IE1vZHVsZSBFeHBvcnRzXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuZXhwb3J0IHsgVGFlRm9vdGVyQ29tcG9uZW50IH0gZnJvbSAnLi9saWIvY29tcG9uZW50cy90YWUtZm9vdGVyL3RhZS1mb290ZXIuY29tcG9uZW50JztcbiJdfQ==
@@ -0,0 +1,48 @@
1
+ import { CommonModule } from '@angular/common';
2
+ import { ChangeDetectionStrategy, Component, input } from '@angular/core';
3
+ import * as i0 from "@angular/core";
4
+ import * as i1 from "@angular/common";
5
+ /**
6
+ * An enhanced standalone footer component based on the Tegel `TdsFooterComponent`.
7
+ *
8
+ * `TaeFooterComponent` maintains the same visual style as the original
9
+ * Tegel footer, but adds two key improvements:
10
+ *
11
+ * - A **compact “small” variant** for layouts where vertical space is limited.
12
+ * - Optional **version display**, allowing applications to show their
13
+ * build or release version directly in the footer.
14
+ *
15
+ * Example:
16
+ * ```html
17
+ * <tae-footer variant="small" version="v1.0.0" />
18
+ * ```
19
+ */
20
+ export class TaeFooterComponent {
21
+ /**
22
+ * Determines the visual layout of the footer.
23
+ *
24
+ * - `"normal"` displays the standard footer layout (aligned to tds-footer)
25
+ * - `"small"` produces a more compact version suitable for tight layouts
26
+ *
27
+ * @default 'normal'
28
+ */
29
+ variant = input('normal');
30
+ /**
31
+ * Optional application version string to display in the footer.
32
+ *
33
+ * When provided, it appears left of the Scania logo.
34
+ * If omitted or `undefined`, the version section is not shown.
35
+ */
36
+ version = input();
37
+ /**
38
+ * The current year used in the copyright section.
39
+ */
40
+ currentYear = new Date().getFullYear();
41
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TaeFooterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
42
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: TaeFooterComponent, isStandalone: true, selector: "tae-footer", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, version: { classPropertyName: "version", publicName: "version", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@let versionValue = version();\n<footer>\n <div class=\"footer-main\" [ngClass]=\"'footer-' + variant()\">\n <div class=\"footer-main-bottom\">\n <small class=\"copyright\">Copyright &copy; {{ currentYear }} Scania</small>\n @if (versionValue) {\n <small class=\"version\">Version: {{ versionValue }}</small>\n }\n <div class=\"brand\"></div>\n </div>\n </div>\n</footer>\n", styles: [":host{display:grid}.footer-main{background-color:var(--tds-footer-main-background);padding:0 40px}.footer-main .footer-main-bottom{padding:40px 0;display:flex;align-items:center;justify-content:space-between;border-top:1px solid var(--tds-footer-main-divider)}.footer-main .footer-main-bottom .copyright,.footer-main .footer-main-bottom .version{margin:0;font:var(--tds-detail-02);letter-spacing:var(--tds-detail-02-ls);color:var(--tds-footer-main-copyright)}.footer-main .footer-main-bottom .version{font-size:smaller;margin-left:auto;margin-right:40px}.footer-main .footer-main-bottom .brand{background-image:var(--tds-background-image-scania-wordmark-white-svg);background-repeat:no-repeat;background-size:117px;background-position:right center;width:117px;height:20px}.footer-main.footer-small .footer-main-bottom{padding:20px 0}.footer-main.footer-small .footer-main-bottom .copyright{font:var(--tds-detail-05);letter-spacing:var(--tds-detail-05-ls)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
43
+ }
44
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: TaeFooterComponent, decorators: [{
45
+ type: Component,
46
+ args: [{ selector: 'tae-footer', imports: [CommonModule], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@let versionValue = version();\n<footer>\n <div class=\"footer-main\" [ngClass]=\"'footer-' + variant()\">\n <div class=\"footer-main-bottom\">\n <small class=\"copyright\">Copyright &copy; {{ currentYear }} Scania</small>\n @if (versionValue) {\n <small class=\"version\">Version: {{ versionValue }}</small>\n }\n <div class=\"brand\"></div>\n </div>\n </div>\n</footer>\n", styles: [":host{display:grid}.footer-main{background-color:var(--tds-footer-main-background);padding:0 40px}.footer-main .footer-main-bottom{padding:40px 0;display:flex;align-items:center;justify-content:space-between;border-top:1px solid var(--tds-footer-main-divider)}.footer-main .footer-main-bottom .copyright,.footer-main .footer-main-bottom .version{margin:0;font:var(--tds-detail-02);letter-spacing:var(--tds-detail-02-ls);color:var(--tds-footer-main-copyright)}.footer-main .footer-main-bottom .version{font-size:smaller;margin-left:auto;margin-right:40px}.footer-main .footer-main-bottom .brand{background-image:var(--tds-background-image-scania-wordmark-white-svg);background-repeat:no-repeat;background-size:117px;background-position:right center;width:117px;height:20px}.footer-main.footer-small .footer-main-bottom{padding:20px 0}.footer-main.footer-small .footer-main-bottom .copyright{font:var(--tds-detail-05);letter-spacing:var(--tds-detail-05-ls)}\n"] }]
47
+ }] });
48
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFlLWZvb3Rlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9saWJzL3RlZ2VsLWFuZ3VsYXItZXh0ZW5zaW9ucy9zcmMvbGliL2NvbXBvbmVudHMvdGFlLWZvb3Rlci90YWUtZm9vdGVyLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uL2xpYnMvdGVnZWwtYW5ndWxhci1leHRlbnNpb25zL3NyYy9saWIvY29tcG9uZW50cy90YWUtZm9vdGVyL3RhZS1mb290ZXIuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLE1BQU0sZUFBZSxDQUFDOzs7QUFFMUU7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFTSCxNQUFNLE9BQU8sa0JBQWtCO0lBQzdCOzs7Ozs7O09BT0c7SUFFTSxPQUFPLEdBQUcsS0FBSyxDQUFxQixRQUFRLENBQUMsQ0FBQztJQUN2RDs7Ozs7T0FLRztJQUNNLE9BQU8sR0FBRyxLQUFLLEVBQXNCLENBQUM7SUFFL0M7O09BRUc7SUFDTSxXQUFXLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUUsQ0FBQzt3R0F0QnJDLGtCQUFrQjs0RkFBbEIsa0JBQWtCLDhVQzFCL0IsMFpBWUEscy9CRFFZLFlBQVk7OzRGQU1YLGtCQUFrQjtrQkFSOUIsU0FBUzsrQkFDRSxZQUFZLFdBQ2IsQ0FBQyxZQUFZLENBQUMsY0FDWCxJQUFJLG1CQUdDLHVCQUF1QixDQUFDLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENvbXBvbmVudCwgaW5wdXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcblxuLyoqXG4gKiBBbiBlbmhhbmNlZCBzdGFuZGFsb25lIGZvb3RlciBjb21wb25lbnQgYmFzZWQgb24gdGhlIFRlZ2VsIGBUZHNGb290ZXJDb21wb25lbnRgLlxuICpcbiAqIGBUYWVGb290ZXJDb21wb25lbnRgIG1haW50YWlucyB0aGUgc2FtZSB2aXN1YWwgc3R5bGUgYXMgdGhlIG9yaWdpbmFsXG4gKiBUZWdlbCBmb290ZXIsIGJ1dCBhZGRzIHR3byBrZXkgaW1wcm92ZW1lbnRzOlxuICpcbiAqIC0gQSAqKmNvbXBhY3Qg4oCcc21hbGzigJ0gdmFyaWFudCoqIGZvciBsYXlvdXRzIHdoZXJlIHZlcnRpY2FsIHNwYWNlIGlzIGxpbWl0ZWQuXG4gKiAtIE9wdGlvbmFsICoqdmVyc2lvbiBkaXNwbGF5KiosIGFsbG93aW5nIGFwcGxpY2F0aW9ucyB0byBzaG93IHRoZWlyXG4gKiAgIGJ1aWxkIG9yIHJlbGVhc2UgdmVyc2lvbiBkaXJlY3RseSBpbiB0aGUgZm9vdGVyLlxuICpcbiAqIEV4YW1wbGU6XG4gKiBgYGBodG1sXG4gKiA8dGFlLWZvb3RlciB2YXJpYW50PVwic21hbGxcIiB2ZXJzaW9uPVwidjEuMC4wXCIgLz5cbiAqIGBgYFxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICd0YWUtZm9vdGVyJyxcbiAgaW1wb3J0czogW0NvbW1vbk1vZHVsZV0sXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIHRlbXBsYXRlVXJsOiAnLi90YWUtZm9vdGVyLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vdGFlLWZvb3Rlci5jb21wb25lbnQuc2NzcyddLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbn0pXG5leHBvcnQgY2xhc3MgVGFlRm9vdGVyQ29tcG9uZW50IHtcbiAgLyoqXG4gICAqIERldGVybWluZXMgdGhlIHZpc3VhbCBsYXlvdXQgb2YgdGhlIGZvb3Rlci5cbiAgICpcbiAgICogLSBgXCJub3JtYWxcImAgZGlzcGxheXMgdGhlIHN0YW5kYXJkIGZvb3RlciBsYXlvdXQgKGFsaWduZWQgdG8gdGRzLWZvb3RlcilcbiAgICogLSBgXCJzbWFsbFwiYCBwcm9kdWNlcyBhIG1vcmUgY29tcGFjdCB2ZXJzaW9uIHN1aXRhYmxlIGZvciB0aWdodCBsYXlvdXRzXG4gICAqXG4gICAqIEBkZWZhdWx0ICdub3JtYWwnXG4gICAqL1xuXG4gIHJlYWRvbmx5IHZhcmlhbnQgPSBpbnB1dDwnbm9ybWFsJyB8ICdzbWFsbCc+KCdub3JtYWwnKTtcbiAgLyoqXG4gICAqIE9wdGlvbmFsIGFwcGxpY2F0aW9uIHZlcnNpb24gc3RyaW5nIHRvIGRpc3BsYXkgaW4gdGhlIGZvb3Rlci5cbiAgICpcbiAgICogV2hlbiBwcm92aWRlZCwgaXQgYXBwZWFycyBsZWZ0IG9mIHRoZSBTY2FuaWEgbG9nby5cbiAgICogSWYgb21pdHRlZCBvciBgdW5kZWZpbmVkYCwgdGhlIHZlcnNpb24gc2VjdGlvbiBpcyBub3Qgc2hvd24uXG4gICAqL1xuICByZWFkb25seSB2ZXJzaW9uID0gaW5wdXQ8c3RyaW5nIHwgdW5kZWZpbmVkPigpO1xuXG4gIC8qKlxuICAgKiBUaGUgY3VycmVudCB5ZWFyIHVzZWQgaW4gdGhlIGNvcHlyaWdodCBzZWN0aW9uLlxuICAgKi9cbiAgcmVhZG9ubHkgY3VycmVudFllYXIgPSBuZXcgRGF0ZSgpLmdldEZ1bGxZZWFyKCk7XG59XG4iLCJAbGV0IHZlcnNpb25WYWx1ZSA9IHZlcnNpb24oKTtcbjxmb290ZXI+XG4gIDxkaXYgY2xhc3M9XCJmb290ZXItbWFpblwiIFtuZ0NsYXNzXT1cIidmb290ZXItJyArIHZhcmlhbnQoKVwiPlxuICAgIDxkaXYgY2xhc3M9XCJmb290ZXItbWFpbi1ib3R0b21cIj5cbiAgICAgIDxzbWFsbCBjbGFzcz1cImNvcHlyaWdodFwiPkNvcHlyaWdodCAmY29weTsge3sgY3VycmVudFllYXIgfX0gU2NhbmlhPC9zbWFsbD5cbiAgICAgIEBpZiAodmVyc2lvblZhbHVlKSB7XG4gICAgICAgIDxzbWFsbCBjbGFzcz1cInZlcnNpb25cIj5WZXJzaW9uOiB7eyB2ZXJzaW9uVmFsdWUgfX08L3NtYWxsPlxuICAgICAgfVxuICAgICAgPGRpdiBjbGFzcz1cImJyYW5kXCI+PC9kaXY+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuPC9mb290ZXI+XG4iXX0=
@@ -0,0 +1,94 @@
1
+ import { DOCUMENT } from '@angular/common';
2
+ import { Directive, inject, input, NgZone, output } from '@angular/core';
3
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
+ import { catchError, EMPTY, exhaustMap, filter, fromEvent, map, share, startWith, takeWhile, timeout, toArray, } from 'rxjs';
5
+ import * as i0 from "@angular/core";
6
+ /**
7
+ * Directive that listens for rapid key sequences ending in a terminator key
8
+ * (default: Enter) and emits the collected characters as a barcode string.
9
+ *
10
+ * @example
11
+ * <ng-container
12
+ * taeBarcodeScanner
13
+ * (barcodeScanned)="handleScan($event)"
14
+ * [inputWindowMs]="100"
15
+ * terminatorKey="Enter"
16
+ * />
17
+ */
18
+ export class BarcodeScannerDirective {
19
+ /**
20
+ * Angular zone used to run key handling outside of change detection.
21
+ */
22
+ _ngZone = inject(NgZone);
23
+ /**
24
+ * Document reference for attaching global keydown event listeners.
25
+ */
26
+ _document = inject(DOCUMENT);
27
+ /**
28
+ * Maximum time window in milliseconds between consecutive keypresses.
29
+ * Sequences exceeding this duration are discarded.
30
+ *
31
+ * @default 100
32
+ */
33
+ inputWindowMs = input(100);
34
+ /**
35
+ * Key that terminates and completes a barcode sequence.
36
+ *
37
+ * @default "Enter"
38
+ */
39
+ terminatorKey = input('Enter');
40
+ /**
41
+ * Emits the complete barcode string captured from the scanner.
42
+ * * @remarks
43
+ * This output is required by the directive selector.
44
+ */
45
+ barcodeScanned = output();
46
+ /**
47
+ * Sets up the global keydown listener and barcode detection pipeline.
48
+ * The pipeline runs outside Angular's zone and only re-enters when a barcode
49
+ * is emitted, to avoid triggering change detection on every keypress.
50
+ */
51
+ constructor() {
52
+ // Run the key handling pipeline outside Angular's zone to avoid triggering
53
+ // change detection on every keypress.
54
+ this._ngZone.runOutsideAngular(() => {
55
+ // Create a global stream of valid keydown events
56
+ const key$ = fromEvent(this._document, 'keydown').pipe(
57
+ // Auto-unsubscribe when the directive is destroyed.
58
+ takeUntilDestroyed(),
59
+ // Allow only character keys and the terminator key
60
+ // Modifier keys (Shift, Ctrl, Alt, Meta) are ignored
61
+ filter((e) => e.key.length === 1 || e.key === this.terminatorKey()),
62
+ // Share a single keydown stream between outer and inner subscribers.
63
+ share());
64
+ key$
65
+ .pipe(
66
+ // Start a new scan session on the first key event
67
+ exhaustMap((firstEvent) => key$.pipe(startWith(firstEvent),
68
+ // Collect until the terminator key is pressed
69
+ takeWhile((e) => e.key !== this.terminatorKey()),
70
+ // Abort the sequence if no key is pressed within the time window
71
+ timeout(this.inputWindowMs()),
72
+ // Materialize the sequence as an array of KeyboardEvents
73
+ toArray(),
74
+ // Ignore empty sequences (e.g. stray terminator presses)
75
+ filter((events) => events.length > 0),
76
+ // On timeout (or other error), drop the sequence silently
77
+ catchError(() => EMPTY))),
78
+ // Map collected key events to their key values and join into a string
79
+ map((events) => events.map((e) => e.key).join('')))
80
+ // Re-enter Angular's zone only to emit the completed barcode.
81
+ .subscribe((barcode) => this._ngZone.run(() => this.barcodeScanned.emit(barcode)));
82
+ });
83
+ }
84
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: BarcodeScannerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
85
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.17", type: BarcodeScannerDirective, isStandalone: true, selector: "[taeBarcodeScanner]", inputs: { inputWindowMs: { classPropertyName: "inputWindowMs", publicName: "inputWindowMs", isSignal: true, isRequired: false, transformFunction: null }, terminatorKey: { classPropertyName: "terminatorKey", publicName: "terminatorKey", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { barcodeScanned: "barcodeScanned" }, ngImport: i0 });
86
+ }
87
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: BarcodeScannerDirective, decorators: [{
88
+ type: Directive,
89
+ args: [{
90
+ selector: '[taeBarcodeScanner]',
91
+ standalone: true,
92
+ }]
93
+ }], ctorParameters: () => [] });
94
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFyY29kZS1zY2FubmVyLmRpcmVjdGl2ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL2xpYnMvdGVnZWwtYW5ndWxhci1leHRlbnNpb25zL3NyYy9saWIvZGlyZWN0aXZlcy9iYXJjb2RlLXNjYW5uZXIuZGlyZWN0aXZlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMzQyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN6RSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUNoRSxPQUFPLEVBQ0wsVUFBVSxFQUNWLEtBQUssRUFDTCxVQUFVLEVBQ1YsTUFBTSxFQUNOLFNBQVMsRUFDVCxHQUFHLEVBQ0gsS0FBSyxFQUNMLFNBQVMsRUFDVCxTQUFTLEVBQ1QsT0FBTyxFQUNQLE9BQU8sR0FDUixNQUFNLE1BQU0sQ0FBQzs7QUFFZDs7Ozs7Ozs7Ozs7R0FXRztBQUtILE1BQU0sT0FBTyx1QkFBdUI7SUFDbEM7O09BRUc7SUFDYyxPQUFPLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBRTFDOztPQUVHO0lBQ2MsU0FBUyxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUU5Qzs7Ozs7T0FLRztJQUNNLGFBQWEsR0FBRyxLQUFLLENBQVMsR0FBRyxDQUFDLENBQUM7SUFFNUM7Ozs7T0FJRztJQUNNLGFBQWEsR0FBRyxLQUFLLENBQVMsT0FBTyxDQUFDLENBQUM7SUFFaEQ7Ozs7T0FJRztJQUNNLGNBQWMsR0FBRyxNQUFNLEVBQVUsQ0FBQztJQUUzQzs7OztPQUlHO0lBQ0g7UUFDRSwyRUFBMkU7UUFDM0Usc0NBQXNDO1FBQ3RDLElBQUksQ0FBQyxPQUFPLENBQUMsaUJBQWlCLENBQUMsR0FBRyxFQUFFO1lBQ2xDLGlEQUFpRDtZQUNqRCxNQUFNLElBQUksR0FBRyxTQUFTLENBQWdCLElBQUksQ0FBQyxTQUFTLEVBQUUsU0FBUyxDQUFDLENBQUMsSUFBSTtZQUNuRSxvREFBb0Q7WUFDcEQsa0JBQWtCLEVBQUU7WUFDcEIsbURBQW1EO1lBQ25ELHFEQUFxRDtZQUNyRCxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsTUFBTSxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxLQUFLLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUNuRSxxRUFBcUU7WUFDckUsS0FBSyxFQUFFLENBQ1IsQ0FBQztZQUVGLElBQUk7aUJBQ0QsSUFBSTtZQUNILGtEQUFrRDtZQUNsRCxVQUFVLENBQUMsQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUN4QixJQUFJLENBQUMsSUFBSSxDQUNQLFNBQVMsQ0FBQyxVQUFVLENBQUM7WUFDckIsOENBQThDO1lBQzlDLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsS0FBSyxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7WUFDaEQsaUVBQWlFO1lBQ2pFLE9BQU8sQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7WUFDN0IseURBQXlEO1lBQ3pELE9BQU8sRUFBRTtZQUNULHlEQUF5RDtZQUN6RCxNQUFNLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO1lBQ3JDLDBEQUEwRDtZQUMxRCxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQ3hCLENBQ0Y7WUFDRCxzRUFBc0U7WUFDdEUsR0FBRyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQ25EO2dCQUNELDhEQUE4RDtpQkFDN0QsU0FBUyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FDckIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FDMUQsQ0FBQztRQUNOLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQzt3R0EvRVUsdUJBQXVCOzRGQUF2Qix1QkFBdUI7OzRGQUF2Qix1QkFBdUI7a0JBSm5DLFNBQVM7bUJBQUM7b0JBQ1QsUUFBUSxFQUFFLHFCQUFxQjtvQkFDL0IsVUFBVSxFQUFFLElBQUk7aUJBQ2pCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRE9DVU1FTlQgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgRGlyZWN0aXZlLCBpbmplY3QsIGlucHV0LCBOZ1pvbmUsIG91dHB1dCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgdGFrZVVudGlsRGVzdHJveWVkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZS9yeGpzLWludGVyb3AnO1xuaW1wb3J0IHtcbiAgY2F0Y2hFcnJvcixcbiAgRU1QVFksXG4gIGV4aGF1c3RNYXAsXG4gIGZpbHRlcixcbiAgZnJvbUV2ZW50LFxuICBtYXAsXG4gIHNoYXJlLFxuICBzdGFydFdpdGgsXG4gIHRha2VXaGlsZSxcbiAgdGltZW91dCxcbiAgdG9BcnJheSxcbn0gZnJvbSAncnhqcyc7XG5cbi8qKlxuICogRGlyZWN0aXZlIHRoYXQgbGlzdGVucyBmb3IgcmFwaWQga2V5IHNlcXVlbmNlcyBlbmRpbmcgaW4gYSB0ZXJtaW5hdG9yIGtleVxuICogKGRlZmF1bHQ6IEVudGVyKSBhbmQgZW1pdHMgdGhlIGNvbGxlY3RlZCBjaGFyYWN0ZXJzIGFzIGEgYmFyY29kZSBzdHJpbmcuXG4gKlxuICogQGV4YW1wbGVcbiAqIDxuZy1jb250YWluZXJcbiAqICAgdGFlQmFyY29kZVNjYW5uZXJcbiAqICAgKGJhcmNvZGVTY2FubmVkKT1cImhhbmRsZVNjYW4oJGV2ZW50KVwiXG4gKiAgIFtpbnB1dFdpbmRvd01zXT1cIjEwMFwiXG4gKiAgIHRlcm1pbmF0b3JLZXk9XCJFbnRlclwiXG4gKiAvPlxuICovXG5ARGlyZWN0aXZlKHtcbiAgc2VsZWN0b3I6ICdbdGFlQmFyY29kZVNjYW5uZXJdJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbn0pXG5leHBvcnQgY2xhc3MgQmFyY29kZVNjYW5uZXJEaXJlY3RpdmUge1xuICAvKipcbiAgICogQW5ndWxhciB6b25lIHVzZWQgdG8gcnVuIGtleSBoYW5kbGluZyBvdXRzaWRlIG9mIGNoYW5nZSBkZXRlY3Rpb24uXG4gICAqL1xuICBwcml2YXRlIHJlYWRvbmx5IF9uZ1pvbmUgPSBpbmplY3QoTmdab25lKTtcblxuICAvKipcbiAgICogRG9jdW1lbnQgcmVmZXJlbmNlIGZvciBhdHRhY2hpbmcgZ2xvYmFsIGtleWRvd24gZXZlbnQgbGlzdGVuZXJzLlxuICAgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBfZG9jdW1lbnQgPSBpbmplY3QoRE9DVU1FTlQpO1xuXG4gIC8qKlxuICAgKiBNYXhpbXVtIHRpbWUgd2luZG93IGluIG1pbGxpc2Vjb25kcyBiZXR3ZWVuIGNvbnNlY3V0aXZlIGtleXByZXNzZXMuXG4gICAqIFNlcXVlbmNlcyBleGNlZWRpbmcgdGhpcyBkdXJhdGlvbiBhcmUgZGlzY2FyZGVkLlxuICAgKlxuICAgKiBAZGVmYXVsdCAxMDBcbiAgICovXG4gIHJlYWRvbmx5IGlucHV0V2luZG93TXMgPSBpbnB1dDxudW1iZXI+KDEwMCk7XG5cbiAgLyoqXG4gICAqIEtleSB0aGF0IHRlcm1pbmF0ZXMgYW5kIGNvbXBsZXRlcyBhIGJhcmNvZGUgc2VxdWVuY2UuXG4gICAqXG4gICAqIEBkZWZhdWx0IFwiRW50ZXJcIlxuICAgKi9cbiAgcmVhZG9ubHkgdGVybWluYXRvcktleSA9IGlucHV0PHN0cmluZz4oJ0VudGVyJyk7XG5cbiAgLyoqXG4gICAqIEVtaXRzIHRoZSBjb21wbGV0ZSBiYXJjb2RlIHN0cmluZyBjYXB0dXJlZCBmcm9tIHRoZSBzY2FubmVyLlxuICAgKiAqIEByZW1hcmtzXG4gICAqIFRoaXMgb3V0cHV0IGlzIHJlcXVpcmVkIGJ5IHRoZSBkaXJlY3RpdmUgc2VsZWN0b3IuXG4gICAqL1xuICByZWFkb25seSBiYXJjb2RlU2Nhbm5lZCA9IG91dHB1dDxzdHJpbmc+KCk7XG5cbiAgLyoqXG4gICAqIFNldHMgdXAgdGhlIGdsb2JhbCBrZXlkb3duIGxpc3RlbmVyIGFuZCBiYXJjb2RlIGRldGVjdGlvbiBwaXBlbGluZS5cbiAgICogVGhlIHBpcGVsaW5lIHJ1bnMgb3V0c2lkZSBBbmd1bGFyJ3Mgem9uZSBhbmQgb25seSByZS1lbnRlcnMgd2hlbiBhIGJhcmNvZGVcbiAgICogaXMgZW1pdHRlZCwgdG8gYXZvaWQgdHJpZ2dlcmluZyBjaGFuZ2UgZGV0ZWN0aW9uIG9uIGV2ZXJ5IGtleXByZXNzLlxuICAgKi9cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgLy8gUnVuIHRoZSBrZXkgaGFuZGxpbmcgcGlwZWxpbmUgb3V0c2lkZSBBbmd1bGFyJ3Mgem9uZSB0byBhdm9pZCB0cmlnZ2VyaW5nXG4gICAgLy8gY2hhbmdlIGRldGVjdGlvbiBvbiBldmVyeSBrZXlwcmVzcy5cbiAgICB0aGlzLl9uZ1pvbmUucnVuT3V0c2lkZUFuZ3VsYXIoKCkgPT4ge1xuICAgICAgLy8gQ3JlYXRlIGEgZ2xvYmFsIHN0cmVhbSBvZiB2YWxpZCBrZXlkb3duIGV2ZW50c1xuICAgICAgY29uc3Qga2V5JCA9IGZyb21FdmVudDxLZXlib2FyZEV2ZW50Pih0aGlzLl9kb2N1bWVudCwgJ2tleWRvd24nKS5waXBlKFxuICAgICAgICAvLyBBdXRvLXVuc3Vic2NyaWJlIHdoZW4gdGhlIGRpcmVjdGl2ZSBpcyBkZXN0cm95ZWQuXG4gICAgICAgIHRha2VVbnRpbERlc3Ryb3llZCgpLFxuICAgICAgICAvLyBBbGxvdyBvbmx5IGNoYXJhY3RlciBrZXlzIGFuZCB0aGUgdGVybWluYXRvciBrZXlcbiAgICAgICAgLy8gTW9kaWZpZXIga2V5cyAoU2hpZnQsIEN0cmwsIEFsdCwgTWV0YSkgYXJlIGlnbm9yZWRcbiAgICAgICAgZmlsdGVyKChlKSA9PiBlLmtleS5sZW5ndGggPT09IDEgfHwgZS5rZXkgPT09IHRoaXMudGVybWluYXRvcktleSgpKSxcbiAgICAgICAgLy8gU2hhcmUgYSBzaW5nbGUga2V5ZG93biBzdHJlYW0gYmV0d2VlbiBvdXRlciBhbmQgaW5uZXIgc3Vic2NyaWJlcnMuXG4gICAgICAgIHNoYXJlKCksXG4gICAgICApO1xuXG4gICAgICBrZXkkXG4gICAgICAgIC5waXBlKFxuICAgICAgICAgIC8vIFN0YXJ0IGEgbmV3IHNjYW4gc2Vzc2lvbiBvbiB0aGUgZmlyc3Qga2V5IGV2ZW50XG4gICAgICAgICAgZXhoYXVzdE1hcCgoZmlyc3RFdmVudCkgPT5cbiAgICAgICAgICAgIGtleSQucGlwZShcbiAgICAgICAgICAgICAgc3RhcnRXaXRoKGZpcnN0RXZlbnQpLFxuICAgICAgICAgICAgICAvLyBDb2xsZWN0IHVudGlsIHRoZSB0ZXJtaW5hdG9yIGtleSBpcyBwcmVzc2VkXG4gICAgICAgICAgICAgIHRha2VXaGlsZSgoZSkgPT4gZS5rZXkgIT09IHRoaXMudGVybWluYXRvcktleSgpKSxcbiAgICAgICAgICAgICAgLy8gQWJvcnQgdGhlIHNlcXVlbmNlIGlmIG5vIGtleSBpcyBwcmVzc2VkIHdpdGhpbiB0aGUgdGltZSB3aW5kb3dcbiAgICAgICAgICAgICAgdGltZW91dCh0aGlzLmlucHV0V2luZG93TXMoKSksXG4gICAgICAgICAgICAgIC8vIE1hdGVyaWFsaXplIHRoZSBzZXF1ZW5jZSBhcyBhbiBhcnJheSBvZiBLZXlib2FyZEV2ZW50c1xuICAgICAgICAgICAgICB0b0FycmF5KCksXG4gICAgICAgICAgICAgIC8vIElnbm9yZSBlbXB0eSBzZXF1ZW5jZXMgKGUuZy4gc3RyYXkgdGVybWluYXRvciBwcmVzc2VzKVxuICAgICAgICAgICAgICBmaWx0ZXIoKGV2ZW50cykgPT4gZXZlbnRzLmxlbmd0aCA+IDApLFxuICAgICAgICAgICAgICAvLyBPbiB0aW1lb3V0IChvciBvdGhlciBlcnJvciksIGRyb3AgdGhlIHNlcXVlbmNlIHNpbGVudGx5XG4gICAgICAgICAgICAgIGNhdGNoRXJyb3IoKCkgPT4gRU1QVFkpLFxuICAgICAgICAgICAgKSxcbiAgICAgICAgICApLFxuICAgICAgICAgIC8vIE1hcCBjb2xsZWN0ZWQga2V5IGV2ZW50cyB0byB0aGVpciBrZXkgdmFsdWVzIGFuZCBqb2luIGludG8gYSBzdHJpbmdcbiAgICAgICAgICBtYXAoKGV2ZW50cykgPT4gZXZlbnRzLm1hcCgoZSkgPT4gZS5rZXkpLmpvaW4oJycpKSxcbiAgICAgICAgKVxuICAgICAgICAvLyBSZS1lbnRlciBBbmd1bGFyJ3Mgem9uZSBvbmx5IHRvIGVtaXQgdGhlIGNvbXBsZXRlZCBiYXJjb2RlLlxuICAgICAgICAuc3Vic2NyaWJlKChiYXJjb2RlKSA9PlxuICAgICAgICAgIHRoaXMuX25nWm9uZS5ydW4oKCkgPT4gdGhpcy5iYXJjb2RlU2Nhbm5lZC5lbWl0KGJhcmNvZGUpKSxcbiAgICAgICAgKTtcbiAgICB9KTtcbiAgfVxufVxuIl19
@@ -0,0 +1,83 @@
1
+ import { Directive, input } from '@angular/core';
2
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
3
+ import { filter, map, pairwise, scan, startWith, Subject, throttleTime, timestamp, } from 'rxjs';
4
+ import * as i0 from "@angular/core";
5
+ /**
6
+ * Directive that triggers a hard page refresh when the host element is clicked
7
+ * a specified number of times within a configurable time window.
8
+ *
9
+ * This is useful for adding developer-oriented shortcuts, diagnostics entry points,
10
+ * hidden "triple-click to reload" behaviors, or fallback mechanisms in production.
11
+ *
12
+ * Usage:
13
+ * ```html
14
+ * <div taeHardRefresh [clicksRequired]="3" [clickWindowMs]="500">...</div>
15
+ * ```
16
+ */
17
+ export class HardRefreshDirective {
18
+ /**
19
+ * The number of rapid consecutive clicks required to trigger a hard refresh.
20
+ * A "rapid" click is one that occurs within `clickWindowMs` of the previous click.
21
+ *
22
+ * @default 3
23
+ */
24
+ clicksRequired = input(3);
25
+ /**
26
+ * The maximum time interval (in milliseconds) allowed between consecutive clicks
27
+ * for them to be considered part of the same "streak".
28
+ *
29
+ * If the interval between two clicks exceeds this value, the streak resets.
30
+ *
31
+ * @default 500
32
+ */
33
+ clickWindowMs = input(500);
34
+ /**
35
+ * Internal click event stream used to build the rapid-click detection pipeline.
36
+ * Emits one value per host click (via the `(click)` host listener).
37
+ */
38
+ clicks$ = new Subject();
39
+ constructor() {
40
+ /**
41
+ * Rapid-click detection pipeline:
42
+ *
43
+ * - Timestamps each click.
44
+ * - Compares consecutive timestamps to determine whether they fall within the
45
+ * configured `clickWindowMs` threshold.
46
+ * - Maintains a streak count using a reducer (`scan`).
47
+ * - Emits once the streak count reaches or exceeds `clicksRequired`.
48
+ * - Uses `throttleTime` to prevent duplicate triggers within the same burst.
49
+ */
50
+ this.clicks$
51
+ .pipe(takeUntilDestroyed(),
52
+ // Turn click events into raw timestamps (epoch ms)
53
+ timestamp(), map((t) => t.timestamp),
54
+ // Work in pairs: [previousTimestamp, currentTimestamp]
55
+ startWith(0), pairwise(),
56
+ // Maintain a streak of clicks within the time window
57
+ scan((acc, [prev, curr]) => curr - prev <= this.clickWindowMs() ? acc + 1 : 1, 0),
58
+ // Only continue when we reach the threshold number of clicks
59
+ filter((streak) => streak >= this.clicksRequired()),
60
+ // Avoid multiple triggers for the same "burst" of clicks
61
+ throttleTime(this.clickWindowMs(), undefined, {
62
+ leading: true,
63
+ trailing: false,
64
+ }))
65
+ .subscribe(() => {
66
+ // Reload the window
67
+ window.location.reload();
68
+ });
69
+ }
70
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: HardRefreshDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
71
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.17", type: HardRefreshDirective, isStandalone: true, selector: "[taeHardRefresh]", inputs: { clicksRequired: { classPropertyName: "clicksRequired", publicName: "clicksRequired", isSignal: true, isRequired: false, transformFunction: null }, clickWindowMs: { classPropertyName: "clickWindowMs", publicName: "clickWindowMs", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "click": "clicks$.next()" } }, ngImport: i0 });
72
+ }
73
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: HardRefreshDirective, decorators: [{
74
+ type: Directive,
75
+ args: [{
76
+ selector: '[taeHardRefresh]',
77
+ standalone: true,
78
+ host: {
79
+ '(click)': 'clicks$.next()',
80
+ },
81
+ }]
82
+ }], ctorParameters: () => [] });
83
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGFyZC1yZWZyZXNoLmRpcmVjdGl2ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL2xpYnMvdGVnZWwtYW5ndWxhci1leHRlbnNpb25zL3NyYy9saWIvZGlyZWN0aXZlcy9oYXJkLXJlZnJlc2guZGlyZWN0aXZlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ2pELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ2hFLE9BQU8sRUFDTCxNQUFNLEVBQ04sR0FBRyxFQUNILFFBQVEsRUFDUixJQUFJLEVBQ0osU0FBUyxFQUNULE9BQU8sRUFDUCxZQUFZLEVBQ1osU0FBUyxHQUNWLE1BQU0sTUFBTSxDQUFDOztBQUVkOzs7Ozs7Ozs7OztHQVdHO0FBUUgsTUFBTSxPQUFPLG9CQUFvQjtJQUMvQjs7Ozs7T0FLRztJQUNNLGNBQWMsR0FBRyxLQUFLLENBQVMsQ0FBQyxDQUFDLENBQUM7SUFFM0M7Ozs7Ozs7T0FPRztJQUNNLGFBQWEsR0FBRyxLQUFLLENBQVMsR0FBRyxDQUFDLENBQUM7SUFFNUM7OztPQUdHO0lBQ2dCLE9BQU8sR0FBRyxJQUFJLE9BQU8sRUFBUSxDQUFDO0lBRWpEO1FBQ0U7Ozs7Ozs7OztXQVNHO1FBQ0gsSUFBSSxDQUFDLE9BQU87YUFDVCxJQUFJLENBQ0gsa0JBQWtCLEVBQUU7UUFDcEIsbURBQW1EO1FBQ25ELFNBQVMsRUFBRSxFQUNYLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztRQUN2Qix1REFBdUQ7UUFDdkQsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUNaLFFBQVEsRUFBRTtRQUNWLHFEQUFxRDtRQUNyRCxJQUFJLENBQ0YsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRSxDQUNwQixJQUFJLEdBQUcsSUFBSSxJQUFJLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUNuRCxDQUFDLENBQ0Y7UUFDRCw2REFBNkQ7UUFDN0QsTUFBTSxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQ25ELHlEQUF5RDtRQUN6RCxZQUFZLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRSxFQUFFLFNBQVMsRUFBRTtZQUM1QyxPQUFPLEVBQUUsSUFBSTtZQUNiLFFBQVEsRUFBRSxLQUFLO1NBQ2hCLENBQUMsQ0FDSDthQUNBLFNBQVMsQ0FBQyxHQUFHLEVBQUU7WUFDZCxvQkFBb0I7WUFDcEIsTUFBTSxDQUFDLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUMzQixDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7d0dBL0RVLG9CQUFvQjs0RkFBcEIsb0JBQW9COzs0RkFBcEIsb0JBQW9CO2tCQVBoQyxTQUFTO21CQUFDO29CQUNULFFBQVEsRUFBRSxrQkFBa0I7b0JBQzVCLFVBQVUsRUFBRSxJQUFJO29CQUNoQixJQUFJLEVBQUU7d0JBQ0osU0FBUyxFQUFFLGdCQUFnQjtxQkFDNUI7aUJBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBEaXJlY3RpdmUsIGlucHV0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyB0YWtlVW50aWxEZXN0cm95ZWQgfSBmcm9tICdAYW5ndWxhci9jb3JlL3J4anMtaW50ZXJvcCc7XG5pbXBvcnQge1xuICBmaWx0ZXIsXG4gIG1hcCxcbiAgcGFpcndpc2UsXG4gIHNjYW4sXG4gIHN0YXJ0V2l0aCxcbiAgU3ViamVjdCxcbiAgdGhyb3R0bGVUaW1lLFxuICB0aW1lc3RhbXAsXG59IGZyb20gJ3J4anMnO1xuXG4vKipcbiAqIERpcmVjdGl2ZSB0aGF0IHRyaWdnZXJzIGEgaGFyZCBwYWdlIHJlZnJlc2ggd2hlbiB0aGUgaG9zdCBlbGVtZW50IGlzIGNsaWNrZWRcbiAqIGEgc3BlY2lmaWVkIG51bWJlciBvZiB0aW1lcyB3aXRoaW4gYSBjb25maWd1cmFibGUgdGltZSB3aW5kb3cuXG4gKlxuICogVGhpcyBpcyB1c2VmdWwgZm9yIGFkZGluZyBkZXZlbG9wZXItb3JpZW50ZWQgc2hvcnRjdXRzLCBkaWFnbm9zdGljcyBlbnRyeSBwb2ludHMsXG4gKiBoaWRkZW4gXCJ0cmlwbGUtY2xpY2sgdG8gcmVsb2FkXCIgYmVoYXZpb3JzLCBvciBmYWxsYmFjayBtZWNoYW5pc21zIGluIHByb2R1Y3Rpb24uXG4gKlxuICogVXNhZ2U6XG4gKiBgYGBodG1sXG4gKiA8ZGl2IHRhZUhhcmRSZWZyZXNoIFtjbGlja3NSZXF1aXJlZF09XCIzXCIgW2NsaWNrV2luZG93TXNdPVwiNTAwXCI+Li4uPC9kaXY+XG4gKiBgYGBcbiAqL1xuQERpcmVjdGl2ZSh7XG4gIHNlbGVjdG9yOiAnW3RhZUhhcmRSZWZyZXNoXScsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGhvc3Q6IHtcbiAgICAnKGNsaWNrKSc6ICdjbGlja3MkLm5leHQoKScsXG4gIH0sXG59KVxuZXhwb3J0IGNsYXNzIEhhcmRSZWZyZXNoRGlyZWN0aXZlIHtcbiAgLyoqXG4gICAqIFRoZSBudW1iZXIgb2YgcmFwaWQgY29uc2VjdXRpdmUgY2xpY2tzIHJlcXVpcmVkIHRvIHRyaWdnZXIgYSBoYXJkIHJlZnJlc2guXG4gICAqIEEgXCJyYXBpZFwiIGNsaWNrIGlzIG9uZSB0aGF0IG9jY3VycyB3aXRoaW4gYGNsaWNrV2luZG93TXNgIG9mIHRoZSBwcmV2aW91cyBjbGljay5cbiAgICpcbiAgICogQGRlZmF1bHQgM1xuICAgKi9cbiAgcmVhZG9ubHkgY2xpY2tzUmVxdWlyZWQgPSBpbnB1dDxudW1iZXI+KDMpO1xuXG4gIC8qKlxuICAgKiBUaGUgbWF4aW11bSB0aW1lIGludGVydmFsIChpbiBtaWxsaXNlY29uZHMpIGFsbG93ZWQgYmV0d2VlbiBjb25zZWN1dGl2ZSBjbGlja3NcbiAgICogZm9yIHRoZW0gdG8gYmUgY29uc2lkZXJlZCBwYXJ0IG9mIHRoZSBzYW1lIFwic3RyZWFrXCIuXG4gICAqXG4gICAqIElmIHRoZSBpbnRlcnZhbCBiZXR3ZWVuIHR3byBjbGlja3MgZXhjZWVkcyB0aGlzIHZhbHVlLCB0aGUgc3RyZWFrIHJlc2V0cy5cbiAgICpcbiAgICogQGRlZmF1bHQgNTAwXG4gICAqL1xuICByZWFkb25seSBjbGlja1dpbmRvd01zID0gaW5wdXQ8bnVtYmVyPig1MDApO1xuXG4gIC8qKlxuICAgKiBJbnRlcm5hbCBjbGljayBldmVudCBzdHJlYW0gdXNlZCB0byBidWlsZCB0aGUgcmFwaWQtY2xpY2sgZGV0ZWN0aW9uIHBpcGVsaW5lLlxuICAgKiBFbWl0cyBvbmUgdmFsdWUgcGVyIGhvc3QgY2xpY2sgKHZpYSB0aGUgYChjbGljaylgIGhvc3QgbGlzdGVuZXIpLlxuICAgKi9cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGNsaWNrcyQgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIC8qKlxuICAgICAqIFJhcGlkLWNsaWNrIGRldGVjdGlvbiBwaXBlbGluZTpcbiAgICAgKlxuICAgICAqIC0gVGltZXN0YW1wcyBlYWNoIGNsaWNrLlxuICAgICAqIC0gQ29tcGFyZXMgY29uc2VjdXRpdmUgdGltZXN0YW1wcyB0byBkZXRlcm1pbmUgd2hldGhlciB0aGV5IGZhbGwgd2l0aGluIHRoZVxuICAgICAqICAgY29uZmlndXJlZCBgY2xpY2tXaW5kb3dNc2AgdGhyZXNob2xkLlxuICAgICAqIC0gTWFpbnRhaW5zIGEgc3RyZWFrIGNvdW50IHVzaW5nIGEgcmVkdWNlciAoYHNjYW5gKS5cbiAgICAgKiAtIEVtaXRzIG9uY2UgdGhlIHN0cmVhayBjb3VudCByZWFjaGVzIG9yIGV4Y2VlZHMgYGNsaWNrc1JlcXVpcmVkYC5cbiAgICAgKiAtIFVzZXMgYHRocm90dGxlVGltZWAgdG8gcHJldmVudCBkdXBsaWNhdGUgdHJpZ2dlcnMgd2l0aGluIHRoZSBzYW1lIGJ1cnN0LlxuICAgICAqL1xuICAgIHRoaXMuY2xpY2tzJFxuICAgICAgLnBpcGUoXG4gICAgICAgIHRha2VVbnRpbERlc3Ryb3llZCgpLFxuICAgICAgICAvLyBUdXJuIGNsaWNrIGV2ZW50cyBpbnRvIHJhdyB0aW1lc3RhbXBzIChlcG9jaCBtcylcbiAgICAgICAgdGltZXN0YW1wKCksXG4gICAgICAgIG1hcCgodCkgPT4gdC50aW1lc3RhbXApLFxuICAgICAgICAvLyBXb3JrIGluIHBhaXJzOiBbcHJldmlvdXNUaW1lc3RhbXAsIGN1cnJlbnRUaW1lc3RhbXBdXG4gICAgICAgIHN0YXJ0V2l0aCgwKSxcbiAgICAgICAgcGFpcndpc2UoKSxcbiAgICAgICAgLy8gTWFpbnRhaW4gYSBzdHJlYWsgb2YgY2xpY2tzIHdpdGhpbiB0aGUgdGltZSB3aW5kb3dcbiAgICAgICAgc2NhbihcbiAgICAgICAgICAoYWNjLCBbcHJldiwgY3Vycl0pID0+XG4gICAgICAgICAgICBjdXJyIC0gcHJldiA8PSB0aGlzLmNsaWNrV2luZG93TXMoKSA/IGFjYyArIDEgOiAxLFxuICAgICAgICAgIDBcbiAgICAgICAgKSxcbiAgICAgICAgLy8gT25seSBjb250aW51ZSB3aGVuIHdlIHJlYWNoIHRoZSB0aHJlc2hvbGQgbnVtYmVyIG9mIGNsaWNrc1xuICAgICAgICBmaWx0ZXIoKHN0cmVhaykgPT4gc3RyZWFrID49IHRoaXMuY2xpY2tzUmVxdWlyZWQoKSksXG4gICAgICAgIC8vIEF2b2lkIG11bHRpcGxlIHRyaWdnZXJzIGZvciB0aGUgc2FtZSBcImJ1cnN0XCIgb2YgY2xpY2tzXG4gICAgICAgIHRocm90dGxlVGltZSh0aGlzLmNsaWNrV2luZG93TXMoKSwgdW5kZWZpbmVkLCB7XG4gICAgICAgICAgbGVhZGluZzogdHJ1ZSxcbiAgICAgICAgICB0cmFpbGluZzogZmFsc2UsXG4gICAgICAgIH0pXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgICAgLy8gUmVsb2FkIHRoZSB3aW5kb3dcbiAgICAgICAgd2luZG93LmxvY2F0aW9uLnJlbG9hZCgpO1xuICAgICAgfSk7XG4gIH1cbn1cbiJdfQ==
@@ -138,10 +138,10 @@ export function provideRuntimeConfig(kit, staticEnv, { envPath = '/env/runtime.e
138
138
  this.config ??= staticEnv;
139
139
  return this.config;
140
140
  }
141
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: RuntimeConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
142
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: RuntimeConfigService, providedIn: 'root' });
141
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: RuntimeConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
142
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: RuntimeConfigService, providedIn: 'root' });
143
143
  }
144
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: RuntimeConfigService, decorators: [{
144
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: RuntimeConfigService, decorators: [{
145
145
  type: Injectable,
146
146
  args: [{ providedIn: 'root' }]
147
147
  }] });
@@ -24,11 +24,11 @@ export class ToastComponent {
24
24
  * @returns void
25
25
  */
26
26
  closeToast = (toast) => this.toastService.close(toast.id);
27
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: ToastComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
28
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.13", type: ToastComponent, isStandalone: true, selector: "tds-ext-toast", ngImport: i0, template: "<ul class=\"toast-list\" aria-live=\"polite\" aria-atomic=\"true\">\n @for (toast of toastsSignal(); track toast.id) {\n <li\n class=\"toast-item\"\n [class]=\"'toast-' + toast.type\"\n [class.toast-closing]=\"toast.state === 'closing'\"\n [style.--duration.ms]=\"toast.duration\"\n [style.--close-duration.ms]=\"toast.closeDuration\"\n role=\"status\"\n >\n <tds-toast\n [variant]=\"toast.type\"\n [header]=\"toast.title\"\n [subheader]=\"toast.description\"\n [closable]=\"toast.closable\"\n tds-close-aria-label=\"Toast close button\"\n >\n @if (toast.link) {\n <tds-link slot=\"actions\">\n <a [routerLink]=\"toast.link\">\n {{ toast.linkText ?? 'Click here' }}\n </a>\n </tds-link>\n } @else if (toast.action) {\n <tds-link slot=\"actions\">\n <a href=\"#\" (click)=\"toast.action()\">\n {{ toast.linkText ?? 'Click here' }}\n </a>\n </tds-link>\n }\n </tds-toast>\n @if (toast.closable) {\n <button\n class=\"toast-close\"\n (click)=\"closeToast(toast)\"\n aria-label=\"Close toast\"\n ></button>\n }\n </li>\n }\n</ul>\n", styles: [":host{position:fixed;right:0;bottom:0;overflow:hidden;z-index:9999}.toast-list{display:grid;grid-template-columns:1fr;gap:6px;list-style:none;padding:6px;margin:0}.toast-item{position:relative;animation:fadeIn .3s ease-in forwards}.toast-item.toast-closing{animation-name:fadeOut;animation-duration:var(--close-duration, .3s);animation-fill-mode:forwards;pointer-events:none}.toast-item:before{content:\"\";position:absolute;height:3px;width:100%;bottom:0;left:4px;right:0;animation:progress var(--duration, 7s) linear forwards;border-top-right-radius:4px;border-bottom-right-radius:4px}.toast-item.toast-information:before{background:var(--tds-information)}.toast-item.toast-success:before{background:var(--tds-positive)}.toast-item.toast-warning:before{background:var(--tds-warning)}.toast-item.toast-error:before{background:var(--tds-negative)}.toast-item .toast-close{height:20px;width:20px;box-sizing:border-box;cursor:pointer;position:absolute;top:14px;right:14px;border:0;background:transparent}.toast-item .toast-close:active{border:2px solid var(--tds-blue-400);outline-offset:-2px}@keyframes fadeIn{0%{transform:translateY(40%);opacity:0;margin-bottom:-25%}to{transform:translateY(0);opacity:1;margin-bottom:0%}}@keyframes fadeOut{0%{transform:translateY(0);opacity:1;margin-top:0}to{opacity:0;transform:translateY(75%);margin-top:-25%}}@keyframes progress{to{width:0%}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TegelModule }, { kind: "component", type: i1.TdsLink, selector: "tds-link", inputs: ["disabled", "standalone", "underline"] }, { kind: "component", type: i1.TdsToast, selector: "tds-toast", inputs: ["closable", "header", "hidden", "subheader", "tdsAriaLive", "tdsCloseAriaLabel", "toastId", "toastRole", "variant"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
27
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: ToastComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
28
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: ToastComponent, isStandalone: true, selector: "tae-toast", ngImport: i0, template: "<ul class=\"toast-list\" aria-live=\"polite\" aria-atomic=\"true\">\n @for (toast of toastsSignal(); track toast.id) {\n <li\n class=\"toast-item\"\n [class]=\"'toast-' + toast.type\"\n [class.toast-closing]=\"toast.state === 'closing'\"\n [style.--duration.ms]=\"toast.duration\"\n [style.--close-duration.ms]=\"toast.closeDuration\"\n role=\"status\"\n >\n <tds-toast\n [variant]=\"toast.type\"\n [header]=\"toast.title\"\n [subheader]=\"toast.description\"\n [closable]=\"toast.closable\"\n tds-close-aria-label=\"Toast close button\"\n >\n @if (toast.link) {\n <tds-link slot=\"actions\">\n <a [routerLink]=\"toast.link\">\n {{ toast.linkText ?? 'Click here' }}\n </a>\n </tds-link>\n } @else if (toast.action) {\n <tds-link slot=\"actions\">\n <a href=\"#\" (click)=\"toast.action()\">\n {{ toast.linkText ?? 'Click here' }}\n </a>\n </tds-link>\n }\n </tds-toast>\n @if (toast.closable) {\n <button\n class=\"toast-close\"\n (click)=\"closeToast(toast)\"\n aria-label=\"Close toast\"\n ></button>\n }\n </li>\n }\n</ul>\n", styles: [":host{position:fixed;right:0;bottom:0;overflow:hidden;z-index:9999}.toast-list{display:grid;grid-template-columns:1fr;gap:6px;list-style:none;padding:6px;margin:0}.toast-item{position:relative;animation:fadeIn .3s ease-in forwards}.toast-item.toast-closing{animation-name:fadeOut;animation-duration:var(--close-duration, .3s);animation-fill-mode:forwards;pointer-events:none}.toast-item:before{content:\"\";position:absolute;height:3px;width:100%;bottom:0;left:4px;right:0;animation:progress var(--duration, 7s) linear forwards;border-top-right-radius:4px;border-bottom-right-radius:4px}.toast-item.toast-information:before{background:var(--tds-information)}.toast-item.toast-success:before{background:var(--tds-positive)}.toast-item.toast-warning:before{background:var(--tds-warning)}.toast-item.toast-error:before{background:var(--tds-negative)}.toast-item .toast-close{height:20px;width:20px;box-sizing:border-box;cursor:pointer;position:absolute;top:14px;right:14px;border:0;background:transparent}.toast-item .toast-close:active{border:2px solid var(--tds-blue-400);outline-offset:-2px}@keyframes fadeIn{0%{transform:translateY(40%);opacity:0;margin-bottom:-25%}to{transform:translateY(0);opacity:1;margin-bottom:0%}}@keyframes fadeOut{0%{transform:translateY(0);opacity:1;margin-top:0}to{opacity:0;transform:translateY(75%);margin-top:-25%}}@keyframes progress{to{width:0%}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TegelModule }, { kind: "component", type: i1.TdsLink, selector: "tds-link", inputs: ["disabled", "standalone", "underline"] }, { kind: "component", type: i1.TdsToast, selector: "tds-toast", inputs: ["closable", "header", "hidden", "subheader", "tdsAriaLive", "tdsCloseAriaLabel", "toastId", "toastRole", "variant"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
29
29
  }
30
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: ToastComponent, decorators: [{
30
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: ToastComponent, decorators: [{
31
31
  type: Component,
32
- args: [{ selector: 'tds-ext-toast', imports: [CommonModule, TegelModule, RouterLink], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ul class=\"toast-list\" aria-live=\"polite\" aria-atomic=\"true\">\n @for (toast of toastsSignal(); track toast.id) {\n <li\n class=\"toast-item\"\n [class]=\"'toast-' + toast.type\"\n [class.toast-closing]=\"toast.state === 'closing'\"\n [style.--duration.ms]=\"toast.duration\"\n [style.--close-duration.ms]=\"toast.closeDuration\"\n role=\"status\"\n >\n <tds-toast\n [variant]=\"toast.type\"\n [header]=\"toast.title\"\n [subheader]=\"toast.description\"\n [closable]=\"toast.closable\"\n tds-close-aria-label=\"Toast close button\"\n >\n @if (toast.link) {\n <tds-link slot=\"actions\">\n <a [routerLink]=\"toast.link\">\n {{ toast.linkText ?? 'Click here' }}\n </a>\n </tds-link>\n } @else if (toast.action) {\n <tds-link slot=\"actions\">\n <a href=\"#\" (click)=\"toast.action()\">\n {{ toast.linkText ?? 'Click here' }}\n </a>\n </tds-link>\n }\n </tds-toast>\n @if (toast.closable) {\n <button\n class=\"toast-close\"\n (click)=\"closeToast(toast)\"\n aria-label=\"Close toast\"\n ></button>\n }\n </li>\n }\n</ul>\n", styles: [":host{position:fixed;right:0;bottom:0;overflow:hidden;z-index:9999}.toast-list{display:grid;grid-template-columns:1fr;gap:6px;list-style:none;padding:6px;margin:0}.toast-item{position:relative;animation:fadeIn .3s ease-in forwards}.toast-item.toast-closing{animation-name:fadeOut;animation-duration:var(--close-duration, .3s);animation-fill-mode:forwards;pointer-events:none}.toast-item:before{content:\"\";position:absolute;height:3px;width:100%;bottom:0;left:4px;right:0;animation:progress var(--duration, 7s) linear forwards;border-top-right-radius:4px;border-bottom-right-radius:4px}.toast-item.toast-information:before{background:var(--tds-information)}.toast-item.toast-success:before{background:var(--tds-positive)}.toast-item.toast-warning:before{background:var(--tds-warning)}.toast-item.toast-error:before{background:var(--tds-negative)}.toast-item .toast-close{height:20px;width:20px;box-sizing:border-box;cursor:pointer;position:absolute;top:14px;right:14px;border:0;background:transparent}.toast-item .toast-close:active{border:2px solid var(--tds-blue-400);outline-offset:-2px}@keyframes fadeIn{0%{transform:translateY(40%);opacity:0;margin-bottom:-25%}to{transform:translateY(0);opacity:1;margin-bottom:0%}}@keyframes fadeOut{0%{transform:translateY(0);opacity:1;margin-top:0}to{opacity:0;transform:translateY(75%);margin-top:-25%}}@keyframes progress{to{width:0%}}\n"] }]
32
+ args: [{ selector: 'tae-toast', imports: [CommonModule, TegelModule, RouterLink], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ul class=\"toast-list\" aria-live=\"polite\" aria-atomic=\"true\">\n @for (toast of toastsSignal(); track toast.id) {\n <li\n class=\"toast-item\"\n [class]=\"'toast-' + toast.type\"\n [class.toast-closing]=\"toast.state === 'closing'\"\n [style.--duration.ms]=\"toast.duration\"\n [style.--close-duration.ms]=\"toast.closeDuration\"\n role=\"status\"\n >\n <tds-toast\n [variant]=\"toast.type\"\n [header]=\"toast.title\"\n [subheader]=\"toast.description\"\n [closable]=\"toast.closable\"\n tds-close-aria-label=\"Toast close button\"\n >\n @if (toast.link) {\n <tds-link slot=\"actions\">\n <a [routerLink]=\"toast.link\">\n {{ toast.linkText ?? 'Click here' }}\n </a>\n </tds-link>\n } @else if (toast.action) {\n <tds-link slot=\"actions\">\n <a href=\"#\" (click)=\"toast.action()\">\n {{ toast.linkText ?? 'Click here' }}\n </a>\n </tds-link>\n }\n </tds-toast>\n @if (toast.closable) {\n <button\n class=\"toast-close\"\n (click)=\"closeToast(toast)\"\n aria-label=\"Close toast\"\n ></button>\n }\n </li>\n }\n</ul>\n", styles: [":host{position:fixed;right:0;bottom:0;overflow:hidden;z-index:9999}.toast-list{display:grid;grid-template-columns:1fr;gap:6px;list-style:none;padding:6px;margin:0}.toast-item{position:relative;animation:fadeIn .3s ease-in forwards}.toast-item.toast-closing{animation-name:fadeOut;animation-duration:var(--close-duration, .3s);animation-fill-mode:forwards;pointer-events:none}.toast-item:before{content:\"\";position:absolute;height:3px;width:100%;bottom:0;left:4px;right:0;animation:progress var(--duration, 7s) linear forwards;border-top-right-radius:4px;border-bottom-right-radius:4px}.toast-item.toast-information:before{background:var(--tds-information)}.toast-item.toast-success:before{background:var(--tds-positive)}.toast-item.toast-warning:before{background:var(--tds-warning)}.toast-item.toast-error:before{background:var(--tds-negative)}.toast-item .toast-close{height:20px;width:20px;box-sizing:border-box;cursor:pointer;position:absolute;top:14px;right:14px;border:0;background:transparent}.toast-item .toast-close:active{border:2px solid var(--tds-blue-400);outline-offset:-2px}@keyframes fadeIn{0%{transform:translateY(40%);opacity:0;margin-bottom:-25%}to{transform:translateY(0);opacity:1;margin-bottom:0%}}@keyframes fadeOut{0%{transform:translateY(0);opacity:1;margin-top:0}to{opacity:0;transform:translateY(75%);margin-top:-25%}}@keyframes progress{to{width:0%}}\n"] }]
33
33
  }] });
34
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9hc3QuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy90ZWdlbC1hbmd1bGFyLWV4dGVuc2lvbnMvc3JjL2xpYi90b2FzdC90b2FzdC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9saWJzL3RlZ2VsLWFuZ3VsYXItZXh0ZW5zaW9ucy9zcmMvbGliL3RvYXN0L3RvYXN0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDN0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBR3ZELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQzs7O0FBRS9DOzs7OztHQUtHO0FBUUgsTUFBTSxPQUFPLGNBQWM7SUFDUixZQUFZLEdBQUcsTUFBTSxDQUFDLFlBQVksQ0FBQyxDQUFDO0lBRXJEOztPQUVHO0lBQ00sWUFBWSxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsWUFBWSxDQUFDO0lBRXZEOzs7OztPQUtHO0lBQ0gsVUFBVSxHQUFHLENBQUMsS0FBWSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7d0dBZHRELGNBQWM7NEZBQWQsY0FBYyx5RUNyQjNCLDBxQ0F5Q0EsKzVDRHZCWSxZQUFZLDhCQUFFLFdBQVcsOFVBQUUsVUFBVTs7NEZBR3BDLGNBQWM7a0JBUDFCLFNBQVM7K0JBQ0UsZUFBZSxXQUdoQixDQUFDLFlBQVksRUFBRSxXQUFXLEVBQUUsVUFBVSxDQUFDLG1CQUMvQix1QkFBdUIsQ0FBQyxNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IENoYW5nZURldGVjdGlvblN0cmF0ZWd5LCBDb21wb25lbnQsIGluamVjdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgUm91dGVyTGluayB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XG5pbXBvcnQgeyBUZWdlbE1vZHVsZSB9IGZyb20gJ0BzY2FuaWEvdGVnZWwtYW5ndWxhci0xNyc7XG5cbmltcG9ydCB7IFRvYXN0IH0gZnJvbSAnLi9tb2RlbHMvdG9hc3QubW9kZWwnO1xuaW1wb3J0IHsgVG9hc3RTZXJ2aWNlIH0gZnJvbSAnLi90b2FzdC5zZXJ2aWNlJztcblxuLyoqXG4gKiBEaXNwbGF5cyB0b2FzdCBub3RpZmljYXRpb25zIHByb3ZpZGVkIGJ5IHRoZSBUb2FzdFNlcnZpY2UuXG4gKlxuICogVG9hc3RzIGFyZSBub24tYmxvY2tpbmcgbWVzc2FnZXMgdGhhdCBhdXRvbWF0aWNhbGx5IGRpc2FwcGVhciBhZnRlciBhIHNldCBkdXJhdGlvblxuICogb3IgY2FuIGJlIGRpc21pc3NlZCBtYW51YWxseSBieSB0aGUgdXNlci5cbiAqL1xuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAndGRzLWV4dC10b2FzdCcsXG4gIHRlbXBsYXRlVXJsOiAnLi90b2FzdC5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL3RvYXN0LmNvbXBvbmVudC5zY3NzJ10sXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGUsIFRlZ2VsTW9kdWxlLCBSb3V0ZXJMaW5rXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG59KVxuZXhwb3J0IGNsYXNzIFRvYXN0Q29tcG9uZW50IHtcbiAgcHJpdmF0ZSByZWFkb25seSB0b2FzdFNlcnZpY2UgPSBpbmplY3QoVG9hc3RTZXJ2aWNlKTtcblxuICAvKipcbiAgICogQSByZWFjdGl2ZSBzaWduYWwgb2YgYWxsIGN1cnJlbnRseSBhY3RpdmUgdG9hc3RzIChvcGVuIG9yIGNsb3NpbmcpLlxuICAgKi9cbiAgcmVhZG9ubHkgdG9hc3RzU2lnbmFsID0gdGhpcy50b2FzdFNlcnZpY2UuYWN0aXZlVG9hc3RzO1xuXG4gIC8qKlxuICAgKiBJbml0aWF0ZXMgdGhlIGNsb3NpbmcgcHJvY2VzcyBmb3IgdGhlIGdpdmVuIHRvYXN0LlxuICAgKlxuICAgKiBAcGFyYW0gdG9hc3QgVGhlIHRvYXN0IHRvIGJlIGNsb3NlZC5cbiAgICogQHJldHVybnMgdm9pZFxuICAgKi9cbiAgY2xvc2VUb2FzdCA9ICh0b2FzdDogVG9hc3QpID0+IHRoaXMudG9hc3RTZXJ2aWNlLmNsb3NlKHRvYXN0LmlkKTtcbn1cbiIsIjx1bCBjbGFzcz1cInRvYXN0LWxpc3RcIiBhcmlhLWxpdmU9XCJwb2xpdGVcIiBhcmlhLWF0b21pYz1cInRydWVcIj5cbiAgQGZvciAodG9hc3Qgb2YgdG9hc3RzU2lnbmFsKCk7IHRyYWNrIHRvYXN0LmlkKSB7XG4gIDxsaVxuICAgIGNsYXNzPVwidG9hc3QtaXRlbVwiXG4gICAgW2NsYXNzXT1cIid0b2FzdC0nICsgdG9hc3QudHlwZVwiXG4gICAgW2NsYXNzLnRvYXN0LWNsb3NpbmddPVwidG9hc3Quc3RhdGUgPT09ICdjbG9zaW5nJ1wiXG4gICAgW3N0eWxlLi0tZHVyYXRpb24ubXNdPVwidG9hc3QuZHVyYXRpb25cIlxuICAgIFtzdHlsZS4tLWNsb3NlLWR1cmF0aW9uLm1zXT1cInRvYXN0LmNsb3NlRHVyYXRpb25cIlxuICAgIHJvbGU9XCJzdGF0dXNcIlxuICA+XG4gICAgPHRkcy10b2FzdFxuICAgICAgW3ZhcmlhbnRdPVwidG9hc3QudHlwZVwiXG4gICAgICBbaGVhZGVyXT1cInRvYXN0LnRpdGxlXCJcbiAgICAgIFtzdWJoZWFkZXJdPVwidG9hc3QuZGVzY3JpcHRpb25cIlxuICAgICAgW2Nsb3NhYmxlXT1cInRvYXN0LmNsb3NhYmxlXCJcbiAgICAgIHRkcy1jbG9zZS1hcmlhLWxhYmVsPVwiVG9hc3QgY2xvc2UgYnV0dG9uXCJcbiAgICA+XG4gICAgICBAaWYgKHRvYXN0LmxpbmspIHtcbiAgICAgIDx0ZHMtbGluayBzbG90PVwiYWN0aW9uc1wiPlxuICAgICAgICA8YSBbcm91dGVyTGlua109XCJ0b2FzdC5saW5rXCI+XG4gICAgICAgICAge3sgdG9hc3QubGlua1RleHQgPz8gJ0NsaWNrIGhlcmUnIH19XG4gICAgICAgIDwvYT5cbiAgICAgIDwvdGRzLWxpbms+XG4gICAgICB9IEBlbHNlIGlmICh0b2FzdC5hY3Rpb24pIHtcbiAgICAgIDx0ZHMtbGluayBzbG90PVwiYWN0aW9uc1wiPlxuICAgICAgICA8YSBocmVmPVwiI1wiIChjbGljayk9XCJ0b2FzdC5hY3Rpb24oKVwiPlxuICAgICAgICAgIHt7IHRvYXN0LmxpbmtUZXh0ID8/ICdDbGljayBoZXJlJyB9fVxuICAgICAgICA8L2E+XG4gICAgICA8L3Rkcy1saW5rPlxuICAgICAgfVxuICAgIDwvdGRzLXRvYXN0PlxuICAgIEBpZiAodG9hc3QuY2xvc2FibGUpIHtcbiAgICA8YnV0dG9uXG4gICAgICBjbGFzcz1cInRvYXN0LWNsb3NlXCJcbiAgICAgIChjbGljayk9XCJjbG9zZVRvYXN0KHRvYXN0KVwiXG4gICAgICBhcmlhLWxhYmVsPVwiQ2xvc2UgdG9hc3RcIlxuICAgID48L2J1dHRvbj5cbiAgICB9XG4gIDwvbGk+XG4gIH1cbjwvdWw+XG4iXX0=
34
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9hc3QuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy90ZWdlbC1hbmd1bGFyLWV4dGVuc2lvbnMvc3JjL2xpYi90b2FzdC90b2FzdC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9saWJzL3RlZ2VsLWFuZ3VsYXItZXh0ZW5zaW9ucy9zcmMvbGliL3RvYXN0L3RvYXN0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDN0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBR3ZELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQzs7O0FBRS9DOzs7OztHQUtHO0FBUUgsTUFBTSxPQUFPLGNBQWM7SUFDUixZQUFZLEdBQUcsTUFBTSxDQUFDLFlBQVksQ0FBQyxDQUFDO0lBRXJEOztPQUVHO0lBQ00sWUFBWSxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsWUFBWSxDQUFDO0lBRXZEOzs7OztPQUtHO0lBQ0gsVUFBVSxHQUFHLENBQUMsS0FBWSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7d0dBZHRELGNBQWM7NEZBQWQsY0FBYyxxRUNyQjNCLDBxQ0F5Q0EsKzVDRHZCWSxZQUFZLDhCQUFFLFdBQVcsOFVBQUUsVUFBVTs7NEZBR3BDLGNBQWM7a0JBUDFCLFNBQVM7K0JBQ0UsV0FBVyxXQUdaLENBQUMsWUFBWSxFQUFFLFdBQVcsRUFBRSxVQUFVLENBQUMsbUJBQy9CLHVCQUF1QixDQUFDLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksIENvbXBvbmVudCwgaW5qZWN0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBSb3V0ZXJMaW5rIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcbmltcG9ydCB7IFRlZ2VsTW9kdWxlIH0gZnJvbSAnQHNjYW5pYS90ZWdlbC1hbmd1bGFyLTE3JztcblxuaW1wb3J0IHsgVG9hc3QgfSBmcm9tICcuL21vZGVscy90b2FzdC5tb2RlbCc7XG5pbXBvcnQgeyBUb2FzdFNlcnZpY2UgfSBmcm9tICcuL3RvYXN0LnNlcnZpY2UnO1xuXG4vKipcbiAqIERpc3BsYXlzIHRvYXN0IG5vdGlmaWNhdGlvbnMgcHJvdmlkZWQgYnkgdGhlIFRvYXN0U2VydmljZS5cbiAqXG4gKiBUb2FzdHMgYXJlIG5vbi1ibG9ja2luZyBtZXNzYWdlcyB0aGF0IGF1dG9tYXRpY2FsbHkgZGlzYXBwZWFyIGFmdGVyIGEgc2V0IGR1cmF0aW9uXG4gKiBvciBjYW4gYmUgZGlzbWlzc2VkIG1hbnVhbGx5IGJ5IHRoZSB1c2VyLlxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICd0YWUtdG9hc3QnLFxuICB0ZW1wbGF0ZVVybDogJy4vdG9hc3QuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi90b2FzdC5jb21wb25lbnQuc2NzcyddLFxuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlLCBUZWdlbE1vZHVsZSwgUm91dGVyTGlua10sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBUb2FzdENvbXBvbmVudCB7XG4gIHByaXZhdGUgcmVhZG9ubHkgdG9hc3RTZXJ2aWNlID0gaW5qZWN0KFRvYXN0U2VydmljZSk7XG5cbiAgLyoqXG4gICAqIEEgcmVhY3RpdmUgc2lnbmFsIG9mIGFsbCBjdXJyZW50bHkgYWN0aXZlIHRvYXN0cyAob3BlbiBvciBjbG9zaW5nKS5cbiAgICovXG4gIHJlYWRvbmx5IHRvYXN0c1NpZ25hbCA9IHRoaXMudG9hc3RTZXJ2aWNlLmFjdGl2ZVRvYXN0cztcblxuICAvKipcbiAgICogSW5pdGlhdGVzIHRoZSBjbG9zaW5nIHByb2Nlc3MgZm9yIHRoZSBnaXZlbiB0b2FzdC5cbiAgICpcbiAgICogQHBhcmFtIHRvYXN0IFRoZSB0b2FzdCB0byBiZSBjbG9zZWQuXG4gICAqIEByZXR1cm5zIHZvaWRcbiAgICovXG4gIGNsb3NlVG9hc3QgPSAodG9hc3Q6IFRvYXN0KSA9PiB0aGlzLnRvYXN0U2VydmljZS5jbG9zZSh0b2FzdC5pZCk7XG59XG4iLCI8dWwgY2xhc3M9XCJ0b2FzdC1saXN0XCIgYXJpYS1saXZlPVwicG9saXRlXCIgYXJpYS1hdG9taWM9XCJ0cnVlXCI+XG4gIEBmb3IgKHRvYXN0IG9mIHRvYXN0c1NpZ25hbCgpOyB0cmFjayB0b2FzdC5pZCkge1xuICA8bGlcbiAgICBjbGFzcz1cInRvYXN0LWl0ZW1cIlxuICAgIFtjbGFzc109XCIndG9hc3QtJyArIHRvYXN0LnR5cGVcIlxuICAgIFtjbGFzcy50b2FzdC1jbG9zaW5nXT1cInRvYXN0LnN0YXRlID09PSAnY2xvc2luZydcIlxuICAgIFtzdHlsZS4tLWR1cmF0aW9uLm1zXT1cInRvYXN0LmR1cmF0aW9uXCJcbiAgICBbc3R5bGUuLS1jbG9zZS1kdXJhdGlvbi5tc109XCJ0b2FzdC5jbG9zZUR1cmF0aW9uXCJcbiAgICByb2xlPVwic3RhdHVzXCJcbiAgPlxuICAgIDx0ZHMtdG9hc3RcbiAgICAgIFt2YXJpYW50XT1cInRvYXN0LnR5cGVcIlxuICAgICAgW2hlYWRlcl09XCJ0b2FzdC50aXRsZVwiXG4gICAgICBbc3ViaGVhZGVyXT1cInRvYXN0LmRlc2NyaXB0aW9uXCJcbiAgICAgIFtjbG9zYWJsZV09XCJ0b2FzdC5jbG9zYWJsZVwiXG4gICAgICB0ZHMtY2xvc2UtYXJpYS1sYWJlbD1cIlRvYXN0IGNsb3NlIGJ1dHRvblwiXG4gICAgPlxuICAgICAgQGlmICh0b2FzdC5saW5rKSB7XG4gICAgICA8dGRzLWxpbmsgc2xvdD1cImFjdGlvbnNcIj5cbiAgICAgICAgPGEgW3JvdXRlckxpbmtdPVwidG9hc3QubGlua1wiPlxuICAgICAgICAgIHt7IHRvYXN0LmxpbmtUZXh0ID8/ICdDbGljayBoZXJlJyB9fVxuICAgICAgICA8L2E+XG4gICAgICA8L3Rkcy1saW5rPlxuICAgICAgfSBAZWxzZSBpZiAodG9hc3QuYWN0aW9uKSB7XG4gICAgICA8dGRzLWxpbmsgc2xvdD1cImFjdGlvbnNcIj5cbiAgICAgICAgPGEgaHJlZj1cIiNcIiAoY2xpY2spPVwidG9hc3QuYWN0aW9uKClcIj5cbiAgICAgICAgICB7eyB0b2FzdC5saW5rVGV4dCA/PyAnQ2xpY2sgaGVyZScgfX1cbiAgICAgICAgPC9hPlxuICAgICAgPC90ZHMtbGluaz5cbiAgICAgIH1cbiAgICA8L3Rkcy10b2FzdD5cbiAgICBAaWYgKHRvYXN0LmNsb3NhYmxlKSB7XG4gICAgPGJ1dHRvblxuICAgICAgY2xhc3M9XCJ0b2FzdC1jbG9zZVwiXG4gICAgICAoY2xpY2spPVwiY2xvc2VUb2FzdCh0b2FzdClcIlxuICAgICAgYXJpYS1sYWJlbD1cIkNsb3NlIHRvYXN0XCJcbiAgICA+PC9idXR0b24+XG4gICAgfVxuICA8L2xpPlxuICB9XG48L3VsPlxuIl19
@@ -194,10 +194,10 @@ export class ToastService {
194
194
  const num = typeof value === 'number' ? value : fallback;
195
195
  return !Number.isFinite(num) || num < 0 ? 0 : num;
196
196
  }
197
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: ToastService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
198
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: ToastService, providedIn: 'root' });
197
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: ToastService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
198
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: ToastService, providedIn: 'root' });
199
199
  }
200
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: ToastService, decorators: [{
200
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: ToastService, decorators: [{
201
201
  type: Injectable,
202
202
  args: [{
203
203
  providedIn: 'root',
package/index.d.ts CHANGED
@@ -2,6 +2,7 @@ import * as _angular_core from '@angular/core';
2
2
  import { InjectionToken, EnvironmentProviders } from '@angular/core';
3
3
  import z$1, { z } from 'zod';
4
4
  import { zx } from '@traversable/zod';
5
+ import { Subject } from 'rxjs';
5
6
 
6
7
  /**
7
8
  * List of available toast types (inherited from Tegel)
@@ -463,5 +464,134 @@ type ProvideStaticConfigOptions<T> = {
463
464
  */
464
465
  declare function provideStaticConfig<T>(env: T | undefined, options: ProvideStaticConfigOptions<T>): EnvironmentProviders;
465
466
 
466
- export { DEFAULT_TOAST_CONFIG, TOAST_CONFIG, ToastService, createEnvKit, parseEnvFile, provideRuntimeConfig, provideStaticConfig, provideToast };
467
+ /**
468
+ * Directive that listens for rapid key sequences ending in a terminator key
469
+ * (default: Enter) and emits the collected characters as a barcode string.
470
+ *
471
+ * @example
472
+ * <ng-container
473
+ * taeBarcodeScanner
474
+ * (barcodeScanned)="handleScan($event)"
475
+ * [inputWindowMs]="100"
476
+ * terminatorKey="Enter"
477
+ * />
478
+ */
479
+ declare class BarcodeScannerDirective {
480
+ /**
481
+ * Angular zone used to run key handling outside of change detection.
482
+ */
483
+ private readonly _ngZone;
484
+ /**
485
+ * Document reference for attaching global keydown event listeners.
486
+ */
487
+ private readonly _document;
488
+ /**
489
+ * Maximum time window in milliseconds between consecutive keypresses.
490
+ * Sequences exceeding this duration are discarded.
491
+ *
492
+ * @default 100
493
+ */
494
+ readonly inputWindowMs: _angular_core.InputSignal<number>;
495
+ /**
496
+ * Key that terminates and completes a barcode sequence.
497
+ *
498
+ * @default "Enter"
499
+ */
500
+ readonly terminatorKey: _angular_core.InputSignal<string>;
501
+ /**
502
+ * Emits the complete barcode string captured from the scanner.
503
+ * * @remarks
504
+ * This output is required by the directive selector.
505
+ */
506
+ readonly barcodeScanned: _angular_core.OutputEmitterRef<string>;
507
+ /**
508
+ * Sets up the global keydown listener and barcode detection pipeline.
509
+ * The pipeline runs outside Angular's zone and only re-enters when a barcode
510
+ * is emitted, to avoid triggering change detection on every keypress.
511
+ */
512
+ constructor();
513
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<BarcodeScannerDirective, never>;
514
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<BarcodeScannerDirective, "[taeBarcodeScanner]", never, { "inputWindowMs": { "alias": "inputWindowMs"; "required": false; "isSignal": true; }; "terminatorKey": { "alias": "terminatorKey"; "required": false; "isSignal": true; }; }, { "barcodeScanned": "barcodeScanned"; }, never, never, true, never>;
515
+ }
516
+
517
+ /**
518
+ * Directive that triggers a hard page refresh when the host element is clicked
519
+ * a specified number of times within a configurable time window.
520
+ *
521
+ * This is useful for adding developer-oriented shortcuts, diagnostics entry points,
522
+ * hidden "triple-click to reload" behaviors, or fallback mechanisms in production.
523
+ *
524
+ * Usage:
525
+ * ```html
526
+ * <div taeHardRefresh [clicksRequired]="3" [clickWindowMs]="500">...</div>
527
+ * ```
528
+ */
529
+ declare class HardRefreshDirective {
530
+ /**
531
+ * The number of rapid consecutive clicks required to trigger a hard refresh.
532
+ * A "rapid" click is one that occurs within `clickWindowMs` of the previous click.
533
+ *
534
+ * @default 3
535
+ */
536
+ readonly clicksRequired: _angular_core.InputSignal<number>;
537
+ /**
538
+ * The maximum time interval (in milliseconds) allowed between consecutive clicks
539
+ * for them to be considered part of the same "streak".
540
+ *
541
+ * If the interval between two clicks exceeds this value, the streak resets.
542
+ *
543
+ * @default 500
544
+ */
545
+ readonly clickWindowMs: _angular_core.InputSignal<number>;
546
+ /**
547
+ * Internal click event stream used to build the rapid-click detection pipeline.
548
+ * Emits one value per host click (via the `(click)` host listener).
549
+ */
550
+ protected readonly clicks$: Subject<void>;
551
+ constructor();
552
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<HardRefreshDirective, never>;
553
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<HardRefreshDirective, "[taeHardRefresh]", never, { "clicksRequired": { "alias": "clicksRequired"; "required": false; "isSignal": true; }; "clickWindowMs": { "alias": "clickWindowMs"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
554
+ }
555
+
556
+ /**
557
+ * An enhanced standalone footer component based on the Tegel `TdsFooterComponent`.
558
+ *
559
+ * `TaeFooterComponent` maintains the same visual style as the original
560
+ * Tegel footer, but adds two key improvements:
561
+ *
562
+ * - A **compact “small” variant** for layouts where vertical space is limited.
563
+ * - Optional **version display**, allowing applications to show their
564
+ * build or release version directly in the footer.
565
+ *
566
+ * Example:
567
+ * ```html
568
+ * <tae-footer variant="small" version="v1.0.0" />
569
+ * ```
570
+ */
571
+ declare class TaeFooterComponent {
572
+ /**
573
+ * Determines the visual layout of the footer.
574
+ *
575
+ * - `"normal"` displays the standard footer layout (aligned to tds-footer)
576
+ * - `"small"` produces a more compact version suitable for tight layouts
577
+ *
578
+ * @default 'normal'
579
+ */
580
+ readonly variant: _angular_core.InputSignal<"normal" | "small">;
581
+ /**
582
+ * Optional application version string to display in the footer.
583
+ *
584
+ * When provided, it appears left of the Scania logo.
585
+ * If omitted or `undefined`, the version section is not shown.
586
+ */
587
+ readonly version: _angular_core.InputSignal<string | undefined>;
588
+ /**
589
+ * The current year used in the copyright section.
590
+ */
591
+ readonly currentYear: number;
592
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TaeFooterComponent, never>;
593
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TaeFooterComponent, "tae-footer", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "version": { "alias": "version"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
594
+ }
595
+
596
+ export { BarcodeScannerDirective, DEFAULT_TOAST_CONFIG, HardRefreshDirective, TOAST_CONFIG, TaeFooterComponent, ToastService, createEnvKit, parseEnvFile, provideRuntimeConfig, provideStaticConfig, provideToast };
467
597
  export type { Toast, ToastConfig, ToastOptions };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scania-nl/tegel-angular-extensions",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"