@m1z23r/ngx-ui 1.1.37 → 1.1.38

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
@@ -45,12 +45,20 @@ import { ButtonComponent } from '@m1z23r/ngx-ui';
45
45
  @Component({
46
46
  imports: [ButtonComponent],
47
47
  template: `
48
- <ui-button variant="primary" size="md" (clicked)="handleClick($event)">
48
+ <ui-button color="primary" size="md" (clicked)="handleClick($event)">
49
49
  Click me
50
50
  </ui-button>
51
51
 
52
- <ui-button variant="outline" [loading]="isLoading">
53
- Submit
52
+ <ui-button variant="outline" color="danger" [loading]="isLoading">
53
+ Delete
54
+ </ui-button>
55
+
56
+ <ui-button variant="ghost" color="secondary">
57
+ Cancel
58
+ </ui-button>
59
+
60
+ <ui-button variant="elevated" color="success">
61
+ Save
54
62
  </ui-button>
55
63
  `
56
64
  })
@@ -60,7 +68,8 @@ import { ButtonComponent } from '@m1z23r/ngx-ui';
60
68
 
61
69
  | Input | Type | Default | Description |
62
70
  |-------|------|---------|-------------|
63
- | `variant` | `'primary' \| 'secondary' \| 'outline' \| 'ghost'` | `'primary'` | Button style variant |
71
+ | `variant` | `'default' \| 'outline' \| 'ghost' \| 'elevated'` | `'default'` | Button style variant |
72
+ | `color` | `'primary' \| 'secondary' \| 'danger' \| 'success' \| 'warning'` | `'primary'` | Button color |
64
73
  | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Button size |
65
74
  | `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | HTML button type |
66
75
  | `disabled` | `boolean` | `false` | Disable the button |
@@ -109,6 +118,9 @@ import { InputComponent } from '@m1z23r/ngx-ui';
109
118
  | `readonly` | `boolean` | `false` | Make input read-only |
110
119
  | `required` | `boolean` | `false` | Mark as required (shows asterisk) |
111
120
  | `id` | `string` | auto-generated | Custom input ID |
121
+ | `validators` | `ValidatorFn[]` | `[]` | Array of validator functions |
122
+ | `validatorFn` | `ValidatorFn \| null` | `null` | Single validator function |
123
+ | `showErrorsOn` | `'touched' \| 'dirty' \| 'always'` | `'touched'` | When to show validation errors |
112
124
 
113
125
  #### Two-way Binding
114
126
 
@@ -116,6 +128,26 @@ import { InputComponent } from '@m1z23r/ngx-ui';
116
128
  |-------|------|-------------|
117
129
  | `value` | `string \| number` | The input value |
118
130
 
131
+ #### Validation
132
+
133
+ The input component has built-in validation support:
134
+
135
+ ```typescript
136
+ // Computed properties
137
+ errors: Signal<ValidationError[]> // All current validation errors
138
+ isValid: Signal<boolean> // Whether input passes validation
139
+ isInvalid: Signal<boolean> // Whether input fails validation
140
+ errorMessage: Signal<string | null> // First error message
141
+ validationState: Signal<ValidationState> // Full validation state
142
+
143
+ // Methods
144
+ reset(): void // Reset value and validation state
145
+ markAsTouched(): void // Mark as touched
146
+ markAsDirty(): void // Mark as dirty
147
+ hasError(key: string): boolean // Check for specific error
148
+ getError(key: string): ValidationError | undefined // Get specific error
149
+ ```
150
+
119
151
  ---
120
152
 
121
153
  ### Table
@@ -399,7 +431,7 @@ import { ButtonComponent, LoadingDirective, LoadingService } from '@m1z23r/ngx-u
399
431
  <!-- These buttons automatically show loading when their identifier is active -->
400
432
  <ui-button uiLoading="login" (clicked)="login()">Login</ui-button>
401
433
  <ui-button uiLoading="submit" (clicked)="submit()">Submit</ui-button>
402
- <ui-button uiLoading="delete" variant="outline">Delete</ui-button>
434
+ <ui-button uiLoading="delete" variant="outline" color="danger">Delete</ui-button>
403
435
  `
404
436
  })
