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

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
@@ -5,24 +5,30 @@
5
5
 
6
6
  # @scania-nl/tegel-angular-extensions
7
7
 
8
- Angular services for working with the [Tegel Angular 17](https://www.npmjs.com/package/@scania/tegel-angular-17) component library.
9
- Provides simple wrappers for toast and modal (TBC) functionality using Angular 19+ **standalone components** and **dependency injection configuration**.
8
+ Angular components, services, and directives for working with the [Tegel Angular 17](https://www.npmjs.com/package/@scania/tegel-angular-17) component library.
9
+ Provides simple wrappers for toast and modal functionality using Angular 19+ **standalone components** and **dependency injection configuration**.
10
10
 
11
11
  ---
12
12
 
13
- ## ✨ Features
13
+  
14
+
15
+ ## Features
14
16
 
15
17
  1. **Runtime environment configuration**
16
18
  - Schema-driven configuration and validation using Zod
17
19
  - Deep-partial runtime overrides
18
20
  - Runtime-required key enforcements
19
21
  - Strong TypeScript inference
20
- 2. **ToastService**
21
- - Drop-in UI integrations for Tegel Angular
22
+ 2. **Toast management**
22
23
  - Signal-based `ToastService` for displaying toasts
23
24
  - Customizable toast appearance and behavior
24
- 3. **Standalone components and directives**
25
- 4. **Default Nginx config**
25
+ 3. **Modal management**
26
+ - Strongly typed modal API
27
+ - Dynamic body content (string, template, or component)
28
+ - Configurable actions and lifecycle callbacks
29
+ 4. **Standalone components and directives**
30
+ - Drop-in UI integrations for Tegel Angular
31
+ 5. **Default Nginx config**
26
32
 
27
33
  - Zero boilerplate - no Angular modules required
28
34
  - Fully typed and configurable via DI
@@ -30,10 +36,12 @@ Provides simple wrappers for toast and modal (TBC) functionality using Angular 1
30
36
 
31
37
  ---
32
38
 
33
- # 📘 Table of Contents
39
+  
40
+
41
+ # Table of Contents
34
42
 
35
- 1. [Installation](#-installation)
36
- 2. [Environment Configuration Overview](#-environment-configuration-overview)
43
+ 1. [Installation](#installation)
44
+ 2. [Environment Configuration Overview](#environment-configuration-overview)
37
45
  1. [Defining your schema with createEnvKit](#defining-your-schema-with-createenvkit)
38
46
  2. [Defining Static Environments (Dev/Prod)](#defining-static-environments-devprod)
39
47
  3. [Providing Runtime Configuration](#providing-runtime-configuration)
@@ -43,28 +51,40 @@ Provides simple wrappers for toast and modal (TBC) functionality using Angular 1
43
51
  2. [`extract-env-vars.sh`](#extract-env-varssh)
44
52
  3. [`nginx.conf`](#nginxconf)
45
53
  4. [Example Docker Commands](#example-docker-commands)
46
- 3. [Toasts](#-toasts)
47
- 1. [Quick Start](#-quick-start)
54
+ 3. [Toasts](#toasts)
55
+ 1. [Quick Start](#quick-start)
48
56
  1. [Add Providers](#add-providers)
49
57
  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)
58
+ 2. [Toast Configuration Options](#toast-configuration-options)
59
+ 3. [ToastService API](#toastservice-api)
60
+ 1. [ToastService Properties](#toastservice-properties)
61
+ 2. [ToastService Methods](#toastservice-methods)
62
+ 3. [Toast Lifecycle Hooks](#toast-lifecycle-hooks)
63
+ 4. [Modals](#modals)
64
+ 1. [Quick Start](#quick-start-1)
65
+ 1. [Add Providers](#add-providers-1)
66
+ 2. [Use in components](#use-in-components-1)
67
+ 2. [Modal Configuration Options](#modal-configuration-options)
68
+ 3. [ModalService API](#modalservice-api)
69
+ 1. [ModalService Properties](#modalservice-properties)
70
+ 2. [ModalService Methods](#modalservice-methods)
71
+ 3. [Modal Lifecycle Hooks](#modal-lifecycle-hooks)
72
+ 5. [Components & Directives](#components--directives)
73
+ 1. [Components](#components)
74
+ 1. [DateTime Picker](#datetime-picker-component-tae-date-time-picker)
57
75
  1. [Footer](#footer-component-tae-footer)
58
- 2. [Directives](#-directives)
76
+ 2. [Directives](#directives)
59
77
  1. [Hard Refresh](#hard-refresh-directive-taehardrefresh)
60
78
  2. [Barcode Scanner](#barcode-scanner-directive-taebarcodescanner)
61
- 5. [Appendix](#appendix)
79
+ 6. [Appendix](#appendix)
62
80
  1. [Dockerfile Example](#runtime-config-dockerfile-example)
63
- 6. [License](#-license)
81
+ 7. [License](#license)
64
82
 
65
83
  ---
66
84
 
67
- # 📦 Installation
85
+  
86
+
87
+ # Installation
68
88
 
69
89
  ```bash
70
90
  npm install @scania-nl/tegel-angular-extensions @scania/tegel-angular-17 @traversable/zod zod
@@ -76,16 +96,18 @@ When creating an Angular project, the following dependencies already should have
76
96
 
77
97
  ```json
78
98
  {
79
- "@angular/common": "^19.0.0",
80
- "@angular/core": "^19.0.0",
81
- "@angular/router": "^19.0.0",
99
+ "@angular/common": ">=19",
100
+ "@angular/core": ">=19",
101
+ "@angular/router": ">=19",
82
102
  "rxjs": ">=7.8.0"
83
103
  }
84
104
  ```
85
105
 
86
106
  ---
87
107
 
88
- # 🌍 Environment Configuration Overview
108
+  
109
+
110
+ # Environment Configuration Overview
89
111
 
90
112
  The runtime-config system provides:
91
113
 
@@ -94,6 +116,8 @@ The runtime-config system provides:
94
116
  - Runtime overrides via .env files (shell scripts included)
95
117
  - Guaranteed config availability before app bootstrap
96
118
 
119
+  
120
+
97
121
  ## Defining your schema with createEnvKit
98
122
 
99
123
  Create a local file: `src/environments/environment-config.ts`
@@ -207,7 +231,7 @@ This setup involves several key steps:
207
231
  - At application startup, the code loads `/env/runtime.env`, parses any overrides using Zod (via a deep-partial schema), and merges them with the static configuration.
208
232
  - Required configuration keys are enforced **only** in production.
209
233
  - The validated configuration is exposed through Angular DI using the `ENV_CONFIG` InjectionToken.
210
- - The `environment` file is referenced directly here. Angulars build process replaces the `development` environment with the `production` environment via file replacement based on the selected build configuration.
234
+ - The `environment` file is referenced directly here. Angular's build process replaces the `development` environment with the `production` environment via file replacement based on the selected build configuration.
211
235
 
212
236
  > The `/env/runtime.env` file must be generated by the container during startup.
213
237
  > Shell script binaries to support this are included the package.
@@ -218,12 +242,16 @@ This setup involves several key steps:
218
242
 
219
243
  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.
220
244
 
245
+  
246
+
221
247
  ### `docker-entrypoint.sh`
222
248
 
223
249
  - Entry point executed every time the container starts
224
250
  - Calls the `extract-env-vars.sh` to generate a fresh `runtime.env`
225
251
  - Lastly, executes the provided Dockerfile `CMD`
226
252
 
253
+  
254
+
227
255
  ### `extract-env-vars.sh`
228
256
 
229
257
  - Reads all container environment variables matching a prefix (default: `NG__`)
@@ -231,6 +259,8 @@ This package ships with two lightweight shell scripts used to generate a runtime
231
259
  - Supports nested keys via ** (e.g., `NG**myFeature\_\_myThreshold`)
232
260
  - Defaults output to `/usr/share/nginx/html/env/runtime.env`
233
261
 
262
+  
263
+
234
264
  ### `nginx.conf`
235
265
 
236
266
  A default Nginx configuration optimized for Angular applications. It provides:
@@ -240,6 +270,8 @@ A default Nginx configuration optimized for Angular applications. It provides:
240
270
  - Gzip compression where supported
241
271
  - Automatic fallback to `index.html` for client-side routing
242
272
 
273
+  
274
+
243
275
  ### **Example Docker Commands**
244
276
 
245
277
  ```Dockerfile
@@ -255,21 +287,24 @@ CMD ["nginx", "-g", "daemon off;"]
255
287
 
256
288
  For a complete Dockerfile example with the shipped `nginx.conf` config, refer to [Runtime Config Dockerfile Example](#runtime-config-dockerfile-example)
257
289
 
258
-  
259
-
260
290
  ---
261
291
 
262
- # 🔔 Toasts
292
+  
293
+
294
+ # Toasts
263
295
 
264
296
  A lightweight, standalone toast system that integrates seamlessly with Tegel Angular. Provides configurable, signal-driven notifications for success, error, warning, and information messages.
265
297
 
266
- ## 🚀 Quick Start
298
+  
299
+
300
+ ## Quick Start
267
301
 
268
302
  ### Add Providers
269
303
 
270
304
  In your `app.config.ts`, specify the provider with `provideToast()`:
271
305
 
272
306
  ```ts
307
+ // app.config.ts
273
308
  import { provideToast } from '@scania-nl/tegel-angular-extensions';
274
309
 
275
310
  export const appConfig: ApplicationConfig = {
@@ -288,6 +323,8 @@ export const appConfig: ApplicationConfig = {
288
323
 
289
324
  > Note: The configuration is optional, all values shown above are the default settings.
290
325
 
326
+  
327
+
291
328
  ### Use in components
292
329
 
293
330
  In any standalone component:
@@ -315,7 +352,7 @@ export class MyToastDemoComponent {
315
352
 
316
353
   
317
354
 
318
- ## ⚙️ Configuration Options
355
+ ## Toast Configuration Options
319
356
 
320
357
  You can configure the default appearance and behavior of toasts by passing a `ToastConfig` object to `provideToast()` in your `app.config.ts`.
321
358
 
@@ -336,22 +373,22 @@ All options are optional. Defaults will be applied if values are not provided.
336
373
 
337
374
   
338
375
 
339
- ## 🧩 ToastService API
376
+ ## ToastService API
340
377
 
341
378
  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
379
 
343
- ---
380
+  
344
381
 
345
- ### 📦 ToastService Properties
382
+ ### ToastService Properties
346
383
 
347
384
  | Property | Type | Description |
348
385
  | -------------- | ----------------- | ----------------------------------------------------- |
349
386
  | `toasts` | `Signal<Toast[]>` | Read-only list of all toasts (including closed) |
350
387
  | `activeToasts` | `Signal<Toast[]>` | List of currently active toasts (`Open` or `Closing`) |
351
388
 
352
- ---
389
+ &nbsp;
353
390
 
354
- ### 🔧 ToastService Methods
391
+ ### ToastService Methods
355
392
 
356
393
  #### `create(toastOptions: Partial<ToastOptions>): number`
357
394
 
@@ -425,7 +462,9 @@ Force-removes all toasts instantly (no animations).
425
462
 
426
463
  ---
427
464
 
428
- ### 🔁 Toast Lifecycle Hooks
465
+ &nbsp;
466
+
467
+ ### Toast Lifecycle Hooks
429
468
 
430
469
  Each toast supports optional lifecycle callbacks:
431
470
 
@@ -449,12 +488,425 @@ toastService.success({
449
488
 
450
489
  &nbsp;
451
490
 
452
- # 🧩 Components & Directives
491
+ # Modals
492
+
493
+ Standalone modal service + host for Tegel's `tds-modal`, with strongly‑typed options and dynamic body support.
494
+
495
+ &nbsp;
496
+
497
+ ## Quick Start
498
+
499
+ ### Add Providers
500
+
501
+ In your `app.config.ts`, specify the provider with `provideModal()`:
502
+
503
+ ```ts
504
+ // app.config.ts
505
+ import { provideModal } from '@scania-nl/tegel-angular-extensions';
506
+
507
+ export const appConfig: ApplicationConfig = {
508
+ providers: [
509
+ provideModal({
510
+ size: 'md', // Modal size
511
+ actionsPosition: 'static', // Actions slot behavior
512
+ prevent: false, // Prevent overlay click from closing the modal
513
+ closable: true, // Show or hide the close [X] button
514
+ alertDialog: 'dialog', // ARIA role of the modal component
515
+ lazy: false, // Render body only while open
516
+ startOpen: true, // Open modal on creation
517
+ removeOnClose: true, // Remove modal from DOM when closed
518
+ }),
519
+ ],
520
+ };
521
+ ```
522
+
523
+ Most of these options are inherited from `tds-modal`.
524
+
525
+ > Note: The configuration is optional, all values shown above are the default settings.
526
+
527
+ ### Use in components
528
+
529
+ `create()` returns a `ModalRef` that can control the modal instance.
530
+
531
+ ```ts
532
+ import { inject } from '@angular/core';
533
+ import { ModalService } from '@scania-nl/tegel-angular-extensions';
534
+
535
+ export class MyComponent {
536
+ private readonly modalService = inject(ModalService);
537
+
538
+ openModal() {
539
+ const ref = this.modalService.create({
540
+ header: 'Demo Modal',
541
+ body: 'Hello from modal',
542
+ startOpen: false,
543
+ removeOnClose: false,
544
+ });
545
+
546
+ ref.open(); // Opens the modal
547
+ ref.close(); // Closes (hides) the modal
548
+ ref.remove(); // Removes the modal from the DOM
549
+ }
550
+ }
551
+ ```
552
+
553
+ You get a `ModalRef` back from `create()`, which you can use to control that specific modal instance (`open()`, `close()`, `remove()`).
554
+
555
+ ---
556
+
557
+ &nbsp;
558
+
559
+ ## Modal Configuration Options
560
+
561
+ | Option | Type | Default | Description |
562
+ | ----------------- | ------------------------------ | -------- | --------------------------- |
563
+ | `size` | `'xs' \| 'sm' \| 'md' \| 'lg'` | `md` | Modal size |
564
+ | `actionsPosition` | `'static' \| 'sticky'` | `static` | Actions slot behavior |
565
+ | `prevent` | `boolean` | `false` | Prevent overlay close |
566
+ | `closable` | `boolean` | `true` | Show/hide close button |
567
+ | `alertDialog` | `'dialog' \| 'alertdialog'` | `dialog` | ARIA role |
568
+ | `lazy` | `boolean` | `false` | Render body only while open |
569
+ | `startOpen` | `boolean` | `true` | Open immediately on create |
570
+ | `removeOnClose` | `boolean` | `true` | Remove modal after close |
571
+
572
+ > Be aware that when `removeOnClose` is set to `false`, the modal content is hidden but **not destroyed**. If your body uses a component with active subscriptions, timers, or sockets, they will continue to run while the modal is hidden. Consider `removeOnClose: true` for component bodies if you want their resources to be disposed on close.
573
+
574
+ ---
575
+
576
+ &nbsp;
577
+
578
+ ### Per-modal options (create)
579
+
580
+ These options are passed to `modalService.create()` and override defaults from `provideModal()` on a per‑modal basis. For shared defaults like `size`, `actionsPosition`, `prevent`, `closable`, `alertDialog`, `lazy`, `startOpen`, and `removeOnClose`, see [Modal Configuration Options](#modal-configuration-options) above.
581
+
582
+ | Option | Type | Description |
583
+ | ------------- | ------------------------------------------------------------------- | ----------------------------------------------------------- |
584
+ | `header` | `string \| TemplateRef<unknown>` | Modal header text or template |
585
+ | `body` | `string \| { template, context } \| { component, inputs, outputs }` | Modal body content (string, template+context, or component) |
586
+ | `buttons` | `ModalButton[]` | Action buttons to render in the actions slot |
587
+ | `selector` | `string` | CSS selector for focus return element |
588
+ | `referenceEl` | `HTMLElement` | Element to return focus to (preferred over selector) |
589
+ | `onClosed` | `() => void \| Promise<void>` | Called when the modal is closed |
590
+ | `onRemoved` | `() => void \| Promise<void>` | Called after the modal is removed |
591
+
592
+ > Note: If you want focus to return to the element that opened the modal, pass either `selector` or `referenceEl` when creating the modal. This avoids Tegel's "Missing focus origin" warning.
593
+
594
+ ---
595
+
596
+ &nbsp;
597
+
598
+ ### Body content options
599
+
600
+ The modal body can be provided as a simple string, a template body, or a component descriptor.
601
+
602
+ &nbsp;
603
+
604
+ #### 1) String body
605
+
606
+ ```ts
607
+ this.modalService.create({
608
+ header: 'Simple',
609
+ body: 'This is a simple modal body',
610
+ });
611
+ ```
612
+
613
+ &nbsp;
614
+
615
+ #### 2) Template body (template + optional context)
616
+
617
+ Signature:
618
+
619
+ ```
620
+ body: {
621
+ template: TemplateRef<TContext>;
622
+ context?: TContext;
623
+ }
624
+ ```
625
+
626
+ &nbsp;
627
+ Example:
628
+
629
+ ```html
630
+ <ng-template #bodyTpl let-context>
631
+ <p>
632
+ <b>{{ context.substance }}<b> boils at
633
+ <b>{{ context.value }}</b> degrees {{ context.units }}.
634
+ </p>
635
+ </ng-template>
636
+ ```
637
+
638
+ ```ts
639
+ interface SubstanceTemperature {
640
+ substance: string;
641
+ value: number;
642
+ units: string;
643
+ }
644
+
645
+ const bodyTpl =
646
+ viewChild.required<TemplateRef<SubstanceTemperature>>('bodyTpl');
647
+ this.modalService.create({
648
+ header: 'Template',
649
+ body: {
650
+ template: bodyTpl(),
651
+ context: {
652
+ substance: 'Water',
653
+ value: 100,
654
+ units: 'Celcius',
655
+ },
656
+ },
657
+ });
658
+ ```
659
+
660
+ &nbsp;
661
+
662
+ For typed templates, you can use `TypedTemplateDirective` to enforce context types in the template:
663
+
664
+ ```html
665
+ <ng-template #bodyTpl let-context [typedContext]="this.bodyTpl()">
666
+ ...
667
+ </ng-template>
668
+ ```
669
+
670
+ &nbsp;
671
+
672
+ #### 3) Component body (with inputs/outputs)
673
+
674
+ Signature:
675
+
676
+ ```ts
677
+ body: {
678
+ component: Type<TComponent>;
679
+ inputs: ComponentInputs<TComponent>;
680
+ outputs?: ComponentOutputs<TComponent>;
681
+ }
682
+ ```
683
+
684
+ &nbsp;
685
+
686
+ When you pass a component as the modal body, the `inputs` and `outputs` objects are fully typed. This means you get IntelliSense for signal inputs/outputs, and any `input.required(...)` fields are enforced at compile time (missing required inputs will fail the build).
687
+
688
+ ```ts
689
+ export class ExampleComponent {
690
+ readonly requiredField = input.required<string>();
691
+ readonly optionalField = input<string>();
692
+ readonly outputField = output<string>();
693
+ }
694
+ ```
695
+
696
+ ```ts
697
+ const ref = this.modalService.create({
698
+ header: 'Example',
699
+ body: {
700
+ component: ExampleComponent,
701
+ inputs: {
702
+ requiredField: 'Required',
703
+ // optionalField: 'Optional'
704
+ },
705
+ outputs: {
706
+ outputField: (value: string) => {
707
+ console.log('Value:', value);
708
+ ref.close();
709
+ },
710
+ },
711
+ },
712
+ });
713
+ ```
714
+
715
+ &nbsp;
716
+
717
+ ### Action buttons
718
+
719
+ ```ts
720
+ this.modalService.create({
721
+ header: 'Confirm',
722
+ body: 'Are you sure?',
723
+ buttons: [
724
+ { text: 'OK', variant: 'primary', onClick: async () => console.log('OK') },
725
+ { text: 'Cancel', variant: 'secondary', dismiss: true },
726
+ ],
727
+ startOpen: true,
728
+ });
729
+ ```
730
+
731
+ - `dismiss`: true adds `data-dismiss-modal` for Tegel's built‑in close behavior.
732
+ - `onClick` supports sync or async handlers.
733
+
734
+ &nbsp;
735
+
736
+ #### ModalButton options
737
+
738
+ Modal action buttons map directly to Tegel's `tds-button` configuration. The following options are supported:
739
+
740
+ | Option | Type | Description |
741
+ | ---------- | --------------------------------------------------- | ----------------------------------------------------------- |
742
+ | `text` | `string` | Button label text |
743
+ | `variant` | `'primary' \| 'secondary' \| 'success' \| 'danger'` | Visual variant |
744
+ | `size` | `'xs' \| 'sm' \| 'md' \| 'lg'` | Button size |
745
+ | `disabled` | `boolean` | Disable the button |
746
+ | `dismiss` | `boolean` | Adds `data-dismiss-modal` to trigger Tegel's close behavior |
747
+ | `onClick` | `() => void \| Promise<void>` | Optional click handler (sync or async) |
748
+
749
+ ---
750
+
751
+ &nbsp;
752
+
753
+ ## ModalService API
754
+
755
+ The `ModalService` provides a signal-based API to create, manage, and dismiss modal instances. It is available after registering `provideModal()` in your `app.config.ts`.
756
+
757
+ &nbsp;
758
+
759
+ ### ModalService Properties
760
+
761
+ | Property | Type | Description |
762
+ | -------- | ---------------------------- | -------------------------------------------------- |
763
+ | `modals` | `Signal<Map<string, Modal>>` | Read-only map of all registered modals keyed by id |
764
+
765
+ &nbsp;
766
+
767
+ ### ModalService Methods
768
+
769
+ #### `create<T>(options?: ModalOptions<T>): ModalRef`
770
+
771
+ Creates and registers a new modal. Returns a `ModalRef` for controlling that instance.
772
+
773
+ ```ts
774
+ const ref = modalService.create({
775
+ header: 'Hello',
776
+ body: 'Modal content',
777
+ startOpen: false,
778
+ });
779
+
780
+ ref.open();
781
+ ref.close();
782
+ ref.remove();
783
+ ```
784
+
785
+ &nbsp;
786
+
787
+ #### ModalRef
788
+
789
+ `create()` returns a `ModalRef` with `open()`, `close()`, and `remove()` methods to control that specific modal instance.
790
+
791
+ #### `open(id: string): void`
792
+
793
+ Opens an existing modal by id.
794
+
795
+ Example:
796
+
797
+ ```ts
798
+ const ref = modalService.create({
799
+ header: 'Example',
800
+ body: 'Hello',
801
+ startOpen: false,
802
+ });
803
+ modalService.open(ref.id); // Equivalent to ref.open()
804
+ ```
805
+
806
+ &nbsp;
807
+
808
+ #### `close(id: string): void`
809
+
810
+ Closes (hides) a modal by id. If `removeOnClose` is `true`, it is removed from the DOM after closing.
811
+
812
+ &nbsp;
813
+
814
+ #### `remove(id: string): void`
815
+
816
+ Removes a modal from the registry/DOM. If the modal is open, it is closed first.
817
+
818
+ &nbsp;
819
+
820
+ #### `closeAll(): void`
821
+
822
+ Closes all registered modals.
823
+
824
+ &nbsp;
825
+
826
+ #### `removeAll(): void`
827
+
828
+ Removes all registered modals.
829
+
830
+ ---
831
+
832
+ &nbsp;
833
+
834
+ ### Modal Lifecycle Hooks
835
+
836
+ Each modal supports optional lifecycle callbacks:
837
+
838
+ | Callback | Description |
839
+ | ------------- | ------------------------------------------------------- |
840
+ | `onClosed()` | Called when the modal is closed |
841
+ | `onRemoved()` | Called after the modal is removed from the registry/DOM |
842
+
843
+ Example:
844
+
845
+ ```ts
846
+ modalService.create({
847
+ header: 'Example',
848
+ body: 'Hello',
849
+ onClosed: () => console.log('Modal closed'),
850
+ onRemoved: () => console.log('Modal removed'),
851
+ });
852
+ ```
853
+
854
+ ---
855
+
856
+ &nbsp;
857
+
858
+ # Components & Directives
453
859
 
454
860
  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
861
  &nbsp;
456
862
 
457
- ## 🧱 Components
863
+ ## Components
864
+
865
+ ### DateTime Picker Component (`tae-date-time-picker`) [BETA]
866
+
867
+ `TaeDateTimePickerComponent` is a standalone, form‑compatible picker that supports `date`, `datetime`, and `time` modes. It implements Angular's `ControlValueAccessor`, so it works with both reactive and template‑driven forms.
868
+
869
+ > Beta: This component is still evolving. Improvements are planned and minor bugs may occur.
870
+
871
+ **Inputs:**
872
+
873
+ | Input | Type | Default | Description |
874
+ | --------------- | ------------------------------------- | --------- | ------------------- |
875
+ | `label` | `string` | `''` | Label text |
876
+ | `size` | `'sm' \| 'md' \| 'lg'` | `lg` | Control size |
877
+ | `labelPosition` | `'inside' \| 'outside' \| 'no-label'` | `outside` | Label placement |
878
+ | `state` | `'error' \| undefined` | — | Error state styling |
879
+ | `helper` | `string` | `''` | Helper text |
880
+ | `mode` | `'date' \| 'datetime' \| 'time'` | `date` | Picker mode |
881
+
882
+ > Note: `labelPosition` is currently not implemented; it will be supported in a future update.
883
+ > Note: `state` is currently only used for styling in the template and does not affect behavior.
884
+
885
+ &nbsp;
886
+
887
+ **Example (reactive forms):**
888
+
889
+ ```ts
890
+ readonly form = this.fb.group({
891
+ date: this.fb.control<string | null>(null),
892
+ time: this.fb.control<string | null>(null),
893
+ dateTime: this.fb.control<string | null>(null),
894
+ });
895
+ ```
896
+
897
+ ```html
898
+ <form [formGroup]="form">
899
+ <tae-date-time-picker label="Date" formControlName="date" mode="date" />
900
+ <tae-date-time-picker label="Time" formControlName="time" mode="time" />
901
+ <tae-date-time-picker
902
+ label="DateTime"
903
+ formControlName="dateTime"
904
+ mode="datetime"
905
+ />
906
+ </form>
907
+ ```
908
+
909
+ &nbsp;
458
910
 
459
911
  ### Footer Component (`tae-footer`)
460
912
 
@@ -480,7 +932,7 @@ This makes it ideal for full-viewport layouts that benefit from space efficiency
480
932
 
481
933
  &nbsp;
482
934
 
483
- ## Directives
935
+ ## Directives
484
936
 
485
937
  ### Hard Refresh Directive (`taeHardRefresh`)
486
938
 
@@ -490,10 +942,10 @@ This is especially useful for hard-reloading tablet or mobile applications which
490
942
 
491
943
  **Inputs:**
492
944
 
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. |
945
+ | Property | Type | Default | Description |
946
+ | ---------------- | -------- | ------- | ---------------------------------------------------------------------- |
947
+ | `clicksRequired` | `number` | `3` | Number of clicks required within the window to trigger a hard refresh. |
948
+ | `clickWindowMs` | `number` | `500` | Time window in milliseconds between two subsequent clicks. |
497
949
 
498
950
  **Example:**
499
951
 
@@ -517,16 +969,16 @@ It operates outside of Angular's zone to prevent unnecessary change detection cy
517
969
 
518
970
  **Inputs:**
519
971
 
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. |
972
+ | Input | Type | Default | Description |
973
+ | --------------- | -------- | --------- | ------------------------------------------------------------------ |
974
+ | `inputWindowMs` | `number` | `100` | Max time allowed between consecutive keypresses before discarding. |
975
+ | `terminatorKey` | `string` | `'Enter'` | The key that signals the end of a barcode sequence. |
524
976
 
525
977
  **Outputs:**
526
978
 
527
- | Output | Type | Description |
528
- | ---------------- | ---------------- | ------------------------------------------------------------------ |
529
- | `barcodeScanned` | `string` | **Required**. Emits the full barcode string once completed. |
979
+ | Output | Type | Description |
980
+ | ---------------- | -------- | ----------------------------------------------------------- |
981
+ | `barcodeScanned` | `string` | **Required**. Emits the full barcode string once completed. |
530
982
 
531
983
  **Example:**
532
984
 
@@ -597,7 +1049,9 @@ CMD ["nginx", "-c", "/etc/nginx/nginx.conf", "-g", "daemon off;"]
597
1049
 
598
1050
  ---
599
1051
 
600
- # 📄 License
1052
+ &nbsp;
1053
+
1054
+ # License
601
1055
 
602
1056
  Copyright 2025 Scania CV AB.
603
1057