405
437
  export class MyComponent {
@@ -569,7 +601,7 @@ import { CircularProgressComponent } from '@m1z23r/ngx-ui';
569
601
  |-------|------|---------|-------------|
570
602
  | `value` | `number` | `0` | Progress value (0-100) |
571
603
  | `variant` | `'primary' \| 'success' \| 'warning' \| 'danger'` | `'primary'` | Color variant |
572
- | `size` | `'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Circle size |
604
+ | `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Circle size |
573
605
  | `strokeWidth` | `number` | `4` | Stroke width in pixels |
574
606
  | `showLabel` | `boolean` | `false` | Show percentage in center |
575
607
  | `indeterminate` | `boolean` | `false` | Spinning animation |
@@ -791,6 +823,7 @@ import { TabsComponent, TabComponent } from '@m1z23r/ngx-ui';
791
823
  | `variant` | `'default' \| 'pills' \| 'underline'` | `'default'` | Tab style |
792
824
  | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Tab size |
793
825
  | `ariaLabel` | `string` | `''` | Accessibility label |
826
+ | `renderMode` | `'conditional' \| 'persistent'` | `'conditional'` | Tab content rendering strategy |
794
827
 
795
828
  ### Tabs Two-way Binding
796
829
 
@@ -798,12 +831,6 @@ import { TabsComponent, TabComponent } from '@m1z23r/ngx-ui';
798
831
  |-------|------|-------------|
799
832
  | `activeTab` | `string \| number` | Active tab ID or index |
800
833
 
801
- ### Tabs Outputs
802
-
803
- | Output | Type | Description |
804
- |--------|------|-------------|
805
- | `changed` | `string \| number` | Emitted when active tab changes |
806
-
807
834
  ### Tab Inputs
808
835
 
809
836
  | Input | Type | Default | Description |
@@ -876,10 +903,10 @@ export class MyComponent {
876
903
  | Method | Parameters | Returns | Description |
877
904
  |--------|------------|---------|-------------|
878
905
  | `show(config)` | `ToastConfig` | `ToastRef` | Show toast with full config |
879
- | `success(message, title?)` | `string, string?` | `ToastRef` | Success toast |
880
- | `error(message, title?)` | `string, string?` | `ToastRef` | Error toast |
881
- | `warning(message, title?)` | `string, string?` | `ToastRef` | Warning toast |
882
- | `info(message, title?)` | `string, string?` | `ToastRef` | Info toast |
906
+ | `success(message, title?, duration?)` | `string, string?, number?` | `ToastRef` | Success toast |
907
+ | `error(message, title?, duration?)` | `string, string?, number?` | `ToastRef` | Error toast |
908
+ | `warning(message, title?, duration?)` | `string, string?, number?` | `ToastRef` | Warning toast |
909
+ | `info(message, title?, duration?)` | `string, string?, number?` | `ToastRef` | Info toast |
883
910
  | `dismiss(id)` | `string` | `void` | Dismiss specific toast |
884
911
  | `dismissAll()` | - | `void` | Dismiss all toasts |
885
912
 
@@ -894,6 +921,7 @@ export class MyComponent {
894
921
  | `position` | `ToastPosition` | `'top-right'` | Screen position |
895
922
  | `dismissible` | `boolean` | `true` | Show close button |
896
923
  | `showProgress` | `boolean` | `true` | Show countdown bar |
924
+ | `maxVisible` | `number` | - | Max visible toasts at once |
897
925
 
898
926
  ### ToastPosition Values
899
927
 
@@ -927,7 +955,6 @@ import { PaginationComponent } from '@m1z23r/ngx-ui';
927
955
  [maxPages]="7"
928
956
  [showFirstLast]="true"
929
957
  size="md"
930
- (changed)="onPageChange($event)"
931
958
  />
932
959
  ```
933
960
 
@@ -947,12 +974,6 @@ import { PaginationComponent } from '@m1z23r/ngx-ui';
947
974
  |-------|------|-------------|
948
975
  | `page` | `number` | Current page (1-indexed) |
949
976
 
950
- ### Outputs
951
-
952
- | Output | Type | Description |
953
- |--------|------|-------------|
954
- | `changed` | `number` | Emitted when page changes |
955
-
956
977
  ### Features
957
978
 
958
979
  - **Smart truncation**: Shows ellipsis when there are many pages
@@ -981,7 +1002,7 @@ import { DialogService, DIALOG_DATA, DIALOG_REF, DialogRef, ModalComponent, Butt
981
1002
  <p>{{ data.message }}</p>
982
1003
 
983
1004
  <ng-container footer>
984
- <ui-button variant="outline" (clicked)="dialogRef.close(false)">Cancel</ui-button>
1005
+ <ui-button variant="outline" color="secondary" (clicked)="dialogRef.close(false)">Cancel</ui-button>
985
1006
  <ui-button (clicked)="dialogRef.close(true)">Confirm</ui-button>
986
1007
  </ng-container>
987
1008
  </ui-modal>
@@ -1021,7 +1042,7 @@ A wrapper component that provides the modal UI with backdrop, header, body, and
1021
1042
 
1022
1043
  <!-- Footer content (named slot) -->
1023
1044
  <ng-container footer>
1024
- <ui-button variant="outline" (clicked)="cancel()">Cancel</ui-button>
1045
+ <ui-button variant="outline" color="secondary" (clicked)="cancel()">Cancel</ui-button>
1025
1046
  <ui-button (clicked)="save()">Save</ui-button>
1026
1047
  </ng-container>
1027
1048
  </ui-modal>
@@ -1109,8 +1130,17 @@ All components use CSS custom properties for styling. Override these in your glo
1109
1130
 
1110
1131
  // Semantic colors
1111
1132
  --ui-success: #22c55e;
1133
+ --ui-success-hover: #16a34a;
1134
+ --ui-success-active: #15803d;
1135
+ --ui-success-text: #ffffff;
1112
1136
  --ui-danger: #ef4444;
1137
+ --ui-danger-hover: #dc2626;
1138
+ --ui-danger-active: #b91c1c;
1139
+ --ui-danger-text: #ffffff;
1113
1140
  --ui-warning: #f59e0b;
1141
+ --ui-warning-hover: #d97706;
1142
+ --ui-warning-active: #b45309;
1143
+ --ui-warning-text: #ffffff;
1114
1144
 
1115
1145
  // Background colors
1116
1146
  --ui-bg: #ffffff;
@@ -1132,6 +1162,7 @@ All components use CSS custom properties for styling. Override these in your glo
1132
1162
  --ui-radius-sm: 0.25rem;
1133
1163
  --ui-radius-md: 0.375rem;
1134
1164
  --ui-radius-lg: 0.5rem;
1165
+ --ui-radius-xl: 0.75rem;
1135
1166
 
1136
1167
  // Spacing
1137
1168
  --ui-spacing-xs: 0.25rem;
@@ -1146,10 +1177,13 @@ All components use CSS custom properties for styling. Override these in your glo
1146
1177
  --ui-navbar-height: 4rem;
1147
1178
  --ui-footer-height: 3rem;
1148
1179
 
1180
+ // Breakpoints
1181
+ --ui-breakpoint-mobile: 768px;
1182
+
1149
1183
  // Shadows
1150
1184
  --ui-shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
1151
- --ui-shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
1152
- --ui-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
1185
+ --ui-shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
1186
+ --ui-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
1153
1187
 
1154
1188
  // Transitions
1155
1189
  --ui-transition-fast: 150ms ease;
@@ -1161,6 +1195,19 @@ All components use CSS custom properties for styling. Override these in your glo
1161
1195
  --ui-font-sm: 0.875rem;
1162
1196
  --ui-font-md: 1rem;
1163
1197
  --ui-font-lg: 1.125rem;
1198
+ --ui-font-xl: 1.25rem;
1199
+
1200
+ // Dropdown & Select
1201
+ --ui-dropdown-bg: var(--ui-bg);
1202
+ --ui-dropdown-border: var(--ui-border);
1203
+ --ui-dropdown-shadow: var(--ui-shadow-lg);
1204
+ --ui-dropdown-radius: var(--ui-radius-md);
1205
+ --ui-dropdown-max-height: 300px;
1206
+
1207
+ // Option/Item states
1208
+ --ui-option-hover-bg: var(--ui-bg-hover);
1209
+ --ui-option-selected-bg: color-mix(in srgb, var(--ui-primary) 10%, transparent);
1210
+ --ui-option-selected-text: var(--ui-primary);
1164
1211
  }
1165
1212
  ```
1166
1213
 
@@ -1,6 +1,6 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { inject, PLATFORM_ID, signal, Injectable, computed, InjectionToken, ApplicationRef, EnvironmentInjector, createComponent, Injector, input, output, ChangeDetectionStrategy, Component, ElementRef, HostListener, effect, Directive, model, Pipe, contentChildren, TemplateRef, contentChild, ViewChild, viewChild, afterRenderEffect, DestroyRef } from '@angular/core';
3
- import { isPlatformBrowser, NgTemplateOutlet, NgComponentOutlet, DOCUMENT, DecimalPipe } from '@angular/common';
3
+ import { isPlatformBrowser, DOCUMENT, NgTemplateOutlet, NgComponentOutlet, DecimalPipe } from '@angular/common';
4
4
  import * as i1 from '@angular/forms';
5
5
  import { FormsModule } from '@angular/forms';
6
6
 
@@ -378,6 +378,8 @@ const DEFAULT_DIALOG_CONFIG = {
378
378
  class DialogService {
379
379
  appRef = inject(ApplicationRef);
380
380
  injector = inject(EnvironmentInjector);
381
+ document = inject(DOCUMENT);
382
+ platformId = inject(PLATFORM_ID);
381
383
  /**
382
384
  * Opens a dialog with the specified component.
383
385
  *
@@ -397,7 +399,9 @@ class DialogService {
397
399
  const hostElement = componentRef.location.nativeElement;
398
400
  hostElement.dataset['dialogConfig'] = JSON.stringify(mergedConfig);
399
401
  this.appRef.attachView(componentRef.hostView);
400
- document.body.appendChild(hostElement);
402
+ if (isPlatformBrowser(this.platformId)) {
403
+ this.document.body.appendChild(hostElement);
404
+ }
401
405
  return dialogRef;
402
406
  }
403
407
  destroy(componentRef) {
@@ -550,6 +554,8 @@ const TOAST_DATA = new InjectionToken('TOAST_DATA');
550
554
  class ToastService {
551
555
  appRef = inject(ApplicationRef);
552
556
  injector = inject(EnvironmentInjector);
557
+ document = inject(DOCUMENT);
558
+ platformId = inject(PLATFORM_ID);
553
559
  containerRef = null;
554
560
  toasts = signal([], ...(ngDevMode ? [{ debugName: "toasts" }] : []));
555
561
  toastRefs = new Map();
@@ -658,7 +664,9 @@ class ToastService {
658
664
  });
659
665
  this.updateContainer();
660
666
  this.appRef.attachView(this.containerRef.hostView);
661
- document.body.appendChild(this.containerRef.location.nativeElement);
667
+ if (isPlatformBrowser(this.platformId)) {
668
+ this.document.body.appendChild(this.containerRef.location.nativeElement);
669
+ }
662
670
  }
663
671
  updateContainer() {
664
672
  if (!this.containerRef)
@@ -1432,6 +1440,7 @@ class SelectComponent {
1432
1440
  asyncSearchAbortController = null;
1433
1441
  debounceTimer = null;
1434
1442
  elementRef = inject(ElementRef);
1443
+ document = inject(DOCUMENT);
1435
1444
  positionCleanup = null;
1436
1445
  initializedOptions = new WeakSet();
1437
1446
  constructor() {
@@ -1496,8 +1505,8 @@ class SelectComponent {
1496
1505
  }
1497
1506
  ngOnDestroy() {
1498
1507
  const dropdown = this.dropdownRef?.nativeElement;
1499
- if (dropdown?.parentElement === document.body) {
1500
- document.body.removeChild(dropdown);
1508
+ if (dropdown?.parentElement === this.document.body) {
1509
+ this.document.body.removeChild(dropdown);
1501
1510
  }
1502
1511
  this.removePositionListeners();
1503
1512
  this.cancelAsyncSearch();
@@ -2011,7 +2020,7 @@ class SelectComponent {
2011
2020
  if (!dropdown)
2012
2021
  return;
2013
2022
  dropdown.style.display = 'block';
2014
- document.body.appendChild(dropdown);
2023
+ this.document.body.appendChild(dropdown);
2015
2024
  this.updateDropdownPosition();
2016
2025
  this.addPositionListeners();
2017
2026
  }
@@ -2019,7 +2028,7 @@ class SelectComponent {
2019
2028
  const dropdown = this.dropdownRef?.nativeElement;
2020
2029
  if (!dropdown)
2021
2030
  return;
2022
- if (dropdown.parentElement === document.body) {
2031
+ if (dropdown.parentElement === this.document.body) {
2023
2032
  const wrapper = this.elementRef.nativeElement.querySelector('.ui-select-wrapper');
2024
2033
  if (wrapper) {
2025
2034
  wrapper.appendChild(dropdown);
@@ -2159,6 +2168,7 @@ class DropdownComponent {
2159
2168
  triggerRef;
2160
2169
  menuRef;
2161
2170
  elementRef = inject(ElementRef);
2171
+ document = inject(DOCUMENT);
2162
2172
  positionCleanup = null;
2163
2173
  contextMenuPosition = null;
2164
2174
  trigger = contentChild(DropdownTriggerDirective, ...(ngDevMode ? [{ debugName: "trigger" }] : []));
@@ -2194,8 +2204,8 @@ class DropdownComponent {
2194
2204
  }
2195
2205
  ngOnDestroy() {
2196
2206
  const menu = this.menuRef?.nativeElement;
2197
- if (menu?.parentElement === document.body) {
2198
- document.body.removeChild(menu);
2207
+ if (menu?.parentElement === this.document.body) {
2208
+ this.document.body.removeChild(menu);
2199
2209
  }
2200
2210
  this.removePositionListeners();
2201
2211
  }
@@ -2296,7 +2306,7 @@ class DropdownComponent {
2296
2306
  if (!menu)
2297
2307
  return;
2298
2308
  menu.style.display = 'block';
2299
- document.body.appendChild(menu);
2309
+ this.document.body.appendChild(menu);
2300
2310
  this.updateMenuPosition();
2301
2311
  this.addPositionListeners();
2302
2312
  }
@@ -2304,7 +2314,7 @@ class DropdownComponent {
2304
2314
  const menu = this.menuRef?.nativeElement;
2305
2315
  if (!menu)
2306
2316
  return;
2307
- if (menu.parentElement === document.body) {
2317
+ if (menu.parentElement === this.document.body) {
2308
2318
  const wrapper = this.elementRef.nativeElement.querySelector('.ui-dropdown');
2309
2319
  if (wrapper) {
2310
2320
  wrapper.appendChild(menu);
@@ -2684,6 +2694,8 @@ class TooltipDirective {
2684
2694
  tooltipPosition = input('top', ...(ngDevMode ? [{ debugName: "tooltipPosition" }] : []));
2685
2695
  tooltipDelay = input(200, ...(ngDevMode ? [{ debugName: "tooltipDelay" }] : []));
2686
2696
  tooltipDisabled = input(false, ...(ngDevMode ? [{ debugName: "tooltipDisabled" }] : []));
2697
+ document = inject(DOCUMENT);
2698
+ platformId = inject(PLATFORM_ID);
2687
2699
  tooltipElement = null;
2688
2700
  showTimeout = null;
2689
2701
  isVisible = signal(false, ...(ngDevMode ? [{ debugName: "isVisible" }] : []));
@@ -2748,7 +2760,7 @@ class TooltipDirective {
2748
2760
  const arrow = this.renderer.createElement('span');
2749
2761
  this.renderer.addClass(arrow, 'ui-tooltip__arrow');
2750
2762
  this.renderer.appendChild(this.tooltipElement, arrow);
2751
- this.renderer.appendChild(document.body, this.tooltipElement);
2763
+ this.renderer.appendChild(this.document.body, this.tooltipElement);
2752
2764
  this.injectStyles();
2753
2765
  }
2754
2766
  positionTooltip() {
@@ -2787,13 +2799,13 @@ class TooltipDirective {
2787
2799
  }
2788
2800
  destroyTooltip() {
2789
2801
  if (this.tooltipElement) {
2790
- this.renderer.removeChild(document.body, this.tooltipElement);
2802
+ this.renderer.removeChild(this.document.body, this.tooltipElement);
2791
2803
  this.tooltipElement = null;
2792
2804
  }
2793
2805
  }
2794
2806
  injectStyles() {
2795
2807
  const styleId = 'ui-tooltip-styles';
2796
- if (document.getElementById(styleId))
2808
+ if (!isPlatformBrowser(this.platformId) || this.document.getElementById(styleId))
2797
2809
  return;
2798
2810
  const style = this.renderer.createElement('style');
2799
2811
  this.renderer.setProperty(style, 'id', styleId);
@@ -2856,7 +2868,7 @@ class TooltipDirective {
2856
2868
  margin-top: -4px;
2857
2869
  }
2858
2870
  `);
2859
- this.renderer.appendChild(document.head, style);
2871
+ this.renderer.appendChild(this.document.head, style);
2860
2872
  }
2861
2873
  ngOnDestroy() {
2862
2874
  this.hide();
@@ -4032,6 +4044,7 @@ class DatepickerComponent {
4032
4044
  focusedDate = signal(null, ...(ngDevMode ? [{ debugName: "focusedDate" }] : []));
4033
4045
  hoveredDate = signal(null, ...(ngDevMode ? [{ debugName: "hoveredDate" }] : []));
4034
4046
  elementRef = inject(ElementRef);
4047
+ document = inject(DOCUMENT);
4035
4048
  positionCleanup = null;
4036
4049
  static nextId = 0;
4037
4050
  generatedId = `ui-datepicker-${++DatepickerComponent.nextId}`;
@@ -4289,8 +4302,8 @@ class DatepickerComponent {
4289
4302
  }, ...(ngDevMode ? [{ debugName: "canNavigateNext" }] : []));
4290
4303
  ngOnDestroy() {
4291
4304
  const dropdown = this.dropdownRef?.nativeElement;
4292
- if (dropdown?.parentElement === document.body) {
4293
- document.body.removeChild(dropdown);
4305
+ if (dropdown?.parentElement === this.document.body) {
4306
+ this.document.body.removeChild(dropdown);
4294
4307
  }
4295
4308
  this.removePositionListeners();
4296
4309
  }
@@ -4606,7 +4619,7 @@ class DatepickerComponent {
4606
4619
  if (!dropdown)
4607
4620
  return;
4608
4621
  dropdown.style.display = 'block';
4609
- document.body.appendChild(dropdown);
4622
+ this.document.body.appendChild(dropdown);
4610
4623
  this.updateDropdownPosition();
4611
4624
  this.addPositionListeners();
4612
4625
  }
@@ -4614,7 +4627,7 @@ class DatepickerComponent {
4614
4627
  const dropdown = this.dropdownRef?.nativeElement;
4615
4628
  if (!dropdown)
4616
4629
  return;
4617
- if (dropdown.parentElement === document.body) {
4630
+ if (dropdown.parentElement === this.document.body) {
4618
4631
  const wrapper = this.elementRef.nativeElement.querySelector('.ui-datepicker-wrapper');
4619
4632
  if (wrapper) {
4620
4633
  wrapper.appendChild(dropdown);
@@ -4723,6 +4736,7 @@ class TimepickerComponent {
4723
4736
  selectedSecond = signal(0, ...(ngDevMode ? [{ debugName: "selectedSecond" }] : []));
4724
4737
  selectedPeriod = signal('AM', ...(ngDevMode ? [{ debugName: "selectedPeriod" }] : []));
4725
4738
  elementRef = inject(ElementRef);
4739
+ document = inject(DOCUMENT);
4726
4740
  positionCleanup = null;
4727
4741
  static nextId = 0;
4728
4742
  generatedId = `ui-timepicker-${++TimepickerComponent.nextId}`;
@@ -4788,8 +4802,8 @@ class TimepickerComponent {
4788
4802
  }, ...(ngDevMode ? [{ debugName: "hasValue" }] : []));
4789
4803
  ngOnDestroy() {
4790
4804
  const dropdown = this.dropdownRef?.nativeElement;
4791
- if (dropdown?.parentElement === document.body) {
4792
- document.body.removeChild(dropdown);
4805
+ if (dropdown?.parentElement === this.document.body) {
4806
+ this.document.body.removeChild(dropdown);
4793
4807
  }
4794
4808
  this.removePositionListeners();
4795
4809
  }
@@ -4951,7 +4965,7 @@ class TimepickerComponent {
4951
4965
  if (!dropdown)
4952
4966
  return;
4953
4967
  dropdown.style.display = 'block';
4954
- document.body.appendChild(dropdown);
4968
+ this.document.body.appendChild(dropdown);
4955
4969
  this.updateDropdownPosition();
4956
4970
  this.addPositionListeners();
4957
4971
  }
@@ -4959,7 +4973,7 @@ class TimepickerComponent {
4959
4973
  const dropdown = this.dropdownRef?.nativeElement;
4960
4974
  if (!dropdown)
4961
4975
  return;
4962
- if (dropdown.parentElement === document.body) {
4976
+ if (dropdown.parentElement === this.document.body) {
4963
4977
  const wrapper = this.elementRef.nativeElement.querySelector('.ui-timepicker-wrapper');
4964
4978
  if (wrapper) {
4965
4979
  wrapper.appendChild(dropdown);
@@ -5075,6 +5089,7 @@ class DatetimepickerComponent {
5075
5089
  selectedSecond = signal(0, ...(ngDevMode ? [{ debugName: "selectedSecond" }] : []));
5076
5090
  selectedPeriod = signal('AM', ...(ngDevMode ? [{ debugName: "selectedPeriod" }] : []));
5077
5091
  elementRef = inject(ElementRef);
5092
+ document = inject(DOCUMENT);
5078
5093
  positionCleanup = null;
5079
5094
  static nextId = 0;
5080
5095
  generatedId = `ui-datetimepicker-${++DatetimepickerComponent.nextId}`;
@@ -5283,8 +5298,8 @@ class DatetimepickerComponent {
5283
5298
  }, ...(ngDevMode ? [{ debugName: "canNavigateNext" }] : []));
5284
5299
  ngOnDestroy() {
5285
5300
  const dropdown = this.dropdownRef?.nativeElement;
5286
- if (dropdown?.parentElement === document.body) {
5287
- document.body.removeChild(dropdown);
5301
+ if (dropdown?.parentElement === this.document.body) {
5302
+ this.document.body.removeChild(dropdown);
5288
5303
  }
5289
5304
  this.removePositionListeners();
5290
5305
  }
@@ -5630,7 +5645,7 @@ class DatetimepickerComponent {
5630
5645
  if (!dropdown)
5631
5646
  return;
5632
5647
  dropdown.style.display = 'block';
5633
- document.body.appendChild(dropdown);
5648
+ this.document.body.appendChild(dropdown);
5634
5649
  this.updateDropdownPosition();
5635
5650
  this.addPositionListeners();
5636
5651
  }
@@ -5638,7 +5653,7 @@ class DatetimepickerComponent {
5638
5653
  const dropdown = this.dropdownRef?.nativeElement;
5639
5654
  if (!dropdown)
5640
5655
  return;
5641
- if (dropdown.parentElement === document.body) {
5656
+ if (dropdown.parentElement === this.document.body) {
5642
5657
  const wrapper = this.elementRef.nativeElement.querySelector('.ui-datetimepicker-wrapper');
5643
5658
  if (wrapper) {
5644
5659
  wrapper.appendChild(dropdown);
@@ -6276,6 +6291,8 @@ class TemplateInputComponent {
6276
6291
  inputRef = viewChild('inputEl', ...(ngDevMode ? [{ debugName: "inputRef" }] : []));
6277
6292
  popoverRef;
6278
6293
  hostRef = inject(ElementRef);
6294
+ document = inject(DOCUMENT);
6295
+ platformId = inject(PLATFORM_ID);
6279
6296
  positionCleanup = null;
6280
6297
  currentSpanRect = null;
6281
6298
  isPortaled = false;
@@ -6470,7 +6487,9 @@ class TemplateInputComponent {
6470
6487
  `;
6471
6488
  injectStyles() {
6472
6489
  const styleId = 'ui-tmpl-styles';
6473
- let existing = document.getElementById(styleId);
6490
+ if (!isPlatformBrowser(this.platformId))
6491
+ return;
6492
+ let existing = this.document.getElementById(styleId);
6474
6493
  // Always replace to handle HMR / version upgrades
6475
6494
  if (existing) {
6476
6495
  existing.textContent = TemplateInputComponent.STYLE_CONTENT;
@@ -6479,11 +6498,11 @@ class TemplateInputComponent {
6479
6498
  const style = this.renderer.createElement('style');
6480
6499
  this.renderer.setProperty(style, 'id', styleId);
6481
6500
  this.renderer.setProperty(style, 'textContent', TemplateInputComponent.STYLE_CONTENT);
6482
- this.renderer.appendChild(document.head, style);
6501
+ this.renderer.appendChild(this.document.head, style);
6483
6502
  }
6484
6503
  portalPopover() {
6485
6504
  const el = this.popoverRef.nativeElement;
6486
- document.body.appendChild(el);
6505
+ this.document.body.appendChild(el);
6487
6506
  el.style.display = 'block';
6488
6507
  this.isPortaled = true;
6489
6508
  requestAnimationFrame(() => this.updatePopoverPosition